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