Skip to content

Commit 90c12df

Browse files
committed
Merge branch 'multipart-v0' of https://github.com/eos1d3/scribejava into eos1d3-multipart-v0
2 parents 7a635da + 16de05a commit 90c12df

6 files changed

Lines changed: 171 additions & 8 deletions

File tree

scribejava-core/src/main/java/com/github/scribejava/core/httpclient/AbstractAsyncOnlyHttpClient.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,10 @@ public Response execute(String userAgent, Map<String, String> headers, Verb http
3030
return executeAsync(userAgent, headers, httpVerb, completeUrl, bodyContents, null,
3131
(OAuthRequest.ResponseConverter<Response>) null).get();
3232
}
33+
34+
@Override
35+
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
36+
OAuthRequest.MultipartPayloads multipartPayloads) throws InterruptedException, ExecutionException, IOException {
37+
throw new UnsupportedOperationException("This HttpClient does not support Multipart payload for the moment");
38+
}
3339
}

scribejava-core/src/main/java/com/github/scribejava/core/httpclient/HttpClient.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb h
2727

2828
Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
2929
byte[] bodyContents) throws InterruptedException, ExecutionException, IOException;
30+
31+
Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
32+
OAuthRequest.MultipartPayloads multipartPayloads) throws InterruptedException, ExecutionException, IOException;
3033

3134
Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
3235
String bodyContents) throws InterruptedException, ExecutionException, IOException;

scribejava-core/src/main/java/com/github/scribejava/core/httpclient/jdk/JDKHttpClient.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.github.scribejava.core.model.Verb;
1010
import java.io.File;
1111
import java.io.IOException;
12+
import java.io.OutputStream;
1213
import java.net.HttpURLConnection;
1314
import java.net.URL;
1415
import java.net.UnknownHostException;
@@ -73,7 +74,7 @@ public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers,
7374
@Override
7475
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
7576
File bodyContents, OAuthAsyncRequestCallback<T> callback, OAuthRequest.ResponseConverter<T> converter) {
76-
throw new UnsupportedOperationException("JDKHttpClient do not support File payload for the moment");
77+
throw new UnsupportedOperationException("JDKHttpClient does not support File payload for the moment");
7778
}
7879

7980
@Override
@@ -94,6 +95,12 @@ public Response execute(String userAgent, Map<String, String> headers, Verb http
9495
throw new UnsupportedOperationException("JDKHttpClient do not support File payload for the moment");
9596
}
9697

98+
@Override
99+
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
100+
OAuthRequest.MultipartPayloads multipartPayloads) throws InterruptedException, ExecutionException, IOException {
101+
return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.MULTIPART, multipartPayloads);
102+
}
103+
97104
private Response doExecute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
98105
BodyType bodyType, Object bodyContents) throws IOException {
99106
final HttpURLConnection connection = (HttpURLConnection) new URL(completeUrl).openConnection();
@@ -128,6 +135,12 @@ void setBody(HttpURLConnection connection, Object bodyContents, boolean requires
128135
addBody(connection, (byte[]) bodyContents, requiresBody);
129136
}
130137
},
138+
MULTIPART {
139+
@Override
140+
void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException {
141+
addBody(connection, (OAuthRequest.MultipartPayloads) bodyContents, requiresBody);
142+
}
143+
},
131144
STRING {
132145
@Override
133146
void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException {
@@ -137,6 +150,7 @@ void setBody(HttpURLConnection connection, Object bodyContents, boolean requires
137150

138151
abstract void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody)
139152
throws IOException;
153+
140154
}
141155

142156
private static Map<String, String> parseHeaders(HttpURLConnection conn) {
@@ -164,16 +178,41 @@ private static void addHeaders(HttpURLConnection connection, Map<String, String>
164178
}
165179
}
166180

181+
/*
182+
* Multipart implementation supporting more than one payload
183+
*
184+
*/
185+
private static void addBody(HttpURLConnection connection, OAuthRequest.MultipartPayloads multipartPayloads, boolean requiresBody) throws IOException {
186+
int contentLength = multipartPayloads.getContentLength();
187+
System.out.println("length: " + contentLength);
188+
if (requiresBody || contentLength > 0) {
189+
connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(contentLength));
190+
if (connection.getRequestProperty(CONTENT_TYPE) == null) {
191+
connection.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
192+
}
193+
System.out.println("content-length: " + connection.getRequestProperty(CONTENT_TYPE));
194+
connection.setDoOutput(true);
195+
OutputStream os = connection.getOutputStream();
196+
197+
int totalParts = multipartPayloads.getMultipartPayloadList().size();
198+
for (int i = 0; i < totalParts; i++) {
199+
os.write(multipartPayloads.getStartBoundary(i));
200+
os.write(multipartPayloads.getMultipartPayloadList().get(i).getPayload(), 0, multipartPayloads.getMultipartPayloadList().get(i).getLength());
201+
os.write(multipartPayloads.getEndBoundary(i));
202+
}
203+
}
204+
}
205+
167206
private static void addBody(HttpURLConnection connection, byte[] content, boolean requiresBody) throws IOException {
168207
final int contentLength = content.length;
169208
if (requiresBody || contentLength > 0) {
170209
connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(contentLength));
171-
172210
if (connection.getRequestProperty(CONTENT_TYPE) == null) {
173211
connection.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
174212
}
175213
connection.setDoOutput(true);
176214
connection.getOutputStream().write(content);
177215
}
178216
}
217+
179218
}

scribejava-core/src/main/java/com/github/scribejava/core/model/OAuthRequest.java

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,79 @@
77
import java.net.MalformedURLException;
88
import java.net.URL;
99
import java.nio.charset.Charset;
10+
import java.util.ArrayList;
1011
import java.util.HashMap;
12+
import java.util.List;
1113
import java.util.Map;
1214

15+
1316
/**
1417
* The representation of an OAuth HttpRequest.
1518
*/
1619
public class OAuthRequest {
17-
18-
private static final String OAUTH_PREFIX = "oauth_";
20+
/*
21+
* The class containing more than one payload of multipart/form-data request
22+
*/
23+
public class MultipartPayloads {
24+
private String boundary;
25+
private int contentLength;
26+
private List<MultipartPayload> multipartPayloadList;
27+
28+
public MultipartPayloads(String boundary) {
29+
this.boundary = boundary;
30+
this.multipartPayloadList = new ArrayList<>();
31+
}
32+
33+
public byte[] getStartBoundary(int index) {
34+
MultipartPayload multipartPaayLoad = multipartPayloadList.get(index);
35+
byte[] bytes = ("--" + boundary +"\r\n"
36+
+ "Content-Disposition: " + multipartPaayLoad.contentDisposition + "\r\n"
37+
+ (multipartPaayLoad == null ? "" : "Content-Type: " + multipartPaayLoad.contentType + "\r\n")
38+
+ "\r\n").getBytes();
39+
return bytes;
40+
}
41+
42+
public byte[] getEndBoundary(int index) {
43+
return ("\r\n"
44+
+ "--" + boundary + "--\r\n").getBytes();
45+
}
46+
47+
public int getContentLength() {
48+
return contentLength;
49+
}
50+
51+
public void addContentLength(int length) {
52+
this.contentLength += length;
53+
}
54+
55+
public List<MultipartPayload> getMultipartPayloadList() {
56+
return multipartPayloadList;
57+
}
58+
}
59+
60+
public class MultipartPayload {
61+
private String contentDisposition;
62+
private String contentType;
63+
private byte[] payload;
64+
private int length;
65+
66+
public MultipartPayload(String contentDisposition, String contentType, byte[] payload, int length) {
67+
this.contentDisposition = contentDisposition;
68+
this.contentType = contentType;
69+
this.payload = payload;
70+
this.length = length;
71+
}
72+
73+
public byte[] getPayload() {
74+
return payload;
75+
}
76+
77+
public int getLength() {
78+
return length;
79+
}
80+
}
81+
82+
private static final String OAUTH_PREFIX = "oauth_";
1983

2084
private final String url;
2185
private final Verb verb;
@@ -28,6 +92,7 @@ public class OAuthRequest {
2892
private String stringPayload;
2993
private byte[] byteArrayPayload;
3094
private File filePayload;
95+
private MultipartPayloads multipartPayloads;
3196

3297
private final Map<String, String> oauthParameters = new HashMap<>();
3398

@@ -123,7 +188,43 @@ public void addParameter(String key, String value) {
123188
querystringParams.add(key, value);
124189
}
125190
}
191+
126192

193+
/*
194+
* Set boundary of multipart request
195+
*
196+
* @param boundary can be any string
197+
*/
198+
public void setMultipartBoundary(String boundary) {
199+
multipartPayloads = new MultipartPayloads(boundary);
200+
}
201+
202+
203+
/*
204+
* Add one multipart form-data payload to the request & increase the current Content-Length
205+
*
206+
* @param contentDisposition value of Content-Disposition header
207+
* @param contentType value of Content-Type header
208+
* @param payload data array containing the data to send
209+
* @param length the max no of bytes to send
210+
*
211+
* Remarks:
212+
* 57 and 37 are the length of constant portions of contentDisposition and/or contentType headers
213+
* refer getStartBoundary and getEndBoundary for the constant
214+
*
215+
* Must be called after setMultipartBoundary method
216+
*/
217+
public void addMultipartPayload(String contentDisposition, String contentType, byte[] payload, int length) {
218+
int contentLenght;
219+
if (contentType == null)
220+
contentLenght = 37 + multipartPayloads.boundary.length() * 2 + contentDisposition.length() + payload.length;
221+
else
222+
contentLenght = 53 + multipartPayloads.boundary.length() * 2 + contentDisposition.length() + + contentType.length() + payload.length;
223+
multipartPayloads.addContentLength(contentLenght);
224+
225+
multipartPayloads.getMultipartPayloadList().add(new MultipartPayload(contentDisposition, contentType, payload, length));
226+
}
227+
127228
/**
128229
* Set body payload. This method is used when the HTTP body is not a form-url-encoded string, but another thing.
129230
* Like for example XML. Note: The contents are not part of the OAuth signature
@@ -159,6 +260,7 @@ private void resetPayload() {
159260
stringPayload = null;
160261
byteArrayPayload = null;
161262
filePayload = null;
263+
multipartPayloads = null;
162264
}
163265

164266
/**
@@ -237,6 +339,10 @@ public byte[] getByteArrayPayload() {
237339
}
238340
}
239341

342+
public MultipartPayloads getMultipartPayloads() {
343+
return multipartPayloads;
344+
}
345+
240346
public File getFilePayload() {
241347
return filePayload;
242348
}

scribejava-core/src/main/java/com/github/scribejava/core/oauth/OAuthService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@ public Response execute(OAuthRequest request) throws InterruptedException, Execu
110110
} else if (request.getStringPayload() != null) {
111111
return httpClient.execute(userAgent, request.getHeaders(), request.getVerb(), request.getCompleteUrl(),
112112
request.getStringPayload());
113-
} else {
113+
} else if (request.getMultipartPayloads() != null) {
114+
return httpClient.execute(userAgent, request.getHeaders(), request.getVerb(), request.getCompleteUrl(),
115+
request.getMultipartPayloads());
116+
}
117+
else {
114118
return httpClient.execute(userAgent, request.getHeaders(), request.getVerb(), request.getCompleteUrl(),
115119
request.getByteArrayPayload());
116120
}

scribejava-httpclient-okhttp/src/main/java/com/github/scribejava/httpclient/okhttp/OkHttpHttpClient.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,17 @@
44
import com.github.scribejava.core.model.OAuthAsyncRequestCallback;
55
import com.github.scribejava.core.model.OAuthConstants;
66
import com.github.scribejava.core.model.OAuthRequest;
7+
import com.github.scribejava.core.model.OAuthRequest.MultipartPayloads;
78
import com.github.scribejava.core.model.Verb;
89
import okhttp3.Call;
910
import okhttp3.MediaType;
1011
import okhttp3.OkHttpClient;
1112
import okhttp3.Request;
1213
import okhttp3.RequestBody;
1314
import okhttp3.internal.http.HttpMethod;
14-
1515
import java.io.IOException;
1616
import java.util.Map;
1717
import java.util.concurrent.Future;
18-
1918
import com.github.scribejava.core.model.Response;
2019
import java.io.File;
2120
import java.util.HashMap;
@@ -101,6 +100,12 @@ public Response execute(String userAgent, Map<String, String> headers, Verb http
101100
return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.FILE, bodyContents);
102101
}
103102

103+
@Override
104+
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
105+
MultipartPayloads multipartPayloads) throws InterruptedException, ExecutionException, IOException {
106+
throw new UnsupportedOperationException("OKHttpClient does not support Multipart payload for the moment");
107+
}
108+
104109
private Response doExecute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
105110
BodyType bodyType, Object bodyContents) throws IOException {
106111
final Call call = createCall(userAgent, headers, httpVerb, completeUrl, bodyType, bodyContents);
@@ -174,6 +179,6 @@ static Response convertResponse(okhttp3.Response okHttpResponse) {
174179
final ResponseBody body = okHttpResponse.body();
175180
return new Response(okHttpResponse.code(), okHttpResponse.message(), headersMap,
176181
body == null ? null : body.byteStream());
177-
178182
}
183+
179184
}

0 commit comments

Comments
 (0)