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 13 using base::StringPiece; 14 using std::string; 15 16 namespace net { 17 namespace tools { 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 void 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; 76 } 77 78 if (!SpdyUtils::FillBalsaRequestHeaders(headers, &headers_)) { 79 SendErrorResponse(); 80 return; 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 } 90 91 void QuicSpdyServerStream::SendResponse() { 92 // Find response in cache. If not found, send error response. 93 const QuicInMemoryCache::Response* response = 94 QuicInMemoryCache::GetInstance()->GetResponse(headers_); 95 if (response == NULL) { 96 SendErrorResponse(); 97 return; 98 } 99 100 if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) { 101 DVLOG(1) << "Special response: closing connection."; 102 CloseConnection(QUIC_NO_ERROR); 103 return; 104 } 105 106 if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) { 107 DVLOG(1) << "Special response: ignoring request."; 108 return; 109 } 110 111 DVLOG(1) << "Sending response for stream " << id(); 112 SendHeadersAndBody(response->headers(), response->body()); 113 } 114 115 void QuicSpdyServerStream::SendErrorResponse() { 116 DVLOG(1) << "Sending error response for stream " << id(); 117 BalsaHeaders headers; 118 headers.SetResponseFirstlineFromStringPieces( 119 "HTTP/1.1", "500", "Server Error"); 120 headers.ReplaceOrAppendHeader("content-length", "3"); 121 SendHeadersAndBody(headers, "bad"); 122 } 123 124 void QuicSpdyServerStream::SendHeadersAndBody( 125 const BalsaHeaders& response_headers, 126 StringPiece body) { 127 // We only support SPDY and HTTP, and neither handles bidirectional streaming. 128 if (!read_side_closed()) { 129 CloseReadSide(); 130 } 131 132 SpdyHeaderBlock header_block = 133 SpdyUtils::ResponseHeadersToSpdyHeaders(response_headers); 134 135 WriteHeaders(header_block, body.empty(), NULL); 136 137 if (!body.empty()) { 138 WriteOrBufferData(body, true, NULL); 139 } 140 } 141 142 } // namespace tools 143 } // namespace net 144