blob: 2e467ae9d1546ab823d74b03d61576c3893d2934 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2015 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#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_SESSION_H_
6#define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_SESSION_H_
7
8#include <cstddef>
9#include <memory>
vasilvv872e7a32019-03-12 16:42:44 -070010#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -050011
QUICHE teama6ef0a62019-03-07 20:34:33 -050012#include "net/third_party/quiche/src/quic/core/http/quic_header_list.h"
13#include "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h"
renjietang3a1bb802019-06-11 10:42:41 -070014#include "net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h"
15#include "net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050016#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h"
17#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
18#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h"
19#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h"
20#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
renjietangc2aa5cb2019-06-20 12:22:53 -070021#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050022#include "net/third_party/quiche/src/quic/core/quic_session.h"
23#include "net/third_party/quiche/src/quic/core/quic_versions.h"
24#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050025#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
26#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h"
27
28namespace quic {
29
30namespace test {
31class QuicSpdySessionPeer;
32} // namespace test
33
34// QuicHpackDebugVisitor gathers data used for understanding HPACK HoL
35// dynamics. Specifically, it is to help predict the compression
36// penalty of avoiding HoL by chagning how the dynamic table is used.
37// In chromium, the concrete instance populates an UMA
38// histogram with the data.
39class QUIC_EXPORT_PRIVATE QuicHpackDebugVisitor {
40 public:
41 QuicHpackDebugVisitor();
42 QuicHpackDebugVisitor(const QuicHpackDebugVisitor&) = delete;
43 QuicHpackDebugVisitor& operator=(const QuicHpackDebugVisitor&) = delete;
44
45 virtual ~QuicHpackDebugVisitor();
46
47 // For each HPACK indexed representation processed, |elapsed| is
48 // the time since the corresponding entry was added to the dynamic
49 // table.
50 virtual void OnUseEntry(QuicTime::Delta elapsed) = 0;
51};
52
53// A QUIC session with a headers stream.
54class QUIC_EXPORT_PRIVATE QuicSpdySession
55 : public QuicSession,
56 public QpackEncoder::DecoderStreamErrorDelegate,
renjietangc2aa5cb2019-06-20 12:22:53 -070057 public QpackDecoder::EncoderStreamErrorDelegate {
QUICHE teama6ef0a62019-03-07 20:34:33 -050058 public:
59 // Does not take ownership of |connection| or |visitor|.
60 QuicSpdySession(QuicConnection* connection,
61 QuicSession::Visitor* visitor,
62 const QuicConfig& config,
63 const ParsedQuicVersionVector& supported_versions);
64 QuicSpdySession(const QuicSpdySession&) = delete;
65 QuicSpdySession& operator=(const QuicSpdySession&) = delete;
66
67 ~QuicSpdySession() override;
68
69 void Initialize() override;
70
71 // QpackEncoder::DecoderStreamErrorDelegate implementation.
72 void OnDecoderStreamError(QuicStringPiece error_message) override;
73
QUICHE teama6ef0a62019-03-07 20:34:33 -050074 // QpackDecoder::EncoderStreamErrorDelegate implementation.
75 void OnEncoderStreamError(QuicStringPiece error_message) override;
76
QUICHE teama6ef0a62019-03-07 20:34:33 -050077 // Called by |headers_stream_| when headers with a priority have been
78 // received for a stream. This method will only be called for server streams.
fayang476683a2019-07-25 12:42:16 -070079 virtual void OnStreamHeadersPriority(
80 QuicStreamId stream_id,
81 const spdy::SpdyStreamPrecedence& precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -050082
83 // Called by |headers_stream_| when headers have been completely received
84 // for a stream. |fin| will be true if the fin flag was set in the headers
85 // frame.
86 virtual void OnStreamHeaderList(QuicStreamId stream_id,
87 bool fin,
88 size_t frame_len,
89 const QuicHeaderList& header_list);
90
91 // Called by |headers_stream_| when push promise headers have been
92 // completely received. |fin| will be true if the fin flag was set
93 // in the headers.
94 virtual void OnPromiseHeaderList(QuicStreamId stream_id,
95 QuicStreamId promised_stream_id,
96 size_t frame_len,
97 const QuicHeaderList& header_list);
98
99 // Called by |headers_stream_| when a PRIORITY frame has been received for a
100 // stream. This method will only be called for server streams.
101 virtual void OnPriorityFrame(QuicStreamId stream_id,
fayang476683a2019-07-25 12:42:16 -0700102 const spdy::SpdyStreamPrecedence& precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500103
104 // Sends contents of |iov| to h2_deframer_, returns number of bytes processed.
105 size_t ProcessHeaderData(const struct iovec& iov);
106
107 // Writes |headers| for the stream |id| to the dedicated headers stream.
108 // If |fin| is true, then no more data will be sent for the stream |id|.
109 // If provided, |ack_notifier_delegate| will be registered to be notified when
110 // we have seen ACKs for all packets resulting from this call.
111 virtual size_t WriteHeadersOnHeadersStream(
112 QuicStreamId id,
113 spdy::SpdyHeaderBlock headers,
114 bool fin,
fayang476683a2019-07-25 12:42:16 -0700115 const spdy::SpdyStreamPrecedence& precedence,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500116 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
117
118 // Writes a PRIORITY frame the to peer. Returns the size in bytes of the
119 // resulting PRIORITY frame for QUIC_VERSION_43 and above. Otherwise, does
120 // nothing and returns 0.
121 size_t WritePriority(QuicStreamId id,
122 QuicStreamId parent_stream_id,
123 int weight,
124 bool exclusive);
125
renjietang7498c8c2019-07-02 19:28:42 -0700126 // Writes a HTTP/3 PRIORITY frame to the peer.
127 void WriteH3Priority(const PriorityFrame& priority);
128
QUICHE teama6ef0a62019-03-07 20:34:33 -0500129 // Write |headers| for |promised_stream_id| on |original_stream_id| in a
130 // PUSH_PROMISE frame to peer.
renjietangf4f47122019-07-22 12:08:53 -0700131 virtual void WritePushPromise(QuicStreamId original_stream_id,
132 QuicStreamId promised_stream_id,
133 spdy::SpdyHeaderBlock headers);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500134
135 // Sends SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame.
QUICHE team2252b702019-05-14 23:55:14 -0400136 void SendMaxHeaderListSize(size_t value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500137
138 QpackEncoder* qpack_encoder();
139 QpackDecoder* qpack_decoder();
renjietang9818f8c2019-07-16 11:12:27 -0700140 QuicHeadersStream* headers_stream() { return headers_stream_; }
renjietangfbeb5bf2019-04-19 15:06:20 -0700141
renjietang9818f8c2019-07-16 11:12:27 -0700142 const QuicHeadersStream* headers_stream() const { return headers_stream_; }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500143
144 bool server_push_enabled() const { return server_push_enabled_; }
145
bnc5b182b92019-07-30 11:00:15 -0700146 // Called when a setting is parsed from an incoming SETTINGS frame.
147 void OnSetting(uint64_t id, uint64_t value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500148
149 // Return true if this session wants to release headers stream's buffer
150 // aggressively.
151 virtual bool ShouldReleaseHeadersStreamSequencerBuffer();
152
153 void CloseConnectionWithDetails(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700154 const std::string& details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500155
bnc30d610c2019-07-08 18:39:59 -0700156 // Must be called before Initialize().
157 // TODO(bnc): Move to constructor argument.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500158 void set_max_inbound_header_list_size(size_t max_inbound_header_list_size) {
159 max_inbound_header_list_size_ = max_inbound_header_list_size;
160 }
161
renjietang3a1bb802019-06-11 10:42:41 -0700162 size_t max_outbound_header_list_size() const {
163 return max_outbound_header_list_size_;
164 }
165
renjietangfee2cc32019-04-05 11:32:07 -0700166 size_t max_inbound_header_list_size() const {
167 return max_inbound_header_list_size_;
168 }
169
QUICHE teamc2653c42019-03-08 13:30:06 -0800170 // Returns true if the session has active request streams.
171 bool HasActiveRequestStreams() const;
172
renjietang3c3dfb72019-07-26 11:55:52 -0700173 // Called when the size of the compressed frame payload is available.
174 void OnCompressedFrameSize(size_t frame_len);
175
176 // Called when a PUSH_PROMISE frame has been received.
177 void OnPushPromise(spdy::SpdyStreamId stream_id,
178 spdy::SpdyStreamId promised_stream_id);
179
180 // Called when the complete list of headers is available.
181 void OnHeaderList(const QuicHeaderList& header_list);
182
183 QuicStreamId promised_stream_id() const { return promised_stream_id_; }
184
renjietangc04c85f2019-07-25 14:07:27 -0700185 // Initialze HTTP/3 unidirectional streams if |unidirectional| is true and
186 // those streams are not initialized yet.
187 void OnCanCreateNewOutgoingStream(bool unidirectional) override;
188
QUICHE teama6ef0a62019-03-07 20:34:33 -0500189 protected:
190 // Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
191 // CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to
192 // make sure that all data streams are QuicSpdyStreams.
193 QuicSpdyStream* CreateIncomingStream(QuicStreamId id) override = 0;
renjietangbaea59c2019-05-29 15:08:14 -0700194 QuicSpdyStream* CreateIncomingStream(PendingStream* pending) override = 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500195 virtual QuicSpdyStream* CreateOutgoingBidirectionalStream() = 0;
196 virtual QuicSpdyStream* CreateOutgoingUnidirectionalStream() = 0;
197
198 QuicSpdyStream* GetSpdyDataStream(const QuicStreamId stream_id);
199
200 // If an incoming stream can be created, return true.
201 virtual bool ShouldCreateIncomingStream(QuicStreamId id) = 0;
202
203 // If an outgoing bidirectional/unidirectional stream can be created, return
204 // true.
205 virtual bool ShouldCreateOutgoingBidirectionalStream() = 0;
206 virtual bool ShouldCreateOutgoingUnidirectionalStream() = 0;
207
208 // Returns true if there are open HTTP requests.
209 bool ShouldKeepConnectionAlive() const override;
210
renjietange76b2da2019-05-13 14:50:23 -0700211 // Overridden to buffer incoming unidirectional streams for version 99.
212 bool UsesPendingStreams() const override;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500213
renjietangbb1c4892019-05-24 15:58:44 -0700214 // Overridden to Process HTTP/3 stream types. H/3 streams will be created from
215 // pending streams accordingly if the stream type can be read. Returns true if
216 // unidirectional streams are created.
217 bool ProcessPendingStream(PendingStream* pending) override;
renjietang0c558862019-05-08 13:26:23 -0700218
QUICHE teama6ef0a62019-03-07 20:34:33 -0500219 size_t WriteHeadersOnHeadersStreamImpl(
220 QuicStreamId id,
221 spdy::SpdyHeaderBlock headers,
222 bool fin,
223 QuicStreamId parent_stream_id,
224 int weight,
225 bool exclusive,
226 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
227
228 void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
229
230 bool supports_push_promise() { return supports_push_promise_; }
231
232 // Optional, enables instrumentation related to go/quic-hpack.
233 void SetHpackEncoderDebugVisitor(
234 std::unique_ptr<QuicHpackDebugVisitor> visitor);
235 void SetHpackDecoderDebugVisitor(
236 std::unique_ptr<QuicHpackDebugVisitor> visitor);
237
238 // Sets the maximum size of the header compression table spdy_framer_ is
239 // willing to use to encode header blocks.
240 void UpdateHeaderEncoderTableSize(uint32_t value);
241
242 // Called when SETTINGS_ENABLE_PUSH is received, only supported on
243 // server side.
244 void UpdateEnableServerPush(bool value);
245
246 bool IsConnected() { return connection()->connected(); }
247
renjietang118c8ac2019-07-30 11:43:59 -0700248 const QuicReceiveControlStream* receive_control_stream() const {
249 return receive_control_stream_;
250 }
251
QUICHE teama6ef0a62019-03-07 20:34:33 -0500252 private:
253 friend class test::QuicSpdySessionPeer;
254
255 class SpdyFramerVisitor;
256
257 // The following methods are called by the SimpleVisitor.
258
259 // Called when a HEADERS frame has been received.
260 void OnHeaders(spdy::SpdyStreamId stream_id,
261 bool has_priority,
fayang476683a2019-07-25 12:42:16 -0700262 const spdy::SpdyStreamPrecedence& precedence,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500263 bool fin);
264
QUICHE teama6ef0a62019-03-07 20:34:33 -0500265 // Called when a PRIORITY frame has been received.
fayang476683a2019-07-25 12:42:16 -0700266 void OnPriority(spdy::SpdyStreamId stream_id,
267 const spdy::SpdyStreamPrecedence& precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500268
renjietangc04c85f2019-07-25 14:07:27 -0700269 // Initializes HTTP/3 unidirectional streams if not yet initialzed.
270 void MaybeInitializeHttp3UnidirectionalStreams();
271
QUICHE teama6ef0a62019-03-07 20:34:33 -0500272 std::unique_ptr<QpackEncoder> qpack_encoder_;
273 std::unique_ptr<QpackDecoder> qpack_decoder_;
274
renjietang9818f8c2019-07-16 11:12:27 -0700275 // Pointer to the header stream in stream_map_.
276 QuicHeadersStream* headers_stream_;
renjietangfbeb5bf2019-04-19 15:06:20 -0700277
renjietang3a1bb802019-06-11 10:42:41 -0700278 // HTTP/3 control streams. They are owned by QuicSession inside dynamic
279 // stream map, and can be accessed by those unowned pointers below.
280 QuicSendControlStream* send_control_stream_;
281 QuicReceiveControlStream* receive_control_stream_;
282
QUICHE teama6ef0a62019-03-07 20:34:33 -0500283 // The maximum size of a header block that will be accepted from the peer,
284 // defined per spec as key + value + overhead per field (uncompressed).
285 size_t max_inbound_header_list_size_;
286
renjietang3a1bb802019-06-11 10:42:41 -0700287 // The maximum size of a header block that can be sent to the peer. This field
288 // is informed and set by the peer via SETTINGS frame.
289 // TODO(renjietang): Honor this field when sending headers.
290 size_t max_outbound_header_list_size_;
291
QUICHE teama6ef0a62019-03-07 20:34:33 -0500292 // Set during handshake. If true, resources in x-associated-content and link
293 // headers will be pushed.
294 bool server_push_enabled_;
295
296 // Data about the stream whose headers are being processed.
297 QuicStreamId stream_id_;
298 QuicStreamId promised_stream_id_;
299 bool fin_;
300 size_t frame_len_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500301
302 bool supports_push_promise_;
303
304 spdy::SpdyFramer spdy_framer_;
305 http2::Http2DecoderAdapter h2_deframer_;
306 std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
renjietangc2aa5cb2019-06-20 12:22:53 -0700307
308 // TODO(renjietang): Replace these two members with actual QPACK send streams.
309 NoopQpackStreamSenderDelegate encoder_stream_sender_delegate_;
310 NoopQpackStreamSenderDelegate decoder_stream_sender_delegate_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500311};
312
313} // namespace quic
314
315#endif // QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_SESSION_H_