Revert "Removed the experimental flag for Chromecast support and the corresponding...
[chromium-blink-merge.git] / net / quic / quic_http_stream.cc
blob79ab0016008d845a979ea7226b1a4bc4549ce03c
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/quic_http_stream.h"
7 #include "base/callback_helpers.h"
8 #include "base/strings/stringprintf.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11 #include "net/http/http_response_headers.h"
12 #include "net/http/http_util.h"
13 #include "net/quic/quic_client_session.h"
14 #include "net/quic/quic_http_utils.h"
15 #include "net/quic/quic_reliable_client_stream.h"
16 #include "net/quic/quic_utils.h"
17 #include "net/socket/next_proto.h"
18 #include "net/spdy/spdy_frame_builder.h"
19 #include "net/spdy/spdy_framer.h"
20 #include "net/spdy/spdy_http_utils.h"
21 #include "net/ssl/ssl_info.h"
23 namespace net {
25 static const size_t kHeaderBufInitialSize = 4096;
27 QuicHttpStream::QuicHttpStream(const base::WeakPtr<QuicClientSession> session)
28 : next_state_(STATE_NONE),
29 session_(session),
30 stream_(NULL),
31 request_info_(NULL),
32 request_body_stream_(NULL),
33 priority_(MINIMUM_PRIORITY),
34 response_info_(NULL),
35 response_status_(OK),
36 response_headers_received_(false),
37 read_buf_(new GrowableIOBuffer()),
38 user_buffer_len_(0),
39 weak_factory_(this) {
40 DCHECK(session_);
43 QuicHttpStream::~QuicHttpStream() {
44 Close(false);
47 int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info,
48 RequestPriority priority,
49 const BoundNetLog& stream_net_log,
50 const CompletionCallback& callback) {
51 DCHECK(!stream_);
52 if (!session_)
53 return ERR_CONNECTION_CLOSED;
55 stream_net_log_ = stream_net_log;
56 request_info_ = request_info;
57 priority_ = priority;
59 int rv = stream_request_.StartRequest(
60 session_, &stream_, base::Bind(&QuicHttpStream::OnStreamReady,
61 weak_factory_.GetWeakPtr()));
62 if (rv == ERR_IO_PENDING)
63 callback_ = callback;
65 if (rv == OK)
66 stream_->SetDelegate(this);
68 return rv;
71 void QuicHttpStream::OnStreamReady(int rv) {
72 DCHECK(rv == OK || !stream_);
73 if (rv == OK)
74 stream_->SetDelegate(this);
76 ResetAndReturn(&callback_).Run(rv);
79 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
80 HttpResponseInfo* response,
81 const CompletionCallback& callback) {
82 CHECK(stream_);
83 CHECK(!request_body_stream_);
84 CHECK(!response_info_);
85 CHECK(!callback.is_null());
86 CHECK(response);
88 QuicPriority priority = ConvertRequestPriorityToQuicPriority(priority_);
89 stream_->set_priority(priority);
90 // Store the serialized request headers.
91 SpdyHeaderBlock headers;
92 CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers,
93 &headers, 3, /*direct=*/true);
94 request_ = stream_->compressor()->CompressHeadersWithPriority(priority,
95 headers);
96 // Log the actual request with the URL Request's net log.
97 stream_net_log_.AddEvent(
98 NetLog::TYPE_HTTP_TRANSACTION_SPDY_SEND_REQUEST_HEADERS,
99 base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
100 // Also log to the QuicSession's net log.
101 stream_->net_log().AddEvent(
102 NetLog::TYPE_QUIC_HTTP_STREAM_SEND_REQUEST_HEADERS,
103 base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
105 // Store the request body.
106 request_body_stream_ = request_info_->upload_data_stream;
107 if (request_body_stream_) {
108 // TODO(rch): Can we be more precise about when to allocate
109 // raw_request_body_buf_. Removed the following check. DoReadRequestBody()
110 // was being called even if we didn't yet allocate raw_request_body_buf_.
111 // && (request_body_stream_->size() ||
112 // request_body_stream_->is_chunked()))
114 // Use kMaxPacketSize as the buffer size, since the request
115 // body data is written with this size at a time.
116 // TODO(rch): use a smarter value since we can't write an entire
117 // packet due to overhead.
118 raw_request_body_buf_ = new IOBufferWithSize(kMaxPacketSize);
119 // The request body buffer is empty at first.
120 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0);
123 // Store the response info.
124 response_info_ = response;
126 next_state_ = STATE_SEND_HEADERS;
127 int rv = DoLoop(OK);
128 if (rv == ERR_IO_PENDING)
129 callback_ = callback;
131 return rv > 0 ? OK : rv;
134 UploadProgress QuicHttpStream::GetUploadProgress() const {
135 if (!request_body_stream_)
136 return UploadProgress();
138 return UploadProgress(request_body_stream_->position(),
139 request_body_stream_->size());
142 int QuicHttpStream::ReadResponseHeaders(const CompletionCallback& callback) {
143 CHECK(!callback.is_null());
145 if (stream_ == NULL)
146 return response_status_;
148 // Check if we already have the response headers. If so, return synchronously.
149 if (response_headers_received_)
150 return OK;
152 // Still waiting for the response, return IO_PENDING.
153 CHECK(callback_.is_null());
154 callback_ = callback;
155 return ERR_IO_PENDING;
158 const HttpResponseInfo* QuicHttpStream::GetResponseInfo() const {
159 return response_info_;
162 int QuicHttpStream::ReadResponseBody(
163 IOBuffer* buf, int buf_len, const CompletionCallback& callback) {
164 CHECK(buf);
165 CHECK(buf_len);
166 CHECK(!callback.is_null());
168 // If we have data buffered, complete the IO immediately.
169 if (!response_body_.empty()) {
170 int bytes_read = 0;
171 while (!response_body_.empty() && buf_len > 0) {
172 scoped_refptr<IOBufferWithSize> data = response_body_.front();
173 const int bytes_to_copy = std::min(buf_len, data->size());
174 memcpy(&(buf->data()[bytes_read]), data->data(), bytes_to_copy);
175 buf_len -= bytes_to_copy;
176 if (bytes_to_copy == data->size()) {
177 response_body_.pop_front();
178 } else {
179 const int bytes_remaining = data->size() - bytes_to_copy;
180 IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining);
181 memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]),
182 bytes_remaining);
183 response_body_.pop_front();
184 response_body_.push_front(make_scoped_refptr(new_buffer));
186 bytes_read += bytes_to_copy;
188 return bytes_read;
191 if (!stream_) {
192 // If the stream is already closed, there is no body to read.
193 return response_status_;
196 CHECK(callback_.is_null());
197 CHECK(!user_buffer_.get());
198 CHECK_EQ(0, user_buffer_len_);
200 callback_ = callback;
201 user_buffer_ = buf;
202 user_buffer_len_ = buf_len;
203 return ERR_IO_PENDING;
206 void QuicHttpStream::Close(bool not_reusable) {
207 // Note: the not_reusable flag has no meaning for SPDY streams.
208 if (stream_) {
209 stream_->SetDelegate(NULL);
210 // TODO(rch): use new CANCELLED error code here once quic 11
211 // is everywhere.
212 stream_->Close(QUIC_ERROR_PROCESSING_STREAM);
213 stream_ = NULL;
217 HttpStream* QuicHttpStream::RenewStreamForAuth() {
218 return NULL;
221 bool QuicHttpStream::IsResponseBodyComplete() const {
222 return next_state_ == STATE_OPEN && !stream_;
225 bool QuicHttpStream::CanFindEndOfResponse() const {
226 return true;
229 bool QuicHttpStream::IsConnectionReused() const {
230 // TODO(rch): do something smarter here.
231 return stream_ && stream_->id() > 1;
234 void QuicHttpStream::SetConnectionReused() {
235 // QUIC doesn't need an indicator here.
238 bool QuicHttpStream::IsConnectionReusable() const {
239 // QUIC streams aren't considered reusable.
240 return false;
243 bool QuicHttpStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
244 // TODO(mmenke): Figure out what to do here.
245 return true;
248 void QuicHttpStream::GetSSLInfo(SSLInfo* ssl_info) {
249 DCHECK(stream_);
250 stream_->GetSSLInfo(ssl_info);
253 void QuicHttpStream::GetSSLCertRequestInfo(
254 SSLCertRequestInfo* cert_request_info) {
255 DCHECK(stream_);
256 NOTIMPLEMENTED();
259 bool QuicHttpStream::IsSpdyHttpStream() const {
260 return false;
263 void QuicHttpStream::Drain(HttpNetworkSession* session) {
264 Close(false);
265 delete this;
268 void QuicHttpStream::SetPriority(RequestPriority priority) {
269 priority_ = priority;
272 int QuicHttpStream::OnSendData() {
273 // TODO(rch): Change QUIC IO to provide notifications to the streams.
274 NOTREACHED();
275 return OK;
278 int QuicHttpStream::OnSendDataComplete(int status, bool* eof) {
279 // TODO(rch): Change QUIC IO to provide notifications to the streams.
280 NOTREACHED();
281 return OK;
284 int QuicHttpStream::OnDataReceived(const char* data, int length) {
285 DCHECK_NE(0, length);
286 // Are we still reading the response headers.
287 if (!response_headers_received_) {
288 // Grow the read buffer if necessary.
289 if (read_buf_->RemainingCapacity() < length) {
290 size_t additional_capacity = length - read_buf_->RemainingCapacity();
291 if (additional_capacity < kHeaderBufInitialSize)
292 additional_capacity = kHeaderBufInitialSize;
293 read_buf_->SetCapacity(read_buf_->capacity() + additional_capacity);
295 memcpy(read_buf_->data(), data, length);
296 read_buf_->set_offset(read_buf_->offset() + length);
297 int rv = ParseResponseHeaders();
298 if (rv != ERR_IO_PENDING && !callback_.is_null()) {
299 DoCallback(rv);
301 return OK;
304 if (callback_.is_null()) {
305 BufferResponseBody(data, length);
306 return OK;
309 if (length <= user_buffer_len_) {
310 memcpy(user_buffer_->data(), data, length);
311 } else {
312 memcpy(user_buffer_->data(), data, user_buffer_len_);
313 int delta = length - user_buffer_len_;
314 BufferResponseBody(data + user_buffer_len_, delta);
315 length = user_buffer_len_;
318 user_buffer_ = NULL;
319 user_buffer_len_ = 0;
320 DoCallback(length);
321 return OK;
324 void QuicHttpStream::OnClose(QuicErrorCode error) {
325 if (error != QUIC_NO_ERROR) {
326 response_status_ = ERR_QUIC_PROTOCOL_ERROR;
327 } else if (!response_headers_received_) {
328 response_status_ = ERR_ABORTED;
331 stream_ = NULL;
332 if (!callback_.is_null())
333 DoCallback(response_status_);
336 void QuicHttpStream::OnError(int error) {
337 stream_ = NULL;
338 response_status_ = error;
339 if (!callback_.is_null())
340 DoCallback(response_status_);
343 bool QuicHttpStream::HasSendHeadersComplete() {
344 return next_state_ > STATE_SEND_HEADERS_COMPLETE;
347 void QuicHttpStream::OnIOComplete(int rv) {
348 rv = DoLoop(rv);
350 if (rv != ERR_IO_PENDING && !callback_.is_null()) {
351 DoCallback(rv);
355 void QuicHttpStream::DoCallback(int rv) {
356 CHECK_NE(rv, ERR_IO_PENDING);
357 CHECK(!callback_.is_null());
359 // The client callback can do anything, including destroying this class,
360 // so any pending callback must be issued after everything else is done.
361 base::ResetAndReturn(&callback_).Run(rv);
364 int QuicHttpStream::DoLoop(int rv) {
365 do {
366 State state = next_state_;
367 next_state_ = STATE_NONE;
368 switch (state) {
369 case STATE_SEND_HEADERS:
370 CHECK_EQ(OK, rv);
371 rv = DoSendHeaders();
372 break;
373 case STATE_SEND_HEADERS_COMPLETE:
374 rv = DoSendHeadersComplete(rv);
375 break;
376 case STATE_READ_REQUEST_BODY:
377 CHECK_EQ(OK, rv);
378 rv = DoReadRequestBody();
379 break;
380 case STATE_READ_REQUEST_BODY_COMPLETE:
381 rv = DoReadRequestBodyComplete(rv);
382 break;
383 case STATE_SEND_BODY:
384 CHECK_EQ(OK, rv);
385 rv = DoSendBody();
386 break;
387 case STATE_SEND_BODY_COMPLETE:
388 rv = DoSendBodyComplete(rv);
389 break;
390 case STATE_OPEN:
391 CHECK_EQ(OK, rv);
392 break;
393 default:
394 NOTREACHED() << "next_state_: " << next_state_;
395 break;
397 } while (next_state_ != STATE_NONE && next_state_ != STATE_OPEN &&
398 rv != ERR_IO_PENDING);
400 return rv;
403 int QuicHttpStream::DoSendHeaders() {
404 if (!stream_)
405 return ERR_UNEXPECTED;
407 bool has_upload_data = request_body_stream_ != NULL;
409 next_state_ = STATE_SEND_HEADERS_COMPLETE;
410 return stream_->WriteStreamData(
411 request_, !has_upload_data,
412 base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr()));
415 int QuicHttpStream::DoSendHeadersComplete(int rv) {
416 if (rv < 0)
417 return rv;
419 next_state_ = request_body_stream_ ?
420 STATE_READ_REQUEST_BODY : STATE_OPEN;
422 return OK;
425 int QuicHttpStream::DoReadRequestBody() {
426 next_state_ = STATE_READ_REQUEST_BODY_COMPLETE;
427 return request_body_stream_->Read(
428 raw_request_body_buf_.get(),
429 raw_request_body_buf_->size(),
430 base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr()));
433 int QuicHttpStream::DoReadRequestBodyComplete(int rv) {
434 // |rv| is the result of read from the request body from the last call to
435 // DoSendBody().
436 if (rv < 0)
437 return rv;
439 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), rv);
440 if (rv == 0) { // Reached the end.
441 DCHECK(request_body_stream_->IsEOF());
444 next_state_ = STATE_SEND_BODY;
445 return OK;
448 int QuicHttpStream::DoSendBody() {
449 if (!stream_)
450 return ERR_UNEXPECTED;
452 CHECK(request_body_stream_);
453 CHECK(request_body_buf_.get());
454 const bool eof = request_body_stream_->IsEOF();
455 int len = request_body_buf_->BytesRemaining();
456 if (len > 0 || eof) {
457 next_state_ = STATE_SEND_BODY_COMPLETE;
458 base::StringPiece data(request_body_buf_->data(), len);
459 return stream_->WriteStreamData(
460 data, eof,
461 base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr()));
464 next_state_ = STATE_OPEN;
465 return OK;
468 int QuicHttpStream::DoSendBodyComplete(int rv) {
469 if (rv < 0)
470 return rv;
472 request_body_buf_->DidConsume(request_body_buf_->BytesRemaining());
474 if (!request_body_stream_->IsEOF()) {
475 next_state_ = STATE_READ_REQUEST_BODY;
476 return OK;
479 next_state_ = STATE_OPEN;
480 return OK;
483 int QuicHttpStream::ParseResponseHeaders() {
484 size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
485 SpdyFramer framer(SPDY3);
486 SpdyHeaderBlock headers;
487 char* data = read_buf_->StartOfBuffer();
488 size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(),
489 &headers);
491 if (len == 0) {
492 return ERR_IO_PENDING;
495 // Save the remaining received data.
496 size_t delta = read_buf_len - len;
497 if (delta > 0) {
498 BufferResponseBody(data + len, delta);
501 // The URLRequest logs these headers, so only log to the QuicSession's
502 // net log.
503 stream_->net_log().AddEvent(
504 NetLog::TYPE_QUIC_HTTP_STREAM_READ_RESPONSE_HEADERS,
505 base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
507 if (!SpdyHeadersToHttpResponse(headers, 3, response_info_)) {
508 DLOG(WARNING) << "Invalid headers";
509 return ERR_QUIC_PROTOCOL_ERROR;
511 // Put the peer's IP address and port into the response.
512 IPEndPoint address = stream_->GetPeerAddress();
513 response_info_->socket_address = HostPortPair::FromIPEndPoint(address);
514 response_info_->connection_info =
515 HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3;
516 response_info_->vary_data
517 .Init(*request_info_, *response_info_->headers.get());
518 response_info_->was_npn_negotiated = true;
519 response_info_->npn_negotiated_protocol = "quic/1+spdy/3";
520 response_headers_received_ = true;
522 return OK;
525 void QuicHttpStream::BufferResponseBody(const char* data, int length) {
526 if (length == 0)
527 return;
528 IOBufferWithSize* io_buffer = new IOBufferWithSize(length);
529 memcpy(io_buffer->data(), data, length);
530 response_body_.push_back(make_scoped_refptr(io_buffer));
533 } // namespace net