summaryrefslogtreecommitdiffstats
path: root/net/quic
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-25 07:43:36 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-25 07:43:36 +0000
commit6cca996b2937c087759355f2a166b7b1c5623192 (patch)
tree8b6eb3212ae6c0f5e6ffe0db41cf5f889aa7e5b4 /net/quic
parentb6a837b8a0a8b4beb6fabb9ca9a5af8d14c63dde (diff)
downloadchromium_src-6cca996b2937c087759355f2a166b7b1c5623192.zip
chromium_src-6cca996b2937c087759355f2a166b7b1c5623192.tar.gz
chromium_src-6cca996b2937c087759355f2a166b7b1c5623192.tar.bz2
Change QuicHttpStream to use SPDY header blocks for reading/writing
HTTP headers, instead of vanilla HTTP headers. Review URL: https://chromiumcodereview.appspot.com/11859035 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@178771 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
-rw-r--r--net/quic/quic_http_stream.cc54
-rw-r--r--net/quic/quic_http_stream.h5
-rw-r--r--net/quic/quic_http_stream_test.cc115
-rw-r--r--net/quic/quic_stream_factory.cc5
4 files changed, 134 insertions, 45 deletions
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index bd3073a..4439ef7 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -14,13 +14,16 @@
#include "net/quic/quic_reliable_client_stream.h"
#include "net/quic/quic_utils.h"
#include "net/socket/next_proto.h"
+#include "net/spdy/spdy_frame_builder.h"
#include "net/spdy/spdy_framer.h"
+#include "net/spdy/spdy_http_utils.h"
namespace net {
static const size_t kHeaderBufInitialSize = 4096;
-QuicHttpStream::QuicHttpStream(QuicReliableClientStream* stream)
+QuicHttpStream::QuicHttpStream(QuicReliableClientStream* stream,
+ bool use_spdy)
: io_state_(STATE_NONE),
stream_(stream),
request_info_(NULL),
@@ -28,6 +31,7 @@ QuicHttpStream::QuicHttpStream(QuicReliableClientStream* stream)
response_info_(NULL),
response_status_(OK),
response_headers_received_(false),
+ use_spdy_(use_spdy),
read_buf_(new GrowableIOBuffer()),
user_buffer_len_(0),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
@@ -59,12 +63,22 @@ int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
CHECK(response);
// Store the serialized request headers.
- // TODO(rch): use SPDY serialization
- std::string path = HttpUtil::PathForRequest(request_info_->url);
- std::string first_line = base::StringPrintf("%s %s HTTP/1.1\r\n",
- request_info_->method.c_str(),
- path.c_str());
- request_ = first_line + request_headers.ToString();
+ if (use_spdy_) {
+ SpdyHeaderBlock headers;
+ CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers,
+ &headers, 3, /*direct=*/true);
+ size_t len = SpdyFramer::GetSerializedLength(3, &headers);
+ SpdyFrameBuilder builder(len);
+ SpdyFramer::WriteHeaderBlock(&builder, 3, &headers);
+ scoped_ptr<SpdyFrame> frame(builder.take());
+ request_ = std::string(frame->data(), len);
+ } else {
+ std::string path = HttpUtil::PathForRequest(request_info_->url);
+ std::string first_line = base::StringPrintf("%s %s HTTP/1.1\r\n",
+ request_info_->method.c_str(),
+ path.c_str());
+ request_ = first_line + request_headers.ToString();
+ }
// Store the request body.
request_body_stream_ = request_info_->upload_data_stream;
@@ -427,6 +441,32 @@ int QuicHttpStream::DoSendBodyComplete(int rv) {
}
int QuicHttpStream::ParseResponseHeaders() {
+ if (use_spdy_) {
+ size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
+ SpdyFramer framer(3);
+ SpdyHeaderBlock headers;
+ size_t len = framer.ParseHeaderBlockInBuffer(
+ read_buf_->StartOfBuffer(), read_buf_->offset(), &headers);
+
+ if (len == 0) {
+ return ERR_IO_PENDING;
+ }
+
+ // Save the remaining received data.
+ size_t delta = read_buf_len - len;
+ if (delta > 0) {
+ BufferResponseBody(read_buf_->data(), delta);
+ }
+
+ SpdyHeadersToHttpResponse(headers, 3, response_info_);
+ // Put the peer's IP address and port into the response.
+ IPEndPoint address = stream_->GetPeerAddress();
+ response_info_->socket_address = HostPortPair::FromIPEndPoint(address);
+ response_info_->vary_data.Init(*request_info_, *response_info_->headers);
+ response_headers_received_ = true;
+
+ return OK;
+ }
int end_offset = HttpUtil::LocateEndOfHeaders(read_buf_->StartOfBuffer(),
read_buf_->offset(), 0);
diff --git a/net/quic/quic_http_stream.h b/net/quic/quic_http_stream.h
index 0ca1f81..a3dd962 100644
--- a/net/quic/quic_http_stream.h
+++ b/net/quic/quic_http_stream.h
@@ -21,7 +21,7 @@ class NET_EXPORT_PRIVATE QuicHttpStream :
public QuicReliableClientStream::Delegate,
public HttpStream {
public:
- explicit QuicHttpStream(QuicReliableClientStream* stream);
+ QuicHttpStream(QuicReliableClientStream* stream, bool use_spdy);
virtual ~QuicHttpStream();
@@ -113,6 +113,9 @@ class NET_EXPORT_PRIVATE QuicHttpStream :
bool response_headers_received_;
+ // True if the request and response bodies should be serialized via SPDY.
+ bool use_spdy_;
+
// Serialized HTTP request.
std::string request_;
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index fd53f85..ee35d6d 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -19,6 +19,10 @@
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/test_task_runner.h"
#include "net/socket/socket_test_util.h"
+#include "net/spdy/spdy_frame_builder.h"
+#include "net/spdy/spdy_framer.h"
+#include "net/spdy/spdy_http_utils.h"
+#include "net/spdy/spdy_protocol.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -77,8 +81,8 @@ class TestCollector : public QuicReceiptMetricsCollector {
// is received.
class AutoClosingStream : public QuicHttpStream {
public:
- explicit AutoClosingStream(QuicReliableClientStream* stream)
- : QuicHttpStream(stream) {
+ AutoClosingStream(QuicReliableClientStream* stream, bool use_spdy)
+ : QuicHttpStream(stream, use_spdy) {
}
virtual int OnDataReceived(const char* data, int length) {
@@ -89,10 +93,9 @@ class AutoClosingStream : public QuicHttpStream {
} // namespace
-class QuicHttpStreamTest : public ::testing::Test {
+class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
protected:
const static bool kFin = true;
- const static bool kNoFin = false;
// Holds a packet to be written to the wire, and the IO mode that should
// be used by the mock socket when performing the write.
struct PacketToWrite {
@@ -176,9 +179,45 @@ class QuicHttpStreamTest : public ::testing::Test {
EXPECT_TRUE(session_->IsCryptoHandshakeComplete());
QuicReliableClientStream* stream =
session_->CreateOutgoingReliableStream();
- stream_.reset(use_closing_stream_ ? new AutoClosingStream(stream) :
- new QuicHttpStream(stream));
- }
+ stream_.reset(use_closing_stream_ ?
+ new AutoClosingStream(stream, GetParam()) :
+ new QuicHttpStream(stream, GetParam()));
+ }
+
+ void SetRequestString(const std::string& method, const std::string& path) {
+ if (GetParam() == true) {
+ SpdyHeaderBlock headers;
+ headers[":method"] = method;
+ headers[":host"] = "www.google.com";
+ headers[":path"] = path;
+ headers[":scheme"] = "http";
+ headers[":version"] = "HTTP/1.1";
+ request_data_ = SerializeHeaderBlock(headers);
+ } else {
+ request_data_ = method + " " + path + " HTTP/1.1\r\n\r\n";
+ }
+ }
+
+ void SetResponseString(const std::string& status, const std::string& body) {
+ if (GetParam() == true) {
+ SpdyHeaderBlock headers;
+ headers[":status"] = status;
+ headers[":version"] = "HTTP/1.1";
+ headers["content-type"] = "text/plain";
+ response_data_ = SerializeHeaderBlock(headers) + body;
+ } else {
+ response_data_ = "HTTP/1.1 " + status + " \r\n"
+ "Content-Type: text/plain\r\n\r\n" + body;
+ }
+ }
+
+ std::string SerializeHeaderBlock(const SpdyHeaderBlock& headers) {
+ size_t len = SpdyFramer::GetSerializedLength(3, &headers);
+ SpdyFrameBuilder builder(len);
+ SpdyFramer::WriteHeaderBlock(&builder, 3, &headers);
+ scoped_ptr<SpdyFrame> frame(builder.take());
+ return std::string(frame->data(), len);
+ }
// Returns a newly created packet to send kData on stream 1.
QuicEncryptedPacket* ConstructDataPacket(
@@ -231,6 +270,8 @@ class QuicHttpStreamTest : public ::testing::Test {
HttpRequestHeaders headers_;
HttpResponseInfo response_;
scoped_refptr<IOBufferWithSize> read_buffer_;
+ std::string request_data_;
+ std::string response_data_;
private:
void InitializeHeader(QuicPacketSequenceNumber sequence_number) {
@@ -260,25 +301,31 @@ class QuicHttpStreamTest : public ::testing::Test {
std::vector<PacketToWrite> writes_;
};
-TEST_F(QuicHttpStreamTest, RenewStreamForAuth) {
+// All tests are run with two different serializations, HTTP/SPDY
+INSTANTIATE_TEST_CASE_P(QuicHttpStreamTests,
+ QuicHttpStreamTest,
+ ::testing::Values(true, false));
+
+TEST_P(QuicHttpStreamTest, RenewStreamForAuth) {
EXPECT_EQ(NULL, stream_->RenewStreamForAuth());
}
-TEST_F(QuicHttpStreamTest, CanFindEndOfResponse) {
+TEST_P(QuicHttpStreamTest, CanFindEndOfResponse) {
EXPECT_TRUE(stream_->CanFindEndOfResponse());
}
-TEST_F(QuicHttpStreamTest, IsMoreDataBuffered) {
+TEST_P(QuicHttpStreamTest, IsMoreDataBuffered) {
EXPECT_FALSE(stream_->IsMoreDataBuffered());
}
-TEST_F(QuicHttpStreamTest, IsConnectionReusable) {
+TEST_P(QuicHttpStreamTest, IsConnectionReusable) {
EXPECT_FALSE(stream_->IsConnectionReusable());
}
-TEST_F(QuicHttpStreamTest, GetRequest) {
+TEST_P(QuicHttpStreamTest, GetRequest) {
+ SetRequestString("GET", "/");
AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0,
- "GET / HTTP/1.1\r\n\r\n"));
+ request_data_));
AddWrite(SYNCHRONOUS, ConstructAckPacket(2, 2, 2));
Initialize();
@@ -299,10 +346,9 @@ TEST_F(QuicHttpStreamTest, GetRequest) {
stream_->ReadResponseHeaders(callback_.callback()));
// Send the response without a body.
- const char kResponseHeaders[] = "HTTP/1.1 404 OK\r\n"
- "Content-Type: text/plain\r\n\r\n";
+ SetResponseString("404 Not Found", "");
scoped_ptr<QuicEncryptedPacket> resp(
- ConstructDataPacket(2, kFin, 0, kResponseHeaders));
+ ConstructDataPacket(2, kFin, 0, response_data_));
ProcessPacket(*resp);
// Now that the headers have been processed, the callback will return.
@@ -319,9 +365,9 @@ TEST_F(QuicHttpStreamTest, GetRequest) {
EXPECT_TRUE(AtEof());
}
-TEST_F(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) {
- AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0,
- "GET / HTTP/1.1\r\n\r\n"));
+TEST_P(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) {
+ SetRequestString("GET", "/");
+ AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0, request_data_));
AddWrite(SYNCHRONOUS, ConstructAckPacket(2, 2, 2));
Initialize();
@@ -342,16 +388,15 @@ TEST_F(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) {
stream_->ReadResponseHeaders(callback_.callback()));
// Send the response with a body.
- const char kResponseHeaders[] = "HTTP/1.1 404 OK\r\n"
- "Content-Type: text/plain\r\n\r\nhello world!";
+ SetResponseString("200 OK", "hello world!");
scoped_ptr<QuicEncryptedPacket> resp(
- ConstructDataPacket(2, kFin, 0, kResponseHeaders));
+ ConstructDataPacket(2, kFin, 0, response_data_));
ProcessPacket(*resp);
// Now that the headers have been processed, the callback will return.
EXPECT_EQ(OK, callback_.WaitForResult());
ASSERT_TRUE(response_.headers != NULL);
- EXPECT_EQ(404, response_.headers->response_code());
+ EXPECT_EQ(200, response_.headers->response_code());
EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
// There is no body, so this should return immediately.
@@ -363,10 +408,10 @@ TEST_F(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) {
EXPECT_TRUE(AtEof());
}
-TEST_F(QuicHttpStreamTest, SendPostRequest) {
- const char kRequestData[] = "POST / HTTP/1.1\r\n\r\n";
- AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kNoFin, 0, kRequestData));
- AddWrite(SYNCHRONOUS, ConstructDataPacket(2, kFin, strlen(kRequestData),
+TEST_P(QuicHttpStreamTest, SendPostRequest) {
+ SetRequestString("POST", "/");
+ AddWrite(SYNCHRONOUS, ConstructDataPacket(1, !kFin, 0, request_data_));
+ AddWrite(SYNCHRONOUS, ConstructDataPacket(2, kFin, request_data_.length(),
kUploadData));
AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2, 3));
@@ -392,10 +437,9 @@ TEST_F(QuicHttpStreamTest, SendPostRequest) {
ProcessPacket(*ack);
// Send the response headers (but not the body).
- const char kResponseHeaders[] = "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/plain\r\n\r\n";
+ SetResponseString("200 OK", "");
scoped_ptr<QuicEncryptedPacket> resp(
- ConstructDataPacket(2, kNoFin, 0, kResponseHeaders));
+ ConstructDataPacket(2, !kFin, 0, response_data_));
ProcessPacket(*resp);
// Since the headers have already arrived, this should return immediately.
@@ -407,7 +451,7 @@ TEST_F(QuicHttpStreamTest, SendPostRequest) {
// Send the response body.
const char kResponseBody[] = "Hello world!";
scoped_ptr<QuicEncryptedPacket> resp_body(
- ConstructDataPacket(3, kFin, strlen(kResponseHeaders), kResponseBody));
+ ConstructDataPacket(3, kFin, response_data_.length(), kResponseBody));
ProcessPacket(*resp_body);
// Since the body has already arrived, this should return immediately.
@@ -419,10 +463,10 @@ TEST_F(QuicHttpStreamTest, SendPostRequest) {
EXPECT_TRUE(AtEof());
}
-TEST_F(QuicHttpStreamTest, DestroyedEarly) {
- const char kRequest[] = "GET / HTTP/1.1\r\n\r\n";
- AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0, kRequest));
- AddWrite(SYNCHRONOUS, ConstructRstPacket(2, 3, strlen(kRequest)));
+TEST_P(QuicHttpStreamTest, DestroyedEarly) {
+ SetRequestString("GET", "/");
+ AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0, request_data_));
+ AddWrite(SYNCHRONOUS, ConstructRstPacket(2, 3, request_data_.length()));
AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2, 2));
use_closing_stream_ = true;
Initialize();
@@ -430,7 +474,6 @@ TEST_F(QuicHttpStreamTest, DestroyedEarly) {
request_.method = "GET";
request_.url = GURL("http://www.google.com/");
- //stream_.reset(new TestStream(session_->CreateOutgoingReliableStream()));
EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
callback_.callback()));
EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index c9191c9..e9908be 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -300,7 +300,7 @@ scoped_ptr<QuicHttpStream> QuicStreamFactory::CreateIfSessionExists(
QuicClientSession* session = active_sessions_[host_port_proxy_pair];
DCHECK(session);
return scoped_ptr<QuicHttpStream>(
- new QuicHttpStream(session->CreateOutgoingReliableStream()));
+ new QuicHttpStream(session->CreateOutgoingReliableStream(), true));
}
void QuicStreamFactory::OnIdleSession(QuicClientSession* session) {
@@ -331,6 +331,9 @@ void QuicStreamFactory::CloseAllSessions(int error) {
while (!active_sessions_.empty()) {
active_sessions_.begin()->second->CloseSessionOnError(error);
}
+ while (!all_sessions_.empty()) {
+ (*all_sessions_.begin())->CloseSessionOnError(error);
+ }
DCHECK(all_sessions_.empty());
}