Index: net/http/http_security_headers.cc |
diff --git a/net/http/http_security_headers.cc b/net/http/http_security_headers.cc |
index 77b170f3e285704d5e0239a7a6e2c36927edb231..d95e5878d7c4ce10e2e393d875fb254257d5b6de 100644 |
--- a/net/http/http_security_headers.cc |
+++ b/net/http/http_security_headers.cc |
@@ -5,12 +5,10 @@ |
#include "base/base64.h" |
#include "base/basictypes.h" |
#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_piece.h" |
#include "base/strings/string_tokenizer.h" |
#include "base/strings/string_util.h" |
#include "net/http/http_security_headers.h" |
#include "net/http/http_util.h" |
-#include "url/gurl.h" |
namespace net { |
@@ -25,10 +23,7 @@ |
bool MaxAgeToInt(std::string::const_iterator begin, |
std::string::const_iterator end, |
uint32* result) { |
- const base::StringPiece s(begin, end); |
- if (s.empty()) |
- return false; |
- |
+ const std::string s(begin, end); |
int64 i = 0; |
// Return false on any StringToInt64 parse errors *except* for |
@@ -97,16 +92,42 @@ |
HashesIntersect(pins, from_cert_chain); |
} |
-bool ParseAndAppendPin(std::string::const_iterator begin, |
- std::string::const_iterator end, |
+std::string Strip(const std::string& source) { |
+ if (source.empty()) |
+ return source; |
+ |
+ std::string::const_iterator start = source.begin(); |
+ std::string::const_iterator end = source.end(); |
+ HttpUtil::TrimLWS(&start, &end); |
+ return std::string(start, end); |
+} |
+ |
+typedef std::pair<std::string, std::string> StringPair; |
+ |
+StringPair Split(const std::string& source, char delimiter) { |
+ StringPair pair; |
+ size_t point = source.find(delimiter); |
+ |
+ pair.first = source.substr(0, point); |
+ if (std::string::npos != point) |
+ pair.second = source.substr(point + 1); |
+ |
+ return pair; |
+} |
+ |
+bool ParseAndAppendPin(const std::string& value, |
HashValueTag tag, |
HashValueVector* hashes) { |
- const base::StringPiece value(begin, end); |
- if (value.empty()) |
- return false; |
+ // Pins are always quoted. |
+ if (value.empty() || !HttpUtil::IsQuote(value[0])) |
+ return false; |
+ |
+ std::string unquoted = HttpUtil::Unquote(value); |
+ if (unquoted.empty()) |
+ return false; |
std::string decoded; |
- if (!base::Base64Decode(value, &decoded)) |
+ if (!base::Base64Decode(unquoted, &decoded)) |
return false; |
HashValue hash(tag); |
@@ -252,76 +273,50 @@ |
} |
} |
-// "Public-Key-Pins[-Report-Only]" ":" |
+// "Public-Key-Pins" ":" |
// "max-age" "=" delta-seconds ";" |
// "pin-" algo "=" base64 [ ";" ... ] |
-// [ ";" "includeSubdomains" ] |
-// [ ";" "report-uri" "=" uri-reference ] |
bool ParseHPKPHeader(const std::string& value, |
const HashValueVector& chain_hashes, |
base::TimeDelta* max_age, |
bool* include_subdomains, |
- HashValueVector* hashes, |
- GURL* report_uri) { |
+ HashValueVector* hashes) { |
bool parsed_max_age = false; |
bool include_subdomains_candidate = false; |
uint32 max_age_candidate = 0; |
- GURL parsed_report_uri; |
HashValueVector pins; |
- HttpUtil::NameValuePairsIterator name_value_pairs( |
- value.begin(), value.end(), ';', |
- HttpUtil::NameValuePairsIterator::VALUES_OPTIONAL); |
- |
- while (name_value_pairs.GetNext()) { |
- if (base::LowerCaseEqualsASCII(name_value_pairs.name_begin(), |
- name_value_pairs.name_end(), "max-age")) { |
- if (!MaxAgeToInt(name_value_pairs.value_begin(), |
- name_value_pairs.value_end(), &max_age_candidate)) { |
+ std::string source = value; |
+ |
+ while (!source.empty()) { |
+ StringPair semicolon = Split(source, ';'); |
+ semicolon.first = Strip(semicolon.first); |
+ semicolon.second = Strip(semicolon.second); |
+ StringPair equals = Split(semicolon.first, '='); |
+ equals.first = Strip(equals.first); |
+ equals.second = Strip(equals.second); |
+ |
+ if (base::LowerCaseEqualsASCII(equals.first, "max-age")) { |
+ if (equals.second.empty() || |
+ !MaxAgeToInt(equals.second.begin(), equals.second.end(), |
+ &max_age_candidate)) { |
return false; |
} |
parsed_max_age = true; |
- } else if (base::LowerCaseEqualsASCII(name_value_pairs.name_begin(), |
- name_value_pairs.name_end(), |
- "pin-sha1")) { |
- // Pins are always quoted. |
- if (!name_value_pairs.value_is_quoted() || |
- !ParseAndAppendPin(name_value_pairs.value_begin(), |
- name_value_pairs.value_end(), HASH_VALUE_SHA1, |
- &pins)) { |
+ } else if (base::LowerCaseEqualsASCII(equals.first, "pin-sha1")) { |
+ if (!ParseAndAppendPin(equals.second, HASH_VALUE_SHA1, &pins)) |
return false; |
- } |
- } else if (base::LowerCaseEqualsASCII(name_value_pairs.name_begin(), |
- name_value_pairs.name_end(), |
- "pin-sha256")) { |
- // Pins are always quoted. |
- if (!name_value_pairs.value_is_quoted() || |
- !ParseAndAppendPin(name_value_pairs.value_begin(), |
- name_value_pairs.value_end(), HASH_VALUE_SHA256, |
- &pins)) { |
+ } else if (base::LowerCaseEqualsASCII(equals.first, "pin-sha256")) { |
+ if (!ParseAndAppendPin(equals.second, HASH_VALUE_SHA256, &pins)) |
return false; |
- } |
- } else if (base::LowerCaseEqualsASCII(name_value_pairs.name_begin(), |
- name_value_pairs.name_end(), |
- "includesubdomains")) { |
+ } else if (base::LowerCaseEqualsASCII(equals.first, "includesubdomains")) { |
include_subdomains_candidate = true; |
- } else if (base::LowerCaseEqualsASCII(name_value_pairs.name_begin(), |
- name_value_pairs.name_end(), |
- "report-uri")) { |
- // report-uris are always quoted. |
- if (!name_value_pairs.value_is_quoted()) |
- return false; |
- |
- parsed_report_uri = GURL(name_value_pairs.value()); |
- if (parsed_report_uri.is_empty() || !parsed_report_uri.is_valid()) |
- return false; |
} else { |
// Silently ignore unknown directives for forward compatibility. |
} |
- } |
- |
- if (!name_value_pairs.valid()) |
- return false; |
+ |
+ source = semicolon.second; |
+ } |
if (!parsed_max_age) |
return false; |
@@ -332,7 +327,6 @@ |
*max_age = base::TimeDelta::FromSeconds(max_age_candidate); |
*include_subdomains = include_subdomains_candidate; |
hashes->swap(pins); |
- *report_uri = parsed_report_uri; |
return true; |
} |