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