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 <folly/IntrusiveList.h> 12 #include <proxygen/lib/http/ProxygenErrorEnum.h> 13 #include <proxygen/lib/http/connpool/Endpoint.h> 14 #include <proxygen/lib/http/session/HTTPSessionBase.h> 15 16 namespace proxygen { 17 18 class HTTPMessage; 19 20 /** 21 * This class is essentially an implementation detail for SessionPool. It 22 * encapsulates a single HTTPSessionBase and manages which list in the 23 * SessionPool it should be a part of. 24 */ 25 class SessionHolder : private HTTPSessionBase::InfoCallback { 26 public: 27 class Callback { 28 public: ~Callback()29 virtual ~Callback() { 30 } 31 virtual void detachIdle(SessionHolder*) = 0; 32 virtual void detachPartiallyFilled(SessionHolder*) = 0; 33 virtual void detachFilled(SessionHolder*) = 0; 34 virtual void attachIdle(SessionHolder*) = 0; 35 virtual void attachPartiallyFilled(SessionHolder*) = 0; 36 virtual void attachFilled(SessionHolder*) = 0; 37 virtual void addDrainingSession(HTTPSessionBase*) = 0; 38 }; 39 40 class Stats { 41 public: ~Stats()42 virtual ~Stats() { 43 } 44 virtual void onConnectionCreated() = 0; 45 virtual void onConnectionClosed() = 0; 46 virtual void onConnectionActivated() = 0; 47 virtual void onConnectionDeactivated() = 0; 48 virtual void onRead(size_t bytesRead) = 0; 49 virtual void onWrite(size_t bytesWritten) = 0; 50 }; 51 52 explicit SessionHolder(HTTPSessionBase*, 53 Callback*, 54 Stats* = nullptr, 55 Endpoint = Endpoint("", 0, false)); 56 ~SessionHolder() override; 57 release()58 HTTPSessionBase* release() { 59 if (listHook.is_linked()) { 60 unlink(); 61 } else { 62 state_ = ListState::DETACHED; 63 } 64 auto session = session_; 65 session->setInfoCallback(originalSessionInfoCb_); 66 session_ = nullptr; 67 delete this; 68 return session; 69 } 70 71 /** 72 * Returns true if the given session can be wrapped in a 73 * SessionHolder. This function does *not* imply that the session is 74 * or isn't idle. It returns true iff a SessionHolder can be constructed 75 * around it. 76 */ 77 static bool isPoolable(const HTTPSessionBase*); 78 79 const HTTPSessionBase& getSession() const; 80 HTTPTransaction* newTransaction(HTTPTransaction::Handler* upstreamHandler); 81 void drain(); 82 83 /** 84 * This will immediately delete the SessionHolder and the underlying session. 85 * When this function returns, the SessionHolder has been deleted. 86 */ 87 void closeWithReset(); 88 89 std::chrono::steady_clock::time_point getLastUseTime() const; 90 91 /** 92 * Unlink this session holder instance from the necessary session lists.. 93 * This is achieved by calling the SessionHolder::Callbacks. 94 */ 95 void unlink(); 96 97 /** 98 * Link this session holder instance to the necessary session lists. This is 99 * achieved by calling the SessionHolder::Callbacks. 100 */ 101 void link(); 102 103 bool shouldAgeOut(std::chrono::milliseconds maxAge) const; 104 void describe(std::ostream& os) const; 105 getEndpoint()106 Endpoint getEndpoint() { 107 return endpoint_; 108 } 109 110 friend std::ostream& operator<<(std::ostream& os, const SessionHolder& conn) { 111 conn.describe(os); 112 return os; 113 } 114 115 // HTTPSession::InfoCallback 116 void onCreate(const HTTPSessionBase&) override; 117 void onIngressError(const HTTPSessionBase&, ProxygenError) override; onIngressEOF()118 void onIngressEOF() override { 119 } 120 void onRead(const HTTPSessionBase&, size_t bytesRead) override; 121 void onRead(const HTTPSessionBase& sess, 122 size_t bytesRead, 123 folly::Optional<HTTPCodec::StreamID> /*stream id*/) override; 124 void onWrite(const HTTPSessionBase&, size_t bytesWritten) override; 125 void onRequestBegin(const HTTPSessionBase&) override; 126 void onRequestEnd(const HTTPSessionBase&, 127 uint32_t maxIngressQueueSize) override; 128 void onActivateConnection(const HTTPSessionBase&) override; 129 void onDeactivateConnection(const HTTPSessionBase&) override; 130 void onDestroy(const HTTPSessionBase&) override; 131 void onIngressMessage(const HTTPSessionBase&, const HTTPMessage&) override; 132 void onIngressLimitExceeded(const HTTPSessionBase&) override; 133 void onIngressPaused(const HTTPSessionBase&) override; 134 void onTransactionDetached(const HTTPSessionBase&) override; 135 void onPingReplySent(int64_t latency) override; 136 void onPingReplyReceived() override; 137 void onSettingsOutgoingStreamsFull(const HTTPSessionBase&) override; 138 void onSettingsOutgoingStreamsNotFull(const HTTPSessionBase&) override; 139 void onFlowControlWindowClosed(const HTTPSessionBase&) override; 140 void onEgressBuffered(const HTTPSessionBase&) override; 141 void onEgressBufferCleared(const HTTPSessionBase&) override; 142 void onSettings(const HTTPSessionBase&, const SettingsList&) override; 143 void onSettingsAck(const HTTPSessionBase&) override; 144 145 // Hook in the first session pool list. 146 folly::SafeIntrusiveListHook listHook; 147 148 // Hook in the second session pool list if necessary. 149 folly::SafeIntrusiveListHook secondaryListHook; 150 151 private: 152 void handleTransactionDetached(); 153 154 enum class ListState { 155 DETACHED = 0, 156 IDLE = 1, 157 PARTIAL = 2, 158 FULL = 3, 159 }; 160 161 HTTPSessionBase* session_; 162 Callback* parent_; 163 Stats* stats_; 164 std::chrono::steady_clock::time_point lastUseTime_; // init'd in link() 165 double jitter_; 166 ListState state_{ListState::DETACHED}; 167 Endpoint endpoint_; 168 HTTPSessionBase::InfoCallback* originalSessionInfoCb_; 169 }; 170 typedef folly::CountedIntrusiveList<SessionHolder, &SessionHolder::listHook> 171 SessionList; 172 173 typedef folly::CountedIntrusiveList<SessionHolder, 174 &SessionHolder::secondaryListHook> 175 SecondarySessionList; 176 } // namespace proxygen 177