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_client_stream.h" 6 7#include "net/spdy/spdy_framer.h" 8#include "net/tools/quic/quic_client_session.h" 9#include "net/tools/quic/spdy_utils.h" 10 11using base::StringPiece; 12using std::string; 13 14namespace net { 15namespace tools { 16 17static const size_t kHeaderBufInitialSize = 4096; 18 19QuicSpdyClientStream::QuicSpdyClientStream(QuicStreamId id, 20 QuicClientSession* session) 21 : QuicReliableClientStream(id, session), 22 read_buf_(new GrowableIOBuffer()), 23 response_headers_received_(false) { 24} 25 26QuicSpdyClientStream::~QuicSpdyClientStream() { 27} 28 29uint32 QuicSpdyClientStream::ProcessData(const char* data, uint32 length) { 30 uint32 total_bytes_processed = 0; 31 32 // Are we still reading the response headers. 33 if (!response_headers_received_) { 34 // Grow the read buffer if necessary. 35 if (read_buf_->RemainingCapacity() < (int)length) { 36 read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize); 37 } 38 memcpy(read_buf_->data(), data, length); 39 read_buf_->set_offset(read_buf_->offset() + length); 40 ParseResponseHeaders(); 41 } else { 42 mutable_data()->append(data + total_bytes_processed, 43 length - total_bytes_processed); 44 } 45 return length; 46} 47 48void QuicSpdyClientStream::TerminateFromPeer(bool half_close) { 49 ReliableQuicStream::TerminateFromPeer(half_close); 50 if (!response_headers_received_) { 51 Close(QUIC_BAD_APPLICATION_PAYLOAD); 52 } else if ((headers().content_length_status() == 53 BalsaHeadersEnums::VALID_CONTENT_LENGTH) && 54 mutable_data()->size() != headers().content_length()) { 55 Close(QUIC_BAD_APPLICATION_PAYLOAD); 56 } 57} 58 59ssize_t QuicSpdyClientStream::SendRequest(const BalsaHeaders& headers, 60 StringPiece body, 61 bool fin) { 62 SpdyHeaderBlock header_block = 63 SpdyUtils::RequestHeadersToSpdyHeaders(headers); 64 65 string headers_string = 66 session()->compressor()->CompressHeaders(header_block); 67 68 bool has_body = !body.empty(); 69 70 WriteData(headers_string, fin && !has_body); // last_data 71 72 if (has_body) { 73 WriteData(body, fin); 74 } 75 76 return headers_string.size() + body.size(); 77} 78 79int QuicSpdyClientStream::ParseResponseHeaders() { 80 size_t read_buf_len = static_cast<size_t>(read_buf_->offset()); 81 SpdyFramer framer(SPDY3); 82 SpdyHeaderBlock headers; 83 char* data = read_buf_->StartOfBuffer(); 84 size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(), 85 &headers); 86 if (len == 0) { 87 return -1; 88 } 89 90 if (!SpdyUtils::FillBalsaResponseHeaders(headers, mutable_headers())) { 91 Close(QUIC_BAD_APPLICATION_PAYLOAD); 92 return -1; 93 } 94 95 size_t delta = read_buf_len - len; 96 if (delta > 0) { 97 mutable_data()->append(data + len, delta); 98 } 99 100 return len; 101} 102 103} // namespace tools 104} // namespace net 105