1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef nsHttpConnection_h__ 7 #define nsHttpConnection_h__ 8 9 #include "HttpConnectionBase.h" 10 #include "nsHttpConnectionInfo.h" 11 #include "nsHttpResponseHead.h" 12 #include "nsAHttpTransaction.h" 13 #include "nsCOMPtr.h" 14 #include "nsProxyRelease.h" 15 #include "prinrval.h" 16 #include "TunnelUtils.h" 17 #include "mozilla/Mutex.h" 18 #include "ARefBase.h" 19 #include "TimingStruct.h" 20 #include "HttpTrafficAnalyzer.h" 21 22 #include "nsIAsyncInputStream.h" 23 #include "nsIAsyncOutputStream.h" 24 #include "nsIInterfaceRequestor.h" 25 #include "nsISupportsPriority.h" 26 #include "nsITimer.h" 27 28 class nsISocketTransport; 29 class nsISSLSocketControl; 30 31 namespace mozilla { 32 namespace net { 33 34 class nsHttpHandler; 35 class ASpdySession; 36 37 // 1dcc863e-db90-4652-a1fe-13fea0b54e46 38 #define NS_HTTPCONNECTION_IID \ 39 { \ 40 0x1dcc863e, 0xdb90, 0x4652, { \ 41 0xa1, 0xfe, 0x13, 0xfe, 0xa0, 0xb5, 0x4e, 0x46 \ 42 } \ 43 } 44 45 //----------------------------------------------------------------------------- 46 // nsHttpConnection - represents a connection to a HTTP server (or proxy) 47 // 48 // NOTE: this objects lives on the socket thread only. it should not be 49 // accessed from any other thread. 50 //----------------------------------------------------------------------------- 51 52 class nsHttpConnection final : public HttpConnectionBase, 53 public nsAHttpSegmentReader, 54 public nsAHttpSegmentWriter, 55 public nsIInputStreamCallback, 56 public nsIOutputStreamCallback, 57 public nsITransportEventSink, 58 public nsIInterfaceRequestor, 59 public NudgeTunnelCallback { 60 private: 61 virtual ~nsHttpConnection(); 62 63 public: 64 NS_DECLARE_STATIC_IID_ACCESSOR(NS_HTTPCONNECTION_IID) 65 NS_DECL_HTTPCONNECTIONBASE 66 NS_DECL_THREADSAFE_ISUPPORTS 67 NS_DECL_NSAHTTPSEGMENTREADER 68 NS_DECL_NSAHTTPSEGMENTWRITER 69 NS_DECL_NSIINPUTSTREAMCALLBACK 70 NS_DECL_NSIOUTPUTSTREAMCALLBACK 71 NS_DECL_NSITRANSPORTEVENTSINK 72 NS_DECL_NSIINTERFACEREQUESTOR 73 NS_DECL_NUDGETUNNELCALLBACK 74 75 nsHttpConnection(); 76 77 // Initialize the connection: 78 // info - specifies the connection parameters. 79 // maxHangTime - limits the amount of time this connection can spend on a 80 // single transaction before it should no longer be kept 81 // alive. a value of 0xffff indicates no limit. 82 [[nodiscard]] virtual nsresult Init(nsHttpConnectionInfo* info, 83 uint16_t maxHangTime, nsISocketTransport*, 84 nsIAsyncInputStream*, 85 nsIAsyncOutputStream*, 86 bool connectedTransport, nsresult status, 87 nsIInterfaceRequestor*, PRIntervalTime, 88 bool forWebSocket); 89 90 //------------------------------------------------------------------------- 91 // XXX document when these are ok to call 92 IsKeepAlive()93 bool IsKeepAlive() { 94 return (mUsingSpdyVersion != SpdyVersion::NONE) || 95 (mKeepAliveMask && mKeepAlive); 96 } 97 98 // Returns time in seconds for how long connection can be reused. 99 uint32_t TimeToLive(); 100 NeedSpdyTunnel()101 bool NeedSpdyTunnel() { 102 return mConnInfo->UsingHttpsProxy() && !mTLSFilter && 103 mConnInfo->UsingConnect(); 104 } 105 106 // A connection is forced into plaintext when it is intended to be used as a 107 // CONNECT tunnel but the setup fails. The plaintext only carries the CONNECT 108 // error. ForcePlainText()109 void ForcePlainText() { mForcePlainText = true; } 110 IsUrgentStartPreferred()111 bool IsUrgentStartPreferred() const { 112 return mUrgentStartPreferredKnown && mUrgentStartPreferred; 113 } 114 void SetUrgentStartPreferred(bool urgent); 115 116 void SetIsReusedAfter(uint32_t afterMilliseconds); 117 MaxBytesRead()118 int64_t MaxBytesRead() { return mMaxBytesRead; } GetLastHttpResponseVersion()119 HttpVersion GetLastHttpResponseVersion() { return mLastHttpResponseVersion; } 120 121 friend class HttpConnectionForceIO; 122 123 [[nodiscard]] static nsresult ReadFromStream(nsIInputStream*, void*, 124 const char*, uint32_t, uint32_t, 125 uint32_t*); 126 127 // When a persistent connection is in the connection manager idle 128 // connection pool, the nsHttpConnection still reads errors and hangups 129 // on the socket so that it can be proactively released if the server 130 // initiates a termination. Only call on socket thread. 131 void BeginIdleMonitoring(); 132 void EndIdleMonitoring(); 133 UsingSpdy()134 bool UsingSpdy() override { return (mUsingSpdyVersion != SpdyVersion::NONE); } GetSpdyVersion()135 SpdyVersion GetSpdyVersion() { return mUsingSpdyVersion; } EverUsedSpdy()136 bool EverUsedSpdy() { return mEverUsedSpdy; } UsingHttp3()137 bool UsingHttp3() override { return false; } 138 139 // true when connection SSL NPN phase is complete and we know 140 // authoritatively whether UsingSpdy() or not. ReportedNPN()141 bool ReportedNPN() { return mReportedSpdy; } 142 143 // When the connection is active this is called up to once every 1 second 144 // return the interval (in seconds) that the connection next wants to 145 // have this invoked. It might happen sooner depending on the needs of 146 // other connections. 147 uint32_t ReadTimeoutTick(PRIntervalTime now); 148 149 // For Active and Idle connections, this will be called when 150 // mTCPKeepaliveTransitionTimer fires, to check if the TCP keepalive config 151 // should move from short-lived (fast-detect) to long-lived. 152 static void UpdateTCPKeepalive(nsITimer* aTimer, void* aClosure); 153 154 // When the connection is active this is called every second 155 void ReadTimeoutTick(); 156 ContentBytesWritten()157 int64_t ContentBytesWritten() { return mContentBytesWritten; } 158 159 [[nodiscard]] static nsresult MakeConnectString(nsAHttpTransaction* trans, 160 nsHttpRequestHead* request, 161 nsACString& result, 162 bool h2ws); 163 void SetupSecondaryTLS(nsAHttpTransaction* aSpdyConnectTransaction = nullptr); 164 void SetInSpdyTunnel(bool arg); 165 166 // Check active connections for traffic (or not). SPDY connections send a 167 // ping, ordinary HTTP connections get some time to get traffic to be 168 // considered alive. 169 void CheckForTraffic(bool check); 170 171 // NoTraffic() returns true if there's been no traffic on the (non-spdy) 172 // connection since CheckForTraffic() was called. NoTraffic()173 bool NoTraffic() { 174 return mTrafficStamp && 175 (mTrafficCount == (mTotalBytesWritten + mTotalBytesRead)); 176 } 177 178 // Return true when the socket this connection is using has not been 179 // authenticated using a client certificate. Before SSL negotiation 180 // has finished this returns false. 181 bool NoClientCertAuth() const override; 182 183 bool CanAcceptWebsocket() override; 184 BytesWritten()185 int64_t BytesWritten() override { return mTotalBytesWritten; } 186 Transport()187 nsISocketTransport* Transport() override { return mSocketTransport; } 188 189 nsresult GetSelfAddr(NetAddr* addr) override; 190 nsresult GetPeerAddr(NetAddr* addr) override; 191 bool ResolvedByTRR() override; 192 bool GetEchConfigUsed() override; 193 IsForWebSocket()194 bool IsForWebSocket() { return mForWebSocket; } 195 196 private: 197 // Value (set in mTCPKeepaliveConfig) indicates which set of prefs to use. 198 enum TCPKeepaliveConfig { 199 kTCPKeepaliveDisabled = 0, 200 kTCPKeepaliveShortLivedConfig, 201 kTCPKeepaliveLongLivedConfig 202 }; 203 204 // called to cause the underlying socket to start speaking SSL 205 [[nodiscard]] nsresult InitSSLParams(bool connectingToProxy, 206 bool ProxyStartSSL); 207 [[nodiscard]] nsresult SetupNPNList(nsISSLSocketControl* ssl, uint32_t caps); 208 209 [[nodiscard]] nsresult OnTransactionDone(nsresult reason); 210 [[nodiscard]] nsresult OnSocketWritable(); 211 [[nodiscard]] nsresult OnSocketReadable(); 212 213 [[nodiscard]] nsresult SetupProxyConnect(); 214 215 PRIntervalTime IdleTime(); 216 bool IsAlive(); 217 218 // Makes certain the SSL handshake is complete and NPN negotiation 219 // has had a chance to happen 220 [[nodiscard]] bool EnsureNPNComplete(nsresult& aOut0RTTWriteHandshakeValue, 221 uint32_t& aOut0RTTBytesWritten); 222 223 void SetupSSL(); 224 225 // Start the Spdy transaction handler when NPN indicates spdy/* 226 void StartSpdy(nsISSLSocketControl* ssl, SpdyVersion spdyVersion); 227 // Like the above, but do the bare minimum to do 0RTT data, so we can back 228 // it out, if necessary 229 void Start0RTTSpdy(SpdyVersion spdyVersion); 230 231 // Helpers for Start*Spdy 232 nsresult TryTakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction> >& list); 233 nsresult MoveTransactionsToSpdy(nsresult status, 234 nsTArray<RefPtr<nsAHttpTransaction> >& list); 235 236 // Directly Add a transaction to an active connection for SPDY 237 [[nodiscard]] nsresult AddTransaction(nsAHttpTransaction*, int32_t); 238 239 // Used to set TCP keepalives for fast detection of dead connections during 240 // an initial period, and slower detection for long-lived connections. 241 [[nodiscard]] nsresult StartShortLivedTCPKeepalives(); 242 [[nodiscard]] nsresult StartLongLivedTCPKeepalives(); 243 [[nodiscard]] nsresult DisableTCPKeepalives(); 244 245 bool CheckCanWrite0RTTData(); 246 247 private: 248 // mTransaction only points to the HTTP Transaction callbacks if the 249 // transaction is open, otherwise it is null. 250 RefPtr<nsAHttpTransaction> mTransaction; 251 252 nsCOMPtr<nsIAsyncInputStream> mSocketIn; 253 nsCOMPtr<nsIAsyncOutputStream> mSocketOut; 254 255 nsresult mSocketInCondition{NS_ERROR_NOT_INITIALIZED}; 256 nsresult mSocketOutCondition{NS_ERROR_NOT_INITIALIZED}; 257 258 nsCOMPtr<nsIInputStream> mProxyConnectStream; 259 nsCOMPtr<nsIInputStream> mRequestStream; 260 261 RefPtr<TLSFilterTransaction> mTLSFilter; 262 nsWeakPtr mWeakTrans; // SpdyConnectTransaction * 263 264 RefPtr<nsHttpHandler> mHttpHandler; // keep gHttpHandler alive 265 266 PRIntervalTime mLastReadTime{0}; 267 PRIntervalTime mLastWriteTime{0}; 268 // max download time before dropping keep-alive status 269 PRIntervalTime mMaxHangTime{0}; 270 PRIntervalTime mIdleTimeout; // value of keep-alive: timeout= 271 PRIntervalTime mConsiderReusedAfterInterval{0}; 272 PRIntervalTime mConsiderReusedAfterEpoch{0}; 273 int64_t mCurrentBytesRead{0}; // data read per activation 274 int64_t mMaxBytesRead{0}; // max read in 1 activation 275 int64_t mTotalBytesRead{0}; // total data read 276 int64_t mContentBytesWritten{0}; // does not include CONNECT tunnel or TLS 277 278 RefPtr<nsIAsyncInputStream> mInputOverflow; 279 280 // Whether the first non-null transaction dispatched on this connection was 281 // urgent-start or not 282 bool mUrgentStartPreferred{false}; 283 // A flag to prevent reset of mUrgentStartPreferred by subsequent transactions 284 bool mUrgentStartPreferredKnown{false}; 285 bool mConnectedTransport{false}; 286 // assume to keep-alive by default 287 bool mKeepAlive{true}; 288 bool mKeepAliveMask{true}; 289 bool mDontReuse{false}; 290 bool mIsReused{false}; 291 bool mCompletedProxyConnect{false}; 292 bool mLastTransactionExpectedNoContent{false}; 293 bool mIdleMonitoring{false}; 294 bool mProxyConnectInProgress{false}; 295 bool mInSpdyTunnel{false}; 296 bool mForcePlainText{false}; 297 298 // A snapshot of current number of transfered bytes 299 int64_t mTrafficCount{0}; 300 bool mTrafficStamp{false}; // true then the above is set 301 302 // The number of <= HTTP/1.1 transactions performed on this connection. This 303 // excludes spdy transactions. 304 uint32_t mHttp1xTransactionCount{0}; 305 306 // Keep-Alive: max="mRemainingConnectionUses" provides the number of future 307 // transactions (including the current one) that the server expects to allow 308 // on this persistent connection. 309 uint32_t mRemainingConnectionUses{0xffffffff}; 310 311 // SPDY related 312 bool mNPNComplete{false}; 313 bool mSetupSSLCalled{false}; 314 315 // version level in use, 0 if unused 316 SpdyVersion mUsingSpdyVersion{SpdyVersion::NONE}; 317 318 RefPtr<ASpdySession> mSpdySession; 319 int32_t mPriority{nsISupportsPriority::PRIORITY_NORMAL}; 320 bool mReportedSpdy{false}; 321 322 // mUsingSpdyVersion is cleared when mSpdySession is freed, this is permanent 323 bool mEverUsedSpdy{false}; 324 325 // mLastHttpResponseVersion stores the last response's http version seen. 326 HttpVersion mLastHttpResponseVersion{HttpVersion::v1_1}; 327 328 // If a large keepalive has been requested for any trans, 329 // scale the default by this factor 330 uint32_t mDefaultTimeoutFactor{1}; 331 332 bool mResponseTimeoutEnabled{false}; 333 334 // Flag to indicate connection is in inital keepalive period (fast detect). 335 uint32_t mTCPKeepaliveConfig{kTCPKeepaliveDisabled}; 336 nsCOMPtr<nsITimer> mTCPKeepaliveTransitionTimer; 337 338 private: 339 // For ForceSend() 340 static void ForceSendIO(nsITimer* aTimer, void* aClosure); 341 [[nodiscard]] nsresult MaybeForceSendIO(); 342 bool mForceSendPending{false}; 343 nsCOMPtr<nsITimer> mForceSendTimer; 344 345 // Helper variable for 0RTT handshake; 346 // Possible 0RTT has been checked. 347 bool m0RTTChecked{false}; 348 // We have are sending 0RTT data and we are waiting 349 // for the end of the handsake. 350 bool mWaitingFor0RTTResponse{false}; 351 int64_t mContentBytesWritten0RTT{0}; 352 bool mEarlyDataNegotiated{false}; // Only used for telemetry 353 nsCString mEarlyNegotiatedALPN; 354 bool mDid0RTTSpdy{false}; 355 356 nsresult mErrorBeforeConnect = NS_OK; 357 358 nsCOMPtr<nsISocketTransport> mSocketTransport; 359 360 bool mForWebSocket{false}; 361 362 private: 363 bool mThroughCaptivePortal; 364 int64_t mTotalBytesWritten = 0; // does not include CONNECT tunnel 365 }; 366 367 NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpConnection, NS_HTTPCONNECTION_IID) 368 369 } // namespace net 370 } // namespace mozilla 371 372 #endif // nsHttpConnection_h__ 373