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_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
);
49 uint32
QuicSpdyClientStream::ProcessData(const char* data
, uint32 data_len
) {
50 if (!headers_decompressed()) {
51 // Let the headers data accumulate in the underlying QuicDataStream.
54 if (response_headers_
.empty()) {
55 if (!ParseResponseHeaders(data
, data_len
)) {
56 // Headers were invalid.
57 Reset(QUIC_BAD_APPLICATION_PAYLOAD
);
61 data_
.append(data
, data_len
);
63 DCHECK(!response_headers_
.empty());
64 if (content_length_
>= 0 &&
65 static_cast<int>(data_
.size()) > content_length_
) {
66 Reset(QUIC_BAD_APPLICATION_PAYLOAD
);
69 DVLOG(1) << "Client processed " << data_len
<< " bytes for stream " << id();
73 bool QuicSpdyClientStream::ParseResponseHeaders(const char* data
,
75 DCHECK(headers_decompressed());
76 SpdyFramer
framer(SPDY3
);
77 size_t len
= framer
.ParseHeaderBlockInBuffer(data
,
80 DCHECK_LE(len
, data_len
);
81 if (len
== 0 || response_headers_
.empty()) {
82 return false; // Headers were invalid.
86 data_
.append(data
+ len
, data_len
- len
);
88 if (ContainsKey(response_headers_
, "content-length") &&
89 !StringToInt(response_headers_
["content-length"], &content_length_
)) {
90 return false; // Invalid content-length.
92 string status
= response_headers_
[":status"];
93 size_t end
= status
.find(" ");
94 if (end
!= string::npos
) {
97 if (!StringToInt(status
, &response_code_
)) {
98 return false; // Invalid response code.
103 size_t QuicSpdyClientStream::SendRequest(const SpdyHeaderBlock
& headers
,
106 bool send_fin_with_headers
= fin
&& body
.empty();
107 size_t bytes_sent
= body
.size();
108 header_bytes_written_
=
109 WriteHeaders(headers
, send_fin_with_headers
, nullptr);
110 bytes_sent
+= header_bytes_written_
;
113 WriteOrBufferData(body
, fin
, nullptr);
119 void QuicSpdyClientStream::SendBody(const string
& data
, bool fin
) {
120 SendBody(data
, fin
, nullptr);
123 void QuicSpdyClientStream::SendBody(
124 const string
& data
, bool fin
,
125 QuicAckNotifier::DelegateInterface
* delegate
) {
126 WriteOrBufferData(data
, fin
, delegate
);