michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsHttpConnection_h__ michael@0: #define nsHttpConnection_h__ michael@0: michael@0: #include "nsHttpConnectionInfo.h" michael@0: #include "nsAHttpTransaction.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsProxyRelease.h" michael@0: #include "prinrval.h" michael@0: michael@0: #include "nsIAsyncInputStream.h" michael@0: #include "nsIAsyncOutputStream.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsITimer.h" michael@0: michael@0: class nsISocketTransport; michael@0: michael@0: namespace mozilla { michael@0: namespace net { michael@0: michael@0: class nsHttpHandler; michael@0: class ASpdySession; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // nsHttpConnection - represents a connection to a HTTP server (or proxy) michael@0: // michael@0: // NOTE: this objects lives on the socket thread only. it should not be michael@0: // accessed from any other thread. michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class nsHttpConnection : public nsAHttpSegmentReader michael@0: , public nsAHttpSegmentWriter michael@0: , public nsIInputStreamCallback michael@0: , public nsIOutputStreamCallback michael@0: , public nsITransportEventSink michael@0: , public nsIInterfaceRequestor michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSAHTTPSEGMENTREADER michael@0: NS_DECL_NSAHTTPSEGMENTWRITER michael@0: NS_DECL_NSIINPUTSTREAMCALLBACK michael@0: NS_DECL_NSIOUTPUTSTREAMCALLBACK michael@0: NS_DECL_NSITRANSPORTEVENTSINK michael@0: NS_DECL_NSIINTERFACEREQUESTOR michael@0: michael@0: nsHttpConnection(); michael@0: virtual ~nsHttpConnection(); michael@0: michael@0: // Initialize the connection: michael@0: // info - specifies the connection parameters. michael@0: // maxHangTime - limits the amount of time this connection can spend on a michael@0: // single transaction before it should no longer be kept michael@0: // alive. a value of 0xffff indicates no limit. michael@0: nsresult Init(nsHttpConnectionInfo *info, uint16_t maxHangTime, michael@0: nsISocketTransport *, nsIAsyncInputStream *, michael@0: nsIAsyncOutputStream *, nsIInterfaceRequestor *, michael@0: PRIntervalTime); michael@0: michael@0: // Activate causes the given transaction to be processed on this michael@0: // connection. It fails if there is already an existing transaction unless michael@0: // a multiplexing protocol such as SPDY is being used michael@0: nsresult Activate(nsAHttpTransaction *, uint32_t caps, int32_t pri); michael@0: michael@0: // Close the underlying socket transport. michael@0: void Close(nsresult reason); michael@0: michael@0: //------------------------------------------------------------------------- michael@0: // XXX document when these are ok to call michael@0: michael@0: bool SupportsPipelining(); michael@0: bool IsKeepAlive() { return mUsingSpdyVersion || michael@0: (mKeepAliveMask && mKeepAlive); } michael@0: bool CanReuse(); // can this connection be reused? michael@0: bool CanDirectlyActivate(); michael@0: michael@0: // Returns time in seconds for how long connection can be reused. michael@0: uint32_t TimeToLive(); michael@0: michael@0: void DontReuse(); michael@0: michael@0: bool IsProxyConnectInProgress() michael@0: { michael@0: return mProxyConnectInProgress; michael@0: } michael@0: michael@0: bool LastTransactionExpectedNoContent() michael@0: { michael@0: return mLastTransactionExpectedNoContent; michael@0: } michael@0: michael@0: void SetLastTransactionExpectedNoContent(bool val) michael@0: { michael@0: mLastTransactionExpectedNoContent = val; michael@0: } michael@0: michael@0: nsISocketTransport *Transport() { return mSocketTransport; } michael@0: nsAHttpTransaction *Transaction() { return mTransaction; } michael@0: nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; } michael@0: michael@0: // nsAHttpConnection compatible methods (non-virtual): michael@0: nsresult OnHeadersAvailable(nsAHttpTransaction *, nsHttpRequestHead *, nsHttpResponseHead *, bool *reset); michael@0: void CloseTransaction(nsAHttpTransaction *, nsresult reason); michael@0: void GetConnectionInfo(nsHttpConnectionInfo **ci) { NS_IF_ADDREF(*ci = mConnInfo); } michael@0: nsresult TakeTransport(nsISocketTransport **, michael@0: nsIAsyncInputStream **, michael@0: nsIAsyncOutputStream **); michael@0: void GetSecurityInfo(nsISupports **); michael@0: bool IsPersistent() { return IsKeepAlive(); } michael@0: bool IsReused(); michael@0: void SetIsReusedAfter(uint32_t afterMilliseconds); michael@0: nsresult PushBack(const char *data, uint32_t length); michael@0: nsresult ResumeSend(); michael@0: nsresult ResumeRecv(); michael@0: int64_t MaxBytesRead() {return mMaxBytesRead;} michael@0: uint8_t GetLastHttpResponseVersion() { return mLastHttpResponseVersion; } michael@0: michael@0: friend class nsHttpConnectionForceRecv; michael@0: nsresult ForceRecv(); michael@0: michael@0: static NS_METHOD ReadFromStream(nsIInputStream *, void *, const char *, michael@0: uint32_t, uint32_t, uint32_t *); michael@0: michael@0: // When a persistent connection is in the connection manager idle michael@0: // connection pool, the nsHttpConnection still reads errors and hangups michael@0: // on the socket so that it can be proactively released if the server michael@0: // initiates a termination. Only call on socket thread. michael@0: void BeginIdleMonitoring(); michael@0: void EndIdleMonitoring(); michael@0: michael@0: bool UsingSpdy() { return !!mUsingSpdyVersion; } michael@0: uint8_t GetSpdyVersion() { return mUsingSpdyVersion; } michael@0: bool EverUsedSpdy() { return mEverUsedSpdy; } michael@0: PRIntervalTime Rtt() { return mRtt; } michael@0: michael@0: // true when connection SSL NPN phase is complete and we know michael@0: // authoritatively whether UsingSpdy() or not. michael@0: bool ReportedNPN() { return mReportedSpdy; } michael@0: michael@0: // When the connection is active this is called up to once every 1 second michael@0: // return the interval (in seconds) that the connection next wants to michael@0: // have this invoked. It might happen sooner depending on the needs of michael@0: // other connections. michael@0: uint32_t ReadTimeoutTick(PRIntervalTime now); michael@0: michael@0: // For Active and Idle connections, this will be called when michael@0: // mTCPKeepaliveTransitionTimer fires, to check if the TCP keepalive config michael@0: // should move from short-lived (fast-detect) to long-lived. michael@0: static void UpdateTCPKeepalive(nsITimer *aTimer, void *aClosure); michael@0: michael@0: nsAHttpTransaction::Classifier Classification() { return mClassification; } michael@0: void Classify(nsAHttpTransaction::Classifier newclass) michael@0: { michael@0: mClassification = newclass; michael@0: } michael@0: michael@0: // When the connection is active this is called every second michael@0: void ReadTimeoutTick(); michael@0: michael@0: int64_t BytesWritten() { return mTotalBytesWritten; } michael@0: michael@0: void SetSecurityCallbacks(nsIInterfaceRequestor* aCallbacks); michael@0: void PrintDiagnostics(nsCString &log); michael@0: michael@0: void SetTransactionCaps(uint32_t aCaps) { mTransactionCaps = aCaps; } michael@0: michael@0: // IsExperienced() returns true when the connection has started at least one michael@0: // non null HTTP transaction of any version. michael@0: bool IsExperienced() { return mExperienced; } michael@0: michael@0: private: michael@0: // Value (set in mTCPKeepaliveConfig) indicates which set of prefs to use. michael@0: enum TCPKeepaliveConfig { michael@0: kTCPKeepaliveDisabled = 0, michael@0: kTCPKeepaliveShortLivedConfig, michael@0: kTCPKeepaliveLongLivedConfig michael@0: }; michael@0: michael@0: // called to cause the underlying socket to start speaking SSL michael@0: nsresult ProxyStartSSL(); michael@0: michael@0: nsresult OnTransactionDone(nsresult reason); michael@0: nsresult OnSocketWritable(); michael@0: nsresult OnSocketReadable(); michael@0: michael@0: nsresult SetupProxyConnect(); michael@0: michael@0: PRIntervalTime IdleTime(); michael@0: bool IsAlive(); michael@0: bool SupportsPipelining(nsHttpResponseHead *); michael@0: michael@0: // Makes certain the SSL handshake is complete and NPN negotiation michael@0: // has had a chance to happen michael@0: bool EnsureNPNComplete(); michael@0: void SetupSSL(uint32_t caps); michael@0: michael@0: // Start the Spdy transaction handler when NPN indicates spdy/* michael@0: void StartSpdy(uint8_t versionLevel); michael@0: michael@0: // Directly Add a transaction to an active connection for SPDY michael@0: nsresult AddTransaction(nsAHttpTransaction *, int32_t); michael@0: michael@0: // Used to set TCP keepalives for fast detection of dead connections during michael@0: // an initial period, and slower detection for long-lived connections. michael@0: nsresult StartShortLivedTCPKeepalives(); michael@0: nsresult StartLongLivedTCPKeepalives(); michael@0: nsresult DisableTCPKeepalives(); michael@0: michael@0: private: michael@0: nsCOMPtr mSocketTransport; michael@0: nsCOMPtr mSocketIn; michael@0: nsCOMPtr mSocketOut; michael@0: michael@0: nsresult mSocketInCondition; michael@0: nsresult mSocketOutCondition; michael@0: michael@0: nsCOMPtr mProxyConnectStream; michael@0: nsCOMPtr mRequestStream; michael@0: michael@0: // mTransaction only points to the HTTP Transaction callbacks if the michael@0: // transaction is open, otherwise it is null. michael@0: nsRefPtr mTransaction; michael@0: michael@0: nsRefPtr mHttpHandler; // keep gHttpHandler alive michael@0: michael@0: Mutex mCallbacksLock; michael@0: nsMainThreadPtrHandle mCallbacks; michael@0: michael@0: nsRefPtr mConnInfo; michael@0: michael@0: PRIntervalTime mLastReadTime; michael@0: PRIntervalTime mLastWriteTime; michael@0: PRIntervalTime mMaxHangTime; // max download time before dropping keep-alive status michael@0: PRIntervalTime mIdleTimeout; // value of keep-alive: timeout= michael@0: PRIntervalTime mConsiderReusedAfterInterval; michael@0: PRIntervalTime mConsiderReusedAfterEpoch; michael@0: int64_t mCurrentBytesRead; // data read per activation michael@0: int64_t mMaxBytesRead; // max read in 1 activation michael@0: int64_t mTotalBytesRead; // total data read michael@0: int64_t mTotalBytesWritten; // does not include CONNECT tunnel michael@0: michael@0: nsRefPtr mInputOverflow; michael@0: michael@0: PRIntervalTime mRtt; michael@0: michael@0: bool mKeepAlive; michael@0: bool mKeepAliveMask; michael@0: bool mDontReuse; michael@0: bool mSupportsPipelining; michael@0: bool mIsReused; michael@0: bool mCompletedProxyConnect; michael@0: bool mLastTransactionExpectedNoContent; michael@0: bool mIdleMonitoring; michael@0: bool mProxyConnectInProgress; michael@0: bool mExperienced; michael@0: michael@0: // The number of <= HTTP/1.1 transactions performed on this connection. This michael@0: // excludes spdy transactions. michael@0: uint32_t mHttp1xTransactionCount; michael@0: michael@0: // Keep-Alive: max="mRemainingConnectionUses" provides the number of future michael@0: // transactions (including the current one) that the server expects to allow michael@0: // on this persistent connection. michael@0: uint32_t mRemainingConnectionUses; michael@0: michael@0: nsAHttpTransaction::Classifier mClassification; michael@0: michael@0: // SPDY related michael@0: bool mNPNComplete; michael@0: bool mSetupSSLCalled; michael@0: michael@0: // version level in use, 0 if unused michael@0: uint8_t mUsingSpdyVersion; michael@0: michael@0: nsRefPtr mSpdySession; michael@0: int32_t mPriority; michael@0: bool mReportedSpdy; michael@0: michael@0: // mUsingSpdyVersion is cleared when mSpdySession is freed, this is permanent michael@0: bool mEverUsedSpdy; michael@0: michael@0: // mLastHttpResponseVersion stores the last response's http version seen. michael@0: uint8_t mLastHttpResponseVersion; michael@0: michael@0: // The capabailities associated with the most recent transaction michael@0: uint32_t mTransactionCaps; michael@0: michael@0: bool mResponseTimeoutEnabled; michael@0: michael@0: // Flag to indicate connection is in inital keepalive period (fast detect). michael@0: uint32_t mTCPKeepaliveConfig; michael@0: nsCOMPtr mTCPKeepaliveTransitionTimer; michael@0: }; michael@0: michael@0: }} // namespace mozilla::net michael@0: michael@0: #endif // nsHttpConnection_h__