/** * FormEncodingBuilder.java[v 1.0.0] * class:com.bdyjy.util,FormEncodingBuilder * �ܺ� create at 2016-4-25 ����3:16:46 */ package com.bdyjy.util; import okio.Buffer; import com.squareup.okhttp.HttpUrl; import com.squareup.okhttp.MediaType; import com.squareup.okhttp.RequestBody; /** * com.bdyjy.util.FormEncodingBuilder * @author �ܺ�<br/> * create at 2016-4-25 ����3:16:46 */ public final class FormEncodingBuilder { private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 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 FORM_ENCODE_SET = " \"':;<=>@[]^`{}|/\\?#&!$(),~"; static final String FRAGMENT_ENCODE_SET = ""; private static final MediaType CONTENT_TYPE = MediaType.parse("application/x-www-form-urlencoded;charset=utf-8"); private final Buffer content = new Buffer(); /** Add new key-value pair. */ public FormEncodingBuilder add(String name, String value) { if (content.size() > 0) { content.writeByte('&'); } canonicalize(content, name, 0, name.length(), FORM_ENCODE_SET, false, true); content.writeByte('='); canonicalize(content, value, 0, value.length(), FORM_ENCODE_SET, false, true); return this; } /** Add new key-value pair. */ public FormEncodingBuilder addEncoded(String name, String value) { if (content.size() > 0) { content.writeByte('&'); } canonicalize(content, name, 0, name.length(), FORM_ENCODE_SET, true, true); content.writeByte('='); canonicalize(content, value, 0, value.length(), FORM_ENCODE_SET, true, true); return this; } public RequestBody build() { return RequestBody.create(CONTENT_TYPE, content.snapshot()); } static String canonicalize(String input, int pos, int limit, String encodeSet, boolean alreadyEncoded, boolean query) { int codePoint; for (int i = pos; i < limit; i += Character.charCount(codePoint)) { codePoint = input.codePointAt(i); if (codePoint < 0x20 || codePoint >= 0x7f || encodeSet.indexOf(codePoint) != -1 || (codePoint == '%' && !alreadyEncoded) || (query && codePoint == '+')) { // 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); return out.readUtf8(); } } // Fast path: no characters in [pos..limit) required encoding. return input.substring(pos, 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; for (int i = pos; i < limit; i += Character.charCount(codePoint)) { codePoint = input.codePointAt(i); 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 < 0x20 || codePoint >= 0x7f || encodeSet.indexOf(codePoint) != -1 || (codePoint == '%' && !alreadyEncoded)) { // Percent encode this character. if (utf8Buffer == null) { utf8Buffer = new Buffer(); } utf8Buffer.writeUtf8CodePoint(codePoint); while (!utf8Buffer.exhausted()) { int b = utf8Buffer.readByte() & 0xff; 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.writeUtf8CodePoint(codePoint); } } } }