| Index: net/tools/quic/quic_spdy_client_stream.cc
|
| diff --git a/net/tools/quic/quic_spdy_client_stream.cc b/net/tools/quic/quic_spdy_client_stream.cc
|
| index 2d649cda8d1781bcde030ef132e153b09ea23a57..9651c8136c660ac801ec67df24b4107fc04c9013 100644
|
| --- a/net/tools/quic/quic_spdy_client_stream.cc
|
| +++ b/net/tools/quic/quic_spdy_client_stream.cc
|
| @@ -4,23 +4,26 @@
|
|
|
| #include "net/tools/quic/quic_spdy_client_stream.h"
|
|
|
| -#include "net/spdy/spdy_framer.h"
|
| +#include "base/logging.h"
|
| +#include "base/stl_util.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "net/quic/spdy_utils.h"
|
| +#include "net/spdy/spdy_protocol.h"
|
| #include "net/tools/quic/quic_client_session.h"
|
| #include "net/tools/quic/spdy_utils.h"
|
|
|
| using base::StringPiece;
|
| using std::string;
|
| +using base::StringToInt;
|
|
|
| namespace net {
|
| namespace tools {
|
|
|
| -static const size_t kHeaderBufInitialSize = 4096;
|
| -
|
| QuicSpdyClientStream::QuicSpdyClientStream(QuicStreamId id,
|
| QuicClientSession* session)
|
| : QuicDataStream(id, session),
|
| - read_buf_(new GrowableIOBuffer()),
|
| - response_headers_received_(false),
|
| + content_length_(-1),
|
| + response_code_(0),
|
| header_bytes_read_(0),
|
| header_bytes_written_(0) {
|
| }
|
| @@ -43,47 +46,67 @@ void QuicSpdyClientStream::OnStreamHeadersComplete(bool fin,
|
| QuicDataStream::OnStreamHeadersComplete(fin, frame_len);
|
| }
|
|
|
| -uint32 QuicSpdyClientStream::ProcessData(const char* data,
|
| - uint32 data_len) {
|
| - int total_bytes_processed = 0;
|
| -
|
| - // Are we still reading the response headers.
|
| - if (!response_headers_received_) {
|
| - // Grow the read buffer if necessary.
|
| - if (read_buf_->RemainingCapacity() < (int)data_len) {
|
| - read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
|
| +uint32 QuicSpdyClientStream::ProcessData(const char* data, uint32 data_len) {
|
| + if (!headers_decompressed()) {
|
| + // Let the headers data accumulate in the underlying QuicDataStream.
|
| + return 0;
|
| + }
|
| + if (response_headers_.empty()) {
|
| + if (!ParseResponseHeaders(data, data_len)) {
|
| + // Headers were invalid.
|
| + Reset(QUIC_BAD_APPLICATION_PAYLOAD);
|
| + return 0;
|
| }
|
| - memcpy(read_buf_->data(), data, data_len);
|
| - read_buf_->set_offset(read_buf_->offset() + data_len);
|
| - ParseResponseHeaders();
|
| } else {
|
| - data_.append(data + total_bytes_processed,
|
| - data_len - total_bytes_processed);
|
| + data_.append(data, data_len);
|
| }
|
| + DCHECK(!response_headers_.empty());
|
| + if (content_length_ >= 0 &&
|
| + static_cast<int>(data_.size()) > content_length_) {
|
| + Reset(QUIC_BAD_APPLICATION_PAYLOAD);
|
| + return 0;
|
| + }
|
| + DVLOG(1) << "Client processed " << data_len << " bytes for stream " << id();
|
| return data_len;
|
| }
|
|
|
| -void QuicSpdyClientStream::OnFinRead() {
|
| - ReliableQuicStream::OnFinRead();
|
| - if (!response_headers_received_) {
|
| - Reset(QUIC_BAD_APPLICATION_PAYLOAD);
|
| - } else if ((headers().content_length_status() ==
|
| - BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
|
| - data_.size() != headers().content_length()) {
|
| - Reset(QUIC_BAD_APPLICATION_PAYLOAD);
|
| +bool QuicSpdyClientStream::ParseResponseHeaders(const char* data,
|
| + uint32 data_len) {
|
| + DCHECK(headers_decompressed());
|
| + SpdyFramer framer(SPDY3);
|
| + size_t len = framer.ParseHeaderBlockInBuffer(data,
|
| + data_len,
|
| + &response_headers_);
|
| + DCHECK_LE(len, data_len);
|
| + if (len == 0 || response_headers_.empty()) {
|
| + return false; // Headers were invalid.
|
| + }
|
| +
|
| + if (data_len > len) {
|
| + data_.append(data + len, data_len - len);
|
| + }
|
| + if (ContainsKey(response_headers_, "content-length") &&
|
| + !StringToInt(response_headers_["content-length"], &content_length_)) {
|
| + return false; // Invalid content-length.
|
| + }
|
| + string status = response_headers_[":status"];
|
| + size_t end = status.find(" ");
|
| + if (end != string::npos) {
|
| + status.erase(end);
|
| }
|
| + if (!StringToInt(status, &response_code_)) {
|
| + return false; // Invalid response code.
|
| + }
|
| + return true;
|
| }
|
|
|
| -ssize_t QuicSpdyClientStream::SendRequest(const BalsaHeaders& headers,
|
| +ssize_t QuicSpdyClientStream::SendRequest(const SpdyHeaderBlock& headers,
|
| StringPiece body,
|
| bool fin) {
|
| - SpdyHeaderBlock header_block =
|
| - SpdyUtils::RequestHeadersToSpdyHeaders(headers);
|
| -
|
| bool send_fin_with_headers = fin && body.empty();
|
| size_t bytes_sent = body.size();
|
| header_bytes_written_ =
|
| - WriteHeaders(header_block, send_fin_with_headers, nullptr);
|
| + WriteHeaders(headers, send_fin_with_headers, nullptr);
|
| bytes_sent += header_bytes_written_;
|
|
|
| if (!body.empty()) {
|
| @@ -93,38 +116,12 @@ ssize_t QuicSpdyClientStream::SendRequest(const BalsaHeaders& headers,
|
| return bytes_sent;
|
| }
|
|
|
| -int QuicSpdyClientStream::ParseResponseHeaders() {
|
| - size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
|
| - SpdyFramer framer(SPDY3);
|
| - SpdyHeaderBlock headers;
|
| - char* data = read_buf_->StartOfBuffer();
|
| - size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(),
|
| - &headers);
|
| - if (len == 0) {
|
| - return -1;
|
| - }
|
| -
|
| - if (!SpdyUtils::FillBalsaResponseHeaders(headers, &headers_)) {
|
| - Reset(QUIC_BAD_APPLICATION_PAYLOAD);
|
| - return -1;
|
| - }
|
| - response_headers_received_ = true;
|
| -
|
| - size_t delta = read_buf_len - len;
|
| - if (delta > 0) {
|
| - data_.append(data + len, delta);
|
| - }
|
| -
|
| - return len;
|
| -}
|
| -
|
| void QuicSpdyClientStream::SendBody(const string& data, bool fin) {
|
| SendBody(data, fin, nullptr);
|
| }
|
|
|
| void QuicSpdyClientStream::SendBody(
|
| - const string& data,
|
| - bool fin,
|
| + const string& data, bool fin,
|
| QuicAckNotifier::DelegateInterface* delegate) {
|
| WriteOrBufferData(data, fin, delegate);
|
| }
|
|
|