quic_spdy_server_stream.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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 "base/memory/singleton.h" 8#include "net/quic/quic_session.h" 9#include "net/spdy/spdy_framer.h" 10#include "net/tools/quic/quic_in_memory_cache.h" 11#include "net/tools/quic/spdy_utils.h" 12 13using base::StringPiece; 14using std::string; 15 16namespace net { 17namespace tools { 18 19static const size_t kHeaderBufInitialSize = 4096; 20 21QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id, 22 QuicSession* session) 23 : QuicDataStream(id, session), 24 read_buf_(new GrowableIOBuffer()), 25 request_headers_received_(false) { 26} 27 28QuicSpdyServerStream::~QuicSpdyServerStream() { 29} 30 31uint32 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 50void 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 67int 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 92void 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 116void 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 125void 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 tools 144} // namespace net 145