blob: 2903b3086d5ce76531a4ed07d33e0c8abe029fae [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
6
7#include <utility>
8
9#include "net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h"
10#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h"
11#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
12#include "net/third_party/quiche/src/quic/core/quic_alarm.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
14#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
15
16using spdy::SpdyHeaderBlock;
17
18namespace quic {
19
20QuicSpdyClientStream::QuicSpdyClientStream(QuicStreamId id,
21 QuicSpdyClientSession* session,
22 StreamType type)
23 : QuicSpdyStream(id, session, type),
24 content_length_(-1),
25 response_code_(0),
26 header_bytes_read_(0),
27 header_bytes_written_(0),
28 session_(session),
29 has_preliminary_headers_(false) {}
30
renjietangbaea59c2019-05-29 15:08:14 -070031QuicSpdyClientStream::QuicSpdyClientStream(PendingStream* pending,
QUICHE teama6ef0a62019-03-07 20:34:33 -050032 QuicSpdyClientSession* session,
33 StreamType type)
renjietangbaea59c2019-05-29 15:08:14 -070034 : QuicSpdyStream(pending, session, type),
QUICHE teama6ef0a62019-03-07 20:34:33 -050035 content_length_(-1),
36 response_code_(0),
37 header_bytes_read_(0),
38 header_bytes_written_(0),
39 session_(session),
40 has_preliminary_headers_(false) {}
41
42QuicSpdyClientStream::~QuicSpdyClientStream() = default;
43
44void QuicSpdyClientStream::OnInitialHeadersComplete(
45 bool fin,
46 size_t frame_len,
47 const QuicHeaderList& header_list) {
48 QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);
49
50 DCHECK(headers_decompressed());
51 header_bytes_read_ += frame_len;
52 if (!SpdyUtils::CopyAndValidateHeaders(header_list, &content_length_,
53 &response_headers_)) {
54 QUIC_DLOG(ERROR) << "Failed to parse header list: "
55 << header_list.DebugString();
56 Reset(QUIC_BAD_APPLICATION_PAYLOAD);
57 return;
58 }
59
60 if (!ParseHeaderStatusCode(response_headers_, &response_code_)) {
61 QUIC_DLOG(ERROR) << "Received invalid response code: "
62 << response_headers_[":status"].as_string();
63 Reset(QUIC_BAD_APPLICATION_PAYLOAD);
64 return;
65 }
66
67 if (response_code_ == 100 && !has_preliminary_headers_) {
68 // These are preliminary 100 Continue headers, not the actual response
69 // headers.
70 set_headers_decompressed(false);
71 has_preliminary_headers_ = true;
72 preliminary_headers_ = std::move(response_headers_);
73 }
74
75 ConsumeHeaderList();
76 QUIC_DVLOG(1) << "headers complete for stream " << id();
77
78 session_->OnInitialHeadersComplete(id(), response_headers_);
79}
80
81void QuicSpdyClientStream::OnTrailingHeadersComplete(
82 bool fin,
83 size_t frame_len,
84 const QuicHeaderList& header_list) {
85 QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list);
86 MarkTrailersConsumed();
87}
88
89void QuicSpdyClientStream::OnPromiseHeaderList(
90 QuicStreamId promised_id,
91 size_t frame_len,
92 const QuicHeaderList& header_list) {
93 header_bytes_read_ += frame_len;
94 int64_t content_length = -1;
95 SpdyHeaderBlock promise_headers;
96 if (!SpdyUtils::CopyAndValidateHeaders(header_list, &content_length,
97 &promise_headers)) {
98 QUIC_DLOG(ERROR) << "Failed to parse promise headers: "
99 << header_list.DebugString();
100 Reset(QUIC_BAD_APPLICATION_PAYLOAD);
101 return;
102 }
103
104 session_->HandlePromised(id(), promised_id, promise_headers);
105 if (visitor() != nullptr) {
106 visitor()->OnPromiseHeadersComplete(promised_id, frame_len);
107 }
108}
109
110void QuicSpdyClientStream::OnBodyAvailable() {
111 // For push streams, visitor will not be set until the rendezvous
112 // between server promise and client request is complete.
113 if (visitor() == nullptr)
114 return;
115
116 while (HasBytesToRead()) {
117 struct iovec iov;
118 if (GetReadableRegions(&iov, 1) == 0) {
119 // No more data to read.
120 break;
121 }
122 QUIC_DVLOG(1) << "Client processed " << iov.iov_len << " bytes for stream "
123 << id();
124 data_.append(static_cast<char*>(iov.iov_base), iov.iov_len);
125
126 if (content_length_ >= 0 &&
127 data_.size() > static_cast<uint64_t>(content_length_)) {
128 QUIC_DLOG(ERROR) << "Invalid content length (" << content_length_
129 << ") with data of size " << data_.size();
130 Reset(QUIC_BAD_APPLICATION_PAYLOAD);
131 return;
132 }
133 MarkConsumed(iov.iov_len);
134 }
135 if (sequencer()->IsClosed()) {
136 OnFinRead();
137 } else {
138 sequencer()->SetUnblocked();
139 }
140}
141
142size_t QuicSpdyClientStream::SendRequest(SpdyHeaderBlock headers,
143 QuicStringPiece body,
144 bool fin) {
145 QuicConnection::ScopedPacketFlusher flusher(
146 session_->connection(), QuicConnection::SEND_ACK_IF_QUEUED);
147 bool send_fin_with_headers = fin && body.empty();
148 size_t bytes_sent = body.size();
149 header_bytes_written_ =
150 WriteHeaders(std::move(headers), send_fin_with_headers, nullptr);
151 bytes_sent += header_bytes_written_;
152
153 if (!body.empty()) {
154 WriteOrBufferBody(body, fin);
155 }
156
157 return bytes_sent;
158}
159
160} // namespace quic