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