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