proxygen
HTTP2Codec.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  */
15 
16 #include <folly/Conv.h>
17 #include <folly/Random.h>
18 #include <folly/io/Cursor.h>
20 #include <type_traits>
21 
22 using namespace proxygen::compress;
23 using namespace folly::io;
24 using namespace folly;
25 
26 using std::string;
27 
28 namespace {
29 std::string base64url_encode(ByteRange range) {
30  return proxygen::Base64::urlEncode(range);
31 }
32 
33 std::string base64url_decode(const std::string& str) {
34  return proxygen::Base64::urlDecode(str);
35 }
36 
37 }
38 
39 namespace proxygen {
40 
41 
43  : HTTPParallelCodec(direction),
44  headerCodec_(direction),
45  frameState_(direction == TransportDirection::DOWNSTREAM
46  ? FrameState::UPSTREAM_CONNECTION_PREFACE
47  : FrameState::DOWNSTREAM_CONNECTION_PREFACE) {
48 
49  // Set headerCodec_ settings if specified, else let headerCodec_ utilize
50  // its own defaults
51  const auto decoderHeaderTableMaxSize = egressSettings_.getSetting(
53  if (decoderHeaderTableMaxSize) {
54  headerCodec_.setDecoderHeaderTableMaxSize(decoderHeaderTableMaxSize->value);
55  }
56  const auto maxHeaderListSize = egressSettings_.getSetting(
58  if (maxHeaderListSize) {
59  headerCodec_.setMaxUncompressed(maxHeaderListSize->value);
60  }
61 
62  VLOG(4) << "creating " << getTransportDirectionString(direction)
63  << " HTTP/2 codec";
64 }
65 
67 
68 // HTTPCodec API
69 
70 size_t HTTP2Codec::onIngress(const folly::IOBuf& buf) {
71  // TODO: ensure only 1 parse at a time on stack.
72  FOLLY_SCOPED_TRACE_SECTION("HTTP2Codec - onIngress");
73 
74  Cursor cursor(&buf);
75  size_t parsed = 0;
76  ErrorCode connError = ErrorCode::NO_ERROR;
77  for (auto bufLen = cursor.totalLength();
78  connError == ErrorCode::NO_ERROR;
79  bufLen = cursor.totalLength()) {
80  if (frameState_ == FrameState::UPSTREAM_CONNECTION_PREFACE) {
81  if (bufLen >= http2::kConnectionPreface.length()) {
82  auto test = cursor.readFixedString(http2::kConnectionPreface.length());
83  parsed += http2::kConnectionPreface.length();
85  goawayErrorMessage_ = "missing connection preface";
86  VLOG(4) << goawayErrorMessage_;
87  connError = ErrorCode::PROTOCOL_ERROR;
88  }
89  frameState_ = FrameState::FRAME_HEADER;
90  } else {
91  break;
92  }
93  } else if (frameState_ == FrameState::FRAME_HEADER ||
94  frameState_ == FrameState::DOWNSTREAM_CONNECTION_PREFACE) {
95  // Waiting to parse the common frame header
96  if (bufLen >= http2::kFrameHeaderSize) {
97  connError = parseFrameHeader(cursor, curHeader_);
98  parsed += http2::kFrameHeaderSize;
99  if (frameState_ == FrameState::DOWNSTREAM_CONNECTION_PREFACE &&
101  goawayErrorMessage_ = folly::to<string>(
102  "GOAWAY error: got invalid connection preface frame type=",
104  " for streamID=", curHeader_.stream);
105  VLOG(4) << goawayErrorMessage_;
106  connError = ErrorCode::PROTOCOL_ERROR;
107  }
109  VLOG(4) << "Excessively large frame len=" << curHeader_.length;
110  connError = ErrorCode::FRAME_SIZE_ERROR;
111  }
112 
113  if (callback_) {
118  static_cast<uint8_t>(curHeader_.type));
119  }
120 
122  FrameState::DATA_FRAME_DATA : FrameState::FRAME_DATA;
125 #ifndef NDEBUG
127 #endif
128  } else {
129  break;
130  }
131  } else if (frameState_ == FrameState::DATA_FRAME_DATA && bufLen > 0 &&
132  (bufLen < curHeader_.length ||
134  // FrameState::DATA_FRAME_DATA with partial data only
135  size_t dataParsed = 0;
136  connError = parseDataFrameData(cursor, bufLen, dataParsed);
137  if (dataParsed == 0 && pendingDataFrameBytes_ > 0) {
138  // We received only the padding byte, we will wait for more
139  break;
140  } else {
141  parsed += dataParsed;
142  if (pendingDataFrameBytes_ == 0) {
143  frameState_ = FrameState::FRAME_HEADER;
144  }
145  }
146  } else { // FrameState::FRAME_DATA
147  // or FrameState::DATA_FRAME_DATA with all data available
148  // Already parsed the common frame header
149  const auto frameLen = curHeader_.length;
150  if (bufLen >= frameLen) {
151  connError = parseFrame(cursor);
152  parsed += curHeader_.length;
153  frameState_ = FrameState::FRAME_HEADER;
154  } else {
155  break;
156  }
157  }
158  }
159  checkConnectionError(connError, &buf);
160  return parsed;
161 }
162 
164  FOLLY_SCOPED_TRACE_SECTION("HTTP2Codec - parseFrame");
165  if (expectedContinuationStream_ != 0 &&
168  goawayErrorMessage_ = folly::to<string>(
169  "GOAWAY error: while expected CONTINUATION with stream=",
170  expectedContinuationStream_, ", received streamID=", curHeader_.stream,
171  " of type=", getFrameTypeString(curHeader_.type));
172  VLOG(4) << goawayErrorMessage_;
174  }
175  if (expectedContinuationStream_ == 0 &&
177  goawayErrorMessage_ = folly::to<string>(
178  "GOAWAY error: unexpected CONTINUATION received with streamID=",
180  VLOG(4) << goawayErrorMessage_;
182  }
186  // this may be off by up to the padding length (max 255), but
187  // these numbers are already so generous, and we're comparing the
188  // max-uncompressed to the actual compressed size. Let's fail
189  // before buffering.
190 
191  // TODO(t6513634): it would be nicer to stream-process this header
192  // block to keep the connection state consistent without consuming
193  // memory, and fail just the request per the HTTP/2 spec (section
194  // 10.3)
195  goawayErrorMessage_ = folly::to<string>(
196  "Failing connection due to excessively large headers");
197  LOG(ERROR) << goawayErrorMessage_;
199  }
200 
204 
205  switch (curHeader_.type) {
207  return parseAllData(cursor);
209  return parseHeaders(cursor);
211  return parsePriority(cursor);
213  return parseRstStream(cursor);
215  return parseSettings(cursor);
217  return parsePushPromise(cursor);
220  return parseExHeaders(cursor);
221  } else {
222  VLOG(2) << "EX_HEADERS not enabled, ignoring the frame";
223  break;
224  }
226  return parsePing(cursor);
228  return parseGoaway(cursor);
230  return parseWindowUpdate(cursor);
232  return parseContinuation(cursor);
234  // fall through, unimplemented
235  break;
237  return parseCertificateRequest(cursor);
239  return parseCertificate(cursor);
240  default:
241  // Implementations MUST ignore and discard any frame that has a
242  // type that is unknown
243  break;
244  }
245 
246  // Landing here means unknown, unimplemented or ignored frame.
247  VLOG(2) << "Skipping frame (type=" << (uint8_t)curHeader_.type << ")";
248  cursor.skip(curHeader_.length);
249  return ErrorCode::NO_ERROR;
250 }
251 
257  return ErrorCode::NO_ERROR;
258  }
259 
260  // do we need to handle case where this stream has already aborted via
261  // another callback (onHeadersComplete/onBody)?
263 
264  // with a websocket upgrade, we need to send message complete cb to
265  // mirror h1x codec's behavior. when the stream closes, we need to
266  // send another callback to clean up the stream's resources.
268  ingressWebsocketUpgrade_ = false;
270  "onMessageComplete", curHeader_.stream, true);
271  }
272 
276  "onMessageComplete", curHeader_.stream, false);
277  }
278  return ErrorCode::NO_ERROR;
279 }
280 
282  std::unique_ptr<IOBuf> outData;
283  uint16_t padding = 0;
284  VLOG(10) << "parsing all frame DATA bytes for stream=" << curHeader_.stream <<
285  " length=" << curHeader_.length;
286  auto ret = http2::parseData(cursor, curHeader_, outData, padding);
287  RETURN_IF_ERROR(ret);
288 
289  if (callback_ && (padding > 0 || (outData && !outData->empty()))) {
290  if (!outData) {
291  outData = std::make_unique<IOBuf>();
292  }
294  curHeader_.stream, std::move(outData), padding);
295  }
296  return handleEndStream();
297 }
298 
300  size_t bufLen,
301  size_t& parsed) {
302  FOLLY_SCOPED_TRACE_SECTION("HTTP2Codec - parseDataFrameData");
303  if (bufLen == 0) {
304  VLOG(10) << "No data to parse";
305  return ErrorCode::NO_ERROR;
306  }
307 
308  std::unique_ptr<IOBuf> outData;
309  uint16_t padding = 0;
310  VLOG(10) << "parsing DATA frame data for stream=" << curHeader_.stream <<
311  " frame data length=" << curHeader_.length << " pendingDataFrameBytes_=" <<
312  pendingDataFrameBytes_ << " pendingDataFramePaddingBytes_=" <<
313  pendingDataFramePaddingBytes_ << " bufLen=" << bufLen <<
314  " parsed=" << parsed;
315  // Parse the padding information only the first time
318  if (frameHasPadding(curHeader_) && bufLen == 1) {
319  // We need to wait for more bytes otherwise we won't be able to pass
320  // the correct padding to the first onBody call
321  return ErrorCode::NO_ERROR;
322  }
323  const auto ret = http2::parseDataBegin(cursor, curHeader_, parsed, padding);
324  RETURN_IF_ERROR(ret);
325  if (padding > 0) {
326  pendingDataFramePaddingBytes_ = padding - 1;
328  bufLen--;
329  parsed++;
330  }
331  VLOG(10) << "out padding=" << padding << " pendingDataFrameBytes_=" <<
332  pendingDataFrameBytes_ << " pendingDataFramePaddingBytes_=" <<
333  pendingDataFramePaddingBytes_ << " bufLen=" << bufLen <<
334  " parsed=" << parsed;
335  }
336  if (bufLen > 0) {
337  // Check if we have application data to parse
339  const size_t pendingAppData =
341  const size_t toClone = std::min(pendingAppData, bufLen);
342  cursor.clone(outData, toClone);
343  bufLen -= toClone;
344  pendingDataFrameBytes_ -= toClone;
345  parsed += toClone;
346  VLOG(10) << "parsed some app data, pendingDataFrameBytes_=" <<
347  pendingDataFrameBytes_ << " pendingDataFramePaddingBytes_=" <<
348  pendingDataFramePaddingBytes_ << " bufLen=" << bufLen <<
349  " parsed=" << parsed;
350  }
351  // Check if we have padding bytes to parse
352  if (bufLen > 0 && pendingDataFramePaddingBytes_ > 0) {
353  size_t toSkip = 0;
354  auto ret = http2::parseDataEnd(cursor, bufLen,
356  RETURN_IF_ERROR(ret);
357  pendingDataFrameBytes_ -= toSkip;
359  parsed += toSkip;
360  VLOG(10) << "parsed some padding, pendingDataFrameBytes_=" <<
361  pendingDataFrameBytes_ << " pendingDataFramePaddingBytes_=" <<
362  pendingDataFramePaddingBytes_ << " bufLen=" << bufLen <<
363  " parsed=" << parsed;
364  }
365  }
366 
367  if (callback_ && (padding > 0 || (outData && !outData->empty()))) {
368  if (!outData) {
369  outData = std::make_unique<IOBuf>();
370  }
372  curHeader_.stream, std::move(outData), padding);
373  }
375 }
376 
377 
379  FOLLY_SCOPED_TRACE_SECTION("HTTP2Codec - parseHeaders");
381  std::unique_ptr<IOBuf> headerBuf;
382  VLOG(4) << "parsing HEADERS frame for stream=" << curHeader_.stream <<
383  " length=" << curHeader_.length;
384  auto err = http2::parseHeaders(cursor, curHeader_, priority, headerBuf);
385  RETURN_IF_ERROR(err);
388  checkNewStream(curHeader_.stream, true /* trailersAllowed */));
389  }
390  err = parseHeadersImpl(cursor, std::move(headerBuf), priority, folly::none,
391  folly::none);
392  return err;
393 }
394 
396  FOLLY_SCOPED_TRACE_SECTION("HTTP2Codec - parseExHeaders");
397  HTTPCodec::ExAttributes exAttributes;
399  std::unique_ptr<IOBuf> headerBuf;
400  VLOG(4) << "parsing ExHEADERS frame for stream=" << curHeader_.stream
401  << " length=" << curHeader_.length;
402  auto err = http2::parseExHeaders(
403  cursor, curHeader_, exAttributes, priority, headerBuf);
404  RETURN_IF_ERROR(err);
405  if (isRequest(curHeader_.stream)) {
407  checkNewStream(curHeader_.stream, false /* trailersAllowed */));
408  }
409  return parseHeadersImpl(cursor, std::move(headerBuf), priority, folly::none,
410  exAttributes);
411 }
412 
414  std::unique_ptr<IOBuf> headerBuf;
415  VLOG(4) << "parsing CONTINUATION frame for stream=" << curHeader_.stream <<
416  " length=" << curHeader_.length;
417  auto err = http2::parseContinuation(cursor, curHeader_, headerBuf);
418  RETURN_IF_ERROR(err);
419  err = parseHeadersImpl(cursor, std::move(headerBuf),
421  return err;
422 }
423 
425  Cursor& /*cursor*/,
426  std::unique_ptr<IOBuf> headerBuf,
428  const folly::Optional<uint32_t>& promisedStream,
429  const folly::Optional<ExAttributes>& exAttributes) {
430  curHeaderBlock_.append(std::move(headerBuf));
431  std::unique_ptr<HTTPMessage> msg;
433  auto errorCode =
434  parseHeadersDecodeFrames(priority, promisedStream, exAttributes, msg);
435  if (errorCode.hasValue()) {
436  return errorCode.value();
437  }
438  }
439 
440  // if we're not parsing CONTINUATION, then it's start of new header block
443  }
444 
445  // Report back what we've parsed
446  if (callback_) {
447  auto concurError = parseHeadersCheckConcurrentStreams(priority);
448  if (concurError.hasValue()) {
449  return concurError.value();
450  }
451  uint32_t headersCompleteStream = curHeader_.stream;
452  bool trailers = parsingTrailers();
453  bool allHeaderFramesReceived =
456  if (allHeaderFramesReceived && !trailers) {
457  // Only deliver onMessageBegin once per stream.
458  // For responses with CONTINUATION, this will be delayed until
459  // the frame with the END_HEADERS flag set.
461  "onMessageBegin",
463  msg.get())) {
464  return handleEndStream();
465  }
468  "onExMessageBegin",
470  exAttributes->controlStream,
471  exAttributes->unidirectional,
472  msg.get())) {
473  return handleEndStream();
474  }
476  DCHECK(promisedStream);
478  "onPushMessageBegin", *promisedStream,
479  curHeader_.stream, msg.get())) {
480  return handleEndStream();
481  }
482  headersCompleteStream = *promisedStream;
483  }
484 
485  if (curHeader_.flags & http2::END_HEADERS && msg) {
487  // If it there are DATA frames coming, consider it chunked
488  msg->setIsChunked(true);
489  }
490  if (trailers) {
491  VLOG(4) << "Trailers complete for streamId=" << headersCompleteStream
492  << " direction=" << transportDirection_;
493  auto trailerHeaders =
494  std::make_unique<HTTPHeaders>(msg->extractHeaders());
495  msg.reset();
496  callback_->onTrailersComplete(headersCompleteStream,
497  std::move(trailerHeaders));
498  } else {
499  callback_->onHeadersComplete(headersCompleteStream, std::move(msg));
500  }
501  }
502  return handleEndStream();
503  }
504  return ErrorCode::NO_ERROR;
505 }
506 
509  const folly::Optional<uint32_t>& promisedStream,
510  const folly::Optional<ExAttributes>& exAttributes,
511  std::unique_ptr<HTTPMessage>& msg) {
512  // decompress headers
513  Cursor headerCursor(curHeaderBlock_.front());
514  bool isReq = false;
515  if (promisedStream) {
516  isReq = true;
517  } else if (exAttributes) {
518  isReq = isRequest(curHeader_.stream);
519  } else {
521  }
522 
524  if (priority) {
525  if (curHeader_.stream == priority->streamDependency) {
526  streamError(folly::to<string>("Circular dependency for txn=",
530  return ErrorCode::NO_ERROR;
531  }
532 
533  decodeInfo_.msg->setHTTP2Priority(
534  std::make_tuple(priority->streamDependency,
535  priority->exclusive,
536  priority->weight));
537  }
539  headerCursor, curHeaderBlock_.chainLength(), this);
540  msg = std::move(decodeInfo_.msg);
541  // Saving this in case we need to log it on error
542  auto g = folly::makeGuard([this] { curHeaderBlock_.move(); });
543  // Check decoding error
545  static const std::string decodeErrorMessage =
546  "Failed decoding header block for stream=";
547  // Avoid logging header blocks that have failed decoding due to being
548  // excessively large.
550  LOG(ERROR) << decodeErrorMessage << curHeader_.stream
551  << " header block=";
553  } else {
554  LOG(ERROR) << decodeErrorMessage << curHeader_.stream;
555  }
556 
557  if (msg) {
558  // print the partial message
559  msg->dumpMessage(3);
560  }
562  }
563 
564  // Check parsing error
565  if (decodeInfo_.parsingError != "") {
566  LOG(ERROR) << "Failed parsing header list for stream=" << curHeader_.stream
567  << ", error=" << decodeInfo_.parsingError << ", header block=";
570  folly::to<std::string>("HTTP2Codec stream error: ",
571  "stream=",
573  " status=",
574  400,
575  " error: ",
577  err.setHttpStatusCode(400);
578  callback_->onError(curHeader_.stream, err, true);
579  return ErrorCode::NO_ERROR;
580  }
581 
583 }
584 
586  const folly::Optional<http2::PriorityUpdate>& priority) {
590  DCHECK(priority);
591  // callback_->onPriority(priority.get());
592  }
593 
594  // callback checks total number of streams is smaller than settings max
595  if (callback_->numIncomingStreams() >=
598  streamError(folly::to<string>("Exceeded max_concurrent_streams"),
600  return ErrorCode::NO_ERROR;
601  }
602  }
604 }
605 
607  const folly::fbstring& value) {
608  if (decodeInfo_.onHeader(name, value)) {
609  if (name == "user-agent" && userAgent_.empty()) {
610  userAgent_ = value.toStdString();
611  }
612  } else {
613  VLOG(4) << "dir=" << uint32_t(transportDirection_) <<
614  decodeInfo_.parsingError << " codec=" << headerCodec_;
615  }
616 }
617 
619  decodeInfo_.onHeadersComplete(decodedSize);
620  decodeInfo_.msg->setAdvancedProtocolString(http2::kProtocolString);
621 
622  HTTPMessage* msg = decodeInfo_.msg.get();
625  verifier.hasUpgradeProtocol() &&
627  msg->getMethod() == HTTPMethod::CONNECT) {
630  } else {
631  auto it = upgradedStreams_.find(curHeader_.stream);
632  if (it != upgradedStreams_.end()) {
634  // a websocket upgrade was sent on this stream.
635  if (msg->getStatusCode() != 200) {
637  folly::to<string>("Invalid response code to a websocket upgrade: ",
638  msg->getStatusCode());
639  return;
640  }
642  }
643  }
644 }
645 
647  decodeInfo_.decodeError = decodeError;
648 }
649 
651  VLOG(4) << "parsing PRIORITY frame for stream=" << curHeader_.stream <<
652  " length=" << curHeader_.length;
654  auto err = http2::parsePriority(cursor, curHeader_, pri);
655  RETURN_IF_ERROR(err);
656  if (curHeader_.stream == pri.streamDependency) {
657  streamError(folly::to<string>("Circular dependency for txn=",
660  return ErrorCode::NO_ERROR;
661  }
665  pri.exclusive,
666  pri.weight));
667  return ErrorCode::NO_ERROR;
668 }
669 
671  PriorityQueue& queue,
673  uint8_t maxLevel) {
675  size_t bytes = 0;
676  while (maxLevel--) {
677  auto id = createStream();
678  virtualPriorityNodes_.push_back(id);
679  queue.addPriorityNode(id, parent);
680  bytes += generatePriority(writeBuf, id, std::make_tuple(parent, false, 0));
681  parent = id;
682  }
683  return bytes;
684 }
685 
687  // rst for stream in idle state - protocol error
688  VLOG(4) << "parsing RST_STREAM frame for stream=" << curHeader_.stream <<
689  " length=" << curHeader_.length;
692  auto err = http2::parseRstStream(cursor, curHeader_, statusCode);
693  RETURN_IF_ERROR(err);
694  if (statusCode == ErrorCode::PROTOCOL_ERROR) {
695  goawayErrorMessage_ = folly::to<string>(
696  "GOAWAY error: RST_STREAM with code=", getErrorCodeString(statusCode),
697  " for streamID=", curHeader_.stream, " user-agent=", userAgent_);
698  VLOG(2) << goawayErrorMessage_;
699  }
701  curHeader_.stream, statusCode);
702  return ErrorCode::NO_ERROR;
703 }
704 
706  VLOG(4) << "parsing SETTINGS frame for stream=" << curHeader_.stream <<
707  " length=" << curHeader_.length;
708  std::deque<SettingPair> settings;
709  auto err = http2::parseSettings(cursor, curHeader_, settings);
710  RETURN_IF_ERROR(err);
711  if (curHeader_.flags & http2::ACK) {
712  // for stats
713  if (callback_) {
715  }
716  return ErrorCode::NO_ERROR;
717  }
718  return handleSettings(settings);
719 }
720 
721 ErrorCode HTTP2Codec::handleSettings(const std::deque<SettingPair>& settings) {
722  SettingsList settingsList;
723  for (auto& setting: settings) {
724  switch (setting.first) {
726  {
727  uint32_t tableSize = setting.second;
728  if (setting.second > http2::kMaxHeaderTableSize) {
729  VLOG(2) << "Limiting table size from " << tableSize << " to " <<
731  tableSize = http2::kMaxHeaderTableSize;
732  }
734  }
735  break;
737  if ((setting.second != 0 && setting.second != 1) ||
738  (setting.second == 1 &&
740  goawayErrorMessage_ = folly::to<string>(
741  "GOAWAY error: ENABLE_PUSH invalid setting=", setting.second,
742  " for streamID=", curHeader_.stream);
743  VLOG(4) << goawayErrorMessage_;
745  }
746  break;
748  break;
750  if (setting.second > http2::kMaxWindowUpdateSize) {
751  goawayErrorMessage_ = folly::to<string>(
752  "GOAWAY error: INITIAL_WINDOW_SIZE invalid size=", setting.second,
753  " for streamID=", curHeader_.stream);
754  VLOG(4) << goawayErrorMessage_;
756  }
757  break;
759  if (setting.second < http2::kMaxFramePayloadLengthMin ||
760  setting.second > http2::kMaxFramePayloadLength) {
761  goawayErrorMessage_ = folly::to<string>(
762  "GOAWAY error: MAX_FRAME_SIZE invalid size=", setting.second,
763  " for streamID=", curHeader_.stream);
764  VLOG(4) << goawayErrorMessage_;
766  }
768  break;
770  break;
772  {
774  if (ptr && ptr->value > 0) {
776  << " got ENABLE_EX_HEADERS=" << setting.second;
777  if (setting.second != 0 && setting.second != 1) {
778  goawayErrorMessage_ = folly::to<string>(
779  "GOAWAY error: invalid ENABLE_EX_HEADERS=", setting.second,
780  " for streamID=", curHeader_.stream);
781  VLOG(4) << goawayErrorMessage_;
783  }
784  break;
785  } else {
786  // egress ENABLE_EX_HEADERS is disabled, consider the ingress
787  // ENABLE_EX_HEADERS as unknown setting, and ignore it.
788  continue;
789  }
790  }
792  if (setting.second > 1) {
793  goawayErrorMessage_ = folly::to<string>(
794  "GOAWAY error: ENABLE_CONNECT_PROTOCOL invalid number=",
795  setting.second, " for streamID=", curHeader_.stream);
796  VLOG(4) << goawayErrorMessage_;
798  }
799  break;
802  break;
804  break;
805  default:
806  continue; // ignore unknown setting
807  }
808  ingressSettings_.setSetting(setting.first, setting.second);
809  settingsList.push_back(*ingressSettings_.getSetting(setting.first));
810  }
811  if (callback_) {
812  callback_->onSettings(settingsList);
813  }
814  return ErrorCode::NO_ERROR;
815 }
816 
818  // stream id must be idle - protocol error
819  // assoc-stream-id=closed/unknown - protocol error, unless rst_stream sent
820 
821  /*
822  * What does "must handle" mean in the following context? I have to
823  * accept this as a valid pushed resource?
824 
825  However, an endpoint that has sent RST_STREAM on the associated
826  stream MUST handle PUSH_PROMISE frames that might have been
827  created before the RST_STREAM frame is received and processed.
828  */
830  goawayErrorMessage_ = folly::to<string>(
831  "Received PUSH_PROMISE on DOWNSTREAM codec");
832  VLOG(2) << goawayErrorMessage_;
834  }
836  goawayErrorMessage_ = folly::to<string>(
837  "Received PUSH_PROMISE on codec with push disabled");
838  VLOG(2) << goawayErrorMessage_;
840  }
841  VLOG(4) << "parsing PUSH_PROMISE frame for stream=" << curHeader_.stream <<
842  " length=" << curHeader_.length;
843  uint32_t promisedStream;
844  std::unique_ptr<IOBuf> headerBlockFragment;
845  auto err = http2::parsePushPromise(cursor, curHeader_, promisedStream,
846  headerBlockFragment);
847  RETURN_IF_ERROR(err);
848  RETURN_IF_ERROR(checkNewStream(promisedStream, false /* trailersAllowed */));
849  err = parseHeadersImpl(cursor, std::move(headerBlockFragment), folly::none,
850  promisedStream, folly::none);
851  return err;
852 }
853 
855  VLOG(4) << "parsing PING frame length=" << curHeader_.length;
856  uint64_t opaqueData = 0;
857  auto err = http2::parsePing(cursor, curHeader_, opaqueData);
858  RETURN_IF_ERROR(err);
859  if (callback_) {
860  if (curHeader_.flags & http2::ACK) {
861  callback_->onPingReply(opaqueData);
862  } else {
863  callback_->onPingRequest(opaqueData);
864  }
865  }
866  return ErrorCode::NO_ERROR;
867 }
868 
870  VLOG(4) << "parsing GOAWAY frame length=" << curHeader_.length;
871  uint32_t lastGoodStream = 0;
873  std::unique_ptr<IOBuf> debugData;
874 
875  auto err = http2::parseGoaway(cursor, curHeader_, lastGoodStream, statusCode,
876  debugData);
877  if (statusCode != ErrorCode::NO_ERROR) {
878  VLOG(2) << "Goaway error statusCode=" << getErrorCodeString(statusCode)
879  << " lastStream=" << lastGoodStream
880  << " user-agent=" << userAgent_ << " debugData=" <<
881  ((debugData) ? string((char*)debugData->data(), debugData->length()):
882  empty_string);
883  }
884  RETURN_IF_ERROR(err);
885  if (lastGoodStream < ingressGoawayAck_) {
886  ingressGoawayAck_ = lastGoodStream;
887  // Drain all streams <= lastGoodStream
888  // and abort streams > lastGoodStream
889  if (callback_) {
890  callback_->onGoaway(lastGoodStream, statusCode, std::move(debugData));
891  }
892  } else {
893  LOG(WARNING) << "Received multiple GOAWAY with increasing ack";
894  }
895  return ErrorCode::NO_ERROR;
896 }
897 
899  VLOG(4) << "parsing WINDOW_UPDATE frame for stream=" << curHeader_.stream <<
900  " length=" << curHeader_.length;
901  uint32_t delta = 0;
902  auto err = http2::parseWindowUpdate(cursor, curHeader_, delta);
903  RETURN_IF_ERROR(err);
904  if (delta == 0) {
905  VLOG(4) << "Invalid 0 length delta for stream=" << curHeader_.stream;
906  if (curHeader_.stream == 0) {
907  goawayErrorMessage_ = folly::to<string>(
908  "GOAWAY error: invalid/0 length delta for streamID=",
911  } else {
912  // Parsing a zero delta window update should cause a protocol error
913  // and send a rst stream
914  goawayErrorMessage_ = folly::to<string>(
915  "parseWindowUpdate Invalid 0 length");
916  VLOG(4) << goawayErrorMessage_;
917  streamError(folly::to<std::string>("streamID=", curHeader_.stream,
918  " with HTTP2Codec stream error: ",
919  "window update delta=", delta),
922  }
923  }
924  // if window exceeds 2^31-1, connection/stream error flow control error
925  // must be checked in session/txn
927  "onWindowUpdate", curHeader_.stream, delta);
928  return ErrorCode::NO_ERROR;
929 }
930 
932  VLOG(4) << "parsing CERTIFICATE_REQUEST frame length=" << curHeader_.length;
933  uint16_t requestId = 0;
934  std::unique_ptr<IOBuf> authRequest;
935 
937  cursor, curHeader_, requestId, authRequest);
938  RETURN_IF_ERROR(err);
939  if (callback_) {
940  callback_->onCertificateRequest(requestId, std::move(authRequest));
941  }
942  return ErrorCode::NO_ERROR;
943 }
944 
946  VLOG(4) << "parsing CERTIFICATE frame length=" << curHeader_.length;
947  uint16_t certId = 0;
948  std::unique_ptr<IOBuf> authData;
949  auto err = http2::parseCertificate(cursor, curHeader_, certId, authData);
950  RETURN_IF_ERROR(err);
952  curCertId_ = certId;
953  } else if (certId != curCertId_) {
954  // Received CERTIFICATE frame with different Cert-ID.
956  }
959  // Received excessively long authenticator.
961  }
963  auto authenticator = curAuthenticatorBlock_.move();
964  if (callback_) {
965  callback_->onCertificate(certId, std::move(authenticator));
966  } else {
968  }
969  }
970  return ErrorCode::NO_ERROR;
971 }
972 
973 ErrorCode HTTP2Codec::checkNewStream(uint32_t streamId, bool trailersAllowed) {
974  if (streamId == 0) {
975  goawayErrorMessage_ = folly::to<string>(
976  "GOAWAY error: received streamID=", streamId,
977  " as invalid new stream for lastStreamID_=", lastStreamID_);
978  VLOG(4) << goawayErrorMessage_;
980  }
981  parsingDownstreamTrailers_ = trailersAllowed && (streamId <= lastStreamID_);
983  VLOG(4) << "Parsing downstream trailers streamId=" << streamId;
984  }
985 
986  if (sessionClosing_ != ClosingState::CLOSED) {
987  lastStreamID_ = streamId;
988  }
989 
990  if (isInitiatedStream(streamId)) {
991  // this stream should be initiated by us, not by peer
992  goawayErrorMessage_ = folly::to<string>(
993  "GOAWAY error: invalid new stream received with streamID=", streamId);
994  VLOG(4) << goawayErrorMessage_;
996  } else {
997  return ErrorCode::NO_ERROR;
998  }
999 }
1000 
1003  VLOG(4) << "generating connection preface";
1005  return http2::kConnectionPreface.length();
1006  }
1007  return 0;
1008 }
1009 
1012  return false;
1013  }
1015  VLOG(4) << __func__ << " with no HTTP2-Settings";
1016  return false;
1017  }
1018 
1019  const auto& settingsHeader = msg.getHeaders().getSingleOrEmpty(
1021  if (settingsHeader.empty()) {
1022  return true;
1023  }
1024 
1025  auto decoded = base64url_decode(settingsHeader);
1026 
1027  // Must be well formed Base64Url and not too large
1028  if (decoded.empty() || decoded.length() > http2::kMaxFramePayloadLength) {
1029  VLOG(4) << __func__ << " failed to decode HTTP2-Settings";
1030  return false;
1031  }
1032  std::unique_ptr<IOBuf> decodedBuf = IOBuf::wrapBuffer(decoded.data(),
1033  decoded.length());
1034  IOBufQueue settingsQueue{IOBufQueue::cacheChainLength()};
1035  settingsQueue.append(std::move(decodedBuf));
1036  Cursor c(settingsQueue.front());
1037  std::deque<SettingPair> settings;
1038  // downcast is ok because of above length check
1039  http2::FrameHeader frameHeader{
1040  (uint32_t)settingsQueue.chainLength(), 0, http2::FrameType::SETTINGS, 0, 0};
1041  auto err = http2::parseSettings(c, frameHeader, settings);
1042  if (err != ErrorCode::NO_ERROR) {
1043  VLOG(4) << __func__ << " bad settings frame";
1044  return false;
1045  }
1046 
1047  if (handleSettings(settings) != ErrorCode::NO_ERROR) {
1048  VLOG(4) << __func__ << " handleSettings failed";
1049  return false;
1050  }
1051 
1052  return true;
1053 }
1054 
1056  StreamID stream,
1057  const HTTPMessage& msg,
1058  bool eom,
1059  HTTPHeaderSize* size) {
1060  generateHeaderImpl(writeBuf,
1061  stream,
1062  msg,
1063  folly::none, /* assocStream */
1064  folly::none, /* controlStream */
1065  eom,
1066  size);
1067 }
1068 
1070  StreamID stream,
1071  const HTTPMessage& msg,
1072  StreamID assocStream,
1073  bool eom,
1074  HTTPHeaderSize* size) {
1075  generateHeaderImpl(writeBuf,
1076  stream,
1077  msg,
1078  assocStream,
1079  folly::none, /* controlStream */
1080  eom,
1081  size);
1082 }
1083 
1085  StreamID stream,
1086  const HTTPMessage& msg,
1087  const HTTPCodec::ExAttributes& exAttributes,
1088  bool eom,
1089  HTTPHeaderSize* size) {
1090  generateHeaderImpl(writeBuf,
1091  stream,
1092  msg,
1093  folly::none, /* assocStream */
1094  exAttributes,
1095  eom,
1096  size);
1097 }
1098 
1101  StreamID stream,
1102  const HTTPMessage& msg,
1103  const folly::Optional<StreamID>& assocStream,
1104  const folly::Optional<HTTPCodec::ExAttributes>& exAttributes,
1105  bool eom,
1106  HTTPHeaderSize* size) {
1107  if (assocStream) {
1108  CHECK(!exAttributes);
1109  VLOG(4) << "generating PUSH_PROMISE for stream=" << stream;
1110  } else if (exAttributes) {
1111  CHECK(!assocStream);
1112  VLOG(4) << "generating ExHEADERS for stream=" << stream
1113  << " with control stream=" << exAttributes->controlStream
1114  << " unidirectional=" << exAttributes->unidirectional;
1115  } else {
1116  VLOG(4) << "generating HEADERS for stream=" << stream;
1117  }
1118 
1119  if (!isStreamIngressEgressAllowed(stream)) {
1120  VLOG(2) << "Suppressing HEADERS/PROMISE for stream=" << stream <<
1121  " ingressGoawayAck_=" << ingressGoawayAck_;
1122  if (size) {
1123  size->uncompressed = 0;
1124  size->compressed = 0;
1125  }
1126  return;
1127  }
1128 
1129  if (msg.isRequest()) {
1131  assocStream || exAttributes);
1132  if (msg.isEgressWebsocketUpgrade()) {
1133  upgradedStreams_.insert(stream);
1134  }
1135  } else {
1137  exAttributes);
1138  }
1139 
1140  std::vector<std::string> temps;
1141  auto allHeaders = CodecUtil::prepareMessageForCompression(msg, temps);
1142  auto out = encodeHeaders(msg.getHeaders(), allHeaders, size);
1143  IOBufQueue queue(IOBufQueue::cacheChainLength());
1144  queue.append(std::move(out));
1145  auto maxFrameSize = maxSendFrameSize();
1146  if (queue.chainLength() > 0) {
1148  auto res = msg.getHTTP2Priority();
1149  auto remainingFrameSize = maxFrameSize;
1150  if (res) {
1151  pri = http2::PriorityUpdate{std::get<0>(*res), std::get<1>(*res),
1152  std::get<2>(*res)};
1153  DCHECK_GE(remainingFrameSize, http2::kFramePrioritySize)
1154  << "no enough space for priority? frameHeadroom=" << remainingFrameSize;
1155  remainingFrameSize -= http2::kFramePrioritySize;
1156  }
1157  auto chunk = queue.split(std::min(remainingFrameSize, queue.chainLength()));
1158 
1159  bool endHeaders = queue.chainLength() == 0;
1160 
1161  if (assocStream) {
1163  DCHECK(!eom);
1165  http2::writePushPromise(writeBuf,
1166  *assocStream,
1167  stream,
1168  std::move(chunk),
1170  endHeaders));
1171  } else if (exAttributes) {
1173  stream,
1175  http2::writeExHeaders(writeBuf,
1176  std::move(chunk),
1177  stream,
1178  *exAttributes,
1179  pri,
1181  eom,
1182  endHeaders));
1183  } else {
1185  http2::writeHeaders(writeBuf,
1186  std::move(chunk),
1187  stream,
1188  pri,
1190  eom,
1191  endHeaders));
1192  }
1193 
1194  if (!endHeaders) {
1195  generateContinuation(writeBuf, queue, stream, maxFrameSize);
1196  }
1197  }
1198 }
1199 
1201  folly::IOBufQueue& queue,
1202  StreamID stream,
1203  size_t maxFrameSize) {
1204  bool endHeaders = false;
1205  while (!endHeaders) {
1206  auto chunk = queue.split(std::min(maxFrameSize, queue.chainLength()));
1207  endHeaders = (queue.chainLength() == 0);
1208  VLOG(4) << "generating CONTINUATION for stream=" << stream;
1210  stream,
1213  writeBuf, stream, endHeaders, std::move(chunk)));
1214  }
1215 }
1216 
1217 std::unique_ptr<folly::IOBuf> HTTP2Codec::encodeHeaders(
1218  const HTTPHeaders& headers,
1219  std::vector<compress::Header>& allHeaders,
1220  HTTPHeaderSize* size) {
1223  auto out = headerCodec_.encode(allHeaders);
1224  if (size) {
1225  *size = headerCodec_.getEncodedSize();
1226  }
1227 
1231  // The remote side told us they don't want headers this large...
1232  // but this function has no mechanism to fail
1233  string serializedHeaders;
1234  headers.forEach(
1235  [&serializedHeaders] (const string& name, const string& value) {
1236  serializedHeaders = folly::to<string>(serializedHeaders, "\\n", name,
1237  ":", value);
1238  });
1239  LOG(ERROR) << "generating HEADERS frame larger than peer maximum nHeaders="
1240  << headers.size() << " all headers="
1241  << serializedHeaders;
1242  }
1243  return out;
1244 }
1245 
1248  size_t length) {
1249  if (callback_) {
1251  static_cast<uint8_t>(type),
1252  length);
1253  }
1254  return length;
1255 }
1256 
1258  StreamID stream,
1259  std::unique_ptr<folly::IOBuf> chain,
1260  folly::Optional<uint8_t> padding,
1261  bool eom) {
1262  // todo: generate random padding for everything?
1263  size_t written = 0;
1264  if (!isStreamIngressEgressAllowed(stream)) {
1265  VLOG(2) << "Suppressing DATA for stream=" << stream << " ingressGoawayAck_="
1266  << ingressGoawayAck_;
1267  return 0;
1268  }
1269  IOBufQueue queue(IOBufQueue::cacheChainLength());
1270  queue.append(std::move(chain));
1271  size_t maxFrameSize = maxSendFrameSize();
1272  while (queue.chainLength() > maxFrameSize) {
1273  auto chunk = queue.split(maxFrameSize);
1274  written += generateHeaderCallbackWrapper(
1275  stream,
1277  http2::writeData(writeBuf,
1278  std::move(chunk),
1279  stream,
1280  padding,
1281  false,
1283  }
1284 
1285  return written + generateHeaderCallbackWrapper(
1286  stream,
1288  http2::writeData(writeBuf,
1289  queue.move(),
1290  stream,
1291  padding,
1292  eom,
1294 }
1295 
1297  StreamID /*stream*/,
1298  size_t /*length*/) {
1299  // HTTP/2 has no chunk headers
1300  return 0;
1301 }
1302 
1304  StreamID /*stream*/) {
1305  // HTTP/2 has no chunk terminators
1306  return 0;
1307 }
1308 
1310  StreamID stream,
1311  const HTTPHeaders& trailers) {
1312  std::vector<compress::Header> allHeaders;
1313  CodecUtil::appendHeaders(trailers, allHeaders, HTTP_HEADER_NONE);
1314 
1316  auto out = encodeHeaders(trailers, allHeaders, &size);
1317 
1318  IOBufQueue queue(IOBufQueue::cacheChainLength());
1319  queue.append(std::move(out));
1320  auto maxFrameSize = maxSendFrameSize();
1321  if (queue.chainLength() > 0) {
1323  auto remainingFrameSize = maxFrameSize;
1324  auto chunk = queue.split(std::min(remainingFrameSize, queue.chainLength()));
1325  bool endHeaders = queue.chainLength() == 0;
1328  http2::writeHeaders(writeBuf,
1329  std::move(chunk),
1330  stream,
1331  pri,
1333  true /*eom*/,
1334  endHeaders));
1335 
1336  if (!endHeaders) {
1337  generateContinuation(writeBuf, queue, stream, maxFrameSize);
1338  }
1339  }
1340 
1341  return size.compressed;
1342 }
1343 
1345  StreamID stream) {
1346  VLOG(4) << "sending EOM for stream=" << stream;
1347  upgradedStreams_.erase(stream);
1348  if (!isStreamIngressEgressAllowed(stream)) {
1349  VLOG(2) << "suppressed EOM for stream=" << stream << " ingressGoawayAck_="
1350  << ingressGoawayAck_;
1351  return 0;
1352  }
1354  stream,
1356  http2::writeData(writeBuf,
1357  nullptr,
1358  stream,
1360  true,
1362 }
1363 
1365  StreamID stream,
1367  VLOG(4) << "sending RST_STREAM for stream=" << stream
1368  << " with code=" << getErrorCodeString(statusCode);
1369  if (!isStreamIngressEgressAllowed(stream)) {
1370  VLOG(2) << "suppressed RST_STREAM for stream=" << stream
1371  << " ingressGoawayAck_=" << ingressGoawayAck_;
1372  return 0;
1373  }
1374  // Suppress any EOM callback for the current frame.
1375  if (stream == curHeader_.stream) {
1376  curHeader_.flags &= ~http2::END_STREAM;
1377  pendingEndStreamHandling_ = false;
1378  ingressWebsocketUpgrade_ = false;
1379  }
1380  upgradedStreams_.erase(stream);
1381 
1382  if (statusCode == ErrorCode::PROTOCOL_ERROR) {
1383  VLOG(2) << "sending RST_STREAM with code=" << getErrorCodeString(statusCode)
1384  << " for stream=" << stream << " user-agent=" << userAgent_;
1385  }
1386  auto code = http2::errorCodeToReset(statusCode);
1388  http2::writeRstStream(writeBuf, stream, code));
1389 }
1390 
1392  StreamID lastStream,
1394  std::unique_ptr<folly::IOBuf> debugData) {
1395  DCHECK_LE(lastStream, egressGoawayAck_) << "Cannot increase last good stream";
1396  egressGoawayAck_ = lastStream;
1397  if (sessionClosing_ == ClosingState::CLOSED) {
1398  VLOG(4) << "Not sending GOAWAY for closed session";
1399  return 0;
1400  }
1401  switch (sessionClosing_) {
1402  case ClosingState::OPEN:
1403  case ClosingState::OPEN_WITH_GRACEFUL_DRAIN_ENABLED:
1404  if (lastStream == std::numeric_limits<int32_t>::max() &&
1405  statusCode == ErrorCode::NO_ERROR) {
1406  sessionClosing_ = ClosingState::FIRST_GOAWAY_SENT;
1407  } else {
1408  // The user of this codec decided not to do the double goaway
1409  // drain, or this is not a graceful shutdown
1410  sessionClosing_ = ClosingState::CLOSED;
1411  }
1412  break;
1413  case ClosingState::FIRST_GOAWAY_SENT:
1414  sessionClosing_ = ClosingState::CLOSED;
1415  break;
1416  case ClosingState::CLOSING:
1417  case ClosingState::CLOSED:
1418  LOG(FATAL) << "unreachable";
1419  }
1420 
1421  VLOG(4) << "Sending GOAWAY with last acknowledged stream="
1422  << lastStream << " with code=" << getErrorCodeString(statusCode);
1423  if (statusCode == ErrorCode::PROTOCOL_ERROR) {
1424  VLOG(2) << "sending GOAWAY with last acknowledged stream=" << lastStream
1425  << " with code=" << getErrorCodeString(statusCode)
1426  << " user-agent=" << userAgent_;
1427  }
1428 
1429  auto code = http2::errorCodeToGoaway(statusCode);
1431  0,
1433  http2::writeGoaway(writeBuf,
1434  lastStream,
1435  code,
1436  std::move(debugData)));
1437 }
1438 
1440  // should probably let the caller specify when integrating with session
1441  // we know HTTPSession sets up events to track ping latency
1442  uint64_t opaqueData = folly::Random::rand64();
1443  VLOG(4) << "Generating ping request with opaqueData=" << opaqueData;
1445  http2::writePing(writeBuf, opaqueData, false /* no ack */));
1446 }
1447 
1449  uint64_t uniqueID) {
1450  VLOG(4) << "Generating ping reply with opaqueData=" << uniqueID;
1452  http2::writePing(writeBuf, uniqueID, true /* ack */));
1453 }
1454 
1456  std::deque<SettingPair> settings;
1457  for (auto& setting: egressSettings_.getAllSettings()) {
1458  switch (setting.id) {
1461  break;
1464  // HTTP/2 spec says downstream must not send this flag
1465  // HTTP2Codec uses it to determine if push features are enabled
1466  continue;
1467  } else {
1468  CHECK(setting.value == 0 || setting.value == 1);
1469  }
1470  break;
1474  break;
1476  headerCodec_.setMaxUncompressed(setting.value);
1477  break;
1479  CHECK(setting.value == 0 || setting.value == 1);
1480  if (setting.value == 0) {
1481  continue; // just skip the experimental setting if disabled
1482  } else {
1483  VLOG(4) << "generating ENABLE_EX_HEADERS=" << setting.value;
1484  }
1485  break;
1487  if (setting.value == 0) {
1488  continue;
1489  }
1490  break;
1493  break;
1494  default:
1495  LOG(ERROR) << "ignore unknown settingsId="
1497  << " value=" << setting.value;
1498  continue;
1499  }
1500 
1501  settings.push_back(SettingPair(setting.id, setting.value));
1502  }
1504  << " generating " << (unsigned)settings.size() << " settings";
1506  http2::writeSettings(writeBuf, settings));
1507 }
1508 
1510  static HTTP2Codec defaultCodec(TransportDirection::UPSTREAM);
1511 
1512  auto& headers = request.getHeaders();
1514  if (!request.checkForHeaderToken(HTTP_HEADER_CONNECTION, "Upgrade", false)) {
1515  headers.add(HTTP_HEADER_CONNECTION, "Upgrade");
1516  }
1517  IOBufQueue writeBuf{IOBufQueue::cacheChainLength()};
1518  defaultCodec.generateSettings(writeBuf);
1519  writeBuf.trimStart(http2::kFrameHeaderSize);
1520  auto buf = writeBuf.move();
1521  buf->coalesce();
1522  headers.set(http2::kProtocolSettingsHeader,
1523  base64url_encode(folly::ByteRange(buf->data(), buf->length())));
1526  false)) {
1528  }
1529 }
1530 
1533  << " generating settings ack";
1535  http2::writeSettingsAck(writeBuf));
1536 }
1537 
1539  StreamID stream,
1540  uint32_t delta) {
1541  VLOG(4) << "generating window update for stream=" << stream
1542  << ": Processed " << delta << " bytes";
1543  if (!isStreamIngressEgressAllowed(stream)) {
1544  VLOG(2) << "suppressed WINDOW_UPDATE for stream=" << stream
1545  << " ingressGoawayAck_=" << ingressGoawayAck_;
1546  return 0;
1547  }
1549  http2::writeWindowUpdate(writeBuf, stream, delta));
1550 }
1551 
1553  StreamID stream,
1554  const HTTPMessage::HTTPPriority& pri) {
1555  VLOG(4) << "generating priority for stream=" << stream;
1556  if (!isStreamIngressEgressAllowed(stream)) {
1557  VLOG(2) << "suppressed PRIORITY for stream=" << stream
1558  << " ingressGoawayAck_=" << ingressGoawayAck_;
1559  return 0;
1560  }
1562  stream,
1564  http2::writePriority(writeBuf, stream,
1565  {std::get<0>(pri),
1566  std::get<1>(pri),
1567  std::get<2>(pri)}));
1568 }
1569 
1572  uint16_t requestId,
1573  std::unique_ptr<folly::IOBuf> certificateRequestData) {
1574  VLOG(4) << "generating CERTIFICATE_REQUEST with Request-ID=" << requestId;
1576  writeBuf, requestId, std::move(certificateRequestData));
1577 }
1578 
1580  uint16_t certId,
1581  std::unique_ptr<folly::IOBuf> certData) {
1582  size_t written = 0;
1583  VLOG(4) << "sending CERTIFICATE with Cert-ID=" << certId << "for stream=0";
1584  IOBufQueue queue(IOBufQueue::cacheChainLength());
1585  queue.append(std::move(certData));
1586  // The maximum size of an autenticator fragment, combined with the Cert-ID can
1587  // not exceed the maximal allowable size of a sent frame.
1588  size_t maxChunkSize = maxSendFrameSize() - sizeof(certId);
1589  while (queue.chainLength() > maxChunkSize) {
1590  auto chunk = queue.splitAtMost(maxChunkSize);
1591  written +=
1592  http2::writeCertificate(writeBuf, certId, std::move(chunk), true);
1593  }
1594  return written +
1595  http2::writeCertificate(writeBuf, certId, queue.move(), false);
1596 }
1597 
1599  if (err != ErrorCode::NO_ERROR) {
1600  LOG(ERROR) << "Connection error " << getErrorCodeString(err)
1601  << " with ingress=";
1602  VLOG(3) << IOBufPrinter::printHexFolly(buf, true);
1603  if (callback_) {
1604  std::string errorDescription = goawayErrorMessage_.empty() ?
1605  "Connection error" : goawayErrorMessage_;
1607  errorDescription);
1608  ex.setCodecStatusCode(err);
1609  callback_->onError(0, ex, false);
1610  }
1611  return true;
1612  }
1613  return false;
1614 }
1615 
1617  bool newTxn) {
1619  msg);
1620  error.setCodecStatusCode(code);
1621  if (callback_) {
1622  callback_->onError(curHeader_.stream, error, newTxn);
1623  }
1624 }
1625 
1628  // If the priority is out of the maximum index of virtual nodes array, we
1629  // return the lowest level virtual node as a punishment of not setting
1630  // priority correctly.
1631  return virtualPriorityNodes_.empty()
1632  ? 0
1634  std::min(priority, uint8_t(virtualPriorityNodes_.size() - 1))];
1635 }
1636 
1638  // HEADERS frame is used for request/response headers and trailers.
1639  // Per spec, specific role of HEADERS frame is determined by it's postion
1640  // within the stream. We don't keep full stream state in this codec,
1641  // thus using heuristics to distinguish between headers/trailers.
1642  // For DOWNSTREAM case, request headers HEADERS frame would be creating
1643  // new stream, thus HEADERS on existing stream ID are considered trailers
1644  // (see checkNewStream).
1645  // For UPSTREAM case, response headers are required to have status code,
1646  // thus if no status code we consider that trailers.
1651  } else {
1652  return !decodeInfo_.hasStatus();
1653  }
1654  }
1655  return false;
1656 }
1657 }
size_t addPriorityNodes(PriorityQueue &queue, folly::IOBufQueue &writeBuf, uint8_t maxLevel) override
Definition: HTTP2Codec.cpp:670
void * ptr
const uint32_t kMaxAuthenticatorBufSize
#define FOLLY_SCOPED_TRACE_SECTION(arg,...)
std::unique_ptr< folly::IOBuf > split(size_t n)
Definition: IOBufQueue.h:420
static std::vector< compress::Header > prepareMessageForCompression(const HTTPMessage &msg, std::vector< std::string > &temps)
Definition: CodecUtil.cpp:82
ErrorCode parseContinuation(Cursor &cursor, const FrameHeader &header, std::unique_ptr< IOBuf > &outBuf) noexcept
void generateContinuation(folly::IOBufQueue &writeBuf, folly::IOBufQueue &queue, StreamID stream, size_t maxFrameSize)
ErrorCode parseFrame(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:163
ErrorCode parseDataFrameData(folly::io::Cursor &cursor, size_t bufLen, size_t &parsed)
Definition: HTTP2Codec.cpp:299
const folly::IOBuf * front() const
Definition: IOBufQueue.h:476
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
ErrorCode parsePushPromise(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:817
bool onIngressUpgradeMessage(const HTTPMessage &msg) override
size_t chainLength() const
Definition: IOBufQueue.h:492
spdy::GoawayStatusCode statusCode
Definition: SPDYCodec.cpp:110
static std::string urlEncode(folly::ByteRange buffer)
Definition: Base64.cpp:107
size_t writePing(IOBufQueue &queue, uint64_t opaqueData, bool ack) noexcept
void setDecoderHeaderTableMaxSize(uint32_t size)
Definition: HPACKCodec.h:58
std::unique_ptr< folly::IOBuf > splitAtMost(size_t n)
Definition: IOBufQueue.h:428
virtual void onError(StreamID stream, const HTTPException &error, bool newTxn=false)=0
ErrorCode parsePushPromise(Cursor &cursor, const FrameHeader &header, uint32_t &outPromisedStream, std::unique_ptr< IOBuf > &outBuf) noexcept
virtual void onMessageBegin(StreamID stream, HTTPMessage *msg)=0
folly::IOBufQueue curHeaderBlock_
Definition: HTTP2Codec.h:254
FrameState frameState_
Definition: HTTP2Codec.h:276
ErrorCode parseFrameHeader(Cursor &cursor, FrameHeader &header) noexcept
const uint32_t kFramePrioritySize
bool empty() const
Definition: IOBuf.cpp:482
void decodeStreaming(folly::io::Cursor &cursor, uint32_t length, HPACK::StreamingCallback *streamingCb) noexcept
Definition: HPACKCodec.cpp:67
http2::FrameType headerBlockFrameType_
Definition: HTTP2Codec.h:296
ErrorCode parseWindowUpdate(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:898
HTTP2Codec(TransportDirection direction)
Definition: HTTP2Codec.cpp:42
HTTPSettings ingressSettings_
Definition: HTTP2Codec.h:255
ErrorCode parseContinuation(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:413
ErrorCode parseCertificateRequest(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:931
ErrorCode parseGoaway(Cursor &cursor, const FrameHeader &header, uint32_t &outLastStreamID, ErrorCode &outCode, std::unique_ptr< IOBuf > &outDebugData) noexcept
ErrorCode parseCertificate(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:945
static std::string printHexFolly(const folly::IOBuf *buf, bool coalesce=false)
Definition: Logging.h:127
bool deliverCallbackIfAllowed(T callbackFn, char const *cbName, StreamID stream, Args &&...args)
LogLevel max
Definition: LogLevel.cpp:31
static std::string urlDecode(const std::string &b64message)
Definition: Base64.cpp:26
const std::string * getUpgradeProtocol() const
Definition: HTTPMessage.h:378
virtual void onSettings(const SettingsList &)
Definition: HTTPCodec.h:251
const char * getTransportDirectionString(TransportDirection dir)
virtual void onExMessageBegin(StreamID, StreamID, bool, HTTPMessage *)
Definition: HTTPCodec.h:107
virtual void onGenerateFrameHeader(StreamID, uint8_t, uint64_t, uint16_t=0)
Definition: HTTPCodec.h:283
HTTPCodec::Callback * callback_
const uint32_t kFrameHeaderSize
ErrorCode parseHeadersImpl(folly::io::Cursor &cursor, std::unique_ptr< folly::IOBuf > headerBuf, const folly::Optional< http2::PriorityUpdate > &priority, const folly::Optional< uint32_t > &promisedStream, const folly::Optional< ExAttributes > &exAttributes)
Definition: HTTP2Codec.cpp:424
HTTPSettings egressSettings_
Definition: HTTP2Codec.h:260
size_t generatePingReply(folly::IOBufQueue &writeBuf, uint64_t uniqueID) override
const std::string kProtocolCleartextString
StreamCodecFactory stream
void generatePushPromise(folly::IOBufQueue &writeBuf, StreamID stream, const HTTPMessage &msg, StreamID assocStream, bool eom=false, HTTPHeaderSize *size=nullptr) override
void setEncoderHeaderTableSize(uint32_t size)
Definition: HPACKCodec.h:54
bool isInitiatedStream(StreamID stream) const
virtual void onMessageComplete(StreamID stream, bool upgrade)=0
void setIngressWebsocketUpgrade()
Definition: HTTPMessage.h:63
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
void clone(std::unique_ptr< folly::IOBuf > &buf, size_t len)
Definition: Cursor.h:456
size_t generatePingRequest(folly::IOBufQueue &writeBuf) override
const std::string kProtocolString
void onHeader(const folly::fbstring &name, const folly::fbstring &value) override
Definition: HTTP2Codec.cpp:606
ErrorCode parseGoaway(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:869
uint16_t getStatusCode() const
PskType type
virtual void onPingReply(uint64_t)
Definition: HTTPCodec.h:237
void generateExHeader(folly::IOBufQueue &writeBuf, StreamID stream, const HTTPMessage &msg, const HTTPCodec::ExAttributes &exAttributes, bool eom=false, HTTPHeaderSize *size=nullptr) override
std::unique_ptr< HTTPMessage > msg
size_t onIngress(const folly::IOBuf &buf) override
Definition: HTTP2Codec.cpp:70
void generateHeaderImpl(folly::IOBufQueue &writeBuf, StreamID stream, const HTTPMessage &msg, const folly::Optional< StreamID > &assocStream, const folly::Optional< ExAttributes > &exAttributes, bool eom, HTTPHeaderSize *size)
virtual void onTrailersComplete(StreamID stream, std::unique_ptr< HTTPHeaders > trailers)=0
folly::Optional< ErrorCode > parseHeadersDecodeFrames(const folly::Optional< http2::PriorityUpdate > &priority, const folly::Optional< uint32_t > &promisedStream, const folly::Optional< ExAttributes > &exAttributes, std::unique_ptr< HTTPMessage > &msg)
Definition: HTTP2Codec.cpp:507
bool empty() const
Definition: IOBufQueue.h:503
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
ErrorCode parsePriority(Cursor &cursor, const FrameHeader &header, PriorityUpdate &outPriority) noexcept
ErrorCode parseSettings(Cursor &cursor, const FrameHeader &header, std::deque< SettingPair > &settings) noexcept
virtual void onCertificate(uint16_t, std::unique_ptr< folly::IOBuf >)
Definition: HTTPCodec.h:310
virtual void onCertificateRequest(uint16_t, std::unique_ptr< folly::IOBuf >)
Definition: HTTPCodec.h:297
std::unordered_set< StreamID > upgradedStreams_
Definition: HTTP2Codec.h:248
ErrorCode errorCodeToGoaway(ErrorCode code)
const uint8_t * data() const
Definition: IOBuf.h:499
const uint32_t kMaxFramePayloadLength
size_t writePushPromise(IOBufQueue &queue, uint32_t associatedStream, uint32_t promisedStream, std::unique_ptr< IOBuf > headers, folly::Optional< uint8_t > padding, bool endHeaders) noexcept
size_t getNumberOfValues(HTTPHeaderCode code) const
std::unique_ptr< folly::IOBuf > move()
Definition: IOBufQueue.h:459
void generateHeader(folly::IOBufQueue &writeBuf, StreamID stream, const HTTPMessage &msg, bool eom=false, HTTPHeaderSize *size=nullptr) override
size_t generateRstStream(folly::IOBufQueue &writeBuf, StreamID stream, ErrorCode statusCode) override
virtual void onPriority(StreamID, const HTTPMessage::HTTPPriority &)
Definition: HTTPCodec.h:263
static http_parser_settings settings
Definition: test.c:1529
ErrorCode checkNewStream(uint32_t stream, bool trailersAllowed)
Definition: HTTP2Codec.cpp:973
ErrorCode parseAllData(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:281
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void setCodecStatusCode(ErrorCode statusCode)
Definition: HTTPException.h:98
size_t generateCertificate(folly::IOBufQueue &writeBuf, uint16_t certId, std::unique_ptr< folly::IOBuf > certData) override
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
tuple make_tuple()
Definition: gtest-tuple.h:675
size_t generateEOM(folly::IOBufQueue &writeBuf, StreamID stream) override
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
HPACK::DecodeError decodeError
ErrorCode parseCertificateRequest(folly::io::Cursor &cursor, const FrameHeader &header, uint16_t &outRequestId, std::unique_ptr< folly::IOBuf > &outAuthRequest) noexcept
bool frameHasPadding(const FrameHeader &header)
size_t generateBody(folly::IOBufQueue &writeBuf, StreamID stream, std::unique_ptr< folly::IOBuf > chain, folly::Optional< uint8_t > padding, bool eom) override
size_t writeSettings(IOBufQueue &queue, const std::deque< SettingPair > &settings)
HPACKCodec headerCodec_
Definition: HTTP2Codec.h:240
const uint32_t kMaxWindowUpdateSize
size_t generatePriority(folly::IOBufQueue &writeBuf, StreamID stream, const HTTPMessage::HTTPPriority &pri) override
void setEncodeHeadroom(uint32_t headroom)
Definition: HeaderCodec.h:69
std::string readFixedString(size_t len)
Definition: Cursor.h:309
size_t pendingDataFrameBytes_
Definition: HTTP2Codec.h:279
size_t maxSendFrameSize() const
Definition: HTTP2Codec.h:229
Gen range(Value begin, Value end)
Definition: Base.h:467
static void requestUpgrade(HTTPMessage &request)
HTTPCodec::StreamID mapPriorityToDependency(uint8_t priority) const override
const char * name
Definition: http_parser.c:437
bool pendingEndStreamHandling_
Definition: HTTP2Codec.h:245
bool onIngressUpgradeMessage(const HTTPMessage &msg) override
void set(folly::StringPiece name, const std::string &value)
Definition: HTTPHeaders.h:119
const uint32_t kMaxFramePayloadLengthMin
size_t generateSettingsAck(folly::IOBufQueue &writeBuf) override
uint32_t maxRecvFrameSize() const
Definition: HTTP2Codec.h:233
folly::Optional< ErrorCode > parseHeadersCheckConcurrentStreams(const folly::Optional< http2::PriorityUpdate > &priority)
Definition: HTTP2Codec.cpp:585
ErrorCode handleSettings(const std::deque< SettingPair > &settings)
Definition: HTTP2Codec.cpp:721
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
const uint32_t kMaxHeaderTableSize
bool checkForHeaderToken(const HTTPHeaderCode headerCode, char const *token, bool caseSensitive) const
enum proxygen::HTTPParallelCodec::ClosingState sessionClosing_
virtual void onPingRequest(uint64_t)
Definition: HTTPCodec.h:230
void writeBuf(const Buf &buf, folly::io::Appender &out)
virtual uint32_t numIncomingStreams() const
Definition: HTTPCodec.h:327
LogLevel min
Definition: LogLevel.cpp:30
size_t generateConnectionPreface(folly::IOBufQueue &writeBuf) override
ErrorCode parseExHeaders(Cursor &cursor, const FrameHeader &header, HTTPCodec::ExAttributes &outExAttributes, folly::Optional< PriorityUpdate > &outPriority, std::unique_ptr< IOBuf > &outBuf) noexcept
bool onHeader(const folly::fbstring &name, const folly::fbstring &value)
ErrorCode errorCodeToReset(ErrorCode code)
virtual void addPriorityNode(StreamID id, StreamID parent)=0
size_t writePriority(IOBufQueue &queue, uint32_t stream, PriorityUpdate priority) noexcept
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
virtual void onFrameHeader(StreamID, uint8_t, uint64_t, uint8_t, uint16_t=0)
Definition: HTTPCodec.h:206
void onDecodeError(HPACK::DecodeError decodeError) override
Definition: HTTP2Codec.cpp:646
std::size_t length() const
Definition: IOBuf.h:533
std::basic_string< E, T, A > toStdString() const
Definition: FBString.h:1227
size_t generateGoaway(folly::IOBufQueue &writeBuf, StreamID lastStream, ErrorCode statusCode, std::unique_ptr< folly::IOBuf > debugData=nullptr) override
HeaderDecodeInfo decodeInfo_
Definition: HTTP2Codec.h:282
ErrorCode parseCertificate(folly::io::Cursor &cursor, const FrameHeader &header, uint16_t &outCertId, std::unique_ptr< folly::IOBuf > &outAuthenticator) noexcept
const uint32_t kFrameHeadersBaseMaxSize
const char * getErrorCodeString(ErrorCode error)
Definition: ErrorCode.cpp:18
std::vector< StreamID > virtualPriorityNodes_
Definition: HTTP2Codec.h:283
ErrorCode parseDataBegin(Cursor &cursor, const FrameHeader &header, size_t &, uint16_t &outPadding) noexcept
StreamID createStream() override
folly::Optional< HTTPPriority > getHTTP2Priority() const
Definition: HTTPMessage.h:594
void forEach(LAMBDA func) const
Definition: HTTPHeaders.h:337
std::pair< SettingsId, uint32_t > SettingPair
Definition: SettingsId.h:58
static const char *const value
Definition: Conv.cpp:50
StreamID expectedContinuationStream_
Definition: HTTP2Codec.h:244
bool isStreamIngressEgressAllowed(StreamID stream) const
HTTPHeaders & getHeaders()
Definition: HTTPMessage.h:273
folly::IOBufQueue curAuthenticatorBlock_
Definition: HTTP2Codec.h:251
http2::FrameHeader curHeader_
Definition: HTTP2Codec.h:243
virtual void onSettingsAck()
Definition: HTTPCodec.h:257
ErrorCode parseExHeaders(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:395
const std::string & getSingleOrEmpty(const T &nameOrCode) const
Definition: HTTPHeaders.h:420
size_t generateHeaderCallbackWrapper(StreamID stream, http2::FrameType type, size_t length)
size_t writeCertificateRequest(folly::IOBufQueue &writeBuf, uint16_t requestId, std::unique_ptr< folly::IOBuf > authRequest)
const std::string kProtocolSettingsHeader
ErrorCode parseHeaders(Cursor &cursor, const FrameHeader &header, folly::Optional< PriorityUpdate > &outPriority, std::unique_ptr< IOBuf > &outBuf) noexcept
size_t writeSettingsAck(IOBufQueue &queue)
size_t size() const
size_t writeRstStream(IOBufQueue &queue, uint32_t stream, ErrorCode errorCode) noexcept
std::tuple< uint32_t, bool, uint8_t > HTTPPriority
Definition: HTTPMessage.h:592
size_t generateTrailers(folly::IOBufQueue &writeBuf, StreamID stream, const HTTPHeaders &trailers) override
uint64_t receivedFrameCount_
Definition: HTTP2Codec.h:267
bool reuseIOBufHeadroomForData_
Definition: HTTP2Codec.h:284
~HTTP2Codec() override
Definition: HTTP2Codec.cpp:66
FOLLY_NODISCARD detail::ScopeGuardImplDecay< F, true > makeGuard(F &&f) noexcept(noexcept(detail::ScopeGuardImplDecay< F, true >(static_cast< F && >(f))))
Definition: ScopeGuard.h:184
void streamError(const std::string &msg, ErrorCode error, bool newTxn=false)
bool parsingDownstreamTrailers_
Definition: HTTP2Codec.h:292
virtual void onHeadersComplete(StreamID stream, std::unique_ptr< HTTPMessage > msg)=0
const std::string empty_string
Definition: HTTPHeaders.cpp:23
std::vector< HTTPSetting > SettingsList
Definition: HTTPSettings.h:81
virtual void onGoaway(uint64_t, ErrorCode, std::unique_ptr< folly::IOBuf >=nullptr)
Definition: HTTPCodec.h:220
std::unique_ptr< folly::IOBuf > encodeHeaders(const HTTPHeaders &headers, std::vector< compress::Header > &allHeaders, HTTPHeaderSize *size)
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 std::vector< HTTPSetting > & getAllSettings()
Definition: HTTPSettings.h:61
size_t pendingDataFramePaddingBytes_
Definition: HTTP2Codec.h:280
bool checkConnectionError(ErrorCode, const folly::IOBuf *buf)
virtual void onAbort(StreamID, ErrorCode)
Definition: HTTPCodec.h:192
void skip(size_t len)
Definition: Cursor.h:371
ErrorCode parseSettings(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:705
const char * string
Definition: Conv.cpp:212
size_t writeGoaway(IOBufQueue &queue, uint32_t lastStreamID, ErrorCode errorCode, std::unique_ptr< IOBuf > debugData) noexcept
size_t generateChunkHeader(folly::IOBufQueue &writeBuf, StreamID stream, size_t length) override
g_t g(f_t)
ErrorCode parseRstStream(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:686
size_t generateWindowUpdate(folly::IOBufQueue &writeBuf, StreamID stream, uint32_t delta) override
static bool appendHeaders(const HTTPHeaders &inputHeaders, std::vector< compress::Header > &headers, HTTPHeaderCode headerToCheck)
Definition: CodecUtil.cpp:131
const std::string kConnectionPreface
ErrorCode parsePriority(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:650
uint64_t StreamID
Definition: HTTPCodec.h:49
const Padding kNoPadding
Definition: HTTP2Framer.cpp:20
void onHeadersComplete(HTTPHeaderSize decodedSize) override
Definition: HTTP2Codec.cpp:618
bool isRequest() const
Definition: HTTPMessage.h:661
virtual void onWindowUpdate(StreamID, uint32_t)
Definition: HTTPCodec.h:243
void init(bool isRequestIn, bool isRequestTrailers)
bool frameAffectsCompression(FrameType t)
std::unique_ptr< folly::IOBuf > encode(std::vector< compress::Header > &headers) noexcept
Definition: HPACKCodec.cpp:48
folly::Optional< HTTPMethod > getMethod() const
#define RETURN_IF_ERROR(err)
Definition: ErrorCode.h:14
const char * getFrameTypeString(FrameType type)
static uint64_t rand64()
Definition: Random.h:263
virtual void onPushMessageBegin(StreamID, StreamID, HTTPMessage *)
Definition: HTTPCodec.h:95
TransportDirection transportDirection_
ErrorCode handleEndStream()
Definition: HTTP2Codec.cpp:252
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
ErrorCode parsePing(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:854
char c
virtual void onBody(StreamID stream, std::unique_ptr< folly::IOBuf > chain, uint16_t padding)=0
size_t writeWindowUpdate(IOBufQueue &queue, uint32_t stream, uint32_t amount) noexcept
const std::string kWebsocketString
const HTTPHeaderSize & getEncodedSize()
Definition: HeaderCodec.h:62
void onHeadersComplete(HTTPHeaderSize decodedSize)
std::string userAgent_
Definition: HTTP2Codec.h:277
size_t totalLength() const
Definition: Cursor.h:126
ErrorCode parseDataEnd(Cursor &cursor, const size_t bufLen, const size_t pendingDataFramePaddingBytes, size_t &toSkip) noexcept
bool isEgressWebsocketUpgrade() const
Definition: HTTPMessage.h:72
TransportDirection getTransportDirection() const override
folly::Function< void()> parent
Definition: AtFork.cpp:34
bool parsingTrailers() const
size_t generateChunkTerminator(folly::IOBufQueue &writeBuf, StreamID stream) override
void setMaxUncompressed(uint64_t maxUncompressed) override
Definition: HPACKCodec.h:64
size_t generateSettings(folly::IOBufQueue &writeBuf) override
constexpr None none
Definition: Optional.h:87
HTTPRequestVerifier verifier
ErrorCode parsePing(Cursor &cursor, const FrameHeader &header, uint64_t &outOpaqueData) noexcept
const HTTPSetting * getSetting(SettingsId id) const
size_t generateCertificateRequest(folly::IOBufQueue &writeBuf, uint16_t requestId, std::unique_ptr< folly::IOBuf > certificateRequestData) override
ErrorCode parseHeaders(folly::io::Cursor &cursor)
Definition: HTTP2Codec.cpp:378
void setSetting(SettingsId id, SettingsValue val)
bool isRequest(StreamID id) const
Definition: HTTP2Codec.h:138