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