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