Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: net/spdy/spdy_alt_svc_wire_format.cc

Issue 1130053007: Update HTTP/2 ALTSVC wireformat from draft-04 to draft-06. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Hack around win_chromium_compile_dbg_ng linker errors. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/spdy/spdy_alt_svc_wire_format.h ('k') | net/spdy/spdy_alt_svc_wire_format_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015 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_alt_svc_wire_format.h"
6
7 #include <limits>
8 #include <string>
9
10 #include "base/logging.h"
11 #include "base/strings/stringprintf.h"
12
13 namespace net {
14
15 namespace {
16
17 template <class T>
18 bool ParsePositiveIntegerImpl(StringPiece::const_iterator c,
19 StringPiece::const_iterator end,
20 T* value) {
21 *value = 0;
22 for (; c != end && isdigit(*c); ++c) {
23 if (*value > std::numeric_limits<T>::max() / 10) {
24 return false;
25 }
26 *value *= 10;
27 if (*value > std::numeric_limits<T>::max() - (*c - '0')) {
28 return false;
29 }
30 *value += *c - '0';
31 }
32 return (c == end && *value > 0);
33 }
34
35 } // namespace
36
37 // static
38 bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(StringPiece value,
39 std::string* protocol_id,
40 std::string* host,
41 uint16* port,
42 uint32* max_age,
43 double* p) {
44 *max_age = 86400;
45 *p = 1.0;
46
47 StringPiece::const_iterator c = value.begin();
48 StringPiece::const_iterator percent_encoded_protocol_id_end =
49 std::find(c, value.end(), '=');
50 if (percent_encoded_protocol_id_end == c ||
51 !PercentDecode(c, percent_encoded_protocol_id_end, protocol_id)) {
52 return false;
53 }
54 c = percent_encoded_protocol_id_end;
55 if (c == value.end()) {
56 return false;
57 }
58 DCHECK_EQ('=', *c);
59 ++c;
60 if (c == value.end() || *c != '"') {
61 return false;
62 }
63 ++c;
64 StringPiece::const_iterator alt_authority_begin = c;
65 for (; c != value.end() && *c != '"'; ++c) {
66 // Decode backslash encoding.
67 if (*c != '\\') {
68 continue;
69 }
70 ++c;
71 if (c == value.end()) {
72 return false;
73 }
74 }
75 if (c == alt_authority_begin || c == value.end()) {
76 return false;
77 }
78 DCHECK_EQ('"', *c);
79 if (!ParseAltAuthority(alt_authority_begin, c, host, port)) {
80 return false;
81 }
82 ++c;
83 StringPiece::const_iterator parameters_end = std::find(c, value.end(), ',');
84 while (c != parameters_end) {
85 SkipWhiteSpace(&c, parameters_end);
86 if (c == parameters_end) {
87 return true;
88 }
89 if (*c != ';') {
90 return false;
91 }
92 ++c;
93 SkipWhiteSpace(&c, parameters_end);
94 if (c == parameters_end) {
95 return true;
96 }
97 std::string parameter_name;
98 for (; c != parameters_end && *c != '=' && *c != ' ' && *c != '\t'; ++c) {
99 parameter_name.push_back(tolower(*c));
100 }
101 SkipWhiteSpace(&c, parameters_end);
102 if (c == parameters_end || *c != '=') {
103 return false;
104 }
105 ++c;
106 SkipWhiteSpace(&c, parameters_end);
107 StringPiece::const_iterator parameter_value_begin = c;
108 for (; c != parameters_end && *c != ';' && *c != ' ' && *c != '\t'; ++c) {
109 }
110 if (c == parameter_value_begin) {
111 return false;
112 }
113 if (parameter_name.compare("ma") == 0) {
114 if (!ParsePositiveInteger32(parameter_value_begin, c, max_age)) {
115 return false;
116 }
117 } else if (parameter_name.compare("p") == 0) {
118 if (!ParseProbability(parameter_value_begin, c, p)) {
119 return false;
120 }
121 }
122 SkipWhiteSpace(&c, parameters_end);
123 }
124 // TODO(bnc): Parse additional alternative services delimited by ','.
125 return true;
126 }
127
128 // static
129 std::string SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
130 const std::string& protocol_id,
131 const std::string& host,
132 uint16 port,
133 uint32 max_age,
134 double p) {
135 const char kNibbleToHex[] = "0123456789ABCDEF";
136 std::string value;
137 // Percent escape protocol id according to
138 // http://tools.ietf.org/html/rfc7230#section-3.2.6.
139 for (char c : protocol_id) {
140 if (isalnum(c)) {
141 value.push_back(c);
142 continue;
143 }
144 switch (c) {
145 case '!':
146 case '#':
147 case '$':
148 case '&':
149 case '\'':
150 case '*':
151 case '+':
152 case '-':
153 case '.':
154 case '^':
155 case '_':
156 case '`':
157 case '|':
158 case '~':
159 value.push_back(c);
160 break;
161 default:
162 value.push_back('%');
163 // Network byte order is big-endian.
164 value.push_back(kNibbleToHex[c >> 4]);
165 value.push_back(kNibbleToHex[c & 0x0f]);
166 break;
167 }
168 }
169 value.push_back('=');
170 value.push_back('"');
171 for (char c : host) {
172 if (c == '"' || c == '\\') {
173 value.push_back('\\');
174 }
175 value.push_back(c);
176 }
177 base::StringAppendF(&value, ":%d\"", port);
178 if (max_age != 86400) {
179 base::StringAppendF(&value, "; ma=%d", max_age);
180 }
181 if (p != 1.0) {
182 base::StringAppendF(&value, "; p=%.2f", p);
183 }
184 return value;
185 }
186
187 // static
188 void SpdyAltSvcWireFormat::SkipWhiteSpace(StringPiece::const_iterator* c,
189 StringPiece::const_iterator end) {
190 for (; *c != end && (**c == ' ' || **c == '\t'); ++*c) {
191 }
192 }
193
194 // static
195 bool SpdyAltSvcWireFormat::PercentDecode(StringPiece::const_iterator c,
196 StringPiece::const_iterator end,
197 std::string* output) {
198 output->clear();
199 for (; c != end; ++c) {
200 if (*c != '%') {
201 output->push_back(*c);
202 continue;
203 }
204 DCHECK_EQ('%', *c);
205 ++c;
206 if (c == end || !isxdigit(*c)) {
207 return false;
208 }
209 char decoded = tolower(*c);
210 // '0' is 0, 'a' is 10.
211 decoded += isdigit(*c) ? (0 - '0') : (10 - 'a');
212 // Network byte order is big-endian.
213 decoded <<= 4;
214 ++c;
215 if (c == end || !isxdigit(*c)) {
216 return false;
217 }
218 decoded += tolower(*c);
219 // '0' is 0, 'a' is 10.
220 decoded += isdigit(*c) ? (0 - '0') : (10 - 'a');
221 output->push_back(decoded);
222 }
223 return true;
224 }
225
226 // static
227 bool SpdyAltSvcWireFormat::ParseAltAuthority(StringPiece::const_iterator c,
228 StringPiece::const_iterator end,
229 std::string* host,
230 uint16* port) {
231 host->clear();
232 for (; c != end && *c != ':'; ++c) {
233 if (*c == '"') {
234 // Port is mandatory.
235 return false;
236 }
237 if (*c == '\\') {
238 ++c;
239 if (c == end) {
240 return false;
241 }
242 }
243 host->push_back(*c);
244 }
245 if (c == end) {
246 return false;
247 }
248 DCHECK_EQ(':', *c);
249 ++c;
250 return ParsePositiveInteger16(c, end, port);
251 }
252
253 // static
254 bool SpdyAltSvcWireFormat::ParsePositiveInteger16(
255 StringPiece::const_iterator c,
256 StringPiece::const_iterator end,
257 uint16* value) {
258 return ParsePositiveIntegerImpl<uint16>(c, end, value);
259 }
260
261 // static
262 bool SpdyAltSvcWireFormat::ParsePositiveInteger32(
263 StringPiece::const_iterator c,
264 StringPiece::const_iterator end,
265 uint32* value) {
266 return ParsePositiveIntegerImpl<uint32>(c, end, value);
267 }
268
269 // Probability is a decimal fraction between 0.0 and 1.0, inclusive, with
270 // optional leading zero, optional decimal point, and optional digits following
271 // the decimal point, with the restriction that there has to be at least one
272 // digit (that is, "" and "." are not valid).
273 // static
274 bool SpdyAltSvcWireFormat::ParseProbability(StringPiece::const_iterator c,
275 StringPiece::const_iterator end,
276 double* p) {
277 // "" is invalid.
278 if (c == end) {
279 return false;
280 }
281 // "." is invalid.
282 if (end - c == 1 && *c == '.') {
283 return false;
284 }
285 if (*c == '1') {
286 *p = 1.0;
287 ++c;
288 } else {
289 *p = 0.0;
290 if (*c == '0') {
291 ++c;
292 }
293 }
294 if (c == end) {
295 return true;
296 }
297 if (*c != '.') {
298 return false;
299 }
300 // So far we could have had ".", "0.", or "1.".
301 ++c;
302 double place_value = 0.1;
303 for (; c != end && isdigit(*c); ++c) {
304 *p += place_value * (*c - '0');
305 place_value *= 0.1;
306 }
307 return (c == end && *p <= 1.0);
308 }
309
310 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/spdy_alt_svc_wire_format.h ('k') | net/spdy/spdy_alt_svc_wire_format_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698