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