diff options
Diffstat (limited to 'chromium/net/spdy/spdy_http_utils.cc')
-rw-r--r-- | chromium/net/spdy/spdy_http_utils.cc | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/chromium/net/spdy/spdy_http_utils.cc b/chromium/net/spdy/spdy_http_utils.cc new file mode 100644 index 00000000000..21012f23fc1 --- /dev/null +++ b/chromium/net/spdy/spdy_http_utils.cc @@ -0,0 +1,203 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/spdy/spdy_http_utils.h" + +#include <string> + +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/time/time.h" +#include "net/base/escape.h" +#include "net/base/load_flags.h" +#include "net/base/net_util.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_request_info.h" +#include "net/http/http_response_headers.h" +#include "net/http/http_response_info.h" +#include "net/http/http_util.h" + +namespace net { + +bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers, + int protocol_version, + HttpResponseInfo* response) { + std::string status_key = (protocol_version >= 3) ? ":status" : "status"; + std::string version_key = (protocol_version >= 3) ? ":version" : "version"; + std::string version; + std::string status; + + // The "status" and "version" headers are required. + SpdyHeaderBlock::const_iterator it; + it = headers.find(status_key); + if (it == headers.end()) + return false; + status = it->second; + + it = headers.find(version_key); + if (it == headers.end()) + return false; + version = it->second; + + std::string raw_headers(version); + raw_headers.push_back(' '); + raw_headers.append(status); + raw_headers.push_back('\0'); + for (it = headers.begin(); it != headers.end(); ++it) { + // For each value, if the server sends a NUL-separated + // list of values, we separate that back out into + // individual headers for each value in the list. + // e.g. + // Set-Cookie "foo\0bar" + // becomes + // Set-Cookie: foo\0 + // Set-Cookie: bar\0 + std::string value = it->second; + size_t start = 0; + size_t end = 0; + do { + end = value.find('\0', start); + std::string tval; + if (end != value.npos) + tval = value.substr(start, (end - start)); + else + tval = value.substr(start); + if (protocol_version >= 3 && it->first[0] == ':') + raw_headers.append(it->first.substr(1)); + else + raw_headers.append(it->first); + raw_headers.push_back(':'); + raw_headers.append(tval); + raw_headers.push_back('\0'); + start = end + 1; + } while (end != value.npos); + } + + response->headers = new HttpResponseHeaders(raw_headers); + response->was_fetched_via_spdy = true; + return true; +} + +void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info, + const HttpRequestHeaders& request_headers, + SpdyHeaderBlock* headers, + int protocol_version, + bool direct) { + + HttpRequestHeaders::Iterator it(request_headers); + while (it.GetNext()) { + std::string name = StringToLowerASCII(it.name()); + if (name == "connection" || name == "proxy-connection" || + name == "transfer-encoding") { + 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; + } + } + static const char kHttpProtocolVersion[] = "HTTP/1.1"; + + if (protocol_version < 3) { + (*headers)["version"] = kHttpProtocolVersion; + (*headers)["method"] = info.method; + (*headers)["host"] = GetHostAndOptionalPort(info.url); + (*headers)["scheme"] = info.url.scheme(); + if (direct) + (*headers)["url"] = HttpUtil::PathForRequest(info.url); + else + (*headers)["url"] = HttpUtil::SpecForRequest(info.url); + } else { + (*headers)[":version"] = kHttpProtocolVersion; + (*headers)[":method"] = info.method; + (*headers)[":host"] = GetHostAndOptionalPort(info.url); + (*headers)[":scheme"] = info.url.scheme(); + (*headers)[":path"] = HttpUtil::PathForRequest(info.url); + headers->erase("host"); // this is kinda insane, spdy 3 spec. + } + +} + +COMPILE_ASSERT(HIGHEST - LOWEST < 4 && + HIGHEST - MINIMUM_PRIORITY < 5, + request_priority_incompatible_with_spdy); + +SpdyPriority ConvertRequestPriorityToSpdyPriority( + const RequestPriority priority, + int protocol_version) { + DCHECK_GE(priority, MINIMUM_PRIORITY); + DCHECK_LT(priority, NUM_PRIORITIES); + if (protocol_version == 2) { + // SPDY 2 only has 2 bits of priority, but we have 5 RequestPriorities. + // Map IDLE => 3, LOWEST => 2, LOW => 2, MEDIUM => 1, HIGHEST => 0. + if (priority > LOWEST) { + return static_cast<SpdyPriority>(HIGHEST - priority); + } else { + return static_cast<SpdyPriority>(HIGHEST - priority - 1); + } + } else { + return static_cast<SpdyPriority>(HIGHEST - priority); + } +} + +NET_EXPORT_PRIVATE RequestPriority ConvertSpdyPriorityToRequestPriority( + SpdyPriority priority, + int protocol_version) { + // Handle invalid values gracefully, and pick LOW to map 2 back + // to for SPDY/2. + SpdyPriority idle_cutoff = (protocol_version == 2) ? 3 : 5; + return (priority >= idle_cutoff) ? + IDLE : static_cast<RequestPriority>(HIGHEST - priority); +} + +GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers, + int protocol_version, + bool pushed) { + // SPDY 2 server push urls are specified in a single "url" header. + if (pushed && protocol_version == 2) { + std::string url; + SpdyHeaderBlock::const_iterator it; + it = headers.find("url"); + if (it != headers.end()) + url = it->second; + return GURL(url); + } + + const char* scheme_header = protocol_version >= 3 ? ":scheme" : "scheme"; + const char* host_header = protocol_version >= 3 ? ":host" : "host"; + const char* path_header = protocol_version >= 3 ? ":path" : "url"; + + std::string scheme; + std::string host_port; + std::string path; + SpdyHeaderBlock::const_iterator it; + it = headers.find(scheme_header); + if (it != headers.end()) + scheme = it->second; + it = headers.find(host_header); + if (it != headers.end()) + host_port = it->second; + it = headers.find(path_header); + if (it != headers.end()) + path = it->second; + + std::string url = (scheme.empty() || host_port.empty() || path.empty()) + ? std::string() + : scheme + "://" + host_port + path; + return GURL(url); +} + +bool ShouldShowHttpHeaderValue(const std::string& header_name) { +#if defined(SPDY_PROXY_AUTH_ORIGIN) + if (header_name == "proxy-authorization") + return false; +#endif + return true; +} + +} // namespace net |