proxygen
HTTP2Framer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
11 
13 
14 using namespace folly::io;
15 using namespace folly;
16 
17 namespace proxygen { namespace http2 {
18 
21 const PriorityUpdate DefaultPriority{0, false, 15};
22 
23 namespace {
24 
25 const uint32_t kLengthMask = 0x00ffffff;
26 const uint32_t kUint31Mask = 0x7fffffff;
27 
28 static const uint64_t kZeroPad[32] = {0};
29 
30 static const bool kStrictPadding = true;
31 
32 static_assert(sizeof(kZeroPad) == 256, "bad zero padding");
33 
34 void writePriorityBody(QueueAppender& appender,
35  uint32_t streamDependency,
36  bool exclusive,
37  uint8_t weight) {
38  DCHECK_EQ(0, ~kUint31Mask & streamDependency);
39 
40  if (exclusive) {
41  streamDependency |= ~kUint31Mask;
42  }
43 
44  appender.writeBE<uint32_t>(streamDependency);
45  appender.writeBE<uint8_t>(weight);
46 }
47 
48 void writePadding(IOBufQueue& queue, folly::Optional<uint8_t> size) {
49  if (size && *size > 0) {
50  auto out = queue.preallocate(*size, *size);
51  memset(out.first, 0, *size);
52  queue.postallocate(*size);
53  }
54 }
55 
61 size_t writeFrameHeader(IOBufQueue& queue,
62  uint32_t length,
64  uint8_t flags,
68  std::unique_ptr<IOBuf> payload,
69  bool reuseIOBufHeadroom = true) noexcept {
71 
72  // the acceptable length is now conditional based on state :(
73  DCHECK_EQ(0, ~kLengthMask & length);
74  DCHECK_EQ(0, ~kUint31Mask & stream);
75 
76  if (priority) {
77  if (FrameType::HEADERS == type || FrameType::EX_HEADERS == type) {
78  DCHECK(flags & PRIORITY);
79  length += kFramePrioritySize;
80  } else {
81  DCHECK(FrameType::PRIORITY == type) << "priority is unexpected";
82  }
83  headerSize += kFramePrioritySize;
84  DCHECK_EQ(0, ~kLengthMask & length);
85  DCHECK_NE(priority->streamDependency, stream) << "Circular dependecy";
86  }
87 
88  // Add or remove padding flags
89  if (padding) {
90  flags |= PADDED;
91  DCHECK(FrameType::HEADERS == type ||
92  FrameType::EX_HEADERS == type ||
93  FrameType::DATA == type ||
94  FrameType::PUSH_PROMISE == type);
95  length += *padding + 1;
96  headerSize += 1;
97  } else {
98  flags &= ~PADDED;
99  }
100 
101  DCHECK_EQ(0, ~kLengthMask & length);
102  DCHECK_EQ(true, isValidFrameType(type));
103  uint32_t lengthAndType =
104  ((kLengthMask & length) << 8) | static_cast<uint8_t>(type);
105 
106  uint64_t payloadLength = 0;
107  if (reuseIOBufHeadroom && payload && !payload->isSharedOne() &&
108  payload->headroom() >= headerSize &&
109  queue.tailroom() < headerSize) {
110  // Use the headroom in payload for the frame header.
111  // Make it appear that the payload IOBuf is empty and retreat so
112  // appender can access the headroom
113  payloadLength = payload->length();
114  payload->trimEnd(payloadLength);
115  payload->retreat(headerSize);
116  auto tail = payload->pop();
117  queue.append(std::move(payload));
118  payload = std::move(tail);
119  }
120  QueueAppender appender(&queue, headerSize);
121  appender.writeBE<uint32_t>(lengthAndType);
122  appender.writeBE<uint8_t>(flags);
123  appender.writeBE<uint32_t>(kUint31Mask & stream);
124 
125  if (padding) {
126  appender.writeBE<uint8_t>(*padding);
127  }
128  if (priority) {
129  writePriorityBody(appender,
130  priority->streamDependency,
131  priority->exclusive,
132  priority->weight);
133  }
134  if (payloadLength) {
135  queue.postallocate(payloadLength);
136  }
137  queue.append(std::move(payload));
138 
139  return length;
140 }
141 
142 uint32_t parseUint31(Cursor& cursor) {
143  // MUST ignore the 1 bit before the stream-id
144  return kUint31Mask & cursor.readBE<uint32_t>();
145 }
146 
147 ErrorCode parseErrorCode(Cursor& cursor, ErrorCode& outCode) {
148  auto code = cursor.readBE<uint32_t>();
149  if (code > kMaxErrorCode) {
150  return ErrorCode::PROTOCOL_ERROR;
151  }
152  outCode = ErrorCode(code);
153  return ErrorCode::NO_ERROR;
154 }
155 
156 PriorityUpdate parsePriorityCommon(Cursor& cursor) {
157  PriorityUpdate priority;
158  uint32_t streamAndExclusive = cursor.readBE<uint32_t>();
159  priority.weight = cursor.readBE<uint8_t>();
160  priority.exclusive = ~kUint31Mask & streamAndExclusive;
161  priority.streamDependency = kUint31Mask & streamAndExclusive;
162  return priority;
163 }
164 
177 ErrorCode
178 parsePadding(Cursor& cursor,
179  const FrameHeader& header,
180  uint8_t& padding, uint32_t& lefttoparse) noexcept {
181  DCHECK(header.type == FrameType::DATA ||
182  header.type == FrameType::HEADERS ||
183  header.type == FrameType::EX_HEADERS ||
184  header.type == FrameType::PUSH_PROMISE);
185  lefttoparse = header.length;
186  if (frameHasPadding(header)) {
187  if (lefttoparse < 1) {
188  return ErrorCode::FRAME_SIZE_ERROR;
189  }
190  lefttoparse -= 1;
191  padding = cursor.readBE<uint8_t>();
192  } else {
193  padding = 0;
194  }
195 
196  if (lefttoparse < padding) {
197  return ErrorCode::PROTOCOL_ERROR;
198  } else {
199  lefttoparse -= padding;
200  return ErrorCode::NO_ERROR;
201  }
202 }
203 
204 ErrorCode
205 skipPadding(Cursor& cursor,
206  uint8_t length,
207  bool verify) {
208  if (verify) {
209  while (length > 0) {
210  auto cur = cursor.peek();
211  uint8_t toCmp = std::min<size_t>(cur.second, length);
212  if (memcmp(cur.first, kZeroPad, toCmp)) {
213  return ErrorCode::PROTOCOL_ERROR;
214  }
215  cursor.skip(toCmp);
216  length -= toCmp;
217  }
218  } else {
219  cursor.skip(length);
220  }
221  return ErrorCode::NO_ERROR;
222 }
223 
224 } // anonymous namespace
225 
227  auto val = static_cast<uint8_t>(type);
228  if (val < kMinExperimentalFrameType) {
229  return val <= static_cast<uint8_t>(FrameType::ALTSVC);
230  } else {
231  switch (type) {
232  case FrameType::EX_HEADERS:
233  // Include the frame types added into FrameType enum for secondary
234  // authentication.
235  case FrameType::CERTIFICATE_REQUEST:
236  case FrameType::CERTIFICATE:
237  return true;
238  default:
239  return false;
240  }
241  }
242 }
243 
245  return t == FrameType::HEADERS ||
246  t == FrameType::PUSH_PROMISE ||
247  t == FrameType::CONTINUATION;
248 }
249 
250  bool frameHasPadding(const FrameHeader& header) {
251  return header.flags & PADDED;
252  }
253 
255 
257  FOLLY_SCOPED_TRACE_SECTION("HTTP2Framer - parseFrameHeader");
258  DCHECK_LE(kFrameHeaderSize, cursor.totalLength());
259 
260  // MUST ignore the 2 bits before the length
261  uint32_t lengthAndType = cursor.readBE<uint32_t>();
262  header.length = kLengthMask & (lengthAndType >> 8);
263  uint8_t type = lengthAndType & 0xff;
264  header.type = FrameType(type);
265  header.flags = cursor.readBE<uint8_t>();
266  header.stream = parseUint31(cursor);
267  return ErrorCode::NO_ERROR;
268  }
269 
271  const FrameHeader& header,
272  std::unique_ptr<IOBuf>& outBuf,
273  uint16_t& outPadding) noexcept {
274  DCHECK_LE(header.length, cursor.totalLength());
275  if (header.stream == 0) {
276  return ErrorCode::PROTOCOL_ERROR;
277  }
278 
279  uint8_t padding;
280  uint32_t lefttoparse;
281  const auto err = parsePadding(cursor, header, padding, lefttoparse);
282  RETURN_IF_ERROR(err);
283  // outPadding is the total number of flow-controlled pad bytes, which
284  // includes the length byte, if present.
285  outPadding = padding + ((frameHasPadding(header)) ? 1 : 0);
286  cursor.clone(outBuf, lefttoparse);
287  return skipPadding(cursor, padding, kStrictPadding);
288  }
289 
291  const FrameHeader& header,
292  size_t& /*parsed*/,
293  uint16_t& outPadding) noexcept {
294  uint8_t padding;
295  uint32_t lefttoparse;
296  const auto err = http2::parsePadding(cursor, header, padding, lefttoparse);
297  RETURN_IF_ERROR(err);
298  // outPadding is the total number of flow-controlled pad bytes, which
299  // includes the length byte, if present.
300  outPadding = padding + ((frameHasPadding(header)) ? 1 : 0);
301  return ErrorCode::NO_ERROR;
302  }
303 
305  const size_t bufLen,
306  const size_t pendingDataFramePaddingBytes,
307  size_t& toSkip) noexcept {
308  toSkip = std::min(pendingDataFramePaddingBytes, bufLen);
309  return skipPadding(cursor, toSkip, kStrictPadding);
310 }
311 
312 ErrorCode
314  const FrameHeader& header,
315  folly::Optional<PriorityUpdate>& outPriority,
316  std::unique_ptr<IOBuf>& outBuf) noexcept {
317  DCHECK_LE(header.length, cursor.totalLength());
318  if (header.stream == 0) {
319  return ErrorCode::PROTOCOL_ERROR;
320  }
321  uint8_t padding;
322  uint32_t lefttoparse;
323  auto err = parsePadding(cursor, header, padding, lefttoparse);
324  RETURN_IF_ERROR(err);
325  if (header.flags & PRIORITY) {
326  if (lefttoparse < kFramePrioritySize) {
327  return ErrorCode::FRAME_SIZE_ERROR;
328  }
329  outPriority = parsePriorityCommon(cursor);
330  lefttoparse -= kFramePrioritySize;
331  } else {
332  outPriority = folly::none;
333  }
334  cursor.clone(outBuf, lefttoparse);
335  return skipPadding(cursor, padding, kStrictPadding);
336 }
337 
338 ErrorCode
340  const FrameHeader& header,
341  HTTPCodec::ExAttributes& outExAttributes,
342  folly::Optional<PriorityUpdate>& outPriority,
343  std::unique_ptr<IOBuf>& outBuf) noexcept {
344  DCHECK_LE(header.length, cursor.totalLength());
345  if (header.stream == 0) {
346  return ErrorCode::PROTOCOL_ERROR;
347  }
348 
349  uint8_t padding;
350  uint32_t lefttoparse;
351  auto err = parsePadding(cursor, header, padding, lefttoparse);
352  RETURN_IF_ERROR(err);
353 
354  // the regular HEADERS frame starts from here
355  if (header.flags & PRIORITY) {
356  if (lefttoparse < kFramePrioritySize) {
357  return ErrorCode::FRAME_SIZE_ERROR;
358  }
359  outPriority = parsePriorityCommon(cursor);
360  lefttoparse -= kFramePrioritySize;
361  } else {
362  outPriority = folly::none;
363  }
364  outExAttributes.unidirectional = header.flags & UNIDIRECTIONAL;
365 
366  if (lefttoparse < kFrameStreamIDSize) {
367  return ErrorCode::FRAME_SIZE_ERROR;
368  }
369  outExAttributes.controlStream = parseUint31(cursor);
370  lefttoparse -= kFrameStreamIDSize;
371  if (!(outExAttributes.controlStream & 0x1)) {
372  // control stream ID should be odd because it is initiated by client
373  return ErrorCode::PROTOCOL_ERROR;
374  }
375 
376  cursor.clone(outBuf, lefttoparse);
377  return skipPadding(cursor, padding, kStrictPadding);
378 }
379 
380 ErrorCode
382  const FrameHeader& header,
383  PriorityUpdate& outPriority) noexcept {
384  DCHECK_LE(header.length, cursor.totalLength());
385  if (header.length != kFramePrioritySize) {
386  return ErrorCode::FRAME_SIZE_ERROR;
387  }
388  if (header.stream == 0) {
389  return ErrorCode::PROTOCOL_ERROR;
390  }
391  outPriority = parsePriorityCommon(cursor);
392  return ErrorCode::NO_ERROR;
393 }
394 
395 ErrorCode
397  const FrameHeader& header,
398  ErrorCode& outCode) noexcept {
399  DCHECK_LE(header.length, cursor.totalLength());
400  if (header.length != kFrameRstStreamSize) {
401  return ErrorCode::FRAME_SIZE_ERROR;
402  }
403  if (header.stream == 0) {
404  return ErrorCode::PROTOCOL_ERROR;
405  }
406  return parseErrorCode(cursor, outCode);
407 }
408 
409 ErrorCode
411  const FrameHeader& header,
412  std::deque<SettingPair>& settings) noexcept {
413  DCHECK_LE(header.length, cursor.totalLength());
414  if (header.stream != 0) {
415  return ErrorCode::PROTOCOL_ERROR;
416  }
417  if (header.flags & ACK) {
418  if (header.length != 0) {
419  return ErrorCode::FRAME_SIZE_ERROR;
420  }
421  return ErrorCode::NO_ERROR;
422  }
423 
424  if (header.length % 6 != 0) {
425  return ErrorCode::FRAME_SIZE_ERROR;
426  }
427  for (auto length = header.length; length > 0; length -= 6) {
428  uint16_t id = cursor.readBE<uint16_t>();
429  uint32_t val = cursor.readBE<uint32_t>();
430  settings.push_back(std::make_pair(SettingsId(id), val));
431  }
432  return ErrorCode::NO_ERROR;
433 }
434 
435 ErrorCode
437  const FrameHeader& header,
438  uint32_t& outPromisedStream,
439  std::unique_ptr<IOBuf>& outBuf) noexcept {
440  DCHECK_LE(header.length, cursor.totalLength());
441  if (header.stream == 0) {
442  return ErrorCode::PROTOCOL_ERROR;
443  }
444 
445  uint8_t padding;
446  uint32_t lefttoparse;
447  auto err = parsePadding(cursor, header, padding, lefttoparse);
448  RETURN_IF_ERROR(err);
449  if (lefttoparse < kFramePushPromiseSize) {
450  return ErrorCode::FRAME_SIZE_ERROR;
451  }
452  lefttoparse -= kFramePushPromiseSize;
453  outPromisedStream = parseUint31(cursor);
454  if (outPromisedStream == 0 ||
455  outPromisedStream & 0x1) {
456  // client MUST reserve an even stream id greater than 0
457  return ErrorCode::PROTOCOL_ERROR;
458  }
459  if (lefttoparse < padding) {
460  return ErrorCode::PROTOCOL_ERROR;
461  }
462  cursor.clone(outBuf, lefttoparse);
463  return skipPadding(cursor, padding, kStrictPadding);
464 }
465 
466 ErrorCode
468  const FrameHeader& header,
469  uint64_t& outOpaqueData) noexcept {
470  DCHECK_LE(header.length, cursor.totalLength());
471 
472  if (header.length != kFramePingSize) {
473  return ErrorCode::FRAME_SIZE_ERROR;
474  }
475  if (header.stream != 0) {
476  return ErrorCode::PROTOCOL_ERROR;
477  }
478 
479  cursor.pull(&outOpaqueData, sizeof(outOpaqueData));
480  return ErrorCode::NO_ERROR;
481 }
482 
483 ErrorCode
485  const FrameHeader& header,
486  uint32_t& outLastStreamID,
487  ErrorCode& outCode,
488  std::unique_ptr<IOBuf>& outDebugData) noexcept {
489  DCHECK_LE(header.length, cursor.totalLength());
490  if (header.length < kFrameGoawaySize) {
491  return ErrorCode::FRAME_SIZE_ERROR;
492  }
493  if (header.stream != 0) {
494  return ErrorCode::PROTOCOL_ERROR;
495  }
496  outLastStreamID = parseUint31(cursor);
497  auto err = parseErrorCode(cursor, outCode);
498  RETURN_IF_ERROR(err);
499  auto length = header.length;
500  length -= kFrameGoawaySize;
501  if (length > 0) {
502  cursor.clone(outDebugData, length);
503  }
504  return ErrorCode::NO_ERROR;
505 }
506 
507 ErrorCode
509  const FrameHeader& header,
510  uint32_t& outAmount) noexcept {
511  DCHECK_LE(header.length, cursor.totalLength());
512  if (header.length != kFrameWindowUpdateSize) {
513  return ErrorCode::FRAME_SIZE_ERROR;
514  }
515  outAmount = parseUint31(cursor);
516  return ErrorCode::NO_ERROR;
517 }
518 
519 ErrorCode
521  const FrameHeader& header,
522  std::unique_ptr<IOBuf>& outBuf) noexcept {
523  DCHECK(header.type == FrameType::CONTINUATION);
524  DCHECK_LE(header.length, cursor.totalLength());
525  if (header.stream == 0) {
526  return ErrorCode::PROTOCOL_ERROR;
527  }
528  cursor.clone(outBuf, header.length);
529  return ErrorCode::NO_ERROR;
530 }
531 
532 ErrorCode
534  const FrameHeader& header,
535  uint32_t& outMaxAge,
536  uint32_t& outPort,
537  std::string& outProtocol,
538  std::string& outHost,
539  std::string& outOrigin) noexcept {
540  DCHECK_LE(header.length, cursor.totalLength());
541  if (header.length < kFrameAltSvcSizeBase) {
542  return ErrorCode::FRAME_SIZE_ERROR;
543  }
544  std::unique_ptr<IOBuf> tmpBuf;
545 
546  outMaxAge = cursor.readBE<uint32_t>();
547  outPort = cursor.readBE<uint16_t>();
548  const auto protoLen = cursor.readBE<uint8_t>();
549  if (header.length < kFrameAltSvcSizeBase + protoLen) {
550  return ErrorCode::FRAME_SIZE_ERROR;
551  }
552  outProtocol = cursor.readFixedString(protoLen);
553  const auto hostLen = cursor.readBE<uint8_t>();
554  if (header.length < kFrameAltSvcSizeBase + protoLen + hostLen) {
555  return ErrorCode::FRAME_SIZE_ERROR;
556  }
557  outHost = cursor.readFixedString(hostLen);
558  const auto originLen = (header.length - kFrameAltSvcSizeBase -
559  protoLen - hostLen);
560  outOrigin = cursor.readFixedString(originLen);
561 
562  return ErrorCode::NO_ERROR;
563 }
564 
566  folly::io::Cursor& cursor,
567  const FrameHeader& header,
568  uint16_t& outRequestId,
569  std::unique_ptr<folly::IOBuf>& outAuthRequest) noexcept {
570  DCHECK_LE(header.length, cursor.totalLength());
571  if (header.length < kFrameCertificateRequestSizeBase) {
572  return ErrorCode::FRAME_SIZE_ERROR;
573  }
574  if (header.stream != 0) {
575  return ErrorCode::PROTOCOL_ERROR;
576  }
577  outRequestId = cursor.readBE<uint16_t>();
578  auto length = header.length;
580  if (length > 0) {
581  cursor.clone(outAuthRequest, length);
582  }
583  return ErrorCode::NO_ERROR;
584 }
585 
587  folly::io::Cursor& cursor,
588  const FrameHeader& header,
589  uint16_t& outCertId,
590  std::unique_ptr<folly::IOBuf>& outAuthenticator) noexcept {
591  DCHECK_LE(header.length, cursor.totalLength());
592  if (header.length < kFrameCertificateSizeBase) {
593  return ErrorCode::FRAME_SIZE_ERROR;
594  }
595  if (header.stream != 0) {
596  return ErrorCode::PROTOCOL_ERROR;
597  }
598  outCertId = cursor.readBE<uint16_t>();
599  auto length = header.length;
600  length -= kFrameCertificateSizeBase;
601  if (length > 0) {
602  cursor.clone(outAuthenticator, length);
603  }
604  return ErrorCode::NO_ERROR;
605 }
606 
608 
609 size_t
611  std::unique_ptr<IOBuf> data,
613  folly::Optional<uint8_t> padding,
614  bool endStream,
615  bool reuseIOBufHeadroom) noexcept {
616  DCHECK_NE(0, stream);
617  uint8_t flags = 0;
618  if (endStream) {
619  flags |= END_STREAM;
620  }
621  const uint64_t dataLen = data ? data->computeChainDataLength() : 0;
622  // Caller must not exceed peer setting for MAX_FRAME_SIZE
623  // TODO: look into using headroom from data to hold the frame header
624  const auto frameLen = writeFrameHeader(queue,
625  dataLen,
626  FrameType::DATA,
627  flags,
628  stream,
629  padding,
630  folly::none,
631  std::move(data),
632  reuseIOBufHeadroom);
633  writePadding(queue, padding);
634  return kFrameHeaderSize + frameLen;
635 }
636 
637 size_t
639  std::unique_ptr<IOBuf> headers,
642  folly::Optional<uint8_t> padding,
643  bool endStream,
644  bool endHeaders) noexcept {
645  DCHECK_NE(0, stream);
646  const auto dataLen = (headers) ? headers->computeChainDataLength() : 0;
647  uint32_t flags = 0;
648  if (priority) {
649  flags |= PRIORITY;
650  }
651  if (endStream) {
652  flags |= END_STREAM;
653  }
654  if (endHeaders) {
655  flags |= END_HEADERS;
656  }
657  // padding flags handled directly inside writeFrameHeader()
658  const auto frameLen = writeFrameHeader(queue,
659  dataLen,
661  flags,
662  stream,
663  padding,
664  priority,
665  std::move(headers));
666  writePadding(queue, padding);
667  return kFrameHeaderSize + frameLen;
668 }
669 
670 size_t
672  std::unique_ptr<IOBuf> headers,
674  const HTTPCodec::ExAttributes& exAttributes,
675  const folly::Optional<PriorityUpdate>& priority,
676  const folly::Optional<uint8_t>& padding,
677  bool endStream,
678  bool endHeaders) noexcept {
679  DCHECK_NE(0, stream);
680  DCHECK_NE(0, exAttributes.controlStream);
681  DCHECK_EQ(0, ~kUint31Mask & stream);
682  DCHECK_EQ(0, ~kUint31Mask & exAttributes.controlStream);
683  DCHECK(0x1 & exAttributes.controlStream) <<
684  "controlStream should be initiated by client";
685 
686  const auto dataLen = (headers) ? headers->computeChainDataLength() : 0;
687  uint32_t flags = 0;
688  if (priority) {
689  flags |= PRIORITY;
690  }
691  if (endStream) {
692  flags |= END_STREAM;
693  }
694  if (endHeaders) {
695  flags |= END_HEADERS;
696  }
697  if (exAttributes.unidirectional) {
698  flags |= UNIDIRECTIONAL;
699  }
700 
701  const auto frameLen = writeFrameHeader(queue,
702  dataLen + kFrameStreamIDSize,
703  FrameType::EX_HEADERS,
704  flags,
705  stream,
706  padding,
707  priority,
708  nullptr);
709  QueueAppender appender(&queue, frameLen);
710  appender.writeBE<uint32_t>(exAttributes.controlStream);
711  queue.append(std::move(headers));
712  writePadding(queue, padding);
713  return kFrameHeaderSize + frameLen;
714 }
715 
716 size_t
719  PriorityUpdate priority) noexcept {
720  DCHECK_NE(0, stream);
721  const auto frameLen = writeFrameHeader(queue,
724  0,
725  stream,
726  kNoPadding,
727  priority,
728  nullptr);
729  return kFrameHeaderSize + frameLen;
730 }
731 
732 size_t
735  ErrorCode errorCode) noexcept {
736  DCHECK_NE(0, stream);
737  const auto frameLen = writeFrameHeader(queue,
740  0,
741  stream,
742  kNoPadding,
743  folly::none,
744  nullptr);
745  QueueAppender appender(&queue, frameLen);
746  appender.writeBE<uint32_t>(static_cast<uint32_t>(errorCode));
747  return kFrameHeaderSize + frameLen;
748 }
749 
750 size_t
752  const std::deque<SettingPair>& settings) {
753  const auto settingsSize = settings.size() * 6;
754  const auto frameLen = writeFrameHeader(queue,
755  settingsSize,
757  0,
758  0,
759  kNoPadding,
760  folly::none,
761  nullptr);
762  QueueAppender appender(&queue, settingsSize);
763  for (const auto& setting: settings) {
764  DCHECK_LE(static_cast<uint32_t>(setting.first),
766  appender.writeBE<uint16_t>(static_cast<uint16_t>(setting.first));
767  appender.writeBE<uint32_t>(setting.second);
768  }
769  return kFrameHeaderSize + frameLen;
770 }
771 
772 size_t
774  writeFrameHeader(queue,
775  0,
777  ACK,
778  0,
779  kNoPadding,
780  folly::none,
781  nullptr);
782  return kFrameHeaderSize;
783 }
784 
785 size_t
787  uint32_t associatedStream,
788  uint32_t promisedStream,
789  std::unique_ptr<IOBuf> headers,
790  folly::Optional<uint8_t> padding,
791  bool endHeaders) noexcept {
792  DCHECK_NE(0, promisedStream);
793  DCHECK_NE(0, associatedStream);
794  DCHECK_EQ(0, 0x1 & promisedStream);
795  DCHECK_EQ(1, 0x1 & associatedStream);
796  DCHECK_EQ(0, ~kUint31Mask & promisedStream);
797 
798  const auto dataLen = headers->computeChainDataLength();
799  const auto frameLen = writeFrameHeader(queue,
800  dataLen + kFramePushPromiseSize,
801  FrameType::PUSH_PROMISE,
802  endHeaders ? END_HEADERS : 0,
803  associatedStream,
804  padding,
805  folly::none,
806  nullptr);
807  QueueAppender appender(&queue, frameLen);
808  appender.writeBE<uint32_t>(promisedStream);
809  queue.append(std::move(headers));
810  writePadding(queue, padding);
811  return kFrameHeaderSize + frameLen;
812 }
813 
814 size_t
816  uint64_t opaqueData,
817  bool ack) noexcept {
818  const auto frameLen = writeFrameHeader(queue,
821  ack ? ACK : 0,
822  0,
823  kNoPadding,
824  folly::none,
825  nullptr);
826  queue.append(&opaqueData, sizeof(opaqueData));
827  return kFrameHeaderSize + frameLen;
828 }
829 
830 size_t
832  uint32_t lastStreamID,
833  ErrorCode errorCode,
834  std::unique_ptr<IOBuf> debugData) noexcept {
835  uint32_t debugLen = debugData ? debugData->computeChainDataLength() : 0;
836  DCHECK_EQ(0, ~kLengthMask & debugLen);
837  const auto frameLen = writeFrameHeader(queue,
838  kFrameGoawaySize + debugLen,
840  0,
841  0,
842  kNoPadding,
843  folly::none,
844  nullptr);
845  QueueAppender appender(&queue, frameLen);
846  appender.writeBE<uint32_t>(lastStreamID);
847  appender.writeBE<uint32_t>(static_cast<uint32_t>(errorCode));
848  queue.append(std::move(debugData));
849  return kFrameHeaderSize + frameLen;
850 }
851 
852 size_t
855  uint32_t amount) noexcept {
856  const auto frameLen = writeFrameHeader(queue,
859  0,
860  stream,
861  kNoPadding,
862  folly::none,
863  nullptr);
864  DCHECK_EQ(0, ~kUint31Mask & amount);
865  DCHECK_LT(0, amount);
866  QueueAppender appender(&queue, kFrameWindowUpdateSize);
867  appender.writeBE<uint32_t>(amount);
868  return kFrameHeaderSize + frameLen;
869 }
870 
871 size_t
874  bool endHeaders,
875  std::unique_ptr<IOBuf> headers) noexcept {
876  DCHECK_NE(0, stream);
877  const auto dataLen = headers->computeChainDataLength();
878  const auto frameLen = writeFrameHeader(queue,
879  dataLen,
880  FrameType::CONTINUATION,
881  endHeaders ? END_HEADERS : 0,
882  stream,
883  kNoPadding,
884  folly::none,
885  std::move(headers));
886  return kFrameHeaderSize + frameLen;
887 }
888 
889 size_t
892  uint32_t maxAge,
893  uint16_t port,
894  StringPiece protocol,
895  StringPiece host,
896  StringPiece origin) noexcept {
897  const auto protoLen = protocol.size();
898  const auto hostLen = host.size();
899  const auto originLen = origin.size();
900  const auto frameLen = protoLen + hostLen + originLen + kFrameAltSvcSizeBase;
901 
902  writeFrameHeader(queue, frameLen, FrameType::ALTSVC, 0, stream, kNoPadding,
903  folly::none, nullptr);
904  QueueAppender appender(&queue, frameLen);
905  appender.writeBE<uint32_t>(maxAge);
906  appender.writeBE<uint16_t>(port);
907  appender.writeBE<uint8_t>(protoLen);
908  appender.push(reinterpret_cast<const uint8_t*>(protocol.data()), protoLen);
909  appender.writeBE<uint8_t>(hostLen);
910  appender.push(reinterpret_cast<const uint8_t*>(host.data()), hostLen);
911  appender.push(reinterpret_cast<const uint8_t*>(origin.data()), originLen);
912  return kFrameHeaderSize + frameLen;
913 }
914 
916  uint16_t requestId,
917  std::unique_ptr<folly::IOBuf> authRequest) {
918  const auto dataLen = authRequest ? kFrameCertificateRequestSizeBase +
919  authRequest->computeChainDataLength()
921  // The CERTIFICATE_REQUEST frame must be sent on stream 0.
922  const auto frameLen = writeFrameHeader(writeBuf,
923  dataLen,
924  FrameType::CERTIFICATE_REQUEST,
925  0,
926  0,
927  kNoPadding,
928  folly::none,
929  nullptr);
930  QueueAppender appender(&writeBuf, frameLen);
931  appender.writeBE<uint16_t>(requestId);
932  writeBuf.append(std::move(authRequest));
933  return kFrameHeaderSize + frameLen;
934 }
935 
937  uint16_t certId,
938  std::unique_ptr<folly::IOBuf> authenticator,
939  bool toBeContinued) {
940  uint8_t flags = 0;
941  if (toBeContinued) {
942  flags |= TO_BE_CONTINUED;
943  }
944  const auto dataLen =
945  authenticator
948  // The CERTIFICATE_REQUEST frame must be sent on stream 0.
949  const auto frameLen = writeFrameHeader(writeBuf,
950  dataLen,
951  FrameType::CERTIFICATE,
952  flags,
953  0,
954  kNoPadding,
955  folly::none,
956  nullptr);
957  QueueAppender appender(&writeBuf, frameLen);
958  appender.writeBE<uint16_t>(certId);
959  writeBuf.append(std::move(authenticator));
960  return kFrameHeaderSize + frameLen;
961 }
962 
964  switch (type) {
965  case FrameType::DATA: return "DATA";
966  case FrameType::HEADERS: return "HEADERS";
967  case FrameType::PRIORITY: return "PRIORITY";
968  case FrameType::RST_STREAM: return "RST_STREAM";
969  case FrameType::SETTINGS: return "SETTINGS";
970  case FrameType::PUSH_PROMISE: return "PUSH_PROMISE";
971  case FrameType::PING: return "PING";
972  case FrameType::GOAWAY: return "GOAWAY";
973  case FrameType::WINDOW_UPDATE: return "WINDOW_UPDATE";
974  case FrameType::CONTINUATION: return "CONTINUATION";
975  case FrameType::ALTSVC: return "ALTSVC";
976  case FrameType::CERTIFICATE_REQUEST: return "CERTIFICATE_REQUEST";
977  case FrameType::CERTIFICATE: return "CERTIFICATE";
978  default:
979  // can happen when type was cast from uint8_t
980  return "Unknown";
981  }
982  LOG(FATAL) << "Unreachable";
983  return "";
984 }
985 }
986 } // namespace http2
ErrorCode parseAltSvc(Cursor &cursor, const FrameHeader &header, uint32_t &outMaxAge, uint32_t &outPort, std::string &outProtocol, std::string &outHost, std::string &outOrigin) noexcept
#define FOLLY_SCOPED_TRACE_SECTION(arg,...)
ErrorCode parseContinuation(Cursor &cursor, const FrameHeader &header, std::unique_ptr< IOBuf > &outBuf) noexcept
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
flags
Definition: http_parser.h:127
void verify(int extras)
constexpr size_t headerSize()
Definition: RecordIO-inl.h:101
size_t writePing(IOBufQueue &queue, uint64_t opaqueData, bool ack) noexcept
ErrorCode parsePushPromise(Cursor &cursor, const FrameHeader &header, uint32_t &outPromisedStream, std::unique_ptr< IOBuf > &outBuf) noexcept
ErrorCode parseFrameHeader(Cursor &cursor, FrameHeader &header) noexcept
const uint32_t kFramePrioritySize
ErrorCode parseGoaway(Cursor &cursor, const FrameHeader &header, uint32_t &outLastStreamID, ErrorCode &outCode, std::unique_ptr< IOBuf > &outDebugData) noexcept
LogLevel max
Definition: LogLevel.cpp:31
const uint32_t kFrameHeaderSize
StreamCodecFactory stream
size_t writeHeaders(IOBufQueue &queue, std::unique_ptr< IOBuf > headers, uint32_t stream, folly::Optional< PriorityUpdate > priority, folly::Optional< uint8_t > padding, bool endStream, bool endHeaders) noexcept
const uint32_t kFrameAltSvcSizeBase
PskType type
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
ErrorCode parsePriority(Cursor &cursor, const FrameHeader &header, PriorityUpdate &outPriority) noexcept
bool isSharedOne() const
Definition: IOBuf.h:952
ErrorCode parseSettings(Cursor &cursor, const FrameHeader &header, std::deque< SettingPair > &settings) noexcept
size_t tailroom() const
Definition: IOBufQueue.h:403
double val
Definition: String.cpp:273
size_t writePushPromise(IOBufQueue &queue, uint32_t associatedStream, uint32_t promisedStream, std::unique_ptr< IOBuf > headers, folly::Optional< uint8_t > padding, bool endHeaders) noexcept
void push(const uint8_t *buf, size_t len)
Definition: Cursor.h:755
static http_parser_settings settings
Definition: test.c:1529
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
ErrorCode parseWindowUpdate(Cursor &cursor, const FrameHeader &header, uint32_t &outAmount) noexcept
size_t writeContinuation(IOBufQueue &queue, uint32_t stream, bool endHeaders, std::unique_ptr< IOBuf > headers) noexcept
ErrorCode parseCertificateRequest(folly::io::Cursor &cursor, const FrameHeader &header, uint16_t &outRequestId, std::unique_ptr< folly::IOBuf > &outAuthRequest) noexcept
bool frameHasPadding(const FrameHeader &header)
std::pair< void *, std::size_t > preallocate(std::size_t min, std::size_t newAllocationSize, std::size_t max=std::numeric_limits< std::size_t >::max())
Definition: IOBufQueue.h:356
size_t writeSettings(IOBufQueue &queue, const std::deque< SettingPair > &settings)
const uint32_t kFrameCertificateSizeBase
std::pair< const uint8_t *, size_t > peek()
Definition: Cursor.h:451
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
void writeBuf(const Buf &buf, folly::io::Appender &out)
std::unique_ptr< IOBuf > pop()
Definition: IOBuf.h:859
LogLevel min
Definition: LogLevel.cpp:30
ErrorCode parseExHeaders(Cursor &cursor, const FrameHeader &header, HTTPCodec::ExAttributes &outExAttributes, folly::Optional< PriorityUpdate > &outPriority, std::unique_ptr< IOBuf > &outBuf) noexcept
const uint32_t kFrameCertificateRequestSizeBase
size_t writePriority(IOBufQueue &queue, uint32_t stream, PriorityUpdate priority) noexcept
const uint32_t kFrameGoawaySize
std::size_t headroom() const
Definition: IOBuf.h:542
size_t writeCertificate(folly::IOBufQueue &writeBuf, uint16_t certId, std::unique_ptr< folly::IOBuf > authenticator, bool toBeContinued)
ErrorCode parseRstStream(Cursor &cursor, const FrameHeader &header, ErrorCode &outCode) noexcept
const uint32_t kFrameWindowUpdateSize
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
std::size_t length() const
Definition: IOBuf.h:533
ErrorCode parseCertificate(folly::io::Cursor &cursor, const FrameHeader &header, uint16_t &outCertId, std::unique_ptr< folly::IOBuf > &outAuthenticator) noexcept
ErrorCode parseDataBegin(Cursor &cursor, const FrameHeader &header, size_t &, uint16_t &outPadding) noexcept
void retreat(std::size_t amount)
Definition: IOBuf.h:653
size_t writeAltSvc(IOBufQueue &queue, uint32_t stream, uint32_t maxAge, uint16_t port, StringPiece protocol, StringPiece host, StringPiece origin) noexcept
const uint8_t kMaxErrorCode
Definition: ErrorCode.cpp:16
size_t writeCertificateRequest(folly::IOBufQueue &writeBuf, uint16_t requestId, std::unique_ptr< folly::IOBuf > authRequest)
ErrorCode parseHeaders(Cursor &cursor, const FrameHeader &header, folly::Optional< PriorityUpdate > &outPriority, std::unique_ptr< IOBuf > &outBuf) noexcept
size_t writeSettingsAck(IOBufQueue &queue)
const PriorityUpdate DefaultPriority
Definition: HTTP2Framer.cpp:21
const uint32_t kFramePushPromiseSize
std::size_t computeChainDataLength() const
Definition: IOBuf.cpp:501
size_t writeRstStream(IOBufQueue &queue, uint32_t stream, ErrorCode errorCode) noexcept
size_t writeExHeaders(IOBufQueue &queue, std::unique_ptr< IOBuf > headers, uint32_t stream, const HTTPCodec::ExAttributes &exAttributes, const folly::Optional< PriorityUpdate > &priority, const folly::Optional< uint8_t > &padding, bool endStream, bool endHeaders) noexcept
const uint8_t kMinExperimentalFrameType
Definition: HTTP2Framer.cpp:19
void skip(size_t len)
Definition: Cursor.h:371
const char * string
Definition: Conv.cpp:212
size_t writeGoaway(IOBufQueue &queue, uint32_t lastStreamID, ErrorCode errorCode, std::unique_ptr< IOBuf > debugData) noexcept
bool isValidFrameType(FrameType type)
const Padding kNoPadding
Definition: HTTP2Framer.cpp:20
const uint32_t kFramePingSize
bool frameAffectsCompression(FrameType t)
#define RETURN_IF_ERROR(err)
Definition: ErrorCode.h:14
const char * getFrameTypeString(FrameType type)
ErrorCode parseData(Cursor &cursor, const FrameHeader &header, std::unique_ptr< IOBuf > &outBuf, uint16_t &outPadding) noexcept
size_t writeData(IOBufQueue &queue, std::unique_ptr< IOBuf > data, uint32_t stream, folly::Optional< uint8_t > padding, bool endStream, bool reuseIOBufHeadroom) noexcept
void postallocate(std::size_t n)
Definition: IOBufQueue.h:380
void trimEnd(std::size_t amount)
Definition: IOBuf.h:718
size_t writeWindowUpdate(IOBufQueue &queue, uint32_t stream, uint32_t amount) noexcept
const uint32_t kFrameStreamIDSize
ErrorCode parseDataEnd(Cursor &cursor, const size_t bufLen, const size_t pendingDataFramePaddingBytes, size_t &toSkip) noexcept
const uint32_t kFrameRstStreamSize
constexpr None none
Definition: Optional.h:87
ErrorCode parsePing(Cursor &cursor, const FrameHeader &header, uint64_t &outOpaqueData) noexcept
void writeBE(T value)
Definition: Cursor.h:744