Skip to content

Commit b7d0c6d

Browse files
committed
add support for byte[] and File (async only) payload in OAuth Requests (thanks to https://github.com/keijohyttinen)
1 parent 36c33b6 commit b7d0c6d

File tree

8 files changed

+270
-34
lines changed

8 files changed

+270
-34
lines changed

changelog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[SNAPSHOT]
22
* uncouple OAuthRequest and Service. OAuthRequest shouldn't know anything about OAuthservice.
33
You don't need OAuthService to create OAuthRequest anymore. Async request should be sent via OAuthService method.
4+
* add support for byte[] and File (async only) payload in OAuth Requests (thanks to https://github.com/keijohyttinen)
45

56
[3.3.0]
67
* update Facebook v2.6 -> v2.8

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

Lines changed: 80 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.util.Map;
99
import com.github.scribejava.core.exceptions.OAuthException;
1010
import com.github.scribejava.core.oauth.OAuthService;
11+
import java.io.File;
1112

1213
/**
1314
* The representation of an OAuth HttpRequest.
@@ -26,9 +27,12 @@ public abstract class AbstractRequest {
2627
private final Map<String, String> headers = new HashMap<>();
2728
private boolean followRedirects = true;
2829

29-
private String payload;
3030
private String charset;
31-
private byte[] bytePayload;
31+
32+
private String stringPayload;
33+
private byte[] byteArrayPayload;
34+
private File filePayload;
35+
3236
private final Map<String, String> oauthParameters = new HashMap<>();
3337

3438
private String realm;
@@ -142,22 +146,58 @@ protected boolean hasBodyContent() {
142146
}
143147

144148
/**
145-
* Add body payload. This method is used when the HTTP body is not a form-url-encoded string, but another thing.
149+
* @param payload payload
150+
* @deprecated use {@link #setPayload(java.lang.String) }
151+
*/
152+
@Deprecated
153+
public void addPayload(String payload) {
154+
setPayload(payload);
155+
}
156+
157+
/**
158+
* @param payload payload
159+
* @deprecated use {@link #setPayload(byte[]) }
160+
*/
161+
@Deprecated
162+
public void addPayload(byte[] payload) {
163+
setPayload(payload);
164+
}
165+
166+
/**
167+
* Set body payload. This method is used when the HTTP body is not a form-url-encoded string, but another thing.
146168
* Like for example XML. Note: The contents are not part of the OAuth signature
147169
*
148170
* @param payload the body of the request
149171
*/
150-
public void addPayload(String payload) {
151-
this.payload = payload;
172+
public void setPayload(String payload) {
173+
resetPayload();
174+
stringPayload = payload;
152175
}
153176

154177
/**
155178
* Overloaded version for byte arrays
156179
*
157180
* @param payload byte[]
158181
*/
159-
public void addPayload(byte[] payload) {
160-
this.bytePayload = payload.clone();
182+
public void setPayload(byte[] payload) {
183+
resetPayload();
184+
byteArrayPayload = payload.clone();
185+
}
186+
187+
/**
188+
* Overloaded version for File
189+
*
190+
* @param payload File
191+
*/
192+
public void setPayload(File payload) {
193+
resetPayload();
194+
filePayload = payload;
195+
}
196+
197+
private void resetPayload() {
198+
stringPayload = null;
199+
byteArrayPayload = null;
200+
filePayload = null;
161201
}
162202

163203
/**
@@ -212,32 +252,54 @@ public String getSanitizedUrl() {
212252
}
213253

214254
/**
215-
* Returns the body of the request
255+
* @return value set in {@link #setPayload(java.lang.String)}
256+
* @deprecated use {@link #getStringPayload()} or {@link #getByteArrayPayload()}
257+
*/
258+
@Deprecated
259+
public String getBodyContents() {
260+
return getStringPayload();
261+
}
262+
263+
/**
264+
* Returns the body of the request (set in {@link #setPayload(java.lang.String)})
216265
*
217266
* @return form encoded string
218267
*
219268
* @throws OAuthException if the charset chosen is not supported
220269
*/
221-
public String getBodyContents() {
222-
try {
223-
return new String(getByteBodyContents(), getCharset());
224-
} catch (UnsupportedEncodingException uee) {
225-
throw new OAuthException("Unsupported Charset: " + charset, uee);
226-
}
270+
public String getStringPayload() {
271+
return stringPayload;
272+
}
273+
274+
/**
275+
* @return value set in {@link #setPayload(byte[])}
276+
* @deprecated use {@link #getByteArrayPayload() }
277+
*/
278+
@Deprecated
279+
public byte[] getByteBodyContents() {
280+
return getByteArrayPayload();
227281
}
228282

229-
byte[] getByteBodyContents() {
230-
if (bytePayload != null) {
231-
return bytePayload;
283+
/**
284+
* @return the body of the request (set in {@link #setPayload(byte[])} or in
285+
* {@link #addBodyParameter(java.lang.String, java.lang.String)} )
286+
*/
287+
public byte[] getByteArrayPayload() {
288+
if (byteArrayPayload != null) {
289+
return byteArrayPayload;
232290
}
233-
final String body = (payload == null) ? bodyParams.asFormUrlEncodedString() : payload;
291+
final String body = bodyParams.asFormUrlEncodedString();
234292
try {
235293
return body.getBytes(getCharset());
236294
} catch (UnsupportedEncodingException uee) {
237295
throw new OAuthException("Unsupported Charset: " + getCharset(), uee);
238296
}
239297
}
240298

299+
public File getFilePayload() {
300+
return filePayload;
301+
}
302+
241303
@Override
242304
public String toString() {
243305
return String.format("@Request(%s %s)", getVerb(), getUrl());

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
package com.github.scribejava.core.model;
22

3+
import java.io.File;
34
import java.io.IOException;
45
import java.util.Map;
56
import java.util.concurrent.Future;
67

78
public interface HttpClient {
9+
810
void close() throws IOException;
911

1012
<T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
11-
String bodyContents, OAuthAsyncRequestCallback<T> callback,
12-
OAuthRequestAsync.ResponseConverter<T> converter);
13+
byte[] bodyContents, OAuthAsyncRequestCallback<T> callback,
14+
OAuthRequestAsync.ResponseConverter<T> converter);
15+
16+
<T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
17+
String bodyContents, OAuthAsyncRequestCallback<T> callback,
18+
OAuthRequestAsync.ResponseConverter<T> converter);
19+
20+
<T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
21+
File bodyContents, OAuthAsyncRequestCallback<T> callback, OAuthRequestAsync.ResponseConverter<T> converter);
1322

1423
interface Config {
1524
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.github.scribejava.core.exceptions.OAuthConnectionException;
88
import com.github.scribejava.core.exceptions.OAuthException;
99
import com.github.scribejava.core.oauth.OAuthService;
10+
import java.io.File;
1011

1112
public class OAuthRequest extends AbstractRequest {
1213

@@ -69,7 +70,14 @@ Response doSend() throws IOException {
6970
}
7071
addHeaders();
7172
if (hasBodyContent()) {
72-
addBody(getByteBodyContents());
73+
final File filePayload = getFilePayload();
74+
if (filePayload != null) {
75+
throw new UnsupportedOperationException("Sync Requests do not support File payload for the moment");
76+
} else if (getStringPayload() != null) {
77+
addBody(getStringPayload().getBytes(getCharset()));
78+
} else {
79+
addBody(getByteArrayPayload());
80+
}
7381
}
7482
return new Response(connection);
7583
}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.github.scribejava.core.model.ScribeJavaConfig;
1414
import com.github.scribejava.core.model.Token;
1515
import com.github.scribejava.core.model.Verb;
16+
import java.io.File;
1617

1718
import java.io.IOException;
1819
import java.util.Map;
@@ -127,8 +128,17 @@ public <T> Future<T> execute(OAuthRequestAsync request, OAuthAsyncRequestCallbac
127128
config.log("Cannot use async operations, only sync");
128129
}
129130

130-
return httpClient.executeAsync(config.getUserAgent(), request.getHeaders(), request.getVerb(),
131-
request.getCompleteUrl(), request.getBodyContents(), callback, converter);
131+
final File filePayload = request.getFilePayload();
132+
if (filePayload != null) {
133+
return httpClient.executeAsync(config.getUserAgent(), request.getHeaders(), request.getVerb(),
134+
request.getCompleteUrl(), filePayload, callback, converter);
135+
} else if (request.getStringPayload() != null) {
136+
return httpClient.executeAsync(config.getUserAgent(), request.getHeaders(), request.getVerb(),
137+
request.getCompleteUrl(), request.getStringPayload(), callback, converter);
138+
} else {
139+
return httpClient.executeAsync(config.getUserAgent(), request.getHeaders(), request.getVerb(),
140+
request.getCompleteUrl(), request.getByteArrayPayload(), callback, converter);
141+
}
132142
}
133143

134144
public Future<Response> execute(OAuthRequestAsync request, OAuthAsyncRequestCallback<Response> callback) {

scribejava-core/src/test/java/com/github/scribejava/core/model/RequestTest.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,17 @@ public void shouldAddRequestHeaders() {
5151

5252
@Test
5353
public void shouldSetBodyParamsAndAddContentLength() {
54-
assertEquals("param=value&param%20with%20spaces=value%20with%20spaces", postRequest.getBodyContents());
54+
assertEquals("param=value&param%20with%20spaces=value%20with%20spaces",
55+
new String(postRequest.getByteArrayPayload()));
5556
postRequest.send();
5657
assertTrue(connection.getHeaders().containsKey("Content-Length"));
5758
}
5859

5960
@Test
6061
public void shouldSetPayloadAndHeaders() {
61-
postRequest.addPayload("PAYLOAD");
62+
postRequest.setPayload("PAYLOAD");
6263
postRequest.send();
63-
assertEquals("PAYLOAD", postRequest.getBodyContents());
64+
assertEquals("PAYLOAD", postRequest.getStringPayload());
6465
assertTrue(connection.getHeaders().containsKey("Content-Length"));
6566
}
6667

@@ -87,14 +88,14 @@ public void shouldHandleQueryStringSpaceEncodingProperly() {
8788

8889
@Test
8990
public void shouldAutomaticallyAddContentTypeForPostRequestsWithBytePayload() {
90-
postRequest.addPayload("PAYLOAD".getBytes());
91+
postRequest.setPayload("PAYLOAD".getBytes());
9192
postRequest.send();
9293
assertEquals(OAuthRequest.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type"));
9394
}
9495

9596
@Test
9697
public void shouldAutomaticallyAddContentTypeForPostRequestsWithStringPayload() {
97-
postRequest.addPayload("PAYLOAD");
98+
postRequest.setPayload("PAYLOAD");
9899
postRequest.send();
99100
assertEquals(OAuthRequest.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type"));
100101
}

scribejava-httpclient-ahc/src/main/java/com/github/scribejava/httpclient/ahc/AhcHttpClient.java

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.concurrent.Future;
1515

1616
import static com.github.scribejava.core.model.AbstractRequest.DEFAULT_CONTENT_TYPE;
17+
import java.io.File;
1718
import org.asynchttpclient.BoundRequestBuilder;
1819

1920
public class AhcHttpClient implements HttpClient {
@@ -35,8 +36,31 @@ public void close() throws IOException {
3536

3637
@Override
3738
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
38-
String bodyContents, OAuthAsyncRequestCallback<T> callback,
39-
OAuthRequestAsync.ResponseConverter<T> converter) {
39+
byte[] bodyContents, OAuthAsyncRequestCallback<T> callback,
40+
OAuthRequestAsync.ResponseConverter<T> converter) {
41+
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new ByteArrayBodySetter(bodyContents),
42+
callback, converter);
43+
}
44+
45+
@Override
46+
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
47+
String bodyContents, OAuthAsyncRequestCallback<T> callback,
48+
OAuthRequestAsync.ResponseConverter<T> converter) {
49+
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new StringBodySetter(bodyContents), callback,
50+
converter);
51+
}
52+
53+
@Override
54+
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
55+
File bodyContents, OAuthAsyncRequestCallback<T> callback,
56+
OAuthRequestAsync.ResponseConverter<T> converter) {
57+
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, new FileBodySetter(bodyContents), callback,
58+
converter);
59+
}
60+
61+
private <T> Future<T> doExecuteAsync(String userAgent, Map<String, String> headers, Verb httpVerb,
62+
String completeUrl, BodySetter bodySetter, OAuthAsyncRequestCallback<T> callback,
63+
OAuthRequestAsync.ResponseConverter<T> converter) {
4064
final BoundRequestBuilder boundRequestBuilder;
4165
switch (httpVerb) {
4266
case GET:
@@ -47,7 +71,7 @@ public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers,
4771
if (!headers.containsKey(AbstractRequest.CONTENT_TYPE)) {
4872
requestBuilder = requestBuilder.addHeader(AbstractRequest.CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
4973
}
50-
boundRequestBuilder = requestBuilder.setBody(bodyContents);
74+
boundRequestBuilder = bodySetter.setBody(requestBuilder);
5175
break;
5276
default:
5377
throw new IllegalArgumentException("message build error: unknown verb type");
@@ -64,4 +88,51 @@ public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers,
6488
.execute(new OAuthAsyncCompletionHandler<>(
6589
callback, converter));
6690
}
91+
92+
private interface BodySetter {
93+
94+
BoundRequestBuilder setBody(BoundRequestBuilder requestBuilder);
95+
}
96+
97+
private static class ByteArrayBodySetter implements BodySetter {
98+
99+
private final byte[] bodyContents;
100+
101+
private ByteArrayBodySetter(byte[] bodyContents) {
102+
this.bodyContents = bodyContents;
103+
}
104+
105+
@Override
106+
public BoundRequestBuilder setBody(BoundRequestBuilder requestBuilder) {
107+
return requestBuilder.setBody(bodyContents);
108+
}
109+
}
110+
111+
private static class StringBodySetter implements BodySetter {
112+
113+
private final String bodyContents;
114+
115+
private StringBodySetter(String bodyContents) {
116+
this.bodyContents = bodyContents;
117+
}
118+
119+
@Override
120+
public BoundRequestBuilder setBody(BoundRequestBuilder requestBuilder) {
121+
return requestBuilder.setBody(bodyContents);
122+
}
123+
}
124+
125+
private static class FileBodySetter implements BodySetter {
126+
127+
private final File bodyContents;
128+
129+
private FileBodySetter(File bodyContents) {
130+
this.bodyContents = bodyContents;
131+
}
132+
133+
@Override
134+
public BoundRequestBuilder setBody(BoundRequestBuilder requestBuilder) {
135+
return requestBuilder.setBody(bodyContents);
136+
}
137+
}
67138
}

0 commit comments

Comments
 (0)