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.
5 #include "net/spdy/spdy_alt_svc_wire_format.h"
10 #include "base/logging.h"
11 #include "base/strings/stringprintf.h"
18 bool ParsePositiveIntegerImpl(StringPiece::const_iterator c
,
19 StringPiece::const_iterator end
,
22 for (; c
!= end
&& isdigit(*c
); ++c
) {
23 if (*value
> std::numeric_limits
<T
>::max() / 10) {
27 if (*value
> std::numeric_limits
<T
>::max() - (*c
- '0')) {
32 return (c
== end
&& *value
> 0);
38 bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(StringPiece value
,
39 AlternativeService
* altsvc
) {
40 altsvc
->max_age
= 86400;
43 StringPiece::const_iterator c
= value
.begin();
44 StringPiece::const_iterator percent_encoded_protocol_id_end
=
45 std::find(c
, value
.end(), '=');
46 if (percent_encoded_protocol_id_end
== c
||
47 !PercentDecode(c
, percent_encoded_protocol_id_end
,
48 &(altsvc
->protocol_id
))) {
51 c
= percent_encoded_protocol_id_end
;
52 if (c
== value
.end()) {
57 if (c
== value
.end() || *c
!= '"') {
61 StringPiece::const_iterator alt_authority_begin
= c
;
62 for (; c
!= value
.end() && *c
!= '"'; ++c
) {
63 // Decode backslash encoding.
68 if (c
== value
.end()) {
72 if (c
== alt_authority_begin
|| c
== value
.end()) {
76 if (!ParseAltAuthority(alt_authority_begin
, c
, &(altsvc
->host
),
81 StringPiece::const_iterator parameters_end
= std::find(c
, value
.end(), ',');
82 while (c
!= parameters_end
) {
83 SkipWhiteSpace(&c
, parameters_end
);
84 if (c
== parameters_end
) {
91 SkipWhiteSpace(&c
, parameters_end
);
92 if (c
== parameters_end
) {
95 std::string parameter_name
;
96 for (; c
!= parameters_end
&& *c
!= '=' && *c
!= ' ' && *c
!= '\t'; ++c
) {
97 parameter_name
.push_back(tolower(*c
));
99 SkipWhiteSpace(&c
, parameters_end
);
100 if (c
== parameters_end
|| *c
!= '=') {
104 SkipWhiteSpace(&c
, parameters_end
);
105 StringPiece::const_iterator parameter_value_begin
= c
;
106 for (; c
!= parameters_end
&& *c
!= ';' && *c
!= ' ' && *c
!= '\t'; ++c
) {
108 if (c
== parameter_value_begin
) {
111 if (parameter_name
.compare("ma") == 0) {
112 if (!ParsePositiveInteger32(parameter_value_begin
, c
,
113 &(altsvc
->max_age
))) {
116 } else if (parameter_name
.compare("p") == 0) {
117 if (!ParseProbability(parameter_value_begin
, c
, &(altsvc
->p
))) {
121 SkipWhiteSpace(&c
, parameters_end
);
123 // TODO(bnc): Parse additional alternative services delimited by ','.
128 std::string
SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
129 const AlternativeService
& altsvc
) {
130 const char kNibbleToHex
[] = "0123456789ABCDEF";
132 // Percent escape protocol id according to
133 // http://tools.ietf.org/html/rfc7230#section-3.2.6.
134 for (char c
: altsvc
.protocol_id
) {
157 value
.push_back('%');
158 // Network byte order is big-endian.
159 value
.push_back(kNibbleToHex
[c
>> 4]);
160 value
.push_back(kNibbleToHex
[c
& 0x0f]);
164 value
.push_back('=');
165 value
.push_back('"');
166 for (char c
: altsvc
.host
) {
167 if (c
== '"' || c
== '\\') {
168 value
.push_back('\\');
172 base::StringAppendF(&value
, ":%d\"", altsvc
.port
);
173 if (altsvc
.max_age
!= 86400) {
174 base::StringAppendF(&value
, "; ma=%d", altsvc
.max_age
);
176 if (altsvc
.p
!= 1.0) {
177 base::StringAppendF(&value
, "; p=%.2f", altsvc
.p
);
183 void SpdyAltSvcWireFormat::SkipWhiteSpace(StringPiece::const_iterator
* c
,
184 StringPiece::const_iterator end
) {
185 for (; *c
!= end
&& (**c
== ' ' || **c
== '\t'); ++*c
) {
190 bool SpdyAltSvcWireFormat::PercentDecode(StringPiece::const_iterator c
,
191 StringPiece::const_iterator end
,
192 std::string
* output
) {
194 for (; c
!= end
; ++c
) {
196 output
->push_back(*c
);
201 if (c
== end
|| !isxdigit(*c
)) {
204 char decoded
= tolower(*c
);
205 // '0' is 0, 'a' is 10.
206 decoded
+= isdigit(*c
) ? (0 - '0') : (10 - 'a');
207 // Network byte order is big-endian.
210 if (c
== end
|| !isxdigit(*c
)) {
213 decoded
+= tolower(*c
);
214 // '0' is 0, 'a' is 10.
215 decoded
+= isdigit(*c
) ? (0 - '0') : (10 - 'a');
216 output
->push_back(decoded
);
222 bool SpdyAltSvcWireFormat::ParseAltAuthority(StringPiece::const_iterator c
,
223 StringPiece::const_iterator end
,
227 for (; c
!= end
&& *c
!= ':'; ++c
) {
229 // Port is mandatory.
245 return ParsePositiveInteger16(c
, end
, port
);
249 bool SpdyAltSvcWireFormat::ParsePositiveInteger16(
250 StringPiece::const_iterator c
,
251 StringPiece::const_iterator end
,
253 return ParsePositiveIntegerImpl
<uint16
>(c
, end
, value
);
257 bool SpdyAltSvcWireFormat::ParsePositiveInteger32(
258 StringPiece::const_iterator c
,
259 StringPiece::const_iterator end
,
261 return ParsePositiveIntegerImpl
<uint32
>(c
, end
, value
);
264 // Probability is a decimal fraction between 0.0 and 1.0, inclusive, with
265 // optional leading zero, optional decimal point, and optional digits following
266 // the decimal point, with the restriction that there has to be at least one
267 // digit (that is, "" and "." are not valid).
269 bool SpdyAltSvcWireFormat::ParseProbability(StringPiece::const_iterator c
,
270 StringPiece::const_iterator end
,
277 if (end
- c
== 1 && *c
== '.') {
295 // So far we could have had ".", "0.", or "1.".
297 double place_value
= 0.1;
298 for (; c
!= end
&& isdigit(*c
); ++c
) {
299 *p
+= place_value
* (*c
- '0');
302 return (c
== end
&& *p
<= 1.0);