blob: 5af73f10b06fe4d45514fcae3392a1cab1545d2d [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"
14#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h"
15#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
16#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h"
17#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h"
18#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
19#include "net/third_party/quiche/src/quic/core/quic_session.h"
20#include "net/third_party/quiche/src/quic/core/quic_versions.h"
21#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050022#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
23#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h"
24
25namespace quic {
26
27namespace test {
28class QuicSpdySessionPeer;
29} // namespace test
30
renjietangbb1c4892019-05-24 15:58:44 -070031// Unidirectional stream types define by IETF HTTP/3 draft in section 3.2.
32const uint64_t kControlStream = 0;
33const uint64_t kServerPushStream = 1;
34const uint64_t kQpackEncoderStream = 2;
35const uint64_t kQpackDecoderStream = 3;
36
QUICHE teama6ef0a62019-03-07 20:34:33 -050037// QuicHpackDebugVisitor gathers data used for understanding HPACK HoL
38// dynamics. Specifically, it is to help predict the compression
39// penalty of avoiding HoL by chagning how the dynamic table is used.
40// In chromium, the concrete instance populates an UMA
41// histogram with the data.
42class QUIC_EXPORT_PRIVATE QuicHpackDebugVisitor {
43 public:
44 QuicHpackDebugVisitor();
45 QuicHpackDebugVisitor(const QuicHpackDebugVisitor&) = delete;
46 QuicHpackDebugVisitor& operator=(const QuicHpackDebugVisitor&) = delete;
47
48 virtual ~QuicHpackDebugVisitor();
49
50 // For each HPACK indexed representation processed, |elapsed| is
51 // the time since the corresponding entry was added to the dynamic
52 // table.
53 virtual void OnUseEntry(QuicTime::Delta elapsed) = 0;
54};
55
56// A QUIC session with a headers stream.
57class QUIC_EXPORT_PRIVATE QuicSpdySession
58 : public QuicSession,
59 public QpackEncoder::DecoderStreamErrorDelegate,
60 public QpackEncoderStreamSender::Delegate,
61 public QpackDecoder::EncoderStreamErrorDelegate,
62 public QpackDecoderStreamSender::Delegate {
63 public:
64 // Does not take ownership of |connection| or |visitor|.
65 QuicSpdySession(QuicConnection* connection,
66 QuicSession::Visitor* visitor,
67 const QuicConfig& config,
68 const ParsedQuicVersionVector& supported_versions);
69 QuicSpdySession(const QuicSpdySession&) = delete;
70 QuicSpdySession& operator=(const QuicSpdySession&) = delete;
71
72 ~QuicSpdySession() override;
73
74 void Initialize() override;
75
76 // QpackEncoder::DecoderStreamErrorDelegate implementation.
77 void OnDecoderStreamError(QuicStringPiece error_message) override;
78
79 // QpackEncoderStreamSender::Delegate implemenation.
80 void WriteEncoderStreamData(QuicStringPiece data) override;
81
82 // QpackDecoder::EncoderStreamErrorDelegate implementation.
83 void OnEncoderStreamError(QuicStringPiece error_message) override;
84
85 // QpackDecoderStreamSender::Delegate implementation.
86 void WriteDecoderStreamData(QuicStringPiece data) override;
87
88 // Called by |headers_stream_| when headers with a priority have been
89 // received for a stream. This method will only be called for server streams.
90 virtual void OnStreamHeadersPriority(QuicStreamId stream_id,
91 spdy::SpdyPriority priority);
92
93 // Called by |headers_stream_| when headers have been completely received
94 // for a stream. |fin| will be true if the fin flag was set in the headers
95 // frame.
96 virtual void OnStreamHeaderList(QuicStreamId stream_id,
97 bool fin,
98 size_t frame_len,
99 const QuicHeaderList& header_list);
100
101 // Called by |headers_stream_| when push promise headers have been
102 // completely received. |fin| will be true if the fin flag was set
103 // in the headers.
104 virtual void OnPromiseHeaderList(QuicStreamId stream_id,
105 QuicStreamId promised_stream_id,
106 size_t frame_len,
107 const QuicHeaderList& header_list);
108
109 // Called by |headers_stream_| when a PRIORITY frame has been received for a
110 // stream. This method will only be called for server streams.
111 virtual void OnPriorityFrame(QuicStreamId stream_id,
112 spdy::SpdyPriority priority);
113
114 // Sends contents of |iov| to h2_deframer_, returns number of bytes processed.
115 size_t ProcessHeaderData(const struct iovec& iov);
116
117 // Writes |headers| for the stream |id| to the dedicated headers stream.
118 // If |fin| is true, then no more data will be sent for the stream |id|.
119 // If provided, |ack_notifier_delegate| will be registered to be notified when
120 // we have seen ACKs for all packets resulting from this call.
121 virtual size_t WriteHeadersOnHeadersStream(
122 QuicStreamId id,
123 spdy::SpdyHeaderBlock headers,
124 bool fin,
125 spdy::SpdyPriority priority,
126 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
127
128 // Writes a PRIORITY frame the to peer. Returns the size in bytes of the
129 // resulting PRIORITY frame for QUIC_VERSION_43 and above. Otherwise, does
130 // nothing and returns 0.
131 size_t WritePriority(QuicStreamId id,
132 QuicStreamId parent_stream_id,
133 int weight,
134 bool exclusive);
135
136 // Write |headers| for |promised_stream_id| on |original_stream_id| in a
137 // PUSH_PROMISE frame to peer.
138 // Return the size, in bytes, of the resulting PUSH_PROMISE frame.
139 virtual size_t WritePushPromise(QuicStreamId original_stream_id,
140 QuicStreamId promised_stream_id,
141 spdy::SpdyHeaderBlock headers);
142
143 // Sends SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame.
QUICHE team2252b702019-05-14 23:55:14 -0400144 void SendMaxHeaderListSize(size_t value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500145
146 QpackEncoder* qpack_encoder();
147 QpackDecoder* qpack_decoder();
renjietangfbeb5bf2019-04-19 15:06:20 -0700148 QuicHeadersStream* headers_stream() {
renjietang615f13b2019-05-06 17:08:02 -0700149 return eliminate_static_stream_map() ? unowned_headers_stream_
150 : headers_stream_.get();
renjietangfbeb5bf2019-04-19 15:06:20 -0700151 }
152
153 const QuicHeadersStream* headers_stream() const {
renjietang615f13b2019-05-06 17:08:02 -0700154 return eliminate_static_stream_map() ? unowned_headers_stream_
155 : headers_stream_.get();
renjietangfbeb5bf2019-04-19 15:06:20 -0700156 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500157
158 bool server_push_enabled() const { return server_push_enabled_; }
159
160 // Called by |QuicHeadersStream::UpdateEnableServerPush()| with
161 // value from SETTINGS_ENABLE_PUSH.
162 void set_server_push_enabled(bool enable) { server_push_enabled_ = enable; }
163
164 // Return true if this session wants to release headers stream's buffer
165 // aggressively.
166 virtual bool ShouldReleaseHeadersStreamSequencerBuffer();
167
168 void CloseConnectionWithDetails(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700169 const std::string& details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500170
171 void set_max_inbound_header_list_size(size_t max_inbound_header_list_size) {
172 max_inbound_header_list_size_ = max_inbound_header_list_size;
173 }
174
renjietangfee2cc32019-04-05 11:32:07 -0700175 size_t max_inbound_header_list_size() const {
176 return max_inbound_header_list_size_;
177 }
178
QUICHE teamc2653c42019-03-08 13:30:06 -0800179 // Returns true if the session has active request streams.
180 bool HasActiveRequestStreams() const;
181
QUICHE teama6ef0a62019-03-07 20:34:33 -0500182 protected:
183 // Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
184 // CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to
185 // make sure that all data streams are QuicSpdyStreams.
186 QuicSpdyStream* CreateIncomingStream(QuicStreamId id) override = 0;
renjietangbaea59c2019-05-29 15:08:14 -0700187 QuicSpdyStream* CreateIncomingStream(PendingStream* pending) override = 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500188 virtual QuicSpdyStream* CreateOutgoingBidirectionalStream() = 0;
189 virtual QuicSpdyStream* CreateOutgoingUnidirectionalStream() = 0;
190
191 QuicSpdyStream* GetSpdyDataStream(const QuicStreamId stream_id);
192
193 // If an incoming stream can be created, return true.
194 virtual bool ShouldCreateIncomingStream(QuicStreamId id) = 0;
195
196 // If an outgoing bidirectional/unidirectional stream can be created, return
197 // true.
198 virtual bool ShouldCreateOutgoingBidirectionalStream() = 0;
199 virtual bool ShouldCreateOutgoingUnidirectionalStream() = 0;
200
201 // Returns true if there are open HTTP requests.
202 bool ShouldKeepConnectionAlive() const override;
203
renjietange76b2da2019-05-13 14:50:23 -0700204 // Overridden to buffer incoming unidirectional streams for version 99.
205 bool UsesPendingStreams() const override;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500206
renjietangbb1c4892019-05-24 15:58:44 -0700207 // Overridden to Process HTTP/3 stream types. H/3 streams will be created from
208 // pending streams accordingly if the stream type can be read. Returns true if
209 // unidirectional streams are created.
210 bool ProcessPendingStream(PendingStream* pending) override;
renjietang0c558862019-05-08 13:26:23 -0700211
QUICHE teama6ef0a62019-03-07 20:34:33 -0500212 size_t WriteHeadersOnHeadersStreamImpl(
213 QuicStreamId id,
214 spdy::SpdyHeaderBlock headers,
215 bool fin,
216 QuicStreamId parent_stream_id,
217 int weight,
218 bool exclusive,
219 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
220
221 void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
222
223 bool supports_push_promise() { return supports_push_promise_; }
224
225 // Optional, enables instrumentation related to go/quic-hpack.
226 void SetHpackEncoderDebugVisitor(
227 std::unique_ptr<QuicHpackDebugVisitor> visitor);
228 void SetHpackDecoderDebugVisitor(
229 std::unique_ptr<QuicHpackDebugVisitor> visitor);
230
231 // Sets the maximum size of the header compression table spdy_framer_ is
232 // willing to use to encode header blocks.
233 void UpdateHeaderEncoderTableSize(uint32_t value);
234
235 // Called when SETTINGS_ENABLE_PUSH is received, only supported on
236 // server side.
237 void UpdateEnableServerPush(bool value);
238
239 bool IsConnected() { return connection()->connected(); }
240
241 // Sets how much encoded data the hpack decoder of h2_deframer_ is willing to
242 // buffer.
243 void set_max_decode_buffer_size_bytes(size_t max_decode_buffer_size_bytes) {
244 h2_deframer_.GetHpackDecoder()->set_max_decode_buffer_size_bytes(
245 max_decode_buffer_size_bytes);
246 }
247
248 void set_max_uncompressed_header_bytes(
249 size_t set_max_uncompressed_header_bytes);
250
251 private:
252 friend class test::QuicSpdySessionPeer;
253
254 class SpdyFramerVisitor;
255
256 // The following methods are called by the SimpleVisitor.
257
258 // Called when a HEADERS frame has been received.
259 void OnHeaders(spdy::SpdyStreamId stream_id,
260 bool has_priority,
261 spdy::SpdyPriority priority,
262 bool fin);
263
264 // Called when a PUSH_PROMISE frame has been received.
265 void OnPushPromise(spdy::SpdyStreamId stream_id,
266 spdy::SpdyStreamId promised_stream_id,
267 bool end);
268
269 // Called when a PRIORITY frame has been received.
270 void OnPriority(spdy::SpdyStreamId stream_id, spdy::SpdyPriority priority);
271
272 // Called when the complete list of headers is available.
273 void OnHeaderList(const QuicHeaderList& header_list);
274
275 // Called when the size of the compressed frame payload is available.
276 void OnCompressedFrameSize(size_t frame_len);
277
278 std::unique_ptr<QpackEncoder> qpack_encoder_;
279 std::unique_ptr<QpackDecoder> qpack_decoder_;
280
281 // TODO(123528590): Remove this member.
282 std::unique_ptr<QuicHeadersStream> headers_stream_;
283
renjietangfbeb5bf2019-04-19 15:06:20 -0700284 // Unowned headers stream pointer that points to the stream
285 // in dynamic_stream_map.
286 // TODO(renjietang): Merge this with headers_stream_ and clean up other
287 // static_stream_map logic when flag eliminate_static_stream_map
288 // is deprecated.
289 QuicHeadersStream* unowned_headers_stream_;
290
QUICHE teama6ef0a62019-03-07 20:34:33 -0500291 // The maximum size of a header block that will be accepted from the peer,
292 // defined per spec as key + value + overhead per field (uncompressed).
293 size_t max_inbound_header_list_size_;
294
295 // Set during handshake. If true, resources in x-associated-content and link
296 // headers will be pushed.
297 bool server_push_enabled_;
298
299 // Data about the stream whose headers are being processed.
300 QuicStreamId stream_id_;
301 QuicStreamId promised_stream_id_;
302 bool fin_;
303 size_t frame_len_;
304 size_t uncompressed_frame_len_;
305
306 bool supports_push_promise_;
307
308 spdy::SpdyFramer spdy_framer_;
309 http2::Http2DecoderAdapter h2_deframer_;
310 std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
311};
312
313} // namespace quic
314
315#endif // QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_SESSION_H_