Home | History | Annotate | Download | only in quic
      1 // Copyright 2014 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_spdy_server_stream.h"
      6 
      7 #include "base/memory/singleton.h"
      8 #include "net/quic/quic_in_memory_cache.h"
      9 #include "net/quic/quic_session.h"
     10 #include "net/spdy/spdy_framer.h"
     11 #include "net/tools/quic/spdy_utils.h"
     12 
     13 using base::StringPiece;
     14 using std::string;
     15 using net::tools::SpdyUtils;
     16 
     17 namespace net {
     18 
     19 static const size_t kHeaderBufInitialSize = 4096;
     20 
     21 QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id,
     22                                            QuicSession* session)
     23     : QuicDataStream(id, session),
     24       read_buf_(new GrowableIOBuffer()),
     25       request_headers_received_(false) {
     26 }
     27 
     28 QuicSpdyServerStream::~QuicSpdyServerStream() {
     29 }
     30 
     31 uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 data_len) {
     32   uint32 total_bytes_processed = 0;
     33 
     34   // Are we still reading the request headers.
     35   if (!request_headers_received_) {
     36     // Grow the read buffer if necessary.
     37     if (read_buf_->RemainingCapacity() < (int)data_len) {
     38       read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
     39     }
     40     memcpy(read_buf_->data(), data, data_len);
     41     read_buf_->set_offset(read_buf_->offset() + data_len);
     42     ParseRequestHeaders();
     43   } else {
     44     body_.append(data + total_bytes_processed,
     45                  data_len - total_bytes_processed);
     46   }
     47   return data_len;
     48 }
     49 
     50 void QuicSpdyServerStream::OnFinRead() {
     51   ReliableQuicStream::OnFinRead();
     52   if (write_side_closed() || fin_buffered()) {
     53     return;
     54   }
     55 
     56   if (!request_headers_received_) {
     57     SendErrorResponse();  // We're not done reading headers.
     58   } else if ((headers_.content_length_status() ==
     59               BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
     60              body_.size() != headers_.content_length()) {
     61     SendErrorResponse();  // Invalid content length
     62   } else {
     63     SendResponse();
     64   }
     65 }
     66 
     67 int QuicSpdyServerStream::ParseRequestHeaders() {
     68   size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
     69   SpdyFramer framer(SPDY3);
     70   SpdyHeaderBlock headers;
     71   char* data = read_buf_->StartOfBuffer();
     72   size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(),
     73                                                &headers);
     74   if (len == 0) {
     75     return -1;
     76   }
     77 
     78   if (!SpdyUtils::FillBalsaRequestHeaders(headers, &headers_)) {
     79     SendErrorResponse();
     80     return -1;
     81   }
     82 
     83   size_t delta = read_buf_len - len;
     84   if (delta > 0) {
     85     body_.append(data + len, delta);
     86   }
     87 
     88   request_headers_received_ = true;
     89   return len;
     90 }
     91 
     92 void QuicSpdyServerStream::SendResponse() {
     93   // Find response in cache. If not found, send error response.
     94   const QuicInMemoryCache::Response* response =
     95       QuicInMemoryCache::GetInstance()->GetResponse(headers_);
     96   if (response == NULL) {
     97     SendErrorResponse();
     98     return;
     99   }
    100 
    101   if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) {
    102     DVLOG(1) << "Special response: closing connection.";
    103     CloseConnection(QUIC_NO_ERROR);
    104     return;
    105   }
    106 
    107   if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) {
    108     DVLOG(1) << "Special response: ignoring request.";
    109     return;
    110   }
    111 
    112   DVLOG(1) << "Sending response for stream " << id();
    113   SendHeadersAndBody(response->headers(), response->body());
    114 }
    115 
    116 void QuicSpdyServerStream::SendErrorResponse() {
    117   DVLOG(1) << "Sending error response for stream " << id();
    118   BalsaHeaders headers;
    119   headers.SetResponseFirstlineFromStringPieces(
    120       "HTTP/1.1", "500", "Server Error");
    121   headers.ReplaceOrAppendHeader("content-length", "3");
    122   SendHeadersAndBody(headers, "bad");
    123 }
    124 
    125 void QuicSpdyServerStream::SendHeadersAndBody(
    126     const BalsaHeaders& response_headers,
    127     StringPiece body) {
    128   // We only support SPDY and HTTP, and neither handles bidirectional streaming.
    129   if (!read_side_closed()) {
    130     CloseReadSide();
    131   }
    132 
    133   SpdyHeaderBlock header_block =
    134       SpdyUtils::ResponseHeadersToSpdyHeaders(response_headers);
    135 
    136   WriteHeaders(header_block, body.empty(), NULL);
    137 
    138   if (!body.empty()) {
    139     WriteOrBufferData(body, true, NULL);
    140   }
    141 }
    142 
    143 }  // namespace net
    144