зеркало из https://github.com/mozilla/gecko-dev.git
bug 378637 part 14 - https proxying for spdy31 and http2 r=hurley
--HG-- extra : rebase_source : 03a62d69b08f725c85f092b182a95de9c4eb7288
This commit is contained in:
Родитель
0a3b1e638a
Коммит
d52c2946ac
|
@ -898,7 +898,7 @@ nsresult
|
||||||
Http2Compressor::EncodeHeaderBlock(const nsCString &nvInput,
|
Http2Compressor::EncodeHeaderBlock(const nsCString &nvInput,
|
||||||
const nsACString &method, const nsACString &path,
|
const nsACString &method, const nsACString &path,
|
||||||
const nsACString &host, const nsACString &scheme,
|
const nsACString &host, const nsACString &scheme,
|
||||||
nsACString &output)
|
bool connectForm, nsACString &output)
|
||||||
{
|
{
|
||||||
mAlternateReferenceSet.Clear();
|
mAlternateReferenceSet.Clear();
|
||||||
mImpliedReferenceSet.Clear();
|
mImpliedReferenceSet.Clear();
|
||||||
|
@ -917,10 +917,15 @@ Http2Compressor::EncodeHeaderBlock(const nsCString &nvInput,
|
||||||
}
|
}
|
||||||
|
|
||||||
// colon headers first
|
// colon headers first
|
||||||
ProcessHeader(nvPair(NS_LITERAL_CSTRING(":method"), method), false);
|
if (!connectForm) {
|
||||||
ProcessHeader(nvPair(NS_LITERAL_CSTRING(":path"), path), false);
|
ProcessHeader(nvPair(NS_LITERAL_CSTRING(":method"), method), false);
|
||||||
ProcessHeader(nvPair(NS_LITERAL_CSTRING(":authority"), host), false);
|
ProcessHeader(nvPair(NS_LITERAL_CSTRING(":path"), path), false);
|
||||||
ProcessHeader(nvPair(NS_LITERAL_CSTRING(":scheme"), scheme), false);
|
ProcessHeader(nvPair(NS_LITERAL_CSTRING(":authority"), host), false);
|
||||||
|
ProcessHeader(nvPair(NS_LITERAL_CSTRING(":scheme"), scheme), false);
|
||||||
|
} else {
|
||||||
|
ProcessHeader(nvPair(NS_LITERAL_CSTRING(":method"), method), false);
|
||||||
|
ProcessHeader(nvPair(NS_LITERAL_CSTRING(":authority"), host), false);
|
||||||
|
}
|
||||||
|
|
||||||
// now the non colon headers
|
// now the non colon headers
|
||||||
const char *beginBuffer = nvInput.BeginReading();
|
const char *beginBuffer = nvInput.BeginReading();
|
||||||
|
|
|
@ -164,7 +164,7 @@ public:
|
||||||
nsresult EncodeHeaderBlock(const nsCString &nvInput,
|
nsresult EncodeHeaderBlock(const nsCString &nvInput,
|
||||||
const nsACString &method, const nsACString &path,
|
const nsACString &method, const nsACString &path,
|
||||||
const nsACString &host, const nsACString &scheme,
|
const nsACString &host, const nsACString &scheme,
|
||||||
nsACString &output);
|
bool connectForm, nsACString &output);
|
||||||
|
|
||||||
int64_t GetParsedContentLength() { return mParsedContentLength; } // -1 on not found
|
int64_t GetParsedContentLength() { return mParsedContentLength; } // -1 on not found
|
||||||
|
|
||||||
|
|
|
@ -386,23 +386,23 @@ Http2Session::AddStream(nsAHttpTransaction *aHttpTransaction,
|
||||||
return false;
|
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) {
|
if (!mConnection) {
|
||||||
mConnection = aHttpTransaction->Connection();
|
mConnection = aHttpTransaction->Connection();
|
||||||
}
|
}
|
||||||
|
|
||||||
aHttpTransaction->SetConnection(this);
|
aHttpTransaction->SetConnection(this);
|
||||||
|
|
||||||
|
if (aUseTunnel) {
|
||||||
|
LOG3(("Http2Session::AddStream session=%p trans=%p OnTunnel",
|
||||||
|
this, aHttpTransaction));
|
||||||
|
DispatchOnTunnel(aHttpTransaction, aCallbacks);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Http2Stream *stream = new Http2Stream(aHttpTransaction, this, aPriority);
|
Http2Stream *stream = new Http2Stream(aHttpTransaction, this, aPriority);
|
||||||
|
|
||||||
LOG3(("Http2Session::AddStream session=%p stream=%p NextID=0x%X (tentative)",
|
LOG3(("Http2Session::AddStream session=%p stream=%p serial=%u "
|
||||||
this, stream, mNextStreamID));
|
"NextID=0x%X (tentative)", this, stream, mSerial, mNextStreamID));
|
||||||
|
|
||||||
mStreamTransactionHash.Put(aHttpTransaction, stream);
|
mStreamTransactionHash.Put(aHttpTransaction, stream);
|
||||||
|
|
||||||
|
@ -991,6 +991,10 @@ Http2Session::CloseStream(Http2Stream *aStream, nsresult aResult)
|
||||||
|
|
||||||
RemoveStreamFromQueues(aStream);
|
RemoveStreamFromQueues(aStream);
|
||||||
|
|
||||||
|
if (aStream->IsTunnel()) {
|
||||||
|
UnRegisterTunnel(aStream);
|
||||||
|
}
|
||||||
|
|
||||||
// Send the stream the close() indication
|
// Send the stream the close() indication
|
||||||
aStream->Close(aResult);
|
aStream->Close(aResult);
|
||||||
}
|
}
|
||||||
|
@ -1138,7 +1142,11 @@ Http2Session::ResponseHeadersComplete()
|
||||||
// only do this once, afterwards ignore trailers
|
// only do this once, afterwards ignore trailers
|
||||||
if (mInputFrameDataStream->AllHeadersReceived())
|
if (mInputFrameDataStream->AllHeadersReceived())
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
mInputFrameDataStream->SetAllHeadersReceived(true);
|
nsresult rv = mInputFrameDataStream->SetAllHeadersReceived(true);
|
||||||
|
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
// The stream needs to see flattened http headers
|
// The stream needs to see flattened http headers
|
||||||
// Uncompressed http/2 format headers currently live in
|
// Uncompressed http/2 format headers currently live in
|
||||||
|
@ -1146,11 +1154,23 @@ Http2Session::ResponseHeadersComplete()
|
||||||
// mFlatHTTPResponseHeaders via ConvertHeaders()
|
// mFlatHTTPResponseHeaders via ConvertHeaders()
|
||||||
|
|
||||||
mFlatHTTPResponseHeadersOut = 0;
|
mFlatHTTPResponseHeadersOut = 0;
|
||||||
nsresult rv = mInputFrameDataStream->ConvertResponseHeaders(&mDecompressor,
|
rv = mInputFrameDataStream->ConvertResponseHeaders(&mDecompressor,
|
||||||
mDecompressBuffer,
|
mDecompressBuffer,
|
||||||
mFlatHTTPResponseHeaders);
|
mFlatHTTPResponseHeaders);
|
||||||
if (NS_FAILED(rv))
|
if (rv == NS_ERROR_ABORT) {
|
||||||
|
LOG(("Http2Session::ResponseHeadersComplete ConvertResponseHeaders aborted\n"));
|
||||||
|
if (mInputFrameDataStream->IsTunnel()) {
|
||||||
|
gHttpHandler->ConnMgr()->CancelTransactions(
|
||||||
|
mInputFrameDataStream->Transaction()->ConnectionInfo(),
|
||||||
|
NS_ERROR_CONNECTION_REFUSED);
|
||||||
|
}
|
||||||
|
CleanupStream(mInputFrameDataStream, rv, CANCEL_ERROR);
|
||||||
|
ResetDownstreamState();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
else if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
ChangeDownstreamState(PROCESSING_COMPLETE_HEADERS);
|
ChangeDownstreamState(PROCESSING_COMPLETE_HEADERS);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -2278,6 +2298,7 @@ Http2Session::WriteSegments(nsAHttpSegmentWriter *writer,
|
||||||
MOZ_ASSERT(!mNeedsCleanup, "cleanup stream set unexpectedly");
|
MOZ_ASSERT(!mNeedsCleanup, "cleanup stream set unexpectedly");
|
||||||
mNeedsCleanup = nullptr; /* just in case */
|
mNeedsCleanup = nullptr; /* just in case */
|
||||||
|
|
||||||
|
Http2Stream *stream = mInputFrameDataStream;
|
||||||
mSegmentWriter = writer;
|
mSegmentWriter = writer;
|
||||||
rv = mInputFrameDataStream->WriteSegments(this, count, countWritten);
|
rv = mInputFrameDataStream->WriteSegments(this, count, countWritten);
|
||||||
mSegmentWriter = nullptr;
|
mSegmentWriter = nullptr;
|
||||||
|
@ -2288,7 +2309,6 @@ Http2Session::WriteSegments(nsAHttpSegmentWriter *writer,
|
||||||
// This will happen when the transaction figures out it is EOF, generally
|
// 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
|
// due to a content-length match being made. Return OK from this function
|
||||||
// otherwise the whole session would be torn down.
|
// otherwise the whole session would be torn down.
|
||||||
Http2Stream *stream = mInputFrameDataStream;
|
|
||||||
|
|
||||||
// if we were doing PROCESSING_COMPLETE_HEADERS need to pop the state
|
// if we were doing PROCESSING_COMPLETE_HEADERS need to pop the state
|
||||||
// back to PROCESSING_DATA_FRAME where we came from
|
// back to PROCESSING_DATA_FRAME where we came from
|
||||||
|
@ -2302,8 +2322,8 @@ Http2Session::WriteSegments(nsAHttpSegmentWriter *writer,
|
||||||
this, stream, stream ? stream->StreamID() : 0,
|
this, stream, stream ? stream->StreamID() : 0,
|
||||||
mNeedsCleanup, rv));
|
mNeedsCleanup, rv));
|
||||||
CleanupStream(stream, NS_OK, CANCEL_ERROR);
|
CleanupStream(stream, NS_OK, CANCEL_ERROR);
|
||||||
MOZ_ASSERT(!mNeedsCleanup, "double cleanup out of data frame");
|
MOZ_ASSERT(!mNeedsCleanup || mNeedsCleanup == stream);
|
||||||
mNeedsCleanup = nullptr; /* just in case */
|
mNeedsCleanup = nullptr;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2794,6 +2814,80 @@ Http2Session::ConnectPushedStream(Http2Stream *stream)
|
||||||
ForceRecv();
|
ForceRecv();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
Http2Session::FindTunnelCount(nsHttpConnectionInfo *aConnInfo)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||||
|
uint32_t rv = 0;
|
||||||
|
mTunnelHash.Get(aConnInfo->HashKey(), &rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Http2Session::RegisterTunnel(Http2Stream *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(("Http2Stream::RegisterTunnel %p stream=%p tunnels=%d [%s]",
|
||||||
|
this, aTunnel, newcount, ci->HashKey().get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Http2Session::UnRegisterTunnel(Http2Stream *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(("Http2Session::UnRegisterTunnel %p stream=%p tunnels=%d [%s]",
|
||||||
|
this, aTunnel, newcount, ci->HashKey().get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Http2Session::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
|
||||||
|
nsIInterfaceRequestor *aCallbacks)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||||
|
nsHttpTransaction *trans = aHttpTransaction->QueryHttpTransaction();
|
||||||
|
nsHttpConnectionInfo *ci = aHttpTransaction->ConnectionInfo();
|
||||||
|
MOZ_ASSERT(trans);
|
||||||
|
|
||||||
|
LOG3(("Http2Session::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(("Http2Session::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);
|
||||||
|
Http2Stream *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.
|
||||||
|
trans->EnableKeepAlive();
|
||||||
|
gHttpHandler->InitiateTransaction(trans, trans->Priority());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
Http2Session::BufferOutput(const char *buf,
|
Http2Session::BufferOutput(const char *buf,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
|
@ -2894,6 +2988,12 @@ Http2Session::TransactionHasDataToWrite(nsAHttpTransaction *caller)
|
||||||
|
|
||||||
mReadyForWrite.Push(stream);
|
mReadyForWrite.Push(stream);
|
||||||
SetWriteCallbacks();
|
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
|
void
|
||||||
|
@ -2905,6 +3005,7 @@ Http2Session::TransactionHasDataToWrite(Http2Stream *stream)
|
||||||
|
|
||||||
mReadyForWrite.Push(stream);
|
mReadyForWrite.Push(stream);
|
||||||
SetWriteCallbacks();
|
SetWriteCallbacks();
|
||||||
|
ForceSend();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace net {
|
||||||
|
|
||||||
class Http2PushedStream;
|
class Http2PushedStream;
|
||||||
class Http2Stream;
|
class Http2Stream;
|
||||||
|
class nsHttpTransaction;
|
||||||
|
|
||||||
class Http2Session MOZ_FINAL : public ASpdySession
|
class Http2Session MOZ_FINAL : public ASpdySession
|
||||||
, public nsAHttpConnection
|
, public nsAHttpConnection
|
||||||
|
@ -445,6 +446,15 @@ private:
|
||||||
// by the load group and the serial number can be used as part of the cache key
|
// 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.
|
// to make sure streams aren't shared across sessions.
|
||||||
uint64_t mSerial;
|
uint64_t mSerial;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// connect tunnels
|
||||||
|
void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);
|
||||||
|
void RegisterTunnel(Http2Stream *);
|
||||||
|
void UnRegisterTunnel(Http2Stream *);
|
||||||
|
uint32_t FindTunnelCount(nsHttpConnectionInfo *);
|
||||||
|
|
||||||
|
nsDataHashtable<nsCStringHashKey, uint32_t> mTunnelHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla::net
|
} // namespace mozilla::net
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "Http2Session.h"
|
#include "Http2Session.h"
|
||||||
#include "Http2Stream.h"
|
#include "Http2Stream.h"
|
||||||
#include "Http2Push.h"
|
#include "Http2Push.h"
|
||||||
|
#include "TunnelUtils.h"
|
||||||
|
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
#include "nsAlgorithm.h"
|
#include "nsAlgorithm.h"
|
||||||
|
@ -67,6 +68,7 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction,
|
||||||
, mTotalSent(0)
|
, mTotalSent(0)
|
||||||
, mTotalRead(0)
|
, mTotalRead(0)
|
||||||
, mPushSource(nullptr)
|
, mPushSource(nullptr)
|
||||||
|
, mIsTunnel(false)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||||
|
|
||||||
|
@ -96,6 +98,7 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction,
|
||||||
|
|
||||||
Http2Stream::~Http2Stream()
|
Http2Stream::~Http2Stream()
|
||||||
{
|
{
|
||||||
|
ClearTransactionsBlockedOnTunnel();
|
||||||
mStreamID = Http2Session::kDeadStreamID;
|
mStreamID = Http2Session::kDeadStreamID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +144,9 @@ Http2Stream::ReadSegments(nsAHttpSegmentReader *reader,
|
||||||
rv = mTransaction->ReadSegments(this, count, countRead);
|
rv = mTransaction->ReadSegments(this, count, countRead);
|
||||||
mSegmentReader = nullptr;
|
mSegmentReader = nullptr;
|
||||||
|
|
||||||
|
LOG3(("Http2Stream::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.
|
// 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 not, mark the stream for callback when writing can proceed.
|
||||||
if (NS_SUCCEEDED(rv) &&
|
if (NS_SUCCEEDED(rv) &&
|
||||||
|
@ -165,7 +171,7 @@ Http2Stream::ReadSegments(nsAHttpSegmentReader *reader,
|
||||||
if (!mBlockedOnRwin &&
|
if (!mBlockedOnRwin &&
|
||||||
!mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
|
!mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
|
||||||
LOG3(("Http2Stream::ReadSegments %p 0x%X: Sending request data complete, "
|
LOG3(("Http2Stream::ReadSegments %p 0x%X: Sending request data complete, "
|
||||||
"mUpstreamState=%x",this, mStreamID, mUpstreamState));
|
"mUpstreamState=%x\n",this, mStreamID, mUpstreamState));
|
||||||
if (mSentFin) {
|
if (mSentFin) {
|
||||||
ChangeState(UPSTREAM_COMPLETE);
|
ChangeState(UPSTREAM_COMPLETE);
|
||||||
} else {
|
} else {
|
||||||
|
@ -268,6 +274,7 @@ Http2Stream::ParseHttpRequestHeaders(const char *buf,
|
||||||
this, avail, mUpstreamState));
|
this, avail, mUpstreamState));
|
||||||
|
|
||||||
mFlatHttpRequestHeaders.Append(buf, avail);
|
mFlatHttpRequestHeaders.Append(buf, avail);
|
||||||
|
nsHttpRequestHead *head = mTransaction->RequestHead();
|
||||||
|
|
||||||
// We can use the simple double crlf because firefox is the
|
// We can use the simple double crlf because firefox is the
|
||||||
// only client we are parsing
|
// only client we are parsing
|
||||||
|
@ -290,17 +297,17 @@ Http2Stream::ParseHttpRequestHeaders(const char *buf,
|
||||||
*countUsed = avail - (oldLen - endHeader) + 4;
|
*countUsed = avail - (oldLen - endHeader) + 4;
|
||||||
mAllHeadersSent = 1;
|
mAllHeadersSent = 1;
|
||||||
|
|
||||||
nsAutoCString hostHeader;
|
nsAutoCString authorityHeader;
|
||||||
nsAutoCString hashkey;
|
nsAutoCString hashkey;
|
||||||
mTransaction->RequestHead()->GetHeader(nsHttp::Host, hostHeader);
|
head->GetHeader(nsHttp::Host, authorityHeader);
|
||||||
|
|
||||||
CreatePushHashKey(NS_LITERAL_CSTRING("https"),
|
CreatePushHashKey(nsDependentCString(head->IsHTTPS() ? "https" : "http"),
|
||||||
hostHeader, mSession->Serial(),
|
authorityHeader, mSession->Serial(),
|
||||||
mTransaction->RequestHead()->RequestURI(),
|
head->RequestURI(),
|
||||||
mOrigin, hashkey);
|
mOrigin, hashkey);
|
||||||
|
|
||||||
// check the push cache for GET
|
// check the push cache for GET
|
||||||
if (mTransaction->RequestHead()->IsGet()) {
|
if (head->IsGet()) {
|
||||||
// from :scheme, :authority, :path
|
// from :scheme, :authority, :path
|
||||||
nsILoadGroupConnectionInfo *loadGroupCI = mTransaction->LoadGroupConnectionInfo();
|
nsILoadGroupConnectionInfo *loadGroupCI = mTransaction->LoadGroupConnectionInfo();
|
||||||
SpdyPushCache *cache = nullptr;
|
SpdyPushCache *cache = nullptr;
|
||||||
|
@ -347,7 +354,7 @@ Http2Stream::ParseHttpRequestHeaders(const char *buf,
|
||||||
MOZ_ASSERT(mStreamID & 1, "Http2 Stream Channel ID must be odd");
|
MOZ_ASSERT(mStreamID & 1, "Http2 Stream Channel ID must be odd");
|
||||||
LOG3(("Stream ID 0x%X [session=%p] for URI %s\n",
|
LOG3(("Stream ID 0x%X [session=%p] for URI %s\n",
|
||||||
mStreamID, mSession,
|
mStreamID, mSession,
|
||||||
nsCString(mTransaction->RequestHead()->RequestURI()).get()));
|
nsCString(head->RequestURI()).get()));
|
||||||
|
|
||||||
if (mStreamID >= 0x80000000) {
|
if (mStreamID >= 0x80000000) {
|
||||||
// streamID must fit in 31 bits. Evading This is theoretically possible
|
// streamID must fit in 31 bits. Evading This is theoretically possible
|
||||||
|
@ -366,28 +373,46 @@ Http2Stream::ParseHttpRequestHeaders(const char *buf,
|
||||||
// of HTTP/2 headers by writing to mTxInlineFrame{sz}
|
// of HTTP/2 headers by writing to mTxInlineFrame{sz}
|
||||||
|
|
||||||
nsCString compressedData;
|
nsCString compressedData;
|
||||||
|
nsDependentCString scheme(head->IsHTTPS() ? "https" : "http");
|
||||||
|
if (head->IsConnect()) {
|
||||||
|
MOZ_ASSERT(mTransaction->QuerySpdyConnectTransaction());
|
||||||
|
mIsTunnel = true;
|
||||||
|
mRequestBodyLenRemaining = 0x0fffffffffffffffULL;
|
||||||
|
|
||||||
|
// Our normal authority has an implicit port, best to use an
|
||||||
|
// explicit one with a tunnel
|
||||||
|
nsHttpConnectionInfo *ci = mTransaction->ConnectionInfo();
|
||||||
|
if (!ci) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
authorityHeader = ci->GetHost();
|
||||||
|
authorityHeader.AppendLiteral(":");
|
||||||
|
authorityHeader.AppendInt(ci->Port());
|
||||||
|
}
|
||||||
|
|
||||||
mSession->Compressor()->EncodeHeaderBlock(mFlatHttpRequestHeaders,
|
mSession->Compressor()->EncodeHeaderBlock(mFlatHttpRequestHeaders,
|
||||||
mTransaction->RequestHead()->Method(),
|
head->Method(),
|
||||||
mTransaction->RequestHead()->RequestURI(),
|
head->RequestURI(),
|
||||||
hostHeader,
|
authorityHeader,
|
||||||
NS_LITERAL_CSTRING("https"),
|
scheme,
|
||||||
|
head->IsConnect(),
|
||||||
compressedData);
|
compressedData);
|
||||||
|
|
||||||
// Determine whether to put the fin bit on the header frame or whether
|
// Determine whether to put the fin bit on the header frame or whether
|
||||||
// to wait for a data packet to put it on.
|
// to wait for a data packet to put it on.
|
||||||
uint8_t firstFrameFlags = Http2Session::kFlag_PRIORITY;
|
uint8_t firstFrameFlags = Http2Session::kFlag_PRIORITY;
|
||||||
|
|
||||||
if (mTransaction->RequestHead()->IsGet() ||
|
if (head->IsGet() ||
|
||||||
mTransaction->RequestHead()->IsConnect() ||
|
head->IsHead()) {
|
||||||
mTransaction->RequestHead()->IsHead()) {
|
// for GET and HEAD place the fin bit right on the
|
||||||
// for GET, CONNECT, and HEAD place the fin bit right on the
|
|
||||||
// header packet
|
// header packet
|
||||||
|
|
||||||
SetSentFin(true);
|
SetSentFin(true);
|
||||||
firstFrameFlags |= Http2Session::kFlag_END_STREAM;
|
firstFrameFlags |= Http2Session::kFlag_END_STREAM;
|
||||||
} else if (mTransaction->RequestHead()->IsPost() ||
|
} else if (head->IsPost() ||
|
||||||
mTransaction->RequestHead()->IsPut() ||
|
head->IsPut() ||
|
||||||
mTransaction->RequestHead()->IsOptions()) {
|
head->IsConnect() ||
|
||||||
|
head->IsOptions()) {
|
||||||
// place fin in a data frame even for 0 length messages for iterop
|
// place fin in a data frame even for 0 length messages for iterop
|
||||||
} else if (!mRequestBodyLenRemaining) {
|
} else if (!mRequestBodyLenRemaining) {
|
||||||
// for other HTTP extension methods, rely on the content-length
|
// for other HTTP extension methods, rely on the content-length
|
||||||
|
@ -473,7 +498,7 @@ Http2Stream::ParseHttpRequestHeaders(const char *buf,
|
||||||
// The size of the input headers is approximate
|
// The size of the input headers is approximate
|
||||||
uint32_t ratio =
|
uint32_t ratio =
|
||||||
compressedData.Length() * 100 /
|
compressedData.Length() * 100 /
|
||||||
(11 + mTransaction->RequestHead()->RequestURI().Length() +
|
(11 + head->RequestURI().Length() +
|
||||||
mFlatHttpRequestHeaders.Length());
|
mFlatHttpRequestHeaders.Length());
|
||||||
|
|
||||||
const char *beginBuffer = mFlatHttpRequestHeaders.BeginReading();
|
const char *beginBuffer = mFlatHttpRequestHeaders.BeginReading();
|
||||||
|
@ -599,6 +624,10 @@ void
|
||||||
Http2Stream::UpdateTransportReadEvents(uint32_t count)
|
Http2Stream::UpdateTransportReadEvents(uint32_t count)
|
||||||
{
|
{
|
||||||
mTotalRead += count;
|
mTotalRead += count;
|
||||||
|
if (!mSocketTransport) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mTransaction->OnTransportStatus(mSocketTransport,
|
mTransaction->OnTransportStatus(mSocketTransport,
|
||||||
NS_NET_STATUS_RECEIVING_FROM,
|
NS_NET_STATUS_RECEIVING_FROM,
|
||||||
mTotalRead);
|
mTotalRead);
|
||||||
|
@ -831,6 +860,14 @@ Http2Stream::ConvertResponseHeaders(Http2Decompressor *decompressor,
|
||||||
return NS_ERROR_ILLEGAL_VALUE;
|
return NS_ERROR_ILLEGAL_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mIsTunnel) {
|
||||||
|
nsresult errcode;
|
||||||
|
if (status.ToInteger(&errcode) != 200) {
|
||||||
|
LOG3(("Http2Stream %p Tunnel not 200", this));
|
||||||
|
return NS_ERROR_ABORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (aHeadersIn.Length() && aHeadersOut.Length()) {
|
if (aHeadersIn.Length() && aHeadersOut.Length()) {
|
||||||
Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_SIZE, aHeadersIn.Length());
|
Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_SIZE, aHeadersIn.Length());
|
||||||
uint32_t ratio =
|
uint32_t ratio =
|
||||||
|
@ -841,6 +878,11 @@ Http2Stream::ConvertResponseHeaders(Http2Decompressor *decompressor,
|
||||||
aHeadersIn.Truncate();
|
aHeadersIn.Truncate();
|
||||||
aHeadersOut.Append(NS_LITERAL_CSTRING("X-Firefox-Spdy: " NS_HTTP2_DRAFT_TOKEN "\r\n\r\n"));
|
aHeadersOut.Append(NS_LITERAL_CSTRING("X-Firefox-Spdy: " NS_HTTP2_DRAFT_TOKEN "\r\n\r\n"));
|
||||||
LOG (("decoded response headers are:\n%s", aHeadersOut.BeginReading()));
|
LOG (("decoded response headers are:\n%s", aHeadersOut.BeginReading()));
|
||||||
|
if (mIsTunnel) {
|
||||||
|
aHeadersOut.Truncate();
|
||||||
|
LOG(("SpdyStream3::ConvertHeaders %p 0x%X headers removed for tunnel\n",
|
||||||
|
this, mStreamID));
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -891,6 +933,13 @@ Http2Stream::Close(nsresult reason)
|
||||||
mTransaction->Close(reason);
|
mTransaction->Close(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
Http2Stream::SetAllHeadersReceived(bool aStatus)
|
||||||
|
{
|
||||||
|
mAllHeadersReceived = aStatus ? 1 : 0;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Http2Stream::AllowFlowControlledWrite()
|
Http2Stream::AllowFlowControlledWrite()
|
||||||
{
|
{
|
||||||
|
@ -1057,11 +1106,15 @@ Http2Stream::OnReadSegment(const char *buf,
|
||||||
mSession->DecrementServerSessionWindow(dataLength);
|
mSession->DecrementServerSessionWindow(dataLength);
|
||||||
mServerReceiveWindow -= dataLength;
|
mServerReceiveWindow -= dataLength;
|
||||||
|
|
||||||
LOG3(("Http2Stream %p id %x request len remaining %d, "
|
LOG3(("Http2Stream %p id %x request len remaining %u, "
|
||||||
"count avail %d, chunk used %d",
|
"count avail %u, chunk used %u",
|
||||||
this, mStreamID, mRequestBodyLenRemaining, count, dataLength));
|
this, mStreamID, mRequestBodyLenRemaining, count, dataLength));
|
||||||
if (dataLength > mRequestBodyLenRemaining)
|
if (!dataLength && mRequestBodyLenRemaining) {
|
||||||
|
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||||
|
}
|
||||||
|
if (dataLength > mRequestBodyLenRemaining) {
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
mRequestBodyLenRemaining -= dataLength;
|
mRequestBodyLenRemaining -= dataLength;
|
||||||
GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining);
|
GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining);
|
||||||
ChangeState(SENDING_BODY);
|
ChangeState(SENDING_BODY);
|
||||||
|
@ -1127,6 +1180,28 @@ Http2Stream::OnWriteSegment(char *buf,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// connect tunnels
|
||||||
|
|
||||||
|
void
|
||||||
|
Http2Stream::ClearTransactionsBlockedOnTunnel()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||||
|
|
||||||
|
if (!mIsTunnel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Http2Stream::MapStreamToHttpConnection()
|
||||||
|
{
|
||||||
|
nsRefPtr<SpdyConnectTransaction> qiTrans(mTransaction->QuerySpdyConnectTransaction());
|
||||||
|
MOZ_ASSERT(qiTrans);
|
||||||
|
qiTrans->MapStreamToHttpConnection(mSocketTransport,
|
||||||
|
mTransaction->ConnectionInfo());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla::net
|
} // namespace mozilla::net
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -81,12 +81,15 @@ public:
|
||||||
void SetCountAsActive(bool aStatus) { mCountAsActive = aStatus ? 1 : 0; }
|
void SetCountAsActive(bool aStatus) { mCountAsActive = aStatus ? 1 : 0; }
|
||||||
bool CountAsActive() { return mCountAsActive; }
|
bool CountAsActive() { return mCountAsActive; }
|
||||||
|
|
||||||
void SetAllHeadersReceived(bool aStatus) { mAllHeadersReceived = aStatus ? 1 : 0; }
|
// returns failure if stream cannot be made ready and stream
|
||||||
|
// should be canceled
|
||||||
|
nsresult SetAllHeadersReceived(bool aStatus);
|
||||||
bool AllHeadersReceived() { return mAllHeadersReceived; }
|
bool AllHeadersReceived() { return mAllHeadersReceived; }
|
||||||
|
|
||||||
void UpdateTransportSendEvents(uint32_t count);
|
void UpdateTransportSendEvents(uint32_t count);
|
||||||
void UpdateTransportReadEvents(uint32_t count);
|
void UpdateTransportReadEvents(uint32_t count);
|
||||||
|
|
||||||
|
// NS_ERROR_ABORT terminates stream, other failure terminates session
|
||||||
nsresult ConvertResponseHeaders(Http2Decompressor *, nsACString &, nsACString &);
|
nsresult ConvertResponseHeaders(Http2Decompressor *, nsACString &, nsACString &);
|
||||||
nsresult ConvertPushHeaders(Http2Decompressor *, nsACString &, nsACString &);
|
nsresult ConvertPushHeaders(Http2Decompressor *, nsACString &, nsACString &);
|
||||||
|
|
||||||
|
@ -234,7 +237,8 @@ private:
|
||||||
// place the fin flag on the last data packet instead of waiting
|
// place the fin flag on the last data packet instead of waiting
|
||||||
// for a stream closed indication. Relying on stream close results
|
// for a stream closed indication. Relying on stream close results
|
||||||
// in an extra 0-length runt packet and seems to have some interop
|
// 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;
|
int64_t mRequestBodyLenRemaining;
|
||||||
|
|
||||||
uint32_t mPriority;
|
uint32_t mPriority;
|
||||||
|
@ -267,6 +271,15 @@ private:
|
||||||
|
|
||||||
// For Http2Push
|
// For Http2Push
|
||||||
Http2PushedStream *mPushSource;
|
Http2PushedStream *mPushSource;
|
||||||
|
|
||||||
|
/// connect tunnels
|
||||||
|
public:
|
||||||
|
bool IsTunnel() { return mIsTunnel; }
|
||||||
|
private:
|
||||||
|
void ClearTransactionsBlockedOnTunnel();
|
||||||
|
void MapStreamToHttpConnection();
|
||||||
|
|
||||||
|
bool mIsTunnel;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla::net
|
} // namespace mozilla::net
|
||||||
|
|
|
@ -351,23 +351,23 @@ SpdySession31::AddStream(nsAHttpTransaction *aHttpTransaction,
|
||||||
return false;
|
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) {
|
if (!mConnection) {
|
||||||
mConnection = aHttpTransaction->Connection();
|
mConnection = aHttpTransaction->Connection();
|
||||||
}
|
}
|
||||||
|
|
||||||
aHttpTransaction->SetConnection(this);
|
aHttpTransaction->SetConnection(this);
|
||||||
|
|
||||||
|
if (aUseTunnel) {
|
||||||
|
LOG3(("SpdySession31::AddStream session=%p trans=%p OnTunnel",
|
||||||
|
this, aHttpTransaction));
|
||||||
|
DispatchOnTunnel(aHttpTransaction, aCallbacks);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
SpdyStream31 *stream = new SpdyStream31(aHttpTransaction, this, aPriority);
|
SpdyStream31 *stream = new SpdyStream31(aHttpTransaction, this, aPriority);
|
||||||
|
|
||||||
LOG3(("SpdySession31::AddStream session=%p stream=%p NextID=0x%X (tentative)",
|
LOG3(("SpdySession31::AddStream session=%p stream=%p serial=%u "
|
||||||
this, stream, mNextStreamID));
|
"NextID=0x%X (tentative)", this, stream, mSerial, mNextStreamID));
|
||||||
|
|
||||||
mStreamTransactionHash.Put(aHttpTransaction, stream);
|
mStreamTransactionHash.Put(aHttpTransaction, stream);
|
||||||
|
|
||||||
|
@ -946,6 +946,10 @@ SpdySession31::CloseStream(SpdyStream31 *aStream, nsresult aResult)
|
||||||
|
|
||||||
RemoveStreamFromQueues(aStream);
|
RemoveStreamFromQueues(aStream);
|
||||||
|
|
||||||
|
if (aStream->IsTunnel()) {
|
||||||
|
UnRegisterTunnel(aStream);
|
||||||
|
}
|
||||||
|
|
||||||
// Send the stream the close() indication
|
// Send the stream the close() indication
|
||||||
aStream->Close(aResult);
|
aStream->Close(aResult);
|
||||||
}
|
}
|
||||||
|
@ -1067,7 +1071,13 @@ SpdySession31::HandleSynStream(SpdySession31 *self)
|
||||||
self->mPushedStreams.AppendElement(pushedStream);
|
self->mPushedStreams.AppendElement(pushedStream);
|
||||||
|
|
||||||
// The pushed stream is unidirectional so it is fully open immediately
|
// The pushed stream is unidirectional so it is fully open immediately
|
||||||
pushedStream->SetFullyOpen();
|
rv = pushedStream->SetFullyOpen();
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
LOG(("SpdySession31::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
|
// Uncompress the response headers into a stream specific buffer, leaving them
|
||||||
// in spdy format for the time being.
|
// in spdy format for the time being.
|
||||||
|
@ -1140,10 +1150,10 @@ SpdySession31::HandleSynReply(SpdySession31 *self)
|
||||||
return NS_ERROR_ILLEGAL_VALUE;
|
return NS_ERROR_ILLEGAL_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG3(("SpdySession31::HandleSynReply %p lookup via streamID in syn_reply.\n",
|
|
||||||
self));
|
|
||||||
uint32_t streamID =
|
uint32_t streamID =
|
||||||
PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
|
PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
|
||||||
|
LOG3(("SpdySession31::HandleSynReply %p lookup via streamID 0x%X in syn_reply.\n",
|
||||||
|
self, streamID));
|
||||||
nsresult rv = self->SetInputFrameDataStream(streamID);
|
nsresult rv = self->SetInputFrameDataStream(streamID);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -1206,7 +1216,19 @@ SpdySession31::HandleSynReply(SpdySession31 *self)
|
||||||
self->ResetDownstreamState();
|
self->ResetDownstreamState();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
self->mInputFrameDataStream->SetFullyOpen();
|
|
||||||
|
rv = self->mInputFrameDataStream->SetFullyOpen();
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
LOG(("SpdySession31::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->mInputFrameDataLast = self->mInputFrameBuffer[4] & kFlag_Data_FIN;
|
||||||
self->mInputFrameDataStream->UpdateTransportReadEvents(self->mInputFrameDataSize);
|
self->mInputFrameDataStream->UpdateTransportReadEvents(self->mInputFrameDataSize);
|
||||||
|
@ -2067,6 +2089,7 @@ SpdySession31::WriteSegments(nsAHttpSegmentWriter *writer,
|
||||||
MOZ_ASSERT(!mNeedsCleanup, "cleanup stream set unexpectedly");
|
MOZ_ASSERT(!mNeedsCleanup, "cleanup stream set unexpectedly");
|
||||||
mNeedsCleanup = nullptr; /* just in case */
|
mNeedsCleanup = nullptr; /* just in case */
|
||||||
|
|
||||||
|
SpdyStream31 *stream = mInputFrameDataStream;
|
||||||
mSegmentWriter = writer;
|
mSegmentWriter = writer;
|
||||||
rv = mInputFrameDataStream->WriteSegments(this, count, countWritten);
|
rv = mInputFrameDataStream->WriteSegments(this, count, countWritten);
|
||||||
mSegmentWriter = nullptr;
|
mSegmentWriter = nullptr;
|
||||||
|
@ -2077,7 +2100,6 @@ SpdySession31::WriteSegments(nsAHttpSegmentWriter *writer,
|
||||||
// This will happen when the transaction figures out it is EOF, generally
|
// 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
|
// due to a content-length match being made. Return OK from this function
|
||||||
// otherwise the whole session would be torn down.
|
// otherwise the whole session would be torn down.
|
||||||
SpdyStream31 *stream = mInputFrameDataStream;
|
|
||||||
|
|
||||||
// if we were doing PROCESSING_COMPLETE_HEADERS need to pop the state
|
// if we were doing PROCESSING_COMPLETE_HEADERS need to pop the state
|
||||||
// back to PROCESSING_DATA_FRAME where we came from
|
// back to PROCESSING_DATA_FRAME where we came from
|
||||||
|
@ -2091,8 +2113,8 @@ SpdySession31::WriteSegments(nsAHttpSegmentWriter *writer,
|
||||||
this, stream, stream ? stream->StreamID() : 0,
|
this, stream, stream ? stream->StreamID() : 0,
|
||||||
mNeedsCleanup, rv));
|
mNeedsCleanup, rv));
|
||||||
CleanupStream(stream, NS_OK, RST_CANCEL);
|
CleanupStream(stream, NS_OK, RST_CANCEL);
|
||||||
MOZ_ASSERT(!mNeedsCleanup, "double cleanup out of data frame");
|
MOZ_ASSERT(!mNeedsCleanup || mNeedsCleanup == stream);
|
||||||
mNeedsCleanup = nullptr; /* just in case */
|
mNeedsCleanup = nullptr;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2579,6 +2601,79 @@ SpdySession31::ConnectPushedStream(SpdyStream31 *stream)
|
||||||
ForceRecv();
|
ForceRecv();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
SpdySession31::FindTunnelCount(nsHttpConnectionInfo *aConnInfo)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||||
|
uint32_t rv = 0;
|
||||||
|
mTunnelHash.Get(aConnInfo->HashKey(), &rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SpdySession31::RegisterTunnel(SpdyStream31 *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(("SpdySession31::RegisterTunnel %p stream=%p tunnels=%d [%s]",
|
||||||
|
this, aTunnel, newcount, ci->HashKey().get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SpdySession31::UnRegisterTunnel(SpdyStream31 *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(("SpdySession31::UnRegisterTunnel %p stream=%p tunnels=%d [%s]",
|
||||||
|
this, aTunnel, newcount, ci->HashKey().get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SpdySession31::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
|
||||||
|
nsIInterfaceRequestor *aCallbacks)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||||
|
nsHttpTransaction *trans = aHttpTransaction->QueryHttpTransaction();
|
||||||
|
nsHttpConnectionInfo *ci = aHttpTransaction->ConnectionInfo();
|
||||||
|
MOZ_ASSERT(trans);
|
||||||
|
|
||||||
|
LOG3(("SpdySession31::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(("SpdySession31::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);
|
||||||
|
SpdyStream31 *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.
|
||||||
|
trans->EnableKeepAlive();
|
||||||
|
gHttpHandler->InitiateTransaction(trans, trans->Priority());
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
SpdySession31::BufferOutput(const char *buf,
|
SpdySession31::BufferOutput(const char *buf,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
|
@ -2616,6 +2711,11 @@ SpdySession31::TransactionHasDataToWrite(nsAHttpTransaction *caller)
|
||||||
|
|
||||||
mReadyForWrite.Push(stream);
|
mReadyForWrite.Push(stream);
|
||||||
SetWriteCallbacks();
|
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
|
void
|
||||||
|
@ -2627,6 +2727,7 @@ SpdySession31::TransactionHasDataToWrite(SpdyStream31 *stream)
|
||||||
|
|
||||||
mReadyForWrite.Push(stream);
|
mReadyForWrite.Push(stream);
|
||||||
SetWriteCallbacks();
|
SetWriteCallbacks();
|
||||||
|
ForceSend();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace mozilla { namespace net {
|
||||||
|
|
||||||
class SpdyPushedStream31;
|
class SpdyPushedStream31;
|
||||||
class SpdyStream31;
|
class SpdyStream31;
|
||||||
|
class nsHttpTransaction;
|
||||||
|
|
||||||
class SpdySession31 MOZ_FINAL : public ASpdySession
|
class SpdySession31 MOZ_FINAL : public ASpdySession
|
||||||
, public nsAHttpConnection
|
, public nsAHttpConnection
|
||||||
|
@ -402,6 +403,15 @@ private:
|
||||||
// by the load group and the serial number can be used as part of the cache key
|
// 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.
|
// to make sure streams aren't shared across sessions.
|
||||||
uint64_t mSerial;
|
uint64_t mSerial;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// connect tunnels
|
||||||
|
void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);
|
||||||
|
void RegisterTunnel(SpdyStream31 *);
|
||||||
|
void UnRegisterTunnel(SpdyStream31 *);
|
||||||
|
uint32_t FindTunnelCount(nsHttpConnectionInfo *);
|
||||||
|
|
||||||
|
nsDataHashtable<nsCStringHashKey, uint32_t> mTunnelHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace mozilla::net
|
}} // namespace mozilla::net
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "SpdyPush31.h"
|
#include "SpdyPush31.h"
|
||||||
#include "SpdySession31.h"
|
#include "SpdySession31.h"
|
||||||
#include "SpdyStream31.h"
|
#include "SpdyStream31.h"
|
||||||
|
#include "TunnelUtils.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ SpdyStream31::SpdyStream31(nsAHttpTransaction *httpTransaction,
|
||||||
, mTotalSent(0)
|
, mTotalSent(0)
|
||||||
, mTotalRead(0)
|
, mTotalRead(0)
|
||||||
, mPushSource(nullptr)
|
, mPushSource(nullptr)
|
||||||
|
, mIsTunnel(false)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||||
|
|
||||||
|
@ -82,6 +84,7 @@ SpdyStream31::SpdyStream31(nsAHttpTransaction *httpTransaction,
|
||||||
|
|
||||||
SpdyStream31::~SpdyStream31()
|
SpdyStream31::~SpdyStream31()
|
||||||
{
|
{
|
||||||
|
ClearTransactionsBlockedOnTunnel();
|
||||||
mStreamID = SpdySession31::kDeadStreamID;
|
mStreamID = SpdySession31::kDeadStreamID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +122,8 @@ SpdyStream31::ReadSegments(nsAHttpSegmentReader *reader,
|
||||||
mSegmentReader = reader;
|
mSegmentReader = reader;
|
||||||
rv = mTransaction->ReadSegments(this, count, countRead);
|
rv = mTransaction->ReadSegments(this, count, countRead);
|
||||||
mSegmentReader = nullptr;
|
mSegmentReader = nullptr;
|
||||||
|
LOG3(("SpdyStream31::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.
|
// 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 not, mark the stream for callback when writing can proceed.
|
||||||
if (NS_SUCCEEDED(rv) &&
|
if (NS_SUCCEEDED(rv) &&
|
||||||
|
@ -144,7 +148,8 @@ SpdyStream31::ReadSegments(nsAHttpSegmentReader *reader,
|
||||||
if (!mBlockedOnRwin &&
|
if (!mBlockedOnRwin &&
|
||||||
!mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
|
!mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
|
||||||
LOG3(("SpdyStream31::ReadSegments %p 0x%X: Sending request data complete, "
|
LOG3(("SpdyStream31::ReadSegments %p 0x%X: Sending request data complete, "
|
||||||
"mUpstreamState=%x",this, mStreamID, mUpstreamState));
|
"mUpstreamState=%x finondata=%d",this, mStreamID,
|
||||||
|
mUpstreamState, mSentFinOnData));
|
||||||
if (mSentFinOnData) {
|
if (mSentFinOnData) {
|
||||||
ChangeState(UPSTREAM_COMPLETE);
|
ChangeState(UPSTREAM_COMPLETE);
|
||||||
}
|
}
|
||||||
|
@ -464,24 +469,51 @@ SpdyStream31::ParseHttpRequestHeaders(const char *buf,
|
||||||
// headers at this same level so it is not necessary to do so here.
|
// headers at this same level so it is not necessary to do so here.
|
||||||
|
|
||||||
const char *methodHeader = mTransaction->RequestHead()->Method().get();
|
const char *methodHeader = mTransaction->RequestHead()->Method().get();
|
||||||
|
LOG3(("Stream method %p 0x%X %s\n", this, mStreamID, methodHeader));
|
||||||
|
|
||||||
// The header block length
|
// 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);
|
CompressToFrame(count);
|
||||||
|
|
||||||
// :method, :path, :version comprise a HTTP/1 request line, so send those first
|
// :method, :path, :version comprise a HTTP/1 request line, so send those first
|
||||||
// to make life easy for any gateways
|
// to make life easy for any gateways
|
||||||
CompressToFrame(NS_LITERAL_CSTRING(":method"));
|
CompressToFrame(NS_LITERAL_CSTRING(":method"));
|
||||||
CompressToFrame(methodHeader, strlen(methodHeader));
|
CompressToFrame(methodHeader, strlen(methodHeader));
|
||||||
|
|
||||||
CompressToFrame(NS_LITERAL_CSTRING(":path"));
|
CompressToFrame(NS_LITERAL_CSTRING(":path"));
|
||||||
CompressToFrame(mTransaction->RequestHead()->RequestURI());
|
if (!mTransaction->RequestHead()->IsConnect()) {
|
||||||
|
CompressToFrame(mTransaction->RequestHead()->RequestURI());
|
||||||
|
} else {
|
||||||
|
MOZ_ASSERT(mTransaction->QuerySpdyConnectTransaction());
|
||||||
|
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(NS_LITERAL_CSTRING(":version"));
|
||||||
CompressToFrame(versionHeader);
|
CompressToFrame(versionHeader);
|
||||||
|
|
||||||
CompressToFrame(NS_LITERAL_CSTRING(":host"));
|
CompressToFrame(NS_LITERAL_CSTRING(":host"));
|
||||||
CompressToFrame(hostHeader);
|
CompressToFrame(hostHeader);
|
||||||
CompressToFrame(NS_LITERAL_CSTRING(":scheme"));
|
|
||||||
CompressToFrame(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"));
|
if (!mTransaction->RequestHead()->IsConnect()) {
|
||||||
|
// no :scheme with connect
|
||||||
|
CompressToFrame(NS_LITERAL_CSTRING(":scheme"));
|
||||||
|
CompressToFrame(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"));
|
||||||
|
}
|
||||||
|
|
||||||
hdrHash.Enumerate(hdrHashEnumerate, this);
|
hdrHash.Enumerate(hdrHashEnumerate, this);
|
||||||
CompressFlushFrame();
|
CompressFlushFrame();
|
||||||
|
@ -496,9 +528,8 @@ SpdyStream31::ParseHttpRequestHeaders(const char *buf,
|
||||||
// to wait for a data packet to put it on.
|
// to wait for a data packet to put it on.
|
||||||
|
|
||||||
if (mTransaction->RequestHead()->IsGet() ||
|
if (mTransaction->RequestHead()->IsGet() ||
|
||||||
mTransaction->RequestHead()->IsConnect() ||
|
|
||||||
mTransaction->RequestHead()->IsHead()) {
|
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
|
// syn stream packet
|
||||||
|
|
||||||
mSentFinOnData = 1;
|
mSentFinOnData = 1;
|
||||||
|
@ -506,6 +537,7 @@ SpdyStream31::ParseHttpRequestHeaders(const char *buf,
|
||||||
}
|
}
|
||||||
else if (mTransaction->RequestHead()->IsPost() ||
|
else if (mTransaction->RequestHead()->IsPost() ||
|
||||||
mTransaction->RequestHead()->IsPut() ||
|
mTransaction->RequestHead()->IsPut() ||
|
||||||
|
mTransaction->RequestHead()->IsConnect() ||
|
||||||
mTransaction->RequestHead()->IsOptions()) {
|
mTransaction->RequestHead()->IsOptions()) {
|
||||||
// place fin in a data frame even for 0 length messages, I've seen
|
// 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
|
// the google gateway be unhappy with fin-on-syn for 0 length POST
|
||||||
|
@ -600,6 +632,9 @@ void
|
||||||
SpdyStream31::UpdateTransportReadEvents(uint32_t count)
|
SpdyStream31::UpdateTransportReadEvents(uint32_t count)
|
||||||
{
|
{
|
||||||
mTotalRead += count;
|
mTotalRead += count;
|
||||||
|
if (!mSocketTransport) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mTransaction->OnTransportStatus(mSocketTransport,
|
mTransaction->OnTransportStatus(mSocketTransport,
|
||||||
NS_NET_STATUS_RECEIVING_FROM,
|
NS_NET_STATUS_RECEIVING_FROM,
|
||||||
|
@ -1262,6 +1297,12 @@ SpdyStream31::ConvertHeaders(nsACString &aHeadersOut)
|
||||||
mDecompressBufferSize = 0;
|
mDecompressBufferSize = 0;
|
||||||
mDecompressBufferUsed = 0;
|
mDecompressBufferUsed = 0;
|
||||||
|
|
||||||
|
if (mIsTunnel) {
|
||||||
|
aHeadersOut.Truncate();
|
||||||
|
LOG(("SpdyStream31::ConvertHeaders %p 0x%X headers removed for tunnel\n",
|
||||||
|
this, mStreamID));
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1327,6 +1368,38 @@ SpdyStream31::CompressFlushFrame()
|
||||||
ExecuteCompress(Z_SYNC_FLUSH);
|
ExecuteCompress(Z_SYNC_FLUSH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SpdyStream31::GetFullyOpen()
|
||||||
|
{
|
||||||
|
return mFullyOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SpdyStream31::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(("SpdyStream31::SetFullyOpen %p Tunnel not 200", this));
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
LOG3(("SpdyStream31::SetFullyOpen %p Tunnel 200 OK", this));
|
||||||
|
}
|
||||||
|
|
||||||
|
MapStreamToHttpConnection();
|
||||||
|
ClearTransactionsBlockedOnTunnel();
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SpdyStream31::Close(nsresult reason)
|
SpdyStream31::Close(nsresult reason)
|
||||||
{
|
{
|
||||||
|
@ -1420,11 +1493,15 @@ SpdyStream31::OnReadSegment(const char *buf,
|
||||||
mRemoteWindow -= dataLength;
|
mRemoteWindow -= dataLength;
|
||||||
mSession->DecrementRemoteSessionWindow(dataLength);
|
mSession->DecrementRemoteSessionWindow(dataLength);
|
||||||
|
|
||||||
LOG3(("SpdyStream31 %p id %x request len remaining %d, "
|
LOG3(("SpdyStream31 %p id %x request len remaining %u, "
|
||||||
"count avail %d, chunk used %d",
|
"count avail %u, chunk used %u",
|
||||||
this, mStreamID, mRequestBodyLenRemaining, count, dataLength));
|
this, mStreamID, mRequestBodyLenRemaining, count, dataLength));
|
||||||
if (dataLength > mRequestBodyLenRemaining)
|
if (!dataLength && mRequestBodyLenRemaining) {
|
||||||
|
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||||
|
}
|
||||||
|
if (dataLength > mRequestBodyLenRemaining) {
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
mRequestBodyLenRemaining -= dataLength;
|
mRequestBodyLenRemaining -= dataLength;
|
||||||
GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining);
|
GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining);
|
||||||
ChangeState(SENDING_REQUEST_BODY);
|
ChangeState(SENDING_REQUEST_BODY);
|
||||||
|
@ -1490,6 +1567,27 @@ SpdyStream31::OnWriteSegment(char *buf,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// connect tunnels
|
||||||
|
|
||||||
|
void
|
||||||
|
SpdyStream31::ClearTransactionsBlockedOnTunnel()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||||
|
|
||||||
|
if (!mIsTunnel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SpdyStream31::MapStreamToHttpConnection()
|
||||||
|
{
|
||||||
|
nsRefPtr<SpdyConnectTransaction> qiTrans(mTransaction->QuerySpdyConnectTransaction());
|
||||||
|
MOZ_ASSERT(qiTrans);
|
||||||
|
qiTrans->MapStreamToHttpConnection(mSocketTransport,
|
||||||
|
mTransaction->ConnectionInfo());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla::net
|
} // namespace mozilla::net
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,10 @@ public:
|
||||||
return static_cast<bool>(mRequestBlockedOnRead);
|
return static_cast<bool>(mRequestBlockedOnRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns false if called more than once
|
bool GetFullyOpen();
|
||||||
bool GetFullyOpen() {return mFullyOpen;}
|
// returns failure if stream cannot be made ready and stream
|
||||||
void SetFullyOpen()
|
// should be canceled
|
||||||
{
|
nsresult SetFullyOpen();
|
||||||
MOZ_ASSERT(!mFullyOpen);
|
|
||||||
mFullyOpen = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasRegisteredID() { return mStreamID != 0; }
|
bool HasRegisteredID() { return mStreamID != 0; }
|
||||||
|
|
||||||
|
@ -215,7 +212,8 @@ private:
|
||||||
// place the fin flag on the last data packet instead of waiting
|
// place the fin flag on the last data packet instead of waiting
|
||||||
// for a stream closed indication. Relying on stream close results
|
// for a stream closed indication. Relying on stream close results
|
||||||
// in an extra 0-length runt packet and seems to have some interop
|
// 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;
|
int64_t mRequestBodyLenRemaining;
|
||||||
|
|
||||||
// based on nsISupportsPriority definitions
|
// based on nsISupportsPriority definitions
|
||||||
|
@ -248,6 +246,15 @@ private:
|
||||||
|
|
||||||
// For SpdyPush
|
// For SpdyPush
|
||||||
SpdyPushedStream31 *mPushSource;
|
SpdyPushedStream31 *mPushSource;
|
||||||
|
|
||||||
|
/// connect tunnels
|
||||||
|
public:
|
||||||
|
bool IsTunnel() { return mIsTunnel; }
|
||||||
|
private:
|
||||||
|
void ClearTransactionsBlockedOnTunnel();
|
||||||
|
void MapStreamToHttpConnection();
|
||||||
|
|
||||||
|
bool mIsTunnel;
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace mozilla::net
|
}} // namespace mozilla::net
|
||||||
|
|
Загрузка…
Ссылка в новой задаче