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