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(
40 AlternativeServiceVector
* altsvc_vector
) {
41 altsvc_vector
->clear();
42 StringPiece::const_iterator c
= value
.begin();
43 while (c
!= value
.end()) {
45 StringPiece::const_iterator percent_encoded_protocol_id_end
=
46 std::find(c
, value
.end(), '=');
47 std::string protocol_id
;
48 if (percent_encoded_protocol_id_end
== c
||
49 !PercentDecode(c
, percent_encoded_protocol_id_end
, &protocol_id
)) {
52 c
= percent_encoded_protocol_id_end
;
53 if (c
== value
.end()) {
56 // Parse alt-authority.
59 if (c
== value
.end() || *c
!= '"') {
63 StringPiece::const_iterator alt_authority_begin
= c
;
64 for (; c
!= value
.end() && *c
!= '"'; ++c
) {
65 // Decode backslash encoding.
70 if (c
== value
.end()) {
74 if (c
== alt_authority_begin
|| c
== value
.end()) {
80 if (!ParseAltAuthority(alt_authority_begin
, c
, &host
, &port
)) {
85 uint32 max_age
= 86400;
87 StringPiece::const_iterator parameters_end
= std::find(c
, value
.end(), ',');
88 while (c
!= parameters_end
) {
89 SkipWhiteSpace(&c
, parameters_end
);
90 if (c
== parameters_end
) {
97 SkipWhiteSpace(&c
, parameters_end
);
98 if (c
== parameters_end
) {
101 std::string parameter_name
;
102 for (; c
!= parameters_end
&& *c
!= '=' && *c
!= ' ' && *c
!= '\t'; ++c
) {
103 parameter_name
.push_back(tolower(*c
));
105 SkipWhiteSpace(&c
, parameters_end
);
106 if (c
== parameters_end
|| *c
!= '=') {
110 SkipWhiteSpace(&c
, parameters_end
);
111 StringPiece::const_iterator parameter_value_begin
= c
;
112 for (; c
!= parameters_end
&& *c
!= ';' && *c
!= ' ' && *c
!= '\t'; ++c
) {
114 if (c
== parameter_value_begin
) {
117 if (parameter_name
.compare("ma") == 0) {
118 if (!ParsePositiveInteger32(parameter_value_begin
, c
, &max_age
)) {
121 } else if (parameter_name
.compare("p") == 0) {
122 if (!ParseProbability(parameter_value_begin
, c
, &p
)) {
127 altsvc_vector
->push_back(
128 AlternativeService(protocol_id
, host
, port
, max_age
, p
));
129 for (; c
!= value
.end() && (*c
== ' ' || *c
== '\t' || *c
== ','); ++c
) {
136 std::string
SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
137 const AlternativeServiceVector
& altsvc_vector
) {
138 const char kNibbleToHex
[] = "0123456789ABCDEF";
140 for (const AlternativeService
& altsvc
: altsvc_vector
) {
141 if (!value
.empty()) {
142 value
.push_back(',');
144 // Percent escape protocol id according to
145 // http://tools.ietf.org/html/rfc7230#section-3.2.6.
146 for (char c
: altsvc
.protocol_id
) {
169 value
.push_back('%');
170 // Network byte order is big-endian.
171 value
.push_back(kNibbleToHex
[c
>> 4]);
172 value
.push_back(kNibbleToHex
[c
& 0x0f]);
176 value
.push_back('=');
177 value
.push_back('"');
178 for (char c
: altsvc
.host
) {
179 if (c
== '"' || c
== '\\') {
180 value
.push_back('\\');
184 base::StringAppendF(&value
, ":%d\"", altsvc
.port
);
185 if (altsvc
.max_age
!= 86400) {
186 base::StringAppendF(&value
, "; ma=%d", altsvc
.max_age
);
188 if (altsvc
.p
!= 1.0) {
189 base::StringAppendF(&value
, "; p=%.2f", altsvc
.p
);
196 void SpdyAltSvcWireFormat::SkipWhiteSpace(StringPiece::const_iterator
* c
,
197 StringPiece::const_iterator end
) {
198 for (; *c
!= end
&& (**c
== ' ' || **c
== '\t'); ++*c
) {
203 bool SpdyAltSvcWireFormat::PercentDecode(StringPiece::const_iterator c
,
204 StringPiece::const_iterator end
,
205 std::string
* output
) {
207 for (; c
!= end
; ++c
) {
209 output
->push_back(*c
);
214 if (c
== end
|| !isxdigit(*c
)) {
217 char decoded
= tolower(*c
);
218 // '0' is 0, 'a' is 10.
219 decoded
+= isdigit(*c
) ? (0 - '0') : (10 - 'a');
220 // Network byte order is big-endian.
223 if (c
== end
|| !isxdigit(*c
)) {
226 decoded
+= tolower(*c
);
227 // '0' is 0, 'a' is 10.
228 decoded
+= isdigit(*c
) ? (0 - '0') : (10 - 'a');
229 output
->push_back(decoded
);
235 bool SpdyAltSvcWireFormat::ParseAltAuthority(StringPiece::const_iterator c
,
236 StringPiece::const_iterator end
,
240 for (; c
!= end
&& *c
!= ':'; ++c
) {
242 // Port is mandatory.
258 return ParsePositiveInteger16(c
, end
, port
);
262 bool SpdyAltSvcWireFormat::ParsePositiveInteger16(
263 StringPiece::const_iterator c
,
264 StringPiece::const_iterator end
,
266 return ParsePositiveIntegerImpl
<uint16
>(c
, end
, value
);
270 bool SpdyAltSvcWireFormat::ParsePositiveInteger32(
271 StringPiece::const_iterator c
,
272 StringPiece::const_iterator end
,
274 return ParsePositiveIntegerImpl
<uint32
>(c
, end
, value
);
277 // Probability is a decimal fraction between 0.0 and 1.0, inclusive, with
278 // optional leading zero, optional decimal point, and optional digits following
279 // the decimal point, with the restriction that there has to be at least one
280 // digit (that is, "" and "." are not valid).
282 bool SpdyAltSvcWireFormat::ParseProbability(StringPiece::const_iterator c
,
283 StringPiece::const_iterator end
,
290 if (end
- c
== 1 && *c
== '.') {
308 // So far we could have had ".", "0.", or "1.".
310 double place_value
= 0.1;
311 for (; c
!= end
&& isdigit(*c
); ++c
) {
312 *p
+= place_value
* (*c
- '0');
315 return (c
== end
&& *p
<= 1.0);