blob: f16e3bd19167e60114c3e83beedcb2aded257b29 [file] [log] [blame]
QUICHE team82dee2f2019-01-18 12:35:12 -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#ifndef QUICHE_SPDY_CORE_SPDY_FRAMER_H_
6#define QUICHE_SPDY_CORE_SPDY_FRAMER_H_
7
8#include <stddef.h>
9
10#include <cstdint>
11#include <map>
12#include <memory>
bnc44712912019-08-15 18:58:14 -070013#include <string>
QUICHE team82dee2f2019-01-18 12:35:12 -050014#include <utility>
15
bnc45ccf4b2020-01-21 19:05:27 -080016#include "net/third_party/quiche/src/common/platform/api/quiche_export.h"
bnc7f82d042020-01-03 12:18:53 -080017#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
QUICHE team82dee2f2019-01-18 12:35:12 -050018#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h"
19#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h"
20#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
21#include "net/third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h"
22#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
23#include "net/third_party/quiche/src/spdy/core/zero_copy_output_buffer.h"
QUICHE team82dee2f2019-01-18 12:35:12 -050024
25namespace spdy {
26
27namespace test {
28
29class SpdyFramerPeer;
30class SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
31class SpdyFramerTest_PushPromiseFramesWithIterator_Test;
32
33} // namespace test
34
bnc45ccf4b2020-01-21 19:05:27 -080035class QUICHE_EXPORT_PRIVATE SpdyFrameSequence {
QUICHE team82dee2f2019-01-18 12:35:12 -050036 public:
37 virtual ~SpdyFrameSequence() {}
38
39 // Serializes the next frame in the sequence to |output|. Returns the number
40 // of bytes written to |output|.
41 virtual size_t NextFrame(ZeroCopyOutputBuffer* output) = 0;
42
43 // Returns true iff there is at least one more frame in the sequence.
44 virtual bool HasNextFrame() const = 0;
45
46 // Get SpdyFrameIR of the frame to be serialized.
47 virtual const SpdyFrameIR& GetIR() const = 0;
48};
49
bnc45ccf4b2020-01-21 19:05:27 -080050class QUICHE_EXPORT_PRIVATE SpdyFramer {
QUICHE team82dee2f2019-01-18 12:35:12 -050051 public:
52 enum CompressionOption {
53 ENABLE_COMPRESSION,
54 DISABLE_COMPRESSION,
55 };
56
57 // Create a SpdyFrameSequence to serialize |frame_ir|.
58 static std::unique_ptr<SpdyFrameSequence> CreateIterator(
59 SpdyFramer* framer,
60 std::unique_ptr<const SpdyFrameIR> frame_ir);
61
62 // Gets the serialized flags for the given |frame|.
63 static uint8_t GetSerializedFlags(const SpdyFrameIR& frame);
64
65 // Serialize a data frame.
66 static SpdySerializedFrame SerializeData(const SpdyDataIR& data_ir);
67 // Serializes the data frame header and optionally padding length fields,
68 // excluding actual data payload and padding.
69 static SpdySerializedFrame SerializeDataFrameHeaderWithPaddingLengthField(
70 const SpdyDataIR& data_ir);
71
72 // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
73 // frame is used to implement per stream flow control.
74 static SpdySerializedFrame SerializeWindowUpdate(
75 const SpdyWindowUpdateIR& window_update);
76
77 explicit SpdyFramer(CompressionOption option);
78
79 virtual ~SpdyFramer();
80
81 // Set debug callbacks to be called from the framer. The debug visitor is
82 // completely optional and need not be set in order for normal operation.
83 // If this is called multiple times, only the last visitor will be used.
84 void set_debug_visitor(SpdyFramerDebugVisitorInterface* debug_visitor);
85
86 SpdySerializedFrame SerializeRstStream(
87 const SpdyRstStreamIR& rst_stream) const;
88
89 // Serializes a SETTINGS frame. The SETTINGS frame is
90 // used to communicate name/value pairs relevant to the communication channel.
91 SpdySerializedFrame SerializeSettings(const SpdySettingsIR& settings) const;
92
93 // Serializes a PING frame. The unique_id is used to
94 // identify the ping request/response.
95 SpdySerializedFrame SerializePing(const SpdyPingIR& ping) const;
96
97 // Serializes a GOAWAY frame. The GOAWAY frame is used
98 // prior to the shutting down of the TCP connection, and includes the
99 // stream_id of the last stream the sender of the frame is willing to process
100 // to completion.
101 SpdySerializedFrame SerializeGoAway(const SpdyGoAwayIR& goaway) const;
102
103 // Serializes a HEADERS frame. The HEADERS frame is used
104 // for sending headers.
105 SpdySerializedFrame SerializeHeaders(const SpdyHeadersIR& headers);
106
107 // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
108 // to inform the client that it will be receiving an additional stream
109 // in response to the original request. The frame includes synthesized
110 // headers to explain the upcoming data.
111 SpdySerializedFrame SerializePushPromise(
112 const SpdyPushPromiseIR& push_promise);
113
114 // Serializes a CONTINUATION frame. The CONTINUATION frame is used
115 // to continue a sequence of header block fragments.
116 SpdySerializedFrame SerializeContinuation(
117 const SpdyContinuationIR& continuation) const;
118
119 // Serializes an ALTSVC frame. The ALTSVC frame advertises the
120 // availability of an alternative service to the client.
121 SpdySerializedFrame SerializeAltSvc(const SpdyAltSvcIR& altsvc);
122
123 // Serializes a PRIORITY frame. The PRIORITY frame advises a change in
124 // the relative priority of the given stream.
125 SpdySerializedFrame SerializePriority(const SpdyPriorityIR& priority) const;
126
127 // Serializes an unknown frame given a frame header and payload.
128 SpdySerializedFrame SerializeUnknown(const SpdyUnknownIR& unknown) const;
129
130 // Serialize a frame of unknown type.
131 SpdySerializedFrame SerializeFrame(const SpdyFrameIR& frame);
132
133 // Serialize a data frame.
134 bool SerializeData(const SpdyDataIR& data,
135 ZeroCopyOutputBuffer* output) const;
136
137 // Serializes the data frame header and optionally padding length fields,
138 // excluding actual data payload and padding.
139 bool SerializeDataFrameHeaderWithPaddingLengthField(
140 const SpdyDataIR& data,
141 ZeroCopyOutputBuffer* output) const;
142
143 bool SerializeRstStream(const SpdyRstStreamIR& rst_stream,
144 ZeroCopyOutputBuffer* output) const;
145
146 // Serializes a SETTINGS frame. The SETTINGS frame is
147 // used to communicate name/value pairs relevant to the communication channel.
148 bool SerializeSettings(const SpdySettingsIR& settings,
149 ZeroCopyOutputBuffer* output) const;
150
151 // Serializes a PING frame. The unique_id is used to
152 // identify the ping request/response.
153 bool SerializePing(const SpdyPingIR& ping,
154 ZeroCopyOutputBuffer* output) const;
155
156 // Serializes a GOAWAY frame. The GOAWAY frame is used
157 // prior to the shutting down of the TCP connection, and includes the
158 // stream_id of the last stream the sender of the frame is willing to process
159 // to completion.
160 bool SerializeGoAway(const SpdyGoAwayIR& goaway,
161 ZeroCopyOutputBuffer* output) const;
162
163 // Serializes a HEADERS frame. The HEADERS frame is used
164 // for sending headers.
165 bool SerializeHeaders(const SpdyHeadersIR& headers,
166 ZeroCopyOutputBuffer* output);
167
168 // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
169 // frame is used to implement per stream flow control.
170 bool SerializeWindowUpdate(const SpdyWindowUpdateIR& window_update,
171 ZeroCopyOutputBuffer* output) const;
172
173 // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
174 // to inform the client that it will be receiving an additional stream
175 // in response to the original request. The frame includes synthesized
176 // headers to explain the upcoming data.
177 bool SerializePushPromise(const SpdyPushPromiseIR& push_promise,
178 ZeroCopyOutputBuffer* output);
179
180 // Serializes a CONTINUATION frame. The CONTINUATION frame is used
181 // to continue a sequence of header block fragments.
182 bool SerializeContinuation(const SpdyContinuationIR& continuation,
183 ZeroCopyOutputBuffer* output) const;
184
185 // Serializes an ALTSVC frame. The ALTSVC frame advertises the
186 // availability of an alternative service to the client.
187 bool SerializeAltSvc(const SpdyAltSvcIR& altsvc,
188 ZeroCopyOutputBuffer* output);
189
190 // Serializes a PRIORITY frame. The PRIORITY frame advises a change in
191 // the relative priority of the given stream.
192 bool SerializePriority(const SpdyPriorityIR& priority,
193 ZeroCopyOutputBuffer* output) const;
194
195 // Serializes an unknown frame given a frame header and payload.
196 bool SerializeUnknown(const SpdyUnknownIR& unknown,
197 ZeroCopyOutputBuffer* output) const;
198
199 // Serialize a frame of unknown type.
200 size_t SerializeFrame(const SpdyFrameIR& frame, ZeroCopyOutputBuffer* output);
201
202 // Returns whether this SpdyFramer will compress header blocks using HPACK.
203 bool compression_enabled() const {
204 return compression_option_ == ENABLE_COMPRESSION;
205 }
206
207 void SetHpackIndexingPolicy(HpackEncoder::IndexingPolicy policy) {
208 GetHpackEncoder()->SetIndexingPolicy(std::move(policy));
209 }
210
211 // Updates the maximum size of the header encoder compression table.
212 void UpdateHeaderEncoderTableSize(uint32_t value);
213
214 // Returns the maximum size of the header encoder compression table.
215 size_t header_encoder_table_size() const;
216
217 void SetEncoderHeaderTableDebugVisitor(
218 std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor);
219
220 // Get (and lazily initialize) the HPACK encoder state.
221 HpackEncoder* GetHpackEncoder();
222
223 // Returns the estimate of dynamically allocated memory in bytes.
224 size_t EstimateMemoryUsage() const;
225
226 protected:
227 friend class test::SpdyFramerPeer;
228 friend class test::SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
229 friend class test::SpdyFramerTest_PushPromiseFramesWithIterator_Test;
230
231 // Iteratively converts a SpdyFrameIR into an appropriate sequence of Spdy
232 // frames.
233 // Example usage:
234 // std::unique_ptr<SpdyFrameSequence> it = CreateIterator(framer, frame_ir);
235 // while (it->HasNextFrame()) {
236 // if(it->NextFrame(output) == 0) {
237 // // Write failed;
238 // }
239 // }
bnc45ccf4b2020-01-21 19:05:27 -0800240 class QUICHE_EXPORT_PRIVATE SpdyFrameIterator : public SpdyFrameSequence {
QUICHE team82dee2f2019-01-18 12:35:12 -0500241 public:
242 // Creates an iterator with the provided framer.
243 // Does not take ownership of |framer|.
244 // |framer| must outlive this instance.
245 explicit SpdyFrameIterator(SpdyFramer* framer);
246 ~SpdyFrameIterator() override;
247
248 // Serializes the next frame in the sequence to |output|. Returns the number
249 // of bytes written to |output|.
250 size_t NextFrame(ZeroCopyOutputBuffer* output) override;
251
252 // Returns true iff there is at least one more frame in the sequence.
253 bool HasNextFrame() const override;
254
255 // SpdyFrameIterator is neither copyable nor movable.
256 SpdyFrameIterator(const SpdyFrameIterator&) = delete;
257 SpdyFrameIterator& operator=(const SpdyFrameIterator&) = delete;
258
259 protected:
260 virtual size_t GetFrameSizeSansBlock() const = 0;
bnc44712912019-08-15 18:58:14 -0700261 virtual bool SerializeGivenEncoding(const std::string& encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500262 ZeroCopyOutputBuffer* output) const = 0;
263
264 SpdyFramer* GetFramer() const { return framer_; }
265
266 void SetEncoder(const SpdyFrameWithHeaderBlockIR* ir) {
267 encoder_ =
268 framer_->GetHpackEncoder()->EncodeHeaderSet(ir->header_block());
269 }
270
271 bool has_next_frame() const { return has_next_frame_; }
272
273 private:
274 SpdyFramer* const framer_;
275 std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoder_;
276 bool is_first_frame_;
277 bool has_next_frame_;
278 };
279
280 // Iteratively converts a SpdyHeadersIR (with a possibly huge
281 // SpdyHeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
282 // write to the output.
bnc45ccf4b2020-01-21 19:05:27 -0800283 class QUICHE_EXPORT_PRIVATE SpdyHeaderFrameIterator
284 : public SpdyFrameIterator {
QUICHE team82dee2f2019-01-18 12:35:12 -0500285 public:
286 // Does not take ownership of |framer|. Take ownership of |headers_ir|.
287 SpdyHeaderFrameIterator(SpdyFramer* framer,
288 std::unique_ptr<const SpdyHeadersIR> headers_ir);
289
290 ~SpdyHeaderFrameIterator() override;
291
292 private:
293 const SpdyFrameIR& GetIR() const override;
294 size_t GetFrameSizeSansBlock() const override;
bnc44712912019-08-15 18:58:14 -0700295 bool SerializeGivenEncoding(const std::string& encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500296 ZeroCopyOutputBuffer* output) const override;
297
298 const std::unique_ptr<const SpdyHeadersIR> headers_ir_;
299 };
300
301 // Iteratively converts a SpdyPushPromiseIR (with a possibly huge
302 // SpdyHeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
303 // write to the output.
bnc45ccf4b2020-01-21 19:05:27 -0800304 class QUICHE_EXPORT_PRIVATE SpdyPushPromiseFrameIterator
QUICHE team82dee2f2019-01-18 12:35:12 -0500305 : public SpdyFrameIterator {
306 public:
307 // Does not take ownership of |framer|. Take ownership of |push_promise_ir|.
308 SpdyPushPromiseFrameIterator(
309 SpdyFramer* framer,
310 std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir);
311
312 ~SpdyPushPromiseFrameIterator() override;
313
314 private:
315 const SpdyFrameIR& GetIR() const override;
316 size_t GetFrameSizeSansBlock() const override;
bnc44712912019-08-15 18:58:14 -0700317 bool SerializeGivenEncoding(const std::string& encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500318 ZeroCopyOutputBuffer* output) const override;
319
320 const std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir_;
321 };
322
323 // Converts a SpdyFrameIR into one Spdy frame (a sequence of length 1), and
324 // write it to the output.
bnc45ccf4b2020-01-21 19:05:27 -0800325 class QUICHE_EXPORT_PRIVATE SpdyControlFrameIterator
QUICHE team82dee2f2019-01-18 12:35:12 -0500326 : public SpdyFrameSequence {
327 public:
328 SpdyControlFrameIterator(SpdyFramer* framer,
329 std::unique_ptr<const SpdyFrameIR> frame_ir);
330 ~SpdyControlFrameIterator() override;
331
332 size_t NextFrame(ZeroCopyOutputBuffer* output) override;
333
334 bool HasNextFrame() const override;
335
336 const SpdyFrameIR& GetIR() const override;
337
338 private:
339 SpdyFramer* const framer_;
340 std::unique_ptr<const SpdyFrameIR> frame_ir_;
341 bool has_next_frame_ = true;
342 };
343
344 private:
345 void SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers,
346 uint8_t* flags,
347 size_t* size,
bnc44712912019-08-15 18:58:14 -0700348 std::string* hpack_encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500349 int* weight,
350 size_t* length_field);
351 void SerializePushPromiseBuilderHelper(const SpdyPushPromiseIR& push_promise,
352 uint8_t* flags,
bnc44712912019-08-15 18:58:14 -0700353 std::string* hpack_encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500354 size_t* size);
355
356 std::unique_ptr<HpackEncoder> hpack_encoder_;
357
358 SpdyFramerDebugVisitorInterface* debug_visitor_;
359
360 // Determines whether HPACK compression is used.
361 const CompressionOption compression_option_;
362};
363
364} // namespace spdy
365
366#endif // QUICHE_SPDY_CORE_SPDY_FRAMER_H_