xref: /aosp_15_r20/external/cronet/net/spdy/spdy_http_utils.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_http_utils.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <string>
8*6777b538SAndroid Build Coastguard Worker #include <string_view>
9*6777b538SAndroid Build Coastguard Worker #include <vector>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/types/expected.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/types/expected_macros.h"
18*6777b538SAndroid Build Coastguard Worker #include "net/base/features.h"
19*6777b538SAndroid Build Coastguard Worker #include "net/base/url_util.h"
20*6777b538SAndroid Build Coastguard Worker #include "net/http/http_request_headers.h"
21*6777b538SAndroid Build Coastguard Worker #include "net/http/http_request_info.h"
22*6777b538SAndroid Build Coastguard Worker #include "net/http/http_response_headers.h"
23*6777b538SAndroid Build Coastguard Worker #include "net/http/http_response_info.h"
24*6777b538SAndroid Build Coastguard Worker #include "net/http/http_util.h"
25*6777b538SAndroid Build Coastguard Worker #include "net/quic/quic_http_utils.h"
26*6777b538SAndroid Build Coastguard Worker #include "net/third_party/quiche/src/quiche/quic/core/quic_stream_priority.h"
27*6777b538SAndroid Build Coastguard Worker #include "net/third_party/quiche/src/quiche/spdy/core/http2_header_block.h"
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker namespace net {
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker const char* const kHttp2PriorityHeader = "priority";
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker namespace {
34*6777b538SAndroid Build Coastguard Worker 
35*6777b538SAndroid Build Coastguard Worker // The number of bytes to reserve for the raw headers string to avoid having to
36*6777b538SAndroid Build Coastguard Worker // do reallocations most of the time. Equal to the 99th percentile of header
37*6777b538SAndroid Build Coastguard Worker // sizes in ricea@'s cache on 3 Aug 2023.
38*6777b538SAndroid Build Coastguard Worker constexpr size_t kExpectedRawHeaderSize = 4035;
39*6777b538SAndroid Build Coastguard Worker 
40*6777b538SAndroid Build Coastguard Worker // Add header `name` with `value` to `headers`. `name` must not already exist in
41*6777b538SAndroid Build Coastguard Worker // `headers`.
AddUniqueSpdyHeader(std::string_view name,std::string_view value,spdy::Http2HeaderBlock * headers)42*6777b538SAndroid Build Coastguard Worker void AddUniqueSpdyHeader(std::string_view name,
43*6777b538SAndroid Build Coastguard Worker                          std::string_view value,
44*6777b538SAndroid Build Coastguard Worker                          spdy::Http2HeaderBlock* headers) {
45*6777b538SAndroid Build Coastguard Worker   auto insert_result = headers->insert({name, value});
46*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(insert_result, spdy::Http2HeaderBlock::InsertResult::kInserted);
47*6777b538SAndroid Build Coastguard Worker }
48*6777b538SAndroid Build Coastguard Worker 
49*6777b538SAndroid Build Coastguard Worker // Convert `headers` to an HttpResponseHeaders object based on the features
50*6777b538SAndroid Build Coastguard Worker // enabled at runtime.
51*6777b538SAndroid Build Coastguard Worker base::expected<scoped_refptr<HttpResponseHeaders>, int>
SpdyHeadersToHttpResponseHeadersUsingFeatures(const spdy::Http2HeaderBlock & headers)52*6777b538SAndroid Build Coastguard Worker SpdyHeadersToHttpResponseHeadersUsingFeatures(
53*6777b538SAndroid Build Coastguard Worker     const spdy::Http2HeaderBlock& headers) {
54*6777b538SAndroid Build Coastguard Worker   if (base::FeatureList::IsEnabled(
55*6777b538SAndroid Build Coastguard Worker           features::kSpdyHeadersToHttpResponseUseBuilder)) {
56*6777b538SAndroid Build Coastguard Worker     return SpdyHeadersToHttpResponseHeadersUsingBuilder(headers);
57*6777b538SAndroid Build Coastguard Worker   } else {
58*6777b538SAndroid Build Coastguard Worker     return SpdyHeadersToHttpResponseHeadersUsingRawString(headers);
59*6777b538SAndroid Build Coastguard Worker   }
60*6777b538SAndroid Build Coastguard Worker }
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker }  // namespace
63*6777b538SAndroid Build Coastguard Worker 
SpdyHeadersToHttpResponse(const spdy::Http2HeaderBlock & headers,HttpResponseInfo * response)64*6777b538SAndroid Build Coastguard Worker int SpdyHeadersToHttpResponse(const spdy::Http2HeaderBlock& headers,
65*6777b538SAndroid Build Coastguard Worker                               HttpResponseInfo* response) {
66*6777b538SAndroid Build Coastguard Worker   ASSIGN_OR_RETURN(response->headers,
67*6777b538SAndroid Build Coastguard Worker                    SpdyHeadersToHttpResponseHeadersUsingFeatures(headers));
68*6777b538SAndroid Build Coastguard Worker   response->was_fetched_via_spdy = true;
69*6777b538SAndroid Build Coastguard Worker   return OK;
70*6777b538SAndroid Build Coastguard Worker }
71*6777b538SAndroid Build Coastguard Worker 
72*6777b538SAndroid Build Coastguard Worker NET_EXPORT_PRIVATE base::expected<scoped_refptr<HttpResponseHeaders>, int>
SpdyHeadersToHttpResponseHeadersUsingRawString(const spdy::Http2HeaderBlock & headers)73*6777b538SAndroid Build Coastguard Worker SpdyHeadersToHttpResponseHeadersUsingRawString(
74*6777b538SAndroid Build Coastguard Worker     const spdy::Http2HeaderBlock& headers) {
75*6777b538SAndroid Build Coastguard Worker   // The ":status" header is required.
76*6777b538SAndroid Build Coastguard Worker   spdy::Http2HeaderBlock::const_iterator it =
77*6777b538SAndroid Build Coastguard Worker       headers.find(spdy::kHttp2StatusHeader);
78*6777b538SAndroid Build Coastguard Worker   if (it == headers.end()) {
79*6777b538SAndroid Build Coastguard Worker     return base::unexpected(ERR_INCOMPLETE_HTTP2_HEADERS);
80*6777b538SAndroid Build Coastguard Worker   }
81*6777b538SAndroid Build Coastguard Worker 
82*6777b538SAndroid Build Coastguard Worker   const auto status = it->second;
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker   std::string raw_headers =
85*6777b538SAndroid Build Coastguard Worker       base::StrCat({"HTTP/1.1 ", status, std::string_view("\0", 1)});
86*6777b538SAndroid Build Coastguard Worker   raw_headers.reserve(kExpectedRawHeaderSize);
87*6777b538SAndroid Build Coastguard Worker   for (const auto& [name, value] : headers) {
88*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(name.size(), 0u);
89*6777b538SAndroid Build Coastguard Worker     if (name[0] == ':') {
90*6777b538SAndroid Build Coastguard Worker       // https://tools.ietf.org/html/rfc7540#section-8.1.2.4
91*6777b538SAndroid Build Coastguard Worker       // Skip pseudo headers.
92*6777b538SAndroid Build Coastguard Worker       continue;
93*6777b538SAndroid Build Coastguard Worker     }
94*6777b538SAndroid Build Coastguard Worker     // For each value, if the server sends a NUL-separated
95*6777b538SAndroid Build Coastguard Worker     // list of values, we separate that back out into
96*6777b538SAndroid Build Coastguard Worker     // individual headers for each value in the list.
97*6777b538SAndroid Build Coastguard Worker     // e.g.
98*6777b538SAndroid Build Coastguard Worker     //    Set-Cookie "foo\0bar"
99*6777b538SAndroid Build Coastguard Worker     // becomes
100*6777b538SAndroid Build Coastguard Worker     //    Set-Cookie: foo\0
101*6777b538SAndroid Build Coastguard Worker     //    Set-Cookie: bar\0
102*6777b538SAndroid Build Coastguard Worker     size_t start = 0;
103*6777b538SAndroid Build Coastguard Worker     size_t end = 0;
104*6777b538SAndroid Build Coastguard Worker     do {
105*6777b538SAndroid Build Coastguard Worker       end = value.find('\0', start);
106*6777b538SAndroid Build Coastguard Worker       std::string_view tval;
107*6777b538SAndroid Build Coastguard Worker       if (end != value.npos) {
108*6777b538SAndroid Build Coastguard Worker         tval = value.substr(start, (end - start));
109*6777b538SAndroid Build Coastguard Worker       } else {
110*6777b538SAndroid Build Coastguard Worker         tval = value.substr(start);
111*6777b538SAndroid Build Coastguard Worker       }
112*6777b538SAndroid Build Coastguard Worker       base::StrAppend(&raw_headers,
113*6777b538SAndroid Build Coastguard Worker                       {name, ":", tval, std::string_view("\0", 1)});
114*6777b538SAndroid Build Coastguard Worker       start = end + 1;
115*6777b538SAndroid Build Coastguard Worker     } while (end != value.npos);
116*6777b538SAndroid Build Coastguard Worker   }
117*6777b538SAndroid Build Coastguard Worker 
118*6777b538SAndroid Build Coastguard Worker   auto response_headers =
119*6777b538SAndroid Build Coastguard Worker       base::MakeRefCounted<HttpResponseHeaders>(raw_headers);
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   // When there are multiple location headers the response is a potential
122*6777b538SAndroid Build Coastguard Worker   // response smuggling attack.
123*6777b538SAndroid Build Coastguard Worker   if (HttpUtil::HeadersContainMultipleCopiesOfField(*response_headers,
124*6777b538SAndroid Build Coastguard Worker                                                     "location")) {
125*6777b538SAndroid Build Coastguard Worker     return base::unexpected(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION);
126*6777b538SAndroid Build Coastguard Worker   }
127*6777b538SAndroid Build Coastguard Worker 
128*6777b538SAndroid Build Coastguard Worker   return response_headers;
129*6777b538SAndroid Build Coastguard Worker }
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker NET_EXPORT_PRIVATE base::expected<scoped_refptr<HttpResponseHeaders>, int>
SpdyHeadersToHttpResponseHeadersUsingBuilder(const spdy::Http2HeaderBlock & headers)132*6777b538SAndroid Build Coastguard Worker SpdyHeadersToHttpResponseHeadersUsingBuilder(
133*6777b538SAndroid Build Coastguard Worker     const spdy::Http2HeaderBlock& headers) {
134*6777b538SAndroid Build Coastguard Worker   // The ":status" header is required.
135*6777b538SAndroid Build Coastguard Worker   // TODO(ricea): The ":status" header should always come first. Skip this hash
136*6777b538SAndroid Build Coastguard Worker   // lookup after we no longer need to be compatible with the old
137*6777b538SAndroid Build Coastguard Worker   // implementation.
138*6777b538SAndroid Build Coastguard Worker   spdy::Http2HeaderBlock::const_iterator it =
139*6777b538SAndroid Build Coastguard Worker       headers.find(spdy::kHttp2StatusHeader);
140*6777b538SAndroid Build Coastguard Worker   if (it == headers.end()) {
141*6777b538SAndroid Build Coastguard Worker     return base::unexpected(ERR_INCOMPLETE_HTTP2_HEADERS);
142*6777b538SAndroid Build Coastguard Worker   }
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker   const auto status = it->second;
145*6777b538SAndroid Build Coastguard Worker 
146*6777b538SAndroid Build Coastguard Worker   HttpResponseHeaders::Builder builder({1, 1}, status);
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker   for (const auto& [name, value] : headers) {
149*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(name.size(), 0u);
150*6777b538SAndroid Build Coastguard Worker     if (name[0] == ':') {
151*6777b538SAndroid Build Coastguard Worker       // https://tools.ietf.org/html/rfc7540#section-8.1.2.4
152*6777b538SAndroid Build Coastguard Worker       // Skip pseudo headers.
153*6777b538SAndroid Build Coastguard Worker       continue;
154*6777b538SAndroid Build Coastguard Worker     }
155*6777b538SAndroid Build Coastguard Worker     // For each value, if the server sends a NUL-separated
156*6777b538SAndroid Build Coastguard Worker     // list of values, we separate that back out into
157*6777b538SAndroid Build Coastguard Worker     // individual headers for each value in the list.
158*6777b538SAndroid Build Coastguard Worker     // e.g.
159*6777b538SAndroid Build Coastguard Worker     //    Set-Cookie "foo\0bar"
160*6777b538SAndroid Build Coastguard Worker     // becomes
161*6777b538SAndroid Build Coastguard Worker     //    Set-Cookie: foo\0
162*6777b538SAndroid Build Coastguard Worker     //    Set-Cookie: bar\0
163*6777b538SAndroid Build Coastguard Worker     size_t start = 0;
164*6777b538SAndroid Build Coastguard Worker     size_t end = 0;
165*6777b538SAndroid Build Coastguard Worker     std::optional<std::string_view> location_value;
166*6777b538SAndroid Build Coastguard Worker     do {
167*6777b538SAndroid Build Coastguard Worker       end = value.find('\0', start);
168*6777b538SAndroid Build Coastguard Worker       std::string_view tval;
169*6777b538SAndroid Build Coastguard Worker       if (end != value.npos) {
170*6777b538SAndroid Build Coastguard Worker         tval = value.substr(start, (end - start));
171*6777b538SAndroid Build Coastguard Worker 
172*6777b538SAndroid Build Coastguard Worker         // TODO(ricea): Make this comparison case-sensitive when we are no
173*6777b538SAndroid Build Coastguard Worker         // longer maintaining compatibility with the old version of the
174*6777b538SAndroid Build Coastguard Worker         // function.
175*6777b538SAndroid Build Coastguard Worker         if (base::EqualsCaseInsensitiveASCII(name, "location") &&
176*6777b538SAndroid Build Coastguard Worker             !location_value.has_value()) {
177*6777b538SAndroid Build Coastguard Worker           location_value = HttpUtil::TrimLWS(tval);
178*6777b538SAndroid Build Coastguard Worker         }
179*6777b538SAndroid Build Coastguard Worker       } else {
180*6777b538SAndroid Build Coastguard Worker         tval = value.substr(start);
181*6777b538SAndroid Build Coastguard Worker       }
182*6777b538SAndroid Build Coastguard Worker       if (location_value.has_value() && start > 0) {
183*6777b538SAndroid Build Coastguard Worker         DCHECK(base::EqualsCaseInsensitiveASCII(name, "location"));
184*6777b538SAndroid Build Coastguard Worker         std::string_view trimmed_value = HttpUtil::TrimLWS(tval);
185*6777b538SAndroid Build Coastguard Worker         if (trimmed_value != location_value.value()) {
186*6777b538SAndroid Build Coastguard Worker           return base::unexpected(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION);
187*6777b538SAndroid Build Coastguard Worker         }
188*6777b538SAndroid Build Coastguard Worker       }
189*6777b538SAndroid Build Coastguard Worker       builder.AddHeader(name, tval);
190*6777b538SAndroid Build Coastguard Worker       start = end + 1;
191*6777b538SAndroid Build Coastguard Worker     } while (end != value.npos);
192*6777b538SAndroid Build Coastguard Worker   }
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker   return builder.Build();
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker 
CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo & info,std::optional<RequestPriority> priority,const HttpRequestHeaders & request_headers,spdy::Http2HeaderBlock * headers)197*6777b538SAndroid Build Coastguard Worker void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info,
198*6777b538SAndroid Build Coastguard Worker                                       std::optional<RequestPriority> priority,
199*6777b538SAndroid Build Coastguard Worker                                       const HttpRequestHeaders& request_headers,
200*6777b538SAndroid Build Coastguard Worker                                       spdy::Http2HeaderBlock* headers) {
201*6777b538SAndroid Build Coastguard Worker   headers->insert({spdy::kHttp2MethodHeader, info.method});
202*6777b538SAndroid Build Coastguard Worker   if (info.method == "CONNECT") {
203*6777b538SAndroid Build Coastguard Worker     headers->insert({spdy::kHttp2AuthorityHeader, GetHostAndPort(info.url)});
204*6777b538SAndroid Build Coastguard Worker   } else {
205*6777b538SAndroid Build Coastguard Worker     headers->insert(
206*6777b538SAndroid Build Coastguard Worker         {spdy::kHttp2AuthorityHeader, GetHostAndOptionalPort(info.url)});
207*6777b538SAndroid Build Coastguard Worker     headers->insert({spdy::kHttp2SchemeHeader, info.url.scheme()});
208*6777b538SAndroid Build Coastguard Worker     headers->insert({spdy::kHttp2PathHeader, info.url.PathForRequest()});
209*6777b538SAndroid Build Coastguard Worker   }
210*6777b538SAndroid Build Coastguard Worker 
211*6777b538SAndroid Build Coastguard Worker   HttpRequestHeaders::Iterator it(request_headers);
212*6777b538SAndroid Build Coastguard Worker   while (it.GetNext()) {
213*6777b538SAndroid Build Coastguard Worker     std::string name = base::ToLowerASCII(it.name());
214*6777b538SAndroid Build Coastguard Worker     if (name.empty() || name[0] == ':' || name == "connection" ||
215*6777b538SAndroid Build Coastguard Worker         name == "proxy-connection" || name == "transfer-encoding" ||
216*6777b538SAndroid Build Coastguard Worker         name == "host") {
217*6777b538SAndroid Build Coastguard Worker       continue;
218*6777b538SAndroid Build Coastguard Worker     }
219*6777b538SAndroid Build Coastguard Worker     AddUniqueSpdyHeader(name, it.value(), headers);
220*6777b538SAndroid Build Coastguard Worker   }
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   // Add the priority header if there is not already one set. This uses the
223*6777b538SAndroid Build Coastguard Worker   // quic helpers but the header values for HTTP extensible priorities are
224*6777b538SAndroid Build Coastguard Worker   // independent of quic.
225*6777b538SAndroid Build Coastguard Worker   if (priority &&
226*6777b538SAndroid Build Coastguard Worker       base::FeatureList::IsEnabled(net::features::kPriorityHeader) &&
227*6777b538SAndroid Build Coastguard Worker       headers->find(kHttp2PriorityHeader) == headers->end()) {
228*6777b538SAndroid Build Coastguard Worker     uint8_t urgency = ConvertRequestPriorityToQuicPriority(priority.value());
229*6777b538SAndroid Build Coastguard Worker     bool incremental = info.priority_incremental;
230*6777b538SAndroid Build Coastguard Worker     quic::HttpStreamPriority quic_priority{urgency, incremental};
231*6777b538SAndroid Build Coastguard Worker     std::string serialized_priority =
232*6777b538SAndroid Build Coastguard Worker         quic::SerializePriorityFieldValue(quic_priority);
233*6777b538SAndroid Build Coastguard Worker     if (!serialized_priority.empty()) {
234*6777b538SAndroid Build Coastguard Worker       AddUniqueSpdyHeader(kHttp2PriorityHeader, serialized_priority, headers);
235*6777b538SAndroid Build Coastguard Worker     }
236*6777b538SAndroid Build Coastguard Worker   }
237*6777b538SAndroid Build Coastguard Worker }
238*6777b538SAndroid Build Coastguard Worker 
CreateSpdyHeadersFromHttpRequestForExtendedConnect(const HttpRequestInfo & info,std::optional<RequestPriority> priority,const std::string & ext_connect_protocol,const HttpRequestHeaders & request_headers,spdy::Http2HeaderBlock * headers)239*6777b538SAndroid Build Coastguard Worker void CreateSpdyHeadersFromHttpRequestForExtendedConnect(
240*6777b538SAndroid Build Coastguard Worker     const HttpRequestInfo& info,
241*6777b538SAndroid Build Coastguard Worker     std::optional<RequestPriority> priority,
242*6777b538SAndroid Build Coastguard Worker     const std::string& ext_connect_protocol,
243*6777b538SAndroid Build Coastguard Worker     const HttpRequestHeaders& request_headers,
244*6777b538SAndroid Build Coastguard Worker     spdy::Http2HeaderBlock* headers) {
245*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(info.method, "CONNECT");
246*6777b538SAndroid Build Coastguard Worker 
247*6777b538SAndroid Build Coastguard Worker   // Extended CONNECT, unlike CONNECT, requires scheme and path, and uses the
248*6777b538SAndroid Build Coastguard Worker   // default port in the authority header.
249*6777b538SAndroid Build Coastguard Worker   headers->insert({spdy::kHttp2SchemeHeader, info.url.scheme()});
250*6777b538SAndroid Build Coastguard Worker   headers->insert({spdy::kHttp2PathHeader, info.url.PathForRequest()});
251*6777b538SAndroid Build Coastguard Worker   headers->insert({spdy::kHttp2ProtocolHeader, ext_connect_protocol});
252*6777b538SAndroid Build Coastguard Worker 
253*6777b538SAndroid Build Coastguard Worker   CreateSpdyHeadersFromHttpRequest(info, priority, request_headers, headers);
254*6777b538SAndroid Build Coastguard Worker 
255*6777b538SAndroid Build Coastguard Worker   // Replace the existing `:authority` header. This will still be ordered
256*6777b538SAndroid Build Coastguard Worker   // correctly, since the header was first added before any regular headers.
257*6777b538SAndroid Build Coastguard Worker   headers->insert(
258*6777b538SAndroid Build Coastguard Worker       {spdy::kHttp2AuthorityHeader, GetHostAndOptionalPort(info.url)});
259*6777b538SAndroid Build Coastguard Worker }
260*6777b538SAndroid Build Coastguard Worker 
CreateSpdyHeadersFromHttpRequestForWebSocket(const GURL & url,const HttpRequestHeaders & request_headers,spdy::Http2HeaderBlock * headers)261*6777b538SAndroid Build Coastguard Worker void CreateSpdyHeadersFromHttpRequestForWebSocket(
262*6777b538SAndroid Build Coastguard Worker     const GURL& url,
263*6777b538SAndroid Build Coastguard Worker     const HttpRequestHeaders& request_headers,
264*6777b538SAndroid Build Coastguard Worker     spdy::Http2HeaderBlock* headers) {
265*6777b538SAndroid Build Coastguard Worker   headers->insert({spdy::kHttp2MethodHeader, "CONNECT"});
266*6777b538SAndroid Build Coastguard Worker   headers->insert({spdy::kHttp2AuthorityHeader, GetHostAndOptionalPort(url)});
267*6777b538SAndroid Build Coastguard Worker   headers->insert({spdy::kHttp2SchemeHeader, "https"});
268*6777b538SAndroid Build Coastguard Worker   headers->insert({spdy::kHttp2PathHeader, url.PathForRequest()});
269*6777b538SAndroid Build Coastguard Worker   headers->insert({spdy::kHttp2ProtocolHeader, "websocket"});
270*6777b538SAndroid Build Coastguard Worker 
271*6777b538SAndroid Build Coastguard Worker   HttpRequestHeaders::Iterator it(request_headers);
272*6777b538SAndroid Build Coastguard Worker   while (it.GetNext()) {
273*6777b538SAndroid Build Coastguard Worker     std::string name = base::ToLowerASCII(it.name());
274*6777b538SAndroid Build Coastguard Worker     if (name.empty() || name[0] == ':' || name == "upgrade" ||
275*6777b538SAndroid Build Coastguard Worker         name == "connection" || name == "proxy-connection" ||
276*6777b538SAndroid Build Coastguard Worker         name == "transfer-encoding" || name == "host") {
277*6777b538SAndroid Build Coastguard Worker       continue;
278*6777b538SAndroid Build Coastguard Worker     }
279*6777b538SAndroid Build Coastguard Worker     AddUniqueSpdyHeader(name, it.value(), headers);
280*6777b538SAndroid Build Coastguard Worker   }
281*6777b538SAndroid Build Coastguard Worker }
282*6777b538SAndroid Build Coastguard Worker 
283*6777b538SAndroid Build Coastguard Worker static_assert(HIGHEST - LOWEST < 4 && HIGHEST - MINIMUM_PRIORITY < 6,
284*6777b538SAndroid Build Coastguard Worker               "request priority incompatible with spdy");
285*6777b538SAndroid Build Coastguard Worker 
ConvertRequestPriorityToSpdyPriority(const RequestPriority priority)286*6777b538SAndroid Build Coastguard Worker spdy::SpdyPriority ConvertRequestPriorityToSpdyPriority(
287*6777b538SAndroid Build Coastguard Worker     const RequestPriority priority) {
288*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(priority, MINIMUM_PRIORITY);
289*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(priority, MAXIMUM_PRIORITY);
290*6777b538SAndroid Build Coastguard Worker   return static_cast<spdy::SpdyPriority>(MAXIMUM_PRIORITY - priority +
291*6777b538SAndroid Build Coastguard Worker                                          spdy::kV3HighestPriority);
292*6777b538SAndroid Build Coastguard Worker }
293*6777b538SAndroid Build Coastguard Worker 
294*6777b538SAndroid Build Coastguard Worker NET_EXPORT_PRIVATE RequestPriority
ConvertSpdyPriorityToRequestPriority(spdy::SpdyPriority priority)295*6777b538SAndroid Build Coastguard Worker ConvertSpdyPriorityToRequestPriority(spdy::SpdyPriority priority) {
296*6777b538SAndroid Build Coastguard Worker   // Handle invalid values gracefully.
297*6777b538SAndroid Build Coastguard Worker   return ((priority - spdy::kV3HighestPriority) >
298*6777b538SAndroid Build Coastguard Worker           (MAXIMUM_PRIORITY - MINIMUM_PRIORITY))
299*6777b538SAndroid Build Coastguard Worker              ? IDLE
300*6777b538SAndroid Build Coastguard Worker              : static_cast<RequestPriority>(
301*6777b538SAndroid Build Coastguard Worker                    MAXIMUM_PRIORITY - (priority - spdy::kV3HighestPriority));
302*6777b538SAndroid Build Coastguard Worker }
303*6777b538SAndroid Build Coastguard Worker 
ConvertHeaderBlockToHttpRequestHeaders(const spdy::Http2HeaderBlock & spdy_headers,HttpRequestHeaders * http_headers)304*6777b538SAndroid Build Coastguard Worker NET_EXPORT_PRIVATE void ConvertHeaderBlockToHttpRequestHeaders(
305*6777b538SAndroid Build Coastguard Worker     const spdy::Http2HeaderBlock& spdy_headers,
306*6777b538SAndroid Build Coastguard Worker     HttpRequestHeaders* http_headers) {
307*6777b538SAndroid Build Coastguard Worker   for (const auto& it : spdy_headers) {
308*6777b538SAndroid Build Coastguard Worker     std::string_view key = it.first;
309*6777b538SAndroid Build Coastguard Worker     if (key[0] == ':') {
310*6777b538SAndroid Build Coastguard Worker       key.remove_prefix(1);
311*6777b538SAndroid Build Coastguard Worker     }
312*6777b538SAndroid Build Coastguard Worker     std::vector<std::string_view> values = base::SplitStringPiece(
313*6777b538SAndroid Build Coastguard Worker         it.second, "\0", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
314*6777b538SAndroid Build Coastguard Worker     for (const auto& value : values) {
315*6777b538SAndroid Build Coastguard Worker       http_headers->SetHeader(key, value);
316*6777b538SAndroid Build Coastguard Worker     }
317*6777b538SAndroid Build Coastguard Worker   }
318*6777b538SAndroid Build Coastguard Worker }
319*6777b538SAndroid Build Coastguard Worker 
320*6777b538SAndroid Build Coastguard Worker }  // namespace net
321