Skip to content

Commit 9ab7016

Browse files
feat: add flag to allow UrlEncodedContent to use UriPath escaping (#1100)
Fixes #1098 The legacy behavior is kept. Test has been updated
1 parent 407e385 commit 9ab7016

File tree

2 files changed

+56
-14
lines changed

2 files changed

+56
-14
lines changed

google-http-client/src/main/java/com/google/api/client/http/UrlEncodedContent.java

+36-7
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,43 @@
4242
*
4343
* <p>Implementation is not thread-safe.
4444
*
45-
* @since 1.0
4645
* @author Yaniv Inbar
46+
* @since 1.0
4747
*/
4848
public class UrlEncodedContent extends AbstractHttpContent {
4949

5050
/** Key name/value data. */
5151
private Object data;
5252

53-
/** @param data key name/value data */
53+
/** Use URI Path encoder flag. False by default (use legacy and deprecated escapeUri) */
54+
private boolean uriPathEncodingFlag;
55+
56+
/**
57+
* Initialize the UrlEncodedContent with the legacy and deprecated escapeUri encoder
58+
*
59+
* @param data key name/value data
60+
*/
5461
public UrlEncodedContent(Object data) {
5562
super(UrlEncodedParser.MEDIA_TYPE);
5663
setData(data);
64+
this.uriPathEncodingFlag = false;
5765
}
5866

67+
/**
68+
* Initialize the UrlEncodedContent with or without the legacy and deprecated escapeUri encoder
69+
*
70+
* @param data key name/value data
71+
* @param useUriPathEncoding escapes the string value so it can be safely included in URI path
72+
* segments. For details on escaping URIs, see <a
73+
* href="http://tools.ietf.org/html/rfc3986#section-2.4">RFC 3986 - section 2.4</a>
74+
*/
75+
public UrlEncodedContent(Object data, boolean useUriPathEncoding) {
76+
super(UrlEncodedParser.MEDIA_TYPE);
77+
setData(data);
78+
this.uriPathEncodingFlag = useUriPathEncoding;
79+
}
80+
81+
@Override
5982
public void writeTo(OutputStream out) throws IOException {
6083
Writer writer = new BufferedWriter(new OutputStreamWriter(out, getCharset()));
6184
boolean first = true;
@@ -66,10 +89,10 @@ public void writeTo(OutputStream out) throws IOException {
6689
Class<? extends Object> valueClass = value.getClass();
6790
if (value instanceof Iterable<?> || valueClass.isArray()) {
6891
for (Object repeatedValue : Types.iterableOf(value)) {
69-
first = appendParam(first, writer, name, repeatedValue);
92+
first = appendParam(first, writer, name, repeatedValue, this.uriPathEncodingFlag);
7093
}
7194
} else {
72-
first = appendParam(first, writer, name, value);
95+
first = appendParam(first, writer, name, value, this.uriPathEncodingFlag);
7396
}
7497
}
7598
}
@@ -125,7 +148,8 @@ public static UrlEncodedContent getContent(HttpRequest request) {
125148
return result;
126149
}
127150

128-
private static boolean appendParam(boolean first, Writer writer, String name, Object value)
151+
private static boolean appendParam(
152+
boolean first, Writer writer, String name, Object value, boolean uriPathEncodingFlag)
129153
throws IOException {
130154
// ignore nulls
131155
if (value == null || Data.isNull(value)) {
@@ -139,8 +163,13 @@ private static boolean appendParam(boolean first, Writer writer, String name, Ob
139163
}
140164
writer.write(name);
141165
String stringValue =
142-
CharEscapers.escapeUri(
143-
value instanceof Enum<?> ? FieldInfo.of((Enum<?>) value).getName() : value.toString());
166+
value instanceof Enum<?> ? FieldInfo.of((Enum<?>) value).getName() : value.toString();
167+
168+
if (uriPathEncodingFlag) {
169+
stringValue = CharEscapers.escapeUriPath(stringValue);
170+
} else {
171+
stringValue = CharEscapers.escapeUri(stringValue);
172+
}
144173
if (stringValue.length() != 0) {
145174
writer.write("=");
146175
writer.write(stringValue);

google-http-client/src/test/java/com/google/api/client/http/UrlEncodedContentTest.java

+20-7
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,32 @@
3333
public class UrlEncodedContentTest extends TestCase {
3434

3535
public void testWriteTo() throws IOException {
36-
subtestWriteTo("a=x", ArrayMap.of("a", "x"));
37-
subtestWriteTo("noval", ArrayMap.of("noval", ""));
38-
subtestWriteTo("multi=a&multi=b&multi=c", ArrayMap.of("multi", Arrays.asList("a", "b", "c")));
39-
subtestWriteTo("multi=a&multi=b&multi=c", ArrayMap.of("multi", new String[] {"a", "b", "c"}));
36+
subtestWriteTo("a=x", ArrayMap.of("a", "x"), false);
37+
subtestWriteTo("noval", ArrayMap.of("noval", ""), false);
38+
subtestWriteTo(
39+
"multi=a&multi=b&multi=c", ArrayMap.of("multi", Arrays.asList("a", "b", "c")), false);
40+
subtestWriteTo(
41+
"multi=a&multi=b&multi=c", ArrayMap.of("multi", new String[] {"a", "b", "c"}), false);
4042
// https://github.com/googleapis/google-http-java-client/issues/202
4143
final Map<String, String> params = new LinkedHashMap<String, String>();
4244
params.put("username", "un");
4345
params.put("password", "password123;{}");
44-
subtestWriteTo("username=un&password=password123%3B%7B%7D", params);
46+
subtestWriteTo("username=un&password=password123%3B%7B%7D", params, false);
47+
subtestWriteTo("additionkey=add%2Btion", ArrayMap.of("additionkey", "add+tion"), false);
48+
49+
subtestWriteTo("a=x", ArrayMap.of("a", "x"), true);
50+
subtestWriteTo("noval", ArrayMap.of("noval", ""), true);
51+
subtestWriteTo(
52+
"multi=a&multi=b&multi=c", ArrayMap.of("multi", Arrays.asList("a", "b", "c")), true);
53+
subtestWriteTo(
54+
"multi=a&multi=b&multi=c", ArrayMap.of("multi", new String[] {"a", "b", "c"}), true);
55+
subtestWriteTo("username=un&password=password123;%7B%7D", params, true);
56+
subtestWriteTo("additionkey=add+tion", ArrayMap.of("additionkey", "add+tion"), true);
4557
}
4658

47-
private void subtestWriteTo(String expected, Object data) throws IOException {
48-
UrlEncodedContent content = new UrlEncodedContent(data);
59+
private void subtestWriteTo(String expected, Object data, boolean useEscapeUriPathEncoding)
60+
throws IOException {
61+
UrlEncodedContent content = new UrlEncodedContent(data, useEscapeUriPathEncoding);
4962
ByteArrayOutputStream out = new ByteArrayOutputStream();
5063
content.writeTo(out);
5164
assertEquals(expected, out.toString());

0 commit comments

Comments
 (0)