aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNarayan Kamath <narayan@google.com>2016-01-20 18:08:31 +0000
committerandroid-build-merger <android-build-merger@google.com>2016-01-20 18:08:31 +0000
commita7a2ee6078ede705530d0ae0cfc94fea67bc34b5 (patch)
tree987353bba7afe1de0851df174bb41388e843816d
parentdc219ce3f3fe8bb6974da904d4c138e6ba816ed0 (diff)
parent51385e0ead07dd4a3d5f99e86b20fb3edc1d6f6f (diff)
downloadokhttp-a7a2ee6078ede705530d0ae0cfc94fea67bc34b5.tar.gz
Merge "Permit space to be encoded as + or %20." am: 0202993c54
am: 51385e0ead * commit '51385e0ead07dd4a3d5f99e86b20fb3edc1d6f6f': Permit space to be encoded as + or %20.
-rw-r--r--okhttp-tests/src/test/java/com/squareup/okhttp/FormEncodingBuilderTest.java6
-rw-r--r--okhttp-tests/src/test/java/com/squareup/okhttp/HttpUrlTest.java4
-rw-r--r--okhttp/src/main/java/com/squareup/okhttp/HttpUrl.java52
3 files changed, 33 insertions, 29 deletions
diff --git a/okhttp-tests/src/test/java/com/squareup/okhttp/FormEncodingBuilderTest.java b/okhttp-tests/src/test/java/com/squareup/okhttp/FormEncodingBuilderTest.java
index 04e74a4..cb54aef 100644
--- a/okhttp-tests/src/test/java/com/squareup/okhttp/FormEncodingBuilderTest.java
+++ b/okhttp-tests/src/test/java/com/squareup/okhttp/FormEncodingBuilderTest.java
@@ -24,14 +24,14 @@ import static org.junit.Assert.assertEquals;
public final class FormEncodingBuilderTest {
@Test public void urlEncoding() throws Exception {
RequestBody formEncoding = new FormEncodingBuilder()
- .add("a&b", "c=d")
+ .add("a+=& b", "c+=& d")
.add("space, the", "final frontier")
.add("%25", "%25")
.build();
assertEquals("application/x-www-form-urlencoded", formEncoding.contentType().toString());
- String expected = "a%26b=c%3Dd&space%2C%20the=final%20frontier&%2525=%2525";
+ String expected = "a%2B%3D%26%20b=c%2B%3D%26%20d&space%2C%20the=final%20frontier&%2525=%2525";
assertEquals(expected.length(), formEncoding.contentLength());
Buffer out = new Buffer();
@@ -46,7 +46,7 @@ public final class FormEncodingBuilderTest {
.addEncoded("%25", "%25")
.build();
- String expected = "a%20%3D%26%20b=c%20%3D%26%20d&e%20%3D%26%20f=g%20%3D%26%20h&%25=%25";
+ String expected = "a+%3D%26%20b=c+%3D%26%20d&e+%3D%26%20f=g+%3D%26%20h&%25=%25";
Buffer out = new Buffer();
formEncoding.writeTo(out);
assertEquals(expected, out.readUtf8());
diff --git a/okhttp-tests/src/test/java/com/squareup/okhttp/HttpUrlTest.java b/okhttp-tests/src/test/java/com/squareup/okhttp/HttpUrlTest.java
index 371480f..4ec595d 100644
--- a/okhttp-tests/src/test/java/com/squareup/okhttp/HttpUrlTest.java
+++ b/okhttp-tests/src/test/java/com/squareup/okhttp/HttpUrlTest.java
@@ -1006,7 +1006,7 @@ public final class HttpUrlTest {
@Test public void composeQueryWithEncodedComponents() throws Exception {
HttpUrl base = HttpUrl.parse("http://host/");
HttpUrl url = base.newBuilder().addEncodedQueryParameter("a+=& b", "c+=& d").build();
- assertEquals("http://host/?a%20%3D%26%20b=c%20%3D%26%20d", url.toString());
+ assertEquals("http://host/?a+%3D%26%20b=c+%3D%26%20d", url.toString());
assertEquals("c =& d", url.queryParameter("a =& b"));
}
@@ -1042,7 +1042,7 @@ public final class HttpUrlTest {
.addEncodedQueryParameter("a+=& b", "c+=& d")
.setEncodedQueryParameter("a+=& b", "ef")
.build();
- assertEquals("http://host/?a%20%3D%26%20b=ef", url.toString());
+ assertEquals("http://host/?a+%3D%26%20b=ef", url.toString());
assertEquals("ef", url.queryParameter("a =& b"));
}
diff --git a/okhttp/src/main/java/com/squareup/okhttp/HttpUrl.java b/okhttp/src/main/java/com/squareup/okhttp/HttpUrl.java
index ae80c29..dcc2596 100644
--- a/okhttp/src/main/java/com/squareup/okhttp/HttpUrl.java
+++ b/okhttp/src/main/java/com/squareup/okhttp/HttpUrl.java
@@ -301,16 +301,16 @@ public final class HttpUrl {
private HttpUrl(Builder builder) {
this.scheme = builder.scheme;
- this.username = percentDecode(builder.encodedUsername);
- this.password = percentDecode(builder.encodedPassword);
+ this.username = percentDecode(builder.encodedUsername, false);
+ this.password = percentDecode(builder.encodedPassword, false);
this.host = builder.host;
this.port = builder.effectivePort();
- this.pathSegments = percentDecode(builder.encodedPathSegments);
+ this.pathSegments = percentDecode(builder.encodedPathSegments, false);
this.queryNamesAndValues = builder.encodedQueryNamesAndValues != null
- ? percentDecode(builder.encodedQueryNamesAndValues)
+ ? percentDecode(builder.encodedQueryNamesAndValues, true)
: null;
this.fragment = builder.encodedFragment != null
- ? percentDecode(builder.encodedFragment)
+ ? percentDecode(builder.encodedFragment, false)
: null;
this.url = builder.toString();
}
@@ -1227,7 +1227,7 @@ public final class HttpUrl {
private static String canonicalizeHost(String input, int pos, int limit) {
// Start by percent decoding the host. The WHATWG spec suggests doing this only after we've
// checked for IPv6 square braces. But Chrome does it first, and that's more lenient.
- String percentDecoded = percentDecode(input, pos, limit);
+ String percentDecoded = percentDecode(input, pos, limit, false);
// If the input is encased in square braces "[...]", drop 'em. We have an IPv6 address.
if (percentDecoded.startsWith("[") && percentDecoded.endsWith("]")) {
@@ -1447,26 +1447,26 @@ public final class HttpUrl {
return limit;
}
- static String percentDecode(String encoded) {
- return percentDecode(encoded, 0, encoded.length());
+ static String percentDecode(String encoded, boolean plusIsSpace) {
+ return percentDecode(encoded, 0, encoded.length(), plusIsSpace);
}
- private List<String> percentDecode(List<String> list) {
+ private List<String> percentDecode(List<String> list, boolean plusIsSpace) {
List<String> result = new ArrayList<>(list.size());
for (String s : list) {
- result.add(s != null ? percentDecode(s) : null);
+ result.add(s != null ? percentDecode(s, plusIsSpace) : null);
}
return Collections.unmodifiableList(result);
}
- static String percentDecode(String encoded, int pos, int limit) {
+ static String percentDecode(String encoded, int pos, int limit, boolean plusIsSpace) {
for (int i = pos; i < limit; i++) {
char c = encoded.charAt(i);
- if (c == '%') {
+ if (c == '%' || (c == '+' && plusIsSpace)) {
// Slow path: the character at i requires decoding!
Buffer out = new Buffer();
out.writeUtf8(encoded, pos, i);
- percentDecode(out, encoded, i, limit);
+ percentDecode(out, encoded, i, limit, plusIsSpace);
return out.readUtf8();
}
}
@@ -1475,7 +1475,7 @@ public final class HttpUrl {
return encoded.substring(pos, limit);
}
- static void percentDecode(Buffer out, String encoded, int pos, int limit) {
+ static void percentDecode(Buffer out, String encoded, int pos, int limit, boolean plusIsSpace) {
int codePoint;
for (int i = pos; i < limit; i += Character.charCount(codePoint)) {
codePoint = encoded.codePointAt(i);
@@ -1487,6 +1487,9 @@ public final class HttpUrl {
i += 2;
continue;
}
+ } else if (codePoint == '+' && plusIsSpace) {
+ out.writeByte(' ');
+ continue;
}
out.writeUtf8CodePoint(codePoint);
}
@@ -1511,10 +1514,10 @@ public final class HttpUrl {
* </ul>
*
* @param alreadyEncoded true to leave '%' as-is; false to convert it to '%25'.
- * @param query true if to encode ' ' as '+', and '+' as "%2B".
+ * @param plusIsSpace true to encode '+' as "%2B" if it is not already encoded
*/
static String canonicalize(String input, int pos, int limit, String encodeSet,
- boolean alreadyEncoded, boolean query) {
+ boolean alreadyEncoded, boolean plusIsSpace) {
int codePoint;
for (int i = pos; i < limit; i += Character.charCount(codePoint)) {
codePoint = input.codePointAt(i);
@@ -1522,11 +1525,11 @@ public final class HttpUrl {
|| codePoint >= 0x7f
|| encodeSet.indexOf(codePoint) != -1
|| (codePoint == '%' && !alreadyEncoded)
- || (query && codePoint == '+')) {
+ || (codePoint == '+' && plusIsSpace)) {
// Slow path: the character at i requires encoding!
Buffer out = new Buffer();
out.writeUtf8(input, pos, i);
- canonicalize(out, input, i, limit, encodeSet, alreadyEncoded, query);
+ canonicalize(out, input, i, limit, encodeSet, alreadyEncoded, plusIsSpace);
return out.readUtf8();
}
}
@@ -1536,7 +1539,7 @@ public final class HttpUrl {
}
static void canonicalize(Buffer out, String input, int pos, int limit,
- String encodeSet, boolean alreadyEncoded, boolean query) {
+ String encodeSet, boolean alreadyEncoded, boolean plusIsSpace) {
Buffer utf8Buffer = null; // Lazily allocated.
int codePoint;
for (int i = pos; i < limit; i += Character.charCount(codePoint)) {
@@ -1544,9 +1547,9 @@ public final class HttpUrl {
if (alreadyEncoded
&& (codePoint == '\t' || codePoint == '\n' || codePoint == '\f' || codePoint == '\r')) {
// Skip this character.
- } else if (query && codePoint == '+') {
- // HTML permits space to be encoded as '+'. We use '%20' to avoid special cases.
- out.writeUtf8(alreadyEncoded ? "%20" : "%2B");
+ } else if (codePoint == '+' && plusIsSpace) {
+ // Encode '+' as '%2B' since we permit ' ' to be encoded as either '+' or '%20'.
+ out.writeUtf8(alreadyEncoded ? "+" : "%2B");
} else if (codePoint < 0x20
|| codePoint >= 0x7f
|| encodeSet.indexOf(codePoint) != -1
@@ -1570,7 +1573,8 @@ public final class HttpUrl {
}
static String canonicalize(
- String input, String encodeSet, boolean alreadyEncoded, boolean query) {
- return canonicalize(input, 0, input.length(), encodeSet, alreadyEncoded, query);
+ String input, String encodeSet, boolean alreadyEncoded, boolean plusIsSpace) {
+ return canonicalize(
+ input, 0, input.length(), encodeSet, alreadyEncoded, plusIsSpace);
}
}