1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 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 "nsHttpConnectionInfo.h" 10 #include "nsHttpResponseHead.h" 11 #include "nsAHttpTransaction.h" 12 #include "nsCOMPtr.h" 13 #include "nsAutoPtr.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 21 #include "nsIAsyncInputStream.h" 22 #include "nsIAsyncOutputStream.h" 23 #include "nsIInterfaceRequestor.h" 24 #include "nsITimer.h" 25 26 class nsISocketTransport; 27 class nsISSLSocketControl; 28 29 namespace mozilla { 30 namespace net { 31 32 class nsHttpHandler; 33 class ASpdySession; 34 35 // 1dcc863e-db90-4652-a1fe-13fea0b54e46 36 #define NS_HTTPCONNECTION_IID \ 37 { \ 38 0x1dcc863e, 0xdb90, 0x4652, { \ 39 0xa1, 0xfe, 0x13, 0xfe, 0xa0, 0xb5, 0x4e, 0x46 \ 40 } \ 41 } 42 43 //----------------------------------------------------------------------------- 44 // nsHttpConnection - represents a connection to a HTTP server (or proxy) 45 // 46 // NOTE: this objects lives on the socket thread only. it should not be 47 // accessed from any other thread. 48 //----------------------------------------------------------------------------- 49 50 class nsHttpConnection final : public nsAHttpSegmentReader, 51 public nsAHttpSegmentWriter, 52 public nsIInputStreamCallback, 53 public nsIOutputStreamCallback, 54 public nsITransportEventSink, 55 public nsIInterfaceRequestor, 56 public NudgeTunnelCallback, 57 public ARefBase, 58 public nsSupportsWeakReference { 59 virtual ~nsHttpConnection(); 60 61 public: 62 NS_DECLARE_STATIC_IID_ACCESSOR(NS_HTTPCONNECTION_IID) 63 NS_DECL_THREADSAFE_ISUPPORTS 64 NS_DECL_NSAHTTPSEGMENTREADER 65 NS_DECL_NSAHTTPSEGMENTWRITER 66 NS_DECL_NSIINPUTSTREAMCALLBACK 67 NS_DECL_NSIOUTPUTSTREAMCALLBACK 68 NS_DECL_NSITRANSPORTEVENTSINK 69 NS_DECL_NSIINTERFACEREQUESTOR 70 NS_DECL_NUDGETUNNELCALLBACK 71 72 nsHttpConnection(); 73 74 // Initialize the connection: 75 // info - specifies the connection parameters. 76 // maxHangTime - limits the amount of time this connection can spend on a 77 // single transaction before it should no longer be kept 78 // alive. a value of 0xffff indicates no limit. 79 MOZ_MUST_USE nsresult Init(nsHttpConnectionInfo *info, uint16_t maxHangTime, 80 nsISocketTransport *, nsIAsyncInputStream *, 81 nsIAsyncOutputStream *, bool connectedTransport, 82 nsIInterfaceRequestor *, PRIntervalTime); 83 84 // Activate causes the given transaction to be processed on this 85 // connection. It fails if there is already an existing transaction unless 86 // a multiplexing protocol such as SPDY is being used 87 MOZ_MUST_USE nsresult Activate(nsAHttpTransaction *, uint32_t caps, 88 int32_t pri); 89 90 void SetFastOpen(bool aFastOpen); 91 // Close this connection and return the transaction. The transaction is 92 // restarted as well. This will only happened before connection is 93 // connected. 94 nsAHttpTransaction *CloseConnectionFastOpenTakesTooLongOrError( 95 bool aCloseocketTransport); 96 97 // Close the underlying socket transport. 98 void Close(nsresult reason, bool aIsShutdown = false); 99 100 //------------------------------------------------------------------------- 101 // XXX document when these are ok to call 102 IsKeepAlive()103 bool IsKeepAlive() { 104 return mUsingSpdyVersion || (mKeepAliveMask && mKeepAlive); 105 } 106 bool CanReuse(); // can this connection be reused? 107 bool CanDirectlyActivate(); 108 109 // Returns time in seconds for how long connection can be reused. 110 uint32_t TimeToLive(); 111 112 void DontReuse(); 113 IsProxyConnectInProgress()114 bool IsProxyConnectInProgress() { return mProxyConnectInProgress; } 115 LastTransactionExpectedNoContent()116 bool LastTransactionExpectedNoContent() { 117 return mLastTransactionExpectedNoContent; 118 } 119 SetLastTransactionExpectedNoContent(bool val)120 void SetLastTransactionExpectedNoContent(bool val) { 121 mLastTransactionExpectedNoContent = val; 122 } 123 NeedSpdyTunnel()124 bool NeedSpdyTunnel() { 125 return mConnInfo->UsingHttpsProxy() && !mTLSFilter && 126 mConnInfo->UsingConnect(); 127 } 128 129 // A connection is forced into plaintext when it is intended to be used as a 130 // CONNECT tunnel but the setup fails. The plaintext only carries the CONNECT 131 // error. ForcePlainText()132 void ForcePlainText() { mForcePlainText = true; } 133 IsUrgentStartPreferred()134 bool IsUrgentStartPreferred() const { 135 return mUrgentStartPreferredKnown && mUrgentStartPreferred; 136 } 137 void SetUrgentStartPreferred(bool urgent); 138 Transport()139 nsISocketTransport *Transport() { return mSocketTransport; } Transaction()140 nsAHttpTransaction *Transaction() { return mTransaction; } ConnectionInfo()141 nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; } 142 143 // nsAHttpConnection compatible methods (non-virtual): 144 MOZ_MUST_USE nsresult OnHeadersAvailable(nsAHttpTransaction *, 145 nsHttpRequestHead *, 146 nsHttpResponseHead *, bool *reset); 147 void CloseTransaction(nsAHttpTransaction *, nsresult reason, 148 bool aIsShutdown = false); GetConnectionInfo(nsHttpConnectionInfo ** ci)149 void GetConnectionInfo(nsHttpConnectionInfo **ci) { 150 NS_IF_ADDREF(*ci = mConnInfo); 151 } 152 MOZ_MUST_USE nsresult TakeTransport(nsISocketTransport **, 153 nsIAsyncInputStream **, 154 nsIAsyncOutputStream **); 155 void GetSecurityInfo(nsISupports **); IsPersistent()156 bool IsPersistent() { return IsKeepAlive() && !mDontReuse; } 157 bool IsReused(); 158 void SetIsReusedAfter(uint32_t afterMilliseconds); 159 MOZ_MUST_USE nsresult PushBack(const char *data, uint32_t length); 160 MOZ_MUST_USE nsresult ResumeSend(); 161 MOZ_MUST_USE nsresult ResumeRecv(); MaxBytesRead()162 int64_t MaxBytesRead() { return mMaxBytesRead; } GetLastHttpResponseVersion()163 uint8_t GetLastHttpResponseVersion() { return mLastHttpResponseVersion; } 164 165 friend class HttpConnectionForceIO; 166 MOZ_MUST_USE nsresult ForceSend(); 167 MOZ_MUST_USE nsresult ForceRecv(); 168 169 static MOZ_MUST_USE nsresult ReadFromStream(nsIInputStream *, void *, 170 const char *, uint32_t, uint32_t, 171 uint32_t *); 172 173 // When a persistent connection is in the connection manager idle 174 // connection pool, the nsHttpConnection still reads errors and hangups 175 // on the socket so that it can be proactively released if the server 176 // initiates a termination. Only call on socket thread. 177 void BeginIdleMonitoring(); 178 void EndIdleMonitoring(); 179 UsingSpdy()180 bool UsingSpdy() { return !!mUsingSpdyVersion; } GetSpdyVersion()181 uint8_t GetSpdyVersion() { return mUsingSpdyVersion; } EverUsedSpdy()182 bool EverUsedSpdy() { return mEverUsedSpdy; } Rtt()183 PRIntervalTime Rtt() { return mRtt; } 184 185 // true when connection SSL NPN phase is complete and we know 186 // authoritatively whether UsingSpdy() or not. ReportedNPN()187 bool ReportedNPN() { return mReportedSpdy; } 188 189 // When the connection is active this is called up to once every 1 second 190 // return the interval (in seconds) that the connection next wants to 191 // have this invoked. It might happen sooner depending on the needs of 192 // other connections. 193 uint32_t ReadTimeoutTick(PRIntervalTime now); 194 195 // For Active and Idle connections, this will be called when 196 // mTCPKeepaliveTransitionTimer fires, to check if the TCP keepalive config 197 // should move from short-lived (fast-detect) to long-lived. 198 static void UpdateTCPKeepalive(nsITimer *aTimer, void *aClosure); 199 200 // When the connection is active this is called every second 201 void ReadTimeoutTick(); 202 BytesWritten()203 int64_t BytesWritten() { return mTotalBytesWritten; } // includes TLS ContentBytesWritten()204 int64_t ContentBytesWritten() { return mContentBytesWritten; } 205 206 void SetSecurityCallbacks(nsIInterfaceRequestor *aCallbacks); 207 void PrintDiagnostics(nsCString &log); 208 SetTransactionCaps(uint32_t aCaps)209 void SetTransactionCaps(uint32_t aCaps) { mTransactionCaps = aCaps; } 210 211 // IsExperienced() returns true when the connection has started at least one 212 // non null HTTP transaction of any version. IsExperienced()213 bool IsExperienced() { return mExperienced; } 214 215 static MOZ_MUST_USE nsresult MakeConnectString(nsAHttpTransaction *trans, 216 nsHttpRequestHead *request, 217 nsACString &result); 218 void SetupSecondaryTLS(); 219 void SetInSpdyTunnel(bool arg); 220 221 // Check active connections for traffic (or not). SPDY connections send a 222 // ping, ordinary HTTP connections get some time to get traffic to be 223 // considered alive. 224 void CheckForTraffic(bool check); 225 226 // NoTraffic() returns true if there's been no traffic on the (non-spdy) 227 // connection since CheckForTraffic() was called. NoTraffic()228 bool NoTraffic() { 229 return mTrafficStamp && 230 (mTrafficCount == (mTotalBytesWritten + mTotalBytesRead)) && 231 !mFastOpen; 232 } 233 // override of nsAHttpConnection 234 virtual uint32_t Version(); 235 236 bool TestJoinConnection(const nsACString &hostname, int32_t port); 237 bool JoinConnection(const nsACString &hostname, int32_t port); 238 239 void SetFastOpenStatus(uint8_t tfoStatus); GetFastOpenStatus()240 uint8_t GetFastOpenStatus() { return mFastOpenStatus; } 241 242 void SetEvent(nsresult aStatus); 243 244 // Return true when the socket this connection is using has not been 245 // authenticated using a client certificate. Before SSL negotiation 246 // has finished this returns false. 247 bool NoClientCertAuth() const; 248 249 private: 250 // Value (set in mTCPKeepaliveConfig) indicates which set of prefs to use. 251 enum TCPKeepaliveConfig { 252 kTCPKeepaliveDisabled = 0, 253 kTCPKeepaliveShortLivedConfig, 254 kTCPKeepaliveLongLivedConfig 255 }; 256 257 // called to cause the underlying socket to start speaking SSL 258 MOZ_MUST_USE nsresult InitSSLParams(bool connectingToProxy, 259 bool ProxyStartSSL); 260 MOZ_MUST_USE nsresult SetupNPNList(nsISSLSocketControl *ssl, uint32_t caps); 261 262 MOZ_MUST_USE nsresult OnTransactionDone(nsresult reason); 263 MOZ_MUST_USE nsresult OnSocketWritable(); 264 MOZ_MUST_USE nsresult OnSocketReadable(); 265 266 MOZ_MUST_USE nsresult SetupProxyConnect(); 267 268 PRIntervalTime IdleTime(); 269 bool IsAlive(); 270 271 // Makes certain the SSL handshake is complete and NPN negotiation 272 // has had a chance to happen 273 MOZ_MUST_USE bool EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue, 274 uint32_t &aOut0RTTBytesWritten); 275 void SetupSSL(); 276 277 // Start the Spdy transaction handler when NPN indicates spdy/* 278 void StartSpdy(nsISSLSocketControl *ssl, uint8_t versionLevel); 279 // Like the above, but do the bare minimum to do 0RTT data, so we can back 280 // it out, if necessary 281 void Start0RTTSpdy(uint8_t versionLevel); 282 283 // Helpers for Start*Spdy 284 nsresult TryTakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction> > &list); 285 nsresult MoveTransactionsToSpdy(nsresult status, 286 nsTArray<RefPtr<nsAHttpTransaction> > &list); 287 288 // Directly Add a transaction to an active connection for SPDY 289 MOZ_MUST_USE nsresult AddTransaction(nsAHttpTransaction *, int32_t); 290 291 // Used to set TCP keepalives for fast detection of dead connections during 292 // an initial period, and slower detection for long-lived connections. 293 MOZ_MUST_USE nsresult StartShortLivedTCPKeepalives(); 294 MOZ_MUST_USE nsresult StartLongLivedTCPKeepalives(); 295 MOZ_MUST_USE nsresult DisableTCPKeepalives(); 296 297 private: 298 nsCOMPtr<nsISocketTransport> mSocketTransport; 299 nsCOMPtr<nsIAsyncInputStream> mSocketIn; 300 nsCOMPtr<nsIAsyncOutputStream> mSocketOut; 301 302 nsresult mSocketInCondition; 303 nsresult mSocketOutCondition; 304 305 nsCOMPtr<nsIInputStream> mProxyConnectStream; 306 nsCOMPtr<nsIInputStream> mRequestStream; 307 308 // mTransaction only points to the HTTP Transaction callbacks if the 309 // transaction is open, otherwise it is null. 310 RefPtr<nsAHttpTransaction> mTransaction; 311 RefPtr<TLSFilterTransaction> mTLSFilter; 312 313 RefPtr<nsHttpHandler> mHttpHandler; // keep gHttpHandler alive 314 315 Mutex mCallbacksLock; 316 nsMainThreadPtrHandle<nsIInterfaceRequestor> mCallbacks; 317 318 RefPtr<nsHttpConnectionInfo> mConnInfo; 319 320 PRIntervalTime mLastReadTime; 321 PRIntervalTime mLastWriteTime; 322 PRIntervalTime 323 mMaxHangTime; // max download time before dropping keep-alive status 324 PRIntervalTime mIdleTimeout; // value of keep-alive: timeout= 325 PRIntervalTime mConsiderReusedAfterInterval; 326 PRIntervalTime mConsiderReusedAfterEpoch; 327 int64_t mCurrentBytesRead; // data read per activation 328 int64_t mMaxBytesRead; // max read in 1 activation 329 int64_t mTotalBytesRead; // total data read 330 int64_t mTotalBytesWritten; // does not include CONNECT tunnel 331 int64_t mContentBytesWritten; // does not include CONNECT tunnel or TLS 332 333 RefPtr<nsIAsyncInputStream> mInputOverflow; 334 335 PRIntervalTime mRtt; 336 337 // Whether the first non-null transaction dispatched on this connection was 338 // urgent-start or not 339 bool mUrgentStartPreferred; 340 // A flag to prevent reset of mUrgentStartPreferred by subsequent transactions 341 bool mUrgentStartPreferredKnown; 342 bool mConnectedTransport; 343 bool mKeepAlive; 344 bool mKeepAliveMask; 345 bool mDontReuse; 346 bool mIsReused; 347 bool mCompletedProxyConnect; 348 bool mLastTransactionExpectedNoContent; 349 bool mIdleMonitoring; 350 bool mProxyConnectInProgress; 351 bool mExperienced; 352 bool mInSpdyTunnel; 353 bool mForcePlainText; 354 355 // A snapshot of current number of transfered bytes 356 int64_t mTrafficCount; 357 bool mTrafficStamp; // true then the above is set 358 359 // The number of <= HTTP/1.1 transactions performed on this connection. This 360 // excludes spdy transactions. 361 uint32_t mHttp1xTransactionCount; 362 363 // Keep-Alive: max="mRemainingConnectionUses" provides the number of future 364 // transactions (including the current one) that the server expects to allow 365 // on this persistent connection. 366 uint32_t mRemainingConnectionUses; 367 368 // SPDY related 369 bool mNPNComplete; 370 bool mSetupSSLCalled; 371 372 // version level in use, 0 if unused 373 uint8_t mUsingSpdyVersion; 374 375 RefPtr<ASpdySession> mSpdySession; 376 int32_t mPriority; 377 bool mReportedSpdy; 378 379 // mUsingSpdyVersion is cleared when mSpdySession is freed, this is permanent 380 bool mEverUsedSpdy; 381 382 // mLastHttpResponseVersion stores the last response's http version seen. 383 uint8_t mLastHttpResponseVersion; 384 385 // The capabailities associated with the most recent transaction 386 uint32_t mTransactionCaps; 387 388 // If a large keepalive has been requested for any trans, 389 // scale the default by this factor 390 uint32_t mDefaultTimeoutFactor; 391 392 bool mResponseTimeoutEnabled; 393 394 // Flag to indicate connection is in inital keepalive period (fast detect). 395 uint32_t mTCPKeepaliveConfig; 396 nsCOMPtr<nsITimer> mTCPKeepaliveTransitionTimer; 397 398 private: 399 // For ForceSend() 400 static void ForceSendIO(nsITimer *aTimer, void *aClosure); 401 MOZ_MUST_USE nsresult MaybeForceSendIO(); 402 bool mForceSendPending; 403 nsCOMPtr<nsITimer> mForceSendTimer; 404 405 // Helper variable for 0RTT handshake; 406 bool m0RTTChecked; // Possible 0RTT has been 407 // checked. 408 bool mWaitingFor0RTTResponse; // We have are 409 // sending 0RTT 410 // data and we 411 // are waiting 412 // for the end of 413 // the handsake. 414 int64_t mContentBytesWritten0RTT; 415 bool mEarlyDataNegotiated; // Only used for telemetry 416 nsCString mEarlyNegotiatedALPN; 417 bool mDid0RTTSpdy; 418 419 bool mFastOpen; 420 uint8_t mFastOpenStatus; 421 422 bool mForceSendDuringFastOpenPending; 423 bool mReceivedSocketWouldBlockDuringFastOpen; 424 bool mCheckNetworkStallsWithTFO; 425 PRIntervalTime mLastRequestBytesSentTime; 426 427 public: 428 void BootstrapTimings(TimingStruct times); 429 430 private: 431 TimingStruct mBootstrappedTimings; 432 bool mBootstrappedTimingsSet; 433 }; 434 435 NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpConnection, NS_HTTPCONNECTION_IID) 436 437 } // namespace net 438 } // namespace mozilla 439 440 #endif // nsHttpConnection_h__ 441