OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/spdy/spdy_http_utils.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/strings/string_number_conversions.h" | |
10 #include "base/strings/string_split.h" | |
11 #include "base/strings/string_util.h" | |
12 #include "base/time/time.h" | |
13 #include "net/base/escape.h" | |
14 #include "net/base/load_flags.h" | |
15 #include "net/base/url_util.h" | |
16 #include "net/http/http_request_headers.h" | |
17 #include "net/http/http_request_info.h" | |
18 #include "net/http/http_response_headers.h" | |
19 #include "net/http/http_response_info.h" | |
20 #include "net/http/http_util.h" | |
21 #include "net/spdy/platform/api/spdy_string.h" | |
22 #include "net/spdy/platform/api/spdy_string_piece.h" | |
23 | |
24 namespace net { | |
25 | |
26 namespace { | |
27 | |
28 void AddSpdyHeader(const SpdyString& name, | |
29 const SpdyString& value, | |
30 SpdyHeaderBlock* headers) { | |
31 if (headers->find(name) == headers->end()) { | |
32 (*headers)[name] = value; | |
33 } else { | |
34 SpdyString joint_value = (*headers)[name].as_string(); | |
35 joint_value.append(1, '\0'); | |
36 joint_value.append(value); | |
37 (*headers)[name] = joint_value; | |
38 } | |
39 } | |
40 | |
41 } // namespace | |
42 | |
43 bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers, | |
44 HttpResponseInfo* response) { | |
45 // The ":status" header is required. | |
46 SpdyHeaderBlock::const_iterator it = headers.find(":status"); | |
47 if (it == headers.end()) | |
48 return false; | |
49 SpdyString status = it->second.as_string(); | |
50 SpdyString raw_headers("HTTP/1.1 "); | |
51 raw_headers.append(status); | |
52 raw_headers.push_back('\0'); | |
53 for (it = headers.begin(); it != headers.end(); ++it) { | |
54 // For each value, if the server sends a NUL-separated | |
55 // list of values, we separate that back out into | |
56 // individual headers for each value in the list. | |
57 // e.g. | |
58 // Set-Cookie "foo\0bar" | |
59 // becomes | |
60 // Set-Cookie: foo\0 | |
61 // Set-Cookie: bar\0 | |
62 SpdyString value = it->second.as_string(); | |
63 size_t start = 0; | |
64 size_t end = 0; | |
65 do { | |
66 end = value.find('\0', start); | |
67 SpdyString tval; | |
68 if (end != value.npos) | |
69 tval = value.substr(start, (end - start)); | |
70 else | |
71 tval = value.substr(start); | |
72 if (it->first[0] == ':') | |
73 raw_headers.append(it->first.as_string().substr(1)); | |
74 else | |
75 raw_headers.append(it->first.as_string()); | |
76 raw_headers.push_back(':'); | |
77 raw_headers.append(tval); | |
78 raw_headers.push_back('\0'); | |
79 start = end + 1; | |
80 } while (end != value.npos); | |
81 } | |
82 | |
83 response->headers = new HttpResponseHeaders(raw_headers); | |
84 response->was_fetched_via_spdy = true; | |
85 return true; | |
86 } | |
87 | |
88 void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info, | |
89 const HttpRequestHeaders& request_headers, | |
90 bool direct, | |
91 SpdyHeaderBlock* headers) { | |
92 (*headers)[":method"] = info.method; | |
93 if (info.method == "CONNECT") { | |
94 (*headers)[":authority"] = GetHostAndPort(info.url); | |
95 } else { | |
96 (*headers)[":authority"] = GetHostAndOptionalPort(info.url); | |
97 (*headers)[":scheme"] = info.url.scheme(); | |
98 (*headers)[":path"] = info.url.PathForRequest(); | |
99 } | |
100 | |
101 HttpRequestHeaders::Iterator it(request_headers); | |
102 while (it.GetNext()) { | |
103 SpdyString name = base::ToLowerASCII(it.name()); | |
104 if (name.empty() || name[0] == ':' || name == "connection" || | |
105 name == "proxy-connection" || name == "transfer-encoding" || | |
106 name == "host") { | |
107 continue; | |
108 } | |
109 AddSpdyHeader(name, it.value(), headers); | |
110 } | |
111 } | |
112 | |
113 static_assert(HIGHEST - LOWEST < 4 && HIGHEST - MINIMUM_PRIORITY < 6, | |
114 "request priority incompatible with spdy"); | |
115 | |
116 SpdyPriority ConvertRequestPriorityToSpdyPriority( | |
117 const RequestPriority priority) { | |
118 DCHECK_GE(priority, MINIMUM_PRIORITY); | |
119 DCHECK_LE(priority, MAXIMUM_PRIORITY); | |
120 return static_cast<SpdyPriority>(MAXIMUM_PRIORITY - priority + | |
121 kV3HighestPriority); | |
122 } | |
123 | |
124 NET_EXPORT_PRIVATE RequestPriority | |
125 ConvertSpdyPriorityToRequestPriority(SpdyPriority priority) { | |
126 // Handle invalid values gracefully. | |
127 return ((priority - kV3HighestPriority) > | |
128 (MAXIMUM_PRIORITY - MINIMUM_PRIORITY)) | |
129 ? IDLE | |
130 : static_cast<RequestPriority>(MAXIMUM_PRIORITY - | |
131 (priority - kV3HighestPriority)); | |
132 } | |
133 | |
134 NET_EXPORT_PRIVATE void ConvertHeaderBlockToHttpRequestHeaders( | |
135 const SpdyHeaderBlock& spdy_headers, | |
136 HttpRequestHeaders* http_headers) { | |
137 for (const auto& it : spdy_headers) { | |
138 SpdyStringPiece key = it.first; | |
139 if (key[0] == ':') { | |
140 key.remove_prefix(1); | |
141 } | |
142 std::vector<SpdyStringPiece> values = base::SplitStringPiece( | |
143 it.second, "\0", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | |
144 for (const auto& value : values) { | |
145 http_headers->SetHeader(key, value); | |
146 } | |
147 } | |
148 } | |
149 | |
150 GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers) { | |
151 SpdyHeaderBlock::const_iterator it = headers.find(":scheme"); | |
152 if (it == headers.end()) | |
153 return GURL(); | |
154 SpdyString url = it->second.as_string(); | |
155 url.append("://"); | |
156 | |
157 it = headers.find(":authority"); | |
158 if (it == headers.end()) | |
159 return GURL(); | |
160 url.append(it->second.as_string()); | |
161 | |
162 it = headers.find(":path"); | |
163 if (it == headers.end()) | |
164 return GURL(); | |
165 url.append(it->second.as_string()); | |
166 return GURL(url); | |
167 } | |
168 | |
169 } // namespace net | |
OLD | NEW |