1 // 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 #include "quiche/spdy/core/spdy_framer.h"
6
7 #include <algorithm>
8 #include <cstdint>
9 #include <iterator>
10 #include <list>
11 #include <new>
12 #include <utility>
13
14 #include "absl/base/macros.h"
15 #include "absl/memory/memory.h"
16 #include "quiche/common/platform/api/quiche_bug_tracker.h"
17 #include "quiche/common/platform/api/quiche_logging.h"
18 #include "quiche/spdy/core/spdy_bitmasks.h"
19 #include "quiche/spdy/core/spdy_frame_builder.h"
20
21 namespace spdy {
22
23 namespace {
24
25 // Pack parent stream ID and exclusive flag into the format used by HTTP/2
26 // headers and priority frames.
PackStreamDependencyValues(bool exclusive,SpdyStreamId parent_stream_id)27 uint32_t PackStreamDependencyValues(bool exclusive,
28 SpdyStreamId parent_stream_id) {
29 // Make sure the highest-order bit in the parent stream id is zeroed out.
30 uint32_t parent = parent_stream_id & 0x7fffffff;
31 // Set the one-bit exclusivity flag.
32 uint32_t e_bit = exclusive ? 0x80000000 : 0;
33 return parent | e_bit;
34 }
35
36 // Used to indicate no flags in a HTTP2 flags field.
37 const uint8_t kNoFlags = 0;
38
39 // Wire size of pad length field.
40 const size_t kPadLengthFieldSize = 1;
41
42 // The size of one parameter in SETTINGS frame.
43 const size_t kOneSettingParameterSize = 6;
44
GetUncompressedSerializedLength(const Http2HeaderBlock & headers)45 size_t GetUncompressedSerializedLength(const Http2HeaderBlock& headers) {
46 const size_t num_name_value_pairs_size = sizeof(uint32_t);
47 const size_t length_of_name_size = num_name_value_pairs_size;
48 const size_t length_of_value_size = num_name_value_pairs_size;
49
50 size_t total_length = num_name_value_pairs_size;
51 for (const auto& header : headers) {
52 // We add space for the length of the name and the length of the value as
53 // well as the length of the name and the length of the value.
54 total_length += length_of_name_size + header.first.size() +
55 length_of_value_size + header.second.size();
56 }
57 return total_length;
58 }
59
60 // Serializes the flags octet for a given SpdyHeadersIR.
SerializeHeaderFrameFlags(const SpdyHeadersIR & header_ir,const bool end_headers)61 uint8_t SerializeHeaderFrameFlags(const SpdyHeadersIR& header_ir,
62 const bool end_headers) {
63 uint8_t flags = 0;
64 if (header_ir.fin()) {
65 flags |= CONTROL_FLAG_FIN;
66 }
67 if (end_headers) {
68 flags |= HEADERS_FLAG_END_HEADERS;
69 }
70 if (header_ir.padded()) {
71 flags |= HEADERS_FLAG_PADDED;
72 }
73 if (header_ir.has_priority()) {
74 flags |= HEADERS_FLAG_PRIORITY;
75 }
76 return flags;
77 }
78
79 // Serializes the flags octet for a given SpdyPushPromiseIR.
SerializePushPromiseFrameFlags(const SpdyPushPromiseIR & push_promise_ir,const bool end_headers)80 uint8_t SerializePushPromiseFrameFlags(const SpdyPushPromiseIR& push_promise_ir,
81 const bool end_headers) {
82 uint8_t flags = 0;
83 if (push_promise_ir.padded()) {
84 flags = flags | PUSH_PROMISE_FLAG_PADDED;
85 }
86 if (end_headers) {
87 flags |= PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
88 }
89 return flags;
90 }
91
92 // Serializes a HEADERS frame from the given SpdyHeadersIR and encoded header
93 // block. Does not need or use the Http2HeaderBlock inside SpdyHeadersIR.
94 // Return false if the serialization fails. |encoding| should not be empty.
SerializeHeadersGivenEncoding(const SpdyHeadersIR & headers,const std::string & encoding,const bool end_headers,ZeroCopyOutputBuffer * output)95 bool SerializeHeadersGivenEncoding(const SpdyHeadersIR& headers,
96 const std::string& encoding,
97 const bool end_headers,
98 ZeroCopyOutputBuffer* output) {
99 const size_t frame_size =
100 GetHeaderFrameSizeSansBlock(headers) + encoding.size();
101 SpdyFrameBuilder builder(frame_size, output);
102 bool ret = builder.BeginNewFrame(
103 SpdyFrameType::HEADERS, SerializeHeaderFrameFlags(headers, end_headers),
104 headers.stream_id(), frame_size - kFrameHeaderSize);
105 QUICHE_DCHECK_EQ(kFrameHeaderSize, builder.length());
106
107 if (ret && headers.padded()) {
108 ret &= builder.WriteUInt8(headers.padding_payload_len());
109 }
110
111 if (ret && headers.has_priority()) {
112 int weight = ClampHttp2Weight(headers.weight());
113 ret &= builder.WriteUInt32(PackStreamDependencyValues(
114 headers.exclusive(), headers.parent_stream_id()));
115 // Per RFC 7540 section 6.3, serialized weight value is actual value - 1.
116 ret &= builder.WriteUInt8(weight - 1);
117 }
118
119 if (ret) {
120 ret &= builder.WriteBytes(encoding.data(), encoding.size());
121 }
122
123 if (ret && headers.padding_payload_len() > 0) {
124 std::string padding(headers.padding_payload_len(), 0);
125 ret &= builder.WriteBytes(padding.data(), padding.length());
126 }
127
128 if (!ret) {
129 QUICHE_DLOG(WARNING)
130 << "Failed to build HEADERS. Not enough space in output";
131 }
132 return ret;
133 }
134
135 // Serializes a PUSH_PROMISE frame from the given SpdyPushPromiseIR and
136 // encoded header block. Does not need or use the Http2HeaderBlock inside
137 // SpdyPushPromiseIR.
SerializePushPromiseGivenEncoding(const SpdyPushPromiseIR & push_promise,const std::string & encoding,const bool end_headers,ZeroCopyOutputBuffer * output)138 bool SerializePushPromiseGivenEncoding(const SpdyPushPromiseIR& push_promise,
139 const std::string& encoding,
140 const bool end_headers,
141 ZeroCopyOutputBuffer* output) {
142 const size_t frame_size =
143 GetPushPromiseFrameSizeSansBlock(push_promise) + encoding.size();
144 SpdyFrameBuilder builder(frame_size, output);
145 bool ok = builder.BeginNewFrame(
146 SpdyFrameType::PUSH_PROMISE,
147 SerializePushPromiseFrameFlags(push_promise, end_headers),
148 push_promise.stream_id(), frame_size - kFrameHeaderSize);
149
150 if (push_promise.padded()) {
151 ok = ok && builder.WriteUInt8(push_promise.padding_payload_len());
152 }
153 ok = ok && builder.WriteUInt32(push_promise.promised_stream_id()) &&
154 builder.WriteBytes(encoding.data(), encoding.size());
155 if (ok && push_promise.padding_payload_len() > 0) {
156 std::string padding(push_promise.padding_payload_len(), 0);
157 ok = builder.WriteBytes(padding.data(), padding.length());
158 }
159
160 QUICHE_DLOG_IF(ERROR, !ok)
161 << "Failed to write PUSH_PROMISE encoding, not enough "
162 << "space in output";
163 return ok;
164 }
165
WritePayloadWithContinuation(SpdyFrameBuilder * builder,const std::string & hpack_encoding,SpdyStreamId stream_id,SpdyFrameType type,int padding_payload_len)166 bool WritePayloadWithContinuation(SpdyFrameBuilder* builder,
167 const std::string& hpack_encoding,
168 SpdyStreamId stream_id, SpdyFrameType type,
169 int padding_payload_len) {
170 uint8_t end_flag = 0;
171 uint8_t flags = 0;
172 if (type == SpdyFrameType::HEADERS) {
173 end_flag = HEADERS_FLAG_END_HEADERS;
174 } else if (type == SpdyFrameType::PUSH_PROMISE) {
175 end_flag = PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
176 } else {
177 QUICHE_DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type "
178 << FrameTypeToString(type);
179 }
180
181 // Write all the padding payload and as much of the data payload as possible
182 // into the initial frame.
183 size_t bytes_remaining = 0;
184 bytes_remaining = hpack_encoding.size() -
185 std::min(hpack_encoding.size(),
186 kHttp2MaxControlFrameSendSize - builder->length() -
187 padding_payload_len);
188 bool ret = builder->WriteBytes(&hpack_encoding[0],
189 hpack_encoding.size() - bytes_remaining);
190 if (padding_payload_len > 0) {
191 std::string padding = std::string(padding_payload_len, 0);
192 ret &= builder->WriteBytes(padding.data(), padding.length());
193 }
194
195 // Tack on CONTINUATION frames for the overflow.
196 while (bytes_remaining > 0 && ret) {
197 size_t bytes_to_write =
198 std::min(bytes_remaining,
199 kHttp2MaxControlFrameSendSize - kContinuationFrameMinimumSize);
200 // Write CONTINUATION frame prefix.
201 if (bytes_remaining == bytes_to_write) {
202 flags |= end_flag;
203 }
204 ret &= builder->BeginNewFrame(SpdyFrameType::CONTINUATION, flags, stream_id,
205 bytes_to_write);
206 // Write payload fragment.
207 ret &= builder->WriteBytes(
208 &hpack_encoding[hpack_encoding.size() - bytes_remaining],
209 bytes_to_write);
210 bytes_remaining -= bytes_to_write;
211 }
212 return ret;
213 }
214
SerializeDataBuilderHelper(const SpdyDataIR & data_ir,uint8_t * flags,int * num_padding_fields,size_t * size_with_padding)215 void SerializeDataBuilderHelper(const SpdyDataIR& data_ir, uint8_t* flags,
216 int* num_padding_fields,
217 size_t* size_with_padding) {
218 if (data_ir.fin()) {
219 *flags = DATA_FLAG_FIN;
220 }
221
222 if (data_ir.padded()) {
223 *flags = *flags | DATA_FLAG_PADDED;
224 ++*num_padding_fields;
225 }
226
227 *size_with_padding = *num_padding_fields + data_ir.data_len() +
228 data_ir.padding_payload_len() + kDataFrameMinimumSize;
229 }
230
SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper(const SpdyDataIR & data_ir,uint8_t * flags,size_t * frame_size,size_t * num_padding_fields)231 void SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper(
232 const SpdyDataIR& data_ir, uint8_t* flags, size_t* frame_size,
233 size_t* num_padding_fields) {
234 *flags = DATA_FLAG_NONE;
235 if (data_ir.fin()) {
236 *flags = DATA_FLAG_FIN;
237 }
238
239 *frame_size = kDataFrameMinimumSize;
240 if (data_ir.padded()) {
241 *flags = *flags | DATA_FLAG_PADDED;
242 ++(*num_padding_fields);
243 *frame_size = *frame_size + *num_padding_fields;
244 }
245 }
246
SerializeSettingsBuilderHelper(const SpdySettingsIR & settings,uint8_t * flags,const SettingsMap * values,size_t * size)247 void SerializeSettingsBuilderHelper(const SpdySettingsIR& settings,
248 uint8_t* flags, const SettingsMap* values,
249 size_t* size) {
250 if (settings.is_ack()) {
251 *flags = *flags | SETTINGS_FLAG_ACK;
252 }
253 *size =
254 kSettingsFrameMinimumSize + (values->size() * kOneSettingParameterSize);
255 }
256
SerializeAltSvcBuilderHelper(const SpdyAltSvcIR & altsvc_ir,std::string * value,size_t * size)257 void SerializeAltSvcBuilderHelper(const SpdyAltSvcIR& altsvc_ir,
258 std::string* value, size_t* size) {
259 *size = kGetAltSvcFrameMinimumSize;
260 *size = *size + altsvc_ir.origin().length();
261 *value = SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
262 altsvc_ir.altsvc_vector());
263 *size = *size + value->length();
264 }
265
266 } // namespace
267
SpdyFramer(CompressionOption option)268 SpdyFramer::SpdyFramer(CompressionOption option)
269 : debug_visitor_(nullptr), compression_option_(option) {
270 static_assert(kHttp2MaxControlFrameSendSize <= kHttp2DefaultFrameSizeLimit,
271 "Our send limit should be at most our receive limit.");
272 }
273
274 SpdyFramer::~SpdyFramer() = default;
275
set_debug_visitor(SpdyFramerDebugVisitorInterface * debug_visitor)276 void SpdyFramer::set_debug_visitor(
277 SpdyFramerDebugVisitorInterface* debug_visitor) {
278 debug_visitor_ = debug_visitor;
279 }
280
SpdyFrameIterator(SpdyFramer * framer)281 SpdyFramer::SpdyFrameIterator::SpdyFrameIterator(SpdyFramer* framer)
282 : framer_(framer), is_first_frame_(true), has_next_frame_(true) {}
283
284 SpdyFramer::SpdyFrameIterator::~SpdyFrameIterator() = default;
285
NextFrame(ZeroCopyOutputBuffer * output)286 size_t SpdyFramer::SpdyFrameIterator::NextFrame(ZeroCopyOutputBuffer* output) {
287 const SpdyFrameIR& frame_ir = GetIR();
288 if (!has_next_frame_) {
289 QUICHE_BUG(spdy_bug_75_1)
290 << "SpdyFramer::SpdyFrameIterator::NextFrame called without "
291 << "a next frame.";
292 return false;
293 }
294
295 const size_t size_without_block =
296 is_first_frame_ ? GetFrameSizeSansBlock() : kContinuationFrameMinimumSize;
297 std::string encoding =
298 encoder_->Next(kHttp2MaxControlFrameSendSize - size_without_block);
299 has_next_frame_ = encoder_->HasNext();
300
301 if (framer_->debug_visitor_ != nullptr) {
302 const auto& header_block_frame_ir =
303 static_cast<const SpdyFrameWithHeaderBlockIR&>(frame_ir);
304 const size_t header_list_size =
305 GetUncompressedSerializedLength(header_block_frame_ir.header_block());
306 framer_->debug_visitor_->OnSendCompressedFrame(
307 frame_ir.stream_id(),
308 is_first_frame_ ? frame_ir.frame_type() : SpdyFrameType::CONTINUATION,
309 header_list_size, size_without_block + encoding.size());
310 }
311
312 const size_t free_bytes_before = output->BytesFree();
313 bool ok = false;
314 if (is_first_frame_) {
315 is_first_frame_ = false;
316 ok = SerializeGivenEncoding(encoding, output);
317 } else {
318 SpdyContinuationIR continuation_ir(frame_ir.stream_id());
319 continuation_ir.take_encoding(std::move(encoding));
320 continuation_ir.set_end_headers(!has_next_frame_);
321 ok = framer_->SerializeContinuation(continuation_ir, output);
322 }
323 return ok ? free_bytes_before - output->BytesFree() : 0;
324 }
325
HasNextFrame() const326 bool SpdyFramer::SpdyFrameIterator::HasNextFrame() const {
327 return has_next_frame_;
328 }
329
SpdyHeaderFrameIterator(SpdyFramer * framer,std::unique_ptr<const SpdyHeadersIR> headers_ir)330 SpdyFramer::SpdyHeaderFrameIterator::SpdyHeaderFrameIterator(
331 SpdyFramer* framer, std::unique_ptr<const SpdyHeadersIR> headers_ir)
332 : SpdyFrameIterator(framer), headers_ir_(std::move(headers_ir)) {
333 SetEncoder(headers_ir_.get());
334 }
335
336 SpdyFramer::SpdyHeaderFrameIterator::~SpdyHeaderFrameIterator() = default;
337
GetIR() const338 const SpdyFrameIR& SpdyFramer::SpdyHeaderFrameIterator::GetIR() const {
339 return *headers_ir_;
340 }
341
GetFrameSizeSansBlock() const342 size_t SpdyFramer::SpdyHeaderFrameIterator::GetFrameSizeSansBlock() const {
343 return GetHeaderFrameSizeSansBlock(*headers_ir_);
344 }
345
SerializeGivenEncoding(const std::string & encoding,ZeroCopyOutputBuffer * output) const346 bool SpdyFramer::SpdyHeaderFrameIterator::SerializeGivenEncoding(
347 const std::string& encoding, ZeroCopyOutputBuffer* output) const {
348 return SerializeHeadersGivenEncoding(*headers_ir_, encoding,
349 !has_next_frame(), output);
350 }
351
SpdyPushPromiseFrameIterator(SpdyFramer * framer,std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir)352 SpdyFramer::SpdyPushPromiseFrameIterator::SpdyPushPromiseFrameIterator(
353 SpdyFramer* framer,
354 std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir)
355 : SpdyFrameIterator(framer), push_promise_ir_(std::move(push_promise_ir)) {
356 SetEncoder(push_promise_ir_.get());
357 }
358
359 SpdyFramer::SpdyPushPromiseFrameIterator::~SpdyPushPromiseFrameIterator() =
360 default;
361
GetIR() const362 const SpdyFrameIR& SpdyFramer::SpdyPushPromiseFrameIterator::GetIR() const {
363 return *push_promise_ir_;
364 }
365
GetFrameSizeSansBlock() const366 size_t SpdyFramer::SpdyPushPromiseFrameIterator::GetFrameSizeSansBlock() const {
367 return GetPushPromiseFrameSizeSansBlock(*push_promise_ir_);
368 }
369
SerializeGivenEncoding(const std::string & encoding,ZeroCopyOutputBuffer * output) const370 bool SpdyFramer::SpdyPushPromiseFrameIterator::SerializeGivenEncoding(
371 const std::string& encoding, ZeroCopyOutputBuffer* output) const {
372 return SerializePushPromiseGivenEncoding(*push_promise_ir_, encoding,
373 !has_next_frame(), output);
374 }
375
SpdyControlFrameIterator(SpdyFramer * framer,std::unique_ptr<const SpdyFrameIR> frame_ir)376 SpdyFramer::SpdyControlFrameIterator::SpdyControlFrameIterator(
377 SpdyFramer* framer, std::unique_ptr<const SpdyFrameIR> frame_ir)
378 : framer_(framer), frame_ir_(std::move(frame_ir)) {}
379
380 SpdyFramer::SpdyControlFrameIterator::~SpdyControlFrameIterator() = default;
381
NextFrame(ZeroCopyOutputBuffer * output)382 size_t SpdyFramer::SpdyControlFrameIterator::NextFrame(
383 ZeroCopyOutputBuffer* output) {
384 size_t size_written = framer_->SerializeFrame(*frame_ir_, output);
385 has_next_frame_ = false;
386 return size_written;
387 }
388
HasNextFrame() const389 bool SpdyFramer::SpdyControlFrameIterator::HasNextFrame() const {
390 return has_next_frame_;
391 }
392
GetIR() const393 const SpdyFrameIR& SpdyFramer::SpdyControlFrameIterator::GetIR() const {
394 return *frame_ir_;
395 }
396
CreateIterator(SpdyFramer * framer,std::unique_ptr<const SpdyFrameIR> frame_ir)397 std::unique_ptr<SpdyFrameSequence> SpdyFramer::CreateIterator(
398 SpdyFramer* framer, std::unique_ptr<const SpdyFrameIR> frame_ir) {
399 switch (frame_ir->frame_type()) {
400 case SpdyFrameType::HEADERS: {
401 return std::make_unique<SpdyHeaderFrameIterator>(
402 framer, absl::WrapUnique(
403 static_cast<const SpdyHeadersIR*>(frame_ir.release())));
404 }
405 case SpdyFrameType::PUSH_PROMISE: {
406 return std::make_unique<SpdyPushPromiseFrameIterator>(
407 framer, absl::WrapUnique(static_cast<const SpdyPushPromiseIR*>(
408 frame_ir.release())));
409 }
410 case SpdyFrameType::DATA: {
411 QUICHE_DVLOG(1) << "Serialize a stream end DATA frame for VTL";
412 ABSL_FALLTHROUGH_INTENDED;
413 }
414 default: {
415 return std::make_unique<SpdyControlFrameIterator>(framer,
416 std::move(frame_ir));
417 }
418 }
419 }
420
SerializeData(const SpdyDataIR & data_ir)421 SpdySerializedFrame SpdyFramer::SerializeData(const SpdyDataIR& data_ir) {
422 uint8_t flags = DATA_FLAG_NONE;
423 int num_padding_fields = 0;
424 size_t size_with_padding = 0;
425 SerializeDataBuilderHelper(data_ir, &flags, &num_padding_fields,
426 &size_with_padding);
427
428 SpdyFrameBuilder builder(size_with_padding);
429 builder.BeginNewFrame(SpdyFrameType::DATA, flags, data_ir.stream_id());
430 if (data_ir.padded()) {
431 builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
432 }
433 builder.WriteBytes(data_ir.data(), data_ir.data_len());
434 if (data_ir.padding_payload_len() > 0) {
435 std::string padding(data_ir.padding_payload_len(), 0);
436 builder.WriteBytes(padding.data(), padding.length());
437 }
438 QUICHE_DCHECK_EQ(size_with_padding, builder.length());
439 return builder.take();
440 }
441
SerializeDataFrameHeaderWithPaddingLengthField(const SpdyDataIR & data_ir)442 SpdySerializedFrame SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField(
443 const SpdyDataIR& data_ir) {
444 uint8_t flags = DATA_FLAG_NONE;
445 size_t frame_size = 0;
446 size_t num_padding_fields = 0;
447 SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper(
448 data_ir, &flags, &frame_size, &num_padding_fields);
449
450 SpdyFrameBuilder builder(frame_size);
451 builder.BeginNewFrame(
452 SpdyFrameType::DATA, flags, data_ir.stream_id(),
453 num_padding_fields + data_ir.data_len() + data_ir.padding_payload_len());
454 if (data_ir.padded()) {
455 builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
456 }
457 QUICHE_DCHECK_EQ(frame_size, builder.length());
458 return builder.take();
459 }
460
SerializeRstStream(const SpdyRstStreamIR & rst_stream) const461 SpdySerializedFrame SpdyFramer::SerializeRstStream(
462 const SpdyRstStreamIR& rst_stream) const {
463 size_t expected_length = kRstStreamFrameSize;
464 SpdyFrameBuilder builder(expected_length);
465
466 builder.BeginNewFrame(SpdyFrameType::RST_STREAM, 0, rst_stream.stream_id());
467
468 builder.WriteUInt32(rst_stream.error_code());
469
470 QUICHE_DCHECK_EQ(expected_length, builder.length());
471 return builder.take();
472 }
473
SerializeSettings(const SpdySettingsIR & settings) const474 SpdySerializedFrame SpdyFramer::SerializeSettings(
475 const SpdySettingsIR& settings) const {
476 uint8_t flags = 0;
477 // Size, in bytes, of this SETTINGS frame.
478 size_t size = 0;
479 const SettingsMap* values = &(settings.values());
480 SerializeSettingsBuilderHelper(settings, &flags, values, &size);
481 SpdyFrameBuilder builder(size);
482 builder.BeginNewFrame(SpdyFrameType::SETTINGS, flags, 0);
483
484 // If this is an ACK, payload should be empty.
485 if (settings.is_ack()) {
486 return builder.take();
487 }
488
489 QUICHE_DCHECK_EQ(kSettingsFrameMinimumSize, builder.length());
490 for (auto it = values->begin(); it != values->end(); ++it) {
491 int setting_id = it->first;
492 QUICHE_DCHECK_GE(setting_id, 0);
493 builder.WriteUInt16(static_cast<SpdySettingsId>(setting_id));
494 builder.WriteUInt32(it->second);
495 }
496 QUICHE_DCHECK_EQ(size, builder.length());
497 return builder.take();
498 }
499
SerializePing(const SpdyPingIR & ping) const500 SpdySerializedFrame SpdyFramer::SerializePing(const SpdyPingIR& ping) const {
501 SpdyFrameBuilder builder(kPingFrameSize);
502 uint8_t flags = 0;
503 if (ping.is_ack()) {
504 flags |= PING_FLAG_ACK;
505 }
506 builder.BeginNewFrame(SpdyFrameType::PING, flags, 0);
507 builder.WriteUInt64(ping.id());
508 QUICHE_DCHECK_EQ(kPingFrameSize, builder.length());
509 return builder.take();
510 }
511
SerializeGoAway(const SpdyGoAwayIR & goaway) const512 SpdySerializedFrame SpdyFramer::SerializeGoAway(
513 const SpdyGoAwayIR& goaway) const {
514 // Compute the output buffer size, take opaque data into account.
515 size_t expected_length = kGoawayFrameMinimumSize;
516 expected_length += goaway.description().size();
517 SpdyFrameBuilder builder(expected_length);
518
519 // Serialize the GOAWAY frame.
520 builder.BeginNewFrame(SpdyFrameType::GOAWAY, 0, 0);
521
522 // GOAWAY frames specify the last good stream id.
523 builder.WriteUInt32(goaway.last_good_stream_id());
524
525 // GOAWAY frames also specify the error code.
526 builder.WriteUInt32(goaway.error_code());
527
528 // GOAWAY frames may also specify opaque data.
529 if (!goaway.description().empty()) {
530 builder.WriteBytes(goaway.description().data(),
531 goaway.description().size());
532 }
533
534 QUICHE_DCHECK_EQ(expected_length, builder.length());
535 return builder.take();
536 }
537
SerializeHeadersBuilderHelper(const SpdyHeadersIR & headers,uint8_t * flags,size_t * size,std::string * hpack_encoding,int * weight,size_t * length_field)538 void SpdyFramer::SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers,
539 uint8_t* flags, size_t* size,
540 std::string* hpack_encoding,
541 int* weight,
542 size_t* length_field) {
543 if (headers.fin()) {
544 *flags = *flags | CONTROL_FLAG_FIN;
545 }
546 // This will get overwritten if we overflow into a CONTINUATION frame.
547 *flags = *flags | HEADERS_FLAG_END_HEADERS;
548 if (headers.has_priority()) {
549 *flags = *flags | HEADERS_FLAG_PRIORITY;
550 }
551 if (headers.padded()) {
552 *flags = *flags | HEADERS_FLAG_PADDED;
553 }
554
555 *size = kHeadersFrameMinimumSize;
556
557 if (headers.padded()) {
558 *size = *size + kPadLengthFieldSize;
559 *size = *size + headers.padding_payload_len();
560 }
561
562 if (headers.has_priority()) {
563 *weight = ClampHttp2Weight(headers.weight());
564 *size = *size + 5;
565 }
566
567 *hpack_encoding =
568 GetHpackEncoder()->EncodeHeaderBlock(headers.header_block());
569 *size = *size + hpack_encoding->size();
570 if (*size > kHttp2MaxControlFrameSendSize) {
571 *size = *size + GetNumberRequiredContinuationFrames(*size) *
572 kContinuationFrameMinimumSize;
573 *flags = *flags & ~HEADERS_FLAG_END_HEADERS;
574 }
575 // Compute frame length field.
576 if (headers.padded()) {
577 *length_field = *length_field + kPadLengthFieldSize;
578 }
579 if (headers.has_priority()) {
580 *length_field = *length_field + 4; // Dependency field.
581 *length_field = *length_field + 1; // Weight field.
582 }
583 *length_field = *length_field + headers.padding_payload_len();
584 *length_field = *length_field + hpack_encoding->size();
585 // If the HEADERS frame with payload would exceed the max frame size, then
586 // WritePayloadWithContinuation() will serialize CONTINUATION frames as
587 // necessary.
588 *length_field =
589 std::min(*length_field, kHttp2MaxControlFrameSendSize - kFrameHeaderSize);
590 }
591
SerializeHeaders(const SpdyHeadersIR & headers)592 SpdySerializedFrame SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers) {
593 uint8_t flags = 0;
594 // The size of this frame, including padding (if there is any) and
595 // variable-length header block.
596 size_t size = 0;
597 std::string hpack_encoding;
598 int weight = 0;
599 size_t length_field = 0;
600 SerializeHeadersBuilderHelper(headers, &flags, &size, &hpack_encoding,
601 &weight, &length_field);
602
603 SpdyFrameBuilder builder(size);
604 builder.BeginNewFrame(SpdyFrameType::HEADERS, flags, headers.stream_id(),
605 length_field);
606
607 QUICHE_DCHECK_EQ(kHeadersFrameMinimumSize, builder.length());
608
609 int padding_payload_len = 0;
610 if (headers.padded()) {
611 builder.WriteUInt8(headers.padding_payload_len());
612 padding_payload_len = headers.padding_payload_len();
613 }
614 if (headers.has_priority()) {
615 builder.WriteUInt32(PackStreamDependencyValues(headers.exclusive(),
616 headers.parent_stream_id()));
617 // Per RFC 7540 section 6.3, serialized weight value is actual value - 1.
618 builder.WriteUInt8(weight - 1);
619 }
620 WritePayloadWithContinuation(&builder, hpack_encoding, headers.stream_id(),
621 SpdyFrameType::HEADERS, padding_payload_len);
622
623 if (debug_visitor_) {
624 const size_t header_list_size =
625 GetUncompressedSerializedLength(headers.header_block());
626 debug_visitor_->OnSendCompressedFrame(headers.stream_id(),
627 SpdyFrameType::HEADERS,
628 header_list_size, builder.length());
629 }
630
631 return builder.take();
632 }
633
SerializeWindowUpdate(const SpdyWindowUpdateIR & window_update)634 SpdySerializedFrame SpdyFramer::SerializeWindowUpdate(
635 const SpdyWindowUpdateIR& window_update) {
636 SpdyFrameBuilder builder(kWindowUpdateFrameSize);
637 builder.BeginNewFrame(SpdyFrameType::WINDOW_UPDATE, kNoFlags,
638 window_update.stream_id());
639 builder.WriteUInt32(window_update.delta());
640 QUICHE_DCHECK_EQ(kWindowUpdateFrameSize, builder.length());
641 return builder.take();
642 }
643
SerializePushPromiseBuilderHelper(const SpdyPushPromiseIR & push_promise,uint8_t * flags,std::string * hpack_encoding,size_t * size)644 void SpdyFramer::SerializePushPromiseBuilderHelper(
645 const SpdyPushPromiseIR& push_promise, uint8_t* flags,
646 std::string* hpack_encoding, size_t* size) {
647 *flags = 0;
648 // This will get overwritten if we overflow into a CONTINUATION frame.
649 *flags = *flags | PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
650 // The size of this frame, including variable-length name-value block.
651 *size = kPushPromiseFrameMinimumSize;
652
653 if (push_promise.padded()) {
654 *flags = *flags | PUSH_PROMISE_FLAG_PADDED;
655 *size = *size + kPadLengthFieldSize;
656 *size = *size + push_promise.padding_payload_len();
657 }
658
659 *hpack_encoding =
660 GetHpackEncoder()->EncodeHeaderBlock(push_promise.header_block());
661 *size = *size + hpack_encoding->size();
662 if (*size > kHttp2MaxControlFrameSendSize) {
663 *size = *size + GetNumberRequiredContinuationFrames(*size) *
664 kContinuationFrameMinimumSize;
665 *flags = *flags & ~PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
666 }
667 }
668
SerializePushPromise(const SpdyPushPromiseIR & push_promise)669 SpdySerializedFrame SpdyFramer::SerializePushPromise(
670 const SpdyPushPromiseIR& push_promise) {
671 uint8_t flags = 0;
672 size_t size = 0;
673 std::string hpack_encoding;
674 SerializePushPromiseBuilderHelper(push_promise, &flags, &hpack_encoding,
675 &size);
676
677 SpdyFrameBuilder builder(size);
678 size_t length =
679 std::min(size, kHttp2MaxControlFrameSendSize) - kFrameHeaderSize;
680 builder.BeginNewFrame(SpdyFrameType::PUSH_PROMISE, flags,
681 push_promise.stream_id(), length);
682 int padding_payload_len = 0;
683 if (push_promise.padded()) {
684 builder.WriteUInt8(push_promise.padding_payload_len());
685 builder.WriteUInt32(push_promise.promised_stream_id());
686 QUICHE_DCHECK_EQ(kPushPromiseFrameMinimumSize + kPadLengthFieldSize,
687 builder.length());
688
689 padding_payload_len = push_promise.padding_payload_len();
690 } else {
691 builder.WriteUInt32(push_promise.promised_stream_id());
692 QUICHE_DCHECK_EQ(kPushPromiseFrameMinimumSize, builder.length());
693 }
694
695 WritePayloadWithContinuation(
696 &builder, hpack_encoding, push_promise.stream_id(),
697 SpdyFrameType::PUSH_PROMISE, padding_payload_len);
698
699 if (debug_visitor_) {
700 const size_t header_list_size =
701 GetUncompressedSerializedLength(push_promise.header_block());
702 debug_visitor_->OnSendCompressedFrame(push_promise.stream_id(),
703 SpdyFrameType::PUSH_PROMISE,
704 header_list_size, builder.length());
705 }
706
707 return builder.take();
708 }
709
SerializeContinuation(const SpdyContinuationIR & continuation) const710 SpdySerializedFrame SpdyFramer::SerializeContinuation(
711 const SpdyContinuationIR& continuation) const {
712 const std::string& encoding = continuation.encoding();
713 size_t frame_size = kContinuationFrameMinimumSize + encoding.size();
714 SpdyFrameBuilder builder(frame_size);
715 uint8_t flags = continuation.end_headers() ? HEADERS_FLAG_END_HEADERS : 0;
716 builder.BeginNewFrame(SpdyFrameType::CONTINUATION, flags,
717 continuation.stream_id());
718 QUICHE_DCHECK_EQ(kFrameHeaderSize, builder.length());
719
720 builder.WriteBytes(encoding.data(), encoding.size());
721 return builder.take();
722 }
723
SerializeAltSvc(const SpdyAltSvcIR & altsvc_ir)724 SpdySerializedFrame SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir) {
725 std::string value;
726 size_t size = 0;
727 SerializeAltSvcBuilderHelper(altsvc_ir, &value, &size);
728 SpdyFrameBuilder builder(size);
729 builder.BeginNewFrame(SpdyFrameType::ALTSVC, kNoFlags, altsvc_ir.stream_id());
730
731 builder.WriteUInt16(altsvc_ir.origin().length());
732 builder.WriteBytes(altsvc_ir.origin().data(), altsvc_ir.origin().length());
733 builder.WriteBytes(value.data(), value.length());
734 QUICHE_DCHECK_LT(kGetAltSvcFrameMinimumSize, builder.length());
735 return builder.take();
736 }
737
SerializePriority(const SpdyPriorityIR & priority) const738 SpdySerializedFrame SpdyFramer::SerializePriority(
739 const SpdyPriorityIR& priority) const {
740 SpdyFrameBuilder builder(kPriorityFrameSize);
741 builder.BeginNewFrame(SpdyFrameType::PRIORITY, kNoFlags,
742 priority.stream_id());
743
744 builder.WriteUInt32(PackStreamDependencyValues(priority.exclusive(),
745 priority.parent_stream_id()));
746 // Per RFC 7540 section 6.3, serialized weight value is actual value - 1.
747 builder.WriteUInt8(priority.weight() - 1);
748 QUICHE_DCHECK_EQ(kPriorityFrameSize, builder.length());
749 return builder.take();
750 }
751
SerializePriorityUpdate(const SpdyPriorityUpdateIR & priority_update) const752 SpdySerializedFrame SpdyFramer::SerializePriorityUpdate(
753 const SpdyPriorityUpdateIR& priority_update) const {
754 const size_t total_size = kPriorityUpdateFrameMinimumSize +
755 priority_update.priority_field_value().size();
756 SpdyFrameBuilder builder(total_size);
757 builder.BeginNewFrame(SpdyFrameType::PRIORITY_UPDATE, kNoFlags,
758 priority_update.stream_id());
759
760 builder.WriteUInt32(priority_update.prioritized_stream_id());
761 builder.WriteBytes(priority_update.priority_field_value().data(),
762 priority_update.priority_field_value().size());
763 QUICHE_DCHECK_EQ(total_size, builder.length());
764 return builder.take();
765 }
766
SerializeAcceptCh(const SpdyAcceptChIR & accept_ch) const767 SpdySerializedFrame SpdyFramer::SerializeAcceptCh(
768 const SpdyAcceptChIR& accept_ch) const {
769 const size_t total_size = accept_ch.size();
770 SpdyFrameBuilder builder(total_size);
771 builder.BeginNewFrame(SpdyFrameType::ACCEPT_CH, kNoFlags,
772 accept_ch.stream_id());
773
774 for (const AcceptChOriginValuePair& entry : accept_ch.entries()) {
775 builder.WriteUInt16(entry.origin.size());
776 builder.WriteBytes(entry.origin.data(), entry.origin.size());
777 builder.WriteUInt16(entry.value.size());
778 builder.WriteBytes(entry.value.data(), entry.value.size());
779 }
780
781 QUICHE_DCHECK_EQ(total_size, builder.length());
782 return builder.take();
783 }
784
SerializeUnknown(const SpdyUnknownIR & unknown) const785 SpdySerializedFrame SpdyFramer::SerializeUnknown(
786 const SpdyUnknownIR& unknown) const {
787 const size_t total_size = kFrameHeaderSize + unknown.payload().size();
788 SpdyFrameBuilder builder(total_size);
789 builder.BeginNewUncheckedFrame(unknown.type(), unknown.flags(),
790 unknown.stream_id(), unknown.length());
791 builder.WriteBytes(unknown.payload().data(), unknown.payload().size());
792 return builder.take();
793 }
794
795 namespace {
796
797 class FrameSerializationVisitor : public SpdyFrameVisitor {
798 public:
FrameSerializationVisitor(SpdyFramer * framer)799 explicit FrameSerializationVisitor(SpdyFramer* framer)
800 : framer_(framer), frame_() {}
801 ~FrameSerializationVisitor() override = default;
802
ReleaseSerializedFrame()803 SpdySerializedFrame ReleaseSerializedFrame() { return std::move(frame_); }
804
VisitData(const SpdyDataIR & data)805 void VisitData(const SpdyDataIR& data) override {
806 frame_ = framer_->SerializeData(data);
807 }
VisitRstStream(const SpdyRstStreamIR & rst_stream)808 void VisitRstStream(const SpdyRstStreamIR& rst_stream) override {
809 frame_ = framer_->SerializeRstStream(rst_stream);
810 }
VisitSettings(const SpdySettingsIR & settings)811 void VisitSettings(const SpdySettingsIR& settings) override {
812 frame_ = framer_->SerializeSettings(settings);
813 }
VisitPing(const SpdyPingIR & ping)814 void VisitPing(const SpdyPingIR& ping) override {
815 frame_ = framer_->SerializePing(ping);
816 }
VisitGoAway(const SpdyGoAwayIR & goaway)817 void VisitGoAway(const SpdyGoAwayIR& goaway) override {
818 frame_ = framer_->SerializeGoAway(goaway);
819 }
VisitHeaders(const SpdyHeadersIR & headers)820 void VisitHeaders(const SpdyHeadersIR& headers) override {
821 frame_ = framer_->SerializeHeaders(headers);
822 }
VisitWindowUpdate(const SpdyWindowUpdateIR & window_update)823 void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) override {
824 frame_ = framer_->SerializeWindowUpdate(window_update);
825 }
VisitPushPromise(const SpdyPushPromiseIR & push_promise)826 void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override {
827 frame_ = framer_->SerializePushPromise(push_promise);
828 }
VisitContinuation(const SpdyContinuationIR & continuation)829 void VisitContinuation(const SpdyContinuationIR& continuation) override {
830 frame_ = framer_->SerializeContinuation(continuation);
831 }
VisitAltSvc(const SpdyAltSvcIR & altsvc)832 void VisitAltSvc(const SpdyAltSvcIR& altsvc) override {
833 frame_ = framer_->SerializeAltSvc(altsvc);
834 }
VisitPriority(const SpdyPriorityIR & priority)835 void VisitPriority(const SpdyPriorityIR& priority) override {
836 frame_ = framer_->SerializePriority(priority);
837 }
VisitPriorityUpdate(const SpdyPriorityUpdateIR & priority_update)838 void VisitPriorityUpdate(
839 const SpdyPriorityUpdateIR& priority_update) override {
840 frame_ = framer_->SerializePriorityUpdate(priority_update);
841 }
VisitAcceptCh(const SpdyAcceptChIR & accept_ch)842 void VisitAcceptCh(const SpdyAcceptChIR& accept_ch) override {
843 frame_ = framer_->SerializeAcceptCh(accept_ch);
844 }
VisitUnknown(const SpdyUnknownIR & unknown)845 void VisitUnknown(const SpdyUnknownIR& unknown) override {
846 frame_ = framer_->SerializeUnknown(unknown);
847 }
848
849 private:
850 SpdyFramer* framer_;
851 SpdySerializedFrame frame_;
852 };
853
854 // TODO(diannahu): Use also in frame serialization.
855 class FlagsSerializationVisitor : public SpdyFrameVisitor {
856 public:
VisitData(const SpdyDataIR & data)857 void VisitData(const SpdyDataIR& data) override {
858 flags_ = DATA_FLAG_NONE;
859 if (data.fin()) {
860 flags_ |= DATA_FLAG_FIN;
861 }
862 if (data.padded()) {
863 flags_ |= DATA_FLAG_PADDED;
864 }
865 }
866
VisitRstStream(const SpdyRstStreamIR &)867 void VisitRstStream(const SpdyRstStreamIR& /*rst_stream*/) override {
868 flags_ = kNoFlags;
869 }
870
VisitSettings(const SpdySettingsIR & settings)871 void VisitSettings(const SpdySettingsIR& settings) override {
872 flags_ = kNoFlags;
873 if (settings.is_ack()) {
874 flags_ |= SETTINGS_FLAG_ACK;
875 }
876 }
877
VisitPing(const SpdyPingIR & ping)878 void VisitPing(const SpdyPingIR& ping) override {
879 flags_ = kNoFlags;
880 if (ping.is_ack()) {
881 flags_ |= PING_FLAG_ACK;
882 }
883 }
884
VisitGoAway(const SpdyGoAwayIR &)885 void VisitGoAway(const SpdyGoAwayIR& /*goaway*/) override {
886 flags_ = kNoFlags;
887 }
888
889 // TODO(diannahu): The END_HEADERS flag is incorrect for HEADERS that require
890 // CONTINUATION frames.
VisitHeaders(const SpdyHeadersIR & headers)891 void VisitHeaders(const SpdyHeadersIR& headers) override {
892 flags_ = HEADERS_FLAG_END_HEADERS;
893 if (headers.fin()) {
894 flags_ |= CONTROL_FLAG_FIN;
895 }
896 if (headers.padded()) {
897 flags_ |= HEADERS_FLAG_PADDED;
898 }
899 if (headers.has_priority()) {
900 flags_ |= HEADERS_FLAG_PRIORITY;
901 }
902 }
903
VisitWindowUpdate(const SpdyWindowUpdateIR &)904 void VisitWindowUpdate(const SpdyWindowUpdateIR& /*window_update*/) override {
905 flags_ = kNoFlags;
906 }
907
908 // TODO(diannahu): The END_PUSH_PROMISE flag is incorrect for PUSH_PROMISEs
909 // that require CONTINUATION frames.
VisitPushPromise(const SpdyPushPromiseIR & push_promise)910 void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override {
911 flags_ = PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
912 if (push_promise.padded()) {
913 flags_ |= PUSH_PROMISE_FLAG_PADDED;
914 }
915 }
916
917 // TODO(diannahu): The END_HEADERS flag is incorrect for CONTINUATIONs that
918 // require CONTINUATION frames.
VisitContinuation(const SpdyContinuationIR &)919 void VisitContinuation(const SpdyContinuationIR& /*continuation*/) override {
920 flags_ = HEADERS_FLAG_END_HEADERS;
921 }
922
VisitAltSvc(const SpdyAltSvcIR &)923 void VisitAltSvc(const SpdyAltSvcIR& /*altsvc*/) override {
924 flags_ = kNoFlags;
925 }
926
VisitPriority(const SpdyPriorityIR &)927 void VisitPriority(const SpdyPriorityIR& /*priority*/) override {
928 flags_ = kNoFlags;
929 }
930
VisitPriorityUpdate(const SpdyPriorityUpdateIR &)931 void VisitPriorityUpdate(
932 const SpdyPriorityUpdateIR& /*priority_update*/) override {
933 flags_ = kNoFlags;
934 }
935
VisitAcceptCh(const SpdyAcceptChIR &)936 void VisitAcceptCh(const SpdyAcceptChIR& /*accept_ch*/) override {
937 flags_ = kNoFlags;
938 }
939
flags() const940 uint8_t flags() const { return flags_; }
941
942 private:
943 uint8_t flags_ = kNoFlags;
944 };
945
946 } // namespace
947
SerializeFrame(const SpdyFrameIR & frame)948 SpdySerializedFrame SpdyFramer::SerializeFrame(const SpdyFrameIR& frame) {
949 FrameSerializationVisitor visitor(this);
950 frame.Visit(&visitor);
951 return visitor.ReleaseSerializedFrame();
952 }
953
GetSerializedFlags(const SpdyFrameIR & frame)954 uint8_t SpdyFramer::GetSerializedFlags(const SpdyFrameIR& frame) {
955 FlagsSerializationVisitor visitor;
956 frame.Visit(&visitor);
957 return visitor.flags();
958 }
959
SerializeData(const SpdyDataIR & data_ir,ZeroCopyOutputBuffer * output) const960 bool SpdyFramer::SerializeData(const SpdyDataIR& data_ir,
961 ZeroCopyOutputBuffer* output) const {
962 uint8_t flags = DATA_FLAG_NONE;
963 int num_padding_fields = 0;
964 size_t size_with_padding = 0;
965 SerializeDataBuilderHelper(data_ir, &flags, &num_padding_fields,
966 &size_with_padding);
967 SpdyFrameBuilder builder(size_with_padding, output);
968
969 bool ok =
970 builder.BeginNewFrame(SpdyFrameType::DATA, flags, data_ir.stream_id());
971
972 if (data_ir.padded()) {
973 ok = ok && builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
974 }
975
976 ok = ok && builder.WriteBytes(data_ir.data(), data_ir.data_len());
977 if (data_ir.padding_payload_len() > 0) {
978 std::string padding;
979 padding = std::string(data_ir.padding_payload_len(), 0);
980 ok = ok && builder.WriteBytes(padding.data(), padding.length());
981 }
982 QUICHE_DCHECK_EQ(size_with_padding, builder.length());
983 return ok;
984 }
985
SerializeDataFrameHeaderWithPaddingLengthField(const SpdyDataIR & data_ir,ZeroCopyOutputBuffer * output) const986 bool SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField(
987 const SpdyDataIR& data_ir, ZeroCopyOutputBuffer* output) const {
988 uint8_t flags = DATA_FLAG_NONE;
989 size_t frame_size = 0;
990 size_t num_padding_fields = 0;
991 SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper(
992 data_ir, &flags, &frame_size, &num_padding_fields);
993
994 SpdyFrameBuilder builder(frame_size, output);
995 bool ok = true;
996 ok = ok &&
997 builder.BeginNewFrame(SpdyFrameType::DATA, flags, data_ir.stream_id(),
998 num_padding_fields + data_ir.data_len() +
999 data_ir.padding_payload_len());
1000 if (data_ir.padded()) {
1001 ok = ok && builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
1002 }
1003 QUICHE_DCHECK_EQ(frame_size, builder.length());
1004 return ok;
1005 }
1006
SerializeRstStream(const SpdyRstStreamIR & rst_stream,ZeroCopyOutputBuffer * output) const1007 bool SpdyFramer::SerializeRstStream(const SpdyRstStreamIR& rst_stream,
1008 ZeroCopyOutputBuffer* output) const {
1009 size_t expected_length = kRstStreamFrameSize;
1010 SpdyFrameBuilder builder(expected_length, output);
1011 bool ok = builder.BeginNewFrame(SpdyFrameType::RST_STREAM, 0,
1012 rst_stream.stream_id());
1013 ok = ok && builder.WriteUInt32(rst_stream.error_code());
1014
1015 QUICHE_DCHECK_EQ(expected_length, builder.length());
1016 return ok;
1017 }
1018
SerializeSettings(const SpdySettingsIR & settings,ZeroCopyOutputBuffer * output) const1019 bool SpdyFramer::SerializeSettings(const SpdySettingsIR& settings,
1020 ZeroCopyOutputBuffer* output) const {
1021 uint8_t flags = 0;
1022 // Size, in bytes, of this SETTINGS frame.
1023 size_t size = 0;
1024 const SettingsMap* values = &(settings.values());
1025 SerializeSettingsBuilderHelper(settings, &flags, values, &size);
1026 SpdyFrameBuilder builder(size, output);
1027 bool ok = builder.BeginNewFrame(SpdyFrameType::SETTINGS, flags, 0);
1028
1029 // If this is an ACK, payload should be empty.
1030 if (settings.is_ack()) {
1031 return ok;
1032 }
1033
1034 QUICHE_DCHECK_EQ(kSettingsFrameMinimumSize, builder.length());
1035 for (auto it = values->begin(); it != values->end(); ++it) {
1036 int setting_id = it->first;
1037 QUICHE_DCHECK_GE(setting_id, 0);
1038 ok = ok && builder.WriteUInt16(static_cast<SpdySettingsId>(setting_id)) &&
1039 builder.WriteUInt32(it->second);
1040 }
1041 QUICHE_DCHECK_EQ(size, builder.length());
1042 return ok;
1043 }
1044
SerializePing(const SpdyPingIR & ping,ZeroCopyOutputBuffer * output) const1045 bool SpdyFramer::SerializePing(const SpdyPingIR& ping,
1046 ZeroCopyOutputBuffer* output) const {
1047 SpdyFrameBuilder builder(kPingFrameSize, output);
1048 uint8_t flags = 0;
1049 if (ping.is_ack()) {
1050 flags |= PING_FLAG_ACK;
1051 }
1052 bool ok = builder.BeginNewFrame(SpdyFrameType::PING, flags, 0);
1053 ok = ok && builder.WriteUInt64(ping.id());
1054 QUICHE_DCHECK_EQ(kPingFrameSize, builder.length());
1055 return ok;
1056 }
1057
SerializeGoAway(const SpdyGoAwayIR & goaway,ZeroCopyOutputBuffer * output) const1058 bool SpdyFramer::SerializeGoAway(const SpdyGoAwayIR& goaway,
1059 ZeroCopyOutputBuffer* output) const {
1060 // Compute the output buffer size, take opaque data into account.
1061 size_t expected_length = kGoawayFrameMinimumSize;
1062 expected_length += goaway.description().size();
1063 SpdyFrameBuilder builder(expected_length, output);
1064
1065 // Serialize the GOAWAY frame.
1066 bool ok = builder.BeginNewFrame(SpdyFrameType::GOAWAY, 0, 0);
1067
1068 // GOAWAY frames specify the last good stream id.
1069 ok = ok && builder.WriteUInt32(goaway.last_good_stream_id()) &&
1070 // GOAWAY frames also specify the error status code.
1071 builder.WriteUInt32(goaway.error_code());
1072
1073 // GOAWAY frames may also specify opaque data.
1074 if (!goaway.description().empty()) {
1075 ok = ok && builder.WriteBytes(goaway.description().data(),
1076 goaway.description().size());
1077 }
1078
1079 QUICHE_DCHECK_EQ(expected_length, builder.length());
1080 return ok;
1081 }
1082
SerializeHeaders(const SpdyHeadersIR & headers,ZeroCopyOutputBuffer * output)1083 bool SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers,
1084 ZeroCopyOutputBuffer* output) {
1085 uint8_t flags = 0;
1086 // The size of this frame, including padding (if there is any) and
1087 // variable-length header block.
1088 size_t size = 0;
1089 std::string hpack_encoding;
1090 int weight = 0;
1091 size_t length_field = 0;
1092 SerializeHeadersBuilderHelper(headers, &flags, &size, &hpack_encoding,
1093 &weight, &length_field);
1094
1095 bool ok = true;
1096 SpdyFrameBuilder builder(size, output);
1097 ok = ok && builder.BeginNewFrame(SpdyFrameType::HEADERS, flags,
1098 headers.stream_id(), length_field);
1099 QUICHE_DCHECK_EQ(kHeadersFrameMinimumSize, builder.length());
1100
1101 int padding_payload_len = 0;
1102 if (headers.padded()) {
1103 ok = ok && builder.WriteUInt8(headers.padding_payload_len());
1104 padding_payload_len = headers.padding_payload_len();
1105 }
1106 if (headers.has_priority()) {
1107 ok = ok &&
1108 builder.WriteUInt32(PackStreamDependencyValues(
1109 headers.exclusive(), headers.parent_stream_id())) &&
1110 // Per RFC 7540 section 6.3, serialized weight value is weight - 1.
1111 builder.WriteUInt8(weight - 1);
1112 }
1113 ok = ok && WritePayloadWithContinuation(
1114 &builder, hpack_encoding, headers.stream_id(),
1115 SpdyFrameType::HEADERS, padding_payload_len);
1116
1117 if (debug_visitor_) {
1118 const size_t header_list_size =
1119 GetUncompressedSerializedLength(headers.header_block());
1120 debug_visitor_->OnSendCompressedFrame(headers.stream_id(),
1121 SpdyFrameType::HEADERS,
1122 header_list_size, builder.length());
1123 }
1124
1125 return ok;
1126 }
1127
SerializeWindowUpdate(const SpdyWindowUpdateIR & window_update,ZeroCopyOutputBuffer * output) const1128 bool SpdyFramer::SerializeWindowUpdate(const SpdyWindowUpdateIR& window_update,
1129 ZeroCopyOutputBuffer* output) const {
1130 SpdyFrameBuilder builder(kWindowUpdateFrameSize, output);
1131 bool ok = builder.BeginNewFrame(SpdyFrameType::WINDOW_UPDATE, kNoFlags,
1132 window_update.stream_id());
1133 ok = ok && builder.WriteUInt32(window_update.delta());
1134 QUICHE_DCHECK_EQ(kWindowUpdateFrameSize, builder.length());
1135 return ok;
1136 }
1137
SerializePushPromise(const SpdyPushPromiseIR & push_promise,ZeroCopyOutputBuffer * output)1138 bool SpdyFramer::SerializePushPromise(const SpdyPushPromiseIR& push_promise,
1139 ZeroCopyOutputBuffer* output) {
1140 uint8_t flags = 0;
1141 size_t size = 0;
1142 std::string hpack_encoding;
1143 SerializePushPromiseBuilderHelper(push_promise, &flags, &hpack_encoding,
1144 &size);
1145
1146 bool ok = true;
1147 SpdyFrameBuilder builder(size, output);
1148 size_t length =
1149 std::min(size, kHttp2MaxControlFrameSendSize) - kFrameHeaderSize;
1150 ok = builder.BeginNewFrame(SpdyFrameType::PUSH_PROMISE, flags,
1151 push_promise.stream_id(), length);
1152
1153 int padding_payload_len = 0;
1154 if (push_promise.padded()) {
1155 ok = ok && builder.WriteUInt8(push_promise.padding_payload_len()) &&
1156 builder.WriteUInt32(push_promise.promised_stream_id());
1157 QUICHE_DCHECK_EQ(kPushPromiseFrameMinimumSize + kPadLengthFieldSize,
1158 builder.length());
1159
1160 padding_payload_len = push_promise.padding_payload_len();
1161 } else {
1162 ok = ok && builder.WriteUInt32(push_promise.promised_stream_id());
1163 QUICHE_DCHECK_EQ(kPushPromiseFrameMinimumSize, builder.length());
1164 }
1165
1166 ok = ok && WritePayloadWithContinuation(
1167 &builder, hpack_encoding, push_promise.stream_id(),
1168 SpdyFrameType::PUSH_PROMISE, padding_payload_len);
1169
1170 if (debug_visitor_) {
1171 const size_t header_list_size =
1172 GetUncompressedSerializedLength(push_promise.header_block());
1173 debug_visitor_->OnSendCompressedFrame(push_promise.stream_id(),
1174 SpdyFrameType::PUSH_PROMISE,
1175 header_list_size, builder.length());
1176 }
1177
1178 return ok;
1179 }
1180
SerializeContinuation(const SpdyContinuationIR & continuation,ZeroCopyOutputBuffer * output) const1181 bool SpdyFramer::SerializeContinuation(const SpdyContinuationIR& continuation,
1182 ZeroCopyOutputBuffer* output) const {
1183 const std::string& encoding = continuation.encoding();
1184 size_t frame_size = kContinuationFrameMinimumSize + encoding.size();
1185 SpdyFrameBuilder builder(frame_size, output);
1186 uint8_t flags = continuation.end_headers() ? HEADERS_FLAG_END_HEADERS : 0;
1187 bool ok = builder.BeginNewFrame(SpdyFrameType::CONTINUATION, flags,
1188 continuation.stream_id(),
1189 frame_size - kFrameHeaderSize);
1190 QUICHE_DCHECK_EQ(kFrameHeaderSize, builder.length());
1191
1192 ok = ok && builder.WriteBytes(encoding.data(), encoding.size());
1193 return ok;
1194 }
1195
SerializeAltSvc(const SpdyAltSvcIR & altsvc_ir,ZeroCopyOutputBuffer * output)1196 bool SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir,
1197 ZeroCopyOutputBuffer* output) {
1198 std::string value;
1199 size_t size = 0;
1200 SerializeAltSvcBuilderHelper(altsvc_ir, &value, &size);
1201 SpdyFrameBuilder builder(size, output);
1202 bool ok = builder.BeginNewFrame(SpdyFrameType::ALTSVC, kNoFlags,
1203 altsvc_ir.stream_id()) &&
1204 builder.WriteUInt16(altsvc_ir.origin().length()) &&
1205 builder.WriteBytes(altsvc_ir.origin().data(),
1206 altsvc_ir.origin().length()) &&
1207 builder.WriteBytes(value.data(), value.length());
1208 QUICHE_DCHECK_LT(kGetAltSvcFrameMinimumSize, builder.length());
1209 return ok;
1210 }
1211
SerializePriority(const SpdyPriorityIR & priority,ZeroCopyOutputBuffer * output) const1212 bool SpdyFramer::SerializePriority(const SpdyPriorityIR& priority,
1213 ZeroCopyOutputBuffer* output) const {
1214 SpdyFrameBuilder builder(kPriorityFrameSize, output);
1215 bool ok = builder.BeginNewFrame(SpdyFrameType::PRIORITY, kNoFlags,
1216 priority.stream_id());
1217 ok = ok &&
1218 builder.WriteUInt32(PackStreamDependencyValues(
1219 priority.exclusive(), priority.parent_stream_id())) &&
1220 // Per RFC 7540 section 6.3, serialized weight value is actual value - 1.
1221 builder.WriteUInt8(priority.weight() - 1);
1222 QUICHE_DCHECK_EQ(kPriorityFrameSize, builder.length());
1223 return ok;
1224 }
1225
SerializePriorityUpdate(const SpdyPriorityUpdateIR & priority_update,ZeroCopyOutputBuffer * output) const1226 bool SpdyFramer::SerializePriorityUpdate(
1227 const SpdyPriorityUpdateIR& priority_update,
1228 ZeroCopyOutputBuffer* output) const {
1229 const size_t total_size = kPriorityUpdateFrameMinimumSize +
1230 priority_update.priority_field_value().size();
1231 SpdyFrameBuilder builder(total_size, output);
1232 bool ok = builder.BeginNewFrame(SpdyFrameType::PRIORITY_UPDATE, kNoFlags,
1233 priority_update.stream_id());
1234
1235 ok = ok && builder.WriteUInt32(priority_update.prioritized_stream_id());
1236 ok = ok && builder.WriteBytes(priority_update.priority_field_value().data(),
1237 priority_update.priority_field_value().size());
1238 QUICHE_DCHECK_EQ(total_size, builder.length());
1239 return ok;
1240 }
1241
SerializeAcceptCh(const SpdyAcceptChIR & accept_ch,ZeroCopyOutputBuffer * output) const1242 bool SpdyFramer::SerializeAcceptCh(const SpdyAcceptChIR& accept_ch,
1243 ZeroCopyOutputBuffer* output) const {
1244 const size_t total_size = accept_ch.size();
1245 SpdyFrameBuilder builder(total_size, output);
1246 bool ok = builder.BeginNewFrame(SpdyFrameType::ACCEPT_CH, kNoFlags,
1247 accept_ch.stream_id());
1248
1249 for (const AcceptChOriginValuePair& entry : accept_ch.entries()) {
1250 ok = ok && builder.WriteUInt16(entry.origin.size());
1251 ok = ok && builder.WriteBytes(entry.origin.data(), entry.origin.size());
1252 ok = ok && builder.WriteUInt16(entry.value.size());
1253 ok = ok && builder.WriteBytes(entry.value.data(), entry.value.size());
1254 }
1255
1256 QUICHE_DCHECK_EQ(total_size, builder.length());
1257 return ok;
1258 }
1259
SerializeUnknown(const SpdyUnknownIR & unknown,ZeroCopyOutputBuffer * output) const1260 bool SpdyFramer::SerializeUnknown(const SpdyUnknownIR& unknown,
1261 ZeroCopyOutputBuffer* output) const {
1262 const size_t total_size = kFrameHeaderSize + unknown.payload().size();
1263 SpdyFrameBuilder builder(total_size, output);
1264 bool ok = builder.BeginNewUncheckedFrame(
1265 unknown.type(), unknown.flags(), unknown.stream_id(), unknown.length());
1266 ok = ok &&
1267 builder.WriteBytes(unknown.payload().data(), unknown.payload().size());
1268 return ok;
1269 }
1270
1271 namespace {
1272
1273 class FrameSerializationVisitorWithOutput : public SpdyFrameVisitor {
1274 public:
FrameSerializationVisitorWithOutput(SpdyFramer * framer,ZeroCopyOutputBuffer * output)1275 explicit FrameSerializationVisitorWithOutput(SpdyFramer* framer,
1276 ZeroCopyOutputBuffer* output)
1277 : framer_(framer), output_(output), result_(false) {}
1278 ~FrameSerializationVisitorWithOutput() override = default;
1279
Result()1280 size_t Result() { return result_; }
1281
VisitData(const SpdyDataIR & data)1282 void VisitData(const SpdyDataIR& data) override {
1283 result_ = framer_->SerializeData(data, output_);
1284 }
VisitRstStream(const SpdyRstStreamIR & rst_stream)1285 void VisitRstStream(const SpdyRstStreamIR& rst_stream) override {
1286 result_ = framer_->SerializeRstStream(rst_stream, output_);
1287 }
VisitSettings(const SpdySettingsIR & settings)1288 void VisitSettings(const SpdySettingsIR& settings) override {
1289 result_ = framer_->SerializeSettings(settings, output_);
1290 }
VisitPing(const SpdyPingIR & ping)1291 void VisitPing(const SpdyPingIR& ping) override {
1292 result_ = framer_->SerializePing(ping, output_);
1293 }
VisitGoAway(const SpdyGoAwayIR & goaway)1294 void VisitGoAway(const SpdyGoAwayIR& goaway) override {
1295 result_ = framer_->SerializeGoAway(goaway, output_);
1296 }
VisitHeaders(const SpdyHeadersIR & headers)1297 void VisitHeaders(const SpdyHeadersIR& headers) override {
1298 result_ = framer_->SerializeHeaders(headers, output_);
1299 }
VisitWindowUpdate(const SpdyWindowUpdateIR & window_update)1300 void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) override {
1301 result_ = framer_->SerializeWindowUpdate(window_update, output_);
1302 }
VisitPushPromise(const SpdyPushPromiseIR & push_promise)1303 void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override {
1304 result_ = framer_->SerializePushPromise(push_promise, output_);
1305 }
VisitContinuation(const SpdyContinuationIR & continuation)1306 void VisitContinuation(const SpdyContinuationIR& continuation) override {
1307 result_ = framer_->SerializeContinuation(continuation, output_);
1308 }
VisitAltSvc(const SpdyAltSvcIR & altsvc)1309 void VisitAltSvc(const SpdyAltSvcIR& altsvc) override {
1310 result_ = framer_->SerializeAltSvc(altsvc, output_);
1311 }
VisitPriority(const SpdyPriorityIR & priority)1312 void VisitPriority(const SpdyPriorityIR& priority) override {
1313 result_ = framer_->SerializePriority(priority, output_);
1314 }
VisitPriorityUpdate(const SpdyPriorityUpdateIR & priority_update)1315 void VisitPriorityUpdate(
1316 const SpdyPriorityUpdateIR& priority_update) override {
1317 result_ = framer_->SerializePriorityUpdate(priority_update, output_);
1318 }
VisitAcceptCh(const SpdyAcceptChIR & accept_ch)1319 void VisitAcceptCh(const SpdyAcceptChIR& accept_ch) override {
1320 result_ = framer_->SerializeAcceptCh(accept_ch, output_);
1321 }
1322
VisitUnknown(const SpdyUnknownIR & unknown)1323 void VisitUnknown(const SpdyUnknownIR& unknown) override {
1324 result_ = framer_->SerializeUnknown(unknown, output_);
1325 }
1326
1327 private:
1328 SpdyFramer* framer_;
1329 ZeroCopyOutputBuffer* output_;
1330 bool result_;
1331 };
1332
1333 } // namespace
1334
SerializeFrame(const SpdyFrameIR & frame,ZeroCopyOutputBuffer * output)1335 size_t SpdyFramer::SerializeFrame(const SpdyFrameIR& frame,
1336 ZeroCopyOutputBuffer* output) {
1337 FrameSerializationVisitorWithOutput visitor(this, output);
1338 size_t free_bytes_before = output->BytesFree();
1339 frame.Visit(&visitor);
1340 return visitor.Result() ? free_bytes_before - output->BytesFree() : 0;
1341 }
1342
GetHpackEncoder()1343 HpackEncoder* SpdyFramer::GetHpackEncoder() {
1344 if (hpack_encoder_ == nullptr) {
1345 hpack_encoder_ = std::make_unique<HpackEncoder>();
1346 if (!compression_enabled()) {
1347 hpack_encoder_->DisableCompression();
1348 }
1349 }
1350 return hpack_encoder_.get();
1351 }
1352
UpdateHeaderEncoderTableSize(uint32_t value)1353 void SpdyFramer::UpdateHeaderEncoderTableSize(uint32_t value) {
1354 GetHpackEncoder()->ApplyHeaderTableSizeSetting(value);
1355 }
1356
header_encoder_table_size() const1357 size_t SpdyFramer::header_encoder_table_size() const {
1358 if (hpack_encoder_ == nullptr) {
1359 return kDefaultHeaderTableSizeSetting;
1360 } else {
1361 return hpack_encoder_->CurrentHeaderTableSizeSetting();
1362 }
1363 }
1364
1365 } // namespace spdy
1366