summaryrefslogtreecommitdiffstats
path: root/net/http/http_stream_parser.cc
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-19 15:38:47 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-19 15:38:47 +0000
commit84d1da6ea1f246f388d6aa7ae6ffd7f67ddcf7dc (patch)
tree3b6d87cd82997763202563093ca03803ea6d4524 /net/http/http_stream_parser.cc
parent1f98841d1589b4ff53d1a1a307e3da8a61616d36 (diff)
downloadchromium_src-84d1da6ea1f246f388d6aa7ae6ffd7f67ddcf7dc.zip
chromium_src-84d1da6ea1f246f388d6aa7ae6ffd7f67ddcf7dc.tar.gz
chromium_src-84d1da6ea1f246f388d6aa7ae6ffd7f67ddcf7dc.tar.bz2
net: merge HTTP headers and body when the sum is small enough.
(This is a reland of r118099 which was reverted in r118149 because it changed intermediate XMLHttpRequest events - breaking layout tests. We not don't free the request_body_ so that we continue to generate the same intermediate events.) When sending a small POST message we currently do two writes: one for the headers and one for the body. With 1/n-1 record splitting, this results in four TLS records when the connection uses CBC. Plesk correctly handles record splitting in HTTP headers, but incorrectly assumes that the entire POST body is in a single TLS record. Thus record splitting causes Chrome to be unable to log into Plesk (or perform any other action that requires a POST.) IE and Firefox 10 also do record splitting, but they merge the headers and body so there's only a single split after the first byte of the headers and Plesk can handle this. Our histogram data suggests that ~4% of requests can be merged in the fashion of this patch, so it seems independently worthwhile to do this. BUG=107966 TEST=none Review URL: http://codereview.chromium.org/9133007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@118298 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http/http_stream_parser.cc')
-rw-r--r--net/http/http_stream_parser.cc82
1 files changed, 46 insertions, 36 deletions
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc
index bd9bda1..dcde04f 100644
--- a/net/http/http_stream_parser.cc
+++ b/net/http/http_stream_parser.cc
@@ -22,6 +22,8 @@
namespace {
+static const size_t kMaxMergedHeaderAndBodySize = 1400;
+
std::string GetResponseHeaderLines(const net::HttpResponseHeaders& headers) {
std::string raw_headers = headers.raw_headers();
const char* null_separated_headers = raw_headers.c_str();
@@ -122,9 +124,6 @@ int HttpStreamParser::SendRequest(const std::string& request_line,
response_->socket_address = HostPortPair::FromAddrInfo(address.head());
std::string request = request_line + headers.ToString();
- scoped_refptr<StringIOBuffer> headers_io_buf(new StringIOBuffer(request));
- request_headers_ = new DrainableIOBuffer(headers_io_buf,
- headers_io_buf->size());
request_body_.reset(request_body);
if (request_body_ != NULL && request_body_->is_chunked()) {
request_body_->set_chunk_callback(this);
@@ -134,6 +133,48 @@ int HttpStreamParser::SendRequest(const std::string& request_line,
}
io_state_ = STATE_SENDING_HEADERS;
+
+ // If we have a small request body, then we'll merge with the headers into a
+ // single write.
+ bool did_merge = false;
+ if (request_body_ != NULL &&
+ !request_body_->is_chunked() &&
+ request_body_->size() > 0) {
+ size_t merged_size = request.size() + request_body_->size();
+ if (merged_size <= kMaxMergedHeaderAndBodySize) {
+ scoped_refptr<IOBuffer> merged_request_headers_and_body(
+ new IOBuffer(merged_size));
+ // We'll repurpose |request_headers_| to store the merged headers and
+ // body.
+ request_headers_ = new DrainableIOBuffer(
+ merged_request_headers_and_body, merged_size);
+
+ char *buf = request_headers_->data();
+ memcpy(buf, request.data(), request.size());
+ buf += request.size();
+
+ size_t todo = request_body_->size();
+ while (todo) {
+ size_t buf_len = request_body_->buf_len();
+ memcpy(buf, request_body_->buf()->data(), buf_len);
+ todo -= buf_len;
+ buf += buf_len;
+ request_body_->MarkConsumedAndFillBuffer(buf_len);
+ }
+ DCHECK(request_body_->eof());
+
+ did_merge = true;
+ }
+ }
+
+ if (!did_merge) {
+ // If we didn't merge the body with the headers, then |request_headers_|
+ // contains just the HTTP headers.
+ scoped_refptr<StringIOBuffer> headers_io_buf(new StringIOBuffer(request));
+ request_headers_ = new DrainableIOBuffer(headers_io_buf,
+ headers_io_buf->size());
+ }
+
result = DoLoop(OK);
if (result == ERR_IO_PENDING)
callback_ = callback;
@@ -280,44 +321,13 @@ int HttpStreamParser::DoSendHeaders(int result) {
// out the first bytes of the request headers.
if (bytes_remaining == request_headers_->size()) {
response_->request_time = base::Time::Now();
-
- // We'll record the count of uncoalesced packets IFF coalescing will help,
- // and otherwise we'll use an enum to tell why it won't help.
- enum COALESCE_POTENTIAL {
- // Coalescing won't reduce packet count.
- NO_ADVANTAGE = 0,
- // There is only a header packet or we have a request body but the
- // request body isn't available yet (can't coalesce).
- HEADER_ONLY = 1,
- // Various cases of coalasced savings.
- COALESCE_POTENTIAL_MAX = 30
- };
- size_t coalesce = HEADER_ONLY;
- if (request_body_ != NULL && !request_body_->is_chunked()) {
- const size_t kBytesPerPacket = 1430;
- uint64 body_packets = (request_body_->size() + kBytesPerPacket - 1) /
- kBytesPerPacket;
- uint64 header_packets = (bytes_remaining + kBytesPerPacket - 1) /
- kBytesPerPacket;
- uint64 coalesced_packets = (request_body_->size() + bytes_remaining +
- kBytesPerPacket - 1) / kBytesPerPacket;
- if (coalesced_packets < header_packets + body_packets) {
- if (coalesced_packets > COALESCE_POTENTIAL_MAX)
- coalesce = COALESCE_POTENTIAL_MAX;
- else
- coalesce = static_cast<size_t>(header_packets + body_packets);
- } else {
- coalesce = NO_ADVANTAGE;
- }
- }
- UMA_HISTOGRAM_ENUMERATION("Net.CoalescePotential", coalesce,
- COALESCE_POTENTIAL_MAX);
}
result = connection_->socket()->Write(request_headers_,
bytes_remaining,
io_callback_);
} else if (request_body_ != NULL &&
- (request_body_->is_chunked() || request_body_->size())) {
+ (request_body_->is_chunked() ||
+ (request_body_->size() && !request_body_->eof()))) {
io_state_ = STATE_SENDING_BODY;
result = OK;
} else {