diff options
author | Narayan Kamath <narayan@google.com> | 2016-01-20 18:08:31 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-01-20 18:08:31 +0000 |
commit | a7a2ee6078ede705530d0ae0cfc94fea67bc34b5 (patch) | |
tree | 987353bba7afe1de0851df174bb41388e843816d | |
parent | dc219ce3f3fe8bb6974da904d4c138e6ba816ed0 (diff) | |
parent | 51385e0ead07dd4a3d5f99e86b20fb3edc1d6f6f (diff) | |
download | okhttp-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.
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); } } |