diff options
author | dmziegler@chromium.org <dmziegler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-01 22:21:23 +0000 |
---|---|---|
committer | dmziegler@chromium.org <dmziegler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-01 22:21:23 +0000 |
commit | 585df96b44f1fbbdc8ee1cc14ee2096ab3a0e9d1 (patch) | |
tree | ac08c8e6cbb2910e2be8aac04b0e323a15f9f59e | |
parent | 93a7a14ea110d5da8b9ee3a3e1adb9cdb176abd1 (diff) | |
download | chromium_src-585df96b44f1fbbdc8ee1cc14ee2096ab3a0e9d1.zip chromium_src-585df96b44f1fbbdc8ee1cc14ee2096ab3a0e9d1.tar.gz chromium_src-585df96b44f1fbbdc8ee1cc14ee2096ab3a0e9d1.tar.bz2 |
QuicServer: Use Chrome's header parsing rather than Balsa
It used to be that the QuicInMemoryCache mapped Balsa request headers to
Balsa responses, initializing the cache by using Balsa to parse
responses out of files in a specified directory. Then,
QuicSpdyServerStream would use Balsa to parse the incoming request
headers to pass of to the QuicInMemoryCache.
Now, instead of BalsaHeaders, I've made the QuicInMemoryCache be keyed by GURL, since it was ignoring all the other parts of the request headers anyway. Thus, QuicSpdyServerStream now constructs GURLs
by converting them from SPDY headers that are parsed out of the request,
and converts the resulting HttpResponseHeaders from the
QuicInMemoryCache into writable SPDY headers by using a new helper
function SpdyHttpUtils::CreateSpdyHeadersFromHttpResponse.
I removed the dependency on Balsa and tested the code by running the
quic_server binary.
R=wtc,rch@chromium.org
BUG=
Review URL: https://codereview.chromium.org/337093003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@280901 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/BUILD.gn | 1 | ||||
-rw-r--r-- | net/net.gyp | 1 | ||||
-rw-r--r-- | net/quic/quic_http_stream.cc | 2 | ||||
-rw-r--r-- | net/quic/quic_in_memory_cache.cc | 218 | ||||
-rw-r--r-- | net/quic/quic_in_memory_cache.h | 35 | ||||
-rw-r--r-- | net/quic/quic_spdy_server_stream.cc | 80 | ||||
-rw-r--r-- | net/quic/quic_spdy_server_stream.h | 10 | ||||
-rw-r--r-- | net/quic/spdy_utils.cc | 7 | ||||
-rw-r--r-- | net/quic/spdy_utils.h | 2 | ||||
-rw-r--r-- | net/spdy/hpack_huffman_aggregator.cc | 2 | ||||
-rw-r--r-- | net/spdy/spdy_http_stream.cc | 4 | ||||
-rw-r--r-- | net/spdy/spdy_http_utils.cc | 52 | ||||
-rw-r--r-- | net/spdy/spdy_http_utils.h | 16 | ||||
-rw-r--r-- | net/spdy/spdy_proxy_client_socket.cc | 5 |
14 files changed, 214 insertions, 221 deletions
diff --git a/net/BUILD.gn b/net/BUILD.gn index 06ab3f8..db3e631 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn @@ -1041,7 +1041,6 @@ source_set("quic_tools") { "quic/quic_time_wait_list_manager.h", ] deps = [ - ":balsa", ":net", "//base", "//base/third_party/dynamic_annotations", diff --git a/net/net.gyp b/net/net.gyp index bfe78d7..db7f277 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -1124,7 +1124,6 @@ '../base/base.gyp:base', '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../url/url.gyp:url_lib', - 'balsa', 'net', ], 'sources': [ diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc index 20b60de..36eac6a 100644 --- a/net/quic/quic_http_stream.cc +++ b/net/quic/quic_http_stream.cc @@ -112,7 +112,7 @@ int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers, stream_->set_priority(priority); // Store the serialized request headers. CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, - &request_headers_, SPDY3, /*direct=*/true); + SPDY3, /*direct=*/true, &request_headers_); // Store the request body. request_body_stream_ = request_info_->upload_data_stream; diff --git a/net/quic/quic_in_memory_cache.cc b/net/quic/quic_in_memory_cache.cc index 9d40fa5..58c6e90 100644 --- a/net/quic/quic_in_memory_cache.cc +++ b/net/quic/quic_in_memory_cache.cc @@ -7,7 +7,9 @@ #include "base/files/file_enumerator.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" -#include "net/tools/balsa/balsa_headers.h" +#include "base/strings/string_util.h" +#include "net/http/http_util.h" +#include "url/gurl.h" using base::FilePath; using base::StringPiece; @@ -21,45 +23,11 @@ namespace net { FilePath::StringType g_quic_in_memory_cache_dir = FILE_PATH_LITERAL(""); -namespace { - -// BalsaVisitor implementation (glue) which caches response bodies. -class CachingBalsaVisitor : public NoOpBalsaVisitor { - public: - CachingBalsaVisitor() : done_framing_(false) {} - virtual void ProcessBodyData(const char* input, size_t size) OVERRIDE { - AppendToBody(input, size); - } - virtual void MessageDone() OVERRIDE { - done_framing_ = true; - } - virtual void HandleHeaderError(BalsaFrame* framer) OVERRIDE { - UnhandledError(); - } - virtual void HandleHeaderWarning(BalsaFrame* framer) OVERRIDE { - UnhandledError(); - } - virtual void HandleChunkingError(BalsaFrame* framer) OVERRIDE { - UnhandledError(); - } - virtual void HandleBodyError(BalsaFrame* framer) OVERRIDE { - UnhandledError(); - } - void UnhandledError() { - LOG(DFATAL) << "Unhandled error framing HTTP."; - } - void AppendToBody(const char* input, size_t size) { - body_.append(input, size); - } - bool done_framing() const { return done_framing_; } - const string& body() const { return body_; } - - private: - bool done_framing_; - string body_; -}; +QuicInMemoryCache::Response::Response() : response_type_(REGULAR_RESPONSE) { +} -} // namespace +QuicInMemoryCache::Response::~Response() { +} // static QuicInMemoryCache* QuicInMemoryCache::GetInstance() { @@ -67,58 +35,56 @@ QuicInMemoryCache* QuicInMemoryCache::GetInstance() { } const QuicInMemoryCache::Response* QuicInMemoryCache::GetResponse( - const BalsaHeaders& request_headers) const { - ResponseMap::const_iterator it = responses_.find(GetKey(request_headers)); + const GURL& url) const { + ResponseMap::const_iterator it = responses_.find(GetKey(url)); if (it == responses_.end()) { return NULL; } return it->second; } -void QuicInMemoryCache::AddSimpleResponse(StringPiece method, - StringPiece path, +void QuicInMemoryCache::AddSimpleResponse(StringPiece path, StringPiece version, StringPiece response_code, StringPiece response_detail, StringPiece body) { - BalsaHeaders request_headers, response_headers; - request_headers.SetRequestFirstlineFromStringPieces(method, - path, - version); - response_headers.SetRequestFirstlineFromStringPieces(version, - response_code, - response_detail); - response_headers.AppendHeader( - "content-length", - base::Uint64ToString(static_cast<uint64>(body.length()))); - - AddResponse(request_headers, response_headers, body); + GURL url("http://" + path.as_string()); + + string status_line = version.as_string() + " " + + response_code.as_string() + " " + + response_detail.as_string(); + + string header = "content-length: " + + base::Uint64ToString(static_cast<uint64>(body.length())); + + scoped_refptr<HttpResponseHeaders> response_headers = + new HttpResponseHeaders(status_line + '\0' + header + '\0' + '\0'); + + AddResponse(url, response_headers, body); } -void QuicInMemoryCache::AddResponse(const BalsaHeaders& request_headers, - const BalsaHeaders& response_headers, - StringPiece response_body) { - VLOG(1) << "Adding response for: " << GetKey(request_headers); - if (ContainsKey(responses_, GetKey(request_headers))) { +void QuicInMemoryCache::AddResponse( + const GURL& url, + scoped_refptr<HttpResponseHeaders> response_headers, + StringPiece response_body) { + string key = GetKey(url); + VLOG(1) << "Adding response for: " << key; + if (ContainsKey(responses_, key)) { LOG(DFATAL) << "Response for given request already exists!"; return; } Response* new_response = new Response(); new_response->set_headers(response_headers); new_response->set_body(response_body); - responses_[GetKey(request_headers)] = new_response; + responses_[key] = new_response; } -void QuicInMemoryCache::AddSpecialResponse(StringPiece method, - StringPiece path, - StringPiece version, +void QuicInMemoryCache::AddSpecialResponse(StringPiece path, SpecialResponseType response_type) { - BalsaHeaders request_headers, response_headers; - request_headers.SetRequestFirstlineFromStringPieces(method, - path, - version); - AddResponse(request_headers, response_headers, ""); - responses_[GetKey(request_headers)]->response_type_ = response_type; + GURL url("http://" + path.as_string()); + + AddResponse(url, NULL, string()); + responses_[GetKey(url)]->response_type_ = response_type; } QuicInMemoryCache::QuicInMemoryCache() { @@ -145,78 +111,63 @@ void QuicInMemoryCache::Initialize() { base::FileEnumerator::FILES); FilePath file = file_list.Next(); - while (!file.empty()) { + for (; !file.empty(); file = file_list.Next()) { // Need to skip files in .svn directories - if (file.value().find(FILE_PATH_LITERAL("/.svn/")) != std::string::npos) { - file = file_list.Next(); + if (file.value().find(FILE_PATH_LITERAL("/.svn/")) != string::npos) { continue; } - BalsaHeaders request_headers, response_headers; - string file_contents; base::ReadFileToString(file, &file_contents); - // Frame HTTP. - CachingBalsaVisitor caching_visitor; - BalsaFrame framer; - framer.set_balsa_headers(&response_headers); - framer.set_balsa_visitor(&caching_visitor); - size_t processed = 0; - while (processed < file_contents.length() && - !caching_visitor.done_framing()) { - processed += framer.ProcessInput(file_contents.c_str() + processed, - file_contents.length() - processed); + if (file_contents.length() > INT_MAX) { + LOG(WARNING) << "File '" << file.value() << "' too large: " + << file_contents.length(); + continue; } + int file_len = static_cast<int>(file_contents.length()); - string response_headers_str; - response_headers.DumpToString(&response_headers_str); - if (!caching_visitor.done_framing()) { - LOG(DFATAL) << "Did not frame entire message from file: " << file.value() - << " (" << processed << " of " << file_contents.length() - << " bytes)."; - } - if (processed < file_contents.length()) { - // Didn't frame whole file. Assume remainder is body. - // This sometimes happens as a result of incompatibilities between - // BalsaFramer and wget's serialization of HTTP sans content-length. - caching_visitor.AppendToBody(file_contents.c_str() + processed, - file_contents.length() - processed); - processed += file_contents.length(); + int headers_end = HttpUtil::LocateEndOfHeaders(file_contents.data(), + file_len); + if (headers_end < 1) { + LOG(DFATAL) << "Headers invalid or empty, ignoring: " << file.value(); + continue; } - string utf8_file = file.AsUTF8Unsafe(); - StringPiece base = utf8_file; - if (response_headers.HasHeader("X-Original-Url")) { - base = response_headers.GetHeader("X-Original-Url"); - response_headers.RemoveAllOfHeader("X-Original-Url"); - // Remove the protocol so that the string is of the form host + path, - // which is parsed properly below. - if (StringPieceUtils::StartsWithIgnoreCase(base, "https://")) { - base.remove_prefix(8); - } else if (StringPieceUtils::StartsWithIgnoreCase(base, "http://")) { - base.remove_prefix(7); + string raw_headers = + HttpUtil::AssembleRawHeaders(file_contents.data(), headers_end); + + scoped_refptr<HttpResponseHeaders> response_headers = + new HttpResponseHeaders(raw_headers); + + string base; + if (response_headers->GetNormalizedHeader("X-Original-Url", &base)) { + response_headers->RemoveHeader("X-Original-Url"); + // Remove the protocol so we can add it below. + if (StartsWithASCII(base, "https://", false)) { + base = base.substr(8); + } else if (StartsWithASCII(base, "http://", false)) { + base = base.substr(7); } + } else { + base = file.AsUTF8Unsafe(); + } + if (base.length() == 0 || base[0] == '/') { + LOG(DFATAL) << "Invalid path, ignoring: " << base; + continue; } - size_t path_start = base.find_first_of('/'); - DCHECK_LT(0U, path_start); - StringPiece host(base.substr(0, path_start)); - StringPiece path(base.substr(path_start)); - if (path[path.length() - 1] == ',') { - path.remove_suffix(1); + if (base[base.length() - 1] == ',') { + base = base.substr(0, base.length() - 1); } - // Set up request headers. Assume method is GET and protocol is HTTP/1.1. - request_headers.SetRequestFirstlineFromStringPieces("GET", - path, - "HTTP/1.1"); - request_headers.ReplaceOrAppendHeader("host", host); - VLOG(1) << "Inserting 'http://" << GetKey(request_headers) - << "' into QuicInMemoryCache."; + GURL url("http://" + base); - AddResponse(request_headers, response_headers, caching_visitor.body()); + VLOG(1) << "Inserting '" << GetKey(url) << "' into QuicInMemoryCache."; - file = file_list.Next(); + StringPiece body(file_contents.data() + headers_end, + file_contents.size() - headers_end); + + AddResponse(url, response_headers, body); } } @@ -224,20 +175,9 @@ QuicInMemoryCache::~QuicInMemoryCache() { STLDeleteValues(&responses_); } -string QuicInMemoryCache::GetKey(const BalsaHeaders& request_headers) const { - StringPiece uri = request_headers.request_uri(); - if (uri.size() == 0) { - return ""; - } - StringPiece host; - if (uri[0] == '/') { - host = request_headers.GetHeader("host"); - } else if (StringPieceUtils::StartsWithIgnoreCase(uri, "https://")) { - uri.remove_prefix(8); - } else if (StringPieceUtils::StartsWithIgnoreCase(uri, "http://")) { - uri.remove_prefix(7); - } - return host.as_string() + uri.as_string(); +string QuicInMemoryCache::GetKey(const GURL& url) const { + // Take everything but the scheme portion of the URL. + return url.host() + url.PathForRequest(); } } // namespace net diff --git a/net/quic/quic_in_memory_cache.h b/net/quic/quic_in_memory_cache.h index 32dc8d4..e37ce2b 100644 --- a/net/quic/quic_in_memory_cache.h +++ b/net/quic/quic_in_memory_cache.h @@ -11,12 +11,10 @@ #include "base/file_util.h" #include "base/memory/singleton.h" #include "base/strings/string_piece.h" -#include "net/base/net_export.h" -#include "net/tools/balsa/balsa_frame.h" -#include "net/tools/balsa/balsa_headers.h" -#include "net/tools/balsa/noop_balsa_visitor.h" +#include "net/http/http_response_headers.h" template <typename T> struct DefaultSingletonTraits; +class GURL; namespace net { @@ -42,25 +40,25 @@ class QuicInMemoryCache { // Container for response header/body pairs. class Response { public: - Response() : response_type_(REGULAR_RESPONSE) {} - ~Response() {} + Response(); + ~Response(); SpecialResponseType response_type() const { return response_type_; } - const BalsaHeaders& headers() const { return headers_; } + const HttpResponseHeaders& headers() const { return *headers_; } const base::StringPiece body() const { return base::StringPiece(body_); } private: friend class QuicInMemoryCache; - void set_headers(const BalsaHeaders& headers) { - headers_.CopyFrom(headers); + void set_headers(scoped_refptr<HttpResponseHeaders> headers) { + headers_ = headers; } void set_body(base::StringPiece body) { body.CopyToString(&body_); } SpecialResponseType response_type_; - BalsaHeaders headers_; + scoped_refptr<HttpResponseHeaders> headers_; std::string body_; DISALLOW_COPY_AND_ASSIGN(Response); @@ -72,26 +70,23 @@ class QuicInMemoryCache { // Retrieve a response from this cache for a given request. // If no appropriate response exists, NULL is returned. // Currently, responses are selected based on request URI only. - const Response* GetResponse(const BalsaHeaders& request_headers) const; + const Response* GetResponse(const GURL& url) const; // Adds a simple response to the cache. The response headers will - // only contain the "content-length" header with the lenght of |body|. - void AddSimpleResponse(base::StringPiece method, - base::StringPiece path, + // only contain the "content-length" header with the length of |body|. + void AddSimpleResponse(base::StringPiece path, base::StringPiece version, base::StringPiece response_code, base::StringPiece response_detail, base::StringPiece body); // Add a response to the cache. - void AddResponse(const BalsaHeaders& request_headers, - const BalsaHeaders& response_headers, + void AddResponse(const GURL& url, + scoped_refptr<HttpResponseHeaders> response_headers, base::StringPiece response_body); // Simulate a special behavior at a particular path. - void AddSpecialResponse(base::StringPiece method, - base::StringPiece path, - base::StringPiece version, + void AddSpecialResponse(base::StringPiece path, SpecialResponseType response_type); private: @@ -106,7 +101,7 @@ class QuicInMemoryCache { void Initialize(); - std::string GetKey(const BalsaHeaders& response_headers) const; + std::string GetKey(const GURL& url) const; // Cached responses. ResponseMap responses_; diff --git a/net/quic/quic_spdy_server_stream.cc b/net/quic/quic_spdy_server_stream.cc index de6917d..bc67bb9 100644 --- a/net/quic/quic_spdy_server_stream.cc +++ b/net/quic/quic_spdy_server_stream.cc @@ -5,14 +5,16 @@ #include "net/quic/quic_spdy_server_stream.h" #include "base/memory/singleton.h" +#include "base/strings/string_number_conversions.h" #include "net/quic/quic_in_memory_cache.h" #include "net/quic/quic_session.h" +#include "net/quic/spdy_utils.h" #include "net/spdy/spdy_framer.h" -#include "net/tools/quic/spdy_utils.h" +#include "net/spdy/spdy_header_block.h" +#include "net/spdy/spdy_http_utils.h" using base::StringPiece; using std::string; -using net::tools::SpdyUtils; namespace net { @@ -23,26 +25,26 @@ QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id, : QuicDataStream(id, session), read_buf_(new GrowableIOBuffer()), request_headers_received_(false) { + read_buf_->SetCapacity(kHeaderBufInitialSize); } QuicSpdyServerStream::~QuicSpdyServerStream() { } uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 data_len) { - uint32 total_bytes_processed = 0; - // Are we still reading the request headers. if (!request_headers_received_) { // Grow the read buffer if necessary. - if (read_buf_->RemainingCapacity() < (int)data_len) { - read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize); + while (read_buf_->RemainingCapacity() < (int)data_len) { + read_buf_->SetCapacity(read_buf_->capacity() * 2); } memcpy(read_buf_->data(), data, data_len); read_buf_->set_offset(read_buf_->offset() + data_len); + // Try parsing the request headers. This will set request_headers_received_ + // if successful; if not, it will be tried again with more data. ParseRequestHeaders(); } else { - body_.append(data + total_bytes_processed, - data_len - total_bytes_processed); + body_.append(data, data_len); } return data_len; } @@ -55,44 +57,57 @@ void QuicSpdyServerStream::OnFinRead() { if (!request_headers_received_) { SendErrorResponse(); // We're not done reading headers. - } else if ((headers_.content_length_status() == - BalsaHeadersEnums::VALID_CONTENT_LENGTH) && - body_.size() != headers_.content_length()) { + return; + } + + SpdyHeaderBlock::const_iterator it = headers_.find("content-length"); + size_t content_length; + if (it != headers_.end() && + (!base::StringToSizeT(it->second, &content_length) || + body_.size() != content_length)) { SendErrorResponse(); // Invalid content length - } else { - SendResponse(); + return; } + + SendResponse(); } -size_t QuicSpdyServerStream::ParseRequestHeaders() { - size_t read_buf_len = static_cast<size_t>(read_buf_->offset()); - SpdyFramer framer(SPDY3); - SpdyHeaderBlock headers; +// Try parsing the request headers. If successful, sets +// request_headers_received_. If not successful, it can just be tried again once +// there's more data. +void QuicSpdyServerStream::ParseRequestHeaders() { + SpdyFramer framer((kDefaultSpdyMajorVersion)); char* data = read_buf_->StartOfBuffer(); - size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(), - &headers); + size_t read_buf_len = static_cast<size_t>(read_buf_->offset()); + size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_len, &headers_); if (len == 0) { - return -1; + // Not enough data yet, presumably. (If we still don't succeed by the end of + // the stream, then we'll error above.) + return; } - if (!SpdyUtils::FillBalsaRequestHeaders(headers, &headers_)) { + // Headers received and parsed: extract the request URL. + request_url_ = GetUrlFromHeaderBlock(headers_, + kDefaultSpdyMajorVersion, + false); + if (!request_url_.is_valid()) { SendErrorResponse(); - return -1; + return; } + // Add any data past the headers to the request body. size_t delta = read_buf_len - len; if (delta > 0) { body_.append(data + len, delta); } request_headers_received_ = true; - return len; } void QuicSpdyServerStream::SendResponse() { // Find response in cache. If not found, send error response. const QuicInMemoryCache::Response* response = - QuicInMemoryCache::GetInstance()->GetResponse(headers_); + QuicInMemoryCache::GetInstance()->GetResponse(request_url_); if (response == NULL) { SendErrorResponse(); return; @@ -115,23 +130,24 @@ void QuicSpdyServerStream::SendResponse() { void QuicSpdyServerStream::SendErrorResponse() { DVLOG(1) << "Sending error response for stream " << id(); - BalsaHeaders headers; - headers.SetResponseFirstlineFromStringPieces( - "HTTP/1.1", "500", "Server Error"); - headers.ReplaceOrAppendHeader("content-length", "3"); - SendHeadersAndBody(headers, "bad"); + scoped_refptr<HttpResponseHeaders> headers + = new HttpResponseHeaders(string("HTTP/1.1 500 Server Error") + '\0' + + "content-length: 3" + '\0' + '\0'); + SendHeadersAndBody(*headers, "bad"); } void QuicSpdyServerStream::SendHeadersAndBody( - const BalsaHeaders& response_headers, + const HttpResponseHeaders& response_headers, StringPiece body) { // We only support SPDY and HTTP, and neither handles bidirectional streaming. if (!read_side_closed()) { CloseReadSide(); } - SpdyHeaderBlock header_block = - SpdyUtils::ResponseHeadersToSpdyHeaders(response_headers); + SpdyHeaderBlock header_block; + CreateSpdyHeadersFromHttpResponse(response_headers, + kDefaultSpdyMajorVersion, + &header_block); WriteHeaders(header_block, body.empty(), NULL); diff --git a/net/quic/quic_spdy_server_stream.h b/net/quic/quic_spdy_server_stream.h index 31d750c..3cecb6b 100644 --- a/net/quic/quic_spdy_server_stream.h +++ b/net/quic/quic_spdy_server_stream.h @@ -11,10 +11,11 @@ #include "net/base/io_buffer.h" #include "net/quic/quic_data_stream.h" #include "net/quic/quic_protocol.h" -#include "net/tools/balsa/balsa_headers.h" +#include "url/gurl.h" namespace net { +class HttpResponseHeaders; class QuicSession; namespace test { @@ -33,7 +34,7 @@ class QuicSpdyServerStream : public QuicDataStream { virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE; virtual void OnFinRead() OVERRIDE; - size_t ParseRequestHeaders(); + void ParseRequestHeaders(); private: friend class test::QuicSpdyServerStreamPeer; @@ -46,11 +47,12 @@ class QuicSpdyServerStream : public QuicDataStream { // for the body void SendErrorResponse(); - void SendHeadersAndBody(const BalsaHeaders& response_headers, + void SendHeadersAndBody(const HttpResponseHeaders& response_headers, base::StringPiece body); - BalsaHeaders headers_; + SpdyHeaderBlock headers_; string body_; + GURL request_url_; // Buffer into which response header data is read. scoped_refptr<GrowableIOBuffer> read_buf_; diff --git a/net/quic/spdy_utils.cc b/net/quic/spdy_utils.cc index c0894d5..d863746 100644 --- a/net/quic/spdy_utils.cc +++ b/net/quic/spdy_utils.cc @@ -15,9 +15,10 @@ namespace net { // static string SpdyUtils::SerializeUncompressedHeaders(const SpdyHeaderBlock& headers) { - int length = SpdyFramer::GetSerializedLength(SPDY3, &headers); - SpdyFrameBuilder builder(length, SPDY3); - SpdyFramer::WriteHeaderBlock(&builder, SPDY3, &headers); + int length = SpdyFramer::GetSerializedLength(kDefaultSpdyMajorVersion, + &headers); + SpdyFrameBuilder builder(length, kDefaultSpdyMajorVersion); + SpdyFramer::WriteHeaderBlock(&builder, kDefaultSpdyMajorVersion, &headers); scoped_ptr<SpdyFrame> block(builder.take()); return string(block->data(), length); } diff --git a/net/quic/spdy_utils.h b/net/quic/spdy_utils.h index 14d3300..efb72a0 100644 --- a/net/quic/spdy_utils.h +++ b/net/quic/spdy_utils.h @@ -12,6 +12,8 @@ namespace net { +const SpdyMajorVersion kDefaultSpdyMajorVersion = SPDY3; + class NET_EXPORT_PRIVATE SpdyUtils { public: static std::string SerializeUncompressedHeaders( diff --git a/net/spdy/hpack_huffman_aggregator.cc b/net/spdy/hpack_huffman_aggregator.cc index 507f872..a54f5cd 100644 --- a/net/spdy/hpack_huffman_aggregator.cc +++ b/net/spdy/hpack_huffman_aggregator.cc @@ -58,7 +58,7 @@ void HpackHuffmanAggregator::AggregateTransactionCharacterCounts( { SpdyHeaderBlock headers; CreateSpdyHeadersFromHttpRequest( - request, request_headers, &headers, SPDY4, false); + request, request_headers, SPDY4, false, &headers); std::string tmp_out; encoder->EncodeHeaderSet(headers, &tmp_out); diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc index 055d46f..7ae8441 100644 --- a/net/spdy/spdy_http_stream.cc +++ b/net/spdy/spdy_http_stream.cc @@ -263,8 +263,8 @@ int SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers, scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); CreateSpdyHeadersFromHttpRequest( *request_info_, request_headers, - headers.get(), stream_->GetProtocolVersion(), - direct_); + stream_->GetProtocolVersion(), direct_, + headers.get()); stream_->net_log().AddEvent( NetLog::TYPE_HTTP_TRANSACTION_SPDY_SEND_REQUEST_HEADERS, base::Bind(&SpdyHeaderBlockNetLogCallback, headers.get())); diff --git a/net/spdy/spdy_http_utils.cc b/net/spdy/spdy_http_utils.cc index 448c82f..55f0395 100644 --- a/net/spdy/spdy_http_utils.cc +++ b/net/spdy/spdy_http_utils.cc @@ -20,6 +20,20 @@ namespace net { +namespace { + +void AddSpdyHeader(const std::string& name, + const std::string& value, + SpdyHeaderBlock* headers) { + if (headers->find(name) == headers->end()) { + (*headers)[name] = value; + } else { + (*headers)[name] += '\0' + value; + } +} + +} // namespace + bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers, SpdyMajorVersion protocol_version, HttpResponseInfo* response) { @@ -85,9 +99,9 @@ bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers, void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info, const HttpRequestHeaders& request_headers, - SpdyHeaderBlock* headers, SpdyMajorVersion protocol_version, - bool direct) { + bool direct, + SpdyHeaderBlock* headers) { HttpRequestHeaders::Iterator it(request_headers); while (it.GetNext()) { @@ -96,14 +110,7 @@ void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info, name == "transfer-encoding" || name == "host") { continue; } - if (headers->find(name) == headers->end()) { - (*headers)[name] = it.value(); - } else { - std::string new_value = (*headers)[name]; - new_value.append(1, '\0'); // +=() doesn't append 0's - new_value += it.value(); - (*headers)[name] = new_value; - } + AddSpdyHeader(name, it.value(), headers); } static const char kHttpProtocolVersion[] = "HTTP/1.1"; @@ -129,6 +136,31 @@ void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info, } } +void CreateSpdyHeadersFromHttpResponse( + const HttpResponseHeaders& response_headers, + SpdyMajorVersion protocol_version, + SpdyHeaderBlock* headers) { + std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status"; + std::string version_key = + (protocol_version >= SPDY3) ? ":version" : "version"; + + const std::string status_line = response_headers.GetStatusLine(); + std::string::const_iterator after_version = + std::find(status_line.begin(), status_line.end(), ' '); + if (protocol_version < SPDY4) { + (*headers)[version_key] = std::string(status_line.begin(), after_version); + } + (*headers)[status_key] = std::string(after_version + 1, status_line.end()); + + void* iter = NULL; + std::string raw_name, value; + while (response_headers.EnumerateHeaderLines(&iter, &raw_name, &value)) { + std::string name = StringToLowerASCII(raw_name); + AddSpdyHeader(name, value, headers); + } +} + + COMPILE_ASSERT(HIGHEST - LOWEST < 4 && HIGHEST - MINIMUM_PRIORITY < 5, request_priority_incompatible_with_spdy); diff --git a/net/spdy/spdy_http_utils.h b/net/spdy/spdy_http_utils.h index d15b6c7..a5c907b 100644 --- a/net/spdy/spdy_http_utils.h +++ b/net/spdy/spdy_http_utils.h @@ -17,6 +17,7 @@ namespace net { class HttpResponseInfo; struct HttpRequestInfo; class HttpRequestHeaders; +class HttpResponseHeaders; // Convert a SpdyHeaderBlock into an HttpResponseInfo. // |headers| input parameter with the SpdyHeaderBlock. @@ -27,14 +28,19 @@ bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers, SpdyMajorVersion protocol_version, HttpResponseInfo* response); -// Create a SpdyHeaderBlock for a Spdy SYN_STREAM Frame from -// HttpRequestInfo and HttpRequestHeaders. -void NET_EXPORT_PRIVATE CreateSpdyHeadersFromHttpRequest( +// Create a SpdyHeaderBlock from HttpRequestInfo and HttpRequestHeaders. +NET_EXPORT_PRIVATE void CreateSpdyHeadersFromHttpRequest( const HttpRequestInfo& info, const HttpRequestHeaders& request_headers, - SpdyHeaderBlock* headers, SpdyMajorVersion protocol_version, - bool direct); + bool direct, + SpdyHeaderBlock* headers); + +// Create a SpdyHeaderBlock from HttpResponseHeaders. +NET_EXPORT_PRIVATE void CreateSpdyHeadersFromHttpResponse( + const HttpResponseHeaders& response_headers, + SpdyMajorVersion protocol_version, + SpdyHeaderBlock* headers); // Returns the URL associated with the |headers| by assembling the // scheme, host and path from the protocol specific keys. diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc index d268a4d..afc1953 100644 --- a/net/spdy/spdy_proxy_client_socket.cc +++ b/net/spdy/spdy_proxy_client_socket.cc @@ -367,8 +367,9 @@ int SpdyProxyClientSocket::DoSendRequest() { request_.extra_headers.MergeFrom(request_headers); scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock()); - CreateSpdyHeadersFromHttpRequest(request_, request_headers, headers.get(), - spdy_stream_->GetProtocolVersion(), true); + CreateSpdyHeadersFromHttpRequest(request_, request_headers, + spdy_stream_->GetProtocolVersion(), true, + headers.get()); // Reset the URL to be the endpoint of the connection if (spdy_stream_->GetProtocolVersion() > 2) { (*headers)[":path"] = endpoint_.ToString(); |