diff options
Diffstat (limited to 'net/http')
-rw-r--r-- | net/http/http_network_transaction.cc | 69 | ||||
-rw-r--r-- | net/http/http_network_transaction.h | 37 | ||||
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 24 |
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()); |