| // Copyright (c) 2010 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/string_number_conversions.h" |
| #include "base/string_util.h" |
| #include "base/time.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 spdy::SpdyHeaderBlock& headers, |
| HttpResponseInfo* response) { |
| std::string version; |
| std::string status; |
| |
| // The "status" and "version" headers are required. |
| spdy::SpdyHeaderBlock::const_iterator it; |
| it = headers.find("status"); |
| if (it == headers.end()) |
| return false; |
| status = it->second; |
| |
| // Grab the version. If not provided by the server, |
| it = headers.find("version"); |
| if (it == headers.end()) |
| return false; |
| version = it->second; |
| |
| response->response_time = base::Time::Now(); |
| |
| 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); |
| 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, |
| spdy::SpdyHeaderBlock* headers, |
| 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"; |
| |
| (*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); |
| |
| } |
| |
| // TODO(gavinp): re-adjust this once SPDY v3 has three priority bits, |
| // eliminating the need for this folding. |
| int ConvertRequestPriorityToSpdyPriority(const RequestPriority priority) { |
| DCHECK(HIGHEST <= priority && priority < NUM_PRIORITIES); |
| switch (priority) { |
| case LOWEST: |
| return SPDY_PRIORITY_LOWEST - 1; |
| case IDLE: |
| return SPDY_PRIORITY_LOWEST; |
| default: |
| return priority; |
| } |
| } |
| |
| } // namespace net |