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