summaryrefslogtreecommitdiffstats
path: root/net/http
diff options
context:
space:
mode:
Diffstat (limited to 'net/http')
-rw-r--r--net/http/http_network_transaction.cc69
-rw-r--r--net/http/http_network_transaction.h37
-rw-r--r--net/http/http_network_transaction_unittest.cc24
3 files changed, 87 insertions, 43 deletions
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index f4fefcc4..e059d97 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -31,6 +31,10 @@ using base::Time;
namespace net {
+void HttpNetworkTransaction::ResponseHeaders::Realloc(size_t new_size) {
+ headers_.reset(static_cast<char*>(realloc(headers_.release(), new_size)));
+}
+
namespace {
void BuildRequestHeaders(const HttpRequestInfo* request_info,
@@ -142,7 +146,9 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session,
using_tunnel_(false),
establishing_tunnel_(false),
reading_body_from_socket_(false),
+ request_headers_(new RequestHeaders()),
request_headers_bytes_sent_(0),
+ header_buf_(new ResponseHeaders()),
header_buf_capacity_(0),
header_buf_len_(0),
header_buf_body_offset_(-1),
@@ -671,7 +677,7 @@ int HttpNetworkTransaction::DoWriteHeaders() {
// This is constructed lazily (instead of within our Start method), so that
// we have proxy info available.
- if (request_headers_.empty()) {
+ if (request_headers_->headers_.empty()) {
// Figure out if we can/should add Proxy-Authentication & Authentication
// headers.
bool have_proxy_auth =
@@ -693,15 +699,14 @@ int HttpNetworkTransaction::DoWriteHeaders() {
BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
if (establishing_tunnel_) {
- BuildTunnelRequest(request_, authorization_headers, &request_headers_);
+ BuildTunnelRequest(request_, authorization_headers,
+ &request_headers_->headers_);
} else {
if (request_->upload_data)
request_body_stream_.reset(new UploadDataStream(request_->upload_data));
- BuildRequestHeaders(request_,
- authorization_headers,
- request_body_stream_.get(),
- using_proxy_,
- &request_headers_);
+ BuildRequestHeaders(request_, authorization_headers,
+ request_body_stream_.get(), using_proxy_,
+ &request_headers_->headers_);
}
}
@@ -711,12 +716,12 @@ int HttpNetworkTransaction::DoWriteHeaders() {
response_.request_time = Time::Now();
}
- const char* buf = request_headers_.data() + request_headers_bytes_sent_;
- int buf_len = static_cast<int>(request_headers_.size() -
+ request_headers_->SetDataOffset(request_headers_bytes_sent_);
+ int buf_len = static_cast<int>(request_headers_->headers_.size() -
request_headers_bytes_sent_);
DCHECK_GT(buf_len, 0);
- return connection_.socket()->Write(buf, buf_len, &io_callback_);
+ return connection_.socket()->Write(request_headers_, buf_len, &io_callback_);
}
int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
@@ -724,7 +729,7 @@ int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
return HandleIOError(result);
request_headers_bytes_sent_ += result;
- if (request_headers_bytes_sent_ < request_headers_.size()) {
+ if (request_headers_bytes_sent_ < request_headers_->headers_.size()) {
next_state_ = STATE_WRITE_HEADERS;
} else if (!establishing_tunnel_ && request_body_stream_.get() &&
request_body_stream_->size()) {
@@ -743,11 +748,17 @@ int HttpNetworkTransaction::DoWriteBody() {
const char* buf = request_body_stream_->buf();
int buf_len = static_cast<int>(request_body_stream_->buf_len());
+ DCHECK(!write_buffer_);
+ write_buffer_ = new IOBuffer(buf_len);
+ memcpy(write_buffer_->data(), buf, buf_len);
- return connection_.socket()->Write(buf, buf_len, &io_callback_);
+ return connection_.socket()->Write(write_buffer_, buf_len, &io_callback_);
}
int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
+ DCHECK(write_buffer_);
+ write_buffer_ = NULL;
+
if (result < 0)
return HandleIOError(result);
@@ -767,14 +778,13 @@ int HttpNetworkTransaction::DoReadHeaders() {
// Grow the read buffer if necessary.
if (header_buf_len_ == header_buf_capacity_) {
header_buf_capacity_ += kHeaderBufInitialSize;
- header_buf_.reset(static_cast<char*>(
- realloc(header_buf_.release(), header_buf_capacity_)));
+ header_buf_->Realloc(header_buf_capacity_);
}
- char* buf = header_buf_.get() + header_buf_len_;
int buf_len = header_buf_capacity_ - header_buf_len_;
+ header_buf_->set_data(header_buf_len_);
- return connection_.socket()->Read(buf, buf_len, &io_callback_);
+ return connection_.socket()->Read(header_buf_, buf_len, &io_callback_);
}
int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
@@ -837,12 +847,12 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
// Look for the start of the status line, if it hasn't been found yet.
if (!has_found_status_line_start()) {
header_buf_http_offset_ = HttpUtil::LocateStartOfStatusLine(
- header_buf_.get(), header_buf_len_);
+ header_buf_->headers(), header_buf_len_);
}
if (has_found_status_line_start()) {
int eoh = HttpUtil::LocateEndOfHeaders(
- header_buf_.get(), header_buf_len_, header_buf_http_offset_);
+ header_buf_->headers(), header_buf_len_, header_buf_http_offset_);
if (eoh == -1) {
// Prevent growing the headers buffer indefinitely.
if (header_buf_len_ >= kMaxHeaderBufSize)
@@ -881,12 +891,13 @@ int HttpNetworkTransaction::DoReadBody() {
return 0;
// We may have some data remaining in the header buffer.
- if (header_buf_.get() && header_buf_body_offset_ < header_buf_len_) {
+ if (header_buf_->headers() && header_buf_body_offset_ < header_buf_len_) {
int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
- memcpy(read_buf_->data(), header_buf_.get() + header_buf_body_offset_, n);
+ memcpy(read_buf_->data(), header_buf_->headers() + header_buf_body_offset_,
+ n);
header_buf_body_offset_ += n;
if (header_buf_body_offset_ == header_buf_len_) {
- header_buf_.reset();
+ header_buf_->Reset();
header_buf_capacity_ = 0;
header_buf_len_ = 0;
header_buf_body_offset_ = -1;
@@ -895,8 +906,7 @@ int HttpNetworkTransaction::DoReadBody() {
}
reading_body_from_socket_ = true;
- return connection_.socket()->Read(read_buf_->data(), read_buf_len_,
- &io_callback_);
+ return connection_.socket()->Read(read_buf_, read_buf_len_, &io_callback_);
}
int HttpNetworkTransaction::DoReadBodyComplete(int result) {
@@ -1120,7 +1130,7 @@ int HttpNetworkTransaction::DidReadResponseHeaders() {
if (has_found_status_line_start()) {
headers = new HttpResponseHeaders(
HttpUtil::AssembleRawHeaders(
- header_buf_.get(), header_buf_body_offset_));
+ header_buf_->headers(), header_buf_body_offset_));
} else {
// Fabricate a status line to to preserve the HTTP/0.9 version.
// (otherwise HttpResponseHeaders will default it to HTTP/1.0).
@@ -1148,7 +1158,7 @@ int HttpNetworkTransaction::DidReadResponseHeaders() {
}
next_state_ = STATE_SSL_CONNECT;
// Reset for the real request and response headers.
- request_headers_.clear();
+ request_headers_->headers_.clear();
request_headers_bytes_sent_ = 0;
header_buf_len_ = 0;
header_buf_body_offset_ = 0;
@@ -1188,7 +1198,8 @@ int HttpNetworkTransaction::DidReadResponseHeaders() {
// If we've already received some bytes after the 1xx response,
// move them to the beginning of header_buf_.
if (header_buf_len_) {
- memmove(header_buf_.get(), header_buf_.get() + header_buf_body_offset_,
+ memmove(header_buf_->headers(),
+ header_buf_->headers() + header_buf_body_offset_,
header_buf_len_);
}
header_buf_body_offset_ = -1;
@@ -1329,7 +1340,7 @@ int HttpNetworkTransaction::HandleIOError(int error) {
void HttpNetworkTransaction::ResetStateForRestart() {
pending_auth_target_ = HttpAuth::AUTH_NONE;
- header_buf_.reset();
+ header_buf_->Reset();
header_buf_capacity_ = 0;
header_buf_len_ = 0;
header_buf_body_offset_ = -1;
@@ -1338,7 +1349,7 @@ void HttpNetworkTransaction::ResetStateForRestart() {
response_body_read_ = 0;
read_buf_ = NULL;
read_buf_len_ = 0;
- request_headers_.clear();
+ request_headers_->headers_.clear();
request_headers_bytes_sent_ = 0;
chunked_decoder_.reset();
// Reset all the members of response_.
@@ -1365,7 +1376,7 @@ void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
// first to recreate the SSL tunnel. 2) An empty request_headers_ causes
// BuildRequestHeaders to be called, which rewinds request_body_stream_ to
// the beginning of request_->upload_data.
- request_headers_.clear();
+ request_headers_->headers_.clear();
request_headers_bytes_sent_ = 0;
next_state_ = STATE_INIT_CONNECTION; // Resend the request.
}
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index d3a6f49..9ba9cc0 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -55,6 +55,38 @@ class HttpNetworkTransaction : public HttpTransaction {
private:
FRIEND_TEST(HttpNetworkTransactionTest, ResetStateForRestart);
+ // This version of IOBuffer lets us use a string as the real storage and
+ // "move" the data pointer inside the string before using it to do actual IO.
+ class RequestHeaders : public net::IOBuffer {
+ public:
+ RequestHeaders() : net::IOBuffer() {}
+ ~RequestHeaders() { data_ = NULL; }
+
+ void SetDataOffset(size_t offset) {
+ data_ = const_cast<char*>(headers_.data()) + offset;
+ }
+
+ // This is intentionally a public member.
+ std::string headers_;
+ };
+
+ // This version of IOBuffer lets us use a malloc'ed buffer as the real storage
+ // and "move" the data pointer inside the buffer before using it to do actual
+ // IO.
+ class ResponseHeaders : public net::IOBuffer {
+ public:
+ ResponseHeaders() : net::IOBuffer() {}
+ ~ResponseHeaders() { data_ = NULL; }
+
+ void set_data(size_t offset) { data_ = headers_.get() + offset; }
+ char* headers() { return headers_.get(); }
+ void Reset() { headers_.reset(); }
+ void Realloc(size_t new_size);
+
+ private:
+ scoped_ptr_malloc<char> headers_;
+ };
+
void DoCallback(int result);
void OnIOComplete(int result);
@@ -276,15 +308,16 @@ class HttpNetworkTransaction : public HttpTransaction {
SSLConfig ssl_config_;
- std::string request_headers_;
+ scoped_refptr<RequestHeaders> request_headers_;
size_t request_headers_bytes_sent_;
scoped_ptr<UploadDataStream> request_body_stream_;
+ scoped_refptr<IOBuffer> write_buffer_;
// The read buffer may be larger than it is full. The 'capacity' indicates
// the allocation size of the buffer, and the 'len' indicates how much data
// is in the buffer already. The 'body offset' indicates the offset of the
// start of the response body within the read buffer.
- scoped_ptr_malloc<char> header_buf_;
+ scoped_refptr<ResponseHeaders> header_buf_;
int header_buf_capacity_;
int header_buf_len_;
int header_buf_body_offset_;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index f6c3fa2..514ee38 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -118,9 +118,9 @@ class MockClientSocket : public SSLClientSocket {
return connected_;
}
// Socket methods:
- virtual int Read(char* buf, int buf_len,
+ virtual int Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) = 0;
- virtual int Write(const char* buf, int buf_len,
+ virtual int Write(IOBuffer* buf, int buf_len,
CompletionCallback* callback) = 0;
#if defined(OS_LINUX)
@@ -175,14 +175,14 @@ class MockTCPClientSocket : public MockClientSocket {
}
// Socket methods:
- virtual int Read(char* buf, int buf_len, CompletionCallback* callback) {
+ virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) {
DCHECK(!callback_);
MockRead& r = data_->reads[read_index_];
int result = r.result;
if (r.data) {
if (r.data_len - read_offset_ > 0) {
result = std::min(buf_len, r.data_len - read_offset_);
- memcpy(buf, r.data + read_offset_, result);
+ memcpy(buf->data(), r.data + read_offset_, result);
read_offset_ += result;
if (read_offset_ == r.data_len) {
read_index_++;
@@ -199,7 +199,7 @@ class MockTCPClientSocket : public MockClientSocket {
return result;
}
- virtual int Write(const char* buf, int buf_len,
+ virtual int Write(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(buf);
DCHECK(buf_len > 0);
@@ -214,7 +214,7 @@ class MockTCPClientSocket : public MockClientSocket {
int result = w.result;
if (w.data) {
std::string expected_data(w.data, w.data_len);
- std::string actual_data(buf, buf_len);
+ std::string actual_data(buf->data(), buf_len);
EXPECT_EQ(expected_data, actual_data);
if (expected_data != actual_data)
return ERR_UNEXPECTED;
@@ -307,12 +307,12 @@ class MockSSLClientSocket : public MockClientSocket {
}
// Socket methods:
- virtual int Read(char* buf, int buf_len, CompletionCallback* callback) {
+ virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) {
DCHECK(!callback_);
return transport_->Read(buf, buf_len, callback);
}
- virtual int Write(const char* buf, int buf_len,
+ virtual int Write(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(!callback_);
return transport_->Write(buf, buf_len, callback);
@@ -2912,7 +2912,7 @@ TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
CreateSession(proxy_service.get()), &mock_socket_factory));
// Setup some state (which we expect ResetStateForRestart() will clear).
- trans->header_buf_.reset(static_cast<char*>(malloc(10)));
+ trans->header_buf_->Realloc(10);
trans->header_buf_capacity_ = 10;
trans->header_buf_len_ = 3;
trans->header_buf_body_offset_ = 11;
@@ -2921,7 +2921,7 @@ TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
trans->response_body_read_ = 1;
trans->read_buf_ = new IOBuffer(15);
trans->read_buf_len_ = 15;
- trans->request_headers_ = "Authorization: NTLM";
+ trans->request_headers_->headers_ = "Authorization: NTLM";
trans->request_headers_bytes_sent_ = 3;
// Setup state in response_
@@ -2943,7 +2943,7 @@ TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
trans->ResetStateForRestart();
// Verify that the state that needed to be reset, has been reset.
- EXPECT_EQ(NULL, trans->header_buf_.get());
+ EXPECT_EQ(NULL, trans->header_buf_->headers());
EXPECT_EQ(0, trans->header_buf_capacity_);
EXPECT_EQ(0, trans->header_buf_len_);
EXPECT_EQ(-1, trans->header_buf_body_offset_);
@@ -2952,7 +2952,7 @@ TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
EXPECT_EQ(0, trans->response_body_read_);
EXPECT_EQ(NULL, trans->read_buf_.get());
EXPECT_EQ(0, trans->read_buf_len_);
- EXPECT_EQ("", trans->request_headers_);
+ EXPECT_EQ("", trans->request_headers_->headers_);
EXPECT_EQ(0U, trans->request_headers_bytes_sent_);
EXPECT_EQ(NULL, trans->response_.auth_challenge.get());
EXPECT_EQ(NULL, trans->response_.headers.get());