| 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 |