| Index: net/quic/spdy_utils.cc
|
| diff --git a/net/quic/spdy_utils.cc b/net/quic/spdy_utils.cc
|
| index 7343cceaf8ef5002bf3907096d1922120f7d4920..bdb4a752ebdce67ec352a484644dbaa40de8a150 100644
|
| --- a/net/quic/spdy_utils.cc
|
| +++ b/net/quic/spdy_utils.cc
|
| @@ -16,6 +16,7 @@
|
| #include "net/spdy/spdy_protocol.h"
|
| #include "url/gurl.h"
|
|
|
| +using base::StringPiece;
|
| using std::string;
|
| using std::vector;
|
|
|
| @@ -108,11 +109,76 @@ bool SpdyUtils::ParseTrailers(const char* data,
|
| return true;
|
| }
|
|
|
| +bool SpdyUtils::CopyAndValidateHeaders(const QuicHeaderList& header_list,
|
| + int64_t* content_length,
|
| + SpdyHeaderBlock* headers) {
|
| + for (const auto& p : header_list) {
|
| + const string& name = p.first;
|
| + if (name.empty()) {
|
| + DVLOG(1) << "Header name must not be empty.";
|
| + return false;
|
| + }
|
| +
|
| + if (std::any_of(name.begin(), name.end(), base::IsAsciiUpper<char>)) {
|
| + DLOG(ERROR) << "Malformed header: Header name " << name
|
| + << " contains upper-case characters.";
|
| + return false;
|
| + }
|
| +
|
| + if (headers->find(name) != headers->end()) {
|
| + DLOG(ERROR) << "Duplicate header '" << name << "' found.";
|
| + return false;
|
| + }
|
| +
|
| + (*headers)[name] = p.second;
|
| + }
|
| +
|
| + if (ContainsKey(*headers, "content-length")) {
|
| + // Check whether multiple values are consistent.
|
| + StringPiece content_length_header = (*headers)["content-length"];
|
| + vector<string> values =
|
| + base::SplitString(content_length_header, base::StringPiece("\0", 1),
|
| + base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
|
| + for (const string& value : values) {
|
| + int new_value;
|
| + if (!base::StringToInt(value, &new_value) || new_value < 0) {
|
| + DLOG(ERROR) << "Content length was either unparseable or negative.";
|
| + return false;
|
| + }
|
| + if (*content_length < 0) {
|
| + *content_length = new_value;
|
| + continue;
|
| + }
|
| + if (new_value != *content_length) {
|
| + DLOG(ERROR) << "Parsed content length " << new_value << " is "
|
| + << "inconsistent with previously detected content length "
|
| + << *content_length;
|
| + return false;
|
| + }
|
| + }
|
| + }
|
| +
|
| + DVLOG(1) << "Successfully parsed headers: " << headers->DebugString();
|
| + return true;
|
| +}
|
| +
|
| bool SpdyUtils::CopyAndValidateTrailers(const QuicHeaderList& header_list,
|
| size_t* final_byte_offset,
|
| SpdyHeaderBlock* trailers) {
|
| + bool found_final_byte_offset = false;
|
| for (const auto& p : header_list) {
|
| const string& name = p.first;
|
| +
|
| + // Pull out the final offset pseudo header which indicates the number of
|
| + // response body bytes expected.
|
| + int offset;
|
| + if (!found_final_byte_offset && name == kFinalOffsetHeaderKey &&
|
| + base::StringToInt(p.second, &offset)) {
|
| + *final_byte_offset = offset;
|
| + found_final_byte_offset = true;
|
| + continue;
|
| + }
|
| +
|
| if (name.empty() || name[0] == ':') {
|
| DVLOG(1) << "Trailers must not be empty, and must not contain pseudo-"
|
| << "headers. Found: '" << name << "'";
|
| @@ -133,20 +199,10 @@ bool SpdyUtils::CopyAndValidateTrailers(const QuicHeaderList& header_list,
|
| (*trailers)[name] = p.second;
|
| }
|
|
|
| - if (trailers->empty()) {
|
| - DVLOG(1) << "Request Trailers are invalid.";
|
| - return false; // Trailers were invalid.
|
| - }
|
| -
|
| - // Pull out the final offset pseudo header which indicates the number of
|
| - // response body bytes expected.
|
| - auto it = trailers->find(kFinalOffsetHeaderKey);
|
| - if (it == trailers->end() || !StringToSizeT(it->second, final_byte_offset)) {
|
| + if (!found_final_byte_offset) {
|
| DVLOG(1) << "Required key '" << kFinalOffsetHeaderKey << "' not present";
|
| return false;
|
| }
|
| - // The final offset header is no longer needed.
|
| - trailers->erase(it->first);
|
|
|
| // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec.
|
|
|
|
|