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

Merge pull request #384 from square/jwilson_1230_rename_raw_headers

Rename RawHeaders to Headers.
This commit is contained in:
Jake Wharton
2013-12-30 23:12:58 -08:00
13 changed files with 149 additions and 177 deletions

View File

@@ -72,14 +72,10 @@ public final class Util {
return specifiedPort != -1 ? specifiedPort : getDefaultPort(scheme);
}
public static int getDefaultPort(String scheme) {
if ("http".equalsIgnoreCase(scheme)) {
return 80;
} else if ("https".equalsIgnoreCase(scheme)) {
return 443;
} else {
return -1;
}
public static int getDefaultPort(String protocol) {
if ("http".equals(protocol)) return 80;
if ("https".equals(protocol)) return 443;
return -1;
}
public static void checkOffsetAndCount(int arrayLength, int offset, int count) {

View File

@@ -310,7 +310,7 @@ public final class Connection implements Closeable {
Request request = tunnelRequest.getRequest();
String requestLine = tunnelRequest.requestLine();
while (true) {
out.write(request.rawHeaders().toBytes(requestLine));
HttpTransport.writeRequest(out, request.headers(), requestLine);
Response response = HttpTransport.readResponse(request, in).build();
switch (response.code()) {

View File

@@ -20,7 +20,7 @@ import com.squareup.okhttp.internal.Base64;
import com.squareup.okhttp.internal.DiskLruCache;
import com.squareup.okhttp.internal.StrictLineReader;
import com.squareup.okhttp.internal.Util;
import com.squareup.okhttp.internal.http.RawHeaders;
import com.squareup.okhttp.internal.http.Headers;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -356,10 +356,10 @@ public final class HttpResponseCache extends ResponseCache implements OkResponse
private static final class Entry {
private final String url;
private final RawHeaders varyHeaders;
private final Headers varyHeaders;
private final String requestMethod;
private final String statusLine;
private final RawHeaders responseHeaders;
private final Headers responseHeaders;
private final Handshake handshake;
/**
@@ -416,7 +416,7 @@ public final class HttpResponseCache extends ResponseCache implements OkResponse
StrictLineReader reader = new StrictLineReader(in, US_ASCII);
url = reader.readLine();
requestMethod = reader.readLine();
RawHeaders.Builder varyHeadersBuilder = new RawHeaders.Builder();
Headers.Builder varyHeadersBuilder = new Headers.Builder();
int varyRequestHeaderLineCount = reader.readInt();
for (int i = 0; i < varyRequestHeaderLineCount; i++) {
varyHeadersBuilder.addLine(reader.readLine());
@@ -424,7 +424,7 @@ public final class HttpResponseCache extends ResponseCache implements OkResponse
varyHeaders = varyHeadersBuilder.build();
statusLine = reader.readLine();
RawHeaders.Builder responseHeadersBuilder = new RawHeaders.Builder();
Headers.Builder responseHeadersBuilder = new Headers.Builder();
int responseHeaderLineCount = reader.readInt();
for (int i = 0; i < responseHeaderLineCount; i++) {
responseHeadersBuilder.addLine(reader.readLine());
@@ -450,10 +450,10 @@ public final class HttpResponseCache extends ResponseCache implements OkResponse
public Entry(Response response) {
this.url = response.request().urlString();
this.varyHeaders = response.request().rawHeaders().getAll(response.getVaryFields());
this.varyHeaders = response.request().headers().getAll(response.getVaryFields());
this.requestMethod = response.request().method();
this.statusLine = response.statusLine();
this.responseHeaders = response.rawHeaders();
this.responseHeaders = response.headers();
this.handshake = response.handshake();
}
@@ -529,7 +529,7 @@ public final class HttpResponseCache extends ResponseCache implements OkResponse
String contentLength = responseHeaders.get("Content-Length");
return new Response.Builder(request)
.statusLine(statusLine)
.rawHeaders(responseHeaders)
.headers(responseHeaders)
.body(new CacheResponseBody(snapshot, contentType, contentLength))
.handshake(handshake)
.build();

View File

@@ -18,8 +18,8 @@ package com.squareup.okhttp;
import com.squareup.okhttp.internal.Platform;
import com.squareup.okhttp.internal.Util;
import com.squareup.okhttp.internal.http.HeaderParser;
import com.squareup.okhttp.internal.http.Headers;
import com.squareup.okhttp.internal.http.HttpDate;
import com.squareup.okhttp.internal.http.RawHeaders;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -45,7 +45,7 @@ import java.util.Set;
public final class Request {
private final URL url;
private final String method;
private final RawHeaders headers;
private final Headers headers;
private final Body body;
private final Object tag;
@@ -93,7 +93,7 @@ public final class Request {
return headers.names();
}
RawHeaders rawHeaders() {
Headers headers() {
return headers;
}
@@ -120,7 +120,7 @@ public final class Request {
public Builder newBuilder() {
return new Builder(url)
.method(method, body)
.rawHeaders(headers)
.headers(headers)
.tag(tag);
}
@@ -132,7 +132,7 @@ public final class Request {
return "close".equalsIgnoreCase(parsedHeaders().connection);
}
public RawHeaders getHeaders() {
public Headers getHeaders() {
return headers;
}
@@ -255,7 +255,7 @@ public final class Request {
private String ifNoneMatch;
private String proxyAuthorization;
public ParsedHeaders(RawHeaders headers) {
public ParsedHeaders(Headers headers) {
HeaderParser.CacheControlHandler handler = new HeaderParser.CacheControlHandler() {
@Override public void handle(String directive, String parameter) {
if ("no-cache".equalsIgnoreCase(directive)) {
@@ -398,7 +398,7 @@ public final class Request {
public static class Builder {
private URL url;
private String method = "GET";
private RawHeaders.Builder headers = new RawHeaders.Builder();
private Headers.Builder headers = new Headers.Builder();
private Body body;
private Object tag;
@@ -444,8 +444,8 @@ public final class Request {
}
// TODO: this shouldn't be public.
public Builder rawHeaders(RawHeaders rawHeaders) {
headers = rawHeaders.newBuilder();
public Builder headers(Headers headers) {
this.headers = headers.newBuilder();
return this;
}

View File

@@ -18,8 +18,8 @@ package com.squareup.okhttp;
import com.squareup.okhttp.internal.Platform;
import com.squareup.okhttp.internal.Util;
import com.squareup.okhttp.internal.http.HeaderParser;
import com.squareup.okhttp.internal.http.Headers;
import com.squareup.okhttp.internal.http.HttpDate;
import com.squareup.okhttp.internal.http.RawHeaders;
import com.squareup.okhttp.internal.http.StatusLine;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
@@ -65,7 +65,7 @@ public final class Response {
private final Request request;
private final StatusLine statusLine;
private final Handshake handshake;
private final RawHeaders headers;
private final Headers headers;
private final Body body;
private final Response redirectedBy;
@@ -146,7 +146,7 @@ public final class Response {
}
// TODO: this shouldn't be public.
public RawHeaders rawHeaders() {
public Headers headers() {
return headers;
}
@@ -162,7 +162,7 @@ public final class Response {
return new Builder(request)
.statusLine(statusLine)
.handshake(handshake)
.rawHeaders(headers)
.headers(headers)
.body(body)
.redirectedBy(redirectedBy);
}
@@ -189,10 +189,6 @@ public final class Response {
return "close".equalsIgnoreCase(parsedHeaders().connection);
}
public RawHeaders getHeaders() {
return headers;
}
public Date getServedDate() {
return parsedHeaders().servedDate;
}
@@ -267,7 +263,7 @@ public final class Response {
* Returns true if none of the Vary headers on this response have changed
* between {@code cachedRequest} and {@code newRequest}.
*/
public boolean varyMatches(RawHeaders varyHeaders, Request newRequest) {
public boolean varyMatches(Headers varyHeaders, Request newRequest) {
for (String field : parsedHeaders().varyFields) {
if (!equal(varyHeaders.values(field), newRequest.headers(field))) return false;
}
@@ -301,7 +297,7 @@ public final class Response {
* 13.5.3.
*/
public Response combine(Response network) throws IOException {
RawHeaders.Builder result = new RawHeaders.Builder();
Headers.Builder result = new Headers.Builder();
for (int i = 0; i < headers.length(); i++) {
String fieldName = headers.getFieldName(i);
@@ -321,7 +317,7 @@ public final class Response {
}
}
return newBuilder().rawHeaders(result.build()).build();
return newBuilder().headers(result.build()).build();
}
/**
@@ -506,7 +502,7 @@ public final class Response {
private String connection;
private String contentType;
private ParsedHeaders(RawHeaders headers) {
private ParsedHeaders(Headers headers) {
HeaderParser.CacheControlHandler handler = new HeaderParser.CacheControlHandler() {
@Override public void handle(String directive, String parameter) {
if ("no-cache".equalsIgnoreCase(directive)) {
@@ -619,7 +615,7 @@ public final class Response {
private final Request request;
private StatusLine statusLine;
private Handshake handshake;
private RawHeaders.Builder headers = new RawHeaders.Builder();
private Headers.Builder headers = new Headers.Builder();
private Body body;
private Response redirectedBy;
@@ -666,8 +662,8 @@ public final class Response {
}
// TODO: this shouldn't be public.
public Builder rawHeaders(RawHeaders rawHeaders) {
headers = rawHeaders.newBuilder();
public Builder headers(Headers headers) {
this.headers = headers.newBuilder();
return this;
}

View File

@@ -20,13 +20,10 @@ package com.squareup.okhttp.internal.http;
import com.squareup.okhttp.internal.Util;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
@@ -48,7 +45,7 @@ import java.util.TreeSet;
* <p>This class trims whitespace from values. It never returns values with
* leading or trailing whitespace.
*/
public final class RawHeaders {
public final class Headers {
private static final Comparator<String> FIELD_NAME_COMPARATOR = new Comparator<String>() {
// @FindBugsSuppressWarnings("ES_COMPARING_PARAMETER_STRING_WITH_EQ")
@Override public int compare(String a, String b) {
@@ -66,7 +63,7 @@ public final class RawHeaders {
private final List<String> namesAndValues;
private RawHeaders(Builder builder) {
private Headers(Builder builder) {
this.namesAndValues = Util.immutableList(builder.namesAndValues);
}
@@ -122,7 +119,7 @@ public final class RawHeaders {
}
/** @param fieldNames a case-insensitive set of HTTP header field names. */
public RawHeaders getAll(Set<String> fieldNames) {
public Headers getAll(Set<String> fieldNames) {
Builder result = new Builder();
for (int i = 0; i < namesAndValues.size(); i += 2) {
String fieldName = namesAndValues.get(i);
@@ -133,20 +130,6 @@ public final class RawHeaders {
return result.build();
}
/** Returns bytes of a request header for sending on an HTTP transport. */
public byte[] toBytes(String requestLine) throws UnsupportedEncodingException {
StringBuilder result = new StringBuilder(256);
result.append(requestLine).append("\r\n");
for (int i = 0; i < namesAndValues.size(); i += 2) {
result.append(namesAndValues.get(i))
.append(": ")
.append(namesAndValues.get(i + 1))
.append("\r\n");
}
result.append("\r\n");
return result.toString().getBytes("ISO-8859-1");
}
/**
* Returns an immutable map containing each field to its list of values.
*
@@ -173,45 +156,6 @@ public final class RawHeaders {
return Collections.unmodifiableMap(result);
}
/**
* Returns a list of alternating names and values. Names are all lower case.
* No names are repeated. If any name has multiple values, they are
* concatenated using "\0" as a delimiter.
*/
public List<String> toNameValueBlock() {
Set<String> names = new HashSet<String>();
List<String> result = new ArrayList<String>();
for (int i = 0; i < namesAndValues.size(); i += 2) {
String name = namesAndValues.get(i).toLowerCase(Locale.US);
String value = namesAndValues.get(i + 1);
// Drop headers that are forbidden when layering HTTP over SPDY.
if (name.equals("connection")
|| name.equals("host")
|| name.equals("keep-alive")
|| name.equals("proxy-connection")
|| name.equals("transfer-encoding")) {
continue;
}
// If we haven't seen this name before, add the pair to the end of the list...
if (names.add(name)) {
result.add(name);
result.add(value);
continue;
}
// ...otherwise concatenate the existing values and this value.
for (int j = 0; j < result.size(); j += 2) {
if (name.equals(result.get(j))) {
result.set(j + 1, result.get(j + 1) + "\0" + value);
break;
}
}
}
return result;
}
public Builder newBuilder() {
Builder result = new Builder();
result.namesAndValues.addAll(namesAndValues);
@@ -232,7 +176,7 @@ public final class RawHeaders {
/** Equivalent to {@code build().get(fieldName)}, but potentially faster. */
public String get(String fieldName) {
return RawHeaders.get(namesAndValues, fieldName);
return Headers.get(namesAndValues, fieldName);
}
/**
@@ -300,8 +244,8 @@ public final class RawHeaders {
return this;
}
public RawHeaders build() {
return new RawHeaders(this);
public Headers build() {
return new Headers(this);
}
}
}

View File

@@ -102,7 +102,7 @@ public final class HttpAuthenticator {
} else {
throw new IllegalArgumentException(); // TODO: ProtocolException?
}
List<Challenge> challenges = parseChallenges(response.rawHeaders(), responseField);
List<Challenge> challenges = parseChallenges(response.headers(), responseField);
if (challenges.isEmpty()) return null; // Could not find a challenge so end the request cycle.
Request request = response.request();
@@ -119,7 +119,7 @@ public final class HttpAuthenticator {
* Parse RFC 2617 challenges. This API is only interested in the scheme
* name and realm.
*/
private static List<Challenge> parseChallenges(RawHeaders responseHeaders,
private static List<Challenge> parseChallenges(Headers responseHeaders,
String challengeHeader) {
// auth-scheme = token
// auth-param = token "=" ( token | quoted-string )

View File

@@ -19,7 +19,6 @@ package com.squareup.okhttp.internal.http;
import com.squareup.okhttp.Address;
import com.squareup.okhttp.Connection;
import com.squareup.okhttp.Handshake;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.OkResponseCache;
@@ -336,17 +335,8 @@ public class HttpEngine {
return response;
}
public final int getResponseCode() {
if (response == null) {
throw new IllegalStateException();
}
return response.code();
}
public final InputStream getResponseBody() {
if (response == null) {
throw new IllegalStateException();
}
if (response == null) throw new IllegalStateException();
return responseBodyIn;
}
@@ -434,13 +424,12 @@ public class HttpEngine {
* See RFC 2616 section 4.3.
*/
public final boolean hasResponseBody() {
int responseCode = response.code();
// HEAD requests never yield a body regardless of the response headers.
if (request.method().equals("HEAD")) {
return false;
}
int responseCode = response.code();
if ((responseCode < HTTP_CONTINUE || responseCode >= 200)
&& responseCode != HTTP_NO_CONTENT
&& responseCode != HTTP_NOT_MODIFIED) {
@@ -471,7 +460,7 @@ public class HttpEngine {
}
if (request.getHost() == null) {
result.setHost(getOriginAddress(request.url()));
result.setHost(getHostHeader(request.url()));
}
if ((connection == null || connection.getHttpMinorVersion() != 0)
@@ -496,26 +485,15 @@ public class HttpEngine {
request = result.build();
}
/**
* Returns the TLS handshake created when this engine connected, or null if
* no TLS connection was made.
*/
public Handshake getHandshake() {
return response.handshake();
}
public static String getDefaultUserAgent() {
String agent = System.getProperty("http.agent");
return agent != null ? agent : ("Java" + System.getProperty("java.version"));
}
public static String getOriginAddress(URL url) {
int port = url.getPort();
String result = url.getHost();
if (port > 0 && port != getDefaultPort(url.getProtocol())) {
result = result + ":" + port;
}
return result;
public static String getHostHeader(URL url) {
return getEffectivePort(url) != getDefaultPort(url.getProtocol())
? url.getHost() + ":" + url.getPort()
: url.getHost();
}
/**
@@ -524,6 +502,7 @@ public class HttpEngine {
*/
public final void readResponse() throws IOException {
if (hasResponse()) {
// TODO: this doesn't make much sense.
response = response.newBuilder().setResponseSource(responseSource).build();
return;
}
@@ -599,7 +578,7 @@ public class HttpEngine {
request.getProxyAuthorization());
}
public void receiveHeaders(RawHeaders headers) throws IOException {
public void receiveHeaders(Headers headers) throws IOException {
CookieHandler cookieHandler = client.getCookieHandler();
if (cookieHandler != null) {
cookieHandler.put(request.uri(), headers.toMultimap(null));

View File

@@ -135,12 +135,11 @@ public final class HttpTransport implements Transport {
*/
public void writeRequestHeaders() throws IOException {
httpEngine.writingRequestHeaders();
RawHeaders headersToSend = httpEngine.getRequest().getHeaders();
Headers headersToSend = httpEngine.getRequest().getHeaders();
String requestLine = RequestLine.get(httpEngine.getRequest(),
httpEngine.connection.getRoute().getProxy().type(),
httpEngine.connection.getHttpMinorVersion());
byte[] bytes = headersToSend.toBytes(requestLine);
requestOut.write(bytes);
writeRequest(requestOut, headersToSend, requestLine);
}
@Override public Response readResponseHeaders() throws IOException {
@@ -148,10 +147,25 @@ public final class HttpTransport implements Transport {
.handshake(httpEngine.connection.getHandshake())
.build();
httpEngine.connection.setHttpMinorVersion(response.httpMinorVersion());
httpEngine.receiveHeaders(response.rawHeaders());
httpEngine.receiveHeaders(response.headers());
return response;
}
/** Returns bytes of a request header for sending on an HTTP transport. */
public static void writeRequest(OutputStream out, Headers headers, String requestLine)
throws IOException {
StringBuilder result = new StringBuilder(256);
result.append(requestLine).append("\r\n");
for (int i = 0; i < headers.length(); i ++) {
result.append(headers.getFieldName(i))
.append(": ")
.append(headers.getValue(i))
.append("\r\n");
}
result.append("\r\n");
out.write(result.toString().getBytes("ISO-8859-1"));
}
/** Parses bytes of a response header from an HTTP transport. */
public static Response.Builder readResponse(Request request, InputStream in) throws IOException {
while (true) {
@@ -162,9 +176,9 @@ public final class HttpTransport implements Transport {
responseBuilder.statusLine(statusLine);
responseBuilder.header(Response.SELECTED_TRANSPORT, "http/1.1");
RawHeaders.Builder headersBuilder = new RawHeaders.Builder();
Headers.Builder headersBuilder = new Headers.Builder();
headersBuilder.readHeaders(in);
responseBuilder.rawHeaders(headersBuilder.build());
responseBuilder.headers(headersBuilder.build());
if (statusLine.code() != HTTP_CONTINUE) return responseBuilder;
}
@@ -498,7 +512,7 @@ public final class HttpTransport implements Transport {
}
if (bytesRemainingInChunk == 0) {
hasMoreChunks = false;
RawHeaders trailers = new RawHeaders.Builder()
Headers trailers = new Headers.Builder()
.readHeaders(transport.socketIn)
.build();
httpEngine.receiveHeaders(trailers);

View File

@@ -69,7 +69,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection implements Policy {
final OkHttpClient client;
private RawHeaders.Builder requestHeaders = new RawHeaders.Builder();
private Headers.Builder requestHeaders = new Headers.Builder();
/** Like the superclass field of the same name, but a long and available on all platforms. */
private long fixedContentLength = -1;
@@ -113,7 +113,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection implements Policy {
@Override public final InputStream getErrorStream() {
try {
HttpEngine response = getResponse();
if (response.hasResponseBody() && response.getResponseCode() >= HTTP_BAD_REQUEST) {
if (response.hasResponseBody() && response.getResponse().code() >= HTTP_BAD_REQUEST) {
return response.getResponseBody();
}
return null;
@@ -128,7 +128,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection implements Policy {
*/
@Override public final String getHeaderField(int position) {
try {
return getResponse().getResponse().getHeaders().getValue(position);
return getResponse().getResponse().headers().getValue(position);
} catch (IOException e) {
return null;
}
@@ -142,7 +142,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection implements Policy {
@Override public final String getHeaderField(String fieldName) {
try {
Response response = getResponse().getResponse();
return fieldName == null ? response.statusLine() : response.getHeaders().get(fieldName);
return fieldName == null ? response.statusLine() : response.headers().get(fieldName);
} catch (IOException e) {
return null;
}
@@ -150,7 +150,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection implements Policy {
@Override public final String getHeaderFieldKey(int position) {
try {
return getResponse().getResponse().getHeaders().getFieldName(position);
return getResponse().getResponse().headers().getFieldName(position);
} catch (IOException e) {
return null;
}
@@ -159,7 +159,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection implements Policy {
@Override public final Map<String, List<String>> getHeaderFields() {
try {
Response response = getResponse().getResponse();
return response.getHeaders().toMultimap(response.statusLine());
return response.headers().toMultimap(response.statusLine());
} catch (IOException e) {
return Collections.emptyMap();
}
@@ -273,7 +273,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection implements Policy {
RetryableOutputStream requestBody) throws IOException {
Request request = new Request.Builder(getURL())
.method(method, null) // No body: that's provided later!
.rawHeaders(requestHeaders.build())
.headers(requestHeaders.build())
.build();
// If we're currently not using caches, make sure the engine's client doesn't have one.
@@ -315,7 +315,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection implements Policy {
// Although RFC 2616 10.3.2 specifies that a HTTP_MOVED_PERM
// redirect should keep the same method, Chrome, Firefox and the
// RI all issue GETs when following any redirect.
int responseCode = httpEngine.getResponseCode();
int responseCode = httpEngine.getResponse().code();
if (responseCode == HTTP_MULT_CHOICE
|| responseCode == HTTP_MOVED_PERM
|| responseCode == HTTP_MOVED_TEMP
@@ -501,7 +501,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection implements Policy {
}
@Override public final int getResponseCode() throws IOException {
return getResponse().getResponseCode();
return getResponse().getResponse().code();
}
@Override public final void setRequestProperty(String field, String newValue) {

View File

@@ -76,7 +76,7 @@ public final class HttpsURLConnectionImpl extends HttpsURLConnection {
if (delegate.httpEngine == null) {
throw new IllegalStateException("Connection has not yet been established");
}
return delegate.httpEngine.getHandshake();
return delegate.httpEngine.getResponse().handshake();
}
@Override public void disconnect() {

View File

@@ -27,7 +27,11 @@ import java.io.OutputStream;
import java.net.CacheRequest;
import java.net.ProtocolException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public final class SpdyTransport implements Transport {
private final HttpEngine httpEngine;
@@ -45,7 +49,7 @@ public final class SpdyTransport implements Transport {
String version = RequestLine.version(httpEngine.connection.getHttpMinorVersion());
URL url = request.url();
builder.addSpdyRequestHeaders(request.method(), RequestLine.requestPath(url), version,
HttpEngine.getOriginAddress(url), httpEngine.getRequest().url().getProtocol());
HttpEngine.getHostHeader(url), httpEngine.getRequest().url().getProtocol());
if (httpEngine.hasRequestBody()) {
long fixedContentLength = httpEngine.policy.getFixedContentLength();
@@ -69,7 +73,7 @@ public final class SpdyTransport implements Transport {
httpEngine.writingRequestHeaders();
boolean hasRequestBody = httpEngine.hasRequestBody();
boolean hasResponseBody = true;
stream = spdyConnection.newStream(httpEngine.getRequest().getHeaders().toNameValueBlock(),
stream = spdyConnection.newStream(writeNameValueBlock(httpEngine.getRequest().getHeaders()),
hasRequestBody, hasResponseBody);
stream.setReadTimeout(httpEngine.client.getReadTimeout());
}
@@ -88,10 +92,49 @@ public final class SpdyTransport implements Transport {
.handshake(httpEngine.connection.getHandshake())
.build();
httpEngine.connection.setHttpMinorVersion(response.httpMinorVersion());
httpEngine.receiveHeaders(response.rawHeaders());
httpEngine.receiveHeaders(response.headers());
return response;
}
/**
* Returns a list of alternating names and values containing a SPDY request.
* Names are all lower case. No names are repeated. If any name has multiple
* values, they are concatenated using "\0" as a delimiter.
*/
public static List<String> writeNameValueBlock(Headers headers) {
Set<String> names = new HashSet<String>();
List<String> result = new ArrayList<String>();
for (int i = 0; i < headers.length(); i++) {
String name = headers.getFieldName(i).toLowerCase(Locale.US);
String value = headers.getValue(i);
// Drop headers that are forbidden when layering HTTP over SPDY.
if (name.equals("connection")
|| name.equals("host")
|| name.equals("keep-alive")
|| name.equals("proxy-connection")
|| name.equals("transfer-encoding")) {
continue;
}
// If we haven't seen this name before, add the pair to the end of the list...
if (names.add(name)) {
result.add(name);
result.add(value);
continue;
}
// ...otherwise concatenate the existing values and this value.
for (int j = 0; j < result.size(); j += 2) {
if (name.equals(result.get(j))) {
result.set(j + 1, result.get(j + 1) + "\0" + value);
break;
}
}
}
return result;
}
/** Returns headers for a name value block containing a SPDY response. */
public static Response.Builder readNameValueBlock(Request request, List<String> nameValueBlock)
throws IOException {
@@ -101,7 +144,7 @@ public final class SpdyTransport implements Transport {
String status = null;
String version = null;
RawHeaders.Builder headersBuilder = new RawHeaders.Builder();
Headers.Builder headersBuilder = new Headers.Builder();
headersBuilder.set(Response.SELECTED_TRANSPORT, "spdy/3");
for (int i = 0; i < nameValueBlock.size(); i += 2) {
String name = nameValueBlock.get(i);
@@ -127,7 +170,7 @@ public final class SpdyTransport implements Transport {
return new Response.Builder(request)
.statusLine(new StatusLine(version + " " + status))
.rawHeaders(headersBuilder.build());
.headers(headersBuilder.build());
}
@Override public InputStream getTransferStream(CacheRequest cacheRequest) throws IOException {

View File

@@ -25,7 +25,7 @@ import org.junit.Test;
import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertEquals;
public final class RawHeadersTest {
public final class HeadersTest {
@Test public void parseNameValueBlock() throws IOException {
List<String> nameValueBlock = Arrays.asList(
"cache-control", "no-cache, no-store",
@@ -34,31 +34,31 @@ public final class RawHeadersTest {
":version", "HTTP/1.1");
Request request = new Request.Builder("http://square.com/").build();
Response response = SpdyTransport.readNameValueBlock(request, nameValueBlock).build();
RawHeaders rawHeaders = response.rawHeaders();
assertEquals(4, rawHeaders.length());
Headers headers = response.headers();
assertEquals(4, headers.length());
assertEquals("HTTP/1.1 200 OK", response.statusLine());
assertEquals("no-cache, no-store", rawHeaders.get("cache-control"));
assertEquals("Cookie2", rawHeaders.get("set-cookie"));
assertEquals("spdy/3", rawHeaders.get(Response.SELECTED_TRANSPORT));
assertEquals(Response.SELECTED_TRANSPORT, rawHeaders.getFieldName(0));
assertEquals("spdy/3", rawHeaders.getValue(0));
assertEquals("cache-control", rawHeaders.getFieldName(1));
assertEquals("no-cache, no-store", rawHeaders.getValue(1));
assertEquals("set-cookie", rawHeaders.getFieldName(2));
assertEquals("Cookie1", rawHeaders.getValue(2));
assertEquals("set-cookie", rawHeaders.getFieldName(3));
assertEquals("Cookie2", rawHeaders.getValue(3));
assertNull(rawHeaders.get(":status"));
assertNull(rawHeaders.get(":version"));
assertEquals("no-cache, no-store", headers.get("cache-control"));
assertEquals("Cookie2", headers.get("set-cookie"));
assertEquals("spdy/3", headers.get(Response.SELECTED_TRANSPORT));
assertEquals(Response.SELECTED_TRANSPORT, headers.getFieldName(0));
assertEquals("spdy/3", headers.getValue(0));
assertEquals("cache-control", headers.getFieldName(1));
assertEquals("no-cache, no-store", headers.getValue(1));
assertEquals("set-cookie", headers.getFieldName(2));
assertEquals("Cookie1", headers.getValue(2));
assertEquals("set-cookie", headers.getFieldName(3));
assertEquals("Cookie2", headers.getValue(3));
assertNull(headers.get(":status"));
assertNull(headers.get(":version"));
}
@Test public void toNameValueBlock() {
RawHeaders.Builder builder = new RawHeaders.Builder();
Headers.Builder builder = new Headers.Builder();
builder.add("cache-control", "no-cache, no-store");
builder.add("set-cookie", "Cookie1");
builder.add("set-cookie", "Cookie2");
builder.add(":status", "200 OK");
List<String> nameValueBlock = builder.build().toNameValueBlock();
List<String> nameValueBlock = SpdyTransport.writeNameValueBlock(builder.build());
List<String> expected = Arrays.asList(
"cache-control", "no-cache, no-store",
"set-cookie", "Cookie1\u0000Cookie2",
@@ -67,9 +67,9 @@ public final class RawHeadersTest {
}
@Test public void toNameValueBlockDropsForbiddenHeaders() {
RawHeaders.Builder builder = new RawHeaders.Builder();
Headers.Builder builder = new Headers.Builder();
builder.add("Connection", "close");
builder.add("Transfer-Encoding", "chunked");
assertEquals(Arrays.<String>asList(), builder.build().toNameValueBlock());
assertEquals(Arrays.<String>asList(), SpdyTransport.writeNameValueBlock(builder.build()));
}
}