1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_net_TLSFilterTransaction_h
8 #define mozilla_net_TLSFilterTransaction_h
9 
10 #include "mozilla/Attributes.h"
11 #include "mozilla/UniquePtr.h"
12 #include "nsAHttpTransaction.h"
13 #include "nsIAsyncInputStream.h"
14 #include "nsIAsyncOutputStream.h"
15 #include "nsINamed.h"
16 #include "nsISocketTransport.h"
17 #include "nsITimer.h"
18 #include "NullHttpTransaction.h"
19 #include "mozilla/TimeStamp.h"
20 #include "prio.h"
21 
22 // a TLSFilterTransaction wraps another nsAHttpTransaction but
23 // applies a encode/decode filter of TLS onto the ReadSegments
24 // and WriteSegments data. It is not used for basic https://
25 // but it is used for supplemental TLS tunnels - such as those
26 // needed by CONNECT tunnels in HTTP/2 or even CONNECT tunnels when
27 // the underlying proxy connection is already running TLS
28 //
29 // HTTP/2 CONNECT tunnels cannot use pushed IO layers because of
30 // the multiplexing involved on the base stream. i.e. the base stream
31 // once it is decrypted may have parts that are encrypted with a
32 // variety of keys, or none at all
33 
34 /* ************************************************************************
35 The input path of http over a spdy CONNECT tunnel once it is established as a
36 stream
37 
38 note the "real http transaction" can be either a http/1 transaction or another
39 spdy session inside the tunnel.
40 
41   nsHttpConnection::OnInputStreamReady (real socket)
42   nsHttpConnection::OnSocketReadable()
43   SpdySession::WriteSegment()
44   SpdyStream::WriteSegment (tunnel stream)
45   SpdyConnectTransaction::WriteSegment
46   SpdyStream::OnWriteSegment(tunnel stream)
47   SpdySession::OnWriteSegment()
48   SpdySession::NetworkRead()
49   nsHttpConnection::OnWriteSegment (real socket)
50   realSocketIn->Read() return data from network
51 
52 now pop the stack back up to SpdyConnectTransaction::WriteSegment, the data
53 that has been read is stored mInputData
54 
55   SpdyConnectTransaction.mTunneledConn::OnInputStreamReady(mTunnelStreamIn)
56   SpdyConnectTransaction.mTunneledConn::OnSocketReadable()
57   TLSFilterTransaction::WriteSegment()
58   nsHttpTransaction::WriteSegment(real http transaction)
59   TLSFilterTransaction::OnWriteSegment() removes tls on way back up stack
60   SpdyConnectTransaction.mTunneledConn::OnWriteSegment()
61   // gets data from mInputData
62   SpdyConnectTransaction.mTunneledConn.mTunnelStreamIn->Read()
63 
64 The output path works similarly:
65   nsHttpConnection::OnOutputStreamReady (real socket)
66   nsHttpConnection::OnSocketWritable()
67   SpdySession::ReadSegments (locates tunnel)
68   SpdyStream::ReadSegments (tunnel stream)
69   SpdyConnectTransaction::ReadSegments()
70   SpdyConnectTransaction.mTunneledConn::OnOutputStreamReady (tunnel connection)
71   SpdyConnectTransaction.mTunneledConn::OnSocketWritable (tunnel connection)
72   TLSFilterTransaction::ReadSegment()
73   nsHttpTransaction::ReadSegment (real http transaction generates plaintext on
74                                   way down)
75   TLSFilterTransaction::OnReadSegment (BUF and LEN gets encrypted here on way
76                                        down)
77   SpdyConnectTransaction.mTunneledConn::OnReadSegment (BUF and LEN)
78                                                       (tunnel connection)
79   SpdyConnectTransaction.mTunneledConn.mTunnelStreamOut->Write(BUF, LEN) ..
80                                                      get stored in mOutputData
81 
82 Now pop the stack back up to SpdyConnectTransaction::ReadSegment(), where it has
83 the encrypted text available in mOutputData
84 
85   SpdyStream->OnReadSegment(BUF,LEN) from mOutputData. Tunnel stream
86   SpdySession->OnReadSegment() // encrypted data gets put in a data frame
87   nsHttpConnection->OnReadSegment()
88   realSocketOut->write() writes data to network
89 
90 **************************************************************************/
91 
92 struct PRSocketOptionData;
93 
94 namespace mozilla {
95 namespace net {
96 
97 class nsHttpRequestHead;
98 class NullHttpTransaction;
99 class TLSFilterTransaction;
100 
101 class NudgeTunnelCallback : public nsISupports {
102  public:
103   virtual void OnTunnelNudged(TLSFilterTransaction *) = 0;
104 };
105 
106 #define NS_DECL_NUDGETUNNELCALLBACK \
107   void OnTunnelNudged(TLSFilterTransaction *) override;
108 
109 class TLSFilterTransaction final : public nsAHttpTransaction,
110                                    public nsAHttpSegmentReader,
111                                    public nsAHttpSegmentWriter,
112                                    public nsITimerCallback,
113                                    public nsINamed {
114   ~TLSFilterTransaction();
115 
116  public:
117   NS_DECL_THREADSAFE_ISUPPORTS
118   NS_DECL_NSAHTTPTRANSACTION
119   NS_DECL_NSAHTTPSEGMENTREADER
120   NS_DECL_NSAHTTPSEGMENTWRITER
121   NS_DECL_NSITIMERCALLBACK
122   NS_DECL_NSINAMED
123 
124   TLSFilterTransaction(nsAHttpTransaction *aWrappedTransaction,
125                        const char *tlsHost, int32_t tlsPort,
126                        nsAHttpSegmentReader *reader,
127                        nsAHttpSegmentWriter *writer);
128 
Transaction()129   const nsAHttpTransaction *Transaction() const { return mTransaction.get(); }
130   MOZ_MUST_USE nsresult CommitToSegmentSize(uint32_t size,
131                                             bool forceCommitment) override;
132   MOZ_MUST_USE nsresult GetTransactionSecurityInfo(nsISupports **) override;
133   MOZ_MUST_USE nsresult NudgeTunnel(NudgeTunnelCallback *callback);
134   MOZ_MUST_USE nsresult SetProxiedTransaction(nsAHttpTransaction *aTrans);
135   void newIODriver(nsIAsyncInputStream *aSocketIn,
136                    nsIAsyncOutputStream *aSocketOut,
137                    nsIAsyncInputStream **outSocketIn,
138                    nsIAsyncOutputStream **outSocketOut);
139 
140   // nsAHttpTransaction overloads
141   bool IsNullTransaction() override;
142   NullHttpTransaction *QueryNullTransaction() override;
143   nsHttpTransaction *QueryHttpTransaction() override;
144   SpdyConnectTransaction *QuerySpdyConnectTransaction() override;
145 
146  private:
147   MOZ_MUST_USE nsresult StartTimerCallback();
148   void Cleanup();
149   int32_t FilterOutput(const char *aBuf, int32_t aAmount);
150   int32_t FilterInput(char *aBuf, int32_t aAmount);
151 
152   static PRStatus GetPeerName(PRFileDesc *fd, PRNetAddr *addr);
153   static PRStatus GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data);
154   static PRStatus SetSocketOption(PRFileDesc *fd,
155                                   const PRSocketOptionData *data);
156   static int32_t FilterWrite(PRFileDesc *fd, const void *buf, int32_t amount);
157   static int32_t FilterRead(PRFileDesc *fd, void *buf, int32_t amount);
158   static int32_t FilterSend(PRFileDesc *fd, const void *buf, int32_t amount,
159                             int flags, PRIntervalTime timeout);
160   static int32_t FilterRecv(PRFileDesc *fd, void *buf, int32_t amount,
161                             int flags, PRIntervalTime timeout);
162   static PRStatus FilterClose(PRFileDesc *fd);
163 
164  private:
165   RefPtr<nsAHttpTransaction> mTransaction;
166   nsCOMPtr<nsISupports> mSecInfo;
167   nsCOMPtr<nsITimer> mTimer;
168   RefPtr<NudgeTunnelCallback> mNudgeCallback;
169 
170   // buffered network output, after encryption
171   UniquePtr<char[]> mEncryptedText;
172   uint32_t mEncryptedTextUsed;
173   uint32_t mEncryptedTextSize;
174 
175   PRFileDesc *mFD;
176   nsAHttpSegmentReader *mSegmentReader;
177   nsAHttpSegmentWriter *mSegmentWriter;
178 
179   nsresult mFilterReadCode;
180   bool mForce;
181   bool mReadSegmentBlocked;
182   uint32_t mNudgeCounter;
183 };
184 
185 class SocketTransportShim;
186 class InputStreamShim;
187 class OutputStreamShim;
188 class nsHttpConnection;
189 
190 class SpdyConnectTransaction final : public NullHttpTransaction {
191  public:
192   SpdyConnectTransaction(nsHttpConnectionInfo *ci,
193                          nsIInterfaceRequestor *callbacks, uint32_t caps,
194                          nsHttpTransaction *trans, nsAHttpConnection *session);
195   ~SpdyConnectTransaction();
196 
QuerySpdyConnectTransaction()197   SpdyConnectTransaction *QuerySpdyConnectTransaction() override {
198     return this;
199   }
200 
201   // A transaction is forced into plaintext when it is intended to be used as a
202   // CONNECT tunnel but the setup fails. The plaintext only carries the CONNECT
203   // error.
204   void ForcePlainText();
205   void MapStreamToHttpConnection(nsISocketTransport *aTransport,
206                                  nsHttpConnectionInfo *aConnInfo);
207 
208   MOZ_MUST_USE nsresult ReadSegments(nsAHttpSegmentReader *reader,
209                                      uint32_t count, uint32_t *countRead) final;
210   MOZ_MUST_USE nsresult WriteSegments(nsAHttpSegmentWriter *writer,
211                                       uint32_t count,
212                                       uint32_t *countWritten) final;
213   nsHttpRequestHead *RequestHead() final;
214   void Close(nsresult reason) final;
215 
216   // ConnectedReadyForInput() tests whether the spdy connect transaction is
217   // attached to an nsHttpConnection that can properly deal with flow control,
218   // etc..
219   bool ConnectedReadyForInput();
220 
221  private:
222   friend class InputStreamShim;
223   friend class OutputStreamShim;
224 
225   MOZ_MUST_USE nsresult Flush(uint32_t count, uint32_t *countRead);
226   void CreateShimError(nsresult code);
227 
228   nsCString mConnectString;
229   uint32_t mConnectStringOffset;
230 
231   nsAHttpConnection *mSession;
232   nsAHttpSegmentReader *mSegmentReader;
233 
234   UniquePtr<char[]> mInputData;
235   uint32_t mInputDataSize;
236   uint32_t mInputDataUsed;
237   uint32_t mInputDataOffset;
238 
239   UniquePtr<char[]> mOutputData;
240   uint32_t mOutputDataSize;
241   uint32_t mOutputDataUsed;
242   uint32_t mOutputDataOffset;
243 
244   bool mForcePlainText;
245   TimeStamp mTimestampSyn;
246   RefPtr<nsHttpConnectionInfo> mConnInfo;
247 
248   // mTunneledConn, mTunnelTransport, mTunnelStreamIn, mTunnelStreamOut
249   // are the connectors to the "real" http connection. They are created
250   // together when the tunnel setup is complete and a static reference is held
251   // for the lifetime of the tunnel.
252   RefPtr<nsHttpConnection> mTunneledConn;
253   RefPtr<SocketTransportShim> mTunnelTransport;
254   RefPtr<InputStreamShim> mTunnelStreamIn;
255   RefPtr<OutputStreamShim> mTunnelStreamOut;
256   RefPtr<nsHttpTransaction> mDrivingTransaction;
257 };
258 
259 }  // namespace net
260 }  // namespace mozilla
261 
262 #endif  // mozilla_net_TLSFilterTransaction_h
263