Home | History | Annotate | Download | only in quic
      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.
      4 
      5 #include "net/quic/quic_http_stream.h"
      6 
      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_reliable_client_stream.h"
     15 #include "net/quic/quic_utils.h"
     16 #include "net/socket/next_proto.h"
     17 #include "net/spdy/spdy_frame_builder.h"
     18 #include "net/spdy/spdy_framer.h"
     19 #include "net/spdy/spdy_http_utils.h"
     20 #include "net/ssl/ssl_info.h"
     21 
     22 namespace net {
     23 
     24 static const size_t kHeaderBufInitialSize = 4096;
     25 
     26 QuicHttpStream::QuicHttpStream(const base::WeakPtr<QuicClientSession> session)
     27     : next_state_(STATE_NONE),
     28       session_(session),
     29       stream_(NULL),
     30       request_info_(NULL),
     31       request_body_stream_(NULL),
     32       response_info_(NULL),
     33       response_status_(OK),
     34       response_headers_received_(false),
     35       read_buf_(new GrowableIOBuffer()),
     36       user_buffer_len_(0),
     37       weak_factory_(this) {
     38   DCHECK(session_);
     39 }
     40 
     41 QuicHttpStream::~QuicHttpStream() {
     42   Close(false);
     43 }
     44 
     45 int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info,
     46                                      RequestPriority priority,
     47                                      const BoundNetLog& stream_net_log,
     48                                      const CompletionCallback& callback) {
     49   DCHECK(!stream_);
     50   if (!session_)
     51     return ERR_CONNECTION_CLOSED;
     52 
     53   stream_net_log_ = stream_net_log;
     54   request_info_ = request_info;
     55 
     56   int rv = stream_request_.StartRequest(
     57       session_, &stream_, base::Bind(&QuicHttpStream::OnStreamReady,
     58                                      weak_factory_.GetWeakPtr()));
     59   if (rv == ERR_IO_PENDING)
     60     callback_ = callback;
     61 
     62   if (rv == OK)
     63     stream_->SetDelegate(this);
     64 
     65   return rv;
     66 }
     67 
     68 void QuicHttpStream::OnStreamReady(int rv) {
     69   DCHECK(rv == OK || !stream_);
     70   if (rv == OK)
     71     stream_->SetDelegate(this);
     72 
     73   ResetAndReturn(&callback_).Run(rv);
     74 }
     75 
     76 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
     77                                 HttpResponseInfo* response,
     78                                 const CompletionCallback& callback) {
     79   CHECK(stream_);
     80   CHECK(!request_body_stream_);
     81   CHECK(!response_info_);
     82   CHECK(!callback.is_null());
     83   CHECK(response);
     84 
     85   // Store the serialized request headers.
     86   SpdyHeaderBlock headers;
     87   CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers,
     88                                    &headers, 3, /*direct=*/true);
     89   request_ = stream_->compressor()->CompressHeaders(headers);
     90   // Log the actual request with the URL Request's net log.
     91   stream_net_log_.AddEvent(
     92       NetLog::TYPE_HTTP_TRANSACTION_SPDY_SEND_REQUEST_HEADERS,
     93       base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
     94   // Also log to the QuicSession's net log.
     95   stream_->net_log().AddEvent(
     96       NetLog::TYPE_QUIC_HTTP_STREAM_SEND_REQUEST_HEADERS,
     97       base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
     98 
     99   // Store the request body.
    100   request_body_stream_ = request_info_->upload_data_stream;
    101   if (request_body_stream_) {
    102     // TODO(rch): Can we be more precise about when to allocate
    103     // raw_request_body_buf_. Removed the following check. DoReadRequestBody()
    104     // was being called even if we didn't yet allocate raw_request_body_buf_.
    105     //   && (request_body_stream_->size() ||
    106     //       request_body_stream_->is_chunked()))
    107     //
    108     // Use kMaxPacketSize as the buffer size, since the request
    109     // body data is written with this size at a time.
    110     // TODO(rch): use a smarter value since we can't write an entire
    111     // packet due to overhead.
    112     raw_request_body_buf_ = new IOBufferWithSize(kMaxPacketSize);
    113     // The request body buffer is empty at first.
    114     request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0);
    115   }
    116 
    117   // Store the response info.
    118   response_info_ = response;
    119 
    120   next_state_ = STATE_SEND_HEADERS;
    121   int rv = DoLoop(OK);
    122   if (rv == ERR_IO_PENDING)
    123     callback_ = callback;
    124 
    125   return rv > 0 ? OK : rv;
    126 }
    127 
    128 UploadProgress QuicHttpStream::GetUploadProgress() const {
    129   if (!request_body_stream_)
    130     return UploadProgress();
    131 
    132   return UploadProgress(request_body_stream_->position(),
    133                         request_body_stream_->size());
    134 }
    135 
    136 int QuicHttpStream::ReadResponseHeaders(const CompletionCallback& callback) {
    137   CHECK(!callback.is_null());
    138 
    139   if (stream_ == NULL)
    140     return response_status_;
    141 
    142   // Check if we already have the response headers. If so, return synchronously.
    143   if (response_headers_received_)
    144     return OK;
    145 
    146   // Still waiting for the response, return IO_PENDING.
    147   CHECK(callback_.is_null());
    148   callback_ = callback;
    149   return ERR_IO_PENDING;
    150 }
    151 
    152 const HttpResponseInfo* QuicHttpStream::GetResponseInfo() const {
    153   return response_info_;
    154 }
    155 
    156 int QuicHttpStream::ReadResponseBody(
    157     IOBuffer* buf, int buf_len, const CompletionCallback& callback) {
    158   CHECK(buf);
    159   CHECK(buf_len);
    160   CHECK(!callback.is_null());
    161 
    162   // If we have data buffered, complete the IO immediately.
    163   if (!response_body_.empty()) {
    164     int bytes_read = 0;
    165     while (!response_body_.empty() && buf_len > 0) {
    166       scoped_refptr<IOBufferWithSize> data = response_body_.front();
    167       const int bytes_to_copy = std::min(buf_len, data->size());
    168       memcpy(&(buf->data()[bytes_read]), data->data(), bytes_to_copy);
    169       buf_len -= bytes_to_copy;
    170       if (bytes_to_copy == data->size()) {
    171         response_body_.pop_front();
    172       } else {
    173         const int bytes_remaining = data->size() - bytes_to_copy;
    174         IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining);
    175         memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]),
    176                bytes_remaining);
    177         response_body_.pop_front();
    178         response_body_.push_front(make_scoped_refptr(new_buffer));
    179       }
    180       bytes_read += bytes_to_copy;
    181     }
    182     return bytes_read;
    183   }
    184 
    185   if (!stream_) {
    186     // If the stream is already closed, there is no body to read.
    187     return response_status_;
    188   }
    189 
    190   CHECK(callback_.is_null());
    191   CHECK(!user_buffer_.get());
    192   CHECK_EQ(0, user_buffer_len_);
    193 
    194   callback_ = callback;
    195   user_buffer_ = buf;
    196   user_buffer_len_ = buf_len;
    197   return ERR_IO_PENDING;
    198 }
    199 
    200 void QuicHttpStream::Close(bool not_reusable) {
    201   // Note: the not_reusable flag has no meaning for SPDY streams.
    202   if (stream_) {
    203     stream_->SetDelegate(NULL);
    204     stream_->Close(QUIC_STREAM_NO_ERROR);
    205     stream_ = NULL;
    206   }
    207 }
    208 
    209 HttpStream* QuicHttpStream::RenewStreamForAuth() {
    210   return NULL;
    211 }
    212 
    213 bool QuicHttpStream::IsResponseBodyComplete() const {
    214   return next_state_ == STATE_OPEN && !stream_;
    215 }
    216 
    217 bool QuicHttpStream::CanFindEndOfResponse() const {
    218   return true;
    219 }
    220 
    221 bool QuicHttpStream::IsConnectionReused() const {
    222   // TODO(rch): do something smarter here.
    223   return stream_ && stream_->id() > 1;
    224 }
    225 
    226 void QuicHttpStream::SetConnectionReused() {
    227   // QUIC doesn't need an indicator here.
    228 }
    229 
    230 bool QuicHttpStream::IsConnectionReusable() const {
    231   // QUIC streams aren't considered reusable.
    232   return false;
    233 }
    234 
    235 bool QuicHttpStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
    236   // TODO(mmenke):  Figure out what to do here.
    237   return true;
    238 }
    239 
    240 void QuicHttpStream::GetSSLInfo(SSLInfo* ssl_info) {
    241   DCHECK(stream_);
    242   stream_->GetSSLInfo(ssl_info);
    243 }
    244 
    245 void QuicHttpStream::GetSSLCertRequestInfo(
    246     SSLCertRequestInfo* cert_request_info) {
    247   DCHECK(stream_);
    248   NOTIMPLEMENTED();
    249 }
    250 
    251 bool QuicHttpStream::IsSpdyHttpStream() const {
    252   return false;
    253 }
    254 
    255 void QuicHttpStream::Drain(HttpNetworkSession* session) {
    256   Close(false);
    257   delete this;
    258 }
    259 
    260 int QuicHttpStream::OnSendData() {
    261   // TODO(rch): Change QUIC IO to provide notifications to the streams.
    262   NOTREACHED();
    263   return OK;
    264 }
    265 
    266 int QuicHttpStream::OnSendDataComplete(int status, bool* eof) {
    267   // TODO(rch): Change QUIC IO to provide notifications to the streams.
    268   NOTREACHED();
    269   return OK;
    270 }
    271 
    272 int QuicHttpStream::OnDataReceived(const char* data, int length) {
    273   DCHECK_NE(0, length);
    274   // Are we still reading the response headers.
    275   if (!response_headers_received_) {
    276     // Grow the read buffer if necessary.
    277     if (read_buf_->RemainingCapacity() < length) {
    278       read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
    279     }
    280     memcpy(read_buf_->data(), data, length);
    281     read_buf_->set_offset(read_buf_->offset() + length);
    282     int rv = ParseResponseHeaders();
    283     if (rv != ERR_IO_PENDING && !callback_.is_null()) {
    284       DoCallback(rv);
    285     }
    286     return OK;
    287   }
    288 
    289   if (callback_.is_null()) {
    290     BufferResponseBody(data, length);
    291     return OK;
    292   }
    293 
    294   if (length <= user_buffer_len_) {
    295     memcpy(user_buffer_->data(), data, length);
    296   } else {
    297     memcpy(user_buffer_->data(), data, user_buffer_len_);
    298     int delta = length - user_buffer_len_;
    299     BufferResponseBody(data + user_buffer_len_, delta);
    300   }
    301   user_buffer_ = NULL;
    302   user_buffer_len_ = 0;
    303   DoCallback(length);
    304   return OK;
    305 }
    306 
    307 void QuicHttpStream::OnClose(QuicErrorCode error) {
    308   if (error != QUIC_NO_ERROR) {
    309     response_status_ = ERR_QUIC_PROTOCOL_ERROR;
    310   } else if (!response_headers_received_) {
    311     response_status_ = ERR_ABORTED;
    312   }
    313 
    314   stream_ = NULL;
    315   if (!callback_.is_null())
    316     DoCallback(response_status_);
    317 }
    318 
    319 void QuicHttpStream::OnError(int error) {
    320   stream_ = NULL;
    321   response_status_ = error;
    322   if (!callback_.is_null())
    323     DoCallback(response_status_);
    324 }
    325 
    326 void QuicHttpStream::OnIOComplete(int rv) {
    327   rv = DoLoop(rv);
    328 
    329   if (rv != ERR_IO_PENDING && !callback_.is_null()) {
    330     DoCallback(rv);
    331   }
    332 }
    333 
    334 void QuicHttpStream::DoCallback(int rv) {
    335   CHECK_NE(rv, ERR_IO_PENDING);
    336   CHECK(!callback_.is_null());
    337 
    338   // The client callback can do anything, including destroying this class,
    339   // so any pending callback must be issued after everything else is done.
    340   base::ResetAndReturn(&callback_).Run(rv);
    341 }
    342 
    343 int QuicHttpStream::DoLoop(int rv) {
    344   do {
    345     State state = next_state_;
    346     next_state_ = STATE_NONE;
    347     switch (state) {
    348       case STATE_SEND_HEADERS:
    349         CHECK_EQ(OK, rv);
    350         rv = DoSendHeaders();
    351         break;
    352       case STATE_SEND_HEADERS_COMPLETE:
    353         rv = DoSendHeadersComplete(rv);
    354         break;
    355       case STATE_READ_REQUEST_BODY:
    356         CHECK_EQ(OK, rv);
    357         rv = DoReadRequestBody();
    358         break;
    359       case STATE_READ_REQUEST_BODY_COMPLETE:
    360         rv = DoReadRequestBodyComplete(rv);
    361         break;
    362       case STATE_SEND_BODY:
    363         CHECK_EQ(OK, rv);
    364         rv = DoSendBody();
    365         break;
    366       case STATE_SEND_BODY_COMPLETE:
    367         rv = DoSendBodyComplete(rv);
    368         break;
    369       case STATE_OPEN:
    370         CHECK_EQ(OK, rv);
    371         break;
    372       default:
    373         NOTREACHED() << "next_state_: " << next_state_;
    374         break;
    375     }
    376   } while (next_state_ != STATE_NONE && next_state_ != STATE_OPEN &&
    377            rv != ERR_IO_PENDING);
    378 
    379   return rv;
    380 }
    381 
    382 int QuicHttpStream::DoSendHeaders() {
    383   if (!stream_)
    384     return ERR_UNEXPECTED;
    385 
    386   bool has_upload_data = request_body_stream_ != NULL;
    387 
    388   next_state_ = STATE_SEND_HEADERS_COMPLETE;
    389   QuicConsumedData rv = stream_->WriteData(request_, !has_upload_data);
    390   return rv.bytes_consumed;
    391 }
    392 
    393 int QuicHttpStream::DoSendHeadersComplete(int rv) {
    394   if (rv < 0)
    395     return rv;
    396 
    397   next_state_ = request_body_stream_ ?
    398       STATE_READ_REQUEST_BODY : STATE_OPEN;
    399 
    400   return OK;
    401 }
    402 
    403 int QuicHttpStream::DoReadRequestBody() {
    404   next_state_ = STATE_READ_REQUEST_BODY_COMPLETE;
    405   return request_body_stream_->Read(
    406       raw_request_body_buf_.get(),
    407       raw_request_body_buf_->size(),
    408       base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr()));
    409 }
    410 
    411 int QuicHttpStream::DoReadRequestBodyComplete(int rv) {
    412   // |rv| is the result of read from the request body from the last call to
    413   // DoSendBody().
    414   if (rv < 0)
    415     return rv;
    416 
    417   request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), rv);
    418   if (rv == 0) {  // Reached the end.
    419     DCHECK(request_body_stream_->IsEOF());
    420   }
    421 
    422   next_state_ = STATE_SEND_BODY;
    423   return OK;
    424 }
    425 
    426 int QuicHttpStream::DoSendBody() {
    427   if (!stream_)
    428     return ERR_UNEXPECTED;
    429 
    430   CHECK(request_body_stream_);
    431   CHECK(request_body_buf_.get());
    432   const bool eof = request_body_stream_->IsEOF();
    433   int len = request_body_buf_->BytesRemaining();
    434   if (len > 0 || eof) {
    435     base::StringPiece data(request_body_buf_->data(), len);
    436     QuicConsumedData rv = stream_->WriteData(data, eof);
    437     request_body_buf_->DidConsume(rv.bytes_consumed);
    438     if (eof) {
    439       next_state_ = STATE_OPEN;
    440       return OK;
    441     }
    442     next_state_ = STATE_SEND_BODY_COMPLETE;
    443     return rv.bytes_consumed;
    444   }
    445 
    446   next_state_ = STATE_SEND_BODY_COMPLETE;
    447   return OK;
    448 }
    449 
    450 int QuicHttpStream::DoSendBodyComplete(int rv) {
    451   if (rv < 0)
    452     return rv;
    453 
    454   next_state_ = STATE_READ_REQUEST_BODY;
    455   return OK;
    456 }
    457 
    458 int QuicHttpStream::ParseResponseHeaders() {
    459   size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
    460   SpdyFramer framer(SPDY3);
    461   SpdyHeaderBlock headers;
    462   char* data = read_buf_->StartOfBuffer();
    463   size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(),
    464                                                &headers);
    465 
    466   if (len == 0) {
    467     return ERR_IO_PENDING;
    468   }
    469 
    470   // Save the remaining received data.
    471   size_t delta = read_buf_len - len;
    472   if (delta > 0) {
    473     BufferResponseBody(data + len, delta);
    474   }
    475 
    476   // The URLRequest logs these headers, so only log to the QuicSession's
    477   // net log.
    478   stream_->net_log().AddEvent(
    479       NetLog::TYPE_QUIC_HTTP_STREAM_READ_RESPONSE_HEADERS,
    480       base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
    481 
    482   if (!SpdyHeadersToHttpResponse(headers, 3, response_info_)) {
    483     DLOG(WARNING) << "Invalid headers";
    484     return ERR_QUIC_PROTOCOL_ERROR;
    485   }
    486   // Put the peer's IP address and port into the response.
    487   IPEndPoint address = stream_->GetPeerAddress();
    488   response_info_->socket_address = HostPortPair::FromIPEndPoint(address);
    489   response_info_->connection_info =
    490       HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3;
    491   response_info_->vary_data
    492       .Init(*request_info_, *response_info_->headers.get());
    493   response_info_->was_npn_negotiated = true;
    494   response_info_->npn_negotiated_protocol = "quic/1+spdy/3";
    495   response_headers_received_ = true;
    496 
    497   return OK;
    498 }
    499 
    500 void QuicHttpStream::BufferResponseBody(const char* data, int length) {
    501   if (length == 0)
    502     return;
    503   IOBufferWithSize* io_buffer = new IOBufferWithSize(length);
    504   memcpy(io_buffer->data(), data, length);
    505   response_body_.push_back(make_scoped_refptr(io_buffer));
    506 }
    507 
    508 }  // namespace net
    509