Cast: Fix rtcp event dedup logic in rtcp_receiver.
[chromium-blink-merge.git] / net / spdy / spdy_http_utils.cc
blob448c82ffd3ca9a2fc06f947f706e6082c36f8956
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 bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers,
24 SpdyMajorVersion protocol_version,
25 HttpResponseInfo* response) {
26 std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status";
27 std::string version_key =
28 (protocol_version >= SPDY3) ? ":version" : "version";
29 std::string version;
30 std::string status;
32 // The "status" header is required. "version" is required below SPDY4.
33 SpdyHeaderBlock::const_iterator it;
34 it = headers.find(status_key);
35 if (it == headers.end())
36 return false;
37 status = it->second;
39 if (protocol_version >= SPDY4) {
40 version = "HTTP/1.1";
41 } else {
42 it = headers.find(version_key);
43 if (it == headers.end())
44 return false;
45 version = it->second;
47 std::string raw_headers(version);
48 raw_headers.push_back(' ');
49 raw_headers.append(status);
50 raw_headers.push_back('\0');
51 for (it = headers.begin(); it != headers.end(); ++it) {
52 // For each value, if the server sends a NUL-separated
53 // list of values, we separate that back out into
54 // individual headers for each value in the list.
55 // e.g.
56 // Set-Cookie "foo\0bar"
57 // becomes
58 // Set-Cookie: foo\0
59 // Set-Cookie: bar\0
60 std::string value = it->second;
61 size_t start = 0;
62 size_t end = 0;
63 do {
64 end = value.find('\0', start);
65 std::string tval;
66 if (end != value.npos)
67 tval = value.substr(start, (end - start));
68 else
69 tval = value.substr(start);
70 if (protocol_version >= 3 && it->first[0] == ':')
71 raw_headers.append(it->first.substr(1));
72 else
73 raw_headers.append(it->first);
74 raw_headers.push_back(':');
75 raw_headers.append(tval);
76 raw_headers.push_back('\0');
77 start = end + 1;
78 } while (end != value.npos);
81 response->headers = new HttpResponseHeaders(raw_headers);
82 response->was_fetched_via_spdy = true;
83 return true;
86 void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info,
87 const HttpRequestHeaders& request_headers,
88 SpdyHeaderBlock* headers,
89 SpdyMajorVersion protocol_version,
90 bool direct) {
92 HttpRequestHeaders::Iterator it(request_headers);
93 while (it.GetNext()) {
94 std::string name = StringToLowerASCII(it.name());
95 if (name == "connection" || name == "proxy-connection" ||
96 name == "transfer-encoding" || name == "host") {
97 continue;
99 if (headers->find(name) == headers->end()) {
100 (*headers)[name] = it.value();
101 } else {
102 std::string new_value = (*headers)[name];
103 new_value.append(1, '\0'); // +=() doesn't append 0's
104 new_value += it.value();
105 (*headers)[name] = new_value;
108 static const char kHttpProtocolVersion[] = "HTTP/1.1";
110 if (protocol_version < SPDY3) {
111 (*headers)["version"] = kHttpProtocolVersion;
112 (*headers)["method"] = info.method;
113 (*headers)["host"] = GetHostAndOptionalPort(info.url);
114 (*headers)["scheme"] = info.url.scheme();
115 if (direct)
116 (*headers)["url"] = HttpUtil::PathForRequest(info.url);
117 else
118 (*headers)["url"] = HttpUtil::SpecForRequest(info.url);
119 } else {
120 if (protocol_version < SPDY4) {
121 (*headers)[":version"] = kHttpProtocolVersion;
122 (*headers)[":host"] = GetHostAndOptionalPort(info.url);
123 } else {
124 (*headers)[":authority"] = GetHostAndOptionalPort(info.url);
126 (*headers)[":method"] = info.method;
127 (*headers)[":scheme"] = info.url.scheme();
128 (*headers)[":path"] = HttpUtil::PathForRequest(info.url);
132 COMPILE_ASSERT(HIGHEST - LOWEST < 4 &&
133 HIGHEST - MINIMUM_PRIORITY < 5,
134 request_priority_incompatible_with_spdy);
136 SpdyPriority ConvertRequestPriorityToSpdyPriority(
137 const RequestPriority priority,
138 SpdyMajorVersion protocol_version) {
139 DCHECK_GE(priority, MINIMUM_PRIORITY);
140 DCHECK_LE(priority, MAXIMUM_PRIORITY);
141 if (protocol_version == SPDY2) {
142 // SPDY 2 only has 2 bits of priority, but we have 5 RequestPriorities.
143 // Map IDLE => 3, LOWEST => 2, LOW => 2, MEDIUM => 1, HIGHEST => 0.
144 if (priority > LOWEST) {
145 return static_cast<SpdyPriority>(HIGHEST - priority);
146 } else {
147 return static_cast<SpdyPriority>(HIGHEST - priority - 1);
149 } else {
150 return static_cast<SpdyPriority>(HIGHEST - priority);
154 NET_EXPORT_PRIVATE RequestPriority ConvertSpdyPriorityToRequestPriority(
155 SpdyPriority priority,
156 SpdyMajorVersion protocol_version) {
157 // Handle invalid values gracefully, and pick LOW to map 2 back
158 // to for SPDY/2.
159 SpdyPriority idle_cutoff = (protocol_version == SPDY2) ? 3 : 5;
160 return (priority >= idle_cutoff) ?
161 IDLE : static_cast<RequestPriority>(HIGHEST - priority);
164 GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers,
165 SpdyMajorVersion protocol_version,
166 bool pushed) {
167 // SPDY 2 server push urls are specified in a single "url" header.
168 if (pushed && protocol_version == SPDY2) {
169 std::string url;
170 SpdyHeaderBlock::const_iterator it;
171 it = headers.find("url");
172 if (it != headers.end())
173 url = it->second;
174 return GURL(url);
177 const char* scheme_header = protocol_version >= SPDY3 ? ":scheme" : "scheme";
178 const char* host_header = protocol_version >= SPDY4 ? ":authority" :
179 (protocol_version >= SPDY3 ? ":host" : "host");
180 const char* path_header = protocol_version >= SPDY3 ? ":path" : "url";
182 std::string scheme;
183 std::string host_port;
184 std::string path;
185 SpdyHeaderBlock::const_iterator it;
186 it = headers.find(scheme_header);
187 if (it != headers.end())
188 scheme = it->second;
189 it = headers.find(host_header);
190 if (it != headers.end())
191 host_port = it->second;
192 it = headers.find(path_header);
193 if (it != headers.end())
194 path = it->second;
196 std::string url = (scheme.empty() || host_port.empty() || path.empty())
197 ? std::string()
198 : scheme + "://" + host_port + path;
199 return GURL(url);
202 } // namespace net