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