1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-17 08:42:25 +03:00

New FormEncodingBuilder.addEncoded() API.

This is a behavior change: previously we'd encode '+' as plus
and encode characters that don't need it, including ','. Now
we use the same rules as HttpUrl.
This commit is contained in:
jwilson
2015-05-14 22:53:01 -04:00
parent e0f8b9087a
commit 3103cb1dbc
3 changed files with 47 additions and 24 deletions

View File

@@ -25,11 +25,12 @@ public final class FormEncodingBuilderTest {
RequestBody formEncoding = new FormEncodingBuilder()
.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+the=final+frontier";
String expected = "a%26b=c%3Dd&space,%20the=final%20frontier&%2525=%2525";
assertEquals(expected.length(), formEncoding.contentLength());
Buffer out = new Buffer();
@@ -37,6 +38,19 @@ public final class FormEncodingBuilderTest {
assertEquals(expected, out.readUtf8());
}
@Test public void addEncoded() throws Exception {
RequestBody formEncoding = new FormEncodingBuilder()
.addEncoded("a+=& b", "c+=& d")
.addEncoded("e+=& f", "g+=& h")
.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";
Buffer out = new Buffer();
formEncoding.writeTo(out);
assertEquals(expected, out.readUtf8());
}
@Test public void encodedPair() throws Exception {
RequestBody formEncoding = new FormEncodingBuilder()
.add("sim", "ple")

View File

@@ -15,8 +15,6 @@
*/
package com.squareup.okhttp;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import okio.Buffer;
/**
@@ -34,13 +32,24 @@ public final class FormEncodingBuilder {
if (content.size() > 0) {
content.writeByte('&');
}
try {
content.writeUtf8(URLEncoder.encode(name, "UTF-8"));
content.writeByte('=');
content.writeUtf8(URLEncoder.encode(value, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
HttpUrl.canonicalize(content, name, 0, name.length(),
HttpUrl.QUERY_COMPONENT_ENCODE_SET, false, true);
content.writeByte('=');
HttpUrl.canonicalize(content, value, 0, value.length(),
HttpUrl.QUERY_COMPONENT_ENCODE_SET, false, true);
return this;
}
/** Add new key-value pair. */
public FormEncodingBuilder addEncoded(String name, String value) {
if (content.size() > 0) {
content.writeByte('&');
}
HttpUrl.canonicalize(content, name, 0, name.length(),
HttpUrl.QUERY_COMPONENT_ENCODE_SET, true, true);
content.writeByte('=');
HttpUrl.canonicalize(content, value, 0, value.length(),
HttpUrl.QUERY_COMPONENT_ENCODE_SET, true, true);
return this;
}

View File

@@ -255,12 +255,12 @@ import okio.Buffer;
public final class HttpUrl {
private static final char[] HEX_DIGITS =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
private static final String USERNAME_ENCODE_SET = " \"':;<=>@[]^`{}|/\\?#";
private static final String PASSWORD_ENCODE_SET = " \"':;<=>@[]\\^`{}|/\\?#";
private static final String PATH_SEGMENT_ENCODE_SET = " \"<>^`{}|/\\?#";
private static final String QUERY_ENCODE_SET = " \"'<>#";
private static final String QUERY_COMPONENT_ENCODE_SET = " \"'<>#&=";
private static final String FRAGMENT_ENCODE_SET = "";
static final String USERNAME_ENCODE_SET = " \"':;<=>@[]^`{}|/\\?#";
static final String PASSWORD_ENCODE_SET = " \"':;<=>@[]\\^`{}|/\\?#";
static final String PATH_SEGMENT_ENCODE_SET = " \"<>^`{}|/\\?#";
static final String QUERY_ENCODE_SET = " \"'<>#";
static final String QUERY_COMPONENT_ENCODE_SET = " \"'<>#&=";
static final String FRAGMENT_ENCODE_SET = "";
/** Either "http" or "https". */
private final String scheme;
@@ -1422,10 +1422,10 @@ public final class HttpUrl {
|| (codePoint == '%' && !alreadyEncoded)
|| (query && codePoint == '+')) {
// Slow path: the character at i requires encoding!
StringBuilder out = new StringBuilder();
out.append(input, pos, i);
Buffer out = new Buffer();
out.writeUtf8(input, pos, i);
canonicalize(out, input, i, limit, encodeSet, alreadyEncoded, query);
return out.toString();
return out.readUtf8();
}
}
@@ -1433,7 +1433,7 @@ public final class HttpUrl {
return input.substring(pos, limit);
}
static void canonicalize(StringBuilder out, String input, int pos, int limit,
static void canonicalize(Buffer out, String input, int pos, int limit,
String encodeSet, boolean alreadyEncoded, boolean query) {
Buffer utf8Buffer = null; // Lazily allocated.
int codePoint;
@@ -1444,7 +1444,7 @@ public final class HttpUrl {
// Skip this character.
} else if (query && codePoint == '+') {
// HTML permits space to be encoded as '+'. We use '%20' to avoid special cases.
out.append(alreadyEncoded ? "%20" : "%2B");
out.writeUtf8(alreadyEncoded ? "%20" : "%2B");
} else if (codePoint < 0x20
|| codePoint >= 0x7f
|| encodeSet.indexOf(codePoint) != -1
@@ -1456,13 +1456,13 @@ public final class HttpUrl {
utf8Buffer.writeUtf8CodePoint(codePoint);
while (!utf8Buffer.exhausted()) {
int b = utf8Buffer.readByte() & 0xff;
out.append('%');
out.append(HEX_DIGITS[(b >> 4) & 0xf]);
out.append(HEX_DIGITS[b & 0xf]);
out.writeByte('%');
out.writeByte(HEX_DIGITS[(b >> 4) & 0xf]);
out.writeByte(HEX_DIGITS[b & 0xf]);
}
} else {
// This character doesn't need encoding. Just copy it over.
out.append((char) codePoint);
out.writeUtf8CodePoint(codePoint);
}
}
}