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 : QuicDataStream(id, session), 22 read_buf_(new GrowableIOBuffer()), 23 response_headers_received_(false), 24 header_bytes_read_(0), 25 header_bytes_written_(0) { 26} 27 28QuicSpdyClientStream::~QuicSpdyClientStream() { 29} 30 31void QuicSpdyClientStream::OnStreamFrame(const QuicStreamFrame& frame) { 32 if (!write_side_closed()) { 33 DVLOG(1) << "Got a response before the request was complete. " 34 << "Aborting request."; 35 CloseWriteSide(); 36 } 37 QuicDataStream::OnStreamFrame(frame); 38} 39 40void QuicSpdyClientStream::OnStreamHeadersComplete(bool fin, 41 size_t frame_len) { 42 header_bytes_read_ = frame_len; 43 QuicDataStream::OnStreamHeadersComplete(fin, frame_len); 44} 45 46uint32 QuicSpdyClientStream::ProcessData(const char* data, 47 uint32 data_len) { 48 int total_bytes_processed = 0; 49 50 // Are we still reading the response headers. 51 if (!response_headers_received_) { 52 // Grow the read buffer if necessary. 53 if (read_buf_->RemainingCapacity() < (int)data_len) { 54 read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize); 55 } 56 memcpy(read_buf_->data(), data, data_len); 57 read_buf_->set_offset(read_buf_->offset() + data_len); 58 ParseResponseHeaders(); 59 } else { 60 data_.append(data + total_bytes_processed, 61 data_len - total_bytes_processed); 62 } 63 return data_len; 64} 65 66void QuicSpdyClientStream::OnFinRead() { 67 ReliableQuicStream::OnFinRead(); 68 if (!response_headers_received_) { 69 Reset(QUIC_BAD_APPLICATION_PAYLOAD); 70 } else if ((headers().content_length_status() == 71 BalsaHeadersEnums::VALID_CONTENT_LENGTH) && 72 data_.size() != headers().content_length()) { 73 Reset(QUIC_BAD_APPLICATION_PAYLOAD); 74 } 75} 76 77ssize_t QuicSpdyClientStream::SendRequest(const BalsaHeaders& headers, 78 StringPiece body, 79 bool fin) { 80 SpdyHeaderBlock header_block = 81 SpdyUtils::RequestHeadersToSpdyHeaders(headers); 82 83 bool send_fin_with_headers = fin && body.empty(); 84 size_t bytes_sent = body.size(); 85 header_bytes_written_ = WriteHeaders( 86 header_block, send_fin_with_headers, NULL); 87 bytes_sent += header_bytes_written_; 88 89 if (!body.empty()) { 90 WriteOrBufferData(body, fin, NULL); 91 } 92 93 return bytes_sent; 94} 95 96int QuicSpdyClientStream::ParseResponseHeaders() { 97 size_t read_buf_len = static_cast<size_t>(read_buf_->offset()); 98 SpdyFramer framer(SPDY3); 99 SpdyHeaderBlock headers; 100 char* data = read_buf_->StartOfBuffer(); 101 size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(), 102 &headers); 103 if (len == 0) { 104 return -1; 105 } 106 107 if (!SpdyUtils::FillBalsaResponseHeaders(headers, &headers_)) { 108 Reset(QUIC_BAD_APPLICATION_PAYLOAD); 109 return -1; 110 } 111 response_headers_received_ = true; 112 113 size_t delta = read_buf_len - len; 114 if (delta > 0) { 115 data_.append(data + len, delta); 116 } 117 118 return len; 119} 120 121// Sends body data to the server and returns the number of bytes sent. 122void QuicSpdyClientStream::SendBody(const string& data, bool fin) { 123 WriteOrBufferData(data, fin, NULL); 124} 125 126} // namespace tools 127} // namespace net 128