зеркало из https://github.com/mozilla/gecko-dev.git
bug 378637 part 11 - proxy over TLS (i.e. https proxying) r=hurley
--HG-- extra : rebase_source : 8962538247666781e30eaa3b9673b857ec150204
This commit is contained in:
Родитель
4aec6b5f79
Коммит
f685e08634
|
@ -753,6 +753,7 @@ nsSocketTransport::nsSocketTransport()
|
|||
, mProxyPort(0)
|
||||
, mProxyTransparent(false)
|
||||
, mProxyTransparentResolvesHost(false)
|
||||
, mHttpsProxy(false)
|
||||
, mConnectionFlags(0)
|
||||
, mState(STATE_CLOSED)
|
||||
, mAttached(false)
|
||||
|
@ -783,13 +784,21 @@ nsSocketTransport::~nsSocketTransport()
|
|||
{
|
||||
SOCKET_LOG(("destroying nsSocketTransport @%p\n", this));
|
||||
|
||||
CleanupTypes();
|
||||
}
|
||||
|
||||
void
|
||||
nsSocketTransport::CleanupTypes()
|
||||
{
|
||||
// cleanup socket type info
|
||||
if (mTypes) {
|
||||
uint32_t i;
|
||||
for (i=0; i<mTypeCount; ++i)
|
||||
for (uint32_t i = 0; i < mTypeCount; ++i) {
|
||||
PL_strfree(mTypes[i]);
|
||||
}
|
||||
free(mTypes);
|
||||
mTypes = nullptr;
|
||||
}
|
||||
mTypeCount = 0;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -810,16 +819,22 @@ nsSocketTransport::Init(const char **types, uint32_t typeCount,
|
|||
mPort = port;
|
||||
mHost = host;
|
||||
|
||||
if (proxyInfo) {
|
||||
mHttpsProxy = proxyInfo->IsHTTPS();
|
||||
}
|
||||
|
||||
const char *proxyType = nullptr;
|
||||
if (proxyInfo) {
|
||||
mProxyPort = proxyInfo->Port();
|
||||
mProxyHost = proxyInfo->Host();
|
||||
// grab proxy type (looking for "socks" for example)
|
||||
proxyType = proxyInfo->Type();
|
||||
if (proxyType && (strcmp(proxyType, "http") == 0 ||
|
||||
strcmp(proxyType, "direct") == 0 ||
|
||||
strcmp(proxyType, "unknown") == 0))
|
||||
if (proxyType && (proxyInfo->IsHTTP() ||
|
||||
proxyInfo->IsHTTPS() ||
|
||||
proxyInfo->IsDirect() ||
|
||||
!strcmp(proxyType, "unknown"))) {
|
||||
proxyType = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SOCKET_LOG(("nsSocketTransport::Init [this=%p host=%s:%hu proxy=%s:%hu]\n",
|
||||
|
@ -1105,8 +1120,14 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, bool &proxyTransparent, bool &us
|
|||
if (i == 0) {
|
||||
// if this is the first type, we'll want the
|
||||
// service to allocate a new socket
|
||||
|
||||
// when https proxying we want to just connect to the proxy as if
|
||||
// it were the end host (i.e. expect the proxy's cert)
|
||||
|
||||
rv = provider->NewSocket(mNetAddr.raw.family,
|
||||
host, port, proxyHost, proxyPort,
|
||||
mHttpsProxy ? proxyHost : host,
|
||||
mHttpsProxy ? proxyPort : port,
|
||||
proxyHost, proxyPort,
|
||||
proxyFlags, &fd,
|
||||
getter_AddRefs(secinfo));
|
||||
|
||||
|
@ -1163,6 +1184,7 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, bool &proxyTransparent, bool &us
|
|||
}
|
||||
}
|
||||
|
||||
CleanupTypes();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
@ -150,6 +150,7 @@ public:
|
|||
protected:
|
||||
|
||||
virtual ~nsSocketTransport();
|
||||
void CleanupTypes();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -269,6 +270,7 @@ private:
|
|||
uint16_t mProxyPort;
|
||||
bool mProxyTransparent;
|
||||
bool mProxyTransparentResolvesHost;
|
||||
bool mHttpsProxy;
|
||||
uint32_t mConnectionFlags;
|
||||
|
||||
uint16_t SocketPort() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; }
|
||||
|
|
|
@ -28,6 +28,14 @@
|
|||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
ASpdySession::ASpdySession()
|
||||
{
|
||||
}
|
||||
|
||||
ASpdySession::~ASpdySession()
|
||||
{
|
||||
}
|
||||
|
||||
ASpdySession *
|
||||
ASpdySession::NewSpdySession(uint32_t version,
|
||||
nsISocketTransport *aTransport)
|
||||
|
@ -185,7 +193,6 @@ SpdyPushCache::RemovePushedStreamHttp2(nsCString key)
|
|||
mHashHttp2.Remove(key);
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -15,10 +15,16 @@ class nsISocketTransport;
|
|||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
class nsHttpConnectionInfo;
|
||||
|
||||
class ASpdySession : public nsAHttpTransaction
|
||||
{
|
||||
public:
|
||||
virtual bool AddStream(nsAHttpTransaction *, int32_t) = 0;
|
||||
ASpdySession();
|
||||
virtual ~ASpdySession();
|
||||
|
||||
virtual bool AddStream(nsAHttpTransaction *, int32_t,
|
||||
bool, nsIInterfaceRequestor *) = 0;
|
||||
virtual bool CanReuse() = 0;
|
||||
virtual bool RoomForMoreStreams() = 0;
|
||||
virtual PRIntervalTime IdleTime() = 0;
|
||||
|
|
|
@ -360,7 +360,9 @@ Http2Session::RegisterStreamID(Http2Stream *stream, uint32_t aNewID)
|
|||
|
||||
bool
|
||||
Http2Session::AddStream(nsAHttpTransaction *aHttpTransaction,
|
||||
int32_t aPriority)
|
||||
int32_t aPriority,
|
||||
bool aUseTunnel,
|
||||
nsIInterfaceRequestor *aCallbacks)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
|
@ -2879,6 +2881,7 @@ Http2Session::TransactionHasDataToWrite(nsAHttpTransaction *caller)
|
|||
this, stream->StreamID()));
|
||||
|
||||
mReadyForWrite.Push(stream);
|
||||
SetWriteCallbacks();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2928,10 +2931,17 @@ Http2Session::Classification()
|
|||
return mConnection->Classification();
|
||||
}
|
||||
|
||||
void
|
||||
Http2Session::GetSecurityCallbacks(nsIInterfaceRequestor **aOut)
|
||||
{
|
||||
*aOut = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// unused methods of nsAHttpTransaction
|
||||
// We can be sure of this because Http2Session is only constructed in
|
||||
// nsHttpConnection and is never passed out of that object
|
||||
// nsHttpConnection and is never passed out of that object or a TLSFilterTransaction
|
||||
// TLS tunnel
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
|
@ -2941,13 +2951,6 @@ Http2Session::SetConnection(nsAHttpConnection *)
|
|||
MOZ_ASSERT(false, "Http2Session::SetConnection()");
|
||||
}
|
||||
|
||||
void
|
||||
Http2Session::GetSecurityCallbacks(nsIInterfaceRequestor **)
|
||||
{
|
||||
// This is unexpected
|
||||
MOZ_ASSERT(false, "Http2Session::GetSecurityCallbacks()");
|
||||
}
|
||||
|
||||
void
|
||||
Http2Session::SetProxyConnectFailed()
|
||||
{
|
||||
|
|
|
@ -41,7 +41,8 @@ public:
|
|||
Http2Session(nsISocketTransport *);
|
||||
~Http2Session();
|
||||
|
||||
bool AddStream(nsAHttpTransaction *, int32_t);
|
||||
bool AddStream(nsAHttpTransaction *, int32_t,
|
||||
bool, nsIInterfaceRequestor *);
|
||||
bool CanReuse() { return !mShouldGoAway && !mClosed; }
|
||||
bool RoomForMoreStreams();
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
NS_IMPL_ISUPPORTS0(NullHttpTransaction)
|
||||
NS_IMPL_ISUPPORTS(NullHttpTransaction, nsISupportsWeakReference)
|
||||
|
||||
NullHttpTransaction::NullHttpTransaction(nsHttpConnectionInfo *ci,
|
||||
nsIInterfaceRequestor *callbacks,
|
||||
|
|
|
@ -21,7 +21,7 @@ class nsAHttpConnection;
|
|||
class nsHttpConnectionInfo;
|
||||
class nsHttpRequestHead;
|
||||
|
||||
class NullHttpTransaction MOZ_FINAL : public nsAHttpTransaction
|
||||
class NullHttpTransaction : public nsAHttpTransaction
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
@ -30,7 +30,7 @@ public:
|
|||
NullHttpTransaction(nsHttpConnectionInfo *ci,
|
||||
nsIInterfaceRequestor *callbacks,
|
||||
uint32_t caps);
|
||||
~NullHttpTransaction();
|
||||
virtual ~NullHttpTransaction();
|
||||
|
||||
// Overload of nsAHttpTransaction methods
|
||||
bool IsNullTransaction() MOZ_OVERRIDE MOZ_FINAL { return true; }
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "SpdyStream3.h"
|
||||
#include "PSpdyPush.h"
|
||||
#include "SpdyZlibReporter.h"
|
||||
#include "TunnelUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -334,7 +335,9 @@ SpdySession3::RegisterStreamID(SpdyStream3 *stream, uint32_t aNewID)
|
|||
|
||||
bool
|
||||
SpdySession3::AddStream(nsAHttpTransaction *aHttpTransaction,
|
||||
int32_t aPriority)
|
||||
int32_t aPriority,
|
||||
bool aUseTunnel,
|
||||
nsIInterfaceRequestor *aCallbacks)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
|
@ -345,23 +348,23 @@ SpdySession3::AddStream(nsAHttpTransaction *aHttpTransaction,
|
|||
return false;
|
||||
}
|
||||
|
||||
// assert that
|
||||
// a] in the case we have a connection, that the new transaction connection
|
||||
// is either undefined or on the same connection
|
||||
// b] in the case we don't have a connection, that the new transaction
|
||||
// connection is defined so we can adopt it
|
||||
MOZ_ASSERT((mConnection && (!aHttpTransaction->Connection() ||
|
||||
mConnection == aHttpTransaction->Connection())) ||
|
||||
(!mConnection && aHttpTransaction->Connection()));
|
||||
|
||||
if (!mConnection) {
|
||||
mConnection = aHttpTransaction->Connection();
|
||||
}
|
||||
|
||||
aHttpTransaction->SetConnection(this);
|
||||
|
||||
if (aUseTunnel) {
|
||||
LOG3(("SpdySession3::AddStream session=%p trans=%p OnTunnel",
|
||||
this, aHttpTransaction));
|
||||
DispatchOnTunnel(aHttpTransaction, aCallbacks);
|
||||
return true;
|
||||
}
|
||||
|
||||
SpdyStream3 *stream = new SpdyStream3(aHttpTransaction, this, aPriority);
|
||||
|
||||
LOG3(("SpdySession3::AddStream session=%p stream=%p NextID=0x%X (tentative)",
|
||||
this, stream, mNextStreamID));
|
||||
LOG3(("SpdySession3::AddStream session=%p stream=%p serial=%u "
|
||||
"NextID=0x%X (tentative)", this, stream, mSerial, mNextStreamID));
|
||||
|
||||
mStreamTransactionHash.Put(aHttpTransaction, stream);
|
||||
|
||||
|
@ -907,6 +910,10 @@ SpdySession3::CloseStream(SpdyStream3 *aStream, nsresult aResult)
|
|||
|
||||
RemoveStreamFromQueues(aStream);
|
||||
|
||||
if (aStream->IsTunnel()) {
|
||||
UnRegisterTunnel(aStream);
|
||||
}
|
||||
|
||||
// Send the stream the close() indication
|
||||
aStream->Close(aResult);
|
||||
}
|
||||
|
@ -1028,7 +1035,13 @@ SpdySession3::HandleSynStream(SpdySession3 *self)
|
|||
self->mPushedStreams.AppendElement(pushedStream);
|
||||
|
||||
// The pushed stream is unidirectional so it is fully open immediately
|
||||
pushedStream->SetFullyOpen();
|
||||
rv = pushedStream->SetFullyOpen();
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("SpdySession3::HandleSynStream pushedstream fully open failed\n"));
|
||||
self->CleanupStream(pushedStream, rv, RST_CANCEL);
|
||||
self->ResetDownstreamState();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Uncompress the response headers into a stream specific buffer, leaving them
|
||||
// in spdy format for the time being.
|
||||
|
@ -1101,10 +1114,10 @@ SpdySession3::HandleSynReply(SpdySession3 *self)
|
|||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
LOG3(("SpdySession3::HandleSynReply %p lookup via streamID in syn_reply.\n",
|
||||
self));
|
||||
uint32_t streamID =
|
||||
NetworkEndian::readUint32(self->mInputFrameBuffer + 2 * sizeof(uint32_t));
|
||||
LOG3(("SpdySession3::HandleSynReply %p lookup via streamID 0x%X in syn_reply.\n",
|
||||
self, streamID));
|
||||
nsresult rv = self->SetInputFrameDataStream(streamID);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
@ -1167,7 +1180,19 @@ SpdySession3::HandleSynReply(SpdySession3 *self)
|
|||
self->ResetDownstreamState();
|
||||
return NS_OK;
|
||||
}
|
||||
self->mInputFrameDataStream->SetFullyOpen();
|
||||
|
||||
rv = self->mInputFrameDataStream->SetFullyOpen();
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("SpdySession3::HandleSynReply SetFullyOpen failed\n"));
|
||||
if (self->mInputFrameDataStream->IsTunnel()) {
|
||||
gHttpHandler->ConnMgr()->CancelTransactions(
|
||||
self->mInputFrameDataStream->Transaction()->ConnectionInfo(),
|
||||
NS_ERROR_CONNECTION_REFUSED);
|
||||
}
|
||||
self->CleanupStream(self->mInputFrameDataStream, rv, RST_CANCEL);
|
||||
self->ResetDownstreamState();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
self->mInputFrameDataLast = self->mInputFrameBuffer[4] & kFlag_Data_FIN;
|
||||
self->mInputFrameDataStream->UpdateTransportReadEvents(self->mInputFrameDataSize);
|
||||
|
@ -1996,6 +2021,7 @@ SpdySession3::WriteSegments(nsAHttpSegmentWriter *writer,
|
|||
MOZ_ASSERT(!mNeedsCleanup, "cleanup stream set unexpectedly");
|
||||
mNeedsCleanup = nullptr; /* just in case */
|
||||
|
||||
SpdyStream3 *stream = mInputFrameDataStream;
|
||||
mSegmentWriter = writer;
|
||||
rv = mInputFrameDataStream->WriteSegments(this, count, countWritten);
|
||||
mSegmentWriter = nullptr;
|
||||
|
@ -2006,7 +2032,6 @@ SpdySession3::WriteSegments(nsAHttpSegmentWriter *writer,
|
|||
// This will happen when the transaction figures out it is EOF, generally
|
||||
// due to a content-length match being made. Return OK from this function
|
||||
// otherwise the whole session would be torn down.
|
||||
SpdyStream3 *stream = mInputFrameDataStream;
|
||||
|
||||
// if we were doing PROCESSING_COMPLETE_HEADERS need to pop the state
|
||||
// back to PROCESSING_DATA_FRAME where we came from
|
||||
|
@ -2020,8 +2045,8 @@ SpdySession3::WriteSegments(nsAHttpSegmentWriter *writer,
|
|||
this, stream, stream ? stream->StreamID() : 0,
|
||||
mNeedsCleanup, rv));
|
||||
CleanupStream(stream, NS_OK, RST_CANCEL);
|
||||
MOZ_ASSERT(!mNeedsCleanup, "double cleanup out of data frame");
|
||||
mNeedsCleanup = nullptr; /* just in case */
|
||||
MOZ_ASSERT(!mNeedsCleanup || mNeedsCleanup == stream);
|
||||
mNeedsCleanup = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2444,6 +2469,78 @@ SpdySession3::ConnectPushedStream(SpdyStream3 *stream)
|
|||
ForceRecv();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SpdySession3::FindTunnelCount(nsHttpConnectionInfo *aConnInfo)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
uint32_t rv = 0;
|
||||
mTunnelHash.Get(aConnInfo->HashKey(), &rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
SpdySession3::RegisterTunnel(SpdyStream3 *aTunnel)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
nsHttpConnectionInfo *ci = aTunnel->Transaction()->ConnectionInfo();
|
||||
uint32_t newcount = FindTunnelCount(ci) + 1;
|
||||
mTunnelHash.Remove(ci->HashKey());
|
||||
mTunnelHash.Put(ci->HashKey(), newcount);
|
||||
LOG3(("SpdySession3::RegisterTunnel %p stream=%p tunnels=%d [%s]",
|
||||
this, aTunnel, newcount, ci->HashKey().get()));
|
||||
}
|
||||
|
||||
void
|
||||
SpdySession3::UnRegisterTunnel(SpdyStream3 *aTunnel)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
nsHttpConnectionInfo *ci = aTunnel->Transaction()->ConnectionInfo();
|
||||
MOZ_ASSERT(FindTunnelCount(ci));
|
||||
uint32_t newcount = FindTunnelCount(ci) - 1;
|
||||
mTunnelHash.Remove(ci->HashKey());
|
||||
if (newcount) {
|
||||
mTunnelHash.Put(ci->HashKey(), newcount);
|
||||
}
|
||||
LOG3(("SpdySession3::UnRegisterTunnel %p stream=%p tunnels=%d [%s]",
|
||||
this, aTunnel, newcount, ci->HashKey().get()));
|
||||
}
|
||||
|
||||
void
|
||||
SpdySession3::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
|
||||
nsIInterfaceRequestor *aCallbacks)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
nsHttpTransaction *trans = aHttpTransaction->QueryHttpTransaction();
|
||||
nsHttpConnectionInfo *ci = aHttpTransaction->ConnectionInfo();
|
||||
MOZ_ASSERT(trans);
|
||||
|
||||
LOG3(("SpdySession3::DispatchOnTunnel %p trans=%p", this, trans));
|
||||
|
||||
aHttpTransaction->SetConnection(nullptr);
|
||||
|
||||
// this transaction has done its work of setting up a tunnel, let
|
||||
// the connection manager queue it if necessary
|
||||
trans->SetDontRouteViaWildCard(true);
|
||||
|
||||
if (FindTunnelCount(ci) < gHttpHandler->MaxConnectionsPerOrigin()) {
|
||||
LOG3(("SpdySession3::DispatchOnTunnel %p create on new tunnel %s",
|
||||
this, ci->HashKey().get()));
|
||||
nsRefPtr<SpdyConnectTransaction> connectTrans =
|
||||
new SpdyConnectTransaction(ci, aCallbacks,
|
||||
trans->Caps(), trans, this);
|
||||
AddStream(connectTrans, trans->Priority(),
|
||||
false, nullptr);
|
||||
SpdyStream3 *tunnel = mStreamTransactionHash.Get(connectTrans);
|
||||
MOZ_ASSERT(tunnel);
|
||||
RegisterTunnel(tunnel);
|
||||
}
|
||||
|
||||
// requeue it. The connection manager is responsible for actually putting
|
||||
// this on the tunnel connection with the specific ci now that it
|
||||
// has DontRouteViaWildCard set.
|
||||
gHttpHandler->InitiateTransaction(trans, trans->Priority());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Modified methods of nsAHttpConnection
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -2468,6 +2565,12 @@ SpdySession3::TransactionHasDataToWrite(nsAHttpTransaction *caller)
|
|||
this, stream->StreamID()));
|
||||
|
||||
mReadyForWrite.Push(stream);
|
||||
SetWriteCallbacks();
|
||||
|
||||
// NSPR poll will not poll the network if there are non system PR_FileDesc's
|
||||
// that are ready - so we can get into a deadlock waiting for the system IO
|
||||
// to come back here if we don't force the send loop manually.
|
||||
ForceSend();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2479,6 +2582,7 @@ SpdySession3::TransactionHasDataToWrite(SpdyStream3 *stream)
|
|||
|
||||
mReadyForWrite.Push(stream);
|
||||
SetWriteCallbacks();
|
||||
ForceSend();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2518,10 +2622,17 @@ SpdySession3::Classification()
|
|||
return mConnection->Classification();
|
||||
}
|
||||
|
||||
void
|
||||
SpdySession3::GetSecurityCallbacks(nsIInterfaceRequestor **aOut)
|
||||
{
|
||||
*aOut = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// unused methods of nsAHttpTransaction
|
||||
// We can be sure of this because SpdySession3 is only constructed in
|
||||
// nsHttpConnection and is never passed out of that object
|
||||
// nsHttpConnection and is never passed out of that object or a TLSFilterTransaction
|
||||
// TLS tunnel
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
|
@ -2531,13 +2642,6 @@ SpdySession3::SetConnection(nsAHttpConnection *)
|
|||
MOZ_ASSERT(false, "SpdySession3::SetConnection()");
|
||||
}
|
||||
|
||||
void
|
||||
SpdySession3::GetSecurityCallbacks(nsIInterfaceRequestor **)
|
||||
{
|
||||
// This is unexpected
|
||||
MOZ_ASSERT(false, "SpdySession3::GetSecurityCallbacks()");
|
||||
}
|
||||
|
||||
void
|
||||
SpdySession3::SetProxyConnectFailed()
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace mozilla { namespace net {
|
|||
|
||||
class SpdyPushedStream3;
|
||||
class SpdyStream3;
|
||||
class nsHttpTransaction;
|
||||
|
||||
class SpdySession3 MOZ_FINAL : public ASpdySession
|
||||
, public nsAHttpConnection
|
||||
|
@ -40,7 +41,8 @@ public:
|
|||
SpdySession3(nsISocketTransport *);
|
||||
~SpdySession3();
|
||||
|
||||
bool AddStream(nsAHttpTransaction *, int32_t);
|
||||
bool AddStream(nsAHttpTransaction *, int32_t,
|
||||
bool, nsIInterfaceRequestor *);
|
||||
bool CanReuse() { return !mShouldGoAway && !mClosed; }
|
||||
bool RoomForMoreStreams();
|
||||
|
||||
|
@ -382,6 +384,15 @@ private:
|
|||
// by the load group and the serial number can be used as part of the cache key
|
||||
// to make sure streams aren't shared across sessions.
|
||||
uint64_t mSerial;
|
||||
|
||||
private:
|
||||
/// connect tunnels
|
||||
void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);
|
||||
void RegisterTunnel(SpdyStream3 *);
|
||||
void UnRegisterTunnel(SpdyStream3 *);
|
||||
uint32_t FindTunnelCount(nsHttpConnectionInfo *);
|
||||
|
||||
nsDataHashtable<nsCStringHashKey, uint32_t> mTunnelHash;
|
||||
};
|
||||
|
||||
}} // namespace mozilla::net
|
||||
|
|
|
@ -338,7 +338,9 @@ SpdySession31::RegisterStreamID(SpdyStream31 *stream, uint32_t aNewID)
|
|||
|
||||
bool
|
||||
SpdySession31::AddStream(nsAHttpTransaction *aHttpTransaction,
|
||||
int32_t aPriority)
|
||||
int32_t aPriority,
|
||||
bool aUseTunnel,
|
||||
nsIInterfaceRequestor *aCallbacks)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
|
@ -2613,6 +2615,7 @@ SpdySession31::TransactionHasDataToWrite(nsAHttpTransaction *caller)
|
|||
this, stream->StreamID()));
|
||||
|
||||
mReadyForWrite.Push(stream);
|
||||
SetWriteCallbacks();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2663,10 +2666,17 @@ SpdySession31::Classification()
|
|||
return mConnection->Classification();
|
||||
}
|
||||
|
||||
void
|
||||
SpdySession31::GetSecurityCallbacks(nsIInterfaceRequestor **aOut)
|
||||
{
|
||||
*aOut = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// unused methods of nsAHttpTransaction
|
||||
// We can be sure of this because SpdySession31 is only constructed in
|
||||
// nsHttpConnection and is never passed out of that object
|
||||
// nsHttpConnection and is never passed out of that object or a TLSFilterTransaction
|
||||
// TLS tunnel
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
|
@ -2676,13 +2686,6 @@ SpdySession31::SetConnection(nsAHttpConnection *)
|
|||
MOZ_ASSERT(false, "SpdySession31::SetConnection()");
|
||||
}
|
||||
|
||||
void
|
||||
SpdySession31::GetSecurityCallbacks(nsIInterfaceRequestor **)
|
||||
{
|
||||
// This is unexpected
|
||||
MOZ_ASSERT(false, "SpdySession31::GetSecurityCallbacks()");
|
||||
}
|
||||
|
||||
void
|
||||
SpdySession31::SetProxyConnectFailed()
|
||||
{
|
||||
|
|
|
@ -39,7 +39,8 @@ public:
|
|||
SpdySession31(nsISocketTransport *);
|
||||
~SpdySession31();
|
||||
|
||||
bool AddStream(nsAHttpTransaction *, int32_t);
|
||||
bool AddStream(nsAHttpTransaction *, int32_t,
|
||||
bool, nsIInterfaceRequestor *);
|
||||
bool CanReuse() { return !mShouldGoAway && !mClosed; }
|
||||
bool RoomForMoreStreams();
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "SpdyStream3.h"
|
||||
#include "PSpdyPush.h"
|
||||
#include "SpdyZlibReporter.h"
|
||||
#include "TunnelUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -70,6 +71,7 @@ SpdyStream3::SpdyStream3(nsAHttpTransaction *httpTransaction,
|
|||
, mTotalSent(0)
|
||||
, mTotalRead(0)
|
||||
, mPushSource(nullptr)
|
||||
, mIsTunnel(false)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
|
@ -84,6 +86,7 @@ SpdyStream3::SpdyStream3(nsAHttpTransaction *httpTransaction,
|
|||
|
||||
SpdyStream3::~SpdyStream3()
|
||||
{
|
||||
ClearTransactionsBlockedOnTunnel();
|
||||
mStreamID = SpdySession3::kDeadStreamID;
|
||||
}
|
||||
|
||||
|
@ -114,7 +117,8 @@ SpdyStream3::ReadSegments(nsAHttpSegmentReader *reader,
|
|||
mSegmentReader = reader;
|
||||
rv = mTransaction->ReadSegments(this, count, countRead);
|
||||
mSegmentReader = nullptr;
|
||||
|
||||
LOG3(("SpdyStream3::ReadSegments %p trans readsegments rv %x read=%d\n",
|
||||
this, rv, *countRead));
|
||||
// Check to see if the transaction's request could be written out now.
|
||||
// If not, mark the stream for callback when writing can proceed.
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
|
@ -139,7 +143,8 @@ SpdyStream3::ReadSegments(nsAHttpSegmentReader *reader,
|
|||
if (!mBlockedOnRwin &&
|
||||
!mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
|
||||
LOG3(("SpdyStream3::ReadSegments %p 0x%X: Sending request data complete, "
|
||||
"mUpstreamState=%x",this, mStreamID, mUpstreamState));
|
||||
"mUpstreamState=%x finondata=%d",this, mStreamID,
|
||||
mUpstreamState, mSentFinOnData));
|
||||
if (mSentFinOnData) {
|
||||
ChangeState(UPSTREAM_COMPLETE);
|
||||
}
|
||||
|
@ -283,7 +288,7 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
|
|||
nsAutoCString hashkey;
|
||||
mTransaction->RequestHead()->GetHeader(nsHttp::Host, hostHeader);
|
||||
|
||||
CreatePushHashKey(NS_LITERAL_CSTRING("https"),
|
||||
CreatePushHashKey(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"),
|
||||
hostHeader, mSession->Serial(),
|
||||
mTransaction->RequestHead()->RequestURI(),
|
||||
mOrigin, hashkey);
|
||||
|
@ -458,24 +463,54 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
|
|||
// headers at this same level so it is not necessary to do so here.
|
||||
|
||||
const char *methodHeader = mTransaction->RequestHead()->Method().get();
|
||||
LOG3(("Stream method %p 0x%X %s\n", this, mStreamID, methodHeader));
|
||||
|
||||
// The header block length
|
||||
uint16_t count = hdrHash.Count() + 5; /* method, path, version, host, scheme */
|
||||
uint16_t count = hdrHash.Count() + 4; /* :method, :path, :version, :host */
|
||||
if (mTransaction->RequestHead()->IsConnect()) {
|
||||
mRequestBodyLenRemaining = 0x0fffffffffffffffULL;
|
||||
} else {
|
||||
++count; // :scheme used if not connect
|
||||
}
|
||||
CompressToFrame(count);
|
||||
|
||||
// :method, :path, :version comprise a HTTP/1 request line, so send those first
|
||||
// to make life easy for any gateways
|
||||
CompressToFrame(NS_LITERAL_CSTRING(":method"));
|
||||
CompressToFrame(methodHeader, strlen(methodHeader));
|
||||
|
||||
CompressToFrame(NS_LITERAL_CSTRING(":path"));
|
||||
CompressToFrame(mTransaction->RequestHead()->RequestURI());
|
||||
if (!mTransaction->RequestHead()->IsConnect()) {
|
||||
CompressToFrame(mTransaction->RequestHead()->RequestURI());
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
nsRefPtr<SpdyConnectTransaction> qiTrans(do_QueryObject(mTransaction));
|
||||
MOZ_ASSERT(qiTrans);
|
||||
#endif
|
||||
mIsTunnel = true;
|
||||
// Connect places host:port in :path. Don't use default port.
|
||||
nsHttpConnectionInfo *ci = mTransaction->ConnectionInfo();
|
||||
if (!ci) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
nsAutoCString route;
|
||||
route = ci->GetHost();
|
||||
route.AppendLiteral(":");
|
||||
route.AppendInt(ci->Port());
|
||||
CompressToFrame(route);
|
||||
}
|
||||
|
||||
CompressToFrame(NS_LITERAL_CSTRING(":version"));
|
||||
CompressToFrame(versionHeader);
|
||||
|
||||
CompressToFrame(NS_LITERAL_CSTRING(":host"));
|
||||
CompressToFrame(hostHeader);
|
||||
CompressToFrame(NS_LITERAL_CSTRING(":scheme"));
|
||||
CompressToFrame(NS_LITERAL_CSTRING("https"));
|
||||
|
||||
if (!mTransaction->RequestHead()->IsConnect()) {
|
||||
// no :scheme with connect
|
||||
CompressToFrame(NS_LITERAL_CSTRING(":scheme"));
|
||||
CompressToFrame(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"));
|
||||
}
|
||||
|
||||
hdrHash.Enumerate(hdrHashEnumerate, this);
|
||||
CompressFlushFrame();
|
||||
|
@ -490,9 +525,8 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
|
|||
// to wait for a data packet to put it on.
|
||||
|
||||
if (mTransaction->RequestHead()->IsGet() ||
|
||||
mTransaction->RequestHead()->IsConnect() ||
|
||||
mTransaction->RequestHead()->IsHead()) {
|
||||
// for GET, CONNECT, and HEAD place the fin bit right on the
|
||||
// for GET and HEAD place the fin bit right on the
|
||||
// syn stream packet
|
||||
|
||||
mSentFinOnData = 1;
|
||||
|
@ -500,6 +534,7 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
|
|||
}
|
||||
else if (mTransaction->RequestHead()->IsPost() ||
|
||||
mTransaction->RequestHead()->IsPut() ||
|
||||
mTransaction->RequestHead()->IsConnect() ||
|
||||
mTransaction->RequestHead()->IsOptions()) {
|
||||
// place fin in a data frame even for 0 length messages, I've seen
|
||||
// the google gateway be unhappy with fin-on-syn for 0 length POST
|
||||
|
@ -594,6 +629,9 @@ void
|
|||
SpdyStream3::UpdateTransportReadEvents(uint32_t count)
|
||||
{
|
||||
mTotalRead += count;
|
||||
if (!mSocketTransport) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTransaction->OnTransportStatus(mSocketTransport,
|
||||
NS_NET_STATUS_RECEIVING_FROM,
|
||||
|
@ -1246,6 +1284,12 @@ SpdyStream3::ConvertHeaders(nsACString &aHeadersOut)
|
|||
mDecompressBufferSize = 0;
|
||||
mDecompressBufferUsed = 0;
|
||||
|
||||
if (mIsTunnel) {
|
||||
aHeadersOut.Truncate();
|
||||
LOG(("SpdyStream3::ConvertHeaders %p 0x%X headers removed for tunnel\n",
|
||||
this, mStreamID));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1313,6 +1357,38 @@ SpdyStream3::CompressFlushFrame()
|
|||
ExecuteCompress(Z_SYNC_FLUSH);
|
||||
}
|
||||
|
||||
bool
|
||||
SpdyStream3::GetFullyOpen()
|
||||
{
|
||||
return mFullyOpen;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SpdyStream3::SetFullyOpen()
|
||||
{
|
||||
MOZ_ASSERT(!mFullyOpen);
|
||||
mFullyOpen = 1;
|
||||
if (mIsTunnel) {
|
||||
nsDependentCSubstring statusSubstring;
|
||||
nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"),
|
||||
statusSubstring);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCString status(statusSubstring);
|
||||
nsresult errcode;
|
||||
|
||||
if (status.ToInteger(&errcode) != 200) {
|
||||
LOG3(("SpdyStream3::SetFullyOpen %p Tunnel not 200", this));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LOG3(("SpdyStream3::SetFullyOpen %p Tunnel 200 OK", this));
|
||||
}
|
||||
|
||||
MapStreamToHttpConnection();
|
||||
ClearTransactionsBlockedOnTunnel();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream3::Close(nsresult reason)
|
||||
{
|
||||
|
@ -1396,11 +1472,15 @@ SpdyStream3::OnReadSegment(const char *buf,
|
|||
this, mStreamID, mRemoteWindow, dataLength));
|
||||
mRemoteWindow -= dataLength;
|
||||
|
||||
LOG3(("SpdyStream3 %p id %x request len remaining %d, "
|
||||
"count avail %d, chunk used %d",
|
||||
LOG3(("SpdyStream3 %p id %x request len remaining %u, "
|
||||
"count avail %u, chunk used %u",
|
||||
this, mStreamID, mRequestBodyLenRemaining, count, dataLength));
|
||||
if (dataLength > mRequestBodyLenRemaining)
|
||||
if (!dataLength && mRequestBodyLenRemaining) {
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
if (dataLength > mRequestBodyLenRemaining) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
mRequestBodyLenRemaining -= dataLength;
|
||||
GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining);
|
||||
ChangeState(SENDING_REQUEST_BODY);
|
||||
|
@ -1466,6 +1546,27 @@ SpdyStream3::OnWriteSegment(char *buf,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/// connect tunnels
|
||||
|
||||
void
|
||||
SpdyStream3::ClearTransactionsBlockedOnTunnel()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
if (!mIsTunnel) {
|
||||
return;
|
||||
}
|
||||
gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo());
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream3::MapStreamToHttpConnection()
|
||||
{
|
||||
nsRefPtr<SpdyConnectTransaction> qiTrans(do_QueryObject(mTransaction));
|
||||
MOZ_ASSERT(qiTrans);
|
||||
qiTrans->MapStreamToHttpConnection(mSocketTransport,
|
||||
mTransaction->ConnectionInfo());
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -39,13 +39,10 @@ public:
|
|||
return static_cast<bool>(mRequestBlockedOnRead);
|
||||
}
|
||||
|
||||
// returns false if called more than once
|
||||
bool GetFullyOpen() {return mFullyOpen;}
|
||||
void SetFullyOpen()
|
||||
{
|
||||
MOZ_ASSERT(!mFullyOpen);
|
||||
mFullyOpen = 1;
|
||||
}
|
||||
bool GetFullyOpen();
|
||||
// returns failure if stream cannot be made ready and stream
|
||||
// should be canceled
|
||||
nsresult SetFullyOpen();
|
||||
|
||||
bool HasRegisteredID() { return mStreamID != 0; }
|
||||
|
||||
|
@ -220,7 +217,8 @@ private:
|
|||
// place the fin flag on the last data packet instead of waiting
|
||||
// for a stream closed indication. Relying on stream close results
|
||||
// in an extra 0-length runt packet and seems to have some interop
|
||||
// problems with the google servers.
|
||||
// problems with the google servers. Connect does rely on stream
|
||||
// close by setting this to the max value.
|
||||
int64_t mRequestBodyLenRemaining;
|
||||
|
||||
// based on nsISupportsPriority definitions
|
||||
|
@ -253,6 +251,15 @@ private:
|
|||
|
||||
// For SpdyPush
|
||||
SpdyPushedStream3 *mPushSource;
|
||||
|
||||
/// connect tunnels
|
||||
public:
|
||||
bool IsTunnel() { return mIsTunnel; }
|
||||
private:
|
||||
void ClearTransactionsBlockedOnTunnel();
|
||||
void MapStreamToHttpConnection();
|
||||
|
||||
bool mIsTunnel;
|
||||
};
|
||||
|
||||
}} // namespace mozilla::net
|
||||
|
|
|
@ -288,7 +288,7 @@ SpdyStream31::ParseHttpRequestHeaders(const char *buf,
|
|||
nsAutoCString hashkey;
|
||||
mTransaction->RequestHead()->GetHeader(nsHttp::Host, hostHeader);
|
||||
|
||||
CreatePushHashKey(NS_LITERAL_CSTRING("https"),
|
||||
CreatePushHashKey(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"),
|
||||
hostHeader, mSession->Serial(),
|
||||
mTransaction->RequestHead()->RequestURI(),
|
||||
mOrigin, hashkey);
|
||||
|
@ -481,7 +481,7 @@ SpdyStream31::ParseHttpRequestHeaders(const char *buf,
|
|||
CompressToFrame(NS_LITERAL_CSTRING(":host"));
|
||||
CompressToFrame(hostHeader);
|
||||
CompressToFrame(NS_LITERAL_CSTRING(":scheme"));
|
||||
CompressToFrame(NS_LITERAL_CSTRING("https"));
|
||||
CompressToFrame(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"));
|
||||
|
||||
hdrHash.Enumerate(hdrHashEnumerate, this);
|
||||
CompressFlushFrame();
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,219 @@
|
|||
/* -*- 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 "nsAHttpTransaction.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsISocketTransport.h"
|
||||
#include "nsITimer.h"
|
||||
#include "NullHttpTransaction.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 TLSFilterTransaction;
|
||||
|
||||
class NudgeTunnelCallback : public nsISupports
|
||||
{
|
||||
public:
|
||||
virtual void OnTunnelNudged(TLSFilterTransaction *) = 0;
|
||||
};
|
||||
|
||||
#define NS_DECL_NUDGETUNNELCALLBACK void OnTunnelNudged(TLSFilterTransaction *);
|
||||
|
||||
class TLSFilterTransaction MOZ_FINAL
|
||||
: public nsAHttpTransaction
|
||||
, public nsAHttpSegmentReader
|
||||
, public nsAHttpSegmentWriter
|
||||
, public nsITimerCallback
|
||||
{
|
||||
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);
|
||||
~TLSFilterTransaction();
|
||||
|
||||
const nsAHttpTransaction *Transaction() const { return mTransaction.get(); }
|
||||
nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment);
|
||||
nsresult GetTransactionSecurityInfo(nsISupports **);
|
||||
nsresult NudgeTunnel(NudgeTunnelCallback *callback,
|
||||
nsAHttpSegmentReader *reader,
|
||||
nsAHttpSegmentWriter *writer);
|
||||
|
||||
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:
|
||||
nsRefPtr<nsAHttpTransaction> mTransaction;
|
||||
nsCOMPtr<nsISupports> mSecInfo;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsRefPtr<NudgeTunnelCallback> mNudgeCallback;
|
||||
|
||||
// buffered network output, after encryption
|
||||
nsAutoArrayPtr<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 ASpdySession;
|
||||
|
||||
class SpdyConnectTransaction MOZ_FINAL : public NullHttpTransaction
|
||||
{
|
||||
public:
|
||||
SpdyConnectTransaction(nsHttpConnectionInfo *ci,
|
||||
nsIInterfaceRequestor *callbacks,
|
||||
uint32_t caps,
|
||||
nsAHttpTransaction *trans,
|
||||
ASpdySession *session);
|
||||
~SpdyConnectTransaction();
|
||||
|
||||
void MapStreamToHttpConnection(nsISocketTransport *aTransport,
|
||||
nsHttpConnectionInfo *aConnInfo);
|
||||
|
||||
nsresult ReadSegments(nsAHttpSegmentReader *reader,
|
||||
uint32_t count, uint32_t *countRead) MOZ_OVERRIDE MOZ_FINAL;
|
||||
nsresult WriteSegments(nsAHttpSegmentWriter *writer,
|
||||
uint32_t count, uint32_t *countWritten) MOZ_OVERRIDE MOZ_FINAL;
|
||||
nsHttpRequestHead *RequestHead() MOZ_OVERRIDE MOZ_FINAL;
|
||||
void Close(nsresult reason) MOZ_OVERRIDE MOZ_FINAL;
|
||||
|
||||
private:
|
||||
friend class InputStreamShim;
|
||||
friend class OutputStreamShim;
|
||||
|
||||
nsresult Flush(uint32_t count, uint32_t *countRead);
|
||||
void CreateShimError(nsresult code);
|
||||
|
||||
nsCString mConnectString;
|
||||
uint32_t mConnectStringOffset;
|
||||
nsHttpRequestHead *mRequestHead;
|
||||
|
||||
ASpdySession *mSession;
|
||||
nsAHttpSegmentReader *mSegmentReader;
|
||||
|
||||
nsAutoArrayPtr<char> mInputData;
|
||||
uint32_t mInputDataSize;
|
||||
uint32_t mInputDataUsed;
|
||||
uint32_t mInputDataOffset;
|
||||
|
||||
nsAutoArrayPtr<char> mOutputData;
|
||||
uint32_t mOutputDataSize;
|
||||
uint32_t mOutputDataUsed;
|
||||
uint32_t mOutputDataOffset;
|
||||
|
||||
TimeStamp mTimestampSyn;
|
||||
nsRefPtr<nsHttpConnection> mTunneledConn;
|
||||
nsRefPtr<nsHttpConnectionInfo> mConnInfo;
|
||||
nsRefPtr<SocketTransportShim> mTunnelTransport;
|
||||
nsRefPtr<InputStreamShim> mTunnelStreamIn;
|
||||
nsRefPtr<OutputStreamShim> mTunnelStreamOut;
|
||||
};
|
||||
|
||||
}} // namespace mozilla::net
|
||||
|
||||
#endif // mozilla_net_TLSFilterTransaction_h
|
|
@ -78,6 +78,7 @@ SOURCES += [
|
|||
'SpdyStream3.cpp',
|
||||
'SpdyStream31.cpp',
|
||||
'SpdyZlibReporter.cpp',
|
||||
'TunnelUtils.cpp',
|
||||
]
|
||||
|
||||
# These files cannot be built in unified mode because of OS X headers.
|
||||
|
|
|
@ -48,8 +48,9 @@ public:
|
|||
virtual nsresult ResumeSend() = 0;
|
||||
virtual nsresult ResumeRecv() = 0;
|
||||
|
||||
// called by a transaction to force a "read from network" iteration
|
||||
// called by a transaction to force a "send/recv from network" iteration
|
||||
// even if not scheduled by socket associated with connection
|
||||
virtual nsresult ForceSend() = 0;
|
||||
virtual nsresult ForceRecv() = 0;
|
||||
|
||||
// After a connection has had ResumeSend() called by a transaction,
|
||||
|
@ -180,6 +181,12 @@ public:
|
|||
return NS_ERROR_FAILURE; \
|
||||
return (fwdObject)->ResumeRecv(); \
|
||||
} \
|
||||
nsresult ForceSend() \
|
||||
{ \
|
||||
if (!(fwdObject)) \
|
||||
return NS_ERROR_FAILURE; \
|
||||
return (fwdObject)->ForceSend(); \
|
||||
} \
|
||||
nsresult ForceRecv() \
|
||||
{ \
|
||||
if (!(fwdObject)) \
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "nsISupports.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsIInterfaceRequestor;
|
||||
class nsIEventTarget;
|
||||
|
@ -32,7 +33,7 @@ class nsHttpConnectionInfo;
|
|||
// write function returns NS_BASE_STREAM_WOULD_BLOCK in this case).
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class nsAHttpTransaction : public nsISupports
|
||||
class nsAHttpTransaction : public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
// called by the connection when it takes ownership of the transaction.
|
||||
|
@ -162,6 +163,17 @@ public:
|
|||
|
||||
CLASS_MAX
|
||||
};
|
||||
|
||||
// conceptually the security info is part of the connection, but sometimes
|
||||
// in the case of TLS tunneled within TLS the transaction might present
|
||||
// a more specific security info that cannot be represented as a layer in
|
||||
// the connection due to multiplexing. This interface represents such an
|
||||
// overload. If it returns NS_FAILURE the connection should be considered
|
||||
// authoritative.
|
||||
virtual nsresult GetTransactionSecurityInfo(nsISupports **)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
};
|
||||
|
||||
#define NS_DECL_NSAHTTPTRANSACTION \
|
||||
|
@ -175,12 +187,12 @@ public:
|
|||
uint32_t Caps(); \
|
||||
void SetDNSWasRefreshed(); \
|
||||
uint64_t Available(); \
|
||||
nsresult ReadSegments(nsAHttpSegmentReader *, uint32_t, uint32_t *); \
|
||||
nsresult WriteSegments(nsAHttpSegmentWriter *, uint32_t, uint32_t *); \
|
||||
virtual nsresult ReadSegments(nsAHttpSegmentReader *, uint32_t, uint32_t *); \
|
||||
virtual nsresult WriteSegments(nsAHttpSegmentWriter *, uint32_t, uint32_t *); \
|
||||
void Close(nsresult reason); \
|
||||
nsHttpConnectionInfo *ConnectionInfo(); \
|
||||
void SetProxyConnectFailed(); \
|
||||
nsHttpRequestHead *RequestHead(); \
|
||||
virtual nsHttpRequestHead *RequestHead(); \
|
||||
uint32_t Http1xTransactionCount(); \
|
||||
nsresult TakeSubTransactions(nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions); \
|
||||
nsresult AddTransaction(nsAHttpTransaction *); \
|
||||
|
|
|
@ -86,5 +86,6 @@ HTTP_ATOM(Version, "Version")
|
|||
HTTP_ATOM(WWW_Authenticate, "WWW-Authenticate")
|
||||
HTTP_ATOM(Warning, "Warning")
|
||||
HTTP_ATOM(X_Firefox_Spdy, "X-Firefox-Spdy")
|
||||
HTTP_ATOM(X_Firefox_Spdy_Proxy, "X-Firefox-Spdy-Proxy")
|
||||
|
||||
// methods are case sensitive and do not use atom table
|
||||
|
|
|
@ -13,25 +13,25 @@
|
|||
#undef LOG_ENABLED
|
||||
#define LOG_ENABLED() LOG5_ENABLED()
|
||||
|
||||
#include "ASpdySession.h"
|
||||
#include "mozilla/ChaosMode.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsHttpConnection.h"
|
||||
#include "nsHttpHandler.h"
|
||||
#include "nsHttpPipeline.h"
|
||||
#include "nsHttpRequestHead.h"
|
||||
#include "nsHttpResponseHead.h"
|
||||
#include "nsHttpHandler.h"
|
||||
#include "nsIOService.h"
|
||||
#include "nsISocketTransport.h"
|
||||
#include "nsSocketTransportService2.h"
|
||||
#include "nsISSLSocketControl.h"
|
||||
#include "sslt.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "nsPreloadedStream.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsSocketTransport2.h"
|
||||
#include "nsPreloadedStream.h"
|
||||
#include "ASpdySession.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "nsHttpPipeline.h"
|
||||
#include <algorithm>
|
||||
#include "mozilla/ChaosMode.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "sslt.h"
|
||||
#include "TunnelUtils.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
// defined by the socket transport service while active
|
||||
|
@ -55,6 +55,7 @@ nsHttpConnection::nsHttpConnection()
|
|||
, mMaxBytesRead(0)
|
||||
, mTotalBytesRead(0)
|
||||
, mTotalBytesWritten(0)
|
||||
, mContentBytesWritten(0)
|
||||
, mConnectedTransport(false)
|
||||
, mKeepAlive(true) // assume to keep-alive by default
|
||||
, mKeepAliveMask(true)
|
||||
|
@ -66,6 +67,7 @@ nsHttpConnection::nsHttpConnection()
|
|||
, mIdleMonitoring(false)
|
||||
, mProxyConnectInProgress(false)
|
||||
, mExperienced(false)
|
||||
, mInSpdyTunnel(false)
|
||||
, mHttp1xTransactionCount(0)
|
||||
, mRemainingConnectionUses(0xffffffff)
|
||||
, mClassification(nsAHttpTransaction::CLASS_GENERAL)
|
||||
|
@ -121,13 +123,7 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info,
|
|||
nsIInterfaceRequestor *callbacks,
|
||||
PRIntervalTime rtt)
|
||||
{
|
||||
MOZ_ASSERT(transport && instream && outstream,
|
||||
"invalid socket information");
|
||||
LOG(("nsHttpConnection::Init [this=%p "
|
||||
"transport=%p instream=%p outstream=%p rtt=%d]\n",
|
||||
this, transport, instream, outstream,
|
||||
PR_IntervalToMilliseconds(rtt)));
|
||||
|
||||
LOG(("nsHttpConnection::Init this=%p", this));
|
||||
NS_ENSURE_ARG_POINTER(info);
|
||||
NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
|
||||
|
||||
|
@ -142,13 +138,12 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info,
|
|||
mSocketTransport = transport;
|
||||
mSocketIn = instream;
|
||||
mSocketOut = outstream;
|
||||
nsresult rv = mSocketTransport->SetEventSink(this, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// See explanation for non-strictness of this operation in SetSecurityCallbacks.
|
||||
mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(callbacks, false);
|
||||
rv = mSocketTransport->SetSecurityCallbacks(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSocketTransport->SetEventSink(this, nullptr);
|
||||
mSocketTransport->SetSecurityCallbacks(this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -163,6 +158,11 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
|||
mUsingSpdyVersion = spdyVersion;
|
||||
mEverUsedSpdy = true;
|
||||
|
||||
if (!mReportedSpdy) {
|
||||
mReportedSpdy = true;
|
||||
gHttpHandler->ConnMgr()->ReportSpdyConnection(this, true);
|
||||
}
|
||||
|
||||
// Setting the connection as reused allows some transactions that fail
|
||||
// with NS_ERROR_NET_RESET to be restarted and SPDY uses that code
|
||||
// to handle clean rejections (such as those that arrived after
|
||||
|
@ -197,22 +197,39 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
|||
return;
|
||||
}
|
||||
|
||||
if (NeedSpdyTunnel()) {
|
||||
LOG3(("nsHttpConnection::StartSpdy %p Connecting To a HTTP/2 "
|
||||
"Proxy and Need Connect", this));
|
||||
MOZ_ASSERT(mProxyConnectStream);
|
||||
|
||||
mProxyConnectStream = nullptr;
|
||||
mCompletedProxyConnect = true;
|
||||
mProxyConnectInProgress = false;
|
||||
}
|
||||
|
||||
mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport);
|
||||
bool spdyProxy = mConnInfo->UsingHttpsProxy() && !mTLSFilter;
|
||||
if (spdyProxy) {
|
||||
nsRefPtr<nsHttpConnectionInfo> wildCardProxyCi;
|
||||
mConnInfo->CreateWildCard(getter_AddRefs(wildCardProxyCi));
|
||||
gHttpHandler->ConnMgr()->MoveToWildCardConnEntry(mConnInfo,
|
||||
wildCardProxyCi, this);
|
||||
mConnInfo = wildCardProxyCi;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) { // includes NS_ERROR_NOT_IMPLEMENTED
|
||||
MOZ_ASSERT(list.IsEmpty(), "sub transaction list not empty");
|
||||
|
||||
// This is ok - treat mTransaction as a single real request.
|
||||
// Wrap the old http transaction into the new spdy session
|
||||
// as the first stream.
|
||||
if (!mSpdySession->AddStream(mTransaction, mPriority)) {
|
||||
MOZ_ASSERT(false); // this cannot happen!
|
||||
mTransaction->Close(NS_ERROR_ABORT);
|
||||
rv = AddTransaction(mTransaction, mPriority);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
LOG(("nsHttpConnection::StartSpdy moves single transaction %p "
|
||||
"into SpdySession %p\n", mTransaction.get(), mSpdySession.get()));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
int32_t count = list.Length();
|
||||
|
||||
LOG(("nsHttpConnection::StartSpdy moving transaction list len=%d "
|
||||
|
@ -224,11 +241,8 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
|||
}
|
||||
|
||||
for (int32_t index = 0; index < count; ++index) {
|
||||
// AddStream() cannot fail
|
||||
if (!mSpdySession->AddStream(list[index], mPriority)) {
|
||||
MOZ_ASSERT(false, "SpdySession::AddStream failed");
|
||||
LOG(("SpdySession::AddStream failed\n"));
|
||||
mTransaction->Close(NS_ERROR_ABORT);
|
||||
rv = AddTransaction(list[index], mPriority);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -236,14 +250,19 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
|||
|
||||
// Disable TCP Keepalives - use SPDY ping instead.
|
||||
rv = DisableTCPKeepalives();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("nsHttpConnection::StartSpdy [%p] DisableTCPKeepalives failed "
|
||||
"rv[0x%x]", this, rv));
|
||||
}
|
||||
|
||||
mSupportsPipelining = false; // dont use http/1 pipelines with spdy
|
||||
mTransaction = mSpdySession;
|
||||
mSupportsPipelining = false; // don't use http/1 pipelines with spdy
|
||||
mIdleTimeout = gHttpHandler->SpdyTimeout();
|
||||
|
||||
if (!mTLSFilter) {
|
||||
mTransaction = mSpdySession;
|
||||
} else {
|
||||
mTLSFilter->AddTransaction(mSpdySession);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -259,18 +278,19 @@ nsHttpConnection::EnsureNPNComplete()
|
|||
return true;
|
||||
}
|
||||
|
||||
if (mNPNComplete)
|
||||
if (mNPNComplete) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
nsCOMPtr<nsISSLSocketControl> ssl;
|
||||
nsAutoCString negotiatedNPN;
|
||||
|
||||
rv = mSocketTransport->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (NS_FAILED(rv))
|
||||
GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (!securityInfo) {
|
||||
goto npnComplete;
|
||||
}
|
||||
|
||||
ssl = do_QueryInterface(securityInfo, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -278,28 +298,30 @@ nsHttpConnection::EnsureNPNComplete()
|
|||
|
||||
rv = ssl->GetNegotiatedNPN(negotiatedNPN);
|
||||
if (rv == NS_ERROR_NOT_CONNECTED) {
|
||||
|
||||
// By writing 0 bytes to the socket the SSL handshake machine is
|
||||
// pushed forward.
|
||||
uint32_t count = 0;
|
||||
rv = mSocketOut->Write("", 0, &count);
|
||||
|
||||
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK)
|
||||
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
goto npnComplete;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv)) {
|
||||
goto npnComplete;
|
||||
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete %p [%s] negotiated to '%s'\n",
|
||||
this, mConnInfo->Host(), negotiatedNPN.get()));
|
||||
}
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete %p [%s] negotiated to '%s'%s\n",
|
||||
this, mConnInfo->HashKey().get(), negotiatedNPN.get(),
|
||||
mTLSFilter ? " [Double Tunnel]" : ""));
|
||||
|
||||
uint8_t spdyVersion;
|
||||
rv = gHttpHandler->SpdyInfo()->GetNPNVersionIndex(negotiatedNPN,
|
||||
&spdyVersion);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
StartSpdy(spdyVersion);
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy());
|
||||
|
||||
|
@ -309,6 +331,18 @@ npnComplete:
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::OnTunnelNudged(TLSFilterTransaction *trans)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
LOG(("nsHttpConnection::OnTunnelNudged %p\n", this));
|
||||
if (trans != mTLSFilter) {
|
||||
return;
|
||||
}
|
||||
LOG(("nsHttpConnection::OnTunnelNudged %p Calling OnSocketWritable\n", this));
|
||||
OnSocketWritable();
|
||||
}
|
||||
|
||||
// called on the socket thread
|
||||
nsresult
|
||||
nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri)
|
||||
|
@ -322,8 +356,9 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri
|
|||
|
||||
mTransactionCaps = caps;
|
||||
mPriority = pri;
|
||||
if (mTransaction && mUsingSpdyVersion)
|
||||
if (mTransaction && mUsingSpdyVersion) {
|
||||
return AddTransaction(trans, pri);
|
||||
}
|
||||
|
||||
NS_ENSURE_ARG_POINTER(trans);
|
||||
NS_ENSURE_TRUE(!mTransaction, NS_ERROR_IN_PROGRESS);
|
||||
|
@ -355,8 +390,7 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri
|
|||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
trans->GetSecurityCallbacks(getter_AddRefs(callbacks));
|
||||
SetSecurityCallbacks(callbacks);
|
||||
|
||||
SetupSSL(caps);
|
||||
SetupSSL();
|
||||
|
||||
// take ownership of the transaction
|
||||
mTransaction = trans;
|
||||
|
@ -387,12 +421,17 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri
|
|||
mTransaction->ResponseTimeoutEnabled();
|
||||
|
||||
rv = StartShortLivedTCPKeepalives();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("nsHttpConnection::Activate [%p] "
|
||||
"StartShortLivedTCPKeepalives failed rv[0x%x]",
|
||||
this, rv));
|
||||
}
|
||||
|
||||
if (mTLSFilter) {
|
||||
mTLSFilter->AddTransaction(trans);
|
||||
mTransaction = mTLSFilter;
|
||||
}
|
||||
|
||||
rv = OnOutputStreamReady(mSocketOut);
|
||||
|
||||
failed_activation:
|
||||
|
@ -404,9 +443,10 @@ failed_activation:
|
|||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::SetupSSL(uint32_t caps)
|
||||
nsHttpConnection::SetupSSL()
|
||||
{
|
||||
LOG(("nsHttpConnection::SetupSSL %p caps=0x%X\n", this, caps));
|
||||
LOG(("nsHttpConnection::SetupSSL %p caps=0x%X %s\n",
|
||||
this, mTransactionCaps,mConnInfo->HashKey().get()));
|
||||
|
||||
if (mSetupSSLCalled) // do only once
|
||||
return;
|
||||
|
@ -419,27 +459,23 @@ nsHttpConnection::SetupSSL(uint32_t caps)
|
|||
// of this function
|
||||
mNPNComplete = true;
|
||||
|
||||
if (!mConnInfo->EndToEndSSL())
|
||||
if (!mConnInfo->FirstHopSSL()) {
|
||||
return;
|
||||
|
||||
LOG(("nsHttpConnection::SetupSSL Setting up "
|
||||
"Next Protocol Negotiation"));
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
nsresult rv =
|
||||
mSocketTransport->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(securityInfo, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
if (caps & NS_HTTP_ALLOW_RSA_FALSESTART) {
|
||||
LOG(("nsHttpConnection::SetupSSL %p "
|
||||
">= RSA Key Exchange Expected\n", this));
|
||||
ssl->SetKEAExpected(ssl_kea_rsa);
|
||||
}
|
||||
|
||||
// if we are connected to the proxy with TLS, start the TLS
|
||||
// flow immediately without waiting for a CONNECT sequence.
|
||||
if (mInSpdyTunnel) {
|
||||
InitSSLParams(false, true);
|
||||
} else {
|
||||
bool usingHttpsProxy = mConnInfo->UsingHttpsProxy();
|
||||
InitSSLParams(usingHttpsProxy, usingHttpsProxy);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::SetupNPNList(nsISSLSocketControl *ssl, uint32_t caps)
|
||||
{
|
||||
nsTArray<nsCString> protocolArray;
|
||||
|
||||
// The first protocol is used as the fallback if none of the
|
||||
|
@ -458,32 +494,41 @@ nsHttpConnection::SetupSSL(uint32_t caps)
|
|||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(ssl->SetNPNList(protocolArray))) {
|
||||
LOG(("nsHttpConnection::Init Setting up SPDY Negotiation OK"));
|
||||
mNPNComplete = false;
|
||||
}
|
||||
nsresult rv = ssl->SetNPNList(protocolArray);
|
||||
LOG(("nsHttpConnection::SetupNPNList %p %x\n",this, rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::AddTransaction(nsAHttpTransaction *httpTransaction,
|
||||
int32_t priority)
|
||||
{
|
||||
LOG(("nsHttpConnection::AddTransaction for SPDY"));
|
||||
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
MOZ_ASSERT(mSpdySession && mUsingSpdyVersion,
|
||||
"AddTransaction to live http connection without spdy");
|
||||
MOZ_ASSERT(mTransaction,
|
||||
"AddTransaction to idle http connection");
|
||||
|
||||
if (!mSpdySession->AddStream(httpTransaction, priority)) {
|
||||
MOZ_ASSERT(false, "AddStream should never fail due to"
|
||||
"RoomForMore() admission check");
|
||||
// If this is a wild card nshttpconnection (i.e. a spdy proxy) then
|
||||
// it is important to start the stream using the specific connection
|
||||
// info of the transaction to ensure it is routed on the right tunnel
|
||||
|
||||
nsHttpConnectionInfo *transCI = httpTransaction->ConnectionInfo();
|
||||
|
||||
bool needTunnel = transCI->UsingHttpsProxy();
|
||||
needTunnel = needTunnel && !mTLSFilter;
|
||||
needTunnel = needTunnel && transCI->UsingConnect();
|
||||
needTunnel = needTunnel && httpTransaction->QueryHttpTransaction();
|
||||
|
||||
LOG(("nsHttpConnection::AddTransaction for SPDY%s",
|
||||
needTunnel ? " over tunnel" : ""));
|
||||
|
||||
if (!mSpdySession->AddStream(httpTransaction, priority,
|
||||
needTunnel, mCallbacks)) {
|
||||
MOZ_ASSERT(false); // this cannot happen!
|
||||
httpTransaction->Close(NS_ERROR_ABORT);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ResumeSend();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -504,6 +549,8 @@ nsHttpConnection::Close(nsresult reason)
|
|||
if (mIdleMonitoring)
|
||||
EndIdleMonitoring();
|
||||
|
||||
mTLSFilter = nullptr;
|
||||
|
||||
if (mSocketTransport) {
|
||||
mSocketTransport->SetEventSink(nullptr, nullptr);
|
||||
|
||||
|
@ -536,19 +583,48 @@ nsHttpConnection::Close(nsresult reason)
|
|||
|
||||
// called on the socket thread
|
||||
nsresult
|
||||
nsHttpConnection::ProxyStartSSL()
|
||||
nsHttpConnection::InitSSLParams(bool connectingToProxy, bool proxyStartSSL)
|
||||
{
|
||||
LOG(("nsHttpConnection::ProxyStartSSL [this=%p]\n", this));
|
||||
LOG(("nsHttpConnection::InitSSLParams [this=%p] connectingToProxy=%d\n",
|
||||
this, connectingToProxy));
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
nsresult rv = mSocketTransport->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (!securityInfo) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(securityInfo, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (NS_FAILED(rv)){
|
||||
return rv;
|
||||
}
|
||||
|
||||
return ssl->ProxyStartSSL();
|
||||
if (proxyStartSSL) {
|
||||
rv = ssl->ProxyStartSSL();
|
||||
if (NS_FAILED(rv)){
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(SetupNPNList(ssl, mTransactionCaps))) {
|
||||
LOG(("InitSSLParams Setting up SPDY Negotiation OK"));
|
||||
mNPNComplete = false;
|
||||
}
|
||||
|
||||
// transaction caps apply only to origin. we don't track
|
||||
// proxy history.
|
||||
if (!connectingToProxy &&
|
||||
(mTransactionCaps & NS_HTTP_ALLOW_RSA_FALSESTART)) {
|
||||
LOG(("nsHttpConnection::InitSSLParams %p "
|
||||
">= RSA Key Exchange Expected\n", this));
|
||||
ssl->SetKEAExpected(ssl_kea_rsa);
|
||||
} else {
|
||||
ssl->SetKEAExpected(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -654,7 +730,7 @@ nsHttpConnection::IsAlive()
|
|||
|
||||
// SocketTransport::IsAlive can run the SSL state machine, so make sure
|
||||
// the NPN options are set before that happens.
|
||||
SetupSSL(mTransactionCaps);
|
||||
SetupSSL();
|
||||
|
||||
bool alive;
|
||||
nsresult rv = mSocketTransport->IsAlive(&alive);
|
||||
|
@ -746,6 +822,11 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
NS_ENSURE_ARG_POINTER(trans);
|
||||
MOZ_ASSERT(responseHead, "No response head?");
|
||||
|
||||
if (mInSpdyTunnel) {
|
||||
responseHead->SetHeader(nsHttp::X_Firefox_Spdy_Proxy,
|
||||
NS_LITERAL_CSTRING("true"));
|
||||
}
|
||||
|
||||
// we won't change our keep-alive policy unless the server has explicitly
|
||||
// told us to do so.
|
||||
|
||||
|
@ -892,16 +973,21 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
if (mProxyConnectStream) {
|
||||
MOZ_ASSERT(!mUsingSpdyVersion,
|
||||
"SPDY NPN Complete while using proxy connect stream");
|
||||
mProxyConnectStream = 0;
|
||||
mProxyConnectStream = nullptr;
|
||||
if (responseStatus == 200) {
|
||||
LOG(("proxy CONNECT succeeded! endtoendssl=%s\n",
|
||||
mConnInfo->EndToEndSSL() ? "true" :"false"));
|
||||
*reset = true;
|
||||
nsresult rv;
|
||||
if (mConnInfo->EndToEndSSL()) {
|
||||
rv = ProxyStartSSL();
|
||||
if (NS_FAILED(rv)) // XXX need to handle this for real
|
||||
LOG(("ProxyStartSSL failed [rv=%x]\n", rv));
|
||||
if (mConnInfo->UsingHttpsProxy()) {
|
||||
LOG(("%p new TLSFilterTransaction %s %d\n",
|
||||
this, mConnInfo->Host(), mConnInfo->Port()));
|
||||
SetupSecondaryTLS();
|
||||
}
|
||||
|
||||
rv = InitSSLParams(false, true);
|
||||
LOG(("InitSSLParams [rv=%x]\n", rv));
|
||||
}
|
||||
mCompletedProxyConnect = true;
|
||||
mProxyConnectInProgress = false;
|
||||
|
@ -988,7 +1074,7 @@ nsHttpConnection::TakeTransport(nsISocketTransport **aTransport,
|
|||
nsresult rv = StartLongLivedTCPKeepalives();
|
||||
LOG(("nsHttpConnection::TakeTransport [%p] calling "
|
||||
"StartLongLivedTCPKeepalives", this));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("nsHttpConnection::TakeTransport [%p] "
|
||||
"StartLongLivedTCPKeepalives failed rv[0x%x]", this, rv));
|
||||
}
|
||||
|
@ -1123,7 +1209,7 @@ nsHttpConnection::UpdateTCPKeepalive(nsITimer *aTimer, void *aClosure)
|
|||
}
|
||||
|
||||
nsresult rv = self->StartLongLivedTCPKeepalives();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("nsHttpConnection::UpdateTCPKeepalive [%p] "
|
||||
"StartLongLivedTCPKeepalives failed rv[0x%x]",
|
||||
self, rv));
|
||||
|
@ -1134,11 +1220,25 @@ void
|
|||
nsHttpConnection::GetSecurityInfo(nsISupports **secinfo)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
LOG(("nsHttpConnection::GetSecurityInfo trans=%p tlsfilter=%p socket=%p\n",
|
||||
mTransaction.get(), mTLSFilter.get(), mSocketTransport.get()));
|
||||
|
||||
if (mSocketTransport) {
|
||||
if (NS_FAILED(mSocketTransport->GetSecurityInfo(secinfo)))
|
||||
*secinfo = nullptr;
|
||||
if (mTransaction &&
|
||||
NS_SUCCEEDED(mTransaction->GetTransactionSecurityInfo(secinfo))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTLSFilter &&
|
||||
NS_SUCCEEDED(mTLSFilter->GetTransactionSecurityInfo(secinfo))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSocketTransport &&
|
||||
NS_SUCCEEDED(mSocketTransport->GetSecurityInfo(secinfo))) {
|
||||
return;
|
||||
}
|
||||
|
||||
*secinfo = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1203,22 +1303,30 @@ nsHttpConnection::ResumeRecv()
|
|||
}
|
||||
|
||||
|
||||
class nsHttpConnectionForceRecv : public nsRunnable
|
||||
class nsHttpConnectionForceIO : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsHttpConnectionForceRecv(nsHttpConnection *aConn)
|
||||
: mConn(aConn) {}
|
||||
nsHttpConnectionForceIO(nsHttpConnection *aConn, bool doRecv)
|
||||
: mConn(aConn)
|
||||
, mDoRecv(doRecv)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
if (!mConn->mSocketIn)
|
||||
if (mDoRecv) {
|
||||
if (!mConn->mSocketIn)
|
||||
return NS_OK;
|
||||
return mConn->OnInputStreamReady(mConn->mSocketIn);
|
||||
}
|
||||
if (!mConn->mSocketOut)
|
||||
return NS_OK;
|
||||
return mConn->OnInputStreamReady(mConn->mSocketIn);
|
||||
return mConn->OnOutputStreamReady(mConn->mSocketOut);
|
||||
}
|
||||
private:
|
||||
nsRefPtr<nsHttpConnection> mConn;
|
||||
bool mDoRecv;
|
||||
};
|
||||
|
||||
// trigger an asynchronous read
|
||||
|
@ -1228,7 +1336,21 @@ nsHttpConnection::ForceRecv()
|
|||
LOG(("nsHttpConnection::ForceRecv [this=%p]\n", this));
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
return NS_DispatchToCurrentThread(new nsHttpConnectionForceRecv(this));
|
||||
return NS_DispatchToCurrentThread(new nsHttpConnectionForceIO(this, true));
|
||||
}
|
||||
|
||||
// trigger an asynchronous write
|
||||
nsresult
|
||||
nsHttpConnection::ForceSend()
|
||||
{
|
||||
LOG(("nsHttpConnection::ForceSend [this=%p]\n", this));
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
if (mTLSFilter) {
|
||||
return mTLSFilter->NudgeTunnel(this, this, this);
|
||||
}
|
||||
|
||||
return NS_DispatchToCurrentThread(new nsHttpConnectionForceIO(this, false));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1270,7 +1392,8 @@ nsHttpConnection::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
|
|||
LOG(("nsHttpConnection::CloseTransaction[this=%p trans=%p reason=%x]\n",
|
||||
this, trans, reason));
|
||||
|
||||
MOZ_ASSERT(trans == mTransaction, "wrong transaction");
|
||||
MOZ_ASSERT((trans == mTransaction) ||
|
||||
(mTLSFilter && mTLSFilter->Transaction() == trans));
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
if (mCurrentBytesRead > mMaxBytesRead)
|
||||
|
@ -1355,56 +1478,53 @@ nsHttpConnection::OnSocketWritable()
|
|||
this, mConnInfo->Host()));
|
||||
|
||||
nsresult rv;
|
||||
uint32_t n;
|
||||
uint32_t transactionBytes;
|
||||
bool again = true;
|
||||
|
||||
do {
|
||||
mSocketOutCondition = NS_OK;
|
||||
rv = mSocketOutCondition = NS_OK;
|
||||
transactionBytes = 0;
|
||||
|
||||
// If we're doing a proxy connect, then we need to bypass calling into
|
||||
// the transaction.
|
||||
//
|
||||
// NOTE: this code path can't be shared since the transaction doesn't
|
||||
// implement nsIInputStream. doing so is not worth the added cost of
|
||||
// extra indirections during normal reading.
|
||||
//
|
||||
if (mProxyConnectStream) {
|
||||
// The SSL handshake must be completed before the transaction->readsegments()
|
||||
// processing can proceed because we need to know how to format the
|
||||
// request differently for http/1, http/2, spdy, etc.. and that is
|
||||
// negotiated with NPN/ALPN in the SSL handshake.
|
||||
|
||||
if (mConnInfo->UsingHttpsProxy() && !EnsureNPNComplete()) {
|
||||
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
} else if (mProxyConnectStream) {
|
||||
// If we're need an HTTP/1 CONNECT tunnel through a proxy
|
||||
// send it before doing the SSL handshake
|
||||
LOG((" writing CONNECT request stream\n"));
|
||||
rv = mProxyConnectStream->ReadSegments(ReadFromStream, this,
|
||||
nsIOService::gDefaultSegmentSize,
|
||||
&n);
|
||||
}
|
||||
else if (!EnsureNPNComplete()) {
|
||||
// When SPDY is disabled this branch is not executed because Activate()
|
||||
// sets mNPNComplete to true in that case.
|
||||
|
||||
// We are ready to proceed with SSL but the handshake is not done.
|
||||
// When using NPN to negotiate between HTTPS and SPDY, we need to
|
||||
// see the results of the handshake to know what bytes to send, so
|
||||
// we cannot proceed with the request headers.
|
||||
|
||||
rv = NS_OK;
|
||||
nsIOService::gDefaultSegmentSize,
|
||||
&transactionBytes);
|
||||
} else if (!EnsureNPNComplete()) {
|
||||
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
n = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
|
||||
// for non spdy sessions let the connection manager know
|
||||
if (!mReportedSpdy) {
|
||||
mReportedSpdy = true;
|
||||
gHttpHandler->ConnMgr()->ReportSpdyConnection(this, mEverUsedSpdy);
|
||||
MOZ_ASSERT(!mEverUsedSpdy);
|
||||
gHttpHandler->ConnMgr()->ReportSpdyConnection(this, false);
|
||||
}
|
||||
|
||||
LOG((" writing transaction request stream\n"));
|
||||
mProxyConnectInProgress = false;
|
||||
rv = mTransaction->ReadSegments(this, nsIOService::gDefaultSegmentSize, &n);
|
||||
rv = mTransaction->ReadSegments(this, nsIOService::gDefaultSegmentSize,
|
||||
&transactionBytes);
|
||||
mContentBytesWritten += transactionBytes;
|
||||
}
|
||||
|
||||
LOG((" ReadSegments returned [rv=%x read=%u sock-cond=%x]\n",
|
||||
rv, n, mSocketOutCondition));
|
||||
LOG(("nsHttpConnection::OnSocketWritable %p "
|
||||
"ReadSegments returned [rv=%x read=%u sock-cond=%x]\n",
|
||||
this, rv, transactionBytes, mSocketOutCondition));
|
||||
|
||||
// XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
|
||||
if (rv == NS_BASE_STREAM_CLOSED && !mTransaction->IsDone()) {
|
||||
rv = NS_OK;
|
||||
n = 0;
|
||||
transactionBytes = 0;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -1413,15 +1533,19 @@ nsHttpConnection::OnSocketWritable()
|
|||
if (rv == NS_BASE_STREAM_WOULD_BLOCK)
|
||||
rv = NS_OK;
|
||||
again = false;
|
||||
}
|
||||
else if (NS_FAILED(mSocketOutCondition)) {
|
||||
if (mSocketOutCondition == NS_BASE_STREAM_WOULD_BLOCK)
|
||||
rv = mSocketOut->AsyncWait(this, 0, 0, nullptr); // continue writing
|
||||
else
|
||||
} else if (NS_FAILED(mSocketOutCondition)) {
|
||||
if (mSocketOutCondition == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
if (mTLSFilter) {
|
||||
LOG((" blocked tunnel (handshake?)\n"));
|
||||
mTLSFilter->NudgeTunnel(this, this, this);
|
||||
} else {
|
||||
rv = mSocketOut->AsyncWait(this, 0, 0, nullptr); // continue writing
|
||||
}
|
||||
} else {
|
||||
rv = mSocketOutCondition;
|
||||
}
|
||||
again = false;
|
||||
}
|
||||
else if (n == 0) {
|
||||
} else if (!transactionBytes) {
|
||||
rv = NS_OK;
|
||||
|
||||
if (mTransaction) { // in case the ReadSegments stack called CloseTransaction()
|
||||
|
@ -1583,6 +1707,33 @@ nsHttpConnection::OnSocketReadable()
|
|||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::SetupSecondaryTLS()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
MOZ_ASSERT(!mTLSFilter);
|
||||
LOG(("nsHttpConnection %p SetupSecondaryTLS %s %d\n",
|
||||
this, mConnInfo->Host(), mConnInfo->Port()));
|
||||
mTLSFilter = new TLSFilterTransaction(mTransaction,
|
||||
mConnInfo->Host(),
|
||||
mConnInfo->Port());
|
||||
if (mTransaction) {
|
||||
mTransaction = mTLSFilter;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::SetInSpdyTunnel(bool arg)
|
||||
{
|
||||
MOZ_ASSERT(mTLSFilter);
|
||||
mInSpdyTunnel = arg;
|
||||
|
||||
// don't setup another tunnel :)
|
||||
mProxyConnectStream = nullptr;
|
||||
mCompletedProxyConnect = true;
|
||||
mProxyConnectInProgress = false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::MakeConnectString(nsAHttpTransaction *trans,
|
||||
nsHttpRequestHead *request,
|
||||
|
@ -1667,7 +1818,7 @@ nsHttpConnection::StartShortLivedTCPKeepalives()
|
|||
retryIntervalS =
|
||||
std::max<int32_t>((int32_t)PR_IntervalToSeconds(mRtt), 1);
|
||||
rv = mSocketTransport->SetKeepaliveVals(idleTimeS, retryIntervalS);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = mSocketTransport->SetKeepaliveEnabled(true);
|
||||
|
@ -1676,7 +1827,7 @@ nsHttpConnection::StartShortLivedTCPKeepalives()
|
|||
rv = mSocketTransport->SetKeepaliveEnabled(false);
|
||||
mTCPKeepaliveConfig = kTCPKeepaliveDisabled;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1741,14 +1892,14 @@ nsHttpConnection::StartLongLivedTCPKeepalives()
|
|||
int32_t retryIntervalS =
|
||||
std::max<int32_t>((int32_t)PR_IntervalToSeconds(mRtt), 1);
|
||||
rv = mSocketTransport->SetKeepaliveVals(idleTimeS, retryIntervalS);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Ensure keepalive is enabled, if current status is disabled.
|
||||
if (mTCPKeepaliveConfig == kTCPKeepaliveDisabled) {
|
||||
rv = mSocketTransport->SetKeepaliveEnabled(true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
@ -1758,7 +1909,7 @@ nsHttpConnection::StartLongLivedTCPKeepalives()
|
|||
mTCPKeepaliveConfig = kTCPKeepaliveDisabled;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -1771,10 +1922,11 @@ nsHttpConnection::DisableTCPKeepalives()
|
|||
if (!mSocketTransport) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LOG(("nsHttpConnection::DisableTCPKeepalives [%p]", this));
|
||||
if (mTCPKeepaliveConfig != kTCPKeepaliveDisabled) {
|
||||
nsresult rv = mSocketTransport->SetKeepaliveEnabled(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
mTCPKeepaliveConfig = kTCPKeepaliveDisabled;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "nsAutoPtr.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "prinrval.h"
|
||||
#include "TunnelUtils.h"
|
||||
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
|
@ -19,6 +20,7 @@
|
|||
#include "nsITimer.h"
|
||||
|
||||
class nsISocketTransport;
|
||||
class nsISSLSocketControl;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
@ -39,6 +41,7 @@ class nsHttpConnection : public nsAHttpSegmentReader
|
|||
, public nsIOutputStreamCallback
|
||||
, public nsITransportEventSink
|
||||
, public nsIInterfaceRequestor
|
||||
, public NudgeTunnelCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
@ -48,6 +51,7 @@ public:
|
|||
NS_DECL_NSIOUTPUTSTREAMCALLBACK
|
||||
NS_DECL_NSITRANSPORTEVENTSINK
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NUDGETUNNELCALLBACK
|
||||
|
||||
nsHttpConnection();
|
||||
virtual ~nsHttpConnection();
|
||||
|
@ -101,6 +105,11 @@ public:
|
|||
mLastTransactionExpectedNoContent = val;
|
||||
}
|
||||
|
||||
bool NeedSpdyTunnel()
|
||||
{
|
||||
return mConnInfo->UsingHttpsProxy() && !mTLSFilter && mConnInfo->UsingConnect();
|
||||
}
|
||||
|
||||
nsISocketTransport *Transport() { return mSocketTransport; }
|
||||
nsAHttpTransaction *Transaction() { return mTransaction; }
|
||||
nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; }
|
||||
|
@ -122,7 +131,8 @@ public:
|
|||
int64_t MaxBytesRead() {return mMaxBytesRead;}
|
||||
uint8_t GetLastHttpResponseVersion() { return mLastHttpResponseVersion; }
|
||||
|
||||
friend class nsHttpConnectionForceRecv;
|
||||
friend class nsHttpConnectionForceIO;
|
||||
nsresult ForceSend();
|
||||
nsresult ForceRecv();
|
||||
|
||||
static NS_METHOD ReadFromStream(nsIInputStream *, void *, const char *,
|
||||
|
@ -164,7 +174,8 @@ public:
|
|||
// When the connection is active this is called every second
|
||||
void ReadTimeoutTick();
|
||||
|
||||
int64_t BytesWritten() { return mTotalBytesWritten; }
|
||||
int64_t BytesWritten() { return mTotalBytesWritten; } // includes TLS
|
||||
int64_t ContentBytesWritten() { return mContentBytesWritten; }
|
||||
|
||||
void SetSecurityCallbacks(nsIInterfaceRequestor* aCallbacks);
|
||||
void PrintDiagnostics(nsCString &log);
|
||||
|
@ -178,6 +189,8 @@ public:
|
|||
static nsresult MakeConnectString(nsAHttpTransaction *trans,
|
||||
nsHttpRequestHead *request,
|
||||
nsACString &result);
|
||||
void SetupSecondaryTLS();
|
||||
void SetInSpdyTunnel(bool arg);
|
||||
|
||||
private:
|
||||
// Value (set in mTCPKeepaliveConfig) indicates which set of prefs to use.
|
||||
|
@ -188,7 +201,8 @@ private:
|
|||
};
|
||||
|
||||
// called to cause the underlying socket to start speaking SSL
|
||||
nsresult ProxyStartSSL();
|
||||
nsresult InitSSLParams(bool connectingToProxy, bool ProxyStartSSL);
|
||||
nsresult SetupNPNList(nsISSLSocketControl *ssl, uint32_t caps);
|
||||
|
||||
nsresult OnTransactionDone(nsresult reason);
|
||||
nsresult OnSocketWritable();
|
||||
|
@ -203,7 +217,7 @@ private:
|
|||
// Makes certain the SSL handshake is complete and NPN negotiation
|
||||
// has had a chance to happen
|
||||
bool EnsureNPNComplete();
|
||||
void SetupSSL(uint32_t caps);
|
||||
void SetupSSL();
|
||||
|
||||
// Start the Spdy transaction handler when NPN indicates spdy/*
|
||||
void StartSpdy(uint8_t versionLevel);
|
||||
|
@ -231,6 +245,7 @@ private:
|
|||
// mTransaction only points to the HTTP Transaction callbacks if the
|
||||
// transaction is open, otherwise it is null.
|
||||
nsRefPtr<nsAHttpTransaction> mTransaction;
|
||||
nsRefPtr<TLSFilterTransaction> mTLSFilter;
|
||||
|
||||
nsRefPtr<nsHttpHandler> mHttpHandler; // keep gHttpHandler alive
|
||||
|
||||
|
@ -249,6 +264,7 @@ private:
|
|||
int64_t mMaxBytesRead; // max read in 1 activation
|
||||
int64_t mTotalBytesRead; // total data read
|
||||
int64_t mTotalBytesWritten; // does not include CONNECT tunnel
|
||||
int64_t mContentBytesWritten; // does not include CONNECT tunnel or TLS
|
||||
|
||||
nsRefPtr<nsIAsyncInputStream> mInputOverflow;
|
||||
|
||||
|
@ -265,6 +281,7 @@ private:
|
|||
bool mIdleMonitoring;
|
||||
bool mProxyConnectInProgress;
|
||||
bool mExperienced;
|
||||
bool mInSpdyTunnel;
|
||||
|
||||
// The number of <= HTTP/1.1 transactions performed on this connection. This
|
||||
// excludes spdy transactions.
|
||||
|
|
|
@ -68,8 +68,7 @@ nsHttpConnectionInfo::SetOriginServer(const nsACString &host, int32_t port)
|
|||
if (mUsingHttpProxy && !mUsingConnect) {
|
||||
keyHost = ProxyHost();
|
||||
keyPort = ProxyPort();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
keyHost = Host();
|
||||
keyPort = Port();
|
||||
}
|
||||
|
@ -129,10 +128,31 @@ nsHttpConnectionInfo::Clone() const
|
|||
// Make sure the anonymous and private flags are transferred!
|
||||
clone->SetAnonymous(GetAnonymous());
|
||||
clone->SetPrivate(GetPrivate());
|
||||
|
||||
MOZ_ASSERT(clone->Equals(this));
|
||||
return clone;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnectionInfo::CreateWildCard(nsHttpConnectionInfo **outParam)
|
||||
{
|
||||
// T???mozilla.org:443 (https:proxy.ducksong.com:3128) [specifc form]
|
||||
// TS??*:0 (https:proxy.ducksong.com:3128) [wildcard form]
|
||||
|
||||
if (!mUsingHttpsProxy) {
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsRefPtr<nsHttpConnectionInfo> clone;
|
||||
clone = new nsHttpConnectionInfo(NS_LITERAL_CSTRING("*"), 0,
|
||||
mUsername, mProxyInfo, true);
|
||||
// Make sure the anonymous and private flags are transferred!
|
||||
clone->SetAnonymous(GetAnonymous());
|
||||
clone->SetPrivate(GetPrivate());
|
||||
clone.forget(outParam);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionInfo::UsingProxy()
|
||||
{
|
||||
|
|
|
@ -18,6 +18,15 @@ extern PRLogModuleInfo *gHttpLog;
|
|||
// nsHttpConnectionInfo - holds the properties of a connection
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// http:// uris through a proxy will all share the same CI, because they can
|
||||
// all use the same connection. (modulo pb and anonymous flags). They just use
|
||||
// the proxy as the origin host name.
|
||||
// however, https:// uris tunnel through the proxy so they will have different
|
||||
// CIs - the CI reflects both the proxy and the origin.
|
||||
// however, proxy conenctions made with http/2 (or spdy) can tunnel to the origin
|
||||
// and multiplex non tunneled transactions at the same time, so they have a
|
||||
// special wildcard CI that accepts all origins through that proxy.
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
class nsHttpConnectionInfo
|
||||
|
@ -42,8 +51,9 @@ public:
|
|||
SetOriginServer(nsDependentCString(host), port);
|
||||
}
|
||||
|
||||
// OK to treat this as an infalible allocation
|
||||
// OK to treat these as an infalible allocation
|
||||
nsHttpConnectionInfo* Clone() const;
|
||||
nsresult CreateWildCard(nsHttpConnectionInfo **outParam);
|
||||
|
||||
const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host().get() : nullptr; }
|
||||
int32_t ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; }
|
||||
|
|
|
@ -1044,8 +1044,10 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent, bool consid
|
|||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
LOG(("nsHttpConnectionMgr::ProcessPendingQForEntry [ci=%s]\n",
|
||||
ent->mConnInfo->HashKey().get()));
|
||||
LOG(("nsHttpConnectionMgr::ProcessPendingQForEntry "
|
||||
"[ci=%s ent=%p active=%d idle=%d queued=%d]\n",
|
||||
ent->mConnInfo->HashKey().get(), ent, ent->mActiveConns.Length(),
|
||||
ent->mIdleConns.Length(), ent->mPendingQ.Length()));
|
||||
|
||||
ProcessSpdyPendingQ(ent);
|
||||
|
||||
|
@ -1072,7 +1074,9 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent, bool consid
|
|||
}
|
||||
}
|
||||
|
||||
rv = TryDispatchTransaction(ent, alreadyHalfOpen, trans);
|
||||
rv = TryDispatchTransaction(ent,
|
||||
alreadyHalfOpen || trans->DontRouteViaWildCard(),
|
||||
trans);
|
||||
if (NS_SUCCEEDED(rv) || (rv != NS_ERROR_NOT_AVAILABLE)) {
|
||||
if (NS_SUCCEEDED(rv))
|
||||
LOG((" dispatching pending transaction...\n"));
|
||||
|
@ -1567,8 +1571,10 @@ nsHttpConnectionMgr::TryDispatchTransaction(nsConnectionEntry *ent,
|
|||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
LOG(("nsHttpConnectionMgr::TryDispatchTransaction without conn "
|
||||
"[ci=%s caps=%x]\n",
|
||||
ent->mConnInfo->HashKey().get(), uint32_t(trans->Caps())));
|
||||
"[trans=%p ci=%s caps=%x wildcardok=%d onlyreused=%d]\n",
|
||||
trans, ent->mConnInfo->HashKey().get(),
|
||||
uint32_t(trans->Caps()), !trans->DontRouteViaWildCard(),
|
||||
onlyReusedConnection));
|
||||
|
||||
nsHttpTransaction::Classifier classification = trans->Classification();
|
||||
uint32_t caps = trans->Caps();
|
||||
|
@ -1757,7 +1763,7 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
|
|||
nsresult rv;
|
||||
|
||||
LOG(("nsHttpConnectionMgr::DispatchTransaction "
|
||||
"[ci=%s trans=%p caps=%x conn=%p priority=%d]\n",
|
||||
"[ent-ci=%s trans=%p caps=%x conn=%p priority=%d]\n",
|
||||
ent->mConnInfo->HashKey().get(), trans, caps, conn, priority));
|
||||
|
||||
// It is possible for a rate-paced transaction to be dispatched independent
|
||||
|
@ -1766,7 +1772,7 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
|
|||
trans->CancelPacing(NS_OK);
|
||||
|
||||
if (conn->UsingSpdy()) {
|
||||
LOG(("Spdy Dispatch Transaction via Activate(). Transaction host = %s,"
|
||||
LOG(("Spdy Dispatch Transaction via Activate(). Transaction host = %s, "
|
||||
"Connection host = %s\n",
|
||||
trans->ConnectionInfo()->Host(),
|
||||
conn->ConnectionInfo()->Host()));
|
||||
|
@ -1925,7 +1931,8 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
|
|||
nsHttpConnectionInfo *ci = trans->ConnectionInfo();
|
||||
MOZ_ASSERT(ci);
|
||||
|
||||
nsConnectionEntry *ent = GetOrCreateConnectionEntry(ci);
|
||||
nsConnectionEntry *ent =
|
||||
GetOrCreateConnectionEntry(ci, trans->DontRouteViaWildCard());
|
||||
|
||||
// SPDY coalescing of hostnames means we might redirect from this
|
||||
// connection entry onto the preferred one.
|
||||
|
@ -1957,9 +1964,9 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
|
|||
"sticky connection=%p\n", trans, conn.get()));
|
||||
trans->SetConnection(nullptr);
|
||||
rv = DispatchTransaction(ent, trans, conn);
|
||||
} else {
|
||||
rv = TryDispatchTransaction(ent, trans->DontRouteViaWildCard(), trans);
|
||||
}
|
||||
else
|
||||
rv = TryDispatchTransaction(ent, false, trans);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
LOG((" ProcessNewTransaction Dispatch Immediately trans=%p\n", trans));
|
||||
|
@ -2288,6 +2295,44 @@ nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, void *param)
|
|||
NS_RELEASE(ci);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnectionMgr::CancelTransactions(nsHttpConnectionInfo *aCI, nsresult code)
|
||||
{
|
||||
nsRefPtr<nsHttpConnectionInfo> ci(aCI);
|
||||
LOG(("nsHttpConnectionMgr::CancelTransactions %s\n",ci->HashKey().get()));
|
||||
|
||||
int32_t intReason = static_cast<int32_t>(code);
|
||||
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransactions, intReason, ci);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
unused << ci.forget();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::OnMsgCancelTransactions(int32_t code, void *param)
|
||||
{
|
||||
nsresult reason = static_cast<nsresult>(code);
|
||||
nsRefPtr<nsHttpConnectionInfo> ci =
|
||||
dont_AddRef(static_cast<nsHttpConnectionInfo *>(param));
|
||||
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p\n",
|
||||
ci->HashKey().get(), ent));
|
||||
if (!ent) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<nsHttpTransaction> trans;
|
||||
for (int32_t i = ent->mPendingQ.Length() - 1; i >= 0; --i) {
|
||||
trans = dont_AddRef(ent->mPendingQ[i]);
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p %p\n",
|
||||
ci->HashKey().get(), ent, trans.get()));
|
||||
ent->mPendingQ.RemoveElementAt(i);
|
||||
trans->Close(reason);
|
||||
trans = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, void *)
|
||||
{
|
||||
|
@ -2333,80 +2378,82 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param)
|
|||
|
||||
nsConnectionEntry *ent = LookupConnectionEntry(conn->ConnectionInfo(),
|
||||
conn, nullptr);
|
||||
nsHttpConnectionInfo *ci = nullptr;
|
||||
|
||||
if (!ent) {
|
||||
// this should never happen
|
||||
LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection ent == null\n"));
|
||||
MOZ_ASSERT(false, "no connection entry");
|
||||
NS_ADDREF(ci = conn->ConnectionInfo());
|
||||
// this can happen if the connection is made outside of the
|
||||
// connection manager and is being "reclaimed" for use with
|
||||
// future transactions. HTTP/2 tunnels work like this.
|
||||
ent = GetOrCreateConnectionEntry(conn->ConnectionInfo(), true);
|
||||
LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection conn %p "
|
||||
"forced new hash entry %s\n",
|
||||
conn, conn->ConnectionInfo()->HashKey().get()));
|
||||
}
|
||||
else {
|
||||
NS_ADDREF(ci = ent->mConnInfo);
|
||||
|
||||
// If the connection is in the active list, remove that entry
|
||||
// and the reference held by the mActiveConns list.
|
||||
// This is never the final reference on conn as the event context
|
||||
// is also holding one that is released at the end of this function.
|
||||
MOZ_ASSERT(ent);
|
||||
nsHttpConnectionInfo *ci = nullptr;
|
||||
NS_ADDREF(ci = ent->mConnInfo);
|
||||
|
||||
if (ent->mUsingSpdy) {
|
||||
// Spdy connections aren't reused in the traditional HTTP way in
|
||||
// the idleconns list, they are actively multplexed as active
|
||||
// conns. Even when they have 0 transactions on them they are
|
||||
// considered active connections. So when one is reclaimed it
|
||||
// is really complete and is meant to be shut down and not
|
||||
// reused.
|
||||
conn->DontReuse();
|
||||
// If the connection is in the active list, remove that entry
|
||||
// and the reference held by the mActiveConns list.
|
||||
// This is never the final reference on conn as the event context
|
||||
// is also holding one that is released at the end of this function.
|
||||
|
||||
if (conn->EverUsedSpdy()) {
|
||||
// Spdy connections aren't reused in the traditional HTTP way in
|
||||
// the idleconns list, they are actively multplexed as active
|
||||
// conns. Even when they have 0 transactions on them they are
|
||||
// considered active connections. So when one is reclaimed it
|
||||
// is really complete and is meant to be shut down and not
|
||||
// reused.
|
||||
conn->DontReuse();
|
||||
}
|
||||
|
||||
// a connection that still holds a reference to a transaction was
|
||||
// not closed naturally (i.e. it was reset or aborted) and is
|
||||
// therefore not something that should be reused.
|
||||
if (conn->Transaction()) {
|
||||
conn->DontReuse();
|
||||
}
|
||||
|
||||
if (ent->mActiveConns.RemoveElement(conn)) {
|
||||
if (conn == ent->mYellowConnection) {
|
||||
ent->OnYellowComplete();
|
||||
}
|
||||
nsHttpConnection *temp = conn;
|
||||
NS_RELEASE(temp);
|
||||
DecrementActiveConnCount(conn);
|
||||
ConditionallyStopTimeoutTick();
|
||||
}
|
||||
|
||||
if (conn->CanReuse()) {
|
||||
LOG((" adding connection to idle list\n"));
|
||||
// Keep The idle connection list sorted with the connections that
|
||||
// have moved the largest data pipelines at the front because these
|
||||
// connections have the largest cwnds on the server.
|
||||
|
||||
// The linear search is ok here because the number of idleconns
|
||||
// in a single entry is generally limited to a small number (i.e. 6)
|
||||
|
||||
uint32_t idx;
|
||||
for (idx = 0; idx < ent->mIdleConns.Length(); idx++) {
|
||||
nsHttpConnection *idleConn = ent->mIdleConns[idx];
|
||||
if (idleConn->MaxBytesRead() < conn->MaxBytesRead())
|
||||
break;
|
||||
}
|
||||
|
||||
if (ent->mActiveConns.RemoveElement(conn)) {
|
||||
if (conn == ent->mYellowConnection)
|
||||
ent->OnYellowComplete();
|
||||
nsHttpConnection *temp = conn;
|
||||
NS_RELEASE(temp);
|
||||
DecrementActiveConnCount(conn);
|
||||
ConditionallyStopTimeoutTick();
|
||||
}
|
||||
NS_ADDREF(conn);
|
||||
ent->mIdleConns.InsertElementAt(idx, conn);
|
||||
mNumIdleConns++;
|
||||
conn->BeginIdleMonitoring();
|
||||
|
||||
// a connection that still holds a reference to a transaction was
|
||||
// not closed naturally (i.e. it was reset or aborted) and is
|
||||
// therefore not something that should be reused.
|
||||
if (conn->Transaction()) {
|
||||
conn->DontReuse();
|
||||
}
|
||||
|
||||
if (conn->CanReuse()) {
|
||||
LOG((" adding connection to idle list\n"));
|
||||
// Keep The idle connection list sorted with the connections that
|
||||
// have moved the largest data pipelines at the front because these
|
||||
// connections have the largest cwnds on the server.
|
||||
|
||||
// The linear search is ok here because the number of idleconns
|
||||
// in a single entry is generally limited to a small number (i.e. 6)
|
||||
|
||||
uint32_t idx;
|
||||
for (idx = 0; idx < ent->mIdleConns.Length(); idx++) {
|
||||
nsHttpConnection *idleConn = ent->mIdleConns[idx];
|
||||
if (idleConn->MaxBytesRead() < conn->MaxBytesRead())
|
||||
break;
|
||||
}
|
||||
|
||||
NS_ADDREF(conn);
|
||||
ent->mIdleConns.InsertElementAt(idx, conn);
|
||||
mNumIdleConns++;
|
||||
conn->BeginIdleMonitoring();
|
||||
|
||||
// If the added connection was first idle connection or has shortest
|
||||
// time to live among the watched connections, pruning dead
|
||||
// connections needs to be done when it can't be reused anymore.
|
||||
uint32_t timeToLive = conn->TimeToLive();
|
||||
if(!mTimer || NowInSeconds() + timeToLive < mTimeOfNextWakeUp)
|
||||
PruneDeadConnectionsAfter(timeToLive);
|
||||
}
|
||||
else {
|
||||
LOG((" connection cannot be reused; closing connection\n"));
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
}
|
||||
// If the added connection was first idle connection or has shortest
|
||||
// time to live among the watched connections, pruning dead
|
||||
// connections needs to be done when it can't be reused anymore.
|
||||
uint32_t timeToLive = conn->TimeToLive();
|
||||
if(!mTimer || NowInSeconds() + timeToLive < mTimeOfNextWakeUp)
|
||||
PruneDeadConnectionsAfter(timeToLive);
|
||||
} else {
|
||||
LOG((" connection cannot be reused; closing connection\n"));
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
OnMsgProcessPendingQ(0, ci); // releases |ci|
|
||||
|
@ -2609,17 +2656,43 @@ nsHttpConnectionMgr::nsConnectionHandle::~nsConnectionHandle()
|
|||
|
||||
NS_IMPL_ISUPPORTS0(nsHttpConnectionMgr::nsConnectionHandle)
|
||||
|
||||
nsHttpConnectionMgr::nsConnectionEntry *
|
||||
nsHttpConnectionMgr::GetOrCreateConnectionEntry(nsHttpConnectionInfo *ci)
|
||||
{
|
||||
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
|
||||
if (ent)
|
||||
return ent;
|
||||
// GetOrCreateConnectionEntry finds a ent for a particular CI for use in
|
||||
// dispatching a transaction according to these rules
|
||||
// 1] use an ent that matches the ci that can be dispatched immediately
|
||||
// 2] otherwise use an ent of wildcard(ci) than can be dispatched immediately
|
||||
// 3] otherwise create an ent that matches ci and make new conn on it
|
||||
|
||||
nsHttpConnectionInfo *clone = ci->Clone();
|
||||
ent = new nsConnectionEntry(clone);
|
||||
mCT.Put(ci->HashKey(), ent);
|
||||
return ent;
|
||||
nsHttpConnectionMgr::nsConnectionEntry *
|
||||
nsHttpConnectionMgr::GetOrCreateConnectionEntry(nsHttpConnectionInfo *specificCI,
|
||||
bool prohibitWildCard)
|
||||
{
|
||||
// step 1
|
||||
nsConnectionEntry *specificEnt = mCT.Get(specificCI->HashKey());
|
||||
if (specificEnt && specificEnt->AvailableForDispatchNow()) {
|
||||
return specificEnt;
|
||||
}
|
||||
|
||||
if (!specificCI->UsingHttpsProxy()) {
|
||||
prohibitWildCard = true;
|
||||
}
|
||||
|
||||
// step 2
|
||||
if (!prohibitWildCard) {
|
||||
nsRefPtr<nsHttpConnectionInfo> wildCardProxyCI;
|
||||
specificCI->CreateWildCard(getter_AddRefs(wildCardProxyCI));
|
||||
nsConnectionEntry *wildCardEnt = mCT.Get(wildCardProxyCI->HashKey());
|
||||
if (wildCardEnt && wildCardEnt->AvailableForDispatchNow()) {
|
||||
return wildCardEnt;
|
||||
}
|
||||
}
|
||||
|
||||
// step 3
|
||||
if (!specificEnt) {
|
||||
nsRefPtr<nsHttpConnectionInfo> clone(specificCI->Clone());
|
||||
specificEnt = new nsConnectionEntry(clone);
|
||||
mCT.Put(clone->HashKey(), specificEnt);
|
||||
}
|
||||
return specificEnt;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -2658,7 +2731,7 @@ nsHttpConnectionMgr::OnMsgSpeculativeConnect(int32_t, void *param)
|
|||
args->mTrans->ConnectionInfo()->HashKey().get()));
|
||||
|
||||
nsConnectionEntry *ent =
|
||||
GetOrCreateConnectionEntry(args->mTrans->ConnectionInfo());
|
||||
GetOrCreateConnectionEntry(args->mTrans->ConnectionInfo(), false);
|
||||
|
||||
// If spdy has previously made a preferred entry for this host via
|
||||
// the ip pooling rules. If so, connect to the preferred host instead of
|
||||
|
@ -2760,11 +2833,16 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
|
|||
bool isBackup)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
const char* types[1];
|
||||
types[0] = (mEnt->mConnInfo->EndToEndSSL()) ?
|
||||
"ssl" : gHttpHandler->DefaultSocketType();
|
||||
uint32_t typeCount = (types[0] != nullptr);
|
||||
const char *socketTypes[1];
|
||||
uint32_t typeCount = 0;
|
||||
if (mEnt->mConnInfo->FirstHopSSL()) {
|
||||
socketTypes[typeCount++] = "ssl";
|
||||
} else {
|
||||
socketTypes[typeCount] = gHttpHandler->DefaultSocketType();
|
||||
if (socketTypes[typeCount]) {
|
||||
typeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISocketTransport> socketTransport;
|
||||
nsCOMPtr<nsISocketTransportService> sts;
|
||||
|
@ -2772,7 +2850,7 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
|
|||
sts = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = sts->CreateTransport(types, typeCount,
|
||||
rv = sts->CreateTransport(socketTypes, typeCount,
|
||||
nsDependentCString(mEnt->mConnInfo->Host()),
|
||||
mEnt->mConnInfo->Port(),
|
||||
mEnt->mConnInfo->ProxyInfo(),
|
||||
|
@ -3278,6 +3356,17 @@ nsConnectionEntry::nsConnectionEntry(nsHttpConnectionInfo *ci)
|
|||
memset(mPipeliningClassPenalty, 0, sizeof(int16_t) * nsAHttpTransaction::CLASS_MAX);
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionMgr::nsConnectionEntry::AvailableForDispatchNow()
|
||||
{
|
||||
if (mIdleConns.Length() && mIdleConns[0]->CanReuse()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return gHttpHandler->ConnMgr()->
|
||||
GetSpdyPreferredConn(this) ? true : false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionMgr::nsConnectionEntry::SupportsPipelining()
|
||||
{
|
||||
|
@ -3615,5 +3704,62 @@ nsConnectionEntry::ResetIPFamilyPreference()
|
|||
mPreferIPv6 = false;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::MoveToWildCardConnEntry(nsHttpConnectionInfo *specificCI,
|
||||
nsHttpConnectionInfo *wildCardCI,
|
||||
nsHttpConnection *proxyConn)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
MOZ_ASSERT(specificCI->UsingHttpsProxy());
|
||||
|
||||
LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard conn %p has requested to "
|
||||
"change CI from %s to %s\n", proxyConn, specificCI->HashKey().get(),
|
||||
wildCardCI->HashKey().get()));
|
||||
|
||||
nsConnectionEntry *ent = LookupConnectionEntry(specificCI, proxyConn, nullptr);
|
||||
LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard conn %p using ent %p (spdy %d)\n",
|
||||
proxyConn, ent, ent ? ent->mUsingSpdy : 0));
|
||||
|
||||
if (!ent || !ent->mUsingSpdy) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsConnectionEntry *wcEnt = GetOrCreateConnectionEntry(wildCardCI, true);
|
||||
if (wcEnt == ent) {
|
||||
// nothing to do!
|
||||
return;
|
||||
}
|
||||
wcEnt->mUsingSpdy = true;
|
||||
wcEnt->mTestedSpdy = true;
|
||||
|
||||
LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard ent %p "
|
||||
"idle=%d active=%d half=%d pending=%d\n", ent,
|
||||
ent->mIdleConns.Length(), ent->mActiveConns.Length(),
|
||||
ent->mHalfOpens.Length(), ent->mPendingQ.Length()));
|
||||
|
||||
LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard wc-ent %p "
|
||||
"idle=%d active=%d half=%d pending=%d\n", wcEnt,
|
||||
wcEnt->mIdleConns.Length(), wcEnt->mActiveConns.Length(),
|
||||
wcEnt->mHalfOpens.Length(), wcEnt->mPendingQ.Length()));
|
||||
|
||||
int32_t count = ent->mActiveConns.Length();
|
||||
for (int32_t i = 0; i < count; ++i) {
|
||||
if (ent->mActiveConns[i] == proxyConn) {
|
||||
ent->mActiveConns.RemoveElementAt(i);
|
||||
wcEnt->mActiveConns.InsertElementAt(0, proxyConn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
count = ent->mIdleConns.Length();
|
||||
for (int32_t i = 0; i < count; ++i) {
|
||||
if (ent->mIdleConns[i] == proxyConn) {
|
||||
ent->mIdleConns.RemoveElementAt(i);
|
||||
wcEnt->mIdleConns.InsertElementAt(0, proxyConn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
|
||||
// cancels a transaction w/ the given reason.
|
||||
nsresult CancelTransaction(nsHttpTransaction *, nsresult reason);
|
||||
nsresult CancelTransactions(nsHttpConnectionInfo *, nsresult reason);
|
||||
|
||||
// called to force the connection manager to prune its list of idle
|
||||
// connections.
|
||||
|
@ -202,6 +203,12 @@ public:
|
|||
// NOTE: functions below may be called only on the socket thread.
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// called to change the connection entry associated with conn from specific into
|
||||
// a wildcard (i.e. http2 proxy friendy) mapping
|
||||
void MoveToWildCardConnEntry(nsHttpConnectionInfo *specificCI,
|
||||
nsHttpConnectionInfo *wildcardCI,
|
||||
nsHttpConnection *conn);
|
||||
|
||||
// called to force the transaction queue to be processed once more, giving
|
||||
// preference to the specified connection.
|
||||
nsresult ProcessPendingQ(nsHttpConnectionInfo *);
|
||||
|
@ -231,6 +238,8 @@ public:
|
|||
|
||||
void ResetIPFamilyPreference(nsHttpConnectionInfo *);
|
||||
|
||||
uint16_t MaxRequestDelay() { return mMaxRequestDelay; }
|
||||
|
||||
private:
|
||||
virtual ~nsHttpConnectionMgr();
|
||||
|
||||
|
@ -271,6 +280,8 @@ private:
|
|||
nsTArray<nsHttpConnection*> mIdleConns; // idle persistent connections
|
||||
nsTArray<nsHalfOpenSocket*> mHalfOpens; // half open connections
|
||||
|
||||
bool AvailableForDispatchNow();
|
||||
|
||||
// calculate the number of half open sockets that have not had at least 1
|
||||
// connection complete
|
||||
uint32_t UnconnectedHalfOpens();
|
||||
|
@ -525,7 +536,8 @@ private:
|
|||
void StartedConnect();
|
||||
void RecvdConnect();
|
||||
|
||||
nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *);
|
||||
nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *,
|
||||
bool allowWildCard);
|
||||
|
||||
nsresult MakeNewConnection(nsConnectionEntry *ent,
|
||||
nsHttpTransaction *trans);
|
||||
|
@ -601,6 +613,7 @@ private:
|
|||
void OnMsgNewTransaction (int32_t, void *);
|
||||
void OnMsgReschedTransaction (int32_t, void *);
|
||||
void OnMsgCancelTransaction (int32_t, void *);
|
||||
void OnMsgCancelTransactions (int32_t, void *);
|
||||
void OnMsgProcessPendingQ (int32_t, void *);
|
||||
void OnMsgPruneDeadConnections (int32_t, void *);
|
||||
void OnMsgSpeculativeConnect (int32_t, void *);
|
||||
|
|
|
@ -110,6 +110,7 @@ public:
|
|||
bool CriticalRequestPrioritization() { return mCriticalRequestPrioritization; }
|
||||
double BypassCacheLockThreshold() { return mBypassCacheLockThreshold; }
|
||||
|
||||
uint32_t MaxConnectionsPerOrigin() { return mMaxPersistentConnectionsPerServer; }
|
||||
bool UseRequestTokenBucket() { return mRequestTokenBucketEnabled; }
|
||||
uint16_t RequestTokenBucketMinParallelism() { return mRequestTokenBucketMinParallelism; }
|
||||
uint32_t RequestTokenBucketHz() { return mRequestTokenBucketHz; }
|
||||
|
|
|
@ -123,6 +123,7 @@ nsHttpTransaction::nsHttpTransaction()
|
|||
, mPreserveStream(false)
|
||||
, mDispatchedAsBlocking(false)
|
||||
, mResponseTimeoutEnabled(true)
|
||||
, mDontRouteViaWildCard(false)
|
||||
, mReportedStart(false)
|
||||
, mReportedResponseHeader(false)
|
||||
, mForTakeResponseHead(nullptr)
|
||||
|
@ -1064,6 +1065,7 @@ nsHttpTransaction::Restart()
|
|||
}
|
||||
|
||||
LOG(("restarting transaction @%p\n", this));
|
||||
SetDontRouteViaWildCard(false);
|
||||
|
||||
// rewind streams in case we already wrote out the request
|
||||
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mRequestStream);
|
||||
|
|
|
@ -102,6 +102,14 @@ public:
|
|||
|
||||
bool ProxyConnectFailed() { return mProxyConnectFailed; }
|
||||
|
||||
// setting mDontRouteViaWildCard to true means the transaction should only
|
||||
// be dispatched on a specific ConnectionInfo Hash Key (as opposed to a
|
||||
// generic wild card one). That means in the specific case of carrying this
|
||||
// transaction on an HTTP/2 tunnel it will only be dispatched onto an
|
||||
// existing tunnel instead of triggering creation of a new one.
|
||||
void SetDontRouteViaWildCard(bool var) { mDontRouteViaWildCard = var; }
|
||||
bool DontRouteViaWildCard() { return mDontRouteViaWildCard; }
|
||||
|
||||
// SetPriority() may only be used by the connection manager.
|
||||
void SetPriority(int32_t priority) { mPriority = priority; }
|
||||
int32_t Priority() { return mPriority; }
|
||||
|
@ -247,6 +255,7 @@ private:
|
|||
bool mPreserveStream;
|
||||
bool mDispatchedAsBlocking;
|
||||
bool mResponseTimeoutEnabled;
|
||||
bool mDontRouteViaWildCard;
|
||||
|
||||
// mClosed := transaction has been explicitly closed
|
||||
// mTransactionDone := transaction ran to completion or was interrupted
|
||||
|
|
Загрузка…
Ссылка в новой задаче