| Index: net/tools/quic/spdy_balsa_utils.cc
|
| diff --git a/net/tools/quic/spdy_balsa_utils.cc b/net/tools/quic/spdy_balsa_utils.cc
|
| index 3f0bbc60322d259d1585bf0a2d949a177113571d..701ed7fc99cd48cbad2cd1f8c3da0896550f3a26 100644
|
| --- a/net/tools/quic/spdy_balsa_utils.cc
|
| +++ b/net/tools/quic/spdy_balsa_utils.cc
|
| @@ -10,6 +10,7 @@
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_piece.h"
|
| #include "base/strings/string_util.h"
|
| +#include "net/base/linked_hash_map.h"
|
| #include "net/quic/quic_flags.h"
|
| #include "net/quic/spdy_utils.h"
|
| #include "net/spdy/spdy_frame_builder.h"
|
| @@ -39,6 +40,11 @@ const char kV3Version[] = ":version";
|
| void PopulateSpdyHeaderBlock(const BalsaHeaders& headers,
|
| SpdyHeaderBlock* block,
|
| bool allow_empty_values) {
|
| + typedef linked_hash_map<StringPiece, std::vector<StringPiece>>
|
| + HeaderValuesMap;
|
| + std::deque<string> names;
|
| + HeaderValuesMap header_values_map;
|
| + // First, gather references to all values for each name.
|
| for (BalsaHeaders::const_header_lines_iterator hi =
|
| headers.header_lines_begin();
|
| hi != headers.header_lines_end(); ++hi) {
|
| @@ -47,17 +53,25 @@ void PopulateSpdyHeaderBlock(const BalsaHeaders& headers,
|
| << " from headers";
|
| continue;
|
| }
|
| -
|
| - // This unfortunately involves loads of copying, but its the simplest way
|
| - // to sort the headers and leverage the framer.
|
| - string name = base::ToLowerASCII(hi->first.as_string());
|
| - SpdyHeaderBlock::iterator it = block->find(name);
|
| - if (it != block->end()) {
|
| - it->second.reserve(it->second.size() + 1 + hi->second.size());
|
| - it->second.append("\0", 1);
|
| - it->second.append(hi->second.data(), hi->second.size());
|
| + const string name = base::ToLowerASCII(hi->first.as_string());
|
| + names.push_back(name);
|
| + header_values_map[name].push_back(hi->second);
|
| + }
|
| + // Then, write joined representations to the header block.
|
| + for (const auto& header : header_values_map) {
|
| + if (header.second.size() == 1) {
|
| + // Avoid string allocation for the single value case.
|
| + block->ReplaceOrAppendHeader(header.first, header.second[0]);
|
| } else {
|
| - block->insert(make_pair(name, hi->second.as_string()));
|
| + StringPiece separator("\0", 1);
|
| + auto it = header.second.begin();
|
| + string value = it->as_string();
|
| + ++it;
|
| + for (; it != header.second.end(); ++it) {
|
| + separator.AppendToString(&value);
|
| + value.append(it->data(), it->size());
|
| + }
|
| + block->ReplaceOrAppendHeader(header.first, value);
|
| }
|
| }
|
| }
|
| @@ -71,7 +85,7 @@ void PopulateSpdy3RequestHeaderBlock(const BalsaHeaders& headers,
|
| StringPiece host_header = headers.GetHeader("Host");
|
| if (!host_header.empty()) {
|
| DCHECK(host_and_port.empty() || host_header == host_and_port);
|
| - block->insert(make_pair(kV3Host, host_header.as_string()));
|
| + block->insert(make_pair(kV3Host, host_header));
|
| } else {
|
| block->insert(make_pair(kV3Host, host_and_port));
|
| }
|
| @@ -79,11 +93,11 @@ void PopulateSpdy3RequestHeaderBlock(const BalsaHeaders& headers,
|
| block->insert(make_pair(kV3Scheme, scheme));
|
|
|
| if (!headers.request_method().empty()) {
|
| - block->insert(make_pair(kV3Method, headers.request_method().as_string()));
|
| + block->insert(make_pair(kV3Method, headers.request_method()));
|
| }
|
|
|
| if (!headers.request_version().empty()) {
|
| - (*block)[kV3Version] = headers.request_version().as_string();
|
| + (*block)[kV3Version] = headers.request_version();
|
| }
|
| }
|
|
|
| @@ -96,7 +110,7 @@ void PopulateSpdy4RequestHeaderBlock(const BalsaHeaders& headers,
|
| StringPiece host_header = headers.GetHeader("Host");
|
| if (!host_header.empty()) {
|
| DCHECK(host_and_port.empty() || host_header == host_and_port);
|
| - block->insert(make_pair(kV4Host, host_header.as_string()));
|
| + block->insert(make_pair(kV4Host, host_header));
|
| // PopulateSpdyHeaderBlock already added the "host" header,
|
| // which is invalid for SPDY4.
|
| block->erase("host");
|
| @@ -107,7 +121,7 @@ void PopulateSpdy4RequestHeaderBlock(const BalsaHeaders& headers,
|
| block->insert(make_pair(kV3Scheme, scheme));
|
|
|
| if (!headers.request_method().empty()) {
|
| - block->insert(make_pair(kV3Method, headers.request_method().as_string()));
|
| + block->insert(make_pair(kV3Method, headers.request_method()));
|
| }
|
| }
|
|
|
| @@ -119,9 +133,9 @@ void PopulateSpdyResponseHeaderBlock(SpdyMajorVersion version,
|
| status.append(" ");
|
| status.append(headers.response_reason_phrase().as_string());
|
| (*block)[kV3Status] = status;
|
| - (*block)[kV3Version] = headers.response_version().as_string();
|
| + (*block)[kV3Version] = headers.response_version();
|
| } else {
|
| - (*block)[kV3Status] = headers.response_code().as_string();
|
| + (*block)[kV3Status] = headers.response_code();
|
| }
|
|
|
| PopulateSpdyHeaderBlock(headers, block, true);
|
| @@ -129,11 +143,8 @@ void PopulateSpdyResponseHeaderBlock(SpdyMajorVersion version,
|
|
|
| bool IsSpecialSpdyHeader(SpdyHeaderBlock::const_iterator header,
|
| BalsaHeaders* headers) {
|
| - if (header->first.empty() || header->second.empty()) {
|
| - return true;
|
| - }
|
| - const string& header_name = header->first;
|
| - return header_name.c_str()[0] == ':';
|
| + return header->first.empty() || header->second.empty() ||
|
| + header->first[0] == ':';
|
| }
|
|
|
| // The reason phrase should match regexp [\d\d\d [^\r\n]+]. If not, we will
|
| @@ -224,13 +235,13 @@ void SpdyHeadersToRequestHeaders(const SpdyHeaderBlock& header_block,
|
| if (method_it == end_it) {
|
| method = "GET";
|
| } else {
|
| - method = method_it->second;
|
| + method = method_it->second.as_string();
|
| }
|
| string uri;
|
| if (path_it == end_it) {
|
| uri = "/";
|
| } else {
|
| - uri = path_it->second;
|
| + uri = path_it->second.as_string();
|
| }
|
| request_headers->SetRequestFirstlineFromStringPieces(
|
| method, uri, net::kHttp2VersionString);
|
|
|