diff options
-rw-r--r-- | net/quic/quic_http_stream.cc | 41 | ||||
-rw-r--r-- | net/quic/quic_http_stream.h | 2 | ||||
-rw-r--r-- | net/quic/quic_http_stream_test.cc | 60 |
3 files changed, 80 insertions, 23 deletions
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc index 8df900e..3ddccac 100644 --- a/net/quic/quic_http_stream.cc +++ b/net/quic/quic_http_stream.cc @@ -23,7 +23,7 @@ namespace net { static const size_t kHeaderBufInitialSize = 4096; QuicHttpStream::QuicHttpStream(QuicReliableClientStream* stream) - : io_state_(STATE_NONE), + : next_state_(STATE_NONE), stream_(stream), request_info_(NULL), request_body_stream_(NULL), @@ -95,7 +95,7 @@ int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers, // Store the response info. response_info_ = response; - io_state_ = STATE_SEND_HEADERS; + next_state_ = STATE_SEND_HEADERS; int rv = DoLoop(OK); if (rv == ERR_IO_PENDING) callback_ = callback; @@ -189,7 +189,7 @@ HttpStream* QuicHttpStream::RenewStreamForAuth() { } bool QuicHttpStream::IsResponseBodyComplete() const { - return io_state_ == STATE_OPEN && !stream_; + return next_state_ == STATE_OPEN && !stream_; } bool QuicHttpStream::CanFindEndOfResponse() const { @@ -323,7 +323,9 @@ void QuicHttpStream::DoCallback(int rv) { int QuicHttpStream::DoLoop(int rv) { do { - switch (io_state_) { + State state = next_state_; + next_state_ = STATE_NONE; + switch (state) { case STATE_SEND_HEADERS: CHECK_EQ(OK, rv); rv = DoSendHeaders(); @@ -349,10 +351,10 @@ int QuicHttpStream::DoLoop(int rv) { CHECK_EQ(OK, rv); break; default: - NOTREACHED() << "io_state_: " << io_state_; + NOTREACHED() << "next_state_: " << next_state_; break; } - } while (io_state_ != STATE_NONE && io_state_ != STATE_OPEN && + } while (next_state_ != STATE_NONE && next_state_ != STATE_OPEN && rv != ERR_IO_PENDING); return rv; @@ -364,25 +366,23 @@ int QuicHttpStream::DoSendHeaders() { bool has_upload_data = request_body_stream_ != NULL; - io_state_ = STATE_SEND_HEADERS_COMPLETE; + next_state_ = STATE_SEND_HEADERS_COMPLETE; QuicConsumedData rv = stream_->WriteData(request_, !has_upload_data); return rv.bytes_consumed; } int QuicHttpStream::DoSendHeadersComplete(int rv) { - if (rv < 0) { - io_state_ = STATE_NONE; + if (rv < 0) return rv; - } - io_state_ = request_body_stream_ ? + next_state_ = request_body_stream_ ? STATE_READ_REQUEST_BODY : STATE_OPEN; return OK; } int QuicHttpStream::DoReadRequestBody() { - io_state_ = STATE_READ_REQUEST_BODY_COMPLETE; + next_state_ = STATE_READ_REQUEST_BODY_COMPLETE; return request_body_stream_->Read(raw_request_body_buf_, raw_request_body_buf_->size(), base::Bind(&QuicHttpStream::OnIOComplete, @@ -392,17 +392,15 @@ int QuicHttpStream::DoReadRequestBody() { int QuicHttpStream::DoReadRequestBodyComplete(int rv) { // |rv| is the result of read from the request body from the last call to // DoSendBody(). - if (rv < 0) { - io_state_ = STATE_NONE; + if (rv < 0) return rv; - } request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_, rv); if (rv == 0) { // Reached the end. DCHECK(request_body_stream_->IsEOF()); } - io_state_ = STATE_SEND_BODY; + next_state_ = STATE_SEND_BODY; return OK; } @@ -419,23 +417,22 @@ int QuicHttpStream::DoSendBody() { QuicConsumedData rv = stream_->WriteData(data, eof); request_body_buf_->DidConsume(rv.bytes_consumed); if (eof) { - io_state_ = STATE_OPEN; + next_state_ = STATE_OPEN; return OK; } + next_state_ = STATE_SEND_BODY_COMPLETE; return rv.bytes_consumed; } - io_state_ = STATE_SEND_BODY_COMPLETE; + next_state_ = STATE_SEND_BODY_COMPLETE; return OK; } int QuicHttpStream::DoSendBodyComplete(int rv) { - if (rv < 0) { - io_state_ = STATE_NONE; + if (rv < 0) return rv; - } - io_state_ = STATE_READ_REQUEST_BODY; + next_state_ = STATE_READ_REQUEST_BODY; return OK; } diff --git a/net/quic/quic_http_stream.h b/net/quic/quic_http_stream.h index 6716dd5..f6dd5bb 100644 --- a/net/quic/quic_http_stream.h +++ b/net/quic/quic_http_stream.h @@ -91,7 +91,7 @@ class NET_EXPORT_PRIVATE QuicHttpStream : void BufferResponseBody(const char* data, int length); - State io_state_; + State next_state_; QuicReliableClientStream* stream_; // Non-owning. diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 2b43b2ef..5b4efaa 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -458,6 +458,66 @@ TEST_F(QuicHttpStreamTest, SendPostRequest) { EXPECT_TRUE(AtEof()); } +TEST_F(QuicHttpStreamTest, SendChunkedPostRequest) { + SetRequestString("POST", "/"); + size_t chunk_size = strlen(kUploadData); + AddWrite(SYNCHRONOUS, ConstructDataPacket(1, !kFin, 0, request_data_)); + AddWrite(SYNCHRONOUS, ConstructDataPacket(2, !kFin, request_data_.length(), + kUploadData)); + AddWrite(SYNCHRONOUS, ConstructDataPacket(3, kFin, + request_data_.length() + chunk_size, + kUploadData)); + AddWrite(SYNCHRONOUS, ConstructAckPacket(4, 2, 3)); + + Initialize(); + + UploadDataStream upload_data_stream(UploadDataStream::CHUNKED, 0); + upload_data_stream.AppendChunk(kUploadData, chunk_size, false); + + request_.method = "POST"; + request_.url = GURL("http://www.google.com/"); + request_.upload_data_stream = &upload_data_stream; + ASSERT_EQ(OK, request_.upload_data_stream->Init(CompletionCallback())); + + ASSERT_EQ(OK, stream_->InitializeStream(&request_, net_log_, + callback_.callback())); + ASSERT_EQ(ERR_IO_PENDING, stream_->SendRequest(headers_, &response_, + callback_.callback())); + EXPECT_EQ(&response_, stream_->GetResponseInfo()); + + upload_data_stream.AppendChunk(kUploadData, chunk_size, true); + + // Ack both packets in the request. + scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 2, 1)); + ProcessPacket(*ack); + + // Send the response headers (but not the body). + SetResponseString("200 OK", ""); + scoped_ptr<QuicEncryptedPacket> resp( + ConstructDataPacket(2, !kFin, 0, response_data_)); + ProcessPacket(*resp); + + // Since the headers have already arrived, this should return immediately. + ASSERT_EQ(OK, stream_->ReadResponseHeaders(callback_.callback())); + ASSERT_TRUE(response_.headers != NULL); + EXPECT_EQ(200, response_.headers->response_code()); + EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain")); + + // Send the response body. + const char kResponseBody[] = "Hello world!"; + scoped_ptr<QuicEncryptedPacket> resp_body( + ConstructDataPacket(3, kFin, response_data_.length(), kResponseBody)); + ProcessPacket(*resp_body); + + // Since the body has already arrived, this should return immediately. + ASSERT_EQ(static_cast<int>(strlen(kResponseBody)), + stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(), + callback_.callback())); + + EXPECT_TRUE(stream_->IsResponseBodyComplete()); + EXPECT_TRUE(AtEof()); +} + TEST_F(QuicHttpStreamTest, DestroyedEarly) { SetRequestString("GET", "/"); AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0, request_data_)); |