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 <bitset> 12 #include <deque> 13 #include <folly/Optional.h> 14 #include <proxygen/lib/http/HTTPHeaders.h> 15 #include <proxygen/lib/http/codec/HTTPCodec.h> 16 #include <proxygen/lib/http/codec/HTTPSettings.h> 17 #include <proxygen/lib/http/codec/compress/HeaderCodec.h> 18 #include <zlib.h> 19 20 namespace folly { namespace io { 21 class Cursor; 22 }} // namespace folly::io 23 24 namespace proxygen { 25 26 /** 27 * An implementation of common codec functionality used for multiple 28 * parallel stream downloads. Currently shared by SPDY and HTTP/2 29 */ 30 class HTTPParallelCodec : public HTTPCodec { 31 public: 32 explicit HTTPParallelCodec(TransportDirection direction); 33 getTransportDirection()34 TransportDirection getTransportDirection() const override { 35 return transportDirection_; 36 } 37 38 StreamID createStream() override; isBusy()39 bool isBusy() const override { 40 return false; 41 } supportsStreamFlowControl()42 bool supportsStreamFlowControl() const override { 43 return true; 44 } supportsSessionFlowControl()45 bool supportsSessionFlowControl() const override { 46 return true; 47 } supportsParallelRequests()48 bool supportsParallelRequests() const override { 49 return true; 50 } closeOnEgressComplete()51 bool closeOnEgressComplete() const override { 52 return false; 53 } setCallback(Callback * callback)54 void setCallback(Callback* callback) override { 55 callback_ = callback; 56 } setParserPaused(bool)57 void setParserPaused(bool /* paused */) override { 58 } isParserPaused()59 bool isParserPaused() const override { 60 return false; 61 } onIngressEOF()62 void onIngressEOF() override { 63 } 64 bool isReusable() const override; 65 bool isWaitingToDrain() const override; getLastIncomingStreamID()66 StreamID getLastIncomingStreamID() const override { 67 return lastStreamID_; 68 } 69 void enableDoubleGoawayDrain() override; 70 71 bool onIngressUpgradeMessage(const HTTPMessage& msg) override; 72 setNextEgressStreamId(StreamID nextEgressStreamID)73 void setNextEgressStreamId(StreamID nextEgressStreamID) { 74 if (nextEgressStreamID > nextEgressStreamID_ && 75 (nextEgressStreamID & 0x1) == (nextEgressStreamID_ & 0x1) && 76 nextEgressStreamID_ < std::numeric_limits<int32_t>::max()) { 77 nextEgressStreamID_ = nextEgressStreamID; 78 } 79 } 80 isInitiatedStream(StreamID stream)81 bool isInitiatedStream(StreamID stream) const { 82 return isInitiatedStream(transportDirection_, stream); 83 } 84 isInitiatedStream(TransportDirection direction,StreamID stream)85 static bool isInitiatedStream(TransportDirection direction, StreamID stream) { 86 bool odd = stream & 0x01; 87 bool upstream = (direction == TransportDirection::UPSTREAM); 88 return (odd && upstream) || (!odd && !upstream); 89 } 90 isStreamIngressEgressAllowed(StreamID stream)91 bool isStreamIngressEgressAllowed(StreamID stream) const { 92 bool isInitiated = isInitiatedStream(stream); 93 return (isInitiated && stream <= ingressGoawayAck_) || 94 (!isInitiated && stream <= egressGoawayAck_); 95 } 96 97 protected: 98 TransportDirection transportDirection_; 99 StreamID nextEgressStreamID_; 100 StreamID lastStreamID_{0}; 101 HTTPCodec::Callback* callback_{nullptr}; 102 StreamID ingressGoawayAck_{std::numeric_limits<uint32_t>::max()}; 103 StreamID egressGoawayAck_{std::numeric_limits<uint32_t>::max()}; 104 std::string goawayErrorMessage_; 105 106 enum ClosingState { 107 OPEN = 0, 108 OPEN_WITH_GRACEFUL_DRAIN_ENABLED = 1, 109 FIRST_GOAWAY_SENT = 2, 110 CLOSING = 3, // SPDY only 111 CLOSED = 4 // HTTP2 only 112 } sessionClosing_; 113 114 template <typename T, typename... Args> deliverCallbackIfAllowed(T callbackFn,char const * cbName,StreamID stream,Args &&...args)115 bool deliverCallbackIfAllowed(T callbackFn, 116 char const* cbName, 117 StreamID stream, 118 Args&&... args) { 119 if (isStreamIngressEgressAllowed(stream)) { 120 if (callback_) { 121 (*callback_.*callbackFn)(stream, std::forward<Args>(args)...); 122 } 123 return true; 124 } else { 125 VLOG(2) << "Suppressing " << cbName << " for stream=" << stream 126 << " egressGoawayAck_=" << egressGoawayAck_; 127 } 128 return false; 129 } 130 }; 131 } // namespace proxygen 132