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 "base/strings/string_number_conversions.h"
      9 #include "net/quic/quic_in_memory_cache.h"
     10 #include "net/quic/quic_session.h"
     11 #include "net/quic/spdy_utils.h"
     12 #include "net/spdy/spdy_framer.h"
     13 #include "net/spdy/spdy_header_block.h"
     14 #include "net/spdy/spdy_http_utils.h"
     15 
     16 using base::StringPiece;
     17 using std::string;
     18 
     19 namespace net {
     20 
     21 static const size_t kHeaderBufInitialSize = 4096;
     22 
     23 QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id,
     24                                            QuicSession* session)
     25     : QuicDataStream(id, session),
     26       read_buf_(new GrowableIOBuffer()),
     27       request_headers_received_(false) {
     28   read_buf_->SetCapacity(kHeaderBufInitialSize);
     29 }
     30 
     31 QuicSpdyServerStream::~QuicSpdyServerStream() {
     32 }
     33 
     34 uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 data_len) {
     35   if (data_len > INT_MAX) {
     36     LOG(DFATAL) << "Data length too long: " << data_len;
     37     return 0;
     38   }
     39   // Are we still reading the request headers.
     40   if (!request_headers_received_) {
     41     // Grow the read buffer if necessary.
     42     while (read_buf_->RemainingCapacity() < static_cast<int>(data_len)) {
     43       read_buf_->SetCapacity(read_buf_->capacity() * 2);
     44     }
     45     memcpy(read_buf_->data(), data, data_len);
     46     read_buf_->set_offset(read_buf_->offset() + data_len);
     47     // Try parsing the request headers. This will set request_headers_received_
     48     // if successful; if not, it will be tried again with more data.
     49     ParseRequestHeaders();
     50   } else {
     51     body_.append(data, data_len);
     52   }
     53   return data_len;
     54 }
     55 
     56 void QuicSpdyServerStream::OnFinRead() {
     57   ReliableQuicStream::OnFinRead();
     58   if (write_side_closed() || fin_buffered()) {
     59     return;
     60   }
     61 
     62   if (!request_headers_received_) {
     63     SendErrorResponse();  // We're not done reading headers.
     64     return;
     65   }
     66 
     67   SpdyHeaderBlock::const_iterator it = headers_.find("content-length");
     68   size_t content_length;
     69   if (it != headers_.end() &&
     70       (!base::StringToSizeT(it->second, &content_length) ||
     71        body_.size() != content_length)) {
     72     SendErrorResponse();  // Invalid content length
     73     return;
     74   }
     75 
     76   SendResponse();
     77 }
     78 
     79 // Try parsing the request headers. If successful, sets
     80 // request_headers_received_. If not successful, it can just be tried again once
     81 // there's more data.
     82 void QuicSpdyServerStream::ParseRequestHeaders() {
     83   SpdyFramer framer((kDefaultSpdyMajorVersion));
     84   const char* data = read_buf_->StartOfBuffer();
     85   size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
     86   size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_len, &headers_);
     87   if (len == 0) {
     88     // Not enough data yet, presumably. (If we still don't succeed by the end of
     89     // the stream, then we'll error in OnFinRead().)
     90     return;
     91   }
     92 
     93   // Headers received and parsed: extract the request URL.
     94   request_url_ = GetUrlFromHeaderBlock(headers_,
     95                                        kDefaultSpdyMajorVersion,
     96                                        false);
     97   if (!request_url_.is_valid()) {
     98     SendErrorResponse();
     99     return;
    100   }
    101 
    102   // Add any data past the headers to the request body.
    103   size_t delta = read_buf_len - len;
    104   if (delta > 0) {
    105     body_.append(data + len, delta);
    106   }
    107 
    108   request_headers_received_ = true;
    109 }
    110 
    111 void QuicSpdyServerStream::SendResponse() {
    112   // Find response in cache. If not found, send error response.
    113   const QuicInMemoryCache::Response* response =
    114       QuicInMemoryCache::GetInstance()->GetResponse(request_url_);
    115   if (response == NULL) {
    116     SendErrorResponse();
    117     return;
    118   }
    119 
    120   if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) {
    121     DVLOG(1) << "Special response: closing connection.";
    122     CloseConnection(QUIC_NO_ERROR);
    123     return;
    124   }
    125 
    126   if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) {
    127     DVLOG(1) << "Special response: ignoring request.";
    128     return;
    129   }
    130 
    131   DVLOG(1) << "Sending response for stream " << id();
    132   SendHeadersAndBody(response->headers(), response->body());
    133 }
    134 
    135 void QuicSpdyServerStream::SendErrorResponse() {
    136   DVLOG(1) << "Sending error response for stream " << id();
    137   scoped_refptr<HttpResponseHeaders> headers
    138       = new HttpResponseHeaders(string("HTTP/1.1 500 Server Error") + '\0' +
    139                                 "content-length: 3" + '\0' + '\0');
    140   SendHeadersAndBody(*headers.get(), "bad");
    141 }
    142 
    143 void QuicSpdyServerStream::SendHeadersAndBody(
    144     const HttpResponseHeaders& response_headers,
    145     StringPiece body) {
    146   // We only support SPDY and HTTP, and neither handles bidirectional streaming.
    147   if (!read_side_closed()) {
    148     CloseReadSide();
    149   }
    150 
    151   SpdyHeaderBlock header_block;
    152   CreateSpdyHeadersFromHttpResponse(response_headers,
    153                                     kDefaultSpdyMajorVersion,
    154                                     &header_block);
    155 
    156   WriteHeaders(header_block, body.empty(), NULL);
    157 
    158   if (!body.empty()) {
    159     WriteOrBufferData(body, true, NULL);
    160   }
    161 }
    162 
    163 }  // namespace net
    164