1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-24 04:02:07 +03:00

Merge pull request #413 from adriancole/spdy-bytestring

Refactor SPDY code to use ByteString for headers.
This commit is contained in:
Jesse Wilson
2014-01-06 19:26:19 -08:00
20 changed files with 343 additions and 309 deletions

View File

@@ -16,6 +16,7 @@
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import com.squareup.okhttp.internal.SslContextBuilder;
import java.io.File;
import java.io.FileInputStream;
@@ -32,6 +33,8 @@ import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import org.eclipse.jetty.npn.NextProtoNego;
import static com.squareup.okhttp.internal.Util.asByteStringList;
/** A basic SPDY server that serves the contents of a local directory. */
public final class SpdyServer implements IncomingStreamHandler {
private final File baseDirectory;
@@ -78,12 +81,12 @@ public final class SpdyServer implements IncomingStreamHandler {
}
@Override public void receive(final SpdyStream stream) throws IOException {
List<String> requestHeaders = stream.getRequestHeaders();
List<ByteString> requestHeaders = stream.getRequestHeaders();
String path = null;
for (int i = 0; i < requestHeaders.size(); i += 2) {
String s = requestHeaders.get(i);
if (":path".equals(s)) {
path = requestHeaders.get(i + 1);
ByteString s = requestHeaders.get(i);
if (s.utf8Equals(":path")) {
path = requestHeaders.get(i + 1).utf8();
break;
}
}
@@ -105,8 +108,8 @@ public final class SpdyServer implements IncomingStreamHandler {
}
private void send404(SpdyStream stream, String path) throws IOException {
List<String> responseHeaders =
Arrays.asList(":status", "404", ":version", "HTTP/1.1", "content-type", "text/plain");
List<ByteString> responseHeaders =
asByteStringList(":status", "404", ":version", "HTTP/1.1", "content-type", "text/plain");
stream.reply(responseHeaders, true);
OutputStream out = stream.getOutputStream();
String text = "Not found: " + path;
@@ -115,8 +118,8 @@ public final class SpdyServer implements IncomingStreamHandler {
}
private void serveDirectory(SpdyStream stream, String[] files) throws IOException {
List<String> responseHeaders =
Arrays.asList(":status", "200", ":version", "HTTP/1.1", "content-type",
List<ByteString> responseHeaders =
asByteStringList(":status", "200", ":version", "HTTP/1.1", "content-type",
"text/html; charset=UTF-8");
stream.reply(responseHeaders, true);
OutputStream out = stream.getOutputStream();
@@ -130,9 +133,8 @@ public final class SpdyServer implements IncomingStreamHandler {
private void serveFile(SpdyStream stream, File file) throws IOException {
InputStream in = new FileInputStream(file);
byte[] buffer = new byte[8192];
stream.reply(
Arrays.asList(":status", "200", ":version", "HTTP/1.1", "content-type", contentType(file)),
true);
stream.reply(asByteStringList(":status", "200", ":version", "HTTP/1.1", "content-type",
contentType(file)), true);
OutputStream out = stream.getOutputStream();
int count;
while ((count = in.read(buffer)) != -1) {

View File

@@ -17,6 +17,7 @@
package com.squareup.okhttp.mockwebserver;
import com.squareup.okhttp.internal.ByteString;
import com.squareup.okhttp.internal.Platform;
import com.squareup.okhttp.internal.Util;
import com.squareup.okhttp.internal.spdy.IncomingStreamHandler;
@@ -658,14 +659,14 @@ public final class MockWebServer {
}
private RecordedRequest readRequest(SpdyStream stream) throws IOException {
List<String> spdyHeaders = stream.getRequestHeaders();
List<ByteString> spdyHeaders = stream.getRequestHeaders();
List<String> httpHeaders = new ArrayList<String>();
String method = "<:method omitted>";
String path = "<:path omitted>";
String version = "<:version omitted>";
for (int i = 0, size = spdyHeaders.size(); i < size; i += 2) {
String name = spdyHeaders.get(i);
String value = spdyHeaders.get(i + 1);
String name = spdyHeaders.get(i).utf8();
String value = spdyHeaders.get(i + 1).utf8();
if (":method".equals(name)) {
method = value;
} else if (":path".equals(name)) {
@@ -695,16 +696,17 @@ public final class MockWebServer {
if (response.getSocketPolicy() == SocketPolicy.NO_RESPONSE) {
return;
}
List<String> spdyHeaders = new ArrayList<String>();
List<ByteString> spdyHeaders = new ArrayList<ByteString>();
String[] statusParts = response.getStatus().split(" ", 2);
if (statusParts.length != 2) {
throw new AssertionError("Unexpected status: " + response.getStatus());
}
spdyHeaders.add(":status");
spdyHeaders.add(statusParts[1]);
// TODO: constants for well-known header names.
spdyHeaders.add(ByteString.encodeUtf8(":status"));
spdyHeaders.add(ByteString.encodeUtf8(statusParts[1]));
// TODO: no ":version" header for HTTP/2.0, only SPDY.
spdyHeaders.add(":version");
spdyHeaders.add(statusParts[0]);
spdyHeaders.add(ByteString.encodeUtf8(":version"));
spdyHeaders.add(ByteString.encodeUtf8(statusParts[0]));
List<String> headers = response.getHeaders();
for (int i = 0, size = headers.size(); i < size; i++) {
String header = headers.get(i);
@@ -712,8 +714,8 @@ public final class MockWebServer {
if (headerParts.length != 2) {
throw new AssertionError("Unexpected header: " + header);
}
spdyHeaders.add(headerParts[0].toLowerCase(Locale.US).trim());
spdyHeaders.add(headerParts[1].trim());
spdyHeaders.add(ByteString.encodeUtf8(headerParts[0].toLowerCase(Locale.US).trim()));
spdyHeaders.add(ByteString.encodeUtf8(headerParts[1].trim()));
}
byte[] body = response.getBody();
stream.reply(spdyHeaders, body.length > 0);

View File

@@ -66,7 +66,9 @@ public final class ByteString {
* or {@link #EMPTY} if {@code s} is zero length.
*/
public static ByteString encodeUtf8(String s) {
return new ByteString(s.getBytes(Util.UTF_8));
ByteString byteString = new ByteString(s.getBytes(Util.UTF_8));
byteString.utf8 = s;
return byteString;
}
/** Constructs a new {@code String} by decoding the bytes as UTF-8. */

View File

@@ -392,4 +392,12 @@ public final class Util {
}
};
}
public static List<ByteString> asByteStringList(String... strings) {
List<ByteString> out = new ArrayList<ByteString>(strings.length);
for (String string : strings) {
out.add(ByteString.encodeUtf8(string));
}
return out;
}
}

View File

@@ -16,6 +16,7 @@
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
@@ -33,17 +34,17 @@ public interface FrameReader extends Closeable {
* if necessary. Frames that trigger this are SPDY SYN_STREAM, HEADERS, and
* SYN_REPLY, and HTTP/2.0 HEADERS and PUSH_PROMISE.
*
* @param inFinished true if the sender will not send further frames.
* @param outFinished true if the receiver should not send further frames.
* @param inFinished true if the sender will not send further frames.
* @param streamId the stream owning these headers.
* @param associatedStreamId the stream that triggered the sender to create
* this stream.
* this stream.
* @param priority or -1 for no priority. For SPDY, priorities range from 0
* (highest) thru 7 (lowest). For HTTP/2.0, priorities range from 0
* (highest) thru 2**31-1 (lowest).
* (highest) thru 7 (lowest). For HTTP/2.0, priorities range from 0
* @param nameValueBlock
*/
void headers(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId,
int priority, List<String> nameValueBlock, HeadersMode headersMode);
int priority, List<ByteString> nameValueBlock, HeadersMode headersMode);
void rstStream(int streamId, ErrorCode errorCode);
void settings(boolean clearPrevious, Settings settings);
void noop();

View File

@@ -16,6 +16,7 @@
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
@@ -28,9 +29,10 @@ public interface FrameWriter extends Closeable {
/** SPDY/3 only. */
void flush() throws IOException;
void synStream(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId,
int priority, int slot, List<String> nameValueBlock) throws IOException;
void synReply(boolean outFinished, int streamId, List<String> nameValueBlock) throws IOException;
void headers(int streamId, List<String> nameValueBlock) throws IOException;
int priority, int slot, List<ByteString> nameValueBlock) throws IOException;
void synReply(boolean outFinished, int streamId, List<ByteString> nameValueBlock)
throws IOException;
void headers(int streamId, List<ByteString> nameValueBlock) throws IOException;
void rstStream(int streamId, ErrorCode errorCode) throws IOException;
void data(boolean outFinished, int streamId, byte[] data) throws IOException;
void data(boolean outFinished, int streamId, byte[] data, int offset, int byteCount)

View File

@@ -1,5 +1,6 @@
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -16,20 +17,23 @@ final class HpackDraft05 {
// Visible for testing.
static class HeaderEntry implements Cloneable {
final String name;
final String value;
final ByteString name;
final ByteString value;
final int size;
boolean referenced = true;
HeaderEntry(String name, String value) {
HeaderEntry(ByteString name, ByteString value) {
this.name = name;
this.value = value;
// TODO: This needs to be the size in bytes, not the length in chars.
this.size = 32 + name.length() + value.length();
this.size = 32 + name.size() + value.size();
}
public HeaderEntry(String name, String value) {
this(ByteString.encodeUtf8(name), ByteString.encodeUtf8(value));
}
/** Adds name and value, if this entry is referenced. */
void addTo(List<String> out) {
void addTo(List<ByteString> out) {
if (!referenced) return;
out.add(name);
out.add(value);
@@ -118,7 +122,7 @@ final class HpackDraft05 {
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-05#section-4.1.2
static class Reader {
private final DataInputStream in;
private final List<String> emittedHeaders = new ArrayList<String>();
private final List<ByteString> emittedHeaders = new ArrayList<ByteString>();
private long bytesLeft = 0;
// Visible for testing.
@@ -187,8 +191,8 @@ final class HpackDraft05 {
* Returns all headers emitted since they were last cleared, then clears the
* emitted headers.
*/
public List<String> getAndReset() {
List<String> result = new ArrayList<String>(emittedHeaders);
public List<ByteString> getAndReset() {
List<ByteString> result = new ArrayList<ByteString>(emittedHeaders);
emittedHeaders.clear();
return result;
}
@@ -213,34 +217,34 @@ final class HpackDraft05 {
private void readLiteralHeaderWithoutIndexingIndexedName(int index)
throws IOException {
String name = getName(index);
String value = readString();
ByteString name = getName(index);
ByteString value = readString();
emittedHeaders.add(name);
emittedHeaders.add(value);
}
private void readLiteralHeaderWithoutIndexingNewName()
throws IOException {
String name = readString();
String value = readString();
ByteString name = readString();
ByteString value = readString();
emittedHeaders.add(name);
emittedHeaders.add(value);
}
private void readLiteralHeaderWithIncrementalIndexingIndexedName(int nameIndex)
throws IOException {
String name = getName(nameIndex);
String value = readString();
ByteString name = getName(nameIndex);
ByteString value = readString();
insertIntoHeaderTable(-1, new HeaderEntry(name, value));
}
private void readLiteralHeaderWithIncrementalIndexingNewName() throws IOException {
String name = readString();
String value = readString();
ByteString name = readString();
ByteString value = readString();
insertIntoHeaderTable(-1, new HeaderEntry(name, value));
}
private String getName(int index) {
private ByteString getName(int index) {
if (isStaticHeader(index)) {
return STATIC_HEADER_TABLE.get(index - headerTable.size()).name;
} else {
@@ -318,13 +322,13 @@ final class HpackDraft05 {
* Reads a UTF-8 encoded string. Since ASCII is a subset of UTF-8, this method
* may be used to read strings that are known to be ASCII-only.
*/
public String readString() throws IOException {
public ByteString readString() throws IOException {
int firstByte = readByte();
int length = readInt(firstByte, PREFIX_8_BITS);
byte[] encoded = new byte[length];
bytesLeft -= length;
in.readFully(encoded);
return new String(encoded, "UTF-8");
return ByteString.of(encoded);
}
}
@@ -335,12 +339,12 @@ final class HpackDraft05 {
this.out = out;
}
public void writeHeaders(List<String> nameValueBlock) throws IOException {
public void writeHeaders(List<ByteString> nameValueBlock) throws IOException {
// TODO: implement a compression strategy.
for (int i = 0, size = nameValueBlock.size(); i < size; i += 2) {
out.write(0x40); // Literal Header without Indexing - New Name.
writeString(nameValueBlock.get(i));
writeString(nameValueBlock.get(i + 1));
writeByteString(nameValueBlock.get(i));
writeByteString(nameValueBlock.get(i + 1));
}
}
@@ -364,14 +368,9 @@ final class HpackDraft05 {
out.write(value);
}
/**
* Writes a UTF-8 encoded string. Since ASCII is a subset of UTF-8, this
* method can be used to write strings that are known to be ASCII-only.
*/
public void writeString(String headerName) throws IOException {
byte[] bytes = headerName.getBytes("UTF-8");
writeInt(bytes.length, PREFIX_8_BITS, 0);
out.write(bytes);
public void writeByteString(ByteString data) throws IOException {
writeInt(data.size(), PREFIX_8_BITS, 0);
data.write(out);
}
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import com.squareup.okhttp.internal.Util;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -163,7 +164,7 @@ public final class Http20Draft09 implements Variant {
if ((flags & FLAG_END_HEADERS) != 0) {
hpackReader.emitReferenceSet();
List<String> nameValueBlock = hpackReader.getAndReset();
List<ByteString> nameValueBlock = hpackReader.getAndReset();
// TODO: Concat multi-value headers with 0x0, except COOKIE, which uses 0x3B, 0x20.
// http://tools.ietf.org/html/draft-ietf-httpbis-http2-09#section-8.1.3
int priority = -1; // TODO: priority
@@ -306,25 +307,26 @@ public final class Http20Draft09 implements Variant {
out.write(CONNECTION_HEADER);
}
@Override public synchronized void synStream(boolean outFinished, boolean inFinished,
int streamId, int associatedStreamId, int priority, int slot, List<String> nameValueBlock)
@Override
public synchronized void synStream(boolean outFinished, boolean inFinished, int streamId,
int associatedStreamId, int priority, int slot, List<ByteString> nameValueBlock)
throws IOException {
if (inFinished) throw new UnsupportedOperationException();
headers(outFinished, streamId, priority, nameValueBlock);
}
@Override public synchronized void synReply(boolean outFinished, int streamId,
List<String> nameValueBlock) throws IOException {
List<ByteString> nameValueBlock) throws IOException {
headers(outFinished, streamId, -1, nameValueBlock);
}
@Override public synchronized void headers(int streamId, List<String> nameValueBlock)
@Override public synchronized void headers(int streamId, List<ByteString> nameValueBlock)
throws IOException {
headers(false, streamId, -1, nameValueBlock);
}
private void headers(boolean outFinished, int streamId, int priority,
List<String> nameValueBlock) throws IOException {
List<ByteString> nameValueBlock) throws IOException {
hpackBuffer.reset();
hpackWriter.writeHeaders(nameValueBlock);
int type = TYPE_HEADERS;

View File

@@ -1,5 +1,6 @@
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import com.squareup.okhttp.internal.Util;
import java.io.Closeable;
import java.io.DataInputStream;
@@ -71,7 +72,7 @@ class NameValueBlockReader implements Closeable {
}
}
public List<String> readNameValueBlock(int length) throws IOException {
public List<ByteString> readNameValueBlock(int length) throws IOException {
this.compressedLimit += length;
try {
int numberOfPairs = nameValueBlockIn.readInt();
@@ -81,11 +82,11 @@ class NameValueBlockReader implements Closeable {
if (numberOfPairs > 1024) {
throw new IOException("numberOfPairs > 1024: " + numberOfPairs);
}
List<String> entries = new ArrayList<String>(numberOfPairs * 2);
List<ByteString> entries = new ArrayList<ByteString>(numberOfPairs * 2);
for (int i = 0; i < numberOfPairs; i++) {
String name = readString();
String values = readString();
if (name.length() == 0) throw new IOException("name.length == 0");
ByteString name = readString();
ByteString values = readString();
if (name.size() == 0) throw new IOException("name.size == 0");
entries.add(name);
entries.add(values);
}
@@ -110,11 +111,11 @@ class NameValueBlockReader implements Closeable {
}
}
private String readString() throws DataFormatException, IOException {
private ByteString readString() throws DataFormatException, IOException {
int length = nameValueBlockIn.readInt();
byte[] bytes = new byte[length];
Util.readFully(nameValueBlockIn, bytes);
return new String(bytes, 0, length, "UTF-8");
return ByteString.of(bytes);
}
@Override public void close() throws IOException {

View File

@@ -15,6 +15,7 @@
*/
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import com.squareup.okhttp.internal.Platform;
import com.squareup.okhttp.internal.Util;
import java.io.ByteArrayOutputStream;
@@ -201,7 +202,7 @@ final class Spdy3 implements Variant {
int associatedStreamId = w2 & 0x7fffffff;
int priority = (s3 & 0xe000) >>> 13;
int slot = s3 & 0xff;
List<String> nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 10);
List<ByteString> nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 10);
boolean inFinished = (flags & FLAG_FIN) != 0;
boolean outFinished = (flags & FLAG_UNIDIRECTIONAL) != 0;
@@ -212,7 +213,7 @@ final class Spdy3 implements Variant {
private void readSynReply(Handler handler, int flags, int length) throws IOException {
int w1 = in.readInt();
int streamId = w1 & 0x7fffffff;
List<String> nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 4);
List<ByteString> nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 4);
boolean inFinished = (flags & FLAG_FIN) != 0;
handler.headers(false, inFinished, streamId, -1, -1, nameValueBlock, HeadersMode.SPDY_REPLY);
}
@@ -231,7 +232,7 @@ final class Spdy3 implements Variant {
private void readHeaders(Handler handler, int flags, int length) throws IOException {
int w1 = in.readInt();
int streamId = w1 & 0x7fffffff;
List<String> nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 4);
List<ByteString> nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 4);
handler.headers(false, false, streamId, -1, -1, nameValueBlock, HeadersMode.SPDY_HEADERS);
}
@@ -314,8 +315,9 @@ final class Spdy3 implements Variant {
out.flush();
}
@Override public synchronized void synStream(boolean outFinished, boolean inFinished,
int streamId, int associatedStreamId, int priority, int slot, List<String> nameValueBlock)
@Override
public synchronized void synStream(boolean outFinished, boolean inFinished, int streamId,
int associatedStreamId, int priority, int slot, List<ByteString> nameValueBlock)
throws IOException {
writeNameValueBlockToBuffer(nameValueBlock);
int length = 10 + nameValueBlockBuffer.size();
@@ -332,8 +334,8 @@ final class Spdy3 implements Variant {
out.flush();
}
@Override public synchronized void synReply(
boolean outFinished, int streamId, List<String> nameValueBlock) throws IOException {
@Override public synchronized void synReply(boolean outFinished, int streamId,
List<ByteString> nameValueBlock) throws IOException {
writeNameValueBlockToBuffer(nameValueBlock);
int type = TYPE_SYN_REPLY;
int flags = (outFinished ? FLAG_FIN : 0);
@@ -346,7 +348,7 @@ final class Spdy3 implements Variant {
out.flush();
}
@Override public synchronized void headers(int streamId, List<String> nameValueBlock)
@Override public synchronized void headers(int streamId, List<ByteString> nameValueBlock)
throws IOException {
writeNameValueBlockToBuffer(nameValueBlock);
int flags = 0;
@@ -386,14 +388,14 @@ final class Spdy3 implements Variant {
out.write(data, offset, byteCount);
}
private void writeNameValueBlockToBuffer(List<String> nameValueBlock) throws IOException {
private void writeNameValueBlockToBuffer(List<ByteString> nameValueBlock) throws IOException {
nameValueBlockBuffer.reset();
int numberOfPairs = nameValueBlock.size() / 2;
nameValueBlockOut.writeInt(numberOfPairs);
for (int i = 0, size = nameValueBlock.size(); i < size; i++) {
String s = nameValueBlock.get(i);
nameValueBlockOut.writeInt(s.length());
nameValueBlockOut.write(s.getBytes("UTF-8"));
ByteString s = nameValueBlock.get(i);
nameValueBlockOut.writeInt(s.size());
s.write(nameValueBlockOut);
}
nameValueBlockOut.flush();
}

View File

@@ -16,6 +16,7 @@
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import com.squareup.okhttp.internal.NamedRunnable;
import com.squareup.okhttp.internal.Util;
import java.io.Closeable;
@@ -157,7 +158,7 @@ public final class SpdyConnection implements Closeable {
* @param in true to create an input stream that the remote peer can use to
* send data to us. Corresponds to {@code FLAG_UNIDIRECTIONAL}.
*/
public SpdyStream newStream(List<String> requestHeaders, boolean out, boolean in)
public SpdyStream newStream(List<ByteString> requestHeaders, boolean out, boolean in)
throws IOException {
boolean outFinished = !out;
boolean inFinished = !in;
@@ -189,7 +190,7 @@ public final class SpdyConnection implements Closeable {
return stream;
}
void writeSynReply(int streamId, boolean outFinished, List<String> alternating)
void writeSynReply(int streamId, boolean outFinished, List<ByteString> alternating)
throws IOException {
frameWriter.synReply(outFinished, streamId, alternating);
}
@@ -472,7 +473,7 @@ public final class SpdyConnection implements Closeable {
}
@Override public void headers(boolean outFinished, boolean inFinished, int streamId,
int associatedStreamId, int priority, List<String> nameValueBlock,
int associatedStreamId, int priority, List<ByteString> nameValueBlock,
HeadersMode headersMode) {
SpdyStream stream;
synchronized (SpdyConnection.this) {

View File

@@ -16,6 +16,7 @@
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import com.squareup.okhttp.internal.Util;
import java.io.IOException;
import java.io.InputStream;
@@ -48,10 +49,10 @@ public final class SpdyStream {
private int writeWindowSize;
/** Headers sent by the stream initiator. Immutable and non null. */
private final List<String> requestHeaders;
private final List<ByteString> requestHeaders;
/** Headers sent in the stream reply. Null if reply is either not sent or not sent yet. */
private List<String> responseHeaders;
private List<ByteString> responseHeaders;
private final SpdyDataInputStream in;
private final SpdyDataOutputStream out;
@@ -64,7 +65,7 @@ public final class SpdyStream {
private ErrorCode errorCode = null;
SpdyStream(int id, SpdyConnection connection, boolean outFinished, boolean inFinished,
int priority, List<String> requestHeaders, Settings settings) {
int priority, List<ByteString> requestHeaders, Settings settings) {
if (connection == null) throw new NullPointerException("connection == null");
if (requestHeaders == null) throw new NullPointerException("requestHeaders == null");
this.id = id;
@@ -109,7 +110,7 @@ public final class SpdyStream {
return connection;
}
public List<String> getRequestHeaders() {
public List<ByteString> getRequestHeaders() {
return requestHeaders;
}
@@ -117,7 +118,7 @@ public final class SpdyStream {
* Returns the stream's response headers, blocking if necessary if they
* have not been received yet.
*/
public synchronized List<String> getResponseHeaders() throws IOException {
public synchronized List<ByteString> getResponseHeaders() throws IOException {
long remaining = 0;
long start = 0;
if (readTimeoutMillis != 0) {
@@ -161,7 +162,7 @@ public final class SpdyStream {
* @param out true to create an output stream that we can use to send data
* to the remote peer. Corresponds to {@code FLAG_FIN}.
*/
public void reply(List<String> responseHeaders, boolean out) throws IOException {
public void reply(List<ByteString> responseHeaders, boolean out) throws IOException {
assert (!Thread.holdsLock(SpdyStream.this));
boolean outFinished = false;
synchronized (this) {
@@ -254,7 +255,7 @@ public final class SpdyStream {
return true;
}
void receiveHeaders(List<String> headers, HeadersMode headersMode) {
void receiveHeaders(List<ByteString> headers, HeadersMode headersMode) {
assert (!Thread.holdsLock(SpdyStream.this));
ErrorCode errorCode = null;
boolean open = true;
@@ -271,7 +272,7 @@ public final class SpdyStream {
if (headersMode.failIfHeadersPresent()) {
errorCode = ErrorCode.STREAM_IN_USE;
} else {
List<String> newHeaders = new ArrayList<String>();
List<ByteString> newHeaders = new ArrayList<ByteString>();
newHeaders.addAll(responseHeaders);
newHeaders.addAll(headers);
this.responseHeaders = newHeaders;

View File

@@ -15,6 +15,7 @@
*/
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@@ -29,7 +30,7 @@ class BaseTestHandler implements FrameReader.Handler {
@Override
public void headers(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId,
int priority, List<String> nameValueBlock, HeadersMode headersMode) {
int priority, List<ByteString> nameValueBlock, HeadersMode headersMode) {
fail();
}

View File

@@ -1,75 +1,75 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.okhttp.internal.spdy;
package com.squareup.okhttp.internal.spdy;
import org.junit.Test;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
public class ByteArrayPoolTest {
@Test public void testReusesBuffer() {
ByteArrayPool pool = new ByteArrayPool(32);
public class ByteArrayPoolTest {
@Test public void testReusesBuffer() {
ByteArrayPool pool = new ByteArrayPool(32);
byte[] buf1 = pool.getBuf(16);
byte[] buf2 = pool.getBuf(16);
byte[] buf1 = pool.getBuf(16);
byte[] buf2 = pool.getBuf(16);
pool.returnBuf(buf1);
pool.returnBuf(buf2);
pool.returnBuf(buf1);
pool.returnBuf(buf2);
byte[] buf3 = pool.getBuf(16);
byte[] buf4 = pool.getBuf(16);
assertTrue(buf3 == buf1 || buf3 == buf2);
assertTrue(buf4 == buf1 || buf4 == buf2);
assertTrue(buf3 != buf4);
}
@Test public void testObeysSizeLimit() {
ByteArrayPool pool = new ByteArrayPool(32);
byte[] buf1 = pool.getBuf(16);
byte[] buf2 = pool.getBuf(16);
byte[] buf3 = pool.getBuf(16);
pool.returnBuf(buf1);
pool.returnBuf(buf2);
pool.returnBuf(buf3);
byte[] buf4 = pool.getBuf(16);
byte[] buf5 = pool.getBuf(16);
byte[] buf6 = pool.getBuf(16);
assertTrue(buf4 == buf2 || buf4 == buf3);
assertTrue(buf5 == buf2 || buf5 == buf3);
assertTrue(buf4 != buf5);
assertTrue(buf6 != buf1 && buf6 != buf2 && buf6 != buf3);
}
@Test public void testReturnsBufferWithRightSize() {
ByteArrayPool pool = new ByteArrayPool(32);
byte[] buf1 = pool.getBuf(16);
pool.returnBuf(buf1);
byte[] buf2 = pool.getBuf(17);
assertNotSame(buf2, buf1);
byte[] buf3 = pool.getBuf(15);
assertSame(buf3, buf1);
}
byte[] buf3 = pool.getBuf(16);
byte[] buf4 = pool.getBuf(16);
assertTrue(buf3 == buf1 || buf3 == buf2);
assertTrue(buf4 == buf1 || buf4 == buf2);
assertTrue(buf3 != buf4);
}
@Test public void testObeysSizeLimit() {
ByteArrayPool pool = new ByteArrayPool(32);
byte[] buf1 = pool.getBuf(16);
byte[] buf2 = pool.getBuf(16);
byte[] buf3 = pool.getBuf(16);
pool.returnBuf(buf1);
pool.returnBuf(buf2);
pool.returnBuf(buf3);
byte[] buf4 = pool.getBuf(16);
byte[] buf5 = pool.getBuf(16);
byte[] buf6 = pool.getBuf(16);
assertTrue(buf4 == buf2 || buf4 == buf3);
assertTrue(buf5 == buf2 || buf5 == buf3);
assertTrue(buf4 != buf5);
assertTrue(buf6 != buf1 && buf6 != buf2 && buf6 != buf3);
}
@Test public void testReturnsBufferWithRightSize() {
ByteArrayPool pool = new ByteArrayPool(32);
byte[] buf1 = pool.getBuf(16);
pool.returnBuf(buf1);
byte[] buf2 = pool.getBuf(17);
assertNotSame(buf2, buf1);
byte[] buf3 = pool.getBuf(15);
assertSame(buf3, buf1);
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -25,6 +26,7 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
import static com.squareup.okhttp.internal.Util.asByteStringList;
import static org.junit.Assert.assertEquals;
public class HpackDraft05Test {
@@ -43,7 +45,7 @@ public class HpackDraft05Test {
@Test public void tooLargeToHPackIsStillEmitted() throws IOException {
char[] tooLarge = new char[4096];
Arrays.fill(tooLarge, 'a');
final List<String> sentHeaders = Arrays.asList("foo", new String(tooLarge));
final List<ByteString> sentHeaders = asByteStringList("foo", new String(tooLarge));
ByteArrayOutputStream out = literalHeaders(sentHeaders);
bytesIn.set(out.toByteArray());
@@ -78,7 +80,7 @@ public class HpackDraft05Test {
HpackDraft05.HeaderEntry entry = hpackReader.headerTable.get(0);
checkEntry(entry, "custom-key", "custom-header", 55, true);
assertEquals(Arrays.asList("custom-key", "custom-header"), hpackReader.getAndReset());
assertEquals(asByteStringList("custom-key", "custom-header"), hpackReader.getAndReset());
}
/**
@@ -98,7 +100,7 @@ public class HpackDraft05Test {
assertEquals(0, hpackReader.headerTable.size());
assertEquals(Arrays.asList(":path", "/sample/path"), hpackReader.getAndReset());
assertEquals(asByteStringList(":path", "/sample/path"), hpackReader.getAndReset());
}
/**
@@ -120,7 +122,7 @@ public class HpackDraft05Test {
HpackDraft05.HeaderEntry entry = hpackReader.headerTable.get(0);
checkEntry(entry, ":method", "GET", 42, true);
assertEquals(Arrays.asList(":method", "GET"), hpackReader.getAndReset());
assertEquals(asByteStringList(":method", "GET"), hpackReader.getAndReset());
}
/**
@@ -140,7 +142,7 @@ public class HpackDraft05Test {
// Not buffered in header table.
assertEquals(0, hpackReader.headerTable.size());
assertEquals(Arrays.asList(":method", "GET"), hpackReader.getAndReset());
assertEquals(asByteStringList(":method", "GET"), hpackReader.getAndReset());
}
/**
@@ -206,7 +208,7 @@ public class HpackDraft05Test {
assertEquals(180, hpackReader.headerTableSize);
// Decoded header set:
assertEquals(Arrays.asList( //
assertEquals(asByteStringList( //
":method", "GET", //
":scheme", "http", //
":path", "/", //
@@ -251,7 +253,7 @@ public class HpackDraft05Test {
assertEquals(233, hpackReader.headerTableSize);
// Decoded header set:
assertEquals(Arrays.asList( //
assertEquals(asByteStringList( //
":method", "GET", //
":scheme", "http", //
":path", "/", //
@@ -320,7 +322,7 @@ public class HpackDraft05Test {
// Decoded header set:
// TODO: order is not correct per docs, but then again, the spec doesn't require ordering.
assertEquals(Arrays.asList( //
assertEquals(asByteStringList( //
":method", "GET", //
":authority", "www.example.com", //
":scheme", "https", //
@@ -380,25 +382,25 @@ public class HpackDraft05Test {
}
@Test public void headerName() throws IOException {
hpackWriter.writeString("foo");
hpackWriter.writeByteString(ByteString.encodeUtf8("foo"));
assertBytes(3, 'f', 'o', 'o');
assertEquals("foo", new HpackDraft05.Reader(byteStream(3, 'f', 'o', 'o')).readString());
assertEquals("foo", new HpackDraft05.Reader(byteStream(3, 'f', 'o', 'o')).readString().utf8());
}
@Test public void emptyHeaderName() throws IOException {
hpackWriter.writeString("");
hpackWriter.writeByteString(ByteString.encodeUtf8(""));
assertBytes(0);
assertEquals("", new HpackDraft05.Reader(byteStream(0)).readString());
assertEquals("", new HpackDraft05.Reader(byteStream(0)).readString().utf8());
}
@Test public void headersRoundTrip() throws IOException {
List<String> sentHeaders = Arrays.asList("name", "value");
List<ByteString> sentHeaders = asByteStringList("name", "value");
hpackWriter.writeHeaders(sentHeaders);
ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytesOut.toByteArray());
HpackDraft05.Reader reader = new HpackDraft05.Reader(new DataInputStream(bytesIn));
reader.readHeaders(bytesOut.size());
reader.emitReferenceSet();
List<String> receivedHeaders = reader.getAndReset();
List<ByteString> receivedHeaders = reader.getAndReset();
assertEquals(sentHeaders, receivedHeaders);
}
@@ -407,7 +409,7 @@ public class HpackDraft05Test {
return new DataInputStream(new ByteArrayInputStream(data));
}
private ByteArrayOutputStream literalHeaders(List<String> sentHeaders) throws IOException {
private ByteArrayOutputStream literalHeaders(List<ByteString> sentHeaders) throws IOException {
ByteArrayOutputStream headerBytes = new ByteArrayOutputStream();
new HpackDraft05.Writer(new DataOutputStream(headerBytes)).writeHeaders(sentHeaders);
return headerBytes;
@@ -415,8 +417,8 @@ public class HpackDraft05Test {
private void checkEntry(HpackDraft05.HeaderEntry entry, String name, String value, int size,
boolean referenced) {
assertEquals(name, entry.name);
assertEquals(value, entry.value);
assertEquals(name, entry.name.utf8());
assertEquals(value, entry.value.utf8());
assertEquals(size, entry.size);
assertEquals(referenced, entry.referenced);
}

View File

@@ -15,24 +15,24 @@
*/
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import static com.squareup.okhttp.internal.Util.asByteStringList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class Http20Draft09Test {
static final int expectedStreamId = 15;
@Test public void onlyOneLiteralHeadersFrame() throws IOException {
final List<String> sentHeaders = Arrays.asList("name", "value");
final List<ByteString> sentHeaders = asByteStringList("name", "value");
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(out);
@@ -54,7 +54,7 @@ public class Http20Draft09Test {
@Override
public void headers(boolean outFinished, boolean inFinished, int streamId,
int associatedStreamId, int priority, List<String> nameValueBlock,
int associatedStreamId, int priority, List<ByteString> nameValueBlock,
HeadersMode headersMode) {
assertFalse(outFinished);
assertTrue(inFinished);
@@ -74,7 +74,7 @@ public class Http20Draft09Test {
// Write the first headers frame.
{
byte[] headerBytes = literalHeaders(Arrays.asList("foo", "bar"));
byte[] headerBytes = literalHeaders(asByteStringList("foo", "bar"));
dataOut.writeShort(headerBytes.length);
dataOut.write(Http20Draft09.TYPE_HEADERS);
dataOut.write(0); // no flags
@@ -84,7 +84,7 @@ public class Http20Draft09Test {
// Write the continuation frame, specifying no more frames are expected.
{
byte[] headerBytes = literalHeaders(Arrays.asList("baz", "qux"));
byte[] headerBytes = literalHeaders(asByteStringList("baz", "qux"));
dataOut.writeShort(headerBytes.length);
dataOut.write(Http20Draft09.TYPE_CONTINUATION);
dataOut.write(Http20Draft09.FLAG_END_HEADERS | Http20Draft09.FLAG_END_STREAM);
@@ -99,14 +99,14 @@ public class Http20Draft09Test {
@Override
public void headers(boolean outFinished, boolean inFinished, int streamId,
int associatedStreamId, int priority, List<String> nameValueBlock,
int associatedStreamId, int priority, List<ByteString> nameValueBlock,
HeadersMode headersMode) {
assertFalse(outFinished);
assertFalse(inFinished);
assertEquals(expectedStreamId, streamId);
assertEquals(-1, associatedStreamId);
assertEquals(-1, priority);
assertEquals(Arrays.asList("foo", "bar", "baz", "qux"), nameValueBlock);
assertEquals(asByteStringList("foo", "bar", "baz", "qux"), nameValueBlock);
assertEquals(HeadersMode.HTTP_20_HEADERS, headersMode);
}
});
@@ -133,7 +133,7 @@ public class Http20Draft09Test {
});
}
private byte[] literalHeaders(List<String> sentHeaders) throws IOException {
private byte[] literalHeaders(List<ByteString> sentHeaders) throws IOException {
ByteArrayOutputStream headerBytes = new ByteArrayOutputStream();
new HpackDraft05.Writer(new DataOutputStream(headerBytes)).writeHeaders(sentHeaders);
return headerBytes.toByteArray();

View File

@@ -16,6 +16,7 @@
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.internal.ByteString;
import com.squareup.okhttp.internal.Util;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
@@ -185,7 +186,7 @@ public final class MockSpdyPeer implements Closeable {
public int priority;
public ErrorCode errorCode;
public int deltaWindowSize;
public List<String> nameValueBlock;
public List<ByteString> nameValueBlock;
public byte[] data;
public Settings settings;
public HeadersMode headersMode;
@@ -203,7 +204,7 @@ public final class MockSpdyPeer implements Closeable {
}
@Override public void headers(boolean outFinished, boolean inFinished, int streamId,
int associatedStreamId, int priority, List<String> nameValueBlock,
int associatedStreamId, int priority, List<ByteString> nameValueBlock,
HeadersMode headersMode) {
if (this.type != -1) throw new IllegalStateException();
this.type = Spdy3.TYPE_HEADERS;

View File

@@ -30,6 +30,7 @@ import org.junit.After;
import org.junit.Test;
import static com.squareup.okhttp.internal.Util.UTF_8;
import static com.squareup.okhttp.internal.Util.asByteStringList;
import static com.squareup.okhttp.internal.spdy.ErrorCode.CANCEL;
import static com.squareup.okhttp.internal.spdy.ErrorCode.FLOW_CONTROL_ERROR;
import static com.squareup.okhttp.internal.spdy.ErrorCode.INTERNAL_ERROR;
@@ -66,15 +67,16 @@ public final class SpdyConnectionTest {
@Test public void clientCreatesStreamAndServerReplies() throws Exception {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android"));
peer.sendFrame()
.synReply(false, 1, asByteStringList("a", "android"));
peer.sendFrame().data(true, 1, "robot".getBytes("UTF-8"));
peer.acceptFrame(); // DATA
peer.play();
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("b", "banana"), true, true);
assertEquals(Arrays.asList("a", "android"), stream.getResponseHeaders());
SpdyStream stream = connection.newStream(asByteStringList("b", "banana"), true, true);
assertEquals(asByteStringList("a", "android"), stream.getResponseHeaders());
assertStreamData("robot", stream.getInputStream());
writeAndClose(stream, "c3po");
assertEquals(0, connection.openStreamCount());
@@ -87,20 +89,20 @@ public final class SpdyConnectionTest {
assertFalse(synStream.outFinished);
assertEquals(1, synStream.streamId);
assertEquals(0, synStream.associatedStreamId);
assertEquals(Arrays.asList("b", "banana"), synStream.nameValueBlock);
assertEquals(asByteStringList("b", "banana"), synStream.nameValueBlock);
MockSpdyPeer.InFrame requestData = peer.takeFrame();
assertTrue(Arrays.equals("c3po".getBytes("UTF-8"), requestData.data));
}
@Test public void headersOnlyStreamIsClosedAfterReplyHeaders() throws Exception {
peer.acceptFrame(); // SYN_STREAM
peer.sendFrame().synReply(false, 1, Arrays.asList("b", "banana"));
peer.sendFrame().synReply(false, 1, asByteStringList("b", "banana"));
peer.play();
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), false, false);
SpdyStream stream = connection.newStream(asByteStringList("a", "android"), false, false);
assertEquals(1, connection.openStreamCount());
assertEquals(Arrays.asList("b", "banana"), stream.getResponseHeaders());
assertEquals(asByteStringList("b", "banana"), stream.getResponseHeaders());
assertEquals(0, connection.openStreamCount());
}
@@ -108,13 +110,13 @@ public final class SpdyConnectionTest {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.acceptFrame(); // PING
peer.sendFrame().synReply(true, 1, Arrays.asList("a", "android"));
peer.sendFrame().synReply(true, 1, asByteStringList("a", "android"));
peer.sendFrame().ping(true, 1, 0);
peer.play();
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
connection.newStream(Arrays.asList("b", "banana"), false, true);
connection.newStream(asByteStringList("b", "banana"), false, true);
assertEquals(1, connection.openStreamCount());
connection.ping().roundTripTime(); // Ensure that the SYN_REPLY has been received.
assertEquals(0, connection.openStreamCount());
@@ -129,7 +131,7 @@ public final class SpdyConnectionTest {
@Test public void serverCreatesStreamAndClientReplies() throws Exception {
// write the mocking script
peer.sendFrame().synStream(false, false, 2, 0, 5, 129, Arrays.asList("a", "android"));
peer.sendFrame().synStream(false, false, 2, 0, 5, 129, asByteStringList("a", "android"));
peer.acceptFrame(); // SYN_REPLY
peer.play();
@@ -138,10 +140,10 @@ public final class SpdyConnectionTest {
IncomingStreamHandler handler = new IncomingStreamHandler() {
@Override public void receive(SpdyStream stream) throws IOException {
receiveCount.incrementAndGet();
assertEquals(Arrays.asList("a", "android"), stream.getRequestHeaders());
assertEquals(asByteStringList("a", "android"), stream.getRequestHeaders());
assertEquals(null, stream.getErrorCode());
assertEquals(5, stream.getPriority());
stream.reply(Arrays.asList("b", "banana"), true);
stream.reply(asByteStringList("b", "banana"), true);
}
};
new SpdyConnection.Builder(true, peer.openSocket()).handler(handler).build();
@@ -152,13 +154,13 @@ public final class SpdyConnectionTest {
assertEquals(HeadersMode.SPDY_REPLY, reply.headersMode);
assertFalse(reply.inFinished);
assertEquals(2, reply.streamId);
assertEquals(Arrays.asList("b", "banana"), reply.nameValueBlock);
assertEquals(asByteStringList("b", "banana"), reply.nameValueBlock);
assertEquals(1, receiveCount.get());
}
@Test public void replyWithNoData() throws Exception {
// write the mocking script
peer.sendFrame().synStream(false, false, 2, 0, 0, 0, Arrays.asList("a", "android"));
peer.sendFrame().synStream(false, false, 2, 0, 0, 0, asByteStringList("a", "android"));
peer.acceptFrame(); // SYN_REPLY
peer.play();
@@ -166,7 +168,7 @@ public final class SpdyConnectionTest {
final AtomicInteger receiveCount = new AtomicInteger();
IncomingStreamHandler handler = new IncomingStreamHandler() {
@Override public void receive(SpdyStream stream) throws IOException {
stream.reply(Arrays.asList("b", "banana"), false);
stream.reply(asByteStringList("b", "banana"), false);
receiveCount.incrementAndGet();
}
};
@@ -177,7 +179,7 @@ public final class SpdyConnectionTest {
assertEquals(TYPE_HEADERS, reply.type);
assertEquals(HeadersMode.SPDY_REPLY, reply.headersMode);
assertTrue(reply.inFinished);
assertEquals(Arrays.asList("b", "banana"), reply.nameValueBlock);
assertEquals(asByteStringList("b", "banana"), reply.nameValueBlock);
assertEquals(1, receiveCount.get());
}
@@ -327,7 +329,7 @@ public final class SpdyConnectionTest {
@Test public void bogusReplyFrameDoesNotDisruptConnection() throws Exception {
// write the mocking script
peer.sendFrame().synReply(false, 42, Arrays.asList("a", "android"));
peer.sendFrame().synReply(false, 42, asByteStringList("a", "android"));
peer.acceptFrame(); // RST_STREAM
peer.sendFrame().ping(false, 2, 0);
peer.acceptFrame(); // PING
@@ -348,7 +350,7 @@ public final class SpdyConnectionTest {
@Test public void clientClosesClientOutputStream() throws Exception {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.sendFrame().synReply(false, 1, Arrays.asList("b", "banana"));
peer.sendFrame().synReply(false, 1, asByteStringList("b", "banana"));
peer.acceptFrame(); // TYPE_DATA
peer.acceptFrame(); // TYPE_DATA with FLAG_FIN
peer.acceptFrame(); // PING
@@ -359,7 +361,7 @@ public final class SpdyConnectionTest {
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket())
.handler(REJECT_INCOMING_STREAMS)
.build();
SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), true, false);
SpdyStream stream = connection.newStream(asByteStringList("a", "android"), true, false);
OutputStream out = stream.getOutputStream();
out.write("square".getBytes(UTF_8));
out.flush();
@@ -405,7 +407,7 @@ public final class SpdyConnectionTest {
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket())
.handler(REJECT_INCOMING_STREAMS)
.build();
SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), true, true);
SpdyStream stream = connection.newStream(asByteStringList("a", "android"), true, true);
OutputStream out = stream.getOutputStream();
connection.ping().roundTripTime(); // Ensure that the RST_CANCEL has been received.
try {
@@ -447,7 +449,7 @@ public final class SpdyConnectionTest {
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket())
.handler(REJECT_INCOMING_STREAMS)
.build();
SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), false, true);
SpdyStream stream = connection.newStream(asByteStringList("a", "android"), false, true);
InputStream in = stream.getInputStream();
OutputStream out = stream.getOutputStream();
in.close();
@@ -492,7 +494,7 @@ public final class SpdyConnectionTest {
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket())
.handler(REJECT_INCOMING_STREAMS)
.build();
SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), true, true);
SpdyStream stream = connection.newStream(asByteStringList("a", "android"), true, true);
InputStream in = stream.getInputStream();
OutputStream out = stream.getOutputStream();
in.close();
@@ -528,7 +530,7 @@ public final class SpdyConnectionTest {
@Test public void serverClosesClientInputStream() throws Exception {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.sendFrame().synReply(false, 1, Arrays.asList("b", "banana"));
peer.sendFrame().synReply(false, 1, asByteStringList("b", "banana"));
peer.sendFrame().data(true, 1, "square".getBytes(UTF_8));
peer.play();
@@ -536,7 +538,7 @@ public final class SpdyConnectionTest {
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket())
.handler(REJECT_INCOMING_STREAMS)
.build();
SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), false, true);
SpdyStream stream = connection.newStream(asByteStringList("a", "android"), false, true);
InputStream in = stream.getInputStream();
assertStreamData("square", in);
assertEquals(0, connection.openStreamCount());
@@ -552,17 +554,17 @@ public final class SpdyConnectionTest {
@Test public void remoteDoubleSynReply() throws Exception {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android"));
peer.sendFrame().synReply(false, 1, asByteStringList("a", "android"));
peer.acceptFrame(); // PING
peer.sendFrame().synReply(false, 1, Arrays.asList("b", "banana"));
peer.sendFrame().synReply(false, 1, asByteStringList("b", "banana"));
peer.sendFrame().ping(true, 1, 0);
peer.acceptFrame(); // RST_STREAM
peer.play();
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("c", "cola"), true, true);
assertEquals(Arrays.asList("a", "android"), stream.getResponseHeaders());
SpdyStream stream = connection.newStream(asByteStringList("c", "cola"), true, true);
assertEquals(asByteStringList("a", "android"), stream.getResponseHeaders());
connection.ping().roundTripTime(); // Ensure that the 2nd SYN REPLY has been received.
try {
stream.getInputStream().read();
@@ -585,9 +587,9 @@ public final class SpdyConnectionTest {
@Test public void remoteDoubleSynStream() throws Exception {
// write the mocking script
peer.sendFrame().synStream(false, false, 2, 0, 0, 0, Arrays.asList("a", "android"));
peer.sendFrame().synStream(false, false, 2, 0, 0, 0, asByteStringList("a", "android"));
peer.acceptFrame(); // SYN_REPLY
peer.sendFrame().synStream(false, false, 2, 0, 0, 0, Arrays.asList("b", "banana"));
peer.sendFrame().synStream(false, false, 2, 0, 0, 0, asByteStringList("b", "banana"));
peer.acceptFrame(); // RST_STREAM
peer.play();
@@ -596,9 +598,9 @@ public final class SpdyConnectionTest {
IncomingStreamHandler handler = new IncomingStreamHandler() {
@Override public void receive(SpdyStream stream) throws IOException {
receiveCount.incrementAndGet();
assertEquals(Arrays.asList("a", "android"), stream.getRequestHeaders());
assertEquals(asByteStringList("a", "android"), stream.getRequestHeaders());
assertEquals(null, stream.getErrorCode());
stream.reply(Arrays.asList("c", "cola"), true);
stream.reply(asByteStringList("c", "cola"), true);
}
};
new SpdyConnection.Builder(true, peer.openSocket()).handler(handler).build();
@@ -617,7 +619,7 @@ public final class SpdyConnectionTest {
@Test public void remoteSendsDataAfterInFinished() throws Exception {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android"));
peer.sendFrame().synReply(false, 1, asByteStringList("a", "android"));
peer.sendFrame().data(true, 1, "robot".getBytes("UTF-8"));
peer.sendFrame().data(true, 1, "c3po".getBytes("UTF-8")); // Ignored.
peer.sendFrame().ping(false, 2, 0); // Ping just to make sure the stream was fastforwarded.
@@ -626,8 +628,8 @@ public final class SpdyConnectionTest {
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("b", "banana"), true, true);
assertEquals(Arrays.asList("a", "android"), stream.getResponseHeaders());
SpdyStream stream = connection.newStream(asByteStringList("b", "banana"), true, true);
assertEquals(asByteStringList("a", "android"), stream.getResponseHeaders());
assertStreamData("robot", stream.getInputStream());
// verify the peer received what was expected
@@ -642,7 +644,7 @@ public final class SpdyConnectionTest {
@Test public void remoteSendsTooMuchData() throws Exception {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.sendFrame().synReply(false, 1, Arrays.asList("b", "banana"));
peer.sendFrame().synReply(false, 1, asByteStringList("b", "banana"));
peer.sendFrame().data(false, 1, new byte[64 * 1024 + 1]);
peer.acceptFrame(); // RST_STREAM
peer.sendFrame().ping(false, 2, 0); // Ping just to make sure the stream was fastforwarded.
@@ -651,8 +653,8 @@ public final class SpdyConnectionTest {
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), true, true);
assertEquals(Arrays.asList("b", "banana"), stream.getResponseHeaders());
SpdyStream stream = connection.newStream(asByteStringList("a", "android"), true, true);
assertEquals(asByteStringList("b", "banana"), stream.getResponseHeaders());
// verify the peer received what was expected
MockSpdyPeer.InFrame synStream = peer.takeFrame();
@@ -677,7 +679,7 @@ public final class SpdyConnectionTest {
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), true, true);
SpdyStream stream = connection.newStream(asByteStringList("a", "android"), true, true);
try {
stream.getResponseHeaders();
fail();
@@ -707,8 +709,8 @@ public final class SpdyConnectionTest {
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream1 = connection.newStream(Arrays.asList("a", "android"), true, true);
SpdyStream stream2 = connection.newStream(Arrays.asList("b", "banana"), true, true);
SpdyStream stream1 = connection.newStream(asByteStringList("a", "android"), true, true);
SpdyStream stream2 = connection.newStream(asByteStringList("b", "banana"), true, true);
connection.ping().roundTripTime(); // Ensure that the GO_AWAY has been received.
stream1.getOutputStream().write("abc".getBytes(UTF_8));
try {
@@ -720,7 +722,7 @@ public final class SpdyConnectionTest {
stream1.getOutputStream().write("def".getBytes(UTF_8));
stream1.getOutputStream().close();
try {
connection.newStream(Arrays.asList("c", "cola"), true, true);
connection.newStream(asByteStringList("c", "cola"), true, true);
fail();
} catch (IOException expected) {
assertEquals("shutdown", expected.getMessage());
@@ -745,13 +747,13 @@ public final class SpdyConnectionTest {
peer.acceptFrame(); // SYN_STREAM 1
peer.acceptFrame(); // GOAWAY
peer.acceptFrame(); // PING
peer.sendFrame().synStream(false, false, 2, 0, 0, 0, Arrays.asList("b", "b")); // Should be ignored!
peer.sendFrame().synStream(false, false, 2, 0, 0, 0, asByteStringList("b", "b")); // Should be ignored!
peer.sendFrame().ping(true, 1, 0);
peer.play();
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
connection.newStream(Arrays.asList("a", "android"), true, true);
connection.newStream(asByteStringList("a", "android"), true, true);
Ping ping = connection.ping();
connection.shutdown(PROTOCOL_ERROR);
assertEquals(1, connection.openStreamCount());
@@ -798,12 +800,12 @@ public final class SpdyConnectionTest {
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), true, true);
SpdyStream stream = connection.newStream(asByteStringList("a", "android"), true, true);
assertEquals(1, connection.openStreamCount());
connection.close();
assertEquals(0, connection.openStreamCount());
try {
connection.newStream(Arrays.asList("b", "banana"), true, true);
connection.newStream(asByteStringList("b", "banana"), true, true);
fail();
} catch (IOException expected) {
assertEquals("shutdown", expected.getMessage());
@@ -848,14 +850,14 @@ public final class SpdyConnectionTest {
@Test public void readTimeoutExpires() throws Exception {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android"));
peer.sendFrame().synReply(false, 1, asByteStringList("a", "android"));
peer.acceptFrame(); // PING
peer.sendFrame().ping(true, 1, 0);
peer.play();
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("b", "banana"), true, true);
SpdyStream stream = connection.newStream(asByteStringList("b", "banana"), true, true);
stream.setReadTimeout(1000);
InputStream in = stream.getInputStream();
long startNanos = System.nanoTime();
@@ -878,16 +880,16 @@ public final class SpdyConnectionTest {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.acceptFrame(); // PING
peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android"));
peer.sendFrame().headers(1, Arrays.asList("c", "c3po"));
peer.sendFrame().synReply(false, 1, asByteStringList("a", "android"));
peer.sendFrame().headers(1, asByteStringList("c", "c3po"));
peer.sendFrame().ping(true, 1, 0);
peer.play();
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("b", "banana"), true, true);
SpdyStream stream = connection.newStream(asByteStringList("b", "banana"), true, true);
connection.ping().roundTripTime(); // Ensure that the HEADERS has been received.
assertEquals(Arrays.asList("a", "android", "c", "c3po"), stream.getResponseHeaders());
assertEquals(asByteStringList("a", "android", "c", "c3po"), stream.getResponseHeaders());
// verify the peer received what was expected
MockSpdyPeer.InFrame synStream = peer.takeFrame();
@@ -901,14 +903,14 @@ public final class SpdyConnectionTest {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.acceptFrame(); // PING
peer.sendFrame().headers(1, Arrays.asList("c", "c3po"));
peer.sendFrame().headers(1, asByteStringList("c", "c3po"));
peer.acceptFrame(); // RST_STREAM
peer.sendFrame().ping(true, 1, 0);
peer.play();
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("b", "banana"), true, true);
SpdyStream stream = connection.newStream(asByteStringList("b", "banana"), true, true);
connection.ping().roundTripTime(); // Ensure that the HEADERS has been received.
try {
stream.getResponseHeaders();
@@ -931,7 +933,7 @@ public final class SpdyConnectionTest {
@Test public void readSendsWindowUpdate() throws Exception {
// Write the mocking script.
peer.acceptFrame(); // SYN_STREAM
peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android"));
peer.sendFrame().synReply(false, 1, asByteStringList("a", "android"));
for (int i = 0; i < 3; i++) {
peer.sendFrame().data(false, 1, new byte[WINDOW_UPDATE_THRESHOLD]);
peer.acceptFrame(); // WINDOW UPDATE
@@ -941,8 +943,8 @@ public final class SpdyConnectionTest {
// Play it back.
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("b", "banana"), true, true);
assertEquals(Arrays.asList("a", "android"), stream.getResponseHeaders());
SpdyStream stream = connection.newStream(asByteStringList("b", "banana"), true, true);
assertEquals(asByteStringList("a", "android"), stream.getResponseHeaders());
InputStream in = stream.getInputStream();
int total = 0;
byte[] buffer = new byte[1024];
@@ -974,7 +976,7 @@ public final class SpdyConnectionTest {
// Play it back.
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("b", "banana"), true, true);
SpdyStream stream = connection.newStream(asByteStringList("b", "banana"), true, true);
OutputStream out = stream.getOutputStream();
out.write(new byte[Settings.DEFAULT_INITIAL_WINDOW_SIZE]);
interruptAfterDelay(500);
@@ -995,14 +997,14 @@ public final class SpdyConnectionTest {
@Test public void testTruncatedDataFrame() throws Exception {
// write the mocking script
peer.acceptFrame(); // SYN_STREAM
peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android"));
peer.sendFrame().synReply(false, 1, asByteStringList("a", "android"));
peer.sendTruncatedFrame(8 + 100).data(false, 1, new byte[1024]);
peer.play();
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("b", "banana"), true, true);
assertEquals(Arrays.asList("a", "android"), stream.getResponseHeaders());
SpdyStream stream = connection.newStream(asByteStringList("b", "banana"), true, true);
assertEquals(asByteStringList("a", "android"), stream.getResponseHeaders());
InputStream in = stream.getInputStream();
try {
Util.readFully(in, new byte[101]);
@@ -1033,9 +1035,9 @@ public final class SpdyConnectionTest {
// play it back
SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build();
SpdyStream stream = connection.newStream(Arrays.asList("b", "banana"), true, true);
assertEquals("a", stream.getResponseHeaders().get(0));
assertEquals(60, stream.getResponseHeaders().get(1).length());
SpdyStream stream = connection.newStream(asByteStringList("b", "banana"), true, true);
assertEquals("a", stream.getResponseHeaders().get(0).utf8());
assertEquals(60, stream.getResponseHeaders().get(1).size());
assertStreamData("robot", stream.getInputStream());
}

View File

@@ -19,6 +19,7 @@ package com.squareup.okhttp.internal.http;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.internal.ByteString;
import com.squareup.okhttp.internal.spdy.ErrorCode;
import com.squareup.okhttp.internal.spdy.SpdyConnection;
import com.squareup.okhttp.internal.spdy.SpdyStream;
@@ -79,27 +80,29 @@ public final class SpdyTransport implements Transport {
* 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(Request request, String protocol, String version) {
public static List<ByteString> writeNameValueBlock(Request request, String protocol,
String version) {
Headers headers = request.headers();
List<String> result = new ArrayList<String>(headers.size() + 10);
result.add(":method");
result.add(request.method());
result.add(":path");
result.add(RequestLine.requestPath(request.url()));
result.add(":version");
result.add(version);
// TODO: make the known header names constants.
List<ByteString> result = new ArrayList<ByteString>(headers.size() + 10);
result.add(ByteString.encodeUtf8(":method"));
result.add(ByteString.encodeUtf8(request.method()));
result.add(ByteString.encodeUtf8(":path"));
result.add(ByteString.encodeUtf8(RequestLine.requestPath(request.url())));
result.add(ByteString.encodeUtf8(":version"));
result.add(ByteString.encodeUtf8(version));
if (protocol.equals("spdy/3")) {
result.add(":host");
result.add(ByteString.encodeUtf8(":host"));
} else if (protocol.equals("HTTP-draft-09/2.0")) {
result.add(":authority");
result.add(ByteString.encodeUtf8(":authority"));
} else {
throw new AssertionError();
}
result.add(HttpEngine.hostHeader(request.url()));
result.add(":scheme");
result.add(request.url().getProtocol());
result.add(ByteString.encodeUtf8(HttpEngine.hostHeader(request.url())));
result.add(ByteString.encodeUtf8(":scheme"));
result.add(ByteString.encodeUtf8(request.url().getProtocol()));
Set<String> names = new LinkedHashSet<String>();
Set<ByteString> names = new LinkedHashSet<ByteString>();
for (int i = 0; i < headers.size(); i++) {
String name = headers.name(i).toLowerCase(Locale.US);
String value = headers.value(i);
@@ -118,16 +121,16 @@ public final class SpdyTransport implements Transport {
}
// 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);
if (names.add(ByteString.encodeUtf8(name))) {
result.add(ByteString.encodeUtf8(name));
result.add(ByteString.encodeUtf8(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);
if (result.get(j).utf8Equals(name)) {
result.set(j + 1, ByteString.encodeUtf8(result.get(j + 1).utf8() + "\0" + value));
break;
}
}
@@ -136,8 +139,8 @@ public final class SpdyTransport implements Transport {
}
/** Returns headers for a name value block containing a SPDY response. */
public static Response.Builder readNameValueBlock(List<String> nameValueBlock, String protocol)
throws IOException {
public static Response.Builder readNameValueBlock(List<ByteString> nameValueBlock,
String protocol) throws IOException {
if (nameValueBlock.size() % 2 != 0) {
throw new IllegalArgumentException("Unexpected name value block: " + nameValueBlock);
}
@@ -147,8 +150,8 @@ public final class SpdyTransport implements Transport {
Headers.Builder headersBuilder = new Headers.Builder();
headersBuilder.set(OkHeaders.SELECTED_TRANSPORT, protocol);
for (int i = 0; i < nameValueBlock.size(); i += 2) {
String name = nameValueBlock.get(i);
String values = nameValueBlock.get(i + 1);
String name = nameValueBlock.get(i).utf8();
String values = nameValueBlock.get(i + 1).utf8();
for (int start = 0; start < values.length(); ) {
int end = values.indexOf('\0', start);
if (end == -1) {

View File

@@ -18,20 +18,22 @@ package com.squareup.okhttp.internal.http;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.internal.ByteString;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import static com.squareup.okhttp.internal.Util.asByteStringList;
import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertEquals;
public final class HeadersTest {
@Test public void parseNameValueBlock() throws IOException {
List<String> nameValueBlock = Arrays.asList(
"cache-control", "no-cache, no-store",
"set-cookie", "Cookie1\u0000Cookie2",
":status", "200 OK",
List<ByteString> nameValueBlock = asByteStringList( //
"cache-control", "no-cache, no-store", //
"set-cookie", "Cookie1\u0000Cookie2", //
":status", "200 OK", //
":version", "HTTP/1.1");
Request request = new Request.Builder().url("http://square.com/").build();
Response response =
@@ -55,9 +57,9 @@ public final class HeadersTest {
}
@Test public void readNameValueBlockDropsForbiddenHeadersSpdy3() throws IOException {
List<String> nameValueBlock = Arrays.asList(
":status", "200 OK",
":version", "HTTP/1.1",
List<ByteString> nameValueBlock = asByteStringList( //
":status", "200 OK", //
":version", "HTTP/1.1", //
"connection", "close");
Request request = new Request.Builder().url("http://square.com/").build();
Response response =
@@ -69,9 +71,9 @@ public final class HeadersTest {
}
@Test public void readNameValueBlockDropsForbiddenHeadersHttp2() throws IOException {
List<String> nameValueBlock = Arrays.asList(
":status", "200 OK",
":version", "HTTP/1.1",
List<ByteString> nameValueBlock = asByteStringList( //
":status", "200 OK", //
":version", "HTTP/1.1", //
"connection", "close");
Request request = new Request.Builder().url("http://square.com/").build();
Response response =
@@ -90,15 +92,15 @@ public final class HeadersTest {
.addHeader("set-cookie", "Cookie2")
.header(":status", "200 OK")
.build();
List<String> nameValueBlock = SpdyTransport.writeNameValueBlock(request, "spdy/3", "HTTP/1.1");
List<String> expected = Arrays.asList(
":method", "GET",
":path", "/",
":version", "HTTP/1.1",
":host", "square.com",
":scheme", "http",
"cache-control", "no-cache, no-store",
"set-cookie", "Cookie1\u0000Cookie2",
List<ByteString> nameValueBlock = SpdyTransport.writeNameValueBlock(request, "spdy/3", "HTTP/1.1");
List<ByteString> expected = asByteStringList( //
":method", "GET", //
":path", "/", //
":version", "HTTP/1.1", //
":host", "square.com", //
":scheme", "http", //
"cache-control", "no-cache, no-store", //
"set-cookie", "Cookie1\u0000Cookie2", //
":status", "200 OK");
assertEquals(expected, nameValueBlock);
}
@@ -109,11 +111,11 @@ public final class HeadersTest {
.header("Connection", "close")
.header("Transfer-Encoding", "chunked")
.build();
List<String> expected = Arrays.asList(
":method", "GET",
":path", "/",
":version", "HTTP/1.1",
":host", "square.com",
List<ByteString> expected = asByteStringList( //
":method", "GET", //
":path", "/", //
":version", "HTTP/1.1", //
":host", "square.com", //
":scheme", "http");
assertEquals(expected, SpdyTransport.writeNameValueBlock(request, "spdy/3", "HTTP/1.1"));
}
@@ -124,11 +126,11 @@ public final class HeadersTest {
.header("Connection", "upgrade")
.header("Upgrade", "websocket")
.build();
List<String> expected = Arrays.asList(
":method", "GET",
":path", "/",
":version", "HTTP/1.1",
":authority", "square.com",
List<ByteString> expected = asByteStringList( //
":method", "GET", //
":path", "/", //
":version", "HTTP/1.1", //
":authority", "square.com", //
":scheme", "http");
assertEquals(expected,
SpdyTransport.writeNameValueBlock(request, "HTTP-draft-09/2.0", "HTTP/1.1"));