OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/spdy/spdy_http_utils.h" | 5 #include "net/spdy/spdy_http_utils.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
10 #include "base/strings/string_split.h" | 10 #include "base/strings/string_split.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 std::string joint_value = (*headers)[name].as_string(); | 32 std::string joint_value = (*headers)[name].as_string(); |
33 joint_value.append(1, '\0'); | 33 joint_value.append(1, '\0'); |
34 joint_value.append(value); | 34 joint_value.append(value); |
35 (*headers)[name] = joint_value; | 35 (*headers)[name] = joint_value; |
36 } | 36 } |
37 } | 37 } |
38 | 38 |
39 } // namespace | 39 } // namespace |
40 | 40 |
41 bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers, | 41 bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers, |
42 SpdyMajorVersion protocol_version, | |
43 HttpResponseInfo* response) { | 42 HttpResponseInfo* response) { |
44 std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status"; | 43 // The ":status" header is required. |
45 std::string version_key = | 44 SpdyHeaderBlock::const_iterator it = headers.find(":status"); |
46 (protocol_version >= SPDY3) ? ":version" : "version"; | |
47 std::string version; | |
48 std::string status; | |
49 | |
50 // The "status" header is required. "version" is required below HTTP/2. | |
51 SpdyHeaderBlock::const_iterator it; | |
52 it = headers.find(status_key); | |
53 if (it == headers.end()) | 45 if (it == headers.end()) |
54 return false; | 46 return false; |
55 status = it->second.as_string(); | 47 std::string status = it->second.as_string(); |
56 | 48 std::string raw_headers("HTTP/1.1 "); |
57 if (protocol_version >= HTTP2) { | |
58 version = "HTTP/1.1"; | |
59 } else { | |
60 it = headers.find(version_key); | |
61 if (it == headers.end()) | |
62 return false; | |
63 version = it->second.as_string(); | |
64 } | |
65 std::string raw_headers(version); | |
66 raw_headers.push_back(' '); | |
67 raw_headers.append(status); | 49 raw_headers.append(status); |
68 raw_headers.push_back('\0'); | 50 raw_headers.push_back('\0'); |
69 for (it = headers.begin(); it != headers.end(); ++it) { | 51 for (it = headers.begin(); it != headers.end(); ++it) { |
70 // For each value, if the server sends a NUL-separated | 52 // For each value, if the server sends a NUL-separated |
71 // list of values, we separate that back out into | 53 // list of values, we separate that back out into |
72 // individual headers for each value in the list. | 54 // individual headers for each value in the list. |
73 // e.g. | 55 // e.g. |
74 // Set-Cookie "foo\0bar" | 56 // Set-Cookie "foo\0bar" |
75 // becomes | 57 // becomes |
76 // Set-Cookie: foo\0 | 58 // Set-Cookie: foo\0 |
(...skipping 19 matching lines...) Expand all Loading... |
96 } while (end != value.npos); | 78 } while (end != value.npos); |
97 } | 79 } |
98 | 80 |
99 response->headers = new HttpResponseHeaders(raw_headers); | 81 response->headers = new HttpResponseHeaders(raw_headers); |
100 response->was_fetched_via_spdy = true; | 82 response->was_fetched_via_spdy = true; |
101 return true; | 83 return true; |
102 } | 84 } |
103 | 85 |
104 void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info, | 86 void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info, |
105 const HttpRequestHeaders& request_headers, | 87 const HttpRequestHeaders& request_headers, |
106 SpdyMajorVersion protocol_version, | |
107 bool direct, | 88 bool direct, |
108 SpdyHeaderBlock* headers) { | 89 SpdyHeaderBlock* headers) { |
109 static const char kHttpProtocolVersion[] = "HTTP/1.1"; | 90 (*headers)[":method"] = info.method; |
110 switch (protocol_version) { | 91 if (info.method == "CONNECT") { |
111 case SPDY3: | 92 (*headers)[":authority"] = GetHostAndPort(info.url); |
112 (*headers)[":version"] = kHttpProtocolVersion; | 93 } else { |
113 (*headers)[":method"] = info.method; | 94 (*headers)[":authority"] = GetHostAndOptionalPort(info.url); |
114 (*headers)[":host"] = GetHostAndOptionalPort(info.url); | 95 (*headers)[":scheme"] = info.url.scheme(); |
115 if (info.method == "CONNECT") { | 96 (*headers)[":path"] = info.url.PathForRequest(); |
116 (*headers)[":path"] = GetHostAndPort(info.url); | |
117 } else { | |
118 (*headers)[":scheme"] = info.url.scheme(); | |
119 (*headers)[":path"] = info.url.PathForRequest(); | |
120 } | |
121 break; | |
122 case HTTP2: | |
123 (*headers)[":method"] = info.method; | |
124 if (info.method == "CONNECT") { | |
125 (*headers)[":authority"] = GetHostAndPort(info.url); | |
126 } else { | |
127 (*headers)[":authority"] = GetHostAndOptionalPort(info.url); | |
128 (*headers)[":scheme"] = info.url.scheme(); | |
129 (*headers)[":path"] = info.url.PathForRequest(); | |
130 } | |
131 break; | |
132 default: | |
133 NOTREACHED(); | |
134 } | 97 } |
135 | 98 |
136 HttpRequestHeaders::Iterator it(request_headers); | 99 HttpRequestHeaders::Iterator it(request_headers); |
137 while (it.GetNext()) { | 100 while (it.GetNext()) { |
138 std::string name = base::ToLowerASCII(it.name()); | 101 std::string name = base::ToLowerASCII(it.name()); |
139 if (name.empty() || name[0] == ':' || name == "connection" || | 102 if (name.empty() || name[0] == ':' || name == "connection" || |
140 name == "proxy-connection" || name == "transfer-encoding" || | 103 name == "proxy-connection" || name == "transfer-encoding" || |
141 name == "host") { | 104 name == "host") { |
142 continue; | 105 continue; |
143 } | 106 } |
144 AddSpdyHeader(name, it.value(), headers); | 107 AddSpdyHeader(name, it.value(), headers); |
145 } | 108 } |
146 } | 109 } |
147 | 110 |
148 void CreateSpdyHeadersFromHttpResponse( | 111 void CreateSpdyHeadersFromHttpResponse( |
149 const HttpResponseHeaders& response_headers, | 112 const HttpResponseHeaders& response_headers, |
150 SpdyMajorVersion protocol_version, | |
151 SpdyHeaderBlock* headers) { | 113 SpdyHeaderBlock* headers) { |
152 std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status"; | |
153 std::string version_key = | |
154 (protocol_version >= SPDY3) ? ":version" : "version"; | |
155 | |
156 const std::string status_line = response_headers.GetStatusLine(); | 114 const std::string status_line = response_headers.GetStatusLine(); |
157 std::string::const_iterator after_version = | 115 std::string::const_iterator after_version = |
158 std::find(status_line.begin(), status_line.end(), ' '); | 116 std::find(status_line.begin(), status_line.end(), ' '); |
159 if (protocol_version < HTTP2) { | |
160 (*headers)[version_key] = std::string(status_line.begin(), after_version); | |
161 } | |
162 | |
163 // Get status code only. | 117 // Get status code only. |
164 std::string::const_iterator after_status = | 118 std::string::const_iterator after_status = |
165 std::find(after_version + 1, status_line.end(), ' '); | 119 std::find(after_version + 1, status_line.end(), ' '); |
166 (*headers)[status_key] = std::string(after_version + 1, after_status); | 120 (*headers)[":status"] = std::string(after_version + 1, after_status); |
167 | 121 |
168 size_t iter = 0; | 122 size_t iter = 0; |
169 std::string raw_name, value; | 123 std::string raw_name, value; |
170 while (response_headers.EnumerateHeaderLines(&iter, &raw_name, &value)) { | 124 while (response_headers.EnumerateHeaderLines(&iter, &raw_name, &value)) { |
171 std::string name = base::ToLowerASCII(raw_name); | 125 std::string name = base::ToLowerASCII(raw_name); |
172 AddSpdyHeader(name, value, headers); | 126 AddSpdyHeader(name, value, headers); |
173 } | 127 } |
174 } | 128 } |
175 | 129 |
176 static_assert(HIGHEST - LOWEST < 4 && HIGHEST - MINIMUM_PRIORITY < 5, | 130 static_assert(HIGHEST - LOWEST < 4 && HIGHEST - MINIMUM_PRIORITY < 5, |
177 "request priority incompatible with spdy"); | 131 "request priority incompatible with spdy"); |
178 | 132 |
179 SpdyPriority ConvertRequestPriorityToSpdyPriority( | 133 SpdyPriority ConvertRequestPriorityToSpdyPriority( |
180 const RequestPriority priority, | 134 const RequestPriority priority) { |
181 SpdyMajorVersion protocol_version) { | |
182 DCHECK_GE(priority, MINIMUM_PRIORITY); | 135 DCHECK_GE(priority, MINIMUM_PRIORITY); |
183 DCHECK_LE(priority, MAXIMUM_PRIORITY); | 136 DCHECK_LE(priority, MAXIMUM_PRIORITY); |
184 return static_cast<SpdyPriority>(MAXIMUM_PRIORITY - priority); | 137 return static_cast<SpdyPriority>(MAXIMUM_PRIORITY - priority); |
185 } | 138 } |
186 | 139 |
187 NET_EXPORT_PRIVATE RequestPriority ConvertSpdyPriorityToRequestPriority( | 140 NET_EXPORT_PRIVATE RequestPriority |
188 SpdyPriority priority, | 141 ConvertSpdyPriorityToRequestPriority(SpdyPriority priority) { |
189 SpdyMajorVersion protocol_version) { | |
190 // Handle invalid values gracefully. | 142 // Handle invalid values gracefully. |
191 // Note that SpdyPriority is not an enum, hence the magic constants. | 143 // Note that SpdyPriority is not an enum, hence the magic constants. |
192 return (priority >= 5) ? | 144 return (priority >= 5) ? |
193 IDLE : static_cast<RequestPriority>(4 - priority); | 145 IDLE : static_cast<RequestPriority>(4 - priority); |
194 } | 146 } |
195 | 147 |
196 NET_EXPORT_PRIVATE void ConvertHeaderBlockToHttpRequestHeaders( | 148 NET_EXPORT_PRIVATE void ConvertHeaderBlockToHttpRequestHeaders( |
197 const SpdyHeaderBlock& spdy_headers, | 149 const SpdyHeaderBlock& spdy_headers, |
198 HttpRequestHeaders* http_headers) { | 150 HttpRequestHeaders* http_headers) { |
199 for (const auto& it : spdy_headers) { | 151 for (const auto& it : spdy_headers) { |
200 base::StringPiece key = it.first; | 152 base::StringPiece key = it.first; |
201 if (key[0] == ':') { | 153 if (key[0] == ':') { |
202 key.remove_prefix(1); | 154 key.remove_prefix(1); |
203 } | 155 } |
204 std::vector<base::StringPiece> values = base::SplitStringPiece( | 156 std::vector<base::StringPiece> values = base::SplitStringPiece( |
205 it.second, "\0", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | 157 it.second, "\0", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
206 for (const auto& value : values) { | 158 for (const auto& value : values) { |
207 http_headers->SetHeader(key, value); | 159 http_headers->SetHeader(key, value); |
208 } | 160 } |
209 } | 161 } |
210 } | 162 } |
211 | 163 |
212 GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers, | 164 GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers) { |
213 SpdyMajorVersion protocol_version) { | |
214 SpdyHeaderBlock::const_iterator it = headers.find(":scheme"); | 165 SpdyHeaderBlock::const_iterator it = headers.find(":scheme"); |
215 if (it == headers.end()) | 166 if (it == headers.end()) |
216 return GURL(); | 167 return GURL(); |
217 std::string url = it->second.as_string(); | 168 std::string url = it->second.as_string(); |
218 url.append("://"); | 169 url.append("://"); |
219 | 170 |
220 it = headers.find(protocol_version >= HTTP2 ? ":authority" : ":host"); | 171 it = headers.find(":authority"); |
221 if (it == headers.end()) | 172 if (it == headers.end()) |
222 return GURL(); | 173 return GURL(); |
223 url.append(it->second.as_string()); | 174 url.append(it->second.as_string()); |
224 | 175 |
225 it = headers.find(":path"); | 176 it = headers.find(":path"); |
226 if (it == headers.end()) | 177 if (it == headers.end()) |
227 return GURL(); | 178 return GURL(); |
228 url.append(it->second.as_string()); | 179 url.append(it->second.as_string()); |
229 return GURL(url); | 180 return GURL(url); |
230 } | 181 } |
231 | 182 |
232 } // namespace net | 183 } // namespace net |
OLD | NEW |