diff options
author | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-06 02:28:49 +0000 |
---|---|---|
committer | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-06 02:28:49 +0000 |
commit | 34437af8727dac421df5ff694eea7c8392ed1038 (patch) | |
tree | 20f5cc600d9fcdbfd50e0b468ca17eb1a405d4ea /net | |
parent | 7a38548d24517621838df167e65d41739f735aae (diff) | |
download | chromium_src-34437af8727dac421df5ff694eea7c8392ed1038.zip chromium_src-34437af8727dac421df5ff694eea7c8392ed1038.tar.gz chromium_src-34437af8727dac421df5ff694eea7c8392ed1038.tar.bz2 |
Flip: Refactor Flip stream reading and writing out of FlipNetworkTransaction into FlipStreamParser.
FlipNetworkTransaction still contains the TCP socket connection code, but the
session setup and all the stream communication code has moved into
FlipStreamParser, in anticipation of it being used by the HTTP/SSL code.
It's still not quite in the shape I'll need it to be in for use by other
clients, but this gets it much closer.
Added a test for transaction cancellation and added a basic test for
FlipStreamParser. I'll add more tests as I add more consumers.
I'm not terribly happy with the name FlipStreamParser, but it mirrors the
existing HttpStreamParser in functionality, so oh well.
Did some random other cleanups, including deleting unused #includes.
Review URL: http://codereview.chromium.org/362017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31196 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/flip/flip_network_transaction.cc | 352 | ||||
-rw-r--r-- | net/flip/flip_network_transaction.h | 116 | ||||
-rw-r--r-- | net/flip/flip_network_transaction_unittest.cc | 151 | ||||
-rw-r--r-- | net/flip/flip_session.h | 12 |
4 files changed, 422 insertions, 209 deletions
diff --git a/net/flip/flip_network_transaction.cc b/net/flip/flip_network_transaction.cc index b664826..087d7f8 100644 --- a/net/flip/flip_network_transaction.cc +++ b/net/flip/flip_network_transaction.cc @@ -6,27 +6,15 @@ #include "base/scoped_ptr.h" #include "base/compiler_specific.h" -#include "base/field_trial.h" -#include "base/string_util.h" -#include "base/trace_event.h" -#include "build/build_config.h" -#include "net/base/connection_type_histograms.h" #include "net/base/host_resolver.h" #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" #include "net/base/upload_data_stream.h" -#include "net/http/http_auth.h" -#include "net/http/http_auth_handler.h" -#include "net/http/http_basic_stream.h" -#include "net/http/http_chunked_decoder.h" #include "net/http/http_network_session.h" #include "net/http/http_request_info.h" #include "net/http/http_response_headers.h" -#include "net/http/http_util.h" -#include "net/socket/client_socket_factory.h" -#include "net/socket/ssl_client_socket.h" using base::Time; @@ -34,58 +22,144 @@ namespace net { //----------------------------------------------------------------------------- -FlipNetworkTransaction::FlipNetworkTransaction(HttpNetworkSession* session) - : flip_request_id_(0), - user_callback_(0), - user_buffer_bytes_remaining_(0), - session_(session), +FlipStreamParser::FlipStreamParser() + : flip_(NULL), + flip_stream_id_(0), request_(NULL), + response_(NULL), + request_body_stream_(NULL), response_complete_(false), - response_status_(net::OK), - next_state_(STATE_NONE) { + response_status_(OK), + user_callback_(NULL), + user_buffer_(NULL), + user_buffer_len_(0) { } -FlipNetworkTransaction::~FlipNetworkTransaction() { - LOG(INFO) << "FlipNetworkTransaction dead. " << this; - if (flip_ && flip_request_id_) - flip_->CancelStream(flip_request_id_); +FlipStreamParser::~FlipStreamParser() { + if (flip_ && flip_stream_id_) { + flip_->CancelStream(flip_stream_id_); + } else if (!response_complete_) { + NOTREACHED(); + } +} + +int FlipStreamParser::SendRequest(FlipSession* flip, + const HttpRequestInfo* request, + CompletionCallback* callback) { + CHECK(flip); + CHECK(request); + CHECK(callback); + + request_ = request; + flip_ = flip; + + // TODO(mbelshe): rethink this UploadDataStream wrapper. + if (request_->upload_data) + request_body_stream_.reset(new UploadDataStream(request_->upload_data)); + + CHECK(flip_stream_id_ == 0); + flip_stream_id_ = flip->CreateStream(this); + + CHECK(!user_callback_); + user_callback_ = callback; + + // The FlipSession will always call us back when the send is complete. + return ERR_IO_PENDING; } -const HttpRequestInfo* FlipNetworkTransaction::request() { +int FlipStreamParser::ReadResponseHeaders(CompletionCallback* callback) { + CHECK(callback); + + if (response_.get()) + return OK; + + CHECK(!user_callback_); + user_callback_ = callback; + return ERR_IO_PENDING; +} + +int FlipStreamParser::ReadResponseBody( + IOBuffer* buf, int buf_len, CompletionCallback* callback) { + CHECK(buf); + CHECK(buf_len); + CHECK(callback); + + // If we have data buffered, complete the IO immediately. + if (response_body_.size()) { + int bytes_read = 0; + while (response_body_.size() && buf_len > 0) { + scoped_refptr<IOBufferWithSize> data = response_body_.front(); + const int bytes_to_copy = std::min(buf_len, data->size()); + memcpy(&(buf->data()[bytes_read]), data->data(), bytes_to_copy); + buf_len -= bytes_to_copy; + if (bytes_to_copy == data->size()) { + response_body_.pop_front(); + } else { + const int bytes_remaining = data->size() - bytes_to_copy; + IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining); + memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]), + bytes_remaining); + response_body_.pop_front(); + response_body_.push_front(new_buffer); + } + bytes_read += bytes_to_copy; + } + return bytes_read; + } else if (response_complete_) { + return response_status_; + } + + CHECK(!user_callback_); + CHECK(!user_buffer_); + CHECK(user_buffer_len_ == 0); + + user_callback_ = callback; + user_buffer_ = buf; + user_buffer_len_ = buf_len; + return ERR_IO_PENDING; +} + +uint64 FlipStreamParser::GetUploadProgress() const { + if (!request_body_stream_.get()) + return 0; + + return request_body_stream_->position(); +} + +const HttpResponseInfo* FlipStreamParser::GetResponseInfo() const { + return response_.get(); +} + +const HttpRequestInfo* FlipStreamParser::request() const { return request_; } -const UploadDataStream* FlipNetworkTransaction::data() { +const UploadDataStream* FlipStreamParser::data() const { return request_body_stream_.get(); } -void FlipNetworkTransaction::OnRequestSent(int status) { - if (status == OK) - next_state_ = STATE_SEND_REQUEST_COMPLETE; - else - next_state_ = STATE_NONE; +void FlipStreamParser::OnRequestSent(int status) { + CHECK(user_callback_); - DoLoop(status); + DoCallback(status); } -void FlipNetworkTransaction::OnUploadDataSent(int result) { +void FlipStreamParser::OnUploadDataSent(int result) { NOTIMPLEMENTED(); } -void FlipNetworkTransaction::OnResponseReceived(HttpResponseInfo* response) { - next_state_ = STATE_READ_HEADERS_COMPLETE; +void FlipStreamParser::OnResponseReceived(HttpResponseInfo* response) { + response_.reset(new HttpResponseInfo); + *response_ = *response; // TODO(mbelshe): avoid copy. - response_ = *response; // TODO(mbelshe): avoid copy. - - DoLoop(net::OK); + if (user_callback_) + DoCallback(OK); } -void FlipNetworkTransaction::OnDataReceived(const char* buffer, int bytes) { +void FlipStreamParser::OnDataReceived(const char* buffer, int bytes) { // TODO(mbelshe): if data is received before a syn reply, this will crash. - DCHECK(bytes >= 0); - next_state_ = STATE_READ_BODY; - + DCHECK_GE(bytes, 0); if (bytes > 0) { DCHECK(buffer); @@ -97,22 +171,61 @@ void FlipNetworkTransaction::OnDataReceived(const char* buffer, int bytes) { response_body_.push_back(io_buffer); } - DoLoop(net::OK); + + // Note that data may be received for a FlipStream prior to the user calling + // ReadResponseBody(), therefore user_callback_ may be NULL. + if (user_callback_) { + int rv = ReadResponseBody(user_buffer_, user_buffer_len_, user_callback_); + CHECK(rv != ERR_IO_PENDING); + user_buffer_ = NULL; + user_buffer_len_ = 0; + DoCallback(rv); + } } -void FlipNetworkTransaction::OnClose(int status) { - next_state_ = STATE_READ_BODY_COMPLETE; +void FlipStreamParser::OnClose(int status) { response_complete_ = true; response_status_ = status; - flip_request_id_ = 0; // TODO(mbelshe) - do we need this? - DoLoop(status); + flip_stream_id_ = 0; + + if (user_callback_) + DoCallback(status); +} + +void FlipStreamParser::DoCallback(int rv) { + CHECK(rv != ERR_IO_PENDING); + CHECK(user_callback_); + + // Since Run may result in being called back, clear user_callback_ in advance. + CompletionCallback* c = user_callback_; + user_callback_ = NULL; + c->Run(rv); +} + +//----------------------------------------------------------------------------- + +FlipNetworkTransaction::FlipNetworkTransaction(HttpNetworkSession* session) + : ALLOW_THIS_IN_INITIALIZER_LIST( + io_callback_(this, &FlipNetworkTransaction::OnIOComplete)), + user_callback_(NULL), + user_buffer_len_(0), + session_(session), + request_(NULL), + next_state_(STATE_NONE) { +} + +FlipNetworkTransaction::~FlipNetworkTransaction() { + LOG(INFO) << "FlipNetworkTransaction dead. " << this; } int FlipNetworkTransaction::Start(const HttpRequestInfo* request_info, CompletionCallback* callback, LoadLog* load_log) { + CHECK(request_info); + CHECK(callback); + request_ = request_info; - start_time_ = base::Time::Now(); + start_time_ = base::TimeTicks::Now(); next_state_ = STATE_INIT_CONNECTION; int rv = DoLoop(OK); @@ -147,44 +260,23 @@ int FlipNetworkTransaction::RestartWithAuth( int FlipNetworkTransaction::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(buf); - DCHECK(buf_len > 0); + DCHECK_GT(buf_len, 0); DCHECK(callback); DCHECK(flip_.get()); - // If we have data buffered, complete the IO immediately. - if (response_body_.size()) { - int bytes_read = 0; - while (response_body_.size() && buf_len > 0) { - scoped_refptr<IOBufferWithSize> data = response_body_.front(); - int bytes_to_copy = std::min(buf_len, data->size()); - memcpy(&(buf->data()[bytes_read]), data->data(), bytes_to_copy); - buf_len -= bytes_to_copy; - if (bytes_to_copy == data->size()) { - response_body_.pop_front(); - } else { - int bytes_remaining = data->size() - bytes_to_copy; - IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining); - memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]), - bytes_remaining); - response_body_.pop_front(); - response_body_.push_front(new_buffer); - } - bytes_read += bytes_to_copy; - } - return bytes_read; - } - - if (response_complete_) - return 0; // We already finished reading this stream. - - user_callback_ = callback; user_buffer_ = buf; - user_buffer_bytes_remaining_ = buf_len; - return net::ERR_IO_PENDING; + user_buffer_len_ = buf_len; + + next_state_ = STATE_READ_BODY; + int rv = DoLoop(OK); + if (rv == ERR_IO_PENDING) + user_callback_ = callback; + return rv; } const HttpResponseInfo* FlipNetworkTransaction::GetResponseInfo() const { - return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL; + const HttpResponseInfo* response = flip_stream_parser_->GetResponseInfo(); + return (response->headers || response->ssl_info.cert) ? response : NULL; } LoadState FlipNetworkTransaction::GetLoadState() const { @@ -205,20 +297,15 @@ LoadState FlipNetworkTransaction::GetLoadState() const { } uint64 FlipNetworkTransaction::GetUploadProgress() const { - if (!request_body_stream_.get()) + if (!flip_stream_parser_.get()) return 0; - return request_body_stream_->position(); + return flip_stream_parser_->GetUploadProgress(); } - -void FlipNetworkTransaction::DoHttpTransactionCallback(int rv) { - DCHECK(rv != ERR_IO_PENDING); - - // Because IO is asynchronous from the caller, we could be completing an - // IO even though the user hasn't issued a Read() yet. - if (!user_callback_) - return; +void FlipNetworkTransaction::DoCallback(int rv) { + CHECK(rv != ERR_IO_PENDING); + CHECK(user_callback_); // Since Run may result in Read being called, clear user_callback_ up front. CompletionCallback* c = user_callback_; @@ -226,6 +313,12 @@ void FlipNetworkTransaction::DoHttpTransactionCallback(int rv) { c->Run(rv); } +void FlipNetworkTransaction::OnIOComplete(int result) { + int rv = DoLoop(result); + if (rv != ERR_IO_PENDING) + DoCallback(rv); +} + int FlipNetworkTransaction::DoLoop(int result) { DCHECK(next_state_ != STATE_NONE); DCHECK(request_); @@ -257,26 +350,14 @@ int FlipNetworkTransaction::DoLoop(int result) { rv = DoReadHeaders(); break; case STATE_READ_HEADERS_COMPLETE: - // DoReadHeadersComplete only returns OK becaue the transaction - // could be destroyed as part of the call. rv = DoReadHeadersComplete(rv); - DCHECK(rv == net::OK); - return rv; break; case STATE_READ_BODY: DCHECK_EQ(OK, rv); rv = DoReadBody(); - // DoReadBody only returns OK becaue the transaction could be - // destroyed as part of the call. - DCHECK(rv == net::OK); - return rv; break; case STATE_READ_BODY_COMPLETE: - // We return here because the Transaction could be destroyed after this - // call. rv = DoReadBodyComplete(rv); - DCHECK(rv == net::OK); - return rv; break; case STATE_NONE: rv = ERR_FAILED; @@ -306,8 +387,8 @@ int FlipNetworkTransaction::DoInitConnection() { DCHECK(flip_); int rv = flip_->Connect(connection_group, resolve_info, request_->priority); - DCHECK(rv == net::OK); // The API says it will always return OK. - return net::OK; + DCHECK(rv == OK); // The API says it will always return OK. + return OK; } int FlipNetworkTransaction::DoInitConnectionComplete(int result) { @@ -315,21 +396,14 @@ int FlipNetworkTransaction::DoInitConnectionComplete(int result) { return result; next_state_ = STATE_SEND_REQUEST; - return net::OK; + return OK; } int FlipNetworkTransaction::DoSendRequest() { - // TODO(mbelshe): rethink this UploadDataStream wrapper. - if (request_->upload_data) - request_body_stream_.reset(new UploadDataStream(request_->upload_data)); - - flip_request_id_ = flip_->CreateStream(this); - - if (response_complete_) - return net::OK; - - // The FlipSession will always call us back when the send is complete. - return net::ERR_IO_PENDING; + next_state_ = STATE_SEND_REQUEST_COMPLETE; + CHECK(!flip_stream_parser_.get()); + flip_stream_parser_.reset(new FlipStreamParser); + return flip_stream_parser_->SendRequest(flip_, request_, &io_callback_); } int FlipNetworkTransaction::DoSendRequestComplete(int result) { @@ -337,54 +411,34 @@ int FlipNetworkTransaction::DoSendRequestComplete(int result) { return result; next_state_ = STATE_READ_HEADERS; - return net::OK; + return OK; } int FlipNetworkTransaction::DoReadHeaders() { - // The FlipSession will always call us back when the headers have been - // received. - return net::ERR_IO_PENDING; + next_state_ = STATE_READ_HEADERS_COMPLETE; + return flip_stream_parser_->ReadResponseHeaders(&io_callback_); } int FlipNetworkTransaction::DoReadHeadersComplete(int result) { - // Notify the user that the headers are ready. - DoHttpTransactionCallback(result); - return net::OK; + // TODO(willchan): Flesh out the support for HTTP authentication here. + return OK; } int FlipNetworkTransaction::DoReadBody() { - // The caller has not issued a read request yet. - if (!user_callback_) - return net::OK; - - int bytes_read = 0; - while (response_body_.size() && user_buffer_bytes_remaining_ > 0) { - scoped_refptr<IOBufferWithSize> data = response_body_.front(); - int bytes_to_copy = std::min(user_buffer_bytes_remaining_, data->size()); - memcpy(&(user_buffer_->data()[bytes_read]), data->data(), bytes_to_copy); - user_buffer_bytes_remaining_ -= bytes_to_copy; - if (bytes_to_copy == data->size()) { - response_body_.pop_front(); - } else { - int bytes_remaining = data->size() - bytes_to_copy; - IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining); - memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]), - bytes_remaining); - response_body_.pop_front(); - response_body_.push_front(new_buffer); - } - bytes_read += bytes_to_copy; - } + next_state_ = STATE_READ_BODY_COMPLETE; - DoHttpTransactionCallback(bytes_read); - return net::OK; + return flip_stream_parser_->ReadResponseBody( + user_buffer_, user_buffer_len_, &io_callback_); } int FlipNetworkTransaction::DoReadBodyComplete(int result) { - // TODO(mbelshe): record success or failure of the transaction? - if (user_callback_) - DoHttpTransactionCallback(result); - return OK; + user_buffer_ = NULL; + user_buffer_len_ = 0; + + if (result <= 0) + flip_stream_parser_.reset(); + + return result; } } // namespace net diff --git a/net/flip/flip_network_transaction.h b/net/flip/flip_network_transaction.h index e228d37..f22ddb7 100644 --- a/net/flip/flip_network_transaction.h +++ b/net/flip/flip_network_transaction.h @@ -8,47 +8,97 @@ #include <string> #include <deque> +#include "base/basictypes.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/time.h" -#include "net/base/address_list.h" -#include "net/base/host_resolver.h" #include "net/base/io_buffer.h" -#include "net/base/load_flags.h" #include "net/base/load_states.h" -#include "net/base/ssl_config_service.h" #include "net/flip/flip_session.h" -#include "net/http/http_auth.h" -#include "net/http/http_auth_handler.h" #include "net/http/http_response_info.h" #include "net/http/http_transaction.h" -#include "net/proxy/proxy_service.h" -#include "net/socket/client_socket_handle.h" -#include "net/socket/client_socket_pool.h" -#include "testing/gtest/include/gtest/gtest_prod.h" namespace net { -class ClientSocketFactory; +class FlipSession; class HttpNetworkSession; class UploadDataStream; -// A FlipNetworkTransaction can be used to fetch HTTP conent. -// The FlipDelegate is the consumer of events from the FlipSession. -class FlipNetworkTransaction : public HttpTransaction, public FlipDelegate { +// FlipStreamParser is a class to encapsulate the IO of a FLIP +// stream on top of a FlipSession. All read/writes go through +// the FlipStreamParser. +class FlipStreamParser : public FlipDelegate { public: - explicit FlipNetworkTransaction(HttpNetworkSession* session); - virtual ~FlipNetworkTransaction(); + FlipStreamParser(); + ~FlipStreamParser(); + + // Creates a FLIP stream from |flip| and send the HTTP request over it. + // |request|'s lifetime must persist longer than |this|. This always + // completes asynchronously, so |callback| must be non-NULL. Returns a net + // error code. + int SendRequest(FlipSession* flip, const HttpRequestInfo* request, + CompletionCallback* callback); + + // Reads the response headers. Returns a net error code. + int ReadResponseHeaders(CompletionCallback* callback); + + // Reads the response body. Returns a net error code or the number of bytes + // read. + int ReadResponseBody( + IOBuffer* buf, int buf_len, CompletionCallback* callback); + + // Returns the number of bytes uploaded. + uint64 GetUploadProgress() const; + + const HttpResponseInfo* GetResponseInfo() const; // FlipDelegate methods: - virtual const HttpRequestInfo* request(); - virtual const UploadDataStream* data(); + virtual const HttpRequestInfo* request() const; + virtual const UploadDataStream* data() const; virtual void OnRequestSent(int status); virtual void OnUploadDataSent(int result); virtual void OnResponseReceived(HttpResponseInfo* response); virtual void OnDataReceived(const char* buffer, int bytes); virtual void OnClose(int status); + private: + friend class FlipStreamParserPeer; + + void DoCallback(int rv); + + // The Flip request id for this request. + scoped_refptr<FlipSession> flip_; + flip::FlipStreamId flip_stream_id_; + + const HttpRequestInfo* request_; + scoped_ptr<HttpResponseInfo> response_; + scoped_ptr<UploadDataStream> request_body_stream_; + + bool response_complete_; + // We buffer the response body as it arrives asynchronously from the stream. + // TODO(mbelshe): is this infinite buffering? + std::deque<scoped_refptr<IOBufferWithSize> > response_body_; + + // Since we buffer the response, we also buffer the response status. + // Not valid until response_complete_ is true. + int response_status_; + + CompletionCallback* user_callback_; + + // User provided buffer for the ReadResponseBody() response. + scoped_refptr<IOBuffer> user_buffer_; + int user_buffer_len_; + + DISALLOW_COPY_AND_ASSIGN(FlipStreamParser); +}; + +// A FlipNetworkTransaction can be used to fetch HTTP conent. +// The FlipDelegate is the consumer of events from the FlipSession. +class FlipNetworkTransaction : public HttpTransaction { + public: + explicit FlipNetworkTransaction(HttpNetworkSession* session); + virtual ~FlipNetworkTransaction(); + // HttpTransaction methods: virtual int Start(const HttpRequestInfo* request_info, CompletionCallback* callback, @@ -84,8 +134,8 @@ class FlipNetworkTransaction : public HttpTransaction, public FlipDelegate { STATE_NONE }; - // Used to callback an HttpTransaction call. - void DoHttpTransactionCallback(int result); + void DoCallback(int result); + void OnIOComplete(int result); // Runs the state transition loop. int DoLoop(int result); @@ -103,40 +153,32 @@ class FlipNetworkTransaction : public HttpTransaction, public FlipDelegate { int DoReadBody(); int DoReadBodyComplete(int result); - // The Flip request id for this request. - int flip_request_id_; - // The Flip session servicing this request. If NULL, the request has not // started. scoped_refptr<FlipSession> flip_; + CompletionCallbackImpl<FlipNetworkTransaction> io_callback_; CompletionCallback* user_callback_; + + // Used to pass onto the FlipStreamParser. scoped_refptr<IOBuffer> user_buffer_; - int user_buffer_bytes_remaining_; + int user_buffer_len_; scoped_refptr<HttpNetworkSession> session_; const HttpRequestInfo* request_; - HttpResponseInfo response_; - - scoped_ptr<UploadDataStream> request_body_stream_; - - // We buffer the response body as it arrives asynchronously from the stream. - // TODO(mbelshe): is this infinite buffering? - std::deque<scoped_refptr<IOBufferWithSize> > response_body_; - bool response_complete_; - // Since we buffer the response, we also buffer the response status. - // Not valid until response_complete_ is true. - int response_status_; // The time the Start method was called. - base::Time start_time_; + base::TimeTicks start_time_; // The next state in the state machine. State next_state_; + + scoped_ptr<FlipStreamParser> flip_stream_parser_; + + DISALLOW_COPY_AND_ASSIGN(FlipNetworkTransaction); }; } // namespace net #endif // NET_HTTP_NETWORK_TRANSACTION_H_ - diff --git a/net/flip/flip_network_transaction_unittest.cc b/net/flip/flip_network_transaction_unittest.cc index be2c41e..69eb6c0 100644 --- a/net/flip/flip_network_transaction_unittest.cc +++ b/net/flip/flip_network_transaction_unittest.cc @@ -2,31 +2,37 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <math.h> // ceil +#include "net/flip/flip_network_transaction.h" -#include "base/compiler_specific.h" #include "net/base/completion_callback.h" #include "net/base/mock_host_resolver.h" #include "net/base/ssl_config_service_defaults.h" -#include "net/base/ssl_info.h" #include "net/base/test_completion_callback.h" #include "net/base/upload_data.h" -#include "net/flip/flip_network_transaction.h" #include "net/flip/flip_protocol.h" -#include "net/http/http_auth_handler_ntlm.h" #include "net/http/http_network_session.h" -#include "net/http/http_network_transaction.h" #include "net/http/http_transaction_unittest.h" #include "net/proxy/proxy_config_service_fixed.h" -#include "net/socket/client_socket_factory.h" #include "net/socket/socket_test_util.h" -#include "net/socket/ssl_client_socket.h" #include "testing/platform_test.h" //----------------------------------------------------------------------------- namespace net { +class FlipStreamParserPeer { + public: + explicit FlipStreamParserPeer(FlipStreamParser* flip_stream_parser) + : flip_stream_parser_(flip_stream_parser) {} + + int flip_stream_id() const { return flip_stream_parser_->flip_stream_id_; } + + private: + FlipStreamParser* const flip_stream_parser_; + + DISALLOW_COPY_AND_ASSIGN(FlipStreamParserPeer); +}; + namespace { // Create a proxy service which fails on all requests (falls back to direct). @@ -35,7 +41,7 @@ ProxyService* CreateNullProxyService() { } // Helper to manage the lifetimes of the dependencies for a -// HttpNetworkTransaction. +// FlipNetworkTransaction. class SessionDependencies { public: // Default set of dependencies -- "null" proxy service. @@ -74,10 +80,51 @@ HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { session_deps->flip_session_pool); } +class FlipStreamParserTest : public PlatformTest { + protected: + FlipStreamParserTest() + : session_(CreateSession(&session_deps_)), + parser_peer_(&parser_) {} + + FlipSession* CreateFlipSession() { + HostResolver::RequestInfo resolve_info("www.google.com", 80); + FlipSession* session = session_->flip_session_pool()->Get( + resolve_info, session_); + return session; + } + + virtual void TearDown() { + MessageLoop::current()->RunAllPending(); + PlatformTest::TearDown(); + } + + SessionDependencies session_deps_; + scoped_refptr<HttpNetworkSession> session_; + FlipStreamParser parser_; + FlipStreamParserPeer parser_peer_; +}; + +// TODO(willchan): Look into why TCPConnectJobs are still alive when this test +// goes away. They're calling into the ClientSocketFactory which doesn't exist +// anymore, so it crashes. +TEST_F(FlipStreamParserTest, DISABLED_SendRequest) { + scoped_refptr<FlipSession> flip(CreateFlipSession()); + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + TestCompletionCallback callback; + + EXPECT_EQ(ERR_IO_PENDING, parser_.SendRequest(flip, &request, &callback)); + EXPECT_TRUE(flip->IsStreamActive(parser_peer_.flip_stream_id())); +} + +// TODO(willchan): Write a longer test for FlipStreamParser that exercises all +// methods. + } // namespace class FlipNetworkTransactionTest : public PlatformTest { - public: + protected: virtual void SetUp() { // Disable compression on this test. flip::FlipFramer::set_enable_compression_default(false); @@ -89,7 +136,6 @@ class FlipNetworkTransactionTest : public PlatformTest { PlatformTest::TearDown(); } - protected: void KeepAliveConnectionResendRequestTest(const MockRead& read_failure); struct TransactionHelperResult { @@ -143,7 +189,7 @@ class FlipNetworkTransactionTest : public PlatformTest { // Verify FlipNetworkTransaction constructor. TEST_F(FlipNetworkTransactionTest, Constructor) { SessionDependencies session_deps; - scoped_refptr<net::HttpNetworkSession> session = + scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); scoped_ptr<HttpTransaction> trans(new FlipNetworkTransaction(session)); } @@ -197,10 +243,10 @@ TEST_F(FlipNetworkTransactionTest, Get) { MockRead reads[] = { MockRead(true, reinterpret_cast<const char*>(syn_reply), sizeof(syn_reply)), - MockWrite(true, reinterpret_cast<const char*>(body_frame), - sizeof(body_frame)), - MockWrite(true, reinterpret_cast<const char*>(fin_frame), - sizeof(fin_frame)), + MockRead(true, reinterpret_cast<const char*>(body_frame), + sizeof(body_frame)), + MockRead(true, reinterpret_cast<const char*>(fin_frame), + sizeof(fin_frame)), MockRead(true, 0, 0) // EOF }; @@ -325,5 +371,78 @@ TEST_F(FlipNetworkTransactionTest, ResponseWithoutSynReply) { EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv); } +// TODO(willchan): Look into why TCPConnectJobs are still alive when this test +// goes away. They're calling into the ClientSocketFactory which doesn't exist +// anymore, so it crashes. +TEST_F(FlipNetworkTransactionTest, DISABLED_CancelledTransaction) { + static const unsigned char syn[] = { + 0x80, 0x01, 0x00, 0x01, // header + 0x01, 0x00, 0x00, 0x46, // FIN, len + 0x00, 0x00, 0x00, 0x01, // stream id + 0xc0, 0x00, 0x00, 0x04, // 4 headers + 0x00, 0x04, 'h', 'o', 's', 't', + 0x00, 0x0e, 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', + '.', 'c', 'o', 'm', + 0x00, 0x06, 'm', 'e', 't', 'h', 'o', 'd', + 0x00, 0x03, 'G', 'E', 'T', + 0x00, 0x03, 'u', 'r', 'l', + 0x00, 0x01, '/', + 0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n', + 0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1', + }; + + static const unsigned char syn_reply[] = { + 0x80, 0x01, 0x00, 0x02, // header + 0x00, 0x00, 0x00, 0x45, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, // 4 headers + 0x00, 0x05, 'h', 'e', 'l', 'l', 'o', // "hello" + 0x00, 0x03, 'b', 'y', 'e', // "bye" + 0x00, 0x06, 's', 't', 'a', 't', 'u', 's', // "status" + 0x00, 0x03, '2', '0', '0', // "200" + 0x00, 0x03, 'u', 'r', 'l', // "url" + 0x00, 0x0a, '/', 'i', 'n', 'd', 'e', 'x', '.', 'p', 'h', 'p', // "HTTP/1.1" + 0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n', // "version" + 0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1', // "HTTP/1.1" + }; + + MockWrite writes[] = { + MockWrite(true, reinterpret_cast<const char*>(syn), sizeof(syn)), + }; + + MockRead reads[] = { + MockRead(true, reinterpret_cast<const char*>(syn_reply), sizeof(syn_reply)), + // This following read isn't used by the test, except during the + // RunAllPending() call at the end since the FlipSession survives the + // FlipNetworkTransaction and still tries to continue Read()'ing. Any + // MockRead will do here. + MockRead(true, 0, 0) // EOF + }; + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + // We disable SSL for this test. + FlipSession::SetSSLMode(false); + + SessionDependencies session_deps; + scoped_ptr<FlipNetworkTransaction> trans( + new FlipNetworkTransaction(CreateSession(&session_deps))); + + StaticMockSocket data(reads, writes); + session_deps.socket_factory.AddMockSocket(&data); + + TestCompletionCallback callback; + + int rv = trans->Start(&request, &callback, NULL); + EXPECT_EQ(ERR_IO_PENDING, rv); + trans.reset(); // Cancel the transaction. + + // Flush the MessageLoop while the SessionDependencies (in particular, the + // MockClientSocketFactory) are still alive. + MessageLoop::current()->RunAllPending(); +} } // namespace net diff --git a/net/flip/flip_session.h b/net/flip/flip_session.h index 08160ea..a76630d 100644 --- a/net/flip/flip_session.h +++ b/net/flip/flip_session.h @@ -42,12 +42,12 @@ class FlipDelegate { // The delegate provides access to the HttpRequestInfo for use by the flip // session. - virtual const HttpRequestInfo* request() = 0; + virtual const HttpRequestInfo* request() const = 0; // The delegate provides access to an UploadDataStream for use by the // flip session. If the delegate is not uploading content, this call // must return NULL. - virtual const UploadDataStream* data() = 0; + virtual const UploadDataStream* data() const = 0; // Callbacks. @@ -117,10 +117,11 @@ class FlipSession : public base::RefCounted<FlipSession>, // status, such as "resolving host", "connecting", etc. LoadState GetLoadState() const; + // Enable or disable SSL. + static void SetSSLMode(bool enable) { use_ssl_ = enable; } + protected: - friend class FlipNetworkTransactionTest; friend class FlipSessionPool; - friend class HttpNetworkLayer; // Temporary for server. // Provide access to the framer for testing. flip::FlipFramer* GetFramer() { return &flip_framer_; } @@ -132,9 +133,6 @@ class FlipSession : public base::RefCounted<FlipSession>, // Closes all open streams. Used as part of shutdown. void CloseAllStreams(net::Error code); - // Enable or disable SSL. This is only to be used for testing. - static void SetSSLMode(bool enable) { use_ssl_ = enable; } - private: friend class base::RefCounted<FlipSession>; virtual ~FlipSession(); |