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/tools/quic/quic_spdy_client_stream.h"
      6 
      7 #include "net/spdy/spdy_framer.h"
      8 #include "net/tools/quic/quic_client_session.h"
      9 #include "net/tools/quic/spdy_utils.h"
     10 
     11 using base::StringPiece;
     12 using std::string;
     13 
     14 namespace net {
     15 namespace tools {
     16 
     17 static const size_t kHeaderBufInitialSize = 4096;
     18 
     19 QuicSpdyClientStream::QuicSpdyClientStream(QuicStreamId id,
     20                                            QuicClientSession* session)
     21     : QuicDataStream(id, session),
     22       read_buf_(new GrowableIOBuffer()),
     23       response_headers_received_(false) {
     24 }
     25 
     26 QuicSpdyClientStream::~QuicSpdyClientStream() {
     27 }
     28 
     29 bool QuicSpdyClientStream::OnStreamFrame(const QuicStreamFrame& frame) {
     30   if (!write_side_closed()) {
     31     DLOG(INFO) << "Got a response before the request was complete.  "
     32                << "Aborting request.";
     33     CloseWriteSide();
     34   }
     35   return QuicDataStream::OnStreamFrame(frame);
     36 }
     37 
     38 uint32 QuicSpdyClientStream::ProcessData(const char* data, uint32 length) {
     39   uint32 total_bytes_processed = 0;
     40 
     41   // Are we still reading the response headers.
     42   if (!response_headers_received_) {
     43     // Grow the read buffer if necessary.
     44     if (read_buf_->RemainingCapacity() < (int)length) {
     45       read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
     46     }
     47     memcpy(read_buf_->data(), data, length);
     48     read_buf_->set_offset(read_buf_->offset() + length);
     49     ParseResponseHeaders();
     50   } else {
     51     data_.append(data + total_bytes_processed, length - total_bytes_processed);
     52   }
     53   return length;
     54 }
     55 
     56 void QuicSpdyClientStream::OnFinRead() {
     57   ReliableQuicStream::OnFinRead();
     58   if (!response_headers_received_) {
     59     Reset(QUIC_BAD_APPLICATION_PAYLOAD);
     60   } else if ((headers().content_length_status() ==
     61              BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
     62              data_.size() != headers().content_length()) {
     63     Reset(QUIC_BAD_APPLICATION_PAYLOAD);
     64   }
     65 }
     66 
     67 ssize_t QuicSpdyClientStream::SendRequest(const BalsaHeaders& headers,
     68                                           StringPiece body,
     69                                           bool fin) {
     70   SpdyHeaderBlock header_block =
     71       SpdyUtils::RequestHeadersToSpdyHeaders(headers);
     72 
     73   bool send_fin_with_headers = fin && body.empty();
     74   string headers_string = session()->compressor()->CompressHeadersWithPriority(
     75       priority(), header_block);
     76   WriteOrBufferData(headers_string, send_fin_with_headers);
     77 
     78   if (!body.empty()) {
     79     WriteOrBufferData(body, fin);
     80   }
     81 
     82   return headers_string.size() + body.size();
     83 }
     84 
     85 int QuicSpdyClientStream::ParseResponseHeaders() {
     86   size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
     87   SpdyFramer framer(SPDY3);
     88   SpdyHeaderBlock headers;
     89   char* data = read_buf_->StartOfBuffer();
     90   size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(),
     91                                                &headers);
     92   if (len == 0) {
     93     return -1;
     94   }
     95 
     96   if (!SpdyUtils::FillBalsaResponseHeaders(headers, &headers_)) {
     97     Reset(QUIC_BAD_APPLICATION_PAYLOAD);
     98     return -1;
     99   }
    100   response_headers_received_ = true;
    101 
    102   size_t delta = read_buf_len - len;
    103   if (delta > 0) {
    104     data_.append(data + len, delta);
    105   }
    106 
    107   return len;
    108 }
    109 
    110 // Sends body data to the server and returns the number of bytes sent.
    111 void QuicSpdyClientStream::SendBody(const string& data, bool fin) {
    112   return WriteOrBufferData(data, fin);
    113 }
    114 
    115 }  // namespace tools
    116 }  // namespace net
    117