summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/TunnelUtils.h
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/protocol/http/TunnelUtils.h')
-rw-r--r--netwerk/protocol/http/TunnelUtils.h250
1 files changed, 250 insertions, 0 deletions
diff --git a/netwerk/protocol/http/TunnelUtils.h b/netwerk/protocol/http/TunnelUtils.h
new file mode 100644
index 000000000..20cfaf7ee
--- /dev/null
+++ b/netwerk/protocol/http/TunnelUtils.h
@@ -0,0 +1,250 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_net_TLSFilterTransaction_h
+#define mozilla_net_TLSFilterTransaction_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/UniquePtr.h"
+#include "nsAHttpTransaction.h"
+#include "nsIAsyncInputStream.h"
+#include "nsIAsyncOutputStream.h"
+#include "nsISocketTransport.h"
+#include "nsITimer.h"
+#include "NullHttpTransaction.h"
+#include "mozilla/TimeStamp.h"
+#include "prio.h"
+
+// a TLSFilterTransaction wraps another nsAHttpTransaction but
+// applies a encode/decode filter of TLS onto the ReadSegments
+// and WriteSegments data. It is not used for basic https://
+// but it is used for supplemental TLS tunnels - such as those
+// needed by CONNECT tunnels in HTTP/2 or even CONNECT tunnels when
+// the underlying proxy connection is already running TLS
+//
+// HTTP/2 CONNECT tunnels cannot use pushed IO layers because of
+// the multiplexing involved on the base stream. i.e. the base stream
+// once it is decrypted may have parts that are encrypted with a
+// variety of keys, or none at all
+
+/* ************************************************************************
+The input path of http over a spdy CONNECT tunnel once it is established as a stream
+
+note the "real http transaction" can be either a http/1 transaction or another spdy session
+inside the tunnel.
+
+ nsHttpConnection::OnInputStreamReady (real socket)
+ nsHttpConnection::OnSocketReadable()
+ SpdySession::WriteSegment()
+ SpdyStream::WriteSegment (tunnel stream)
+ SpdyConnectTransaction::WriteSegment
+ SpdyStream::OnWriteSegment(tunnel stream)
+ SpdySession::OnWriteSegment()
+ SpdySession::NetworkRead()
+ nsHttpConnection::OnWriteSegment (real socket)
+ realSocketIn->Read() return data from network
+
+now pop the stack back up to SpdyConnectTransaction::WriteSegment, the data
+that has been read is stored mInputData
+
+ SpdyConnectTransaction.mTunneledConn::OnInputStreamReady(mTunnelStreamIn)
+ SpdyConnectTransaction.mTunneledConn::OnSocketReadable()
+ TLSFilterTransaction::WriteSegment()
+ nsHttpTransaction::WriteSegment(real http transaction)
+ TLSFilterTransaction::OnWriteSegment() removes tls on way back up stack
+ SpdyConnectTransaction.mTunneledConn::OnWriteSegment()
+ SpdyConnectTransaction.mTunneledConn.mTunnelStreamIn->Read() // gets data from mInputData
+
+The output path works similarly:
+ nsHttpConnection::OnOutputStreamReady (real socket)
+ nsHttpConnection::OnSocketWritable()
+ SpdySession::ReadSegments (locates tunnel)
+ SpdyStream::ReadSegments (tunnel stream)
+ SpdyConnectTransaction::ReadSegments()
+ SpdyConnectTransaction.mTunneledConn::OnOutputStreamReady (tunnel connection)
+ SpdyConnectTransaction.mTunneledConn::OnSocketWritable (tunnel connection)
+ TLSFilterTransaction::ReadSegment()
+ nsHttpTransaction::ReadSegment (real http transaction generates plaintext on way down)
+ TLSFilterTransaction::OnReadSegment (BUF and LEN gets encrypted here on way down)
+ SpdyConnectTransaction.mTunneledConn::OnReadSegment (BUF and LEN) (tunnel connection)
+ SpdyConnectTransaction.mTunneledConn.mTunnelStreamOut->Write(BUF, LEN) .. get stored in mOutputData
+
+Now pop the stack back up to SpdyConnectTransaction::ReadSegment(), where it has
+the encrypted text available in mOutputData
+
+ SpdyStream->OnReadSegment(BUF,LEN) from mOutputData. Tunnel stream
+ SpdySession->OnReadSegment() // encrypted data gets put in a data frame
+ nsHttpConnection->OnReadSegment()
+ realSocketOut->write() writes data to network
+
+**************************************************************************/
+
+struct PRSocketOptionData;
+
+namespace mozilla { namespace net {
+
+class nsHttpRequestHead;
+class NullHttpTransaction;
+class TLSFilterTransaction;
+
+class NudgeTunnelCallback : public nsISupports
+{
+public:
+ virtual void OnTunnelNudged(TLSFilterTransaction *) = 0;
+};
+
+#define NS_DECL_NUDGETUNNELCALLBACK void OnTunnelNudged(TLSFilterTransaction *) override;
+
+class TLSFilterTransaction final
+ : public nsAHttpTransaction
+ , public nsAHttpSegmentReader
+ , public nsAHttpSegmentWriter
+ , public nsITimerCallback
+{
+ ~TLSFilterTransaction();
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSAHTTPTRANSACTION
+ NS_DECL_NSAHTTPSEGMENTREADER
+ NS_DECL_NSAHTTPSEGMENTWRITER
+ NS_DECL_NSITIMERCALLBACK
+
+ TLSFilterTransaction(nsAHttpTransaction *aWrappedTransaction,
+ const char *tlsHost, int32_t tlsPort,
+ nsAHttpSegmentReader *reader,
+ nsAHttpSegmentWriter *writer);
+
+ const nsAHttpTransaction *Transaction() const { return mTransaction.get(); }
+ nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment) override;
+ nsresult GetTransactionSecurityInfo(nsISupports **) override;
+ nsresult NudgeTunnel(NudgeTunnelCallback *callback);
+ nsresult SetProxiedTransaction(nsAHttpTransaction *aTrans);
+ void newIODriver(nsIAsyncInputStream *aSocketIn,
+ nsIAsyncOutputStream *aSocketOut,
+ nsIAsyncInputStream **outSocketIn,
+ nsIAsyncOutputStream **outSocketOut);
+
+ // nsAHttpTransaction overloads
+ nsHttpPipeline *QueryPipeline() override;
+ bool IsNullTransaction() override;
+ NullHttpTransaction *QueryNullTransaction() override;
+ nsHttpTransaction *QueryHttpTransaction() override;
+ SpdyConnectTransaction *QuerySpdyConnectTransaction() override;
+
+private:
+ nsresult StartTimerCallback();
+ void Cleanup();
+ int32_t FilterOutput(const char *aBuf, int32_t aAmount);
+ int32_t FilterInput(char *aBuf, int32_t aAmount);
+
+ static PRStatus GetPeerName(PRFileDesc *fd, PRNetAddr*addr);
+ static PRStatus GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data);
+ static PRStatus SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data);
+ static int32_t FilterWrite(PRFileDesc *fd, const void *buf, int32_t amount);
+ static int32_t FilterRead(PRFileDesc *fd, void *buf, int32_t amount);
+ static int32_t FilterSend(PRFileDesc *fd, const void *buf, int32_t amount, int flags,
+ PRIntervalTime timeout);
+ static int32_t FilterRecv(PRFileDesc *fd, void *buf, int32_t amount, int flags,
+ PRIntervalTime timeout);
+ static PRStatus FilterClose(PRFileDesc *fd);
+
+private:
+ RefPtr<nsAHttpTransaction> mTransaction;
+ nsCOMPtr<nsISupports> mSecInfo;
+ nsCOMPtr<nsITimer> mTimer;
+ RefPtr<NudgeTunnelCallback> mNudgeCallback;
+
+ // buffered network output, after encryption
+ UniquePtr<char[]> mEncryptedText;
+ uint32_t mEncryptedTextUsed;
+ uint32_t mEncryptedTextSize;
+
+ PRFileDesc *mFD;
+ nsAHttpSegmentReader *mSegmentReader;
+ nsAHttpSegmentWriter *mSegmentWriter;
+
+ nsresult mFilterReadCode;
+ bool mForce;
+ bool mReadSegmentBlocked;
+ uint32_t mNudgeCounter;
+};
+
+class SocketTransportShim;
+class InputStreamShim;
+class OutputStreamShim;
+class nsHttpConnection;
+
+class SpdyConnectTransaction final : public NullHttpTransaction
+{
+public:
+ SpdyConnectTransaction(nsHttpConnectionInfo *ci,
+ nsIInterfaceRequestor *callbacks,
+ uint32_t caps,
+ nsHttpTransaction *trans,
+ nsAHttpConnection *session);
+ ~SpdyConnectTransaction();
+
+ SpdyConnectTransaction *QuerySpdyConnectTransaction() override { return this; }
+
+ // A transaction is forced into plaintext when it is intended to be used as a CONNECT
+ // tunnel but the setup fails. The plaintext only carries the CONNECT error.
+ void ForcePlainText();
+ void MapStreamToHttpConnection(nsISocketTransport *aTransport,
+ nsHttpConnectionInfo *aConnInfo);
+
+ nsresult ReadSegments(nsAHttpSegmentReader *reader,
+ uint32_t count, uint32_t *countRead) override final;
+ nsresult WriteSegments(nsAHttpSegmentWriter *writer,
+ uint32_t count, uint32_t *countWritten) override final;
+ nsHttpRequestHead *RequestHead() override final;
+ void Close(nsresult reason) override final;
+
+ // ConnectedReadyForInput() tests whether the spdy connect transaction is attached to
+ // an nsHttpConnection that can properly deal with flow control, etc..
+ bool ConnectedReadyForInput();
+
+private:
+ friend class InputStreamShim;
+ friend class OutputStreamShim;
+
+ nsresult Flush(uint32_t count, uint32_t *countRead);
+ void CreateShimError(nsresult code);
+
+ nsCString mConnectString;
+ uint32_t mConnectStringOffset;
+
+ nsAHttpConnection *mSession;
+ nsAHttpSegmentReader *mSegmentReader;
+
+ UniquePtr<char[]> mInputData;
+ uint32_t mInputDataSize;
+ uint32_t mInputDataUsed;
+ uint32_t mInputDataOffset;
+
+ UniquePtr<char[]> mOutputData;
+ uint32_t mOutputDataSize;
+ uint32_t mOutputDataUsed;
+ uint32_t mOutputDataOffset;
+
+ bool mForcePlainText;
+ TimeStamp mTimestampSyn;
+ RefPtr<nsHttpConnectionInfo> mConnInfo;
+
+ // mTunneledConn, mTunnelTransport, mTunnelStreamIn, mTunnelStreamOut
+ // are the connectors to the "real" http connection. They are created
+ // together when the tunnel setup is complete and a static reference is held
+ // for the lifetime of the tunnel.
+ RefPtr<nsHttpConnection> mTunneledConn;
+ RefPtr<SocketTransportShim> mTunnelTransport;
+ RefPtr<InputStreamShim> mTunnelStreamIn;
+ RefPtr<OutputStreamShim> mTunnelStreamOut;
+ RefPtr<nsHttpTransaction> mDrivingTransaction;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_TLSFilterTransaction_h