15 using namespace folly;
17 namespace proxygen {
namespace http2 {
25 const uint32_t kLengthMask = 0x00ffffff;
26 const uint32_t kUint31Mask = 0x7fffffff;
28 static const uint64_t kZeroPad[32] = {0};
30 static const bool kStrictPadding =
true;
32 static_assert(
sizeof(kZeroPad) == 256,
"bad zero padding");
38 DCHECK_EQ(0, ~kUint31Mask & streamDependency);
41 streamDependency |= ~kUint31Mask;
49 if (size && *size > 0) {
51 memset(out.first, 0, *size);
68 std::unique_ptr<IOBuf> payload,
69 bool reuseIOBufHeadroom =
true)
noexcept {
73 DCHECK_EQ(0, ~kLengthMask & length);
74 DCHECK_EQ(0, ~kUint31Mask & stream);
84 DCHECK_EQ(0, ~kLengthMask & length);
85 DCHECK_NE(priority->streamDependency, stream) <<
"Circular dependecy";
92 FrameType::EX_HEADERS == type ||
93 FrameType::DATA == type ||
94 FrameType::PUSH_PROMISE == type);
95 length += *padding + 1;
101 DCHECK_EQ(0, ~kLengthMask & length);
104 ((kLengthMask & length) << 8) |
static_cast<uint8_t>(
type);
107 if (reuseIOBufHeadroom && payload && !payload->
isSharedOne() &&
108 payload->
headroom() >= headerSize &&
113 payloadLength = payload->
length();
114 payload->
trimEnd(payloadLength);
116 auto tail = payload->
pop();
129 writePriorityBody(appender,
130 priority->streamDependency,
150 return ErrorCode::PROTOCOL_ERROR;
153 return ErrorCode::NO_ERROR;
160 priority.
exclusive = ~kUint31Mask & streamAndExclusive;
178 parsePadding(
Cursor& cursor,
181 DCHECK(header.
type == FrameType::DATA ||
183 header.
type == FrameType::EX_HEADERS ||
184 header.
type == FrameType::PUSH_PROMISE);
185 lefttoparse = header.
length;
187 if (lefttoparse < 1) {
188 return ErrorCode::FRAME_SIZE_ERROR;
196 if (lefttoparse < padding) {
197 return ErrorCode::PROTOCOL_ERROR;
199 lefttoparse -= padding;
200 return ErrorCode::NO_ERROR;
205 skipPadding(
Cursor& cursor,
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;
221 return ErrorCode::NO_ERROR;
228 if (
val < kMinExperimentalFrameType) {
229 return val <= static_cast<uint8_t>(FrameType::ALTSVC);
232 case FrameType::EX_HEADERS:
235 case FrameType::CERTIFICATE_REQUEST:
236 case FrameType::CERTIFICATE:
246 t == FrameType::PUSH_PROMISE ||
247 t == FrameType::CONTINUATION;
262 header.length = kLengthMask & (lengthAndType >> 8);
265 header.flags = cursor.readBE<
uint8_t>();
266 header.stream = parseUint31(cursor);
267 return ErrorCode::NO_ERROR;
272 std::unique_ptr<IOBuf>& outBuf,
274 DCHECK_LE(header.length, cursor.totalLength());
275 if (header.stream == 0) {
276 return ErrorCode::PROTOCOL_ERROR;
281 const auto err = parsePadding(cursor, header, padding, lefttoparse);
286 cursor.clone(outBuf, lefttoparse);
287 return skipPadding(cursor, padding, kStrictPadding);
296 const auto err = http2::parsePadding(cursor, header, padding, lefttoparse);
301 return ErrorCode::NO_ERROR;
306 const size_t pendingDataFramePaddingBytes,
308 toSkip =
std::min(pendingDataFramePaddingBytes, bufLen);
309 return skipPadding(cursor, toSkip, kStrictPadding);
316 std::unique_ptr<IOBuf>& outBuf)
noexcept {
317 DCHECK_LE(header.length, cursor.totalLength());
318 if (header.stream == 0) {
319 return ErrorCode::PROTOCOL_ERROR;
323 auto err = parsePadding(cursor, header, padding, lefttoparse);
327 return ErrorCode::FRAME_SIZE_ERROR;
329 outPriority = parsePriorityCommon(cursor);
334 cursor.clone(outBuf, lefttoparse);
335 return skipPadding(cursor, padding, kStrictPadding);
343 std::unique_ptr<IOBuf>& outBuf)
noexcept {
344 DCHECK_LE(header.length, cursor.totalLength());
345 if (header.stream == 0) {
346 return ErrorCode::PROTOCOL_ERROR;
351 auto err = parsePadding(cursor, header, padding, lefttoparse);
357 return ErrorCode::FRAME_SIZE_ERROR;
359 outPriority = parsePriorityCommon(cursor);
367 return ErrorCode::FRAME_SIZE_ERROR;
369 outExAttributes.controlStream = parseUint31(cursor);
371 if (!(outExAttributes.controlStream & 0x1)) {
373 return ErrorCode::PROTOCOL_ERROR;
376 cursor.clone(outBuf, lefttoparse);
377 return skipPadding(cursor, padding, kStrictPadding);
384 DCHECK_LE(header.length, cursor.totalLength());
386 return ErrorCode::FRAME_SIZE_ERROR;
388 if (header.stream == 0) {
389 return ErrorCode::PROTOCOL_ERROR;
391 outPriority = parsePriorityCommon(cursor);
392 return ErrorCode::NO_ERROR;
399 DCHECK_LE(header.length, cursor.totalLength());
401 return ErrorCode::FRAME_SIZE_ERROR;
403 if (header.stream == 0) {
404 return ErrorCode::PROTOCOL_ERROR;
406 return parseErrorCode(cursor, outCode);
413 DCHECK_LE(header.length, cursor.totalLength());
414 if (header.stream != 0) {
415 return ErrorCode::PROTOCOL_ERROR;
417 if (header.flags &
ACK) {
418 if (header.length != 0) {
419 return ErrorCode::FRAME_SIZE_ERROR;
421 return ErrorCode::NO_ERROR;
424 if (header.length % 6 != 0) {
425 return ErrorCode::FRAME_SIZE_ERROR;
427 for (
auto length = header.length; length > 0; length -= 6) {
432 return ErrorCode::NO_ERROR;
439 std::unique_ptr<IOBuf>& outBuf)
noexcept {
440 DCHECK_LE(header.length, cursor.totalLength());
441 if (header.stream == 0) {
442 return ErrorCode::PROTOCOL_ERROR;
447 auto err = parsePadding(cursor, header, padding, lefttoparse);
450 return ErrorCode::FRAME_SIZE_ERROR;
453 outPromisedStream = parseUint31(cursor);
454 if (outPromisedStream == 0 ||
455 outPromisedStream & 0x1) {
457 return ErrorCode::PROTOCOL_ERROR;
459 if (lefttoparse < padding) {
460 return ErrorCode::PROTOCOL_ERROR;
462 cursor.clone(outBuf, lefttoparse);
463 return skipPadding(cursor, padding, kStrictPadding);
470 DCHECK_LE(header.length, cursor.totalLength());
473 return ErrorCode::FRAME_SIZE_ERROR;
475 if (header.stream != 0) {
476 return ErrorCode::PROTOCOL_ERROR;
479 cursor.pull(&outOpaqueData,
sizeof(outOpaqueData));
480 return ErrorCode::NO_ERROR;
488 std::unique_ptr<IOBuf>& outDebugData)
noexcept {
489 DCHECK_LE(header.length, cursor.totalLength());
491 return ErrorCode::FRAME_SIZE_ERROR;
493 if (header.stream != 0) {
494 return ErrorCode::PROTOCOL_ERROR;
496 outLastStreamID = parseUint31(cursor);
497 auto err = parseErrorCode(cursor, outCode);
499 auto length = header.length;
502 cursor.clone(outDebugData, length);
504 return ErrorCode::NO_ERROR;
511 DCHECK_LE(header.length, cursor.totalLength());
513 return ErrorCode::FRAME_SIZE_ERROR;
515 outAmount = parseUint31(cursor);
516 return ErrorCode::NO_ERROR;
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;
528 cursor.clone(outBuf, header.length);
529 return ErrorCode::NO_ERROR;
540 DCHECK_LE(header.length, cursor.totalLength());
542 return ErrorCode::FRAME_SIZE_ERROR;
544 std::unique_ptr<IOBuf> tmpBuf;
546 outMaxAge = cursor.readBE<
uint32_t>();
547 outPort = cursor.readBE<
uint16_t>();
548 const auto protoLen = cursor.readBE<
uint8_t>();
550 return ErrorCode::FRAME_SIZE_ERROR;
552 outProtocol = cursor.readFixedString(protoLen);
553 const auto hostLen = cursor.readBE<
uint8_t>();
555 return ErrorCode::FRAME_SIZE_ERROR;
557 outHost = cursor.readFixedString(hostLen);
560 outOrigin = cursor.readFixedString(originLen);
562 return ErrorCode::NO_ERROR;
569 std::unique_ptr<folly::IOBuf>& outAuthRequest)
noexcept {
570 DCHECK_LE(header.length, cursor.totalLength());
572 return ErrorCode::FRAME_SIZE_ERROR;
574 if (header.stream != 0) {
575 return ErrorCode::PROTOCOL_ERROR;
577 outRequestId = cursor.readBE<
uint16_t>();
578 auto length = header.length;
581 cursor.clone(outAuthRequest, length);
583 return ErrorCode::NO_ERROR;
590 std::unique_ptr<folly::IOBuf>& outAuthenticator)
noexcept {
591 DCHECK_LE(header.length, cursor.totalLength());
593 return ErrorCode::FRAME_SIZE_ERROR;
595 if (header.stream != 0) {
596 return ErrorCode::PROTOCOL_ERROR;
598 outCertId = cursor.readBE<
uint16_t>();
599 auto length = header.length;
602 cursor.clone(outAuthenticator, length);
604 return ErrorCode::NO_ERROR;
611 std::unique_ptr<IOBuf>
data,
624 const auto frameLen = writeFrameHeader(queue,
633 writePadding(queue, padding);
639 std::unique_ptr<IOBuf> headers,
646 const auto dataLen = (headers) ? headers->computeChainDataLength() : 0;
658 const auto frameLen = writeFrameHeader(queue,
666 writePadding(queue, padding);
672 std::unique_ptr<IOBuf> headers,
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";
686 const auto dataLen = (headers) ? headers->computeChainDataLength() : 0;
697 if (exAttributes.unidirectional) {
701 const auto frameLen = writeFrameHeader(queue,
703 FrameType::EX_HEADERS,
712 writePadding(queue, padding);
721 const auto frameLen = writeFrameHeader(queue,
737 const auto frameLen = writeFrameHeader(queue,
752 const std::deque<SettingPair>&
settings) {
753 const auto settingsSize = settings.size() * 6;
754 const auto frameLen = writeFrameHeader(queue,
763 for (
const auto& setting: settings) {
764 DCHECK_LE(static_cast<uint32_t>(setting.first),
774 writeFrameHeader(queue,
789 std::unique_ptr<IOBuf> headers,
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);
798 const auto dataLen = headers->computeChainDataLength();
799 const auto frameLen = writeFrameHeader(queue,
801 FrameType::PUSH_PROMISE,
810 writePadding(queue, padding);
818 const auto frameLen = writeFrameHeader(queue,
826 queue.append(&opaqueData,
sizeof(opaqueData));
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,
856 const auto frameLen = writeFrameHeader(queue,
864 DCHECK_EQ(0, ~kUint31Mask & amount);
865 DCHECK_LT(0, amount);
875 std::unique_ptr<IOBuf> headers)
noexcept {
877 const auto dataLen = headers->computeChainDataLength();
878 const auto frameLen = writeFrameHeader(queue,
880 FrameType::CONTINUATION,
897 const auto protoLen = protocol.size();
898 const auto hostLen = host.size();
899 const auto originLen = origin.size();
902 writeFrameHeader(queue, frameLen, FrameType::ALTSVC, 0,
stream, kNoPadding,
908 appender.
push(reinterpret_cast<const uint8_t*>(protocol.data()), protoLen);
910 appender.
push(reinterpret_cast<const uint8_t*>(host.data()), hostLen);
911 appender.
push(reinterpret_cast<const uint8_t*>(origin.data()), originLen);
917 std::unique_ptr<folly::IOBuf> authRequest) {
922 const auto frameLen = writeFrameHeader(writeBuf,
924 FrameType::CERTIFICATE_REQUEST,
938 std::unique_ptr<folly::IOBuf> authenticator,
939 bool toBeContinued) {
949 const auto frameLen = writeFrameHeader(writeBuf,
951 FrameType::CERTIFICATE,
965 case FrameType::DATA:
return "DATA";
970 case FrameType::PUSH_PROMISE:
return "PUSH_PROMISE";
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";
982 LOG(
FATAL) <<
"Unreachable";
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)
constexpr size_t headerSize()
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
uint32_t streamDependency
ErrorCode parseGoaway(Cursor &cursor, const FrameHeader &header, uint32_t &outLastStreamID, ErrorCode &outCode, std::unique_ptr< IOBuf > &outDebugData) noexcept
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
constexpr detail::Map< Move > move
ErrorCode parsePriority(Cursor &cursor, const FrameHeader &header, PriorityUpdate &outPriority) noexcept
ErrorCode parseSettings(Cursor &cursor, const FrameHeader &header, std::deque< SettingPair > &settings) noexcept
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)
static http_parser_settings settings
—— Concurrent Priority Queue Implementation ——
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())
size_t writeSettings(IOBufQueue &queue, const std::deque< SettingPair > &settings)
const uint32_t kFrameCertificateSizeBase
std::pair< const uint8_t *, size_t > peek()
constexpr auto size(C const &c) -> decltype(c.size())
void writeBuf(const Buf &buf, folly::io::Appender &out)
std::unique_ptr< IOBuf > pop()
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
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())
std::size_t length() const
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)
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
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
const uint32_t kFramePushPromiseSize
std::size_t computeChainDataLength() const
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
size_t writeGoaway(IOBufQueue &queue, uint32_t lastStreamID, ErrorCode errorCode, std::unique_ptr< IOBuf > debugData) noexcept
bool isValidFrameType(FrameType type)
const uint32_t kFramePingSize
bool frameAffectsCompression(FrameType t)
#define RETURN_IF_ERROR(err)
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)
void trimEnd(std::size_t amount)
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
ErrorCode parsePing(Cursor &cursor, const FrameHeader &header, uint64_t &outOpaqueData) noexcept