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_util.h" | 10 #include "base/strings/string_util.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 namespace net { | 21 namespace net { |
22 | 22 |
23 namespace { | 23 namespace { |
24 | 24 |
25 void AddSpdyHeader(const std::string& name, | 25 void AddSpdyHeader(const std::string& name, |
26 const std::string& value, | 26 const std::string& value, |
27 SpdyHeaderBlock* headers) { | 27 SpdyHeaderBlock* headers) { |
28 if (headers->find(name) == headers->end()) { | 28 if (headers->find(name) == headers->end()) { |
29 (*headers)[name] = value; | 29 (*headers)[name] = value; |
30 } else { | 30 } else { |
31 (*headers)[name] += '\0' + value; | 31 std::string joint_value = (*headers)[name].as_string(); |
| 32 joint_value.append(1, '\0'); |
| 33 joint_value.append(value); |
| 34 (*headers)[name] = joint_value; |
32 } | 35 } |
33 } | 36 } |
34 | 37 |
35 } // namespace | 38 } // namespace |
36 | 39 |
37 bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers, | 40 bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers, |
38 SpdyMajorVersion protocol_version, | 41 SpdyMajorVersion protocol_version, |
39 HttpResponseInfo* response) { | 42 HttpResponseInfo* response) { |
40 std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status"; | 43 std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status"; |
41 std::string version_key = | 44 std::string version_key = |
42 (protocol_version >= SPDY3) ? ":version" : "version"; | 45 (protocol_version >= SPDY3) ? ":version" : "version"; |
43 std::string version; | 46 std::string version; |
44 std::string status; | 47 std::string status; |
45 | 48 |
46 // The "status" header is required. "version" is required below HTTP/2. | 49 // The "status" header is required. "version" is required below HTTP/2. |
47 SpdyHeaderBlock::const_iterator it; | 50 SpdyHeaderBlock::const_iterator it; |
48 it = headers.find(status_key); | 51 it = headers.find(status_key); |
49 if (it == headers.end()) | 52 if (it == headers.end()) |
50 return false; | 53 return false; |
51 status = it->second; | 54 status = it->second.as_string(); |
52 | 55 |
53 if (protocol_version >= HTTP2) { | 56 if (protocol_version >= HTTP2) { |
54 version = "HTTP/1.1"; | 57 version = "HTTP/1.1"; |
55 } else { | 58 } else { |
56 it = headers.find(version_key); | 59 it = headers.find(version_key); |
57 if (it == headers.end()) | 60 if (it == headers.end()) |
58 return false; | 61 return false; |
59 version = it->second; | 62 version = it->second.as_string(); |
60 } | 63 } |
61 std::string raw_headers(version); | 64 std::string raw_headers(version); |
62 raw_headers.push_back(' '); | 65 raw_headers.push_back(' '); |
63 raw_headers.append(status); | 66 raw_headers.append(status); |
64 raw_headers.push_back('\0'); | 67 raw_headers.push_back('\0'); |
65 for (it = headers.begin(); it != headers.end(); ++it) { | 68 for (it = headers.begin(); it != headers.end(); ++it) { |
66 // For each value, if the server sends a NUL-separated | 69 // For each value, if the server sends a NUL-separated |
67 // list of values, we separate that back out into | 70 // list of values, we separate that back out into |
68 // individual headers for each value in the list. | 71 // individual headers for each value in the list. |
69 // e.g. | 72 // e.g. |
70 // Set-Cookie "foo\0bar" | 73 // Set-Cookie "foo\0bar" |
71 // becomes | 74 // becomes |
72 // Set-Cookie: foo\0 | 75 // Set-Cookie: foo\0 |
73 // Set-Cookie: bar\0 | 76 // Set-Cookie: bar\0 |
74 std::string value = it->second; | 77 std::string value = it->second.as_string(); |
75 size_t start = 0; | 78 size_t start = 0; |
76 size_t end = 0; | 79 size_t end = 0; |
77 do { | 80 do { |
78 end = value.find('\0', start); | 81 end = value.find('\0', start); |
79 std::string tval; | 82 std::string tval; |
80 if (end != value.npos) | 83 if (end != value.npos) |
81 tval = value.substr(start, (end - start)); | 84 tval = value.substr(start, (end - start)); |
82 else | 85 else |
83 tval = value.substr(start); | 86 tval = value.substr(start); |
84 if (protocol_version >= 3 && it->first[0] == ':') | 87 if (protocol_version >= 3 && it->first[0] == ':') |
85 raw_headers.append(it->first.substr(1)); | 88 raw_headers.append(it->first.as_string().substr(1)); |
86 else | 89 else |
87 raw_headers.append(it->first); | 90 raw_headers.append(it->first.as_string()); |
88 raw_headers.push_back(':'); | 91 raw_headers.push_back(':'); |
89 raw_headers.append(tval); | 92 raw_headers.append(tval); |
90 raw_headers.push_back('\0'); | 93 raw_headers.push_back('\0'); |
91 start = end + 1; | 94 start = end + 1; |
92 } while (end != value.npos); | 95 } while (end != value.npos); |
93 } | 96 } |
94 | 97 |
95 response->headers = new HttpResponseHeaders(raw_headers); | 98 response->headers = new HttpResponseHeaders(raw_headers); |
96 response->was_fetched_via_spdy = true; | 99 response->was_fetched_via_spdy = true; |
97 return true; | 100 return true; |
98 } | 101 } |
99 | 102 |
100 void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info, | 103 void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info, |
101 const HttpRequestHeaders& request_headers, | 104 const HttpRequestHeaders& request_headers, |
102 SpdyMajorVersion protocol_version, | 105 SpdyMajorVersion protocol_version, |
103 bool direct, | 106 bool direct, |
104 SpdyHeaderBlock* headers) { | 107 SpdyHeaderBlock* headers) { |
105 | |
106 HttpRequestHeaders::Iterator it(request_headers); | |
107 while (it.GetNext()) { | |
108 std::string name = base::ToLowerASCII(it.name()); | |
109 if (name == "connection" || name == "proxy-connection" || | |
110 name == "transfer-encoding" || name == "host") { | |
111 continue; | |
112 } | |
113 AddSpdyHeader(name, it.value(), headers); | |
114 } | |
115 static const char kHttpProtocolVersion[] = "HTTP/1.1"; | 108 static const char kHttpProtocolVersion[] = "HTTP/1.1"; |
116 | |
117 switch (protocol_version) { | 109 switch (protocol_version) { |
118 case SPDY2: | 110 case SPDY2: |
119 // TODO(bnc): Remove this code now that SPDY/2 is deprecated. | 111 // TODO(bnc): Remove this code now that SPDY/2 is deprecated. |
120 (*headers)["version"] = kHttpProtocolVersion; | 112 (*headers)["version"] = kHttpProtocolVersion; |
121 (*headers)["method"] = info.method; | 113 (*headers)["method"] = info.method; |
122 (*headers)["host"] = GetHostAndOptionalPort(info.url); | 114 (*headers)["host"] = GetHostAndOptionalPort(info.url); |
123 if (info.method == "CONNECT") { | 115 if (info.method == "CONNECT") { |
124 (*headers)["url"] = GetHostAndPort(info.url); | 116 (*headers)["url"] = GetHostAndPort(info.url); |
125 } else { | 117 } else { |
126 (*headers)["scheme"] = info.url.scheme(); | 118 (*headers)["scheme"] = info.url.scheme(); |
127 (*headers)["url"] = direct ? info.url.PathForRequest() | 119 (*headers)["url"] = direct ? info.url.PathForRequest() |
128 : HttpUtil::SpecForRequest(info.url); | 120 : HttpUtil::SpecForRequest(info.url); |
129 } | 121 } |
130 break; | 122 break; |
131 case SPDY3: | 123 case SPDY3: |
132 (*headers)[":version"] = kHttpProtocolVersion; | 124 (*headers)[":version"] = kHttpProtocolVersion; |
| 125 (*headers)[":method"] = info.method; |
133 (*headers)[":host"] = GetHostAndOptionalPort(info.url); | 126 (*headers)[":host"] = GetHostAndOptionalPort(info.url); |
134 (*headers)[":method"] = info.method; | |
135 if (info.method == "CONNECT") { | 127 if (info.method == "CONNECT") { |
136 (*headers)[":path"] = GetHostAndPort(info.url); | 128 (*headers)[":path"] = GetHostAndPort(info.url); |
137 } else { | 129 } else { |
138 (*headers)[":scheme"] = info.url.scheme(); | 130 (*headers)[":scheme"] = info.url.scheme(); |
139 (*headers)[":path"] = info.url.PathForRequest(); | 131 (*headers)[":path"] = info.url.PathForRequest(); |
140 } | 132 } |
141 break; | 133 break; |
142 case HTTP2: | 134 case HTTP2: |
143 (*headers)[":method"] = info.method; | 135 (*headers)[":method"] = info.method; |
144 if (info.method == "CONNECT") { | 136 if (info.method == "CONNECT") { |
145 (*headers)[":authority"] = GetHostAndPort(info.url); | 137 (*headers)[":authority"] = GetHostAndPort(info.url); |
146 } else { | 138 } else { |
147 (*headers)[":authority"] = GetHostAndOptionalPort(info.url); | 139 (*headers)[":authority"] = GetHostAndOptionalPort(info.url); |
148 (*headers)[":scheme"] = info.url.scheme(); | 140 (*headers)[":scheme"] = info.url.scheme(); |
149 (*headers)[":path"] = info.url.PathForRequest(); | 141 (*headers)[":path"] = info.url.PathForRequest(); |
150 } | 142 } |
151 break; | 143 break; |
152 default: | 144 default: |
153 NOTREACHED(); | 145 NOTREACHED(); |
154 } | 146 } |
| 147 |
| 148 HttpRequestHeaders::Iterator it(request_headers); |
| 149 while (it.GetNext()) { |
| 150 std::string name = base::ToLowerASCII(it.name()); |
| 151 if (name.empty() || name[0] == ':' || name == "connection" || |
| 152 name == "proxy-connection" || name == "transfer-encoding" || |
| 153 name == "host") { |
| 154 continue; |
| 155 } |
| 156 AddSpdyHeader(name, it.value(), headers); |
| 157 } |
155 } | 158 } |
156 | 159 |
157 void CreateSpdyHeadersFromHttpResponse( | 160 void CreateSpdyHeadersFromHttpResponse( |
158 const HttpResponseHeaders& response_headers, | 161 const HttpResponseHeaders& response_headers, |
159 SpdyMajorVersion protocol_version, | 162 SpdyMajorVersion protocol_version, |
160 SpdyHeaderBlock* headers) { | 163 SpdyHeaderBlock* headers) { |
161 std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status"; | 164 std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status"; |
162 std::string version_key = | 165 std::string version_key = |
163 (protocol_version >= SPDY3) ? ":version" : "version"; | 166 (protocol_version >= SPDY3) ? ":version" : "version"; |
164 | 167 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 IDLE : static_cast<RequestPriority>(4 - priority); | 201 IDLE : static_cast<RequestPriority>(4 - priority); |
199 } | 202 } |
200 | 203 |
201 GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers, | 204 GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers, |
202 SpdyMajorVersion protocol_version, | 205 SpdyMajorVersion protocol_version, |
203 bool pushed) { | 206 bool pushed) { |
204 DCHECK_LE(SPDY3, protocol_version); | 207 DCHECK_LE(SPDY3, protocol_version); |
205 SpdyHeaderBlock::const_iterator it = headers.find(":scheme"); | 208 SpdyHeaderBlock::const_iterator it = headers.find(":scheme"); |
206 if (it == headers.end()) | 209 if (it == headers.end()) |
207 return GURL(); | 210 return GURL(); |
208 std::string url = it->second; | 211 std::string url = it->second.as_string(); |
209 url.append("://"); | 212 url.append("://"); |
210 | 213 |
211 it = headers.find(protocol_version >= HTTP2 ? ":authority" : ":host"); | 214 it = headers.find(protocol_version >= HTTP2 ? ":authority" : ":host"); |
212 if (it == headers.end()) | 215 if (it == headers.end()) |
213 return GURL(); | 216 return GURL(); |
214 url.append(it->second); | 217 url.append(it->second.as_string()); |
215 | 218 |
216 it = headers.find(":path"); | 219 it = headers.find(":path"); |
217 if (it == headers.end()) | 220 if (it == headers.end()) |
218 return GURL(); | 221 return GURL(); |
219 url.append(it->second); | 222 url.append(it->second.as_string()); |
220 return GURL(url); | 223 return GURL(url); |
221 } | 224 } |
222 | 225 |
223 } // namespace net | 226 } // namespace net |
OLD | NEW |