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