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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/spdy/spdy_alt_svc_wire_format.cc
diff --git a/net/spdy/spdy_alt_svc_wire_format.cc b/net/spdy/spdy_alt_svc_wire_format.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a1e7361771c64d2d42153918e46d15c2ef57b5ec
--- /dev/null
+++ b/net/spdy/spdy_alt_svc_wire_format.cc
@@ -0,0 +1,310 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/spdy/spdy_alt_svc_wire_format.h"
+
+#include <limits>
+#include <string>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+
+namespace net {
+
+namespace {
+
+template <class T>
+bool ParsePositiveIntegerImpl(StringPiece::const_iterator c,
+ StringPiece::const_iterator end,
+ T* value) {
+ *value = 0;
+ for (; c != end && isdigit(*c); ++c) {
+ if (*value > std::numeric_limits<T>::max() / 10) {
+ return false;
+ }
+ *value *= 10;
+ if (*value > std::numeric_limits<T>::max() - (*c - '0')) {
+ return false;
+ }
+ *value += *c - '0';
+ }
+ return (c == end && *value > 0);
+}
+
+} // namespace
+
+// static
+bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(StringPiece value,
+ std::string* protocol_id,
+ std::string* host,
+ uint16* port,
+ uint32* max_age,
+ double* p) {
+ *max_age = 86400;
+ *p = 1.0;
+
+ StringPiece::const_iterator c = value.begin();
+ StringPiece::const_iterator percent_encoded_protocol_id_end =
+ std::find(c, value.end(), '=');
+ if (percent_encoded_protocol_id_end == c ||
+ !PercentDecode(c, percent_encoded_protocol_id_end, protocol_id)) {
+ return false;
+ }
+ c = percent_encoded_protocol_id_end;
+ if (c == value.end()) {
+ return false;
+ }
+ DCHECK_EQ('=', *c);
+ ++c;
+ if (c == value.end() || *c != '"') {
+ return false;
+ }
+ ++c;
+ StringPiece::const_iterator alt_authority_begin = c;
+ for (; c != value.end() && *c != '"'; ++c) {
+ // Decode backslash encoding.
+ if (*c != '\\') {
+ continue;
+ }
+ ++c;
+ if (c == value.end()) {
+ return false;
+ }
+ }
+ if (c == alt_authority_begin || c == value.end()) {
+ return false;
+ }
+ DCHECK_EQ('"', *c);
+ if (!ParseAltAuthority(alt_authority_begin, c, host, port)) {
+ return false;
+ }
+ ++c;
+ StringPiece::const_iterator parameters_end = std::find(c, value.end(), ',');
+ while (c != parameters_end) {
+ SkipWhiteSpace(&c, parameters_end);
+ if (c == parameters_end) {
+ return true;
+ }
+ if (*c != ';') {
+ return false;
+ }
+ ++c;
+ SkipWhiteSpace(&c, parameters_end);
+ if (c == parameters_end) {
+ return true;
+ }
+ std::string parameter_name;
+ for (; c != parameters_end && *c != '=' && *c != ' ' && *c != '\t'; ++c) {
+ parameter_name.push_back(tolower(*c));
+ }
+ SkipWhiteSpace(&c, parameters_end);
+ if (c == parameters_end || *c != '=') {
+ return false;
+ }
+ ++c;
+ SkipWhiteSpace(&c, parameters_end);
+ StringPiece::const_iterator parameter_value_begin = c;
+ for (; c != parameters_end && *c != ';' && *c != ' ' && *c != '\t'; ++c) {
+ }
+ if (c == parameter_value_begin) {
+ return false;
+ }
+ if (parameter_name.compare("ma") == 0) {
+ if (!ParsePositiveInteger32(parameter_value_begin, c, max_age)) {
+ return false;
+ }
+ } else if (parameter_name.compare("p") == 0) {
+ if (!ParseProbability(parameter_value_begin, c, p)) {
+ return false;
+ }
+ }
+ SkipWhiteSpace(&c, parameters_end);
+ }
+ // TODO(bnc): Parse additional alternative services delimited by ','.
+ return true;
+}
+
+// static
+std::string SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
+ const std::string& protocol_id,
+ const std::string& host,
+ uint16 port,
+ uint32 max_age,
+ double p) {
+ const char kNibbleToHex[] = "0123456789ABCDEF";
+ std::string value;
+ // Percent escape protocol id according to
+ // http://tools.ietf.org/html/rfc7230#section-3.2.6.
+ for (char c : protocol_id) {
+ if (isalnum(c)) {
+ value.push_back(c);
+ continue;
+ }
+ switch (c) {
+ case '!':
+ case '#':
+ case '$':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '.':
+ case '^':
+ case '_':
+ case '`':
+ case '|':
+ case '~':
+ value.push_back(c);
+ break;
+ default:
+ value.push_back('%');
+ // Network byte order is big-endian.
+ value.push_back(kNibbleToHex[c >> 4]);
+ value.push_back(kNibbleToHex[c & 0x0f]);
+ break;
+ }
+ }
+ value.push_back('=');
+ value.push_back('"');
+ for (char c : host) {
+ if (c == '"' || c == '\\') {
+ value.push_back('\\');
+ }
+ value.push_back(c);
+ }
+ base::StringAppendF(&value, ":%d\"", port);
+ if (max_age != 86400) {
+ base::StringAppendF(&value, "; ma=%d", max_age);
+ }
+ if (p != 1.0) {
+ base::StringAppendF(&value, "; p=%.2f", p);
+ }
+ return value;
+}
+
+// static
+void SpdyAltSvcWireFormat::SkipWhiteSpace(StringPiece::const_iterator* c,
+ StringPiece::const_iterator end) {
+ for (; *c != end && (**c == ' ' || **c == '\t'); ++*c) {
+ }
+}
+
+// static
+bool SpdyAltSvcWireFormat::PercentDecode(StringPiece::const_iterator c,
+ StringPiece::const_iterator end,
+ std::string* output) {
+ output->clear();
+ for (; c != end; ++c) {
+ if (*c != '%') {
+ output->push_back(*c);
+ continue;
+ }
+ DCHECK_EQ('%', *c);
+ ++c;
+ if (c == end || !isxdigit(*c)) {
+ return false;
+ }
+ char decoded = tolower(*c);
+ // '0' is 0, 'a' is 10.
+ decoded += isdigit(*c) ? (0 - '0') : (10 - 'a');
+ // Network byte order is big-endian.
+ decoded <<= 4;
+ ++c;
+ if (c == end || !isxdigit(*c)) {
+ return false;
+ }
+ decoded += tolower(*c);
+ // '0' is 0, 'a' is 10.
+ decoded += isdigit(*c) ? (0 - '0') : (10 - 'a');
+ output->push_back(decoded);
+ }
+ return true;
+}
+
+// static
+bool SpdyAltSvcWireFormat::ParseAltAuthority(StringPiece::const_iterator c,
+ StringPiece::const_iterator end,
+ std::string* host,
+ uint16* port) {
+ host->clear();
+ for (; c != end && *c != ':'; ++c) {
+ if (*c == '"') {
+ // Port is mandatory.
+ return false;
+ }
+ if (*c == '\\') {
+ ++c;
+ if (c == end) {
+ return false;
+ }
+ }
+ host->push_back(*c);
+ }
+ if (c == end) {
+ return false;
+ }
+ DCHECK_EQ(':', *c);
+ ++c;
+ return ParsePositiveInteger16(c, end, port);
+}
+
+// static
+bool SpdyAltSvcWireFormat::ParsePositiveInteger16(
+ StringPiece::const_iterator c,
+ StringPiece::const_iterator end,
+ uint16* value) {
+ return ParsePositiveIntegerImpl<uint16>(c, end, value);
+}
+
+// static
+bool SpdyAltSvcWireFormat::ParsePositiveInteger32(
+ StringPiece::const_iterator c,
+ StringPiece::const_iterator end,
+ uint32* value) {
+ return ParsePositiveIntegerImpl<uint32>(c, end, value);
+}
+
+// Probability is a decimal fraction between 0.0 and 1.0, inclusive, with
+// optional leading zero, optional decimal point, and optional digits following
+// the decimal point, with the restriction that there has to be at least one
+// digit (that is, "" and "." are not valid).
+// static
+bool SpdyAltSvcWireFormat::ParseProbability(StringPiece::const_iterator c,
+ StringPiece::const_iterator end,
+ double* p) {
+ // "" is invalid.
+ if (c == end) {
+ return false;
+ }
+ // "." is invalid.
+ if (end - c == 1 && *c == '.') {
+ return false;
+ }
+ if (*c == '1') {
+ *p = 1.0;
+ ++c;
+ } else {
+ *p = 0.0;
+ if (*c == '0') {
+ ++c;
+ }
+ }
+ if (c == end) {
+ return true;
+ }
+ if (*c != '.') {
+ return false;
+ }
+ // So far we could have had ".", "0.", or "1.".
+ ++c;
+ double place_value = 0.1;
+ for (; c != end && isdigit(*c); ++c) {
+ *p += place_value * (*c - '0');
+ place_value *= 0.1;
+ }
+ return (c == end && *p <= 1.0);
+}
+
+} // namespace net
« 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