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"
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"
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";
32 // The "status" and "version" headers are required.
33 SpdyHeaderBlock::const_iterator it
;
34 it
= headers
.find(status_key
);
35 if (it
== headers
.end())
39 it
= headers
.find(version_key
);
40 if (it
== headers
.end())
44 std::string
raw_headers(version
);
45 raw_headers
.push_back(' ');
46 raw_headers
.append(status
);
47 raw_headers
.push_back('\0');
48 for (it
= headers
.begin(); it
!= headers
.end(); ++it
) {
49 // For each value, if the server sends a NUL-separated
50 // list of values, we separate that back out into
51 // individual headers for each value in the list.
53 // Set-Cookie "foo\0bar"
57 std::string value
= it
->second
;
61 end
= value
.find('\0', start
);
63 if (end
!= value
.npos
)
64 tval
= value
.substr(start
, (end
- start
));
66 tval
= value
.substr(start
);
67 if (protocol_version
>= 3 && it
->first
[0] == ':')
68 raw_headers
.append(it
->first
.substr(1));
70 raw_headers
.append(it
->first
);
71 raw_headers
.push_back(':');
72 raw_headers
.append(tval
);
73 raw_headers
.push_back('\0');
75 } while (end
!= value
.npos
);
78 response
->headers
= new HttpResponseHeaders(raw_headers
);
79 response
->was_fetched_via_spdy
= true;
83 void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo
& info
,
84 const HttpRequestHeaders
& request_headers
,
85 SpdyHeaderBlock
* headers
,
86 SpdyMajorVersion protocol_version
,
89 HttpRequestHeaders::Iterator
it(request_headers
);
90 while (it
.GetNext()) {
91 std::string name
= StringToLowerASCII(it
.name());
92 if (name
== "connection" || name
== "proxy-connection" ||
93 name
== "transfer-encoding") {
96 if (headers
->find(name
) == headers
->end()) {
97 (*headers
)[name
] = it
.value();
99 std::string new_value
= (*headers
)[name
];
100 new_value
.append(1, '\0'); // +=() doesn't append 0's
101 new_value
+= it
.value();
102 (*headers
)[name
] = new_value
;
105 static const char kHttpProtocolVersion
[] = "HTTP/1.1";
107 if (protocol_version
< SPDY3
) {
108 (*headers
)["version"] = kHttpProtocolVersion
;
109 (*headers
)["method"] = info
.method
;
110 (*headers
)["host"] = GetHostAndOptionalPort(info
.url
);
111 (*headers
)["scheme"] = info
.url
.scheme();
113 (*headers
)["url"] = HttpUtil::PathForRequest(info
.url
);
115 (*headers
)["url"] = HttpUtil::SpecForRequest(info
.url
);
117 (*headers
)[":version"] = kHttpProtocolVersion
;
118 (*headers
)[":method"] = info
.method
;
119 (*headers
)[":host"] = GetHostAndOptionalPort(info
.url
);
120 (*headers
)[":scheme"] = info
.url
.scheme();
121 (*headers
)[":path"] = HttpUtil::PathForRequest(info
.url
);
122 headers
->erase("host"); // this is kinda insane, spdy 3 spec.
127 COMPILE_ASSERT(HIGHEST
- LOWEST
< 4 &&
128 HIGHEST
- MINIMUM_PRIORITY
< 5,
129 request_priority_incompatible_with_spdy
);
131 SpdyPriority
ConvertRequestPriorityToSpdyPriority(
132 const RequestPriority priority
,
133 SpdyMajorVersion protocol_version
) {
134 DCHECK_GE(priority
, MINIMUM_PRIORITY
);
135 DCHECK_LE(priority
, MAXIMUM_PRIORITY
);
136 if (protocol_version
== SPDY2
) {
137 // SPDY 2 only has 2 bits of priority, but we have 5 RequestPriorities.
138 // Map IDLE => 3, LOWEST => 2, LOW => 2, MEDIUM => 1, HIGHEST => 0.
139 if (priority
> LOWEST
) {
140 return static_cast<SpdyPriority
>(HIGHEST
- priority
);
142 return static_cast<SpdyPriority
>(HIGHEST
- priority
- 1);
145 return static_cast<SpdyPriority
>(HIGHEST
- priority
);
149 NET_EXPORT_PRIVATE RequestPriority
ConvertSpdyPriorityToRequestPriority(
150 SpdyPriority priority
,
151 SpdyMajorVersion protocol_version
) {
152 // Handle invalid values gracefully, and pick LOW to map 2 back
154 SpdyPriority idle_cutoff
= (protocol_version
== SPDY2
) ? 3 : 5;
155 return (priority
>= idle_cutoff
) ?
156 IDLE
: static_cast<RequestPriority
>(HIGHEST
- priority
);
159 GURL
GetUrlFromHeaderBlock(const SpdyHeaderBlock
& headers
,
160 SpdyMajorVersion protocol_version
,
162 // SPDY 2 server push urls are specified in a single "url" header.
163 if (pushed
&& protocol_version
== SPDY2
) {
165 SpdyHeaderBlock::const_iterator it
;
166 it
= headers
.find("url");
167 if (it
!= headers
.end())
172 const char* scheme_header
= protocol_version
>= SPDY3
? ":scheme" : "scheme";
173 const char* host_header
= protocol_version
>= SPDY3
? ":host" : "host";
174 const char* path_header
= protocol_version
>= SPDY3
? ":path" : "url";
177 std::string host_port
;
179 SpdyHeaderBlock::const_iterator it
;
180 it
= headers
.find(scheme_header
);
181 if (it
!= headers
.end())
183 it
= headers
.find(host_header
);
184 if (it
!= headers
.end())
185 host_port
= it
->second
;
186 it
= headers
.find(path_header
);
187 if (it
!= headers
.end())
190 std::string url
= (scheme
.empty() || host_port
.empty() || path
.empty())
192 : scheme
+ "://" + host_port
+ path
;
196 bool ShouldShowHttpHeaderValue(const std::string
& header_name
) {
197 #if defined(SPDY_PROXY_AUTH_ORIGIN)
198 if (header_name
== "proxy-authorization")