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_server_stream.h"
      6 
      7 #include "net/quic/quic_session.h"
      8 #include "net/spdy/spdy_framer.h"
      9 #include "net/tools/quic/spdy_utils.h"
     10 
     11 using std::string;
     12 
     13 namespace net {
     14 namespace tools {
     15 
     16 static const size_t kHeaderBufInitialSize = 4096;
     17 
     18 QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id,
     19                                            QuicSession* session)
     20     : QuicReliableServerStream(id, session),
     21       read_buf_(new GrowableIOBuffer()),
     22       request_headers_received_(false) {
     23 }
     24 
     25 QuicSpdyServerStream::~QuicSpdyServerStream() {
     26 }
     27 
     28 uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 length) {
     29   uint32 total_bytes_processed = 0;
     30 
     31   // Are we still reading the request headers.
     32   if (!request_headers_received_) {
     33     // Grow the read buffer if necessary.
     34     if (read_buf_->RemainingCapacity() < (int)length) {
     35       read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
     36     }
     37     memcpy(read_buf_->data(), data, length);
     38     read_buf_->set_offset(read_buf_->offset() + length);
     39     ParseRequestHeaders();
     40   } else {
     41     mutable_body()->append(data + total_bytes_processed,
     42                            length - total_bytes_processed);
     43   }
     44   return length;
     45 }
     46 
     47 void QuicSpdyServerStream::TerminateFromPeer(bool half_close) {
     48   ReliableQuicStream::TerminateFromPeer(half_close);
     49   // This is a full close: do not send a response.
     50   if (!half_close) {
     51     return;
     52   }
     53   if (write_side_closed() || fin_buffered()) {
     54     return;
     55   }
     56 
     57   if (!request_headers_received_) {
     58     SendErrorResponse();  // We're not done writing headers.
     59   } else if ((headers().content_length_status() ==
     60              BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
     61              mutable_body()->size() != headers().content_length()) {
     62     SendErrorResponse();  // Invalid content length
     63   } else {
     64     SendResponse();
     65   }
     66 }
     67 
     68 void QuicSpdyServerStream::SendHeaders(
     69     const BalsaHeaders& response_headers) {
     70   SpdyHeaderBlock header_block =
     71       SpdyUtils::ResponseHeadersToSpdyHeaders(response_headers);
     72   string headers =
     73       session()->compressor()->CompressHeaders(header_block);
     74 
     75   WriteData(headers, false);
     76 }
     77 
     78 int QuicSpdyServerStream::ParseRequestHeaders() {
     79   size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
     80   SpdyFramer framer(SPDY3);
     81   SpdyHeaderBlock headers;
     82   char* data = read_buf_->StartOfBuffer();
     83   size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(),
     84                                                &headers);
     85   if (len == 0) {
     86     return -1;
     87   }
     88 
     89   if (!SpdyUtils::FillBalsaRequestHeaders(headers, mutable_headers())) {
     90     SendErrorResponse();
     91     return -1;
     92   }
     93 
     94   size_t delta = read_buf_len - len;
     95   if (delta > 0) {
     96     mutable_body()->append(data + len, delta);
     97   }
     98 
     99   request_headers_received_ = true;
    100   return len;
    101 }
    102 
    103 }  // namespace tools
    104 }  // namespace net
    105