1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 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. 7 */ 8 9 #pragma once 10 11 #include <proxygen/lib/http/codec/HQFramedCodec.h> 12 #include <proxygen/lib/http/codec/HQFramer.h> 13 #include <proxygen/lib/http/codec/HQUnidirectionalCodec.h> 14 #include <proxygen/lib/http/codec/HQUtils.h> 15 #include <proxygen/lib/http/codec/HTTPCodec.h> 16 #include <proxygen/lib/http/codec/compress/QPACKCodec.h> 17 18 #include <folly/io/IOBuf.h> 19 #include <folly/lang/Assume.h> 20 21 namespace proxygen { namespace hq { 22 23 class HQControlCodec 24 : public HQUnidirectionalCodec 25 , public HQFramedCodec { 26 27 public: 28 HQControlCodec( 29 HTTPCodec::StreamID streamId, 30 TransportDirection direction, 31 StreamDirection streamDir, 32 HTTPSettings& settings, 33 UnidirectionalStreamType streamType = UnidirectionalStreamType::CONTROL) HQUnidirectionalCodec(streamType,streamDir)34 : HQUnidirectionalCodec(streamType, streamDir), 35 HQFramedCodec(streamId, direction), 36 settings_(settings) { 37 VLOG(4) << "creating " << getTransportDirectionString(direction) 38 << " HQ Control codec for stream " << streamId_; 39 egressGoawayAck_ = direction == TransportDirection::UPSTREAM 40 ? kMaxPushId + 1 41 : kMaxClientBidiStreamId; 42 } 43 ~HQControlCodec()44 ~HQControlCodec() override { 45 } 46 47 // HQ Unidirectional Codec API onUnidirectionalIngress(std::unique_ptr<folly::IOBuf> buf)48 std::unique_ptr<folly::IOBuf> onUnidirectionalIngress( 49 std::unique_ptr<folly::IOBuf> buf) override { 50 CHECK(buf); 51 auto consumed = onFramedIngress(*buf); 52 folly::IOBufQueue q; 53 q.append(std::move(buf)); 54 q.trimStart(consumed); 55 return q.move(); 56 } 57 onUnidirectionalIngressEOF()58 void onUnidirectionalIngressEOF() override { 59 LOG(ERROR) << "Unexpected control stream EOF"; 60 if (callback_) { 61 HTTPException ex(HTTPException::Direction::INGRESS_AND_EGRESS, 62 "Control stream EOF"); 63 ex.setHttp3ErrorCode(HTTP3::ErrorCode::HTTP_CLOSED_CRITICAL_STREAM); 64 callback_->onError(streamId_, ex, false); 65 } 66 } 67 68 // HTTPCodec API 69 bool isWaitingToDrain() const override; 70 getProtocol()71 CodecProtocol getProtocol() const override { 72 return CodecProtocol::HQ; 73 } 74 onIngress(const folly::IOBuf &)75 size_t onIngress(const folly::IOBuf& /*buf*/) override { 76 LOG(FATAL) << __func__ << " not supported"; 77 folly::assume_unreachable(); 78 } 79 onIngressEOF()80 void onIngressEOF() override { 81 // error 82 } 83 84 size_t generateGoaway( 85 folly::IOBufQueue& writeBuf, 86 StreamID lastStream, 87 ErrorCode statusCode, 88 std::unique_ptr<folly::IOBuf> debugData = nullptr) override; 89 90 size_t generateSettings(folly::IOBufQueue& writeBuf) override; 91 92 size_t generatePriority(folly::IOBufQueue& writeBuf, 93 StreamID stream, 94 const HTTPMessage::HTTP2Priority& pri) override; 95 96 size_t generatePriority(folly::IOBufQueue& writeBuf, 97 StreamID stream, 98 HTTPPriority priority) override; 99 100 size_t generatePushPriority(folly::IOBufQueue& writeBuf, 101 StreamID pushId, 102 HTTPPriority priority) override; 103 getIngressSettings()104 const HTTPSettings* getIngressSettings() const override { 105 CHECK(isIngress()); 106 return &settings_; 107 } 108 getEgressSettings()109 HTTPSettings* getEgressSettings() override { 110 CHECK(isEgress()); 111 return &settings_; 112 } 113 enableDoubleGoawayDrain()114 void enableDoubleGoawayDrain() override { 115 doubleGoaway_ = true; 116 } 117 getDefaultWindowSize()118 uint32_t getDefaultWindowSize() const override { 119 CHECK(false) << __func__ << " not supported"; 120 folly::assume_unreachable(); 121 } 122 setHeaderCodecStats(HeaderCodec::Stats *)123 void setHeaderCodecStats(HeaderCodec::Stats* /*hcStats*/) override { 124 CHECK(false) << __func__ << " not supported"; 125 } 126 getCompressionInfo()127 CompressionInfo getCompressionInfo() const override { 128 CHECK(false) << __func__ << " not supported"; 129 folly::assume_unreachable(); 130 } 131 132 size_t addPriorityNodes(PriorityQueue& queue, 133 folly::IOBufQueue& writeBuf, 134 uint8_t maxLevel) override; 135 136 HTTPCodec::StreamID mapPriorityToDependency(uint8_t priority) const override; 137 138 protected: 139 ParseResult checkFrameAllowed(FrameType type) override; 140 ParseResult parseCancelPush(folly::io::Cursor& cursor, 141 const FrameHeader& header) override; 142 ParseResult parseSettings(folly::io::Cursor& cursor, 143 const FrameHeader& header) override; 144 ParseResult parseGoaway(folly::io::Cursor& cursor, 145 const FrameHeader& header) override; 146 ParseResult parseMaxPushId(folly::io::Cursor& cursor, 147 const FrameHeader& header) override; 148 ParseResult parsePriorityUpdate(folly::io::Cursor& cursor, 149 const FrameHeader& header) override; 150 ParseResult parsePushPriorityUpdate(folly::io::Cursor& cursor, 151 const FrameHeader& header) override; 152 153 uint64_t finalGoawayId(); 154 155 protected: 156 bool doubleGoaway_{true}; 157 bool sentGoaway_{false}; 158 bool sentFinalGoaway_{false}; 159 bool receivedSettings_{false}; 160 bool sentSettings_{false}; 161 quic::StreamId egressGoawayAck_; 162 quic::StreamId minUnseenStreamID_{kMaxClientBidiStreamId}; 163 uint64_t minUnseenPushID_{kMaxPushId + 1}; 164 HTTPSettings& settings_; 165 }; 166 167 }} // namespace proxygen::hq 168