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.
5 #include "net/tools/quic/quic_spdy_client_stream.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "net/quic/spdy_utils.h"
11 #include "net/spdy/spdy_protocol.h"
12 #include "net/tools/quic/quic_client_session.h"
13 #include "net/tools/quic/spdy_balsa_utils.h"
15 using base::StringPiece
;
17 using base::StringToInt
;
22 QuicSpdyClientStream::QuicSpdyClientStream(QuicStreamId id
,
23 QuicClientSession
* session
)
24 : QuicDataStream(id
, session
),
27 header_bytes_read_(0),
28 header_bytes_written_(0) {
31 QuicSpdyClientStream::~QuicSpdyClientStream() {
34 void QuicSpdyClientStream::OnStreamFrame(const QuicStreamFrame
& frame
) {
35 if (!write_side_closed()) {
36 DVLOG(1) << "Got a response before the request was complete. "
37 << "Aborting request.";
40 QuicDataStream::OnStreamFrame(frame
);
43 void QuicSpdyClientStream::OnStreamHeadersComplete(bool fin
,
45 header_bytes_read_
= frame_len
;
46 QuicDataStream::OnStreamHeadersComplete(fin
, frame_len
);
47 if (!ParseResponseHeaders(decompressed_headers().data(),
48 decompressed_headers().length())) {
49 Reset(QUIC_BAD_APPLICATION_PAYLOAD
);
52 MarkHeadersConsumed(decompressed_headers().length());
55 void QuicSpdyClientStream::OnDataAvailable() {
56 while (HasBytesToRead()) {
58 if (GetReadableRegions(&iov
, 1) == 0) {
59 // No more data to read.
62 DVLOG(1) << "Client processed " << iov
.iov_len
<< " bytes for stream "
64 data_
.append(static_cast<char*>(iov
.iov_base
), iov
.iov_len
);
66 if (content_length_
>= 0 &&
67 static_cast<int>(data_
.size()) > content_length_
) {
68 Reset(QUIC_BAD_APPLICATION_PAYLOAD
);
71 MarkConsumed(iov
.iov_len
);
73 if (sequencer()->IsClosed()) {
76 sequencer()->SetUnblocked();
80 bool QuicSpdyClientStream::ParseResponseHeaders(const char* data
,
82 DCHECK(headers_decompressed());
83 SpdyFramer
framer(HTTP2
);
84 size_t len
= framer
.ParseHeaderBlockInBuffer(data
,
87 DCHECK_LE(len
, data_len
);
88 if (len
== 0 || response_headers_
.empty()) {
89 return false; // Headers were invalid.
93 data_
.append(data
+ len
, data_len
- len
);
95 if (ContainsKey(response_headers_
, "content-length") &&
96 !StringToInt(response_headers_
["content-length"], &content_length_
)) {
97 return false; // Invalid content-length.
99 string status
= response_headers_
[":status"];
100 size_t end
= status
.find(" ");
101 if (end
!= string::npos
) {
104 if (!StringToInt(status
, &response_code_
)) {
105 return false; // Invalid response code.
110 size_t QuicSpdyClientStream::SendRequest(const SpdyHeaderBlock
& headers
,
113 bool send_fin_with_headers
= fin
&& body
.empty();
114 size_t bytes_sent
= body
.size();
115 header_bytes_written_
=
116 WriteHeaders(headers
, send_fin_with_headers
, nullptr);
117 bytes_sent
+= header_bytes_written_
;
120 WriteOrBufferData(body
, fin
, nullptr);
126 void QuicSpdyClientStream::SendBody(const string
& data
, bool fin
) {
127 SendBody(data
, fin
, nullptr);
130 void QuicSpdyClientStream::SendBody(
131 const string
& data
, bool fin
,
132 QuicAckNotifier::DelegateInterface
* delegate
) {
133 WriteOrBufferData(data
, fin
, delegate
);