summaryrefslogtreecommitdiff
path: root/chromium/net/quic/core/quic_spdy_session.h
blob: 17115a76139b563ea1b74bccf9c5cf7eed9453d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_QUIC_CORE_QUIC_SPDY_SESSION_H_
#define NET_QUIC_CORE_QUIC_SPDY_SESSION_H_

#include <cstddef>
#include <memory>

#include "base/macros.h"
#include "net/quic/core/quic_header_list.h"
#include "net/quic/core/quic_headers_stream.h"
#include "net/quic/core/quic_session.h"
#include "net/quic/core/quic_spdy_stream.h"
#include "net/quic/platform/api/quic_export.h"
#include "net/quic/platform/api/quic_string_piece.h"

namespace net {

namespace test {
class QuicSpdySessionPeer;
}  // namespace test

// QuicHpackDebugVisitor gathers data used for understanding HPACK HoL
// dynamics.  Specifically, it is to help predict the compression
// penalty of avoiding HoL by chagning how the dynamic table is used.
// In chromium, the concrete instance populates an UMA
// histogram with the data.
class QUIC_EXPORT_PRIVATE QuicHpackDebugVisitor {
 public:
  QuicHpackDebugVisitor();

  virtual ~QuicHpackDebugVisitor();

  // For each HPACK indexed representation processed, |elapsed| is
  // the time since the corresponding entry was added to the dynamic
  // table.
  virtual void OnUseEntry(QuicTime::Delta elapsed) = 0;

 private:
  DISALLOW_COPY_AND_ASSIGN(QuicHpackDebugVisitor);
};

// A QUIC session with a headers stream.
class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
 public:
  // Does not take ownership of |connection| or |visitor|.
  QuicSpdySession(QuicConnection* connection,
                  QuicSession::Visitor* visitor,
                  const QuicConfig& config);

  ~QuicSpdySession() override;

  void Initialize() override;

  // Called by |headers_stream_| when headers with a priority have been
  // received for this stream.  This method will only be called for server
  // streams.
  virtual void OnStreamHeadersPriority(QuicStreamId stream_id,
                                       SpdyPriority priority);

  // Called by |headers_stream_| when headers have been completely received
  // for a stream.  |fin| will be true if the fin flag was set in the headers
  // frame.
  virtual void OnStreamHeaderList(QuicStreamId stream_id,
                                  bool fin,
                                  size_t frame_len,
                                  const QuicHeaderList& header_list);

  // Called by |headers_stream_| when push promise headers have been
  // completely received.  |fin| will be true if the fin flag was set
  // in the headers.
  virtual void OnPromiseHeaderList(QuicStreamId stream_id,
                                   QuicStreamId promised_stream_id,
                                   size_t frame_len,
                                   const QuicHeaderList& header_list);

  // Sends contents of |iov| to spdy_framer_, returns number of bytes processd.
  size_t ProcessHeaderData(const struct iovec& iov, QuicTime timestamp);

  // Writes |headers| for the stream |id| to the dedicated headers stream.
  // If |fin| is true, then no more data will be sent for the stream |id|.
  // If provided, |ack_notifier_delegate| will be registered to be notified when
  // we have seen ACKs for all packets resulting from this call.
  virtual size_t WriteHeaders(
      QuicStreamId id,
      SpdyHeaderBlock headers,
      bool fin,
      SpdyPriority priority,
      QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);

  // Write |headers| for |promised_stream_id| on |original_stream_id| in a
  // PUSH_PROMISE frame to peer.
  // Return the size, in bytes, of the resulting PUSH_PROMISE frame.
  virtual size_t WritePushPromise(QuicStreamId original_stream_id,
                                  QuicStreamId promised_stream_id,
                                  SpdyHeaderBlock headers);

  // For forcing HOL blocking.  This encapsulates data from other
  // streams into HTTP/2 data frames on the headers stream.
  QuicConsumedData WritevStreamData(
      QuicStreamId id,
      QuicIOVector iov,
      QuicStreamOffset offset,
      bool fin,
      QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);

  // Sends SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame.
  size_t SendMaxHeaderListSize(size_t value);

  QuicHeadersStream* headers_stream() { return headers_stream_.get(); }

  // Called when Head of Line Blocking happens in the headers stream.
  // |delta| indicates how long that piece of data has been blocked.
  virtual void OnHeadersHeadOfLineBlocking(QuicTime::Delta delta);

  // Called by the stream on creation to set priority in the write blocked list.
  void RegisterStreamPriority(QuicStreamId id, SpdyPriority priority);
  // Called by the stream on deletion to clear priority crom the write blocked
  // list.
  void UnregisterStreamPriority(QuicStreamId id);
  // Called by the stream on SetPriority to update priority on the write blocked
  // list.
  void UpdateStreamPriority(QuicStreamId id, SpdyPriority new_priority);

  void OnConfigNegotiated() override;

  // Called by |headers_stream_| when |force_hol_blocking_| is true.
  virtual void OnStreamFrameData(QuicStreamId stream_id,
                                 const char* data,
                                 size_t len,
                                 bool fin);

  bool force_hol_blocking() const { return force_hol_blocking_; }

  bool server_push_enabled() const { return server_push_enabled_; }

  void UpdateCurMaxTimeStamp(QuicTime timestamp) {
    cur_max_timestamp_ = std::max(timestamp, cur_max_timestamp_);
  }

  // Called by |QuicHeadersStream::UpdateEnableServerPush()| with
  // value from SETTINGS_ENABLE_PUSH.
  void set_server_push_enabled(bool enable) { server_push_enabled_ = enable; }

  // Return true if this session wants to release headers stream's buffer
  // aggressively.
  virtual bool ShouldReleaseHeadersStreamSequencerBuffer();

  SpdyFramer* spdy_framer() { return &spdy_framer_; }

  void CloseConnectionWithDetails(QuicErrorCode error,
                                  const std::string& details);

  // Sets how much encoded data the hpack decoder of spdy_framer_ is willing to
  // buffer.
  void set_max_decode_buffer_size_bytes(size_t max_decode_buffer_size_bytes) {
    spdy_framer_.set_max_decode_buffer_size_bytes(max_decode_buffer_size_bytes);
  }

  void set_max_uncompressed_header_bytes(
      size_t set_max_uncompressed_header_bytes);

 protected:
  // TODO(ckrasic) - remove these two when
  // FLAGS_quic_reloadable_flag_quic_refactor_stream_creation is
  // deprecated.
  // Override CreateIncomingDynamicStream() and CreateOutgoingDynamicStream()
  // with QuicSpdyStream return type to make sure that all data streams are
  // QuicSpdyStreams.
  QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override = 0;
  QuicSpdyStream* CreateOutgoingDynamicStream(SpdyPriority priority) override =
      0;

  QuicSpdyStream* MaybeCreateIncomingDynamicStream(QuicStreamId id) override;
  QuicSpdyStream* MaybeCreateOutgoingDynamicStream(
      SpdyPriority priority) override;

  QuicSpdyStream* GetSpdyDataStream(const QuicStreamId stream_id);

  // TODO(ckrasic) - remove these two when
  // FLAGS_quic_reloadable_flag_quic_refactor_stream_creation is
  // depreacted.

  // If an incoming stream can be created, return true.
  virtual bool ShouldCreateIncomingDynamicStream(QuicStreamId id) = 0;

  // If an outgoing stream can be created, return true.
  virtual bool ShouldCreateOutgoingDynamicStream() = 0;

  void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;

  bool supports_push_promise() { return supports_push_promise_; }

  // Experimental: force HPACK to use static table and huffman coding
  // only.  Part of exploring improvements related to headers stream
  // induced HOL blocking in QUIC.
  void DisableHpackDynamicTable();

  // Optional, enables instrumentation related to go/quic-hpack.
  void SetHpackEncoderDebugVisitor(
      std::unique_ptr<QuicHpackDebugVisitor> visitor);
  void SetHpackDecoderDebugVisitor(
      std::unique_ptr<QuicHpackDebugVisitor> visitor);

  // Sets the maximum size of the header compression table spdy_framer_ is
  // willing to use to decode header blocks.
  void UpdateHeaderEncoderTableSize(uint32_t value);

  // Called when SETTINGS_ENABLE_PUSH is received, only supported on
  // server side.
  void UpdateEnableServerPush(bool value);

  bool IsConnected() { return connection()->connected(); }

 private:
  friend class test::QuicSpdySessionPeer;

  class SpdyFramerVisitor;

  // The following methods are called by the SimpleVisitor.

  // Called when a HEADERS frame has been received.
  void OnHeaders(SpdyStreamId stream_id,
                 bool has_priority,
                 SpdyPriority priority,
                 bool fin);

  // Called when a PUSH_PROMISE frame has been received.
  void OnPushPromise(SpdyStreamId stream_id,
                     SpdyStreamId promised_stream_id,
                     bool end);

  // Called when the complete list of headers is available.
  void OnHeaderList(const QuicHeaderList& header_list);

  // Called when the size of the compressed frame payload is available.
  void OnCompressedFrameSize(size_t frame_len);

  // For force HOL blocking, where stream frames from all streams are
  // plumbed through headers stream as HTTP/2 data frames.
  // The following two return false if force_hol_blocking_ is false.
  bool OnDataFrameHeader(QuicStreamId stream_id, size_t length, bool fin);
  bool OnStreamFrameData(QuicStreamId stream_id, const char* data, size_t len);

  // Helper for |WritevStreamData()|.
  void WriteDataFrame(
      QuicStreamId stream_id,
      QuicStringPiece data,
      bool fin,
      QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);

  // This was formerly QuicHeadersStream::WriteHeaders.  Needs to be
  // separate from QuicSpdySession::WriteHeaders because tests call
  // this but mock the latter.
  size_t WriteHeadersImpl(
      QuicStreamId id,
      SpdyHeaderBlock headers,
      bool fin,
      SpdyPriority priority,
      QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);

  std::unique_ptr<QuicHeadersStream> headers_stream_;

  // If set, redirect all data through the headers stream in order to
  // simulate forced HOL blocking between streams as happens in
  // HTTP/2 over TCP.
  bool force_hol_blocking_;

  // Set during handshake. If true, resources in x-associated-content and link
  // headers will be pushed.
  bool server_push_enabled_;

  // Data about the stream whose headers are being processed.
  QuicStreamId stream_id_;
  QuicStreamId promised_stream_id_;
  bool fin_;
  size_t frame_len_;
  size_t uncompressed_frame_len_;

  bool supports_push_promise_;

  // Timestamps used to measure HOL blocking, these are recorded by
  // the sequencer approximate to the time of arrival off the wire.
  // |cur_max_timestamp_| tracks the most recent arrival time of
  // frames for current (at the headers stream level) processed
  // stream's headers, and |prev_max_timestamp_| tracks the most
  // recent arrival time of lower numbered streams.
  QuicTime cur_max_timestamp_;
  QuicTime prev_max_timestamp_;

  SpdyFramer spdy_framer_;
  std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;

  DISALLOW_COPY_AND_ASSIGN(QuicSpdySession);
};

}  // namespace net

#endif  // NET_QUIC_CORE_QUIC_SPDY_SESSION_H_