Log major user interactions with the WebsiteSettings (origin info) bubble.
[chromium-blink-merge.git] / net / spdy / spdy_http_utils.cc
blobb67e6996fb0fb054bb3bab17a47471a8a69fafca
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/spdy/spdy_http_utils.h"
7 #include <string>
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/time/time.h"
12 #include "net/base/escape.h"
13 #include "net/base/load_flags.h"
14 #include "net/base/net_util.h"
15 #include "net/http/http_request_headers.h"
16 #include "net/http/http_request_info.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/http/http_response_info.h"
19 #include "net/http/http_util.h"
21 namespace net {
23 namespace {
25 void AddSpdyHeader(const std::string& name,
26 const std::string& value,
27 SpdyHeaderBlock* headers) {
28 if (headers->find(name) == headers->end()) {
29 (*headers)[name] = value;
30 } else {
31 (*headers)[name] += '\0' + value;
35 } // namespace
37 bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers,
38 SpdyMajorVersion protocol_version,
39 HttpResponseInfo* response) {
40 std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status";
41 std::string version_key =
42 (protocol_version >= SPDY3) ? ":version" : "version";
43 std::string version;
44 std::string status;
46 // The "status" header is required. "version" is required below SPDY4.
47 SpdyHeaderBlock::const_iterator it;
48 it = headers.find(status_key);
49 if (it == headers.end())
50 return false;
51 status = it->second;
53 if (protocol_version >= SPDY4) {
54 version = "HTTP/1.1";
55 } else {
56 it = headers.find(version_key);
57 if (it == headers.end())
58 return false;
59 version = it->second;
61 std::string raw_headers(version);
62 raw_headers.push_back(' ');
63 raw_headers.append(status);
64 raw_headers.push_back('\0');
65 for (it = headers.begin(); it != headers.end(); ++it) {
66 // For each value, if the server sends a NUL-separated
67 // list of values, we separate that back out into
68 // individual headers for each value in the list.
69 // e.g.
70 // Set-Cookie "foo\0bar"
71 // becomes
72 // Set-Cookie: foo\0
73 // Set-Cookie: bar\0
74 std::string value = it->second;
75 size_t start = 0;
76 size_t end = 0;
77 do {
78 end = value.find('\0', start);
79 std::string tval;
80 if (end != value.npos)
81 tval = value.substr(start, (end - start));
82 else
83 tval = value.substr(start);
84 if (protocol_version >= 3 && it->first[0] == ':')
85 raw_headers.append(it->first.substr(1));
86 else
87 raw_headers.append(it->first);
88 raw_headers.push_back(':');
89 raw_headers.append(tval);
90 raw_headers.push_back('\0');
91 start = end + 1;
92 } while (end != value.npos);
95 response->headers = new HttpResponseHeaders(raw_headers);
96 response->was_fetched_via_spdy = true;
97 return true;
100 void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info,
101 const HttpRequestHeaders& request_headers,
102 SpdyMajorVersion protocol_version,
103 bool direct,
104 SpdyHeaderBlock* headers) {
106 HttpRequestHeaders::Iterator it(request_headers);
107 while (it.GetNext()) {
108 std::string name = base::StringToLowerASCII(it.name());
109 if (name == "connection" || name == "proxy-connection" ||
110 name == "transfer-encoding" || name == "host") {
111 continue;
113 AddSpdyHeader(name, it.value(), headers);
115 static const char kHttpProtocolVersion[] = "HTTP/1.1";
117 if (protocol_version < SPDY3) {
118 (*headers)["version"] = kHttpProtocolVersion;
119 (*headers)["method"] = info.method;
120 (*headers)["host"] = GetHostAndOptionalPort(info.url);
121 (*headers)["scheme"] = info.url.scheme();
122 if (direct)
123 (*headers)["url"] = HttpUtil::PathForRequest(info.url);
124 else
125 (*headers)["url"] = HttpUtil::SpecForRequest(info.url);
126 } else {
127 if (protocol_version < SPDY4) {
128 (*headers)[":version"] = kHttpProtocolVersion;
129 (*headers)[":host"] = GetHostAndOptionalPort(info.url);
130 } else {
131 (*headers)[":authority"] = GetHostAndOptionalPort(info.url);
133 (*headers)[":method"] = info.method;
134 (*headers)[":scheme"] = info.url.scheme();
135 (*headers)[":path"] = HttpUtil::PathForRequest(info.url);
139 void CreateSpdyHeadersFromHttpResponse(
140 const HttpResponseHeaders& response_headers,
141 SpdyMajorVersion protocol_version,
142 SpdyHeaderBlock* headers) {
143 std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status";
144 std::string version_key =
145 (protocol_version >= SPDY3) ? ":version" : "version";
147 const std::string status_line = response_headers.GetStatusLine();
148 std::string::const_iterator after_version =
149 std::find(status_line.begin(), status_line.end(), ' ');
150 if (protocol_version < SPDY4) {
151 (*headers)[version_key] = std::string(status_line.begin(), after_version);
153 (*headers)[status_key] = std::string(after_version + 1, status_line.end());
155 void* iter = NULL;
156 std::string raw_name, value;
157 while (response_headers.EnumerateHeaderLines(&iter, &raw_name, &value)) {
158 std::string name = base::StringToLowerASCII(raw_name);
159 AddSpdyHeader(name, value, headers);
164 COMPILE_ASSERT(HIGHEST - LOWEST < 4 &&
165 HIGHEST - MINIMUM_PRIORITY < 5,
166 request_priority_incompatible_with_spdy);
168 SpdyPriority ConvertRequestPriorityToSpdyPriority(
169 const RequestPriority priority,
170 SpdyMajorVersion protocol_version) {
171 DCHECK_GE(priority, MINIMUM_PRIORITY);
172 DCHECK_LE(priority, MAXIMUM_PRIORITY);
173 if (protocol_version == SPDY2) {
174 // SPDY 2 only has 2 bits of priority, but we have 5 RequestPriorities.
175 // Map IDLE => 3, LOWEST => 2, LOW => 2, MEDIUM => 1, HIGHEST => 0.
176 if (priority > LOWEST) {
177 return static_cast<SpdyPriority>(HIGHEST - priority);
178 } else {
179 return static_cast<SpdyPriority>(HIGHEST - priority - 1);
181 } else {
182 return static_cast<SpdyPriority>(HIGHEST - priority);
186 NET_EXPORT_PRIVATE RequestPriority ConvertSpdyPriorityToRequestPriority(
187 SpdyPriority priority,
188 SpdyMajorVersion protocol_version) {
189 // Handle invalid values gracefully, and pick LOW to map 2 back
190 // to for SPDY/2.
191 SpdyPriority idle_cutoff = (protocol_version == SPDY2) ? 3 : 5;
192 return (priority >= idle_cutoff) ?
193 IDLE : static_cast<RequestPriority>(HIGHEST - priority);
196 GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers,
197 SpdyMajorVersion protocol_version,
198 bool pushed) {
199 // SPDY 2 server push urls are specified in a single "url" header.
200 if (pushed && protocol_version == SPDY2) {
201 std::string url;
202 SpdyHeaderBlock::const_iterator it;
203 it = headers.find("url");
204 if (it != headers.end())
205 url = it->second;
206 return GURL(url);
209 const char* scheme_header = protocol_version >= SPDY3 ? ":scheme" : "scheme";
210 const char* host_header = protocol_version >= SPDY4 ? ":authority" :
211 (protocol_version >= SPDY3 ? ":host" : "host");
212 const char* path_header = protocol_version >= SPDY3 ? ":path" : "url";
214 std::string scheme;
215 std::string host_port;
216 std::string path;
217 SpdyHeaderBlock::const_iterator it;
218 it = headers.find(scheme_header);
219 if (it != headers.end())
220 scheme = it->second;
221 it = headers.find(host_header);
222 if (it != headers.end())
223 host_port = it->second;
224 it = headers.find(path_header);
225 if (it != headers.end())
226 path = it->second;
228 std::string url = (scheme.empty() || host_port.empty() || path.empty())
229 ? std::string()
230 : scheme + "://" + host_port + path;
231 return GURL(url);
234 } // namespace net