blob: d6f0f889876ec900b50e902e5bd535d8ab86af82 [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
QUICHE team5be974e2020-12-29 18:35:24 -05005#include "spdy/core/spdy_framer.h"
QUICHE team82dee2f2019-01-18 12:35:12 -05006
7#include <algorithm>
8#include <cstdint>
9#include <iterator>
10#include <list>
11#include <new>
bnc463f2352019-10-10 04:49:34 -070012#include <utility>
QUICHE team82dee2f2019-01-18 12:35:12 -050013
vasilvvadd8ac32020-10-20 10:32:13 -070014#include "absl/memory/memory.h"
QUICHE team5be974e2020-12-29 18:35:24 -050015#include "http2/platform/api/http2_macros.h"
QUICHE team33a4aa62021-04-08 11:10:59 -070016#include "common/platform/api/quiche_bug_tracker.h"
QUICHE team1b5d09e2021-04-08 13:36:42 -070017#include "common/platform/api/quiche_logging.h"
QUICHE team5be974e2020-12-29 18:35:24 -050018#include "spdy/core/spdy_bitmasks.h"
19#include "spdy/core/spdy_frame_builder.h"
20#include "spdy/core/spdy_frame_reader.h"
QUICHE team5be974e2020-12-29 18:35:24 -050021#include "spdy/platform/api/spdy_estimate_memory_usage.h"
QUICHE team5be974e2020-12-29 18:35:24 -050022#include "spdy/platform/api/spdy_string_utils.h"
QUICHE team82dee2f2019-01-18 12:35:12 -050023
24namespace spdy {
25
26namespace {
27
28// Pack parent stream ID and exclusive flag into the format used by HTTP/2
29// headers and priority frames.
30uint32_t PackStreamDependencyValues(bool exclusive,
31 SpdyStreamId parent_stream_id) {
32 // Make sure the highest-order bit in the parent stream id is zeroed out.
33 uint32_t parent = parent_stream_id & 0x7fffffff;
34 // Set the one-bit exclusivity flag.
35 uint32_t e_bit = exclusive ? 0x80000000 : 0;
36 return parent | e_bit;
37}
38
39// Used to indicate no flags in a HTTP2 flags field.
40const uint8_t kNoFlags = 0;
41
42// Wire size of pad length field.
43const size_t kPadLengthFieldSize = 1;
44
45// The size of one parameter in SETTINGS frame.
46const size_t kOneSettingParameterSize = 6;
47
QUICHE team232cf492020-10-27 08:21:26 -070048size_t GetUncompressedSerializedLength(const Http2HeaderBlock& headers) {
QUICHE team82dee2f2019-01-18 12:35:12 -050049 const size_t num_name_value_pairs_size = sizeof(uint32_t);
50 const size_t length_of_name_size = num_name_value_pairs_size;
51 const size_t length_of_value_size = num_name_value_pairs_size;
52
53 size_t total_length = num_name_value_pairs_size;
54 for (const auto& header : headers) {
55 // We add space for the length of the name and the length of the value as
56 // well as the length of the name and the length of the value.
57 total_length += length_of_name_size + header.first.size() +
58 length_of_value_size + header.second.size();
59 }
60 return total_length;
61}
62
63// Serializes the flags octet for a given SpdyHeadersIR.
64uint8_t SerializeHeaderFrameFlags(const SpdyHeadersIR& header_ir,
65 const bool end_headers) {
66 uint8_t flags = 0;
67 if (header_ir.fin()) {
68 flags |= CONTROL_FLAG_FIN;
69 }
70 if (end_headers) {
71 flags |= HEADERS_FLAG_END_HEADERS;
72 }
73 if (header_ir.padded()) {
74 flags |= HEADERS_FLAG_PADDED;
75 }
76 if (header_ir.has_priority()) {
77 flags |= HEADERS_FLAG_PRIORITY;
78 }
79 return flags;
80}
81
82// Serializes the flags octet for a given SpdyPushPromiseIR.
83uint8_t SerializePushPromiseFrameFlags(const SpdyPushPromiseIR& push_promise_ir,
84 const bool end_headers) {
85 uint8_t flags = 0;
86 if (push_promise_ir.padded()) {
87 flags = flags | PUSH_PROMISE_FLAG_PADDED;
88 }
89 if (end_headers) {
90 flags |= PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
91 }
92 return flags;
93}
94
95// Serializes a HEADERS frame from the given SpdyHeadersIR and encoded header
96// block. Does not need or use the SpdyHeaderBlock inside SpdyHeadersIR.
97// Return false if the serialization fails. |encoding| should not be empty.
98bool SerializeHeadersGivenEncoding(const SpdyHeadersIR& headers,
bnc44712912019-08-15 18:58:14 -070099 const std::string& encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500100 const bool end_headers,
101 ZeroCopyOutputBuffer* output) {
102 const size_t frame_size =
103 GetHeaderFrameSizeSansBlock(headers) + encoding.size();
104 SpdyFrameBuilder builder(frame_size, output);
105 bool ret = builder.BeginNewFrame(
106 SpdyFrameType::HEADERS, SerializeHeaderFrameFlags(headers, end_headers),
107 headers.stream_id(), frame_size - kFrameHeaderSize);
vasilvved4f3082021-02-01 14:29:40 -0800108 QUICHE_DCHECK_EQ(kFrameHeaderSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500109
110 if (ret && headers.padded()) {
111 ret &= builder.WriteUInt8(headers.padding_payload_len());
112 }
113
114 if (ret && headers.has_priority()) {
115 int weight = ClampHttp2Weight(headers.weight());
116 ret &= builder.WriteUInt32(PackStreamDependencyValues(
117 headers.exclusive(), headers.parent_stream_id()));
118 // Per RFC 7540 section 6.3, serialized weight value is actual value - 1.
119 ret &= builder.WriteUInt8(weight - 1);
120 }
121
122 if (ret) {
123 ret &= builder.WriteBytes(encoding.data(), encoding.size());
124 }
125
126 if (ret && headers.padding_payload_len() > 0) {
bnc44712912019-08-15 18:58:14 -0700127 std::string padding(headers.padding_payload_len(), 0);
QUICHE team82dee2f2019-01-18 12:35:12 -0500128 ret &= builder.WriteBytes(padding.data(), padding.length());
129 }
130
131 if (!ret) {
QUICHE team1b5d09e2021-04-08 13:36:42 -0700132 QUICHE_DLOG(WARNING)
133 << "Failed to build HEADERS. Not enough space in output";
QUICHE team82dee2f2019-01-18 12:35:12 -0500134 }
135 return ret;
136}
137
138// Serializes a PUSH_PROMISE frame from the given SpdyPushPromiseIR and
139// encoded header block. Does not need or use the SpdyHeaderBlock inside
140// SpdyPushPromiseIR.
141bool SerializePushPromiseGivenEncoding(const SpdyPushPromiseIR& push_promise,
bnc44712912019-08-15 18:58:14 -0700142 const std::string& encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500143 const bool end_headers,
144 ZeroCopyOutputBuffer* output) {
145 const size_t frame_size =
146 GetPushPromiseFrameSizeSansBlock(push_promise) + encoding.size();
147 SpdyFrameBuilder builder(frame_size, output);
148 bool ok = builder.BeginNewFrame(
149 SpdyFrameType::PUSH_PROMISE,
150 SerializePushPromiseFrameFlags(push_promise, end_headers),
151 push_promise.stream_id(), frame_size - kFrameHeaderSize);
152
153 if (push_promise.padded()) {
154 ok = ok && builder.WriteUInt8(push_promise.padding_payload_len());
155 }
156 ok = ok && builder.WriteUInt32(push_promise.promised_stream_id()) &&
157 builder.WriteBytes(encoding.data(), encoding.size());
158 if (ok && push_promise.padding_payload_len() > 0) {
bnc44712912019-08-15 18:58:14 -0700159 std::string padding(push_promise.padding_payload_len(), 0);
QUICHE team82dee2f2019-01-18 12:35:12 -0500160 ok = builder.WriteBytes(padding.data(), padding.length());
161 }
162
QUICHE team1b5d09e2021-04-08 13:36:42 -0700163 QUICHE_DLOG_IF(ERROR, !ok)
QUICHE teamded03512019-03-07 14:45:11 -0800164 << "Failed to write PUSH_PROMISE encoding, not enough "
165 << "space in output";
QUICHE team82dee2f2019-01-18 12:35:12 -0500166 return ok;
167}
168
169bool WritePayloadWithContinuation(SpdyFrameBuilder* builder,
bnc44712912019-08-15 18:58:14 -0700170 const std::string& hpack_encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500171 SpdyStreamId stream_id,
172 SpdyFrameType type,
173 int padding_payload_len) {
174 uint8_t end_flag = 0;
175 uint8_t flags = 0;
176 if (type == SpdyFrameType::HEADERS) {
177 end_flag = HEADERS_FLAG_END_HEADERS;
178 } else if (type == SpdyFrameType::PUSH_PROMISE) {
179 end_flag = PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
180 } else {
QUICHE team1b5d09e2021-04-08 13:36:42 -0700181 QUICHE_DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type "
182 << FrameTypeToString(type);
QUICHE team82dee2f2019-01-18 12:35:12 -0500183 }
184
185 // Write all the padding payload and as much of the data payload as possible
186 // into the initial frame.
187 size_t bytes_remaining = 0;
188 bytes_remaining = hpack_encoding.size() -
189 std::min(hpack_encoding.size(),
190 kHttp2MaxControlFrameSendSize - builder->length() -
191 padding_payload_len);
192 bool ret = builder->WriteBytes(&hpack_encoding[0],
193 hpack_encoding.size() - bytes_remaining);
194 if (padding_payload_len > 0) {
bnc44712912019-08-15 18:58:14 -0700195 std::string padding = std::string(padding_payload_len, 0);
QUICHE team82dee2f2019-01-18 12:35:12 -0500196 ret &= builder->WriteBytes(padding.data(), padding.length());
197 }
198
199 // Tack on CONTINUATION frames for the overflow.
200 while (bytes_remaining > 0 && ret) {
201 size_t bytes_to_write =
202 std::min(bytes_remaining,
203 kHttp2MaxControlFrameSendSize - kContinuationFrameMinimumSize);
204 // Write CONTINUATION frame prefix.
205 if (bytes_remaining == bytes_to_write) {
206 flags |= end_flag;
207 }
208 ret &= builder->BeginNewFrame(SpdyFrameType::CONTINUATION, flags, stream_id,
209 bytes_to_write);
210 // Write payload fragment.
211 ret &= builder->WriteBytes(
212 &hpack_encoding[hpack_encoding.size() - bytes_remaining],
213 bytes_to_write);
214 bytes_remaining -= bytes_to_write;
215 }
216 return ret;
217}
218
219void SerializeDataBuilderHelper(const SpdyDataIR& data_ir,
220 uint8_t* flags,
221 int* num_padding_fields,
222 size_t* size_with_padding) {
223 if (data_ir.fin()) {
224 *flags = DATA_FLAG_FIN;
225 }
226
227 if (data_ir.padded()) {
228 *flags = *flags | DATA_FLAG_PADDED;
229 ++*num_padding_fields;
230 }
231
232 *size_with_padding = *num_padding_fields + data_ir.data_len() +
233 data_ir.padding_payload_len() + kDataFrameMinimumSize;
234}
235
236void SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper(
237 const SpdyDataIR& data_ir,
238 uint8_t* flags,
239 size_t* frame_size,
240 size_t* num_padding_fields) {
241 *flags = DATA_FLAG_NONE;
242 if (data_ir.fin()) {
243 *flags = DATA_FLAG_FIN;
244 }
245
246 *frame_size = kDataFrameMinimumSize;
247 if (data_ir.padded()) {
248 *flags = *flags | DATA_FLAG_PADDED;
249 ++(*num_padding_fields);
250 *frame_size = *frame_size + *num_padding_fields;
251 }
252}
253
254void SerializeSettingsBuilderHelper(const SpdySettingsIR& settings,
255 uint8_t* flags,
256 const SettingsMap* values,
257 size_t* size) {
258 if (settings.is_ack()) {
259 *flags = *flags | SETTINGS_FLAG_ACK;
260 }
261 *size =
262 kSettingsFrameMinimumSize + (values->size() * kOneSettingParameterSize);
263}
264
265void SerializeAltSvcBuilderHelper(const SpdyAltSvcIR& altsvc_ir,
bnc44712912019-08-15 18:58:14 -0700266 std::string* value,
QUICHE team82dee2f2019-01-18 12:35:12 -0500267 size_t* size) {
268 *size = kGetAltSvcFrameMinimumSize;
269 *size = *size + altsvc_ir.origin().length();
270 *value = SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
271 altsvc_ir.altsvc_vector());
272 *size = *size + value->length();
273}
274
275} // namespace
276
277SpdyFramer::SpdyFramer(CompressionOption option)
278 : debug_visitor_(nullptr), compression_option_(option) {
279 static_assert(kHttp2MaxControlFrameSendSize <= kHttp2DefaultFrameSizeLimit,
280 "Our send limit should be at most our receive limit.");
281}
282
283SpdyFramer::~SpdyFramer() = default;
284
285void SpdyFramer::set_debug_visitor(
286 SpdyFramerDebugVisitorInterface* debug_visitor) {
287 debug_visitor_ = debug_visitor;
288}
289
290SpdyFramer::SpdyFrameIterator::SpdyFrameIterator(SpdyFramer* framer)
291 : framer_(framer), is_first_frame_(true), has_next_frame_(true) {}
292
293SpdyFramer::SpdyFrameIterator::~SpdyFrameIterator() = default;
294
295size_t SpdyFramer::SpdyFrameIterator::NextFrame(ZeroCopyOutputBuffer* output) {
296 const SpdyFrameIR& frame_ir = GetIR();
297 if (!has_next_frame_) {
QUICHE team33a4aa62021-04-08 11:10:59 -0700298 QUICHE_BUG(spdy_bug_75_1)
QUICHE team16501202021-03-11 09:32:16 -0800299 << "SpdyFramer::SpdyFrameIterator::NextFrame called without "
300 << "a next frame.";
QUICHE team82dee2f2019-01-18 12:35:12 -0500301 return false;
302 }
303
304 const size_t size_without_block =
305 is_first_frame_ ? GetFrameSizeSansBlock() : kContinuationFrameMinimumSize;
bnc463f2352019-10-10 04:49:34 -0700306 auto encoding = std::make_unique<std::string>();
QUICHE team82dee2f2019-01-18 12:35:12 -0500307 encoder_->Next(kHttp2MaxControlFrameSendSize - size_without_block,
308 encoding.get());
309 has_next_frame_ = encoder_->HasNext();
310
311 if (framer_->debug_visitor_ != nullptr) {
312 const auto& header_block_frame_ir =
QUICHE team1605d8b2019-01-18 17:10:34 -0500313 static_cast<const SpdyFrameWithHeaderBlockIR&>(frame_ir);
QUICHE team82dee2f2019-01-18 12:35:12 -0500314 const size_t header_list_size =
315 GetUncompressedSerializedLength(header_block_frame_ir.header_block());
316 framer_->debug_visitor_->OnSendCompressedFrame(
317 frame_ir.stream_id(),
318 is_first_frame_ ? frame_ir.frame_type() : SpdyFrameType::CONTINUATION,
319 header_list_size, size_without_block + encoding->size());
320 }
321
322 const size_t free_bytes_before = output->BytesFree();
323 bool ok = false;
324 if (is_first_frame_) {
325 is_first_frame_ = false;
326 ok = SerializeGivenEncoding(*encoding, output);
327 } else {
328 SpdyContinuationIR continuation_ir(frame_ir.stream_id());
329 continuation_ir.take_encoding(std::move(encoding));
330 continuation_ir.set_end_headers(!has_next_frame_);
331 ok = framer_->SerializeContinuation(continuation_ir, output);
332 }
333 return ok ? free_bytes_before - output->BytesFree() : 0;
334}
335
336bool SpdyFramer::SpdyFrameIterator::HasNextFrame() const {
337 return has_next_frame_;
338}
339
340SpdyFramer::SpdyHeaderFrameIterator::SpdyHeaderFrameIterator(
341 SpdyFramer* framer,
342 std::unique_ptr<const SpdyHeadersIR> headers_ir)
343 : SpdyFrameIterator(framer), headers_ir_(std::move(headers_ir)) {
344 SetEncoder(headers_ir_.get());
345}
346
347SpdyFramer::SpdyHeaderFrameIterator::~SpdyHeaderFrameIterator() = default;
348
349const SpdyFrameIR& SpdyFramer::SpdyHeaderFrameIterator::GetIR() const {
350 return *(headers_ir_.get());
351}
352
353size_t SpdyFramer::SpdyHeaderFrameIterator::GetFrameSizeSansBlock() const {
354 return GetHeaderFrameSizeSansBlock(*headers_ir_);
355}
356
357bool SpdyFramer::SpdyHeaderFrameIterator::SerializeGivenEncoding(
bnc44712912019-08-15 18:58:14 -0700358 const std::string& encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500359 ZeroCopyOutputBuffer* output) const {
360 return SerializeHeadersGivenEncoding(*headers_ir_, encoding,
361 !has_next_frame(), output);
362}
363
364SpdyFramer::SpdyPushPromiseFrameIterator::SpdyPushPromiseFrameIterator(
365 SpdyFramer* framer,
366 std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir)
367 : SpdyFrameIterator(framer), push_promise_ir_(std::move(push_promise_ir)) {
368 SetEncoder(push_promise_ir_.get());
369}
370
371SpdyFramer::SpdyPushPromiseFrameIterator::~SpdyPushPromiseFrameIterator() =
372 default;
373
374const SpdyFrameIR& SpdyFramer::SpdyPushPromiseFrameIterator::GetIR() const {
375 return *(push_promise_ir_.get());
376}
377
378size_t SpdyFramer::SpdyPushPromiseFrameIterator::GetFrameSizeSansBlock() const {
379 return GetPushPromiseFrameSizeSansBlock(*push_promise_ir_);
380}
381
382bool SpdyFramer::SpdyPushPromiseFrameIterator::SerializeGivenEncoding(
bnc44712912019-08-15 18:58:14 -0700383 const std::string& encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500384 ZeroCopyOutputBuffer* output) const {
385 return SerializePushPromiseGivenEncoding(*push_promise_ir_, encoding,
386 !has_next_frame(), output);
387}
388
389SpdyFramer::SpdyControlFrameIterator::SpdyControlFrameIterator(
390 SpdyFramer* framer,
391 std::unique_ptr<const SpdyFrameIR> frame_ir)
392 : framer_(framer), frame_ir_(std::move(frame_ir)) {}
393
394SpdyFramer::SpdyControlFrameIterator::~SpdyControlFrameIterator() = default;
395
396size_t SpdyFramer::SpdyControlFrameIterator::NextFrame(
397 ZeroCopyOutputBuffer* output) {
398 size_t size_written = framer_->SerializeFrame(*frame_ir_, output);
399 has_next_frame_ = false;
400 return size_written;
401}
402
403bool SpdyFramer::SpdyControlFrameIterator::HasNextFrame() const {
404 return has_next_frame_;
405}
406
407const SpdyFrameIR& SpdyFramer::SpdyControlFrameIterator::GetIR() const {
408 return *(frame_ir_.get());
409}
410
QUICHE team82dee2f2019-01-18 12:35:12 -0500411std::unique_ptr<SpdyFrameSequence> SpdyFramer::CreateIterator(
412 SpdyFramer* framer,
413 std::unique_ptr<const SpdyFrameIR> frame_ir) {
414 switch (frame_ir->frame_type()) {
415 case SpdyFrameType::HEADERS: {
bnc463f2352019-10-10 04:49:34 -0700416 return std::make_unique<SpdyHeaderFrameIterator>(
vasilvvadd8ac32020-10-20 10:32:13 -0700417 framer, absl::WrapUnique(
bnc24194c82020-01-14 17:39:51 -0800418 static_cast<const SpdyHeadersIR*>(frame_ir.release())));
QUICHE team82dee2f2019-01-18 12:35:12 -0500419 }
420 case SpdyFrameType::PUSH_PROMISE: {
bnc463f2352019-10-10 04:49:34 -0700421 return std::make_unique<SpdyPushPromiseFrameIterator>(
QUICHE team5159c752021-03-31 10:51:05 -0700422 framer, absl::WrapUnique(static_cast<const SpdyPushPromiseIR*>(
423 frame_ir.release())));
QUICHE team82dee2f2019-01-18 12:35:12 -0500424 }
425 case SpdyFrameType::DATA: {
QUICHE team1b5d09e2021-04-08 13:36:42 -0700426 QUICHE_DVLOG(1) << "Serialize a stream end DATA frame for VTL";
QUICHE team82dee2f2019-01-18 12:35:12 -0500427 HTTP2_FALLTHROUGH;
428 }
429 default: {
bnc463f2352019-10-10 04:49:34 -0700430 return std::make_unique<SpdyControlFrameIterator>(framer,
431 std::move(frame_ir));
QUICHE team82dee2f2019-01-18 12:35:12 -0500432 }
433 }
434}
435
436SpdySerializedFrame SpdyFramer::SerializeData(const SpdyDataIR& data_ir) {
437 uint8_t flags = DATA_FLAG_NONE;
438 int num_padding_fields = 0;
439 size_t size_with_padding = 0;
440 SerializeDataBuilderHelper(data_ir, &flags, &num_padding_fields,
441 &size_with_padding);
442
443 SpdyFrameBuilder builder(size_with_padding);
444 builder.BeginNewFrame(SpdyFrameType::DATA, flags, data_ir.stream_id());
445 if (data_ir.padded()) {
446 builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
447 }
448 builder.WriteBytes(data_ir.data(), data_ir.data_len());
449 if (data_ir.padding_payload_len() > 0) {
bnc44712912019-08-15 18:58:14 -0700450 std::string padding(data_ir.padding_payload_len(), 0);
QUICHE team82dee2f2019-01-18 12:35:12 -0500451 builder.WriteBytes(padding.data(), padding.length());
452 }
vasilvved4f3082021-02-01 14:29:40 -0800453 QUICHE_DCHECK_EQ(size_with_padding, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500454 return builder.take();
455}
456
457SpdySerializedFrame SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField(
458 const SpdyDataIR& data_ir) {
459 uint8_t flags = DATA_FLAG_NONE;
460 size_t frame_size = 0;
461 size_t num_padding_fields = 0;
462 SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper(
463 data_ir, &flags, &frame_size, &num_padding_fields);
464
465 SpdyFrameBuilder builder(frame_size);
466 builder.BeginNewFrame(
467 SpdyFrameType::DATA, flags, data_ir.stream_id(),
468 num_padding_fields + data_ir.data_len() + data_ir.padding_payload_len());
469 if (data_ir.padded()) {
470 builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
471 }
vasilvved4f3082021-02-01 14:29:40 -0800472 QUICHE_DCHECK_EQ(frame_size, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500473 return builder.take();
474}
475
476SpdySerializedFrame SpdyFramer::SerializeRstStream(
477 const SpdyRstStreamIR& rst_stream) const {
478 size_t expected_length = kRstStreamFrameSize;
479 SpdyFrameBuilder builder(expected_length);
480
481 builder.BeginNewFrame(SpdyFrameType::RST_STREAM, 0, rst_stream.stream_id());
482
483 builder.WriteUInt32(rst_stream.error_code());
484
vasilvved4f3082021-02-01 14:29:40 -0800485 QUICHE_DCHECK_EQ(expected_length, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500486 return builder.take();
487}
488
489SpdySerializedFrame SpdyFramer::SerializeSettings(
490 const SpdySettingsIR& settings) const {
491 uint8_t flags = 0;
492 // Size, in bytes, of this SETTINGS frame.
493 size_t size = 0;
494 const SettingsMap* values = &(settings.values());
495 SerializeSettingsBuilderHelper(settings, &flags, values, &size);
496 SpdyFrameBuilder builder(size);
497 builder.BeginNewFrame(SpdyFrameType::SETTINGS, flags, 0);
498
499 // If this is an ACK, payload should be empty.
500 if (settings.is_ack()) {
501 return builder.take();
502 }
503
vasilvved4f3082021-02-01 14:29:40 -0800504 QUICHE_DCHECK_EQ(kSettingsFrameMinimumSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500505 for (auto it = values->begin(); it != values->end(); ++it) {
506 int setting_id = it->first;
vasilvved4f3082021-02-01 14:29:40 -0800507 QUICHE_DCHECK_GE(setting_id, 0);
QUICHE team82dee2f2019-01-18 12:35:12 -0500508 builder.WriteUInt16(static_cast<SpdySettingsId>(setting_id));
509 builder.WriteUInt32(it->second);
510 }
vasilvved4f3082021-02-01 14:29:40 -0800511 QUICHE_DCHECK_EQ(size, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500512 return builder.take();
513}
514
515SpdySerializedFrame SpdyFramer::SerializePing(const SpdyPingIR& ping) const {
516 SpdyFrameBuilder builder(kPingFrameSize);
517 uint8_t flags = 0;
518 if (ping.is_ack()) {
519 flags |= PING_FLAG_ACK;
520 }
521 builder.BeginNewFrame(SpdyFrameType::PING, flags, 0);
522 builder.WriteUInt64(ping.id());
vasilvved4f3082021-02-01 14:29:40 -0800523 QUICHE_DCHECK_EQ(kPingFrameSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500524 return builder.take();
525}
526
527SpdySerializedFrame SpdyFramer::SerializeGoAway(
528 const SpdyGoAwayIR& goaway) const {
529 // Compute the output buffer size, take opaque data into account.
530 size_t expected_length = kGoawayFrameMinimumSize;
531 expected_length += goaway.description().size();
532 SpdyFrameBuilder builder(expected_length);
533
534 // Serialize the GOAWAY frame.
535 builder.BeginNewFrame(SpdyFrameType::GOAWAY, 0, 0);
536
537 // GOAWAY frames specify the last good stream id.
538 builder.WriteUInt32(goaway.last_good_stream_id());
539
540 // GOAWAY frames also specify the error code.
541 builder.WriteUInt32(goaway.error_code());
542
543 // GOAWAY frames may also specify opaque data.
544 if (!goaway.description().empty()) {
545 builder.WriteBytes(goaway.description().data(),
546 goaway.description().size());
547 }
548
vasilvved4f3082021-02-01 14:29:40 -0800549 QUICHE_DCHECK_EQ(expected_length, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500550 return builder.take();
551}
552
553void SpdyFramer::SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers,
554 uint8_t* flags,
555 size_t* size,
bnc44712912019-08-15 18:58:14 -0700556 std::string* hpack_encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500557 int* weight,
558 size_t* length_field) {
559 if (headers.fin()) {
560 *flags = *flags | CONTROL_FLAG_FIN;
561 }
562 // This will get overwritten if we overflow into a CONTINUATION frame.
563 *flags = *flags | HEADERS_FLAG_END_HEADERS;
564 if (headers.has_priority()) {
565 *flags = *flags | HEADERS_FLAG_PRIORITY;
566 }
567 if (headers.padded()) {
568 *flags = *flags | HEADERS_FLAG_PADDED;
569 }
570
571 *size = kHeadersFrameMinimumSize;
572
573 if (headers.padded()) {
574 *size = *size + kPadLengthFieldSize;
575 *size = *size + headers.padding_payload_len();
576 }
577
578 if (headers.has_priority()) {
579 *weight = ClampHttp2Weight(headers.weight());
580 *size = *size + 5;
581 }
582
583 GetHpackEncoder()->EncodeHeaderSet(headers.header_block(), hpack_encoding);
584 *size = *size + hpack_encoding->size();
585 if (*size > kHttp2MaxControlFrameSendSize) {
586 *size = *size + GetNumberRequiredContinuationFrames(*size) *
587 kContinuationFrameMinimumSize;
588 *flags = *flags & ~HEADERS_FLAG_END_HEADERS;
589 }
590 // Compute frame length field.
591 if (headers.padded()) {
592 *length_field = *length_field + kPadLengthFieldSize;
593 }
594 if (headers.has_priority()) {
595 *length_field = *length_field + 4; // Dependency field.
596 *length_field = *length_field + 1; // Weight field.
597 }
598 *length_field = *length_field + headers.padding_payload_len();
599 *length_field = *length_field + hpack_encoding->size();
600 // If the HEADERS frame with payload would exceed the max frame size, then
601 // WritePayloadWithContinuation() will serialize CONTINUATION frames as
602 // necessary.
603 *length_field =
604 std::min(*length_field, kHttp2MaxControlFrameSendSize - kFrameHeaderSize);
605}
606
607SpdySerializedFrame SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers) {
608 uint8_t flags = 0;
609 // The size of this frame, including padding (if there is any) and
610 // variable-length header block.
611 size_t size = 0;
bnc44712912019-08-15 18:58:14 -0700612 std::string hpack_encoding;
QUICHE team82dee2f2019-01-18 12:35:12 -0500613 int weight = 0;
614 size_t length_field = 0;
615 SerializeHeadersBuilderHelper(headers, &flags, &size, &hpack_encoding,
616 &weight, &length_field);
617
618 SpdyFrameBuilder builder(size);
619 builder.BeginNewFrame(SpdyFrameType::HEADERS, flags, headers.stream_id(),
620 length_field);
621
vasilvved4f3082021-02-01 14:29:40 -0800622 QUICHE_DCHECK_EQ(kHeadersFrameMinimumSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500623
624 int padding_payload_len = 0;
625 if (headers.padded()) {
626 builder.WriteUInt8(headers.padding_payload_len());
627 padding_payload_len = headers.padding_payload_len();
628 }
629 if (headers.has_priority()) {
630 builder.WriteUInt32(PackStreamDependencyValues(headers.exclusive(),
631 headers.parent_stream_id()));
632 // Per RFC 7540 section 6.3, serialized weight value is actual value - 1.
633 builder.WriteUInt8(weight - 1);
634 }
635 WritePayloadWithContinuation(&builder, hpack_encoding, headers.stream_id(),
636 SpdyFrameType::HEADERS, padding_payload_len);
637
638 if (debug_visitor_) {
639 const size_t header_list_size =
640 GetUncompressedSerializedLength(headers.header_block());
641 debug_visitor_->OnSendCompressedFrame(headers.stream_id(),
642 SpdyFrameType::HEADERS,
643 header_list_size, builder.length());
644 }
645
646 return builder.take();
647}
648
649SpdySerializedFrame SpdyFramer::SerializeWindowUpdate(
650 const SpdyWindowUpdateIR& window_update) {
651 SpdyFrameBuilder builder(kWindowUpdateFrameSize);
652 builder.BeginNewFrame(SpdyFrameType::WINDOW_UPDATE, kNoFlags,
653 window_update.stream_id());
654 builder.WriteUInt32(window_update.delta());
vasilvved4f3082021-02-01 14:29:40 -0800655 QUICHE_DCHECK_EQ(kWindowUpdateFrameSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500656 return builder.take();
657}
658
659void SpdyFramer::SerializePushPromiseBuilderHelper(
660 const SpdyPushPromiseIR& push_promise,
661 uint8_t* flags,
bnc44712912019-08-15 18:58:14 -0700662 std::string* hpack_encoding,
QUICHE team82dee2f2019-01-18 12:35:12 -0500663 size_t* size) {
664 *flags = 0;
665 // This will get overwritten if we overflow into a CONTINUATION frame.
666 *flags = *flags | PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
667 // The size of this frame, including variable-length name-value block.
668 *size = kPushPromiseFrameMinimumSize;
669
670 if (push_promise.padded()) {
671 *flags = *flags | PUSH_PROMISE_FLAG_PADDED;
672 *size = *size + kPadLengthFieldSize;
673 *size = *size + push_promise.padding_payload_len();
674 }
675
676 GetHpackEncoder()->EncodeHeaderSet(push_promise.header_block(),
677 hpack_encoding);
678 *size = *size + hpack_encoding->size();
679 if (*size > kHttp2MaxControlFrameSendSize) {
680 *size = *size + GetNumberRequiredContinuationFrames(*size) *
681 kContinuationFrameMinimumSize;
682 *flags = *flags & ~PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
683 }
684}
685
686SpdySerializedFrame SpdyFramer::SerializePushPromise(
687 const SpdyPushPromiseIR& push_promise) {
688 uint8_t flags = 0;
689 size_t size = 0;
bnc44712912019-08-15 18:58:14 -0700690 std::string hpack_encoding;
QUICHE team82dee2f2019-01-18 12:35:12 -0500691 SerializePushPromiseBuilderHelper(push_promise, &flags, &hpack_encoding,
692 &size);
693
694 SpdyFrameBuilder builder(size);
695 size_t length =
696 std::min(size, kHttp2MaxControlFrameSendSize) - kFrameHeaderSize;
697 builder.BeginNewFrame(SpdyFrameType::PUSH_PROMISE, flags,
698 push_promise.stream_id(), length);
699 int padding_payload_len = 0;
700 if (push_promise.padded()) {
701 builder.WriteUInt8(push_promise.padding_payload_len());
702 builder.WriteUInt32(push_promise.promised_stream_id());
vasilvved4f3082021-02-01 14:29:40 -0800703 QUICHE_DCHECK_EQ(kPushPromiseFrameMinimumSize + kPadLengthFieldSize,
704 builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500705
706 padding_payload_len = push_promise.padding_payload_len();
707 } else {
708 builder.WriteUInt32(push_promise.promised_stream_id());
vasilvved4f3082021-02-01 14:29:40 -0800709 QUICHE_DCHECK_EQ(kPushPromiseFrameMinimumSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500710 }
711
712 WritePayloadWithContinuation(
713 &builder, hpack_encoding, push_promise.stream_id(),
714 SpdyFrameType::PUSH_PROMISE, padding_payload_len);
715
716 if (debug_visitor_) {
717 const size_t header_list_size =
718 GetUncompressedSerializedLength(push_promise.header_block());
719 debug_visitor_->OnSendCompressedFrame(push_promise.stream_id(),
720 SpdyFrameType::PUSH_PROMISE,
721 header_list_size, builder.length());
722 }
723
724 return builder.take();
725}
726
727SpdySerializedFrame SpdyFramer::SerializeContinuation(
728 const SpdyContinuationIR& continuation) const {
bnc44712912019-08-15 18:58:14 -0700729 const std::string& encoding = continuation.encoding();
QUICHE team82dee2f2019-01-18 12:35:12 -0500730 size_t frame_size = kContinuationFrameMinimumSize + encoding.size();
731 SpdyFrameBuilder builder(frame_size);
732 uint8_t flags = continuation.end_headers() ? HEADERS_FLAG_END_HEADERS : 0;
733 builder.BeginNewFrame(SpdyFrameType::CONTINUATION, flags,
734 continuation.stream_id());
vasilvved4f3082021-02-01 14:29:40 -0800735 QUICHE_DCHECK_EQ(kFrameHeaderSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500736
737 builder.WriteBytes(encoding.data(), encoding.size());
738 return builder.take();
739}
740
741SpdySerializedFrame SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir) {
bnc44712912019-08-15 18:58:14 -0700742 std::string value;
QUICHE team82dee2f2019-01-18 12:35:12 -0500743 size_t size = 0;
744 SerializeAltSvcBuilderHelper(altsvc_ir, &value, &size);
745 SpdyFrameBuilder builder(size);
746 builder.BeginNewFrame(SpdyFrameType::ALTSVC, kNoFlags, altsvc_ir.stream_id());
747
748 builder.WriteUInt16(altsvc_ir.origin().length());
749 builder.WriteBytes(altsvc_ir.origin().data(), altsvc_ir.origin().length());
750 builder.WriteBytes(value.data(), value.length());
vasilvved4f3082021-02-01 14:29:40 -0800751 QUICHE_DCHECK_LT(kGetAltSvcFrameMinimumSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500752 return builder.take();
753}
754
755SpdySerializedFrame SpdyFramer::SerializePriority(
756 const SpdyPriorityIR& priority) const {
757 SpdyFrameBuilder builder(kPriorityFrameSize);
758 builder.BeginNewFrame(SpdyFrameType::PRIORITY, kNoFlags,
759 priority.stream_id());
760
761 builder.WriteUInt32(PackStreamDependencyValues(priority.exclusive(),
762 priority.parent_stream_id()));
763 // Per RFC 7540 section 6.3, serialized weight value is actual value - 1.
764 builder.WriteUInt8(priority.weight() - 1);
vasilvved4f3082021-02-01 14:29:40 -0800765 QUICHE_DCHECK_EQ(kPriorityFrameSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -0500766 return builder.take();
767}
768
bnc19423c72020-12-15 07:51:45 -0800769SpdySerializedFrame SpdyFramer::SerializePriorityUpdate(
770 const SpdyPriorityUpdateIR& priority_update) const {
771 const size_t total_size = kPriorityUpdateFrameMinimumSize +
772 priority_update.priority_field_value().size();
773 SpdyFrameBuilder builder(total_size);
774 builder.BeginNewFrame(SpdyFrameType::PRIORITY_UPDATE, kNoFlags,
775 priority_update.stream_id());
776
777 builder.WriteUInt32(priority_update.prioritized_stream_id());
778 builder.WriteBytes(priority_update.priority_field_value().data(),
779 priority_update.priority_field_value().size());
vasilvved4f3082021-02-01 14:29:40 -0800780 QUICHE_DCHECK_EQ(total_size, builder.length());
bnc19423c72020-12-15 07:51:45 -0800781 return builder.take();
782}
783
bnc5c194f32021-02-05 08:15:05 -0800784SpdySerializedFrame SpdyFramer::SerializeAcceptCh(
785 const SpdyAcceptChIR& accept_ch) const {
786 const size_t total_size = accept_ch.size();
787 SpdyFrameBuilder builder(total_size);
788 builder.BeginNewFrame(SpdyFrameType::ACCEPT_CH, kNoFlags,
789 accept_ch.stream_id());
790
bnc8cfb52b2021-02-05 13:49:00 -0800791 for (const AcceptChOriginValuePair& entry : accept_ch.entries()) {
bnc5c194f32021-02-05 08:15:05 -0800792 builder.WriteUInt16(entry.origin.size());
793 builder.WriteBytes(entry.origin.data(), entry.origin.size());
794 builder.WriteUInt16(entry.value.size());
795 builder.WriteBytes(entry.value.data(), entry.value.size());
796 }
797
798 QUICHE_DCHECK_EQ(total_size, builder.length());
799 return builder.take();
800}
801
QUICHE team82dee2f2019-01-18 12:35:12 -0500802SpdySerializedFrame SpdyFramer::SerializeUnknown(
803 const SpdyUnknownIR& unknown) const {
804 const size_t total_size = kFrameHeaderSize + unknown.payload().size();
805 SpdyFrameBuilder builder(total_size);
806 builder.BeginNewUncheckedFrame(unknown.type(), unknown.flags(),
807 unknown.stream_id(), unknown.length());
808 builder.WriteBytes(unknown.payload().data(), unknown.payload().size());
809 return builder.take();
810}
811
812namespace {
813
814class FrameSerializationVisitor : public SpdyFrameVisitor {
815 public:
816 explicit FrameSerializationVisitor(SpdyFramer* framer)
817 : framer_(framer), frame_() {}
818 ~FrameSerializationVisitor() override = default;
819
820 SpdySerializedFrame ReleaseSerializedFrame() { return std::move(frame_); }
821
822 void VisitData(const SpdyDataIR& data) override {
823 frame_ = framer_->SerializeData(data);
824 }
825 void VisitRstStream(const SpdyRstStreamIR& rst_stream) override {
826 frame_ = framer_->SerializeRstStream(rst_stream);
827 }
828 void VisitSettings(const SpdySettingsIR& settings) override {
829 frame_ = framer_->SerializeSettings(settings);
830 }
831 void VisitPing(const SpdyPingIR& ping) override {
832 frame_ = framer_->SerializePing(ping);
833 }
834 void VisitGoAway(const SpdyGoAwayIR& goaway) override {
835 frame_ = framer_->SerializeGoAway(goaway);
836 }
837 void VisitHeaders(const SpdyHeadersIR& headers) override {
838 frame_ = framer_->SerializeHeaders(headers);
839 }
840 void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) override {
841 frame_ = framer_->SerializeWindowUpdate(window_update);
842 }
843 void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override {
844 frame_ = framer_->SerializePushPromise(push_promise);
845 }
846 void VisitContinuation(const SpdyContinuationIR& continuation) override {
847 frame_ = framer_->SerializeContinuation(continuation);
848 }
849 void VisitAltSvc(const SpdyAltSvcIR& altsvc) override {
850 frame_ = framer_->SerializeAltSvc(altsvc);
851 }
852 void VisitPriority(const SpdyPriorityIR& priority) override {
853 frame_ = framer_->SerializePriority(priority);
854 }
bnc19423c72020-12-15 07:51:45 -0800855 void VisitPriorityUpdate(
856 const SpdyPriorityUpdateIR& priority_update) override {
857 frame_ = framer_->SerializePriorityUpdate(priority_update);
858 }
bnc5c194f32021-02-05 08:15:05 -0800859 void VisitAcceptCh(const SpdyAcceptChIR& accept_ch) override {
860 frame_ = framer_->SerializeAcceptCh(accept_ch);
861 }
QUICHE team82dee2f2019-01-18 12:35:12 -0500862 void VisitUnknown(const SpdyUnknownIR& unknown) override {
863 frame_ = framer_->SerializeUnknown(unknown);
864 }
865
866 private:
867 SpdyFramer* framer_;
868 SpdySerializedFrame frame_;
869};
870
871// TODO(diannahu): Use also in frame serialization.
872class FlagsSerializationVisitor : public SpdyFrameVisitor {
873 public:
874 void VisitData(const SpdyDataIR& data) override {
875 flags_ = DATA_FLAG_NONE;
876 if (data.fin()) {
877 flags_ |= DATA_FLAG_FIN;
878 }
879 if (data.padded()) {
880 flags_ |= DATA_FLAG_PADDED;
881 }
882 }
883
danzh8f3a5762019-06-25 13:43:51 -0700884 void VisitRstStream(const SpdyRstStreamIR& /*rst_stream*/) override {
QUICHE team82dee2f2019-01-18 12:35:12 -0500885 flags_ = kNoFlags;
886 }
887
888 void VisitSettings(const SpdySettingsIR& settings) override {
889 flags_ = kNoFlags;
890 if (settings.is_ack()) {
891 flags_ |= SETTINGS_FLAG_ACK;
892 }
893 }
894
895 void VisitPing(const SpdyPingIR& ping) override {
896 flags_ = kNoFlags;
897 if (ping.is_ack()) {
898 flags_ |= PING_FLAG_ACK;
899 }
900 }
901
danzh8f3a5762019-06-25 13:43:51 -0700902 void VisitGoAway(const SpdyGoAwayIR& /*goaway*/) override {
903 flags_ = kNoFlags;
904 }
QUICHE team82dee2f2019-01-18 12:35:12 -0500905
906 // TODO(diannahu): The END_HEADERS flag is incorrect for HEADERS that require
907 // CONTINUATION frames.
908 void VisitHeaders(const SpdyHeadersIR& headers) override {
909 flags_ = HEADERS_FLAG_END_HEADERS;
910 if (headers.fin()) {
911 flags_ |= CONTROL_FLAG_FIN;
912 }
913 if (headers.padded()) {
914 flags_ |= HEADERS_FLAG_PADDED;
915 }
916 if (headers.has_priority()) {
917 flags_ |= HEADERS_FLAG_PRIORITY;
918 }
919 }
920
danzh8f3a5762019-06-25 13:43:51 -0700921 void VisitWindowUpdate(const SpdyWindowUpdateIR& /*window_update*/) override {
QUICHE team82dee2f2019-01-18 12:35:12 -0500922 flags_ = kNoFlags;
923 }
924
925 // TODO(diannahu): The END_PUSH_PROMISE flag is incorrect for PUSH_PROMISEs
926 // that require CONTINUATION frames.
927 void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override {
928 flags_ = PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
929 if (push_promise.padded()) {
930 flags_ |= PUSH_PROMISE_FLAG_PADDED;
931 }
932 }
933
934 // TODO(diannahu): The END_HEADERS flag is incorrect for CONTINUATIONs that
935 // require CONTINUATION frames.
danzh8f3a5762019-06-25 13:43:51 -0700936 void VisitContinuation(const SpdyContinuationIR& /*continuation*/) override {
QUICHE team82dee2f2019-01-18 12:35:12 -0500937 flags_ = HEADERS_FLAG_END_HEADERS;
938 }
939
danzh8f3a5762019-06-25 13:43:51 -0700940 void VisitAltSvc(const SpdyAltSvcIR& /*altsvc*/) override {
941 flags_ = kNoFlags;
942 }
QUICHE team82dee2f2019-01-18 12:35:12 -0500943
danzh8f3a5762019-06-25 13:43:51 -0700944 void VisitPriority(const SpdyPriorityIR& /*priority*/) override {
QUICHE team82dee2f2019-01-18 12:35:12 -0500945 flags_ = kNoFlags;
946 }
947
bnc19423c72020-12-15 07:51:45 -0800948 void VisitPriorityUpdate(
949 const SpdyPriorityUpdateIR& /*priority_update*/) override {
950 flags_ = kNoFlags;
951 }
952
bnc5c194f32021-02-05 08:15:05 -0800953 void VisitAcceptCh(const SpdyAcceptChIR& /*accept_ch*/) override {
954 flags_ = kNoFlags;
955 }
956
QUICHE team82dee2f2019-01-18 12:35:12 -0500957 uint8_t flags() const { return flags_; }
958
959 private:
960 uint8_t flags_ = kNoFlags;
961};
962
963} // namespace
964
965SpdySerializedFrame SpdyFramer::SerializeFrame(const SpdyFrameIR& frame) {
966 FrameSerializationVisitor visitor(this);
967 frame.Visit(&visitor);
968 return visitor.ReleaseSerializedFrame();
969}
970
971uint8_t SpdyFramer::GetSerializedFlags(const SpdyFrameIR& frame) {
972 FlagsSerializationVisitor visitor;
973 frame.Visit(&visitor);
974 return visitor.flags();
975}
976
977bool SpdyFramer::SerializeData(const SpdyDataIR& data_ir,
978 ZeroCopyOutputBuffer* output) const {
979 uint8_t flags = DATA_FLAG_NONE;
980 int num_padding_fields = 0;
981 size_t size_with_padding = 0;
982 SerializeDataBuilderHelper(data_ir, &flags, &num_padding_fields,
983 &size_with_padding);
984 SpdyFrameBuilder builder(size_with_padding, output);
985
986 bool ok =
987 builder.BeginNewFrame(SpdyFrameType::DATA, flags, data_ir.stream_id());
988
989 if (data_ir.padded()) {
990 ok = ok && builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
991 }
992
993 ok = ok && builder.WriteBytes(data_ir.data(), data_ir.data_len());
994 if (data_ir.padding_payload_len() > 0) {
bnc44712912019-08-15 18:58:14 -0700995 std::string padding;
996 padding = std::string(data_ir.padding_payload_len(), 0);
QUICHE team82dee2f2019-01-18 12:35:12 -0500997 ok = ok && builder.WriteBytes(padding.data(), padding.length());
998 }
vasilvved4f3082021-02-01 14:29:40 -0800999 QUICHE_DCHECK_EQ(size_with_padding, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001000 return ok;
1001}
1002
1003bool SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField(
1004 const SpdyDataIR& data_ir,
1005 ZeroCopyOutputBuffer* output) const {
1006 uint8_t flags = DATA_FLAG_NONE;
1007 size_t frame_size = 0;
1008 size_t num_padding_fields = 0;
1009 SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper(
1010 data_ir, &flags, &frame_size, &num_padding_fields);
1011
1012 SpdyFrameBuilder builder(frame_size, output);
1013 bool ok = true;
1014 ok = ok &&
1015 builder.BeginNewFrame(SpdyFrameType::DATA, flags, data_ir.stream_id(),
1016 num_padding_fields + data_ir.data_len() +
1017 data_ir.padding_payload_len());
1018 if (data_ir.padded()) {
1019 ok = ok && builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
1020 }
vasilvved4f3082021-02-01 14:29:40 -08001021 QUICHE_DCHECK_EQ(frame_size, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001022 return ok;
1023}
1024
1025bool SpdyFramer::SerializeRstStream(const SpdyRstStreamIR& rst_stream,
1026 ZeroCopyOutputBuffer* output) const {
1027 size_t expected_length = kRstStreamFrameSize;
1028 SpdyFrameBuilder builder(expected_length, output);
1029 bool ok = builder.BeginNewFrame(SpdyFrameType::RST_STREAM, 0,
1030 rst_stream.stream_id());
1031 ok = ok && builder.WriteUInt32(rst_stream.error_code());
1032
vasilvved4f3082021-02-01 14:29:40 -08001033 QUICHE_DCHECK_EQ(expected_length, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001034 return ok;
1035}
1036
1037bool SpdyFramer::SerializeSettings(const SpdySettingsIR& settings,
1038 ZeroCopyOutputBuffer* output) const {
1039 uint8_t flags = 0;
1040 // Size, in bytes, of this SETTINGS frame.
1041 size_t size = 0;
1042 const SettingsMap* values = &(settings.values());
1043 SerializeSettingsBuilderHelper(settings, &flags, values, &size);
1044 SpdyFrameBuilder builder(size, output);
1045 bool ok = builder.BeginNewFrame(SpdyFrameType::SETTINGS, flags, 0);
1046
1047 // If this is an ACK, payload should be empty.
1048 if (settings.is_ack()) {
1049 return ok;
1050 }
1051
vasilvved4f3082021-02-01 14:29:40 -08001052 QUICHE_DCHECK_EQ(kSettingsFrameMinimumSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001053 for (auto it = values->begin(); it != values->end(); ++it) {
1054 int setting_id = it->first;
vasilvved4f3082021-02-01 14:29:40 -08001055 QUICHE_DCHECK_GE(setting_id, 0);
QUICHE team82dee2f2019-01-18 12:35:12 -05001056 ok = ok && builder.WriteUInt16(static_cast<SpdySettingsId>(setting_id)) &&
1057 builder.WriteUInt32(it->second);
1058 }
vasilvved4f3082021-02-01 14:29:40 -08001059 QUICHE_DCHECK_EQ(size, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001060 return ok;
1061}
1062
1063bool SpdyFramer::SerializePing(const SpdyPingIR& ping,
1064 ZeroCopyOutputBuffer* output) const {
1065 SpdyFrameBuilder builder(kPingFrameSize, output);
1066 uint8_t flags = 0;
1067 if (ping.is_ack()) {
1068 flags |= PING_FLAG_ACK;
1069 }
1070 bool ok = builder.BeginNewFrame(SpdyFrameType::PING, flags, 0);
1071 ok = ok && builder.WriteUInt64(ping.id());
vasilvved4f3082021-02-01 14:29:40 -08001072 QUICHE_DCHECK_EQ(kPingFrameSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001073 return ok;
1074}
1075
1076bool SpdyFramer::SerializeGoAway(const SpdyGoAwayIR& goaway,
1077 ZeroCopyOutputBuffer* output) const {
1078 // Compute the output buffer size, take opaque data into account.
1079 size_t expected_length = kGoawayFrameMinimumSize;
1080 expected_length += goaway.description().size();
1081 SpdyFrameBuilder builder(expected_length, output);
1082
1083 // Serialize the GOAWAY frame.
1084 bool ok = builder.BeginNewFrame(SpdyFrameType::GOAWAY, 0, 0);
1085
1086 // GOAWAY frames specify the last good stream id.
1087 ok = ok && builder.WriteUInt32(goaway.last_good_stream_id()) &&
1088 // GOAWAY frames also specify the error status code.
1089 builder.WriteUInt32(goaway.error_code());
1090
1091 // GOAWAY frames may also specify opaque data.
1092 if (!goaway.description().empty()) {
1093 ok = ok && builder.WriteBytes(goaway.description().data(),
1094 goaway.description().size());
1095 }
1096
vasilvved4f3082021-02-01 14:29:40 -08001097 QUICHE_DCHECK_EQ(expected_length, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001098 return ok;
1099}
1100
1101bool SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers,
1102 ZeroCopyOutputBuffer* output) {
1103 uint8_t flags = 0;
1104 // The size of this frame, including padding (if there is any) and
1105 // variable-length header block.
1106 size_t size = 0;
bnc44712912019-08-15 18:58:14 -07001107 std::string hpack_encoding;
QUICHE team82dee2f2019-01-18 12:35:12 -05001108 int weight = 0;
1109 size_t length_field = 0;
1110 SerializeHeadersBuilderHelper(headers, &flags, &size, &hpack_encoding,
1111 &weight, &length_field);
1112
1113 bool ok = true;
1114 SpdyFrameBuilder builder(size, output);
1115 ok = ok && builder.BeginNewFrame(SpdyFrameType::HEADERS, flags,
1116 headers.stream_id(), length_field);
vasilvved4f3082021-02-01 14:29:40 -08001117 QUICHE_DCHECK_EQ(kHeadersFrameMinimumSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001118
1119 int padding_payload_len = 0;
1120 if (headers.padded()) {
1121 ok = ok && builder.WriteUInt8(headers.padding_payload_len());
1122 padding_payload_len = headers.padding_payload_len();
1123 }
1124 if (headers.has_priority()) {
1125 ok = ok &&
1126 builder.WriteUInt32(PackStreamDependencyValues(
1127 headers.exclusive(), headers.parent_stream_id())) &&
1128 // Per RFC 7540 section 6.3, serialized weight value is weight - 1.
1129 builder.WriteUInt8(weight - 1);
1130 }
1131 ok = ok && WritePayloadWithContinuation(
1132 &builder, hpack_encoding, headers.stream_id(),
1133 SpdyFrameType::HEADERS, padding_payload_len);
1134
1135 if (debug_visitor_) {
1136 const size_t header_list_size =
1137 GetUncompressedSerializedLength(headers.header_block());
1138 debug_visitor_->OnSendCompressedFrame(headers.stream_id(),
1139 SpdyFrameType::HEADERS,
1140 header_list_size, builder.length());
1141 }
1142
1143 return ok;
1144}
1145
1146bool SpdyFramer::SerializeWindowUpdate(const SpdyWindowUpdateIR& window_update,
1147 ZeroCopyOutputBuffer* output) const {
1148 SpdyFrameBuilder builder(kWindowUpdateFrameSize, output);
1149 bool ok = builder.BeginNewFrame(SpdyFrameType::WINDOW_UPDATE, kNoFlags,
1150 window_update.stream_id());
1151 ok = ok && builder.WriteUInt32(window_update.delta());
vasilvved4f3082021-02-01 14:29:40 -08001152 QUICHE_DCHECK_EQ(kWindowUpdateFrameSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001153 return ok;
1154}
1155
1156bool SpdyFramer::SerializePushPromise(const SpdyPushPromiseIR& push_promise,
1157 ZeroCopyOutputBuffer* output) {
1158 uint8_t flags = 0;
1159 size_t size = 0;
bnc44712912019-08-15 18:58:14 -07001160 std::string hpack_encoding;
QUICHE team82dee2f2019-01-18 12:35:12 -05001161 SerializePushPromiseBuilderHelper(push_promise, &flags, &hpack_encoding,
1162 &size);
1163
1164 bool ok = true;
1165 SpdyFrameBuilder builder(size, output);
1166 size_t length =
1167 std::min(size, kHttp2MaxControlFrameSendSize) - kFrameHeaderSize;
1168 ok = builder.BeginNewFrame(SpdyFrameType::PUSH_PROMISE, flags,
1169 push_promise.stream_id(), length);
1170
1171 int padding_payload_len = 0;
1172 if (push_promise.padded()) {
1173 ok = ok && builder.WriteUInt8(push_promise.padding_payload_len()) &&
1174 builder.WriteUInt32(push_promise.promised_stream_id());
vasilvved4f3082021-02-01 14:29:40 -08001175 QUICHE_DCHECK_EQ(kPushPromiseFrameMinimumSize + kPadLengthFieldSize,
1176 builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001177
1178 padding_payload_len = push_promise.padding_payload_len();
1179 } else {
1180 ok = ok && builder.WriteUInt32(push_promise.promised_stream_id());
vasilvved4f3082021-02-01 14:29:40 -08001181 QUICHE_DCHECK_EQ(kPushPromiseFrameMinimumSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001182 }
1183
1184 ok = ok && WritePayloadWithContinuation(
1185 &builder, hpack_encoding, push_promise.stream_id(),
1186 SpdyFrameType::PUSH_PROMISE, padding_payload_len);
1187
1188 if (debug_visitor_) {
1189 const size_t header_list_size =
1190 GetUncompressedSerializedLength(push_promise.header_block());
1191 debug_visitor_->OnSendCompressedFrame(push_promise.stream_id(),
1192 SpdyFrameType::PUSH_PROMISE,
1193 header_list_size, builder.length());
1194 }
1195
1196 return ok;
1197}
1198
1199bool SpdyFramer::SerializeContinuation(const SpdyContinuationIR& continuation,
1200 ZeroCopyOutputBuffer* output) const {
bnc44712912019-08-15 18:58:14 -07001201 const std::string& encoding = continuation.encoding();
QUICHE team82dee2f2019-01-18 12:35:12 -05001202 size_t frame_size = kContinuationFrameMinimumSize + encoding.size();
1203 SpdyFrameBuilder builder(frame_size, output);
1204 uint8_t flags = continuation.end_headers() ? HEADERS_FLAG_END_HEADERS : 0;
1205 bool ok = builder.BeginNewFrame(SpdyFrameType::CONTINUATION, flags,
1206 continuation.stream_id(),
1207 frame_size - kFrameHeaderSize);
vasilvved4f3082021-02-01 14:29:40 -08001208 QUICHE_DCHECK_EQ(kFrameHeaderSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001209
1210 ok = ok && builder.WriteBytes(encoding.data(), encoding.size());
1211 return ok;
1212}
1213
1214bool SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir,
1215 ZeroCopyOutputBuffer* output) {
bnc44712912019-08-15 18:58:14 -07001216 std::string value;
QUICHE team82dee2f2019-01-18 12:35:12 -05001217 size_t size = 0;
1218 SerializeAltSvcBuilderHelper(altsvc_ir, &value, &size);
1219 SpdyFrameBuilder builder(size, output);
1220 bool ok = builder.BeginNewFrame(SpdyFrameType::ALTSVC, kNoFlags,
1221 altsvc_ir.stream_id()) &&
1222 builder.WriteUInt16(altsvc_ir.origin().length()) &&
1223 builder.WriteBytes(altsvc_ir.origin().data(),
1224 altsvc_ir.origin().length()) &&
1225 builder.WriteBytes(value.data(), value.length());
vasilvved4f3082021-02-01 14:29:40 -08001226 QUICHE_DCHECK_LT(kGetAltSvcFrameMinimumSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001227 return ok;
1228}
1229
1230bool SpdyFramer::SerializePriority(const SpdyPriorityIR& priority,
1231 ZeroCopyOutputBuffer* output) const {
1232 SpdyFrameBuilder builder(kPriorityFrameSize, output);
1233 bool ok = builder.BeginNewFrame(SpdyFrameType::PRIORITY, kNoFlags,
1234 priority.stream_id());
1235 ok = ok &&
1236 builder.WriteUInt32(PackStreamDependencyValues(
1237 priority.exclusive(), priority.parent_stream_id())) &&
1238 // Per RFC 7540 section 6.3, serialized weight value is actual value - 1.
1239 builder.WriteUInt8(priority.weight() - 1);
vasilvved4f3082021-02-01 14:29:40 -08001240 QUICHE_DCHECK_EQ(kPriorityFrameSize, builder.length());
QUICHE team82dee2f2019-01-18 12:35:12 -05001241 return ok;
1242}
1243
bnc19423c72020-12-15 07:51:45 -08001244bool SpdyFramer::SerializePriorityUpdate(
1245 const SpdyPriorityUpdateIR& priority_update,
1246 ZeroCopyOutputBuffer* output) const {
1247 const size_t total_size = kPriorityUpdateFrameMinimumSize +
1248 priority_update.priority_field_value().size();
1249 SpdyFrameBuilder builder(total_size, output);
1250 bool ok = builder.BeginNewFrame(SpdyFrameType::PRIORITY_UPDATE, kNoFlags,
1251 priority_update.stream_id());
1252
1253 ok = ok && builder.WriteUInt32(priority_update.prioritized_stream_id());
1254 ok = ok && builder.WriteBytes(priority_update.priority_field_value().data(),
1255 priority_update.priority_field_value().size());
vasilvved4f3082021-02-01 14:29:40 -08001256 QUICHE_DCHECK_EQ(total_size, builder.length());
bnc19423c72020-12-15 07:51:45 -08001257 return ok;
1258}
1259
bnc5c194f32021-02-05 08:15:05 -08001260bool SpdyFramer::SerializeAcceptCh(const SpdyAcceptChIR& accept_ch,
1261 ZeroCopyOutputBuffer* output) const {
1262 const size_t total_size = accept_ch.size();
1263 SpdyFrameBuilder builder(total_size, output);
1264 bool ok = builder.BeginNewFrame(SpdyFrameType::ACCEPT_CH, kNoFlags,
1265 accept_ch.stream_id());
1266
bnc8cfb52b2021-02-05 13:49:00 -08001267 for (const AcceptChOriginValuePair& entry : accept_ch.entries()) {
bnc5c194f32021-02-05 08:15:05 -08001268 ok = ok && builder.WriteUInt16(entry.origin.size());
1269 ok = ok && builder.WriteBytes(entry.origin.data(), entry.origin.size());
1270 ok = ok && builder.WriteUInt16(entry.value.size());
1271 ok = ok && builder.WriteBytes(entry.value.data(), entry.value.size());
1272 }
1273
1274 QUICHE_DCHECK_EQ(total_size, builder.length());
1275 return ok;
1276}
1277
QUICHE team82dee2f2019-01-18 12:35:12 -05001278bool SpdyFramer::SerializeUnknown(const SpdyUnknownIR& unknown,
1279 ZeroCopyOutputBuffer* output) const {
1280 const size_t total_size = kFrameHeaderSize + unknown.payload().size();
1281 SpdyFrameBuilder builder(total_size, output);
1282 bool ok = builder.BeginNewUncheckedFrame(
1283 unknown.type(), unknown.flags(), unknown.stream_id(), unknown.length());
1284 ok = ok &&
1285 builder.WriteBytes(unknown.payload().data(), unknown.payload().size());
1286 return ok;
1287}
1288
1289namespace {
1290
1291class FrameSerializationVisitorWithOutput : public SpdyFrameVisitor {
1292 public:
1293 explicit FrameSerializationVisitorWithOutput(SpdyFramer* framer,
1294 ZeroCopyOutputBuffer* output)
1295 : framer_(framer), output_(output), result_(false) {}
1296 ~FrameSerializationVisitorWithOutput() override = default;
1297
1298 size_t Result() { return result_; }
1299
1300 void VisitData(const SpdyDataIR& data) override {
1301 result_ = framer_->SerializeData(data, output_);
1302 }
1303 void VisitRstStream(const SpdyRstStreamIR& rst_stream) override {
1304 result_ = framer_->SerializeRstStream(rst_stream, output_);
1305 }
1306 void VisitSettings(const SpdySettingsIR& settings) override {
1307 result_ = framer_->SerializeSettings(settings, output_);
1308 }
1309 void VisitPing(const SpdyPingIR& ping) override {
1310 result_ = framer_->SerializePing(ping, output_);
1311 }
1312 void VisitGoAway(const SpdyGoAwayIR& goaway) override {
1313 result_ = framer_->SerializeGoAway(goaway, output_);
1314 }
1315 void VisitHeaders(const SpdyHeadersIR& headers) override {
1316 result_ = framer_->SerializeHeaders(headers, output_);
1317 }
1318 void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) override {
1319 result_ = framer_->SerializeWindowUpdate(window_update, output_);
1320 }
1321 void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override {
1322 result_ = framer_->SerializePushPromise(push_promise, output_);
1323 }
1324 void VisitContinuation(const SpdyContinuationIR& continuation) override {
1325 result_ = framer_->SerializeContinuation(continuation, output_);
1326 }
1327 void VisitAltSvc(const SpdyAltSvcIR& altsvc) override {
1328 result_ = framer_->SerializeAltSvc(altsvc, output_);
1329 }
1330 void VisitPriority(const SpdyPriorityIR& priority) override {
1331 result_ = framer_->SerializePriority(priority, output_);
1332 }
bnc19423c72020-12-15 07:51:45 -08001333 void VisitPriorityUpdate(
1334 const SpdyPriorityUpdateIR& priority_update) override {
1335 result_ = framer_->SerializePriorityUpdate(priority_update, output_);
1336 }
bnc5c194f32021-02-05 08:15:05 -08001337 void VisitAcceptCh(const SpdyAcceptChIR& accept_ch) override {
1338 result_ = framer_->SerializeAcceptCh(accept_ch, output_);
1339 }
1340
QUICHE team82dee2f2019-01-18 12:35:12 -05001341 void VisitUnknown(const SpdyUnknownIR& unknown) override {
1342 result_ = framer_->SerializeUnknown(unknown, output_);
1343 }
1344
1345 private:
1346 SpdyFramer* framer_;
1347 ZeroCopyOutputBuffer* output_;
1348 bool result_;
1349};
1350
1351} // namespace
1352
1353size_t SpdyFramer::SerializeFrame(const SpdyFrameIR& frame,
1354 ZeroCopyOutputBuffer* output) {
1355 FrameSerializationVisitorWithOutput visitor(this, output);
1356 size_t free_bytes_before = output->BytesFree();
1357 frame.Visit(&visitor);
1358 return visitor.Result() ? free_bytes_before - output->BytesFree() : 0;
1359}
1360
1361HpackEncoder* SpdyFramer::GetHpackEncoder() {
1362 if (hpack_encoder_ == nullptr) {
bnce3fd6862020-10-02 12:46:15 -07001363 hpack_encoder_ = std::make_unique<HpackEncoder>();
QUICHE team82dee2f2019-01-18 12:35:12 -05001364 if (!compression_enabled()) {
1365 hpack_encoder_->DisableCompression();
1366 }
1367 }
1368 return hpack_encoder_.get();
1369}
1370
1371void SpdyFramer::UpdateHeaderEncoderTableSize(uint32_t value) {
1372 GetHpackEncoder()->ApplyHeaderTableSizeSetting(value);
1373}
1374
1375size_t SpdyFramer::header_encoder_table_size() const {
1376 if (hpack_encoder_ == nullptr) {
1377 return kDefaultHeaderTableSizeSetting;
1378 } else {
1379 return hpack_encoder_->CurrentHeaderTableSizeSetting();
1380 }
1381}
1382
QUICHE team82dee2f2019-01-18 12:35:12 -05001383size_t SpdyFramer::EstimateMemoryUsage() const {
1384 return SpdyEstimateMemoryUsage(hpack_encoder_);
1385}
1386
1387} // namespace spdy