blob: 688ca9ff24be2270c50fb65df8dc1e4be8a3ecdf [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
QUICHE team5be974e2020-12-29 18:35:24 -05005#include "quic/tools/quic_simple_server_session.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05006
7#include <utility>
8
bnc38b5aed2021-04-02 10:57:41 -07009#include "absl/memory/memory.h"
vasilvv20d73c42021-04-06 20:14:52 -070010#include "quic/core/http/quic_server_initiated_spdy_stream.h"
QUICHE team5be974e2020-12-29 18:35:24 -050011#include "quic/core/http/quic_spdy_session.h"
12#include "quic/core/quic_connection.h"
13#include "quic/core/quic_utils.h"
14#include "quic/platform/api/quic_flags.h"
15#include "quic/platform/api/quic_logging.h"
QUICHE team5be974e2020-12-29 18:35:24 -050016#include "quic/tools/quic_simple_server_stream.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050017
18namespace quic {
19
20QuicSimpleServerSession::QuicSimpleServerSession(
21 const QuicConfig& config,
22 const ParsedQuicVersionVector& supported_versions,
23 QuicConnection* connection,
24 QuicSession::Visitor* visitor,
nharper5f23a2d2020-02-20 10:44:09 -080025 QuicCryptoServerStreamBase::Helper* helper,
QUICHE teama6ef0a62019-03-07 20:34:33 -050026 const QuicCryptoServerConfig* crypto_config,
27 QuicCompressedCertsCache* compressed_certs_cache,
28 QuicSimpleServerBackend* quic_simple_server_backend)
29 : QuicServerSessionBase(config,
30 supported_versions,
31 connection,
32 visitor,
33 helper,
34 crypto_config,
35 compressed_certs_cache),
36 highest_promised_stream_id_(
renjietang1a33a0c2019-08-12 12:05:31 -070037 QuicUtils::GetInvalidStreamId(connection->transport_version())),
rchd7d9d782019-05-02 18:18:03 -070038 quic_simple_server_backend_(quic_simple_server_backend) {
vasilvvf8035162021-02-01 14:49:14 -080039 QUICHE_DCHECK(quic_simple_server_backend_);
rchd7d9d782019-05-02 18:18:03 -070040}
QUICHE teama6ef0a62019-03-07 20:34:33 -050041
42QuicSimpleServerSession::~QuicSimpleServerSession() {
ianswett6aefa0b2019-12-10 07:26:15 -080043 DeleteConnection();
QUICHE teama6ef0a62019-03-07 20:34:33 -050044}
45
nharpere5e28f92020-01-03 14:10:07 -080046std::unique_ptr<QuicCryptoServerStreamBase>
QUICHE teama6ef0a62019-03-07 20:34:33 -050047QuicSimpleServerSession::CreateQuicCryptoServerStream(
48 const QuicCryptoServerConfig* crypto_config,
49 QuicCompressedCertsCache* compressed_certs_cache) {
nharpere5e28f92020-01-03 14:10:07 -080050 return CreateCryptoServerStream(crypto_config, compressed_certs_cache, this,
51 stream_helper());
QUICHE teama6ef0a62019-03-07 20:34:33 -050052}
53
54void QuicSimpleServerSession::OnStreamFrame(const QuicStreamFrame& frame) {
vasilvv20d73c42021-04-06 20:14:52 -070055 if (!IsIncomingStream(frame.stream_id) && !WillNegotiateWebTransport()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050056 QUIC_LOG(WARNING) << "Client shouldn't send data on server push stream";
57 connection()->CloseConnection(
58 QUIC_INVALID_STREAM_ID, "Client sent data on server push stream",
59 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
60 return;
61 }
62 QuicSpdySession::OnStreamFrame(frame);
63}
64
QUICHE teama6ef0a62019-03-07 20:34:33 -050065QuicSpdyStream* QuicSimpleServerSession::CreateIncomingStream(QuicStreamId id) {
66 if (!ShouldCreateIncomingStream(id)) {
67 return nullptr;
68 }
69
70 QuicSpdyStream* stream = new QuicSimpleServerStream(
71 id, this, BIDIRECTIONAL, quic_simple_server_backend_);
bnc38b5aed2021-04-02 10:57:41 -070072 ActivateStream(absl::WrapUnique(stream));
QUICHE teama6ef0a62019-03-07 20:34:33 -050073 return stream;
74}
75
76QuicSpdyStream* QuicSimpleServerSession::CreateIncomingStream(
renjietangbaea59c2019-05-29 15:08:14 -070077 PendingStream* pending) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050078 QuicSpdyStream* stream = new QuicSimpleServerStream(
renjietangbaea59c2019-05-29 15:08:14 -070079 pending, this, BIDIRECTIONAL, quic_simple_server_backend_);
bnc38b5aed2021-04-02 10:57:41 -070080 ActivateStream(absl::WrapUnique(stream));
QUICHE teama6ef0a62019-03-07 20:34:33 -050081 return stream;
82}
83
vasilvv20d73c42021-04-06 20:14:52 -070084QuicSpdyStream* QuicSimpleServerSession::CreateOutgoingBidirectionalStream() {
85 if (!WillNegotiateWebTransport()) {
86 QUIC_BUG(QuicSimpleServerSession CreateOutgoingBidirectionalStream without
87 WebTransport support)
88 << "QuicSimpleServerSession::CreateOutgoingBidirectionalStream called "
89 "in a session without WebTransport support.";
90 return nullptr;
91 }
92 if (!ShouldCreateOutgoingBidirectionalStream()) {
93 return nullptr;
94 }
95
96 QuicServerInitiatedSpdyStream* stream = new QuicServerInitiatedSpdyStream(
97 GetNextOutgoingBidirectionalStreamId(), this, BIDIRECTIONAL);
98 ActivateStream(absl::WrapUnique(stream));
99 return stream;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500100}
101
102QuicSimpleServerStream*
103QuicSimpleServerSession::CreateOutgoingUnidirectionalStream() {
104 if (!ShouldCreateOutgoingUnidirectionalStream()) {
105 return nullptr;
106 }
107
108 QuicSimpleServerStream* stream = new QuicSimpleServerStream(
109 GetNextOutgoingUnidirectionalStreamId(), this, WRITE_UNIDIRECTIONAL,
110 quic_simple_server_backend_);
bnc38b5aed2021-04-02 10:57:41 -0700111 ActivateStream(absl::WrapUnique(stream));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500112 return stream;
113}
114
115void QuicSimpleServerSession::HandleFrameOnNonexistentOutgoingStream(
116 QuicStreamId stream_id) {
117 // If this stream is a promised but not created stream (stream_id within the
118 // range of next_outgoing_stream_id_ and highes_promised_stream_id_),
119 // connection shouldn't be closed.
120 // Otherwise behave in the same way as base class.
121 if (highest_promised_stream_id_ ==
renjietangd1d00852019-09-06 10:43:12 -0700122 QuicUtils::GetInvalidStreamId(transport_version()) ||
QUICHE teama6ef0a62019-03-07 20:34:33 -0500123 stream_id > highest_promised_stream_id_) {
124 QuicSession::HandleFrameOnNonexistentOutgoingStream(stream_id);
125 }
126}
127
128void QuicSimpleServerSession::HandleRstOnValidNonexistentStream(
129 const QuicRstStreamFrame& frame) {
130 QuicSession::HandleRstOnValidNonexistentStream(frame);
131 if (!IsClosedStream(frame.stream_id)) {
132 // If a nonexistent stream is not a closed stream and still valid, it must
133 // be a locally preserved stream. Resetting this kind of stream means
134 // cancelling the promised server push.
135 // Since PromisedStreamInfo are queued in sequence, the corresponding
136 // index for it in promised_streams_ can be calculated.
137 QuicStreamId next_stream_id = next_outgoing_unidirectional_stream_id();
dschinazi1de58192020-11-25 14:46:08 -0800138 if ((!version().HasIetfQuicFrames() ||
139 !QuicUtils::IsBidirectionalStreamId(frame.stream_id, version())) &&
140 frame.stream_id >= next_stream_id) {
141 size_t index = (frame.stream_id - next_stream_id) /
142 QuicUtils::StreamIdDelta(transport_version());
143 if (index <= promised_streams_.size()) {
144 promised_streams_[index].is_cancelled = true;
145 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500146 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500147 control_frame_manager().WriteOrBufferRstStream(frame.stream_id,
148 QUIC_RST_ACKNOWLEDGEMENT, 0);
149 connection()->OnStreamReset(frame.stream_id, QUIC_RST_ACKNOWLEDGEMENT);
150 }
151}
152
QUICHE team82103522020-10-22 08:15:09 -0700153spdy::Http2HeaderBlock QuicSimpleServerSession::SynthesizePushRequestHeaders(
vasilvvc48c8712019-03-11 13:38:16 -0700154 std::string request_url,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500155 QuicBackendResponse::ServerPushInfo resource,
QUICHE team82103522020-10-22 08:15:09 -0700156 const spdy::Http2HeaderBlock& original_request_headers) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500157 QuicUrl push_request_url = resource.request_url;
158
QUICHE team82103522020-10-22 08:15:09 -0700159 spdy::Http2HeaderBlock spdy_headers = original_request_headers.Clone();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500160 // :authority could be different from original request.
161 spdy_headers[":authority"] = push_request_url.host();
162 spdy_headers[":path"] = push_request_url.path();
163 // Push request always use GET.
164 spdy_headers[":method"] = "GET";
165 spdy_headers["referer"] = request_url;
166 spdy_headers[":scheme"] = push_request_url.scheme();
167 // It is not possible to push a response to a request that includes a request
168 // body.
169 spdy_headers["content-length"] = "0";
170 // Remove "host" field as push request is a directly generated HTTP2 request
171 // which should use ":authority" instead of "host".
172 spdy_headers.erase("host");
173 return spdy_headers;
174}
175
176void QuicSimpleServerSession::SendPushPromise(QuicStreamId original_stream_id,
177 QuicStreamId promised_stream_id,
QUICHE team82103522020-10-22 08:15:09 -0700178 spdy::Http2HeaderBlock headers) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500179 QUIC_DLOG(INFO) << "stream " << original_stream_id
180 << " send PUSH_PROMISE for promised stream "
181 << promised_stream_id;
182 WritePushPromise(original_stream_id, promised_stream_id, std::move(headers));
183}
184
185void QuicSimpleServerSession::HandlePromisedPushRequests() {
186 while (!promised_streams_.empty() &&
187 ShouldCreateOutgoingUnidirectionalStream()) {
188 PromisedStreamInfo& promised_info = promised_streams_.front();
vasilvvf8035162021-02-01 14:49:14 -0800189 QUICHE_DCHECK_EQ(next_outgoing_unidirectional_stream_id(),
190 promised_info.stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500191
192 if (promised_info.is_cancelled) {
193 // This stream has been reset by client. Skip this stream id.
194 promised_streams_.pop_front();
195 GetNextOutgoingUnidirectionalStreamId();
196 return;
197 }
198
199 QuicSimpleServerStream* promised_stream =
200 static_cast<QuicSimpleServerStream*>(
201 CreateOutgoingUnidirectionalStream());
vasilvvf8035162021-02-01 14:49:14 -0800202 QUICHE_DCHECK_NE(promised_stream, nullptr);
203 QUICHE_DCHECK_EQ(promised_info.stream_id, promised_stream->id());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500204 QUIC_DLOG(INFO) << "created server push stream " << promised_stream->id();
205
fayang9a423762019-07-31 08:12:58 -0700206 promised_stream->SetPriority(promised_info.precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500207
QUICHE team82103522020-10-22 08:15:09 -0700208 spdy::Http2HeaderBlock request_headers(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500209 std::move(promised_info.request_headers));
210
211 promised_streams_.pop_front();
212 promised_stream->PushResponse(std::move(request_headers));
213 }
214}
215
fkastenholz8556dc22019-07-18 12:42:38 -0700216void QuicSimpleServerSession::OnCanCreateNewOutgoingStream(
renjietangde12d3d2019-07-19 10:57:42 -0700217 bool unidirectional) {
renjietangc04c85f2019-07-25 14:07:27 -0700218 QuicSpdySession::OnCanCreateNewOutgoingStream(unidirectional);
renjietangde12d3d2019-07-19 10:57:42 -0700219 if (unidirectional) {
220 HandlePromisedPushRequests();
221 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500222}
renjietang1a33a0c2019-08-12 12:05:31 -0700223
224void QuicSimpleServerSession::MaybeInitializeHttp3UnidirectionalStreams() {
fayang116fa4c2020-06-02 08:10:49 -0700225 size_t previous_static_stream_count = num_static_streams();
renjietang1a33a0c2019-08-12 12:05:31 -0700226 QuicSpdySession::MaybeInitializeHttp3UnidirectionalStreams();
fayang116fa4c2020-06-02 08:10:49 -0700227 size_t current_static_stream_count = num_static_streams();
vasilvvf8035162021-02-01 14:49:14 -0800228 QUICHE_DCHECK_GE(current_static_stream_count, previous_static_stream_count);
renjietang1a33a0c2019-08-12 12:05:31 -0700229 highest_promised_stream_id_ +=
230 QuicUtils::StreamIdDelta(transport_version()) *
231 (current_static_stream_count - previous_static_stream_count);
232}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500233} // namespace quic