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