summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-30 21:51:25 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-30 21:51:25 +0000
commitffeb088e92325536ac1c371df3c4bd857ccb1221 (patch)
treeaf34055a796ac8181e3d90b838a02fcaf960ce26 /net
parentb57d5cc9dd98fc4fb284878ecc73e2eb95f6d1bd (diff)
downloadchromium_src-ffeb088e92325536ac1c371df3c4bd857ccb1221.zip
chromium_src-ffeb088e92325536ac1c371df3c4bd857ccb1221.tar.gz
chromium_src-ffeb088e92325536ac1c371df3c4bd857ccb1221.tar.bz2
Extend the use of IOBuffers to the code underneath
HttpNetworkTransaction (to the Socket class). This is the first step to remove the blocking call on the destructor of the network transaction, from IO thread. BUG=9258 R=wtc Review URL: http://codereview.chromium.org/87073 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14998 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/client_socket_pool_unittest.cc4
-rw-r--r--net/base/socket.h15
-rw-r--r--net/base/ssl_client_socket_mac.cc48
-rw-r--r--net/base/ssl_client_socket_mac.h10
-rw-r--r--net/base/ssl_client_socket_nss.cc47
-rw-r--r--net/base/ssl_client_socket_nss.h7
-rw-r--r--net/base/ssl_client_socket_unittest.cc30
-rw-r--r--net/base/ssl_client_socket_win.cc77
-rw-r--r--net/base/ssl_client_socket_win.h9
-rw-r--r--net/base/tcp_client_socket_libevent.cc12
-rw-r--r--net/base/tcp_client_socket_libevent.h8
-rw-r--r--net/base/tcp_client_socket_unittest.cc58
-rw-r--r--net/base/tcp_client_socket_win.cc18
-rw-r--r--net/base/tcp_client_socket_win.h6
-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
17 files changed, 331 insertions, 148 deletions
diff --git a/net/base/client_socket_pool_unittest.cc b/net/base/client_socket_pool_unittest.cc
index dd51819..a889d9a 100644
--- a/net/base/client_socket_pool_unittest.cc
+++ b/net/base/client_socket_pool_unittest.cc
@@ -43,11 +43,11 @@ class MockClientSocket : public net::ClientSocket {
}
// Socket methods:
- virtual int Read(char* buf, int buf_len,
+ virtual int Read(net::IOBuffer* buf, int buf_len,
net::CompletionCallback* callback) {
return net::ERR_FAILED;
}
- virtual int Write(const char* buf, int buf_len,
+ virtual int Write(net::IOBuffer* buf, int buf_len,
net::CompletionCallback* callback) {
return net::ERR_FAILED;
}
diff --git a/net/base/socket.h b/net/base/socket.h
index c8db6d1..843104b 100644
--- a/net/base/socket.h
+++ b/net/base/socket.h
@@ -6,6 +6,7 @@
#define NET_BASE_SOCKET_H_
#include "net/base/completion_callback.h"
+#include "net/base/io_buffer.h"
namespace net {
@@ -18,16 +19,22 @@ class Socket {
// read is returned, or an error is returned upon failure. Zero is returned
// to indicate end-of-file. ERR_IO_PENDING is returned if the operation
// could not be completed synchronously, in which case the result will be
- // passed to the callback when available.
- virtual int Read(char* buf, int buf_len,
+ // passed to the callback when available. If the operation is not completed
+ // immediately, the socket acquires a reference to the provided buffer until
+ // the callback is invoked or the socket is destroyed.
+ virtual int Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) = 0;
// Writes data, up to buf_len bytes, to the socket. Note: only part of the
// data may be written! The number of bytes written is returned, or an error
// is returned upon failure. ERR_IO_PENDING is returned if the operation
// could not be completed synchronously, in which case the result will be
- // passed to the callback when available.
- virtual int Write(const char* buf, int buf_len,
+ // passed to the callback when available. If the operation is not completed
+ // immediately, the socket acquires a reference to the provided buffer until
+ // the callback is invoked or the socket is destroyed.
+ // Implementations of this method should not modify the contents of the actual
+ // buffer that is written to the socket.
+ virtual int Write(IOBuffer* buf, int buf_len,
CompletionCallback* callback) = 0;
};
diff --git a/net/base/ssl_client_socket_mac.cc b/net/base/ssl_client_socket_mac.cc
index 9c40ad4..298a1a7 100644
--- a/net/base/ssl_client_socket_mac.cc
+++ b/net/base/ssl_client_socket_mac.cc
@@ -349,35 +349,43 @@ bool SSLClientSocketMac::IsConnectedAndIdle() const {
return completed_handshake_ && transport_->IsConnectedAndIdle();
}
-int SSLClientSocketMac::Read(char* buf, int buf_len,
+int SSLClientSocketMac::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake_);
DCHECK(next_state_ == STATE_NONE);
DCHECK(!user_callback_);
+ DCHECK(!user_buf_);
user_buf_ = buf;
user_buf_len_ = buf_len;
next_state_ = STATE_PAYLOAD_READ;
int rv = DoLoop(OK);
- if (rv == ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING) {
user_callback_ = callback;
+ } else {
+ user_buf_ = NULL;
+ }
return rv;
}
-int SSLClientSocketMac::Write(const char* buf, int buf_len,
+int SSLClientSocketMac::Write(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake_);
DCHECK(next_state_ == STATE_NONE);
DCHECK(!user_callback_);
+ DCHECK(!user_buf_);
- user_buf_ = const_cast<char*>(buf);
+ user_buf_ = buf;
user_buf_len_ = buf_len;
next_state_ = STATE_PAYLOAD_WRITE;
int rv = DoLoop(OK);
- if (rv == ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING) {
user_callback_ = callback;
+ } else {
+ user_buf_ = NULL;
+ }
return rv;
}
@@ -419,6 +427,7 @@ void SSLClientSocketMac::DoCallback(int rv) {
// since Run may result in Read being called, clear user_callback_ up front.
CompletionCallback* c = user_callback_;
user_callback_ = NULL;
+ user_buf_ = NULL;
c->Run(rv);
}
@@ -498,8 +507,14 @@ int SSLClientSocketMac::DoHandshake() {
}
int SSLClientSocketMac::DoReadComplete(int result) {
- if (result < 0)
+ if (result < 0) {
+ read_io_buf_ = NULL;
return result;
+ }
+
+ char* buffer = &recv_buffer_[recv_buffer_.size() - recv_buffer_tail_slop_];
+ memcpy(buffer, read_io_buf_->data(), result);
+ read_io_buf_ = NULL;
recv_buffer_tail_slop_ -= result;
@@ -522,7 +537,7 @@ void SSLClientSocketMac::OnWriteComplete(int result) {
int SSLClientSocketMac::DoPayloadRead() {
size_t processed;
OSStatus status = SSLRead(ssl_context_,
- user_buf_,
+ user_buf_->data(),
user_buf_len_,
&processed);
@@ -547,7 +562,7 @@ int SSLClientSocketMac::DoPayloadRead() {
int SSLClientSocketMac::DoPayloadWrite() {
size_t processed;
OSStatus status = SSLWrite(ssl_context_,
- user_buf_,
+ user_buf_->data(),
user_buf_len_,
&processed);
@@ -660,12 +675,15 @@ OSStatus SSLClientSocketMac::SSLReadCallback(SSLConnectionRef connection,
int rv = 1; // any old value to spin the loop below
while (rv > 0 && total_read < *data_length) {
- rv = us->transport_->Read(&us->recv_buffer_[us->recv_buffer_head_slop_ +
- total_read],
- us->recv_buffer_tail_slop_,
+ char* buffer = &us->recv_buffer_[us->recv_buffer_head_slop_ + total_read];
+ us->read_io_buf_ = new IOBuffer(*data_length - total_read);
+ rv = us->transport_->Read(us->read_io_buf_,
+ *data_length - total_read,
&us->io_callback_);
- if (rv > 0) {
+ if (rv >= 0) {
+ memcpy(buffer, us->read_io_buf_->data(), rv);
+ us->read_io_buf_ = NULL;
total_read += rv;
us->recv_buffer_tail_slop_ -= rv;
}
@@ -689,6 +707,8 @@ OSStatus SSLClientSocketMac::SSLReadCallback(SSLConnectionRef connection,
if (rv == ERR_IO_PENDING) {
us->next_io_state_ = STATE_READ_COMPLETE;
+ } else {
+ us->read_io_buf_ = NULL;
}
if (rv < 0)
@@ -717,7 +737,9 @@ OSStatus SSLClientSocketMac::SSLWriteCallback(SSLConnectionRef connection,
static_cast<const char*>(data) + *data_length);
int rv;
do {
- rv = us->transport_->Write(&us->send_buffer_[0],
+ scoped_refptr<IOBuffer> buffer = new IOBuffer(us->send_buffer_.size());
+ memcpy(buffer->data(), &us->send_buffer_[0], us->send_buffer_.size());
+ rv = us->transport_->Write(buffer,
us->send_buffer_.size(),
&us->write_callback_);
if (rv > 0) {
diff --git a/net/base/ssl_client_socket_mac.h b/net/base/ssl_client_socket_mac.h
index 3396c2d..9d4dec0 100644
--- a/net/base/ssl_client_socket_mac.h
+++ b/net/base/ssl_client_socket_mac.h
@@ -39,8 +39,8 @@ class SSLClientSocketMac : public SSLClientSocket {
virtual bool IsConnectedAndIdle() const;
// Socket methods:
- virtual int Read(char* buf, int buf_len, CompletionCallback* callback);
- virtual int Write(const char* buf, int buf_len, CompletionCallback* callback);
+ virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
+ virtual int Write(IOBuffer* buf, int buf_len, CompletionCallback* callback);
private:
void DoCallback(int result);
@@ -70,7 +70,7 @@ class SSLClientSocketMac : public SSLClientSocket {
CompletionCallback* user_callback_;
// Used by both Read and Write functions.
- char* user_buf_;
+ scoped_refptr<IOBuffer> user_buf_;
int user_buf_len_;
enum State {
@@ -96,6 +96,10 @@ class SSLClientSocketMac : public SSLClientSocket {
std::vector<char> recv_buffer_;
int recv_buffer_head_slop_;
int recv_buffer_tail_slop_;
+
+ // This buffer holds data for Read() operations on the underlying transport
+ // (ClientSocket::Read()).
+ scoped_refptr<IOBuffer> read_io_buf_;
};
} // namespace net
diff --git a/net/base/ssl_client_socket_nss.cc b/net/base/ssl_client_socket_nss.cc
index 78cd3c0..7318b25 100644
--- a/net/base/ssl_client_socket_nss.cc
+++ b/net/base/ssl_client_socket_nss.cc
@@ -105,7 +105,6 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocket* transport_socket,
hostname_(hostname),
ssl_config_(ssl_config),
user_callback_(NULL),
- user_buf_(NULL),
user_buf_len_(0),
server_cert_error_(0),
completed_handshake_(false),
@@ -317,7 +316,7 @@ bool SSLClientSocketNSS::IsConnectedAndIdle() const {
return ret;
}
-int SSLClientSocketNSS::Read(char* buf, int buf_len,
+int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
EnterFunction(buf_len);
DCHECK(completed_handshake_);
@@ -336,7 +335,7 @@ int SSLClientSocketNSS::Read(char* buf, int buf_len,
return rv;
}
-int SSLClientSocketNSS::Write(const char* buf, int buf_len,
+int SSLClientSocketNSS::Write(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
EnterFunction(buf_len);
DCHECK(completed_handshake_);
@@ -344,7 +343,7 @@ int SSLClientSocketNSS::Write(const char* buf, int buf_len,
DCHECK(!user_callback_);
DCHECK(!user_buf_);
- user_buf_ = const_cast<char*>(buf);
+ user_buf_ = buf;
user_buf_len_ = buf_len;
GotoState(STATE_PAYLOAD_WRITE);
@@ -405,6 +404,7 @@ void SSLClientSocketNSS::DoCallback(int rv) {
// since Run may result in Read being called, clear user_callback_ up front.
CompletionCallback* c = user_callback_;
user_callback_ = NULL;
+ user_buf_ = NULL;
c->Run(rv);
LeaveFunction("");
}
@@ -428,12 +428,10 @@ static PRErrorCode MapErrorToNSS(int result) {
return PR_UNKNOWN_ERROR;
}
-/*
- * Do network I/O between the given buffer and the given socket.
- * Return 0 for EOF,
- * > 0 for bytes transferred immediately,
- * < 0 for error (or the non-error ERR_IO_PENDING).
- */
+// Do network I/O between the given buffer and the given socket.
+// Return 0 for EOF,
+// > 0 for bytes transferred immediately,
+// < 0 for error (or the non-error ERR_IO_PENDING).
int SSLClientSocketNSS::BufferSend(void) {
if (transport_send_busy_) return ERR_IO_PENDING;
@@ -445,7 +443,9 @@ int SSLClientSocketNSS::BufferSend(void) {
if (!nb) {
rv = OK;
} else {
- rv = transport_->Write(buf, nb, &buffer_send_callback_);
+ scoped_refptr<IOBuffer> send_buffer = new IOBuffer(nb);
+ memcpy(send_buffer->data(), buf, nb);
+ rv = transport_->Write(send_buffer, nb, &buffer_send_callback_);
if (rv == ERR_IO_PENDING)
transport_send_busy_ = true;
else
@@ -476,11 +476,16 @@ int SSLClientSocketNSS::BufferRecv(void) {
// buffer too full to read into, so no I/O possible at moment
rv = ERR_IO_PENDING;
} else {
- rv = transport_->Read(buf, nb, &buffer_recv_callback_);
- if (rv == ERR_IO_PENDING)
+ recv_buffer_ = new IOBuffer(nb);
+ rv = transport_->Read(recv_buffer_, nb, &buffer_recv_callback_);
+ if (rv == ERR_IO_PENDING) {
transport_recv_busy_ = true;
- else
+ } else {
+ if (rv > 0)
+ memcpy(buf, recv_buffer_->data(), rv);
memio_PutReadResult(nss_bufs_, MapErrorToNSS(rv));
+ recv_buffer_ = NULL;
+ }
}
LeaveFunction(rv);
return rv;
@@ -488,6 +493,12 @@ int SSLClientSocketNSS::BufferRecv(void) {
void SSLClientSocketNSS::BufferRecvComplete(int result) {
EnterFunction(result);
+ if (result > 0) {
+ char *buf;
+ memio_GetReadParams(nss_bufs_, &buf);
+ memcpy(buf, recv_buffer_->data(), result);
+ }
+ recv_buffer_ = NULL;
memio_PutReadResult(nss_bufs_, result);
transport_recv_busy_ = false;
OnIOComplete(result);
@@ -607,9 +618,9 @@ int SSLClientSocketNSS::DoHandshakeRead() {
int SSLClientSocketNSS::DoPayloadRead() {
EnterFunction(user_buf_len_);
- int rv = PR_Read(nss_fd_, user_buf_, user_buf_len_);
+ int rv = PR_Read(nss_fd_, user_buf_->data(), user_buf_len_);
if (rv >= 0) {
- LogData(user_buf_, rv);
+ LogData(user_buf_->data(), rv);
user_buf_ = NULL;
LeaveFunction("");
return rv;
@@ -627,9 +638,9 @@ int SSLClientSocketNSS::DoPayloadRead() {
int SSLClientSocketNSS::DoPayloadWrite() {
EnterFunction(user_buf_len_);
- int rv = PR_Write(nss_fd_, user_buf_, user_buf_len_);
+ int rv = PR_Write(nss_fd_, user_buf_->data(), user_buf_len_);
if (rv >= 0) {
- LogData(user_buf_, rv);
+ LogData(user_buf_->data(), rv);
user_buf_ = NULL;
LeaveFunction("");
return rv;
diff --git a/net/base/ssl_client_socket_nss.h b/net/base/ssl_client_socket_nss.h
index 49e7a31..9dfe5ab 100644
--- a/net/base/ssl_client_socket_nss.h
+++ b/net/base/ssl_client_socket_nss.h
@@ -41,8 +41,8 @@ class SSLClientSocketNSS : public SSLClientSocket {
virtual bool IsConnectedAndIdle() const;
// Socket methods:
- virtual int Read(char* buf, int buf_len, CompletionCallback* callback);
- virtual int Write(const char* buf, int buf_len, CompletionCallback* callback);
+ virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
+ virtual int Write(IOBuffer* buf, int buf_len, CompletionCallback* callback);
private:
void InvalidateSessionIfBadCertificate();
@@ -72,6 +72,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
CompletionCallbackImpl<SSLClientSocketNSS> buffer_recv_callback_;
bool transport_send_busy_;
bool transport_recv_busy_;
+ scoped_refptr<IOBuffer> recv_buffer_;
CompletionCallbackImpl<SSLClientSocketNSS> io_callback_;
scoped_ptr<ClientSocket> transport_;
@@ -81,7 +82,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
CompletionCallback* user_callback_;
// Used by both Read and Write functions.
- char* user_buf_;
+ scoped_refptr<IOBuffer> user_buf_;
int user_buf_len_;
// Set when handshake finishes. Value is net error code, see net_errors.h
diff --git a/net/base/ssl_client_socket_unittest.cc b/net/base/ssl_client_socket_unittest.cc
index 2399466..324f3b6 100644
--- a/net/base/ssl_client_socket_unittest.cc
+++ b/net/base/ssl_client_socket_unittest.cc
@@ -220,7 +220,11 @@ TEST_F(SSLClientSocketTest, MAYBE_Read) {
EXPECT_TRUE(sock->IsConnected());
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- rv = sock->Write(request_text, arraysize(request_text) - 1, &callback);
+ scoped_refptr<net::IOBuffer> request_buffer =
+ new net::IOBuffer(arraysize(request_text) - 1);
+ memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
+
+ rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING) {
@@ -228,9 +232,9 @@ TEST_F(SSLClientSocketTest, MAYBE_Read) {
EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
}
- char buf[4096];
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(4096);
for (;;) {
- rv = sock->Read(buf, sizeof(buf), &callback);
+ rv = sock->Read(buf, 4096, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING)
@@ -272,7 +276,11 @@ TEST_F(SSLClientSocketTest, MAYBE_Read_SmallChunks) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- rv = sock->Write(request_text, arraysize(request_text) - 1, &callback);
+ scoped_refptr<net::IOBuffer> request_buffer =
+ new net::IOBuffer(arraysize(request_text) - 1);
+ memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
+
+ rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING) {
@@ -280,9 +288,9 @@ TEST_F(SSLClientSocketTest, MAYBE_Read_SmallChunks) {
EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
}
- char buf[1];
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(1);
for (;;) {
- rv = sock->Read(buf, sizeof(buf), &callback);
+ rv = sock->Read(buf, 1, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING)
@@ -324,7 +332,11 @@ TEST_F(SSLClientSocketTest, MAYBE_Read_Interrupted) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- rv = sock->Write(request_text, arraysize(request_text) - 1, &callback);
+ scoped_refptr<net::IOBuffer> request_buffer =
+ new net::IOBuffer(arraysize(request_text) - 1);
+ memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
+
+ rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING) {
@@ -333,8 +345,8 @@ TEST_F(SSLClientSocketTest, MAYBE_Read_Interrupted) {
}
// Do a partial read and then exit. This test should not crash!
- char buf[512];
- rv = sock->Read(buf, sizeof(buf), &callback);
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(512);
+ rv = sock->Read(buf, 512, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING)
diff --git a/net/base/ssl_client_socket_win.cc b/net/base/ssl_client_socket_win.cc
index 373173d..19c94bc 100644
--- a/net/base/ssl_client_socket_win.cc
+++ b/net/base/ssl_client_socket_win.cc
@@ -212,7 +212,6 @@ SSLClientSocketWin::SSLClientSocketWin(ClientSocket* transport_socket,
hostname_(hostname),
ssl_config_(ssl_config),
user_callback_(NULL),
- user_buf_(NULL),
user_buf_len_(0),
next_state_(STATE_NONE),
creds_(NULL),
@@ -363,7 +362,7 @@ bool SSLClientSocketWin::IsConnectedAndIdle() const {
return completed_handshake_ && transport_->IsConnectedAndIdle();
}
-int SSLClientSocketWin::Read(char* buf, int buf_len,
+int SSLClientSocketWin::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake_);
DCHECK(next_state_ == STATE_NONE);
@@ -373,7 +372,7 @@ int SSLClientSocketWin::Read(char* buf, int buf_len,
// reading more ciphertext from the transport socket.
if (bytes_decrypted_ != 0) {
int len = std::min(buf_len, bytes_decrypted_);
- memcpy(buf, decrypted_ptr_, len);
+ memcpy(buf->data(), decrypted_ptr_, len);
decrypted_ptr_ += len;
bytes_decrypted_ -= len;
if (bytes_decrypted_ == 0) {
@@ -386,29 +385,37 @@ int SSLClientSocketWin::Read(char* buf, int buf_len,
return len;
}
+ DCHECK(!user_buf_);
user_buf_ = buf;
user_buf_len_ = buf_len;
SetNextStateForRead();
int rv = DoLoop(OK);
- if (rv == ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING) {
user_callback_ = callback;
+ } else {
+ user_buf_ = NULL;
+ }
return rv;
}
-int SSLClientSocketWin::Write(const char* buf, int buf_len,
+int SSLClientSocketWin::Write(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake_);
DCHECK(next_state_ == STATE_NONE);
DCHECK(!user_callback_);
- user_buf_ = const_cast<char*>(buf);
+ DCHECK(!user_buf_);
+ user_buf_ = buf;
user_buf_len_ = buf_len;
next_state_ = STATE_PAYLOAD_ENCRYPT;
int rv = DoLoop(OK);
- if (rv == ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING) {
user_callback_ = callback;
+ } else {
+ user_buf_ = NULL;
+ }
return rv;
}
@@ -419,6 +426,7 @@ void SSLClientSocketWin::DoCallback(int rv) {
// since Run may result in Read being called, clear user_callback_ up front.
CompletionCallback* c = user_callback_;
user_callback_ = NULL;
+ user_buf_ = NULL;
c->Run(rv);
}
@@ -483,7 +491,6 @@ int SSLClientSocketWin::DoHandshakeRead() {
if (!recv_buffer_.get())
recv_buffer_.reset(new char[kRecvBufferSize]);
- char* buf = recv_buffer_.get() + bytes_received_;
int buf_len = kRecvBufferSize - bytes_received_;
if (buf_len <= 0) {
@@ -491,12 +498,23 @@ int SSLClientSocketWin::DoHandshakeRead() {
return ERR_UNEXPECTED;
}
- return transport_->Read(buf, buf_len, &io_callback_);
+ DCHECK(!transport_buf_);
+ transport_buf_ = new IOBuffer(buf_len);
+
+ return transport_->Read(transport_buf_, buf_len, &io_callback_);
}
int SSLClientSocketWin::DoHandshakeReadComplete(int result) {
- if (result < 0)
+ DCHECK(transport_buf_);
+ if (result < 0) {
+ transport_buf_ = NULL;
return result;
+ }
+ DCHECK_LE(result, kRecvBufferSize - bytes_received_);
+ char* buf = recv_buffer_.get() + bytes_received_;
+ memcpy(buf, transport_buf_->data(), result);
+ transport_buf_ = NULL;
+
if (result == 0 && !ignore_ok_result_)
return ERR_SSL_PROTOCOL_ERROR; // Incomplete response :(
@@ -624,14 +642,19 @@ int SSLClientSocketWin::DoHandshakeWrite() {
// We should have something to send.
DCHECK(send_buffer_.pvBuffer);
DCHECK(send_buffer_.cbBuffer > 0);
+ DCHECK(!transport_buf_);
const char* buf = static_cast<char*>(send_buffer_.pvBuffer) + bytes_sent_;
int buf_len = send_buffer_.cbBuffer - bytes_sent_;
+ transport_buf_ = new IOBuffer(buf_len);
+ memcpy(transport_buf_->data(), buf, buf_len);
- return transport_->Write(buf, buf_len, &io_callback_);
+ return transport_->Write(transport_buf_, buf_len, &io_callback_);
}
int SSLClientSocketWin::DoHandshakeWriteComplete(int result) {
+ DCHECK(transport_buf_);
+ transport_buf_ = NULL;
if (result < 0)
return result;
@@ -703,7 +726,6 @@ int SSLClientSocketWin::DoPayloadRead() {
DCHECK(recv_buffer_.get());
- char* buf = recv_buffer_.get() + bytes_received_;
int buf_len = kRecvBufferSize - bytes_received_;
if (buf_len <= 0) {
@@ -711,12 +733,28 @@ int SSLClientSocketWin::DoPayloadRead() {
return ERR_FAILED;
}
- return transport_->Read(buf, buf_len, &io_callback_);
+ DCHECK(!transport_buf_);
+ transport_buf_ = new IOBuffer(buf_len);
+
+ return transport_->Read(transport_buf_, buf_len, &io_callback_);
}
int SSLClientSocketWin::DoPayloadReadComplete(int result) {
- if (result < 0)
+ if (result < 0) {
+ transport_buf_ = NULL;
return result;
+ }
+ if (transport_buf_) {
+ // This method is called after a state transition following DoPayloadRead(),
+ // or if SetNextStateForRead() was called. We have a transport_buf_ only
+ // in the first case, and we have to transfer the data from transport_buf_
+ // to recv_buffer_.
+ DCHECK_LE(result, kRecvBufferSize - bytes_received_);
+ char* buf = recv_buffer_.get() + bytes_received_;
+ memcpy(buf, transport_buf_->data(), result);
+ transport_buf_ = NULL;
+ }
+
if (result == 0 && !ignore_ok_result_) {
// TODO(wtc): Unless we have received the close_notify alert, we need to
// return an error code indicating that the SSL connection ended
@@ -785,7 +823,7 @@ int SSLClientSocketWin::DoPayloadReadComplete(int result) {
int len = 0;
if (bytes_decrypted_ != 0) {
len = std::min(user_buf_len_, bytes_decrypted_);
- memcpy(user_buf_, decrypted_ptr_, len);
+ memcpy(user_buf_->data(), decrypted_ptr_, len);
decrypted_ptr_ += len;
bytes_decrypted_ -= len;
}
@@ -845,7 +883,7 @@ int SSLClientSocketWin::DoPayloadEncrypt() {
payload_send_buffer_.reset(new char[alloc_len]);
memcpy(&payload_send_buffer_[stream_sizes_.cbHeader],
- user_buf_, message_len);
+ user_buf_->data(), message_len);
SecBuffer buffers[4];
buffers[0].pvBuffer = payload_send_buffer_.get();
@@ -888,14 +926,19 @@ int SSLClientSocketWin::DoPayloadWrite() {
// We should have something to send.
DCHECK(payload_send_buffer_.get());
DCHECK(payload_send_buffer_len_ > 0);
+ DCHECK(!transport_buf_);
const char* buf = payload_send_buffer_.get() + bytes_sent_;
int buf_len = payload_send_buffer_len_ - bytes_sent_;
+ transport_buf_ = new IOBuffer(buf_len);
+ memcpy(transport_buf_->data(), buf, buf_len);
- return transport_->Write(buf, buf_len, &io_callback_);
+ return transport_->Write(transport_buf_, buf_len, &io_callback_);
}
int SSLClientSocketWin::DoPayloadWriteComplete(int result) {
+ DCHECK(transport_buf_);
+ transport_buf_ = NULL;
if (result < 0)
return result;
diff --git a/net/base/ssl_client_socket_win.h b/net/base/ssl_client_socket_win.h
index 734fde8..9bdb5a1 100644
--- a/net/base/ssl_client_socket_win.h
+++ b/net/base/ssl_client_socket_win.h
@@ -44,8 +44,8 @@ class SSLClientSocketWin : public SSLClientSocket {
virtual bool IsConnectedAndIdle() const;
// Socket methods:
- virtual int Read(char* buf, int buf_len, CompletionCallback* callback);
- virtual int Write(const char* buf, int buf_len, CompletionCallback* callback);
+ virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
+ virtual int Write(IOBuffer* buf, int buf_len, CompletionCallback* callback);
private:
void DoCallback(int result);
@@ -78,9 +78,12 @@ class SSLClientSocketWin : public SSLClientSocket {
CompletionCallback* user_callback_;
// Used by both Read and Write functions.
- char* user_buf_;
+ scoped_refptr<IOBuffer> user_buf_;
int user_buf_len_;
+ // Used to Read and Write using transport_.
+ scoped_refptr<IOBuffer> transport_buf_;
+
enum State {
STATE_NONE,
STATE_HANDSHAKE_READ,
diff --git a/net/base/tcp_client_socket_libevent.cc b/net/base/tcp_client_socket_libevent.cc
index ab89501..f6672c4 100644
--- a/net/base/tcp_client_socket_libevent.cc
+++ b/net/base/tcp_client_socket_libevent.cc
@@ -172,7 +172,7 @@ bool TCPClientSocketLibevent::IsConnectedAndIdle() const {
return true;
}
-int TCPClientSocketLibevent::Read(char* buf,
+int TCPClientSocketLibevent::Read(IOBuffer* buf,
int buf_len,
CompletionCallback* callback) {
DCHECK_NE(kInvalidSocket, socket_);
@@ -183,7 +183,7 @@ int TCPClientSocketLibevent::Read(char* buf,
DCHECK_GT(buf_len, 0);
TRACE_EVENT_BEGIN("socket.read", this, "");
- int nread = read(socket_, buf, buf_len);
+ int nread = read(socket_, buf->data(), buf_len);
if (nread >= 0) {
TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", nread));
return nread;
@@ -206,7 +206,7 @@ int TCPClientSocketLibevent::Read(char* buf,
return ERR_IO_PENDING;
}
-int TCPClientSocketLibevent::Write(const char* buf,
+int TCPClientSocketLibevent::Write(IOBuffer* buf,
int buf_len,
CompletionCallback* callback) {
DCHECK_NE(kInvalidSocket, socket_);
@@ -217,7 +217,7 @@ int TCPClientSocketLibevent::Write(const char* buf,
DCHECK_GT(buf_len, 0);
TRACE_EVENT_BEGIN("socket.write", this, "");
- int nwrite = write(socket_, buf, buf_len);
+ int nwrite = write(socket_, buf->data(), buf_len);
if (nwrite >= 0) {
TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", nwrite));
return nwrite;
@@ -309,7 +309,7 @@ void TCPClientSocketLibevent::DidCompleteConnect() {
void TCPClientSocketLibevent::DidCompleteRead() {
int bytes_transferred;
- bytes_transferred = read(socket_, read_buf_, read_buf_len_);
+ bytes_transferred = read(socket_, read_buf_->data(), read_buf_len_);
int result;
if (bytes_transferred >= 0) {
@@ -330,7 +330,7 @@ void TCPClientSocketLibevent::DidCompleteRead() {
void TCPClientSocketLibevent::DidCompleteWrite() {
int bytes_transferred;
- bytes_transferred = write(socket_, write_buf_, write_buf_len_);
+ bytes_transferred = write(socket_, write_buf_->data(), write_buf_len_);
int result;
if (bytes_transferred >= 0) {
diff --git a/net/base/tcp_client_socket_libevent.h b/net/base/tcp_client_socket_libevent.h
index c933bfa..4b3dd45 100644
--- a/net/base/tcp_client_socket_libevent.h
+++ b/net/base/tcp_client_socket_libevent.h
@@ -36,8 +36,8 @@ class TCPClientSocketLibevent : public ClientSocket,
// Socket methods:
// Multiple outstanding requests are not supported.
// Full duplex mode (reading and writing at the same time) is supported
- virtual int Read(char* buf, int buf_len, CompletionCallback* callback);
- virtual int Write(const char* buf, int buf_len, CompletionCallback* callback);
+ virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
+ virtual int Write(IOBuffer* buf, int buf_len, CompletionCallback* callback);
// Identical to posix system call of same name
// Needed by ssl_client_socket_nss
@@ -71,11 +71,11 @@ class TCPClientSocketLibevent : public ClientSocket,
MessageLoopForIO::FileDescriptorWatcher socket_watcher_;
// The buffer used by OnSocketReady to retry Read requests
- char* read_buf_;
+ scoped_refptr<IOBuffer> read_buf_;
int read_buf_len_;
// The buffer used by OnSocketReady to retry Write requests
- const char* write_buf_;
+ scoped_refptr<IOBuffer> write_buf_;
int write_buf_len_;
// External callback; called when read is complete.
diff --git a/net/base/tcp_client_socket_unittest.cc b/net/base/tcp_client_socket_unittest.cc
index 1c40ac6..3fbb02c 100644
--- a/net/base/tcp_client_socket_unittest.cc
+++ b/net/base/tcp_client_socket_unittest.cc
@@ -103,7 +103,11 @@ TEST_F(TCPClientSocketTest, Read) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- rv = sock_->Write(request_text, arraysize(request_text) - 1, &callback);
+ scoped_refptr<net::IOBuffer> request_buffer =
+ new net::IOBuffer(arraysize(request_text) - 1);
+ memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
+
+ rv = sock_->Write(request_buffer, arraysize(request_text) - 1, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING) {
@@ -111,9 +115,9 @@ TEST_F(TCPClientSocketTest, Read) {
EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1));
}
- char buf[4096];
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(4096);
for (;;) {
- rv = sock_->Read(buf, sizeof(buf), &callback);
+ rv = sock_->Read(buf, 4096, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING)
@@ -136,7 +140,11 @@ TEST_F(TCPClientSocketTest, Read_SmallChunks) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- rv = sock_->Write(request_text, arraysize(request_text) - 1, &callback);
+ scoped_refptr<net::IOBuffer> request_buffer =
+ new net::IOBuffer(arraysize(request_text) - 1);
+ memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
+
+ rv = sock_->Write(request_buffer, arraysize(request_text) - 1, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING) {
@@ -144,9 +152,9 @@ TEST_F(TCPClientSocketTest, Read_SmallChunks) {
EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1));
}
- char buf[1];
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(1);
for (;;) {
- rv = sock_->Read(buf, sizeof(buf), &callback);
+ rv = sock_->Read(buf, 1, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING)
@@ -169,7 +177,11 @@ TEST_F(TCPClientSocketTest, Read_Interrupted) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
- rv = sock_->Write(request_text, arraysize(request_text) - 1, &callback);
+ scoped_refptr<net::IOBuffer> request_buffer =
+ new net::IOBuffer(arraysize(request_text) - 1);
+ memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
+
+ rv = sock_->Write(request_buffer, arraysize(request_text) - 1, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING) {
@@ -178,8 +190,8 @@ TEST_F(TCPClientSocketTest, Read_Interrupted) {
}
// Do a partial read and then exit. This test should not crash!
- char buf[512];
- rv = sock_->Read(buf, sizeof(buf), &callback);
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(512);
+ rv = sock_->Read(buf, 512, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING)
@@ -198,13 +210,19 @@ TEST_F(TCPClientSocketTest, FullDuplex_ReadFirst) {
EXPECT_EQ(rv, net::OK);
}
- char buf[4096];
- rv = sock_->Read(buf, sizeof(buf), &callback);
+ const int kBufLen = 4096;
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kBufLen);
+ rv = sock_->Read(buf, kBufLen, &callback);
EXPECT_EQ(net::ERR_IO_PENDING, rv);
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
+ scoped_refptr<net::IOBuffer> request_buffer =
+ new net::IOBuffer(arraysize(request_text) - 1);
+ memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
TestCompletionCallback write_callback;
- rv = sock_->Write(request_text, arraysize(request_text) - 1, &write_callback);
+
+ rv = sock_->Write(request_buffer, arraysize(request_text) - 1,
+ &write_callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING) {
@@ -215,7 +233,7 @@ TEST_F(TCPClientSocketTest, FullDuplex_ReadFirst) {
rv = callback.WaitForResult();
EXPECT_GE(rv, 0);
while (rv > 0) {
- rv = sock_->Read(buf, sizeof(buf), &callback);
+ rv = sock_->Read(buf, kBufLen, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING)
@@ -238,12 +256,18 @@ TEST_F(TCPClientSocketTest, FullDuplex_WriteFirst) {
}
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
+ scoped_refptr<net::IOBuffer> request_buffer =
+ new net::IOBuffer(arraysize(request_text) - 1);
+ memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
TestCompletionCallback write_callback;
- rv = sock_->Write(request_text, arraysize(request_text) - 1, &write_callback);
+
+ rv = sock_->Write(request_buffer, arraysize(request_text) - 1,
+ &write_callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
- char buf[4096];
- int read_rv = sock_->Read(buf, sizeof(buf), &callback);
+ const int kBufLen = 4096;
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kBufLen);
+ int read_rv = sock_->Read(buf, kBufLen, &callback);
EXPECT_TRUE(read_rv >= 0 || read_rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING) {
@@ -254,7 +278,7 @@ TEST_F(TCPClientSocketTest, FullDuplex_WriteFirst) {
rv = callback.WaitForResult();
EXPECT_GE(rv, 0);
while (rv > 0) {
- rv = sock_->Read(buf, sizeof(buf), &callback);
+ rv = sock_->Read(buf, kBufLen, &callback);
EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
if (rv == net::ERR_IO_PENDING)
diff --git a/net/base/tcp_client_socket_win.cc b/net/base/tcp_client_socket_win.cc
index 2066ec0..70da428 100644
--- a/net/base/tcp_client_socket_win.cc
+++ b/net/base/tcp_client_socket_win.cc
@@ -181,6 +181,8 @@ void TCPClientSocketWin::Disconnect() {
waiting_read_ = false;
waiting_write_ = false;
+ read_iobuffer_ = NULL;
+ write_iobuffer_ = NULL;
waiting_connect_ = false;
}
@@ -215,15 +217,16 @@ bool TCPClientSocketWin::IsConnectedAndIdle() const {
return true;
}
-int TCPClientSocketWin::Read(char* buf,
+int TCPClientSocketWin::Read(IOBuffer* buf,
int buf_len,
CompletionCallback* callback) {
DCHECK_NE(socket_, INVALID_SOCKET);
DCHECK(!waiting_read_);
DCHECK(!read_callback_);
+ DCHECK(!read_iobuffer_);
read_buffer_.len = buf_len;
- read_buffer_.buf = buf;
+ read_buffer_.buf = buf->data();
TRACE_EVENT_BEGIN("socket.read", this, "");
// TODO(wtc): Remove the CHECK after enough testing.
@@ -249,21 +252,23 @@ int TCPClientSocketWin::Read(char* buf,
read_watcher_.StartWatching(read_overlapped_.hEvent, &reader_);
waiting_read_ = true;
read_callback_ = callback;
+ read_iobuffer_ = buf;
return ERR_IO_PENDING;
}
return MapWinsockError(err);
}
-int TCPClientSocketWin::Write(const char* buf,
+int TCPClientSocketWin::Write(IOBuffer* buf,
int buf_len,
CompletionCallback* callback) {
DCHECK_NE(socket_, INVALID_SOCKET);
DCHECK(!waiting_write_);
DCHECK(!write_callback_);
DCHECK_GT(buf_len, 0);
+ DCHECK(!write_iobuffer_);
write_buffer_.len = buf_len;
- write_buffer_.buf = const_cast<char*>(buf);
+ write_buffer_.buf = buf->data();
TRACE_EVENT_BEGIN("socket.write", this, "");
// TODO(wtc): Remove the CHECK after enough testing.
@@ -281,6 +286,7 @@ int TCPClientSocketWin::Write(const char* buf,
write_watcher_.StartWatching(write_overlapped_.hEvent, &writer_);
waiting_write_ = true;
write_callback_ = callback;
+ write_iobuffer_ = buf;
return ERR_IO_PENDING;
}
return MapWinsockError(err);
@@ -413,6 +419,7 @@ void TCPClientSocketWin::ReadDelegate::OnObjectSignaled(HANDLE object) {
if (tcp_socket_->waiting_connect_) {
tcp_socket_->DidCompleteConnect();
} else {
+ DCHECK(tcp_socket_->waiting_read_);
DWORD num_bytes, flags;
BOOL ok = WSAGetOverlappedResult(
tcp_socket_->socket_, &tcp_socket_->read_overlapped_, &num_bytes,
@@ -421,6 +428,7 @@ void TCPClientSocketWin::ReadDelegate::OnObjectSignaled(HANDLE object) {
TRACE_EVENT_END("socket.read", tcp_socket_,
StringPrintf("%d bytes", num_bytes));
tcp_socket_->waiting_read_ = false;
+ tcp_socket_->read_iobuffer_ = NULL;
tcp_socket_->DoReadCallback(
ok ? num_bytes : MapWinsockError(WSAGetLastError()));
}
@@ -428,6 +436,7 @@ void TCPClientSocketWin::ReadDelegate::OnObjectSignaled(HANDLE object) {
void TCPClientSocketWin::WriteDelegate::OnObjectSignaled(HANDLE object) {
DCHECK_EQ(object, tcp_socket_->write_overlapped_.hEvent);
+ DCHECK(tcp_socket_->waiting_write_);
DWORD num_bytes, flags;
BOOL ok = WSAGetOverlappedResult(
@@ -437,6 +446,7 @@ void TCPClientSocketWin::WriteDelegate::OnObjectSignaled(HANDLE object) {
TRACE_EVENT_END("socket.write", tcp_socket_,
StringPrintf("%d bytes", num_bytes));
tcp_socket_->waiting_write_ = false;
+ tcp_socket_->write_iobuffer_ = NULL;
tcp_socket_->DoWriteCallback(
ok ? num_bytes : MapWinsockError(WSAGetLastError()));
}
diff --git a/net/base/tcp_client_socket_win.h b/net/base/tcp_client_socket_win.h
index 63f2b93..0199bfc 100644
--- a/net/base/tcp_client_socket_win.h
+++ b/net/base/tcp_client_socket_win.h
@@ -32,8 +32,8 @@ class TCPClientSocketWin : public ClientSocket {
// Socket methods:
// Multiple outstanding requests are not supported.
// Full duplex mode (reading and writing at the same time) is supported
- virtual int Read(char* buf, int buf_len, CompletionCallback* callback);
- virtual int Write(const char* buf, int buf_len, CompletionCallback* callback);
+ virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
+ virtual int Write(IOBuffer* buf, int buf_len, CompletionCallback* callback);
private:
class ReadDelegate : public base::ObjectWatcher::Delegate {
@@ -89,6 +89,8 @@ class TCPClientSocketWin : public ClientSocket {
// The buffers used in Read() and Write().
WSABUF read_buffer_;
WSABUF write_buffer_;
+ scoped_refptr<IOBuffer> read_iobuffer_;
+ scoped_refptr<IOBuffer> write_iobuffer_;
// |reader_| handles the signals from |read_watcher_|.
ReadDelegate reader_;
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());