diff options
author | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-25 07:43:36 +0000 |
---|---|---|
committer | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-25 07:43:36 +0000 |
commit | 6cca996b2937c087759355f2a166b7b1c5623192 (patch) | |
tree | 8b6eb3212ae6c0f5e6ffe0db41cf5f889aa7e5b4 /net/quic | |
parent | b6a837b8a0a8b4beb6fabb9ca9a5af8d14c63dde (diff) | |
download | chromium_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.cc | 54 | ||||
-rw-r--r-- | net/quic/quic_http_stream.h | 5 | ||||
-rw-r--r-- | net/quic/quic_http_stream_test.cc | 115 | ||||
-rw-r--r-- | net/quic/quic_stream_factory.cc | 5 |
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()); } |