bug 912549 - spdy/3.1 r=hurley

--HG--
rename : netwerk/protocol/http/PSpdyPush3.h => netwerk/protocol/http/PSpdyPush.h
This commit is contained in:
Patrick McManus 2013-07-26 17:22:46 -04:00
parent 5925bfa7a6
commit 70a6addf38
22 changed files with 5670 additions and 122 deletions

View File

@ -1094,6 +1094,7 @@ pref("network.http.bypass-cachelock-threshold", 250);
pref("network.http.spdy.enabled", true);
pref("network.http.spdy.enabled.v2", true);
pref("network.http.spdy.enabled.v3", true);
pref("network.http.spdy.enabled.v3-1", true);
pref("network.http.spdy.chunk-size", 4096);
pref("network.http.spdy.timeout", 180);
pref("network.http.spdy.coalesce-hostnames", true);

View File

@ -96,22 +96,22 @@ interface nsILoadGroup : nsIRequest
};
%{C++
// Forward-declare mozilla::net::SpdyPushCache3
// Forward-declare mozilla::net::SpdyPushCache
namespace mozilla {
namespace net {
class SpdyPushCache3;
class SpdyPushCache;
}
}
%}
[ptr] native SpdyPushCache3Ptr(mozilla::net::SpdyPushCache3);
[ptr] native SpdyPushCachePtr(mozilla::net::SpdyPushCache);
/**
* Used to maintain state about the connections of a load group and
* how they interact with blocking items like HEAD css/js loads.
*/
[uuid(5361f30e-f968-437c-8f41-69d2756a6022)]
[uuid(fdc9659c-b597-4ac0-9c9e-14b04dbb682f)]
interface nsILoadGroupConnectionInfo : nsISupports
{
/**
@ -137,5 +137,5 @@ interface nsILoadGroupConnectionInfo : nsISupports
* and will destroy it when overwritten or when the load group
* ends.
*/
[noscript] attribute SpdyPushCache3Ptr spdyPushCache3;
[noscript] attribute SpdyPushCachePtr spdyPushCache;
};

View File

@ -574,8 +574,12 @@ HttpConnInfo::SetHTTP2ProtocolVersion(uint8_t pv)
{
if (pv == SPDY_VERSION_2)
protocolVersion.Assign(NS_LITERAL_STRING("spdy/2"));
else
else if (pv == SPDY_VERSION_3)
protocolVersion.Assign(NS_LITERAL_STRING("spdy/3"));
else {
MOZ_ASSERT (pv == SPDY_VERSION_31);
protocolVersion.Assign(NS_LITERAL_STRING("spdy/3.1"));
}
}
NS_IMETHODIMP

View File

@ -17,7 +17,7 @@
#include "mozilla/Atomics.h"
#include "mozilla/Telemetry.h"
#include "nsAutoPtr.h"
#include "mozilla/net/PSpdyPush3.h"
#include "mozilla/net/PSpdyPush.h"
#include "nsITimedChannel.h"
#include "nsIInterfaceRequestor.h"
#include "nsIRequestObserver.h"
@ -1101,7 +1101,7 @@ public:
nsLoadGroupConnectionInfo();
private:
Atomic<uint32_t> mBlockingTransactionCount;
nsAutoPtr<mozilla::net::SpdyPushCache3> mSpdyCache3;
nsAutoPtr<mozilla::net::SpdyPushCache> mSpdyCache;
};
NS_IMPL_ISUPPORTS1(nsLoadGroupConnectionInfo, nsILoadGroupConnectionInfo)
@ -1135,17 +1135,18 @@ nsLoadGroupConnectionInfo::RemoveBlockingTransaction(uint32_t *_retval)
return NS_OK;
}
/* [noscript] attribute SpdyPushCache3Ptr spdyPushCache3; */
/* [noscript] attribute SpdyPushCachePtr spdyPushCache; */
NS_IMETHODIMP
nsLoadGroupConnectionInfo::GetSpdyPushCache3(mozilla::net::SpdyPushCache3 **aSpdyPushCache3)
nsLoadGroupConnectionInfo::GetSpdyPushCache(mozilla::net::SpdyPushCache **aSpdyPushCache)
{
*aSpdyPushCache3 = mSpdyCache3.get();
*aSpdyPushCache = mSpdyCache.get();
return NS_OK;
}
NS_IMETHODIMP
nsLoadGroupConnectionInfo::SetSpdyPushCache3(mozilla::net::SpdyPushCache3 *aSpdyPushCache3)
nsLoadGroupConnectionInfo::SetSpdyPushCache(mozilla::net::SpdyPushCache *aSpdyPushCache)
{
mSpdyCache3 = aSpdyPushCache3;
mSpdyCache = aSpdyPushCache;
return NS_OK;
}

View File

@ -7,12 +7,21 @@
// HttpLog.h should generally be included first
#include "HttpLog.h"
/*
Currently supported are spdy/3.1 and spdy/3 and spdy/2
*/
#include "nsHttp.h"
#include "nsHttpHandler.h"
#include "ASpdySession.h"
#include "PSpdyPush.h"
#include "SpdyPush3.h"
#include "SpdyPush31.h"
#include "SpdySession2.h"
#include "SpdySession3.h"
#include "SpdySession31.h"
#include "mozilla/Telemetry.h"
@ -28,7 +37,8 @@ ASpdySession::NewSpdySession(uint32_t version,
// This is a necko only interface, so we can enforce version
// requests as a precondition
MOZ_ASSERT(version == SPDY_VERSION_2 ||
version == SPDY_VERSION_3,
version == SPDY_VERSION_3 ||
version == SPDY_VERSION_31 ,
"Unsupported spdy version");
// Don't do a runtime check of IsSpdyV?Enabled() here because pref value
@ -38,32 +48,40 @@ ASpdySession::NewSpdySession(uint32_t version,
Telemetry::Accumulate(Telemetry::SPDY_VERSION2, version);
if (version == SPDY_VERSION_3)
return new SpdySession3(aTransaction, aTransport, aPriority);
if (version == SPDY_VERSION_2)
return new SpdySession2(aTransaction, aTransport, aPriority);
return new SpdySession3(aTransaction, aTransport, aPriority);
return new SpdySession31(aTransaction, aTransport, aPriority);
}
SpdyInformation::SpdyInformation()
{
// list the preferred version first
Version[0] = SPDY_VERSION_3;
VersionString[0] = NS_LITERAL_CSTRING("spdy/3");
Version[0] = SPDY_VERSION_2;
VersionString[0] = NS_LITERAL_CSTRING("spdy/2");
Version[1] = SPDY_VERSION_2;
VersionString[1] = NS_LITERAL_CSTRING("spdy/2");
Version[1] = SPDY_VERSION_3;
VersionString[1] = NS_LITERAL_CSTRING("spdy/3");
Version[2] = SPDY_VERSION_31;
VersionString[2] = NS_LITERAL_CSTRING("spdy/3.1");
}
bool
SpdyInformation::ProtocolEnabled(uint32_t index)
{
if (index == 0)
return gHttpHandler->IsSpdyV3Enabled();
MOZ_ASSERT(index < kCount, "index out of range");
if (index == 1)
switch (index) {
case 0:
return gHttpHandler->IsSpdyV2Enabled();
MOZ_ASSERT(false, "index out of range");
case 1:
return gHttpHandler->IsSpdyV3Enabled();
case 2:
return gHttpHandler->IsSpdyV31Enabled();
}
return false;
}
@ -74,14 +92,74 @@ SpdyInformation::GetNPNVersionIndex(const nsACString &npnString,
if (npnString.IsEmpty())
return NS_ERROR_FAILURE;
if (npnString.Equals(VersionString[0]))
*result = Version[0];
else if (npnString.Equals(VersionString[1]))
*result = Version[1];
else
return NS_ERROR_FAILURE;
for (uint32_t index = 0; index < kCount; ++index) {
if (npnString.Equals(VersionString[index])) {
*result = Version[index];
return NS_OK;
}
}
return NS_OK;
return NS_ERROR_FAILURE;
}
//////////////////////////////////////////
// SpdyPushCache
//////////////////////////////////////////
SpdyPushCache::SpdyPushCache()
{
}
SpdyPushCache::~SpdyPushCache()
{
mHashSpdy3.Clear();
mHashSpdy31.Clear();
}
bool
SpdyPushCache::RegisterPushedStreamSpdy3(nsCString key,
SpdyPushedStream3 *stream)
{
LOG3(("SpdyPushCache::RegisterPushedStreamSpdy3 %s 0x%X\n",
key.get(), stream->StreamID()));
if(mHashSpdy3.Get(key))
return false;
mHashSpdy3.Put(key, stream);
return true;
}
SpdyPushedStream3 *
SpdyPushCache::RemovePushedStreamSpdy3(nsCString key)
{
SpdyPushedStream3 *rv = mHashSpdy3.Get(key);
LOG3(("SpdyPushCache::RemovePushedStream %s 0x%X\n",
key.get(), rv ? rv->StreamID() : 0));
if (rv)
mHashSpdy3.Remove(key);
return rv;
}
bool
SpdyPushCache::RegisterPushedStreamSpdy31(nsCString key,
SpdyPushedStream31 *stream)
{
LOG3(("SpdyPushCache::RegisterPushedStreamSpdy31 %s 0x%X\n",
key.get(), stream->StreamID()));
if(mHashSpdy31.Get(key))
return false;
mHashSpdy31.Put(key, stream);
return true;
}
SpdyPushedStream31 *
SpdyPushCache::RemovePushedStreamSpdy31(nsCString key)
{
SpdyPushedStream31 *rv = mHashSpdy31.Get(key);
LOG3(("SpdyPushCache::RemovePushedStream %s 0x%X\n",
key.get(), rv ? rv->StreamID() : 0));
if (rv)
mHashSpdy31.Remove(key);
return rv;
}
} // namespace mozilla::net

View File

@ -15,13 +15,6 @@ class nsISocketTransport;
namespace mozilla { namespace net {
// This is designed to handle up to 2 concrete protocol levels
// simultaneously
//
// Currently supported are v3 (preferred), and v2
// network.protocol.http.spdy.enabled.v2 (and v3) prefs can enable/disable
// them.
class ASpdySession : public nsAHttpTransaction
{
public:
@ -58,16 +51,17 @@ public:
SpdyInformation();
~SpdyInformation() {}
// determine if a version of the protocol is enabled. The primary
// version is index 0, the secondary version is index 1.
static const uint32_t kCount = 3;
// determine if a version of the protocol is enabled for index <= kCount
bool ProtocolEnabled(uint32_t index);
// lookup a version enum based on an npn string. returns NS_OK if
// string was known.
nsresult GetNPNVersionIndex(const nsACString &npnString, uint8_t *result);
uint8_t Version[2];
nsCString VersionString[2];
uint8_t Version[kCount];
nsCString VersionString[kCount];
};
}} // namespace mozilla::net

View File

@ -11,6 +11,7 @@
#include "nsHttpConnection.h"
#include "SpdySession2.h"
#include "SpdySession3.h"
#include "SpdySession31.h"
#include "nsHttpHandler.h"
#include "nsIConsoleService.h"
#include "nsHttpRequestHead.h"
@ -159,6 +160,43 @@ nsHttpConnection::PrintDiagnostics(nsCString &log)
mSpdySession->PrintDiagnostics(log);
}
void
SpdySession2::PrintDiagnostics(nsCString &log)
{
log.AppendPrintf(" ::: SPDY VERSION 2\n");
log.AppendPrintf(" shouldgoaway = %d mClosed = %d CanReuse = %d nextID=0x%X\n",
mShouldGoAway, mClosed, CanReuse(), mNextStreamID);
log.AppendPrintf(" concurrent = %d maxconcurrent = %d\n",
mConcurrent, mMaxConcurrent);
log.AppendPrintf(" roomformorestreams = %d roomformoreconcurrent = %d\n",
RoomForMoreStreams(), RoomForMoreConcurrent());
log.AppendPrintf(" transactionHashCount = %d streamIDHashCount = %d\n",
mStreamTransactionHash.Count(),
mStreamIDHash.Count());
log.AppendPrintf(" Queued Stream Size = %d\n", mQueuedStreams.GetSize());
PRIntervalTime now = PR_IntervalNow();
log.AppendPrintf(" Ping Threshold = %ums next ping id = 0x%X\n",
PR_IntervalToMilliseconds(mPingThreshold),
mNextPingID);
log.AppendPrintf(" Ping Timeout = %ums\n",
PR_IntervalToMilliseconds(gHttpHandler->SpdyPingTimeout()));
log.AppendPrintf(" Idle for Any Activity (ping) = %ums\n",
PR_IntervalToMilliseconds(now - mLastReadEpoch));
log.AppendPrintf(" Idle for Data Activity = %ums\n",
PR_IntervalToMilliseconds(now - mLastDataReadEpoch));
if (mPingSentEpoch)
log.AppendPrintf(" Ping Outstanding (ping) = %ums, expired = %d\n",
PR_IntervalToMilliseconds(now - mPingSentEpoch),
now - mPingSentEpoch >= gHttpHandler->SpdyPingTimeout());
else
log.AppendPrintf(" No Ping Outstanding\n");
}
void
SpdySession3::PrintDiagnostics(nsCString &log)
{
@ -197,9 +235,9 @@ SpdySession3::PrintDiagnostics(nsCString &log)
}
void
SpdySession2::PrintDiagnostics(nsCString &log)
SpdySession31::PrintDiagnostics(nsCString &log)
{
log.AppendPrintf(" ::: SPDY VERSION 2\n");
log.AppendPrintf(" ::: SPDY VERSION 3.1\n");
log.AppendPrintf(" shouldgoaway = %d mClosed = %d CanReuse = %d nextID=0x%X\n",
mShouldGoAway, mClosed, CanReuse(), mNextStreamID);

View File

@ -3,8 +3,7 @@
* 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/. */
// SPDY Server Push as defined by
// http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3
// SPDY Server Push
/*
A pushed stream is put into a memory buffer (The SpdyPushTransactionBuffer)
@ -23,8 +22,8 @@
client pull behavior.
*/
#ifndef mozilla_net_SpdyPush3_Public_h
#define mozilla_net_SpdyPush3_Public_h
#ifndef mozilla_net_SpdyPush_Public_h
#define mozilla_net_SpdyPush_Public_h
#include "nsAutoPtr.h"
#include "nsDataHashtable.h"
@ -36,25 +35,35 @@ namespace mozilla {
namespace net {
class SpdyPushedStream3;
class SpdyPushedStream31;
// One Cache per load group
class SpdyPushCache3
// One cache per load group
class SpdyPushCache
{
public:
SpdyPushCache3();
virtual ~SpdyPushCache3();
// The cache holds only weak pointers - no references
bool RegisterPushedStream(nsCString key,
SpdyPushedStream3 *stream);
SpdyPushedStream3 *RemovePushedStream(nsCString key);
SpdyPushedStream3 *GetPushedStream(nsCString key);
SpdyPushCache();
virtual ~SpdyPushCache();
// for spdy/3
public:
bool RegisterPushedStreamSpdy3(nsCString key,
SpdyPushedStream3 *stream);
SpdyPushedStream3 *RemovePushedStreamSpdy3(nsCString key);
private:
nsDataHashtable<nsCStringHashKey, SpdyPushedStream3 *> mHash;
nsDataHashtable<nsCStringHashKey, SpdyPushedStream3 *> mHashSpdy3;
// for spdy/3.1
public:
bool RegisterPushedStreamSpdy31(nsCString key,
SpdyPushedStream31 *stream);
SpdyPushedStream31 *RemovePushedStreamSpdy31(nsCString key);
private:
nsDataHashtable<nsCStringHashKey, SpdyPushedStream31 *> mHashSpdy31;
};
} // namespace mozilla::net
} // namespace mozilla
#endif // mozilla_net_SpdyPush3_Public_h
#endif // mozilla_net_SpdyPush_Public_h

View File

@ -10,7 +10,7 @@
#include <algorithm>
#include "SpdyPush3.h"
#include "PSpdyPush3.h"
#include "PSpdyPush.h"
#include "SpdySession3.h"
#include "nsHttpRequestHead.h"
@ -137,7 +137,7 @@ SpdyPushedStream3::IsOrphaned(TimeStamp now)
bool rv = ((now - mLastRead).ToSeconds() > 30.0);
if (rv) {
LOG3(("SpdyPushCache3::IsOrphaned 0x%X IsOrphaned %3.2f\n",
LOG3(("SpdyPushCache::IsOrphaned 0x%X IsOrphaned %3.2f\n",
mStreamID, (now - mLastRead).ToSeconds()));
}
return rv;
@ -161,47 +161,6 @@ SpdyPushedStream3::GetBufferedData(char *buf,
return rv;
}
//////////////////////////////////////////
// SpdyPushCache3
//////////////////////////////////////////
SpdyPushCache3::SpdyPushCache3()
{
}
SpdyPushCache3::~SpdyPushCache3()
{
}
SpdyPushedStream3 *
SpdyPushCache3::GetPushedStream(nsCString key)
{
return mHash.Get(key);
}
bool
SpdyPushCache3::RegisterPushedStream(nsCString key,
SpdyPushedStream3 *stream)
{
LOG3(("SpdyPushCache3::RegisterPushedStream %s 0x%X\n",
key.get(), stream->StreamID()));
if(mHash.Get(key))
return false;
mHash.Put(key, stream);
return true;
}
SpdyPushedStream3 *
SpdyPushCache3::RemovePushedStream(nsCString key)
{
SpdyPushedStream3 *rv = mHash.Get(key);
LOG3(("SpdyPushCache3::RemovePushedStream %s 0x%X\n",
key.get(), rv ? rv->StreamID() : 0));
if (rv)
mHash.Remove(key);
return rv;
}
//////////////////////////////////////////
// SpdyPush3TransactionBuffer
// This is the nsAHttpTransction owned by the stream when the pushed

View File

@ -0,0 +1,355 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* 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/. */
// HttpLog.h should generally be included first
#include "HttpLog.h"
#include <algorithm>
#include "nsDependentString.h"
#include "SpdyPush31.h"
namespace mozilla {
namespace net {
//////////////////////////////////////////
// SpdyPushedStream31
//////////////////////////////////////////
SpdyPushedStream31::SpdyPushedStream31(SpdyPush31TransactionBuffer *aTransaction,
SpdySession31 *aSession,
SpdyStream31 *aAssociatedStream,
uint32_t aID)
:SpdyStream31(aTransaction, aSession,
0 /* priority is only for sending, so ignore it on push */)
, mConsumerStream(nullptr)
, mBufferedPush(aTransaction)
, mStatus(NS_OK)
, mPushCompleted(false)
, mDeferCleanupOnSuccess(true)
{
LOG3(("SpdyPushedStream31 ctor this=%p id=0x%X\n", this, aID));
mStreamID = aID;
mBufferedPush->SetPushStream(this);
mLoadGroupCI = aAssociatedStream->LoadGroupConnectionInfo();
mLastRead = TimeStamp::Now();
}
bool
SpdyPushedStream31::GetPushComplete()
{
return mPushCompleted;
}
nsresult
SpdyPushedStream31::WriteSegments(nsAHttpSegmentWriter *writer,
uint32_t count,
uint32_t *countWritten)
{
nsresult rv = SpdyStream31::WriteSegments(writer, count, countWritten);
if (NS_SUCCEEDED(rv) && *countWritten) {
mLastRead = TimeStamp::Now();
}
if (rv == NS_BASE_STREAM_CLOSED) {
mPushCompleted = true;
rv = NS_OK; // this is what a normal HTTP transaction would do
}
if (rv != NS_BASE_STREAM_WOULD_BLOCK && NS_FAILED(rv))
mStatus = rv;
return rv;
}
nsresult
SpdyPushedStream31::ReadSegments(nsAHttpSegmentReader *, uint32_t, uint32_t *count)
{
// The SYN_STREAM for this has been processed, so we need to verify
// that :host, :scheme, and :path MUST be present
nsDependentCSubstring host, scheme, path;
nsresult rv;
rv = SpdyStream31::FindHeader(NS_LITERAL_CSTRING(":host"), host);
if (NS_FAILED(rv)) {
LOG3(("SpdyPushedStream31::ReadSegments session=%p ID 0x%X "
"push without required :host\n", mSession, mStreamID));
return rv;
}
rv = SpdyStream31::FindHeader(NS_LITERAL_CSTRING(":scheme"), scheme);
if (NS_FAILED(rv)) {
LOG3(("SpdyPushedStream31::ReadSegments session=%p ID 0x%X "
"push without required :scheme\n", mSession, mStreamID));
return rv;
}
rv = SpdyStream31::FindHeader(NS_LITERAL_CSTRING(":path"), path);
if (NS_FAILED(rv)) {
LOG3(("SpdyPushedStream31::ReadSegments session=%p ID 0x%X "
"push without required :host\n", mSession, mStreamID));
return rv;
}
CreatePushHashKey(nsCString(scheme), nsCString(host),
mSession->Serial(), path,
mOrigin, mHashKey);
LOG3(("SpdyPushStream31 0x%X hash key %s\n", mStreamID, mHashKey.get()));
// the write side of a pushed transaction just involves manipulating a little state
SpdyStream31::mSentFinOnData = 1;
SpdyStream31::mSynFrameComplete = 1;
SpdyStream31::ChangeState(UPSTREAM_COMPLETE);
*count = 0;
return NS_OK;
}
bool
SpdyPushedStream31::GetHashKey(nsCString &key)
{
if (mHashKey.IsEmpty())
return false;
key = mHashKey;
return true;
}
void
SpdyPushedStream31::ConnectPushedStream(SpdyStream31 *stream)
{
mSession->ConnectPushedStream(stream);
}
bool
SpdyPushedStream31::IsOrphaned(TimeStamp now)
{
MOZ_ASSERT(!now.IsNull());
// if spdy is not transmitting, and is also not connected to a consumer
// stream, and its been like that for too long then it is oprhaned
if (mConsumerStream)
return false;
bool rv = ((now - mLastRead).ToSeconds() > 30.0);
if (rv) {
LOG3(("SpdyPushedStream31::IsOrphaned 0x%X IsOrphaned %3.2f\n",
mStreamID, (now - mLastRead).ToSeconds()));
}
return rv;
}
nsresult
SpdyPushedStream31::GetBufferedData(char *buf,
uint32_t count,
uint32_t *countWritten)
{
if (NS_FAILED(mStatus))
return mStatus;
nsresult rv = mBufferedPush->GetBufferedData(buf, count, countWritten);
if (NS_FAILED(rv))
return rv;
if (!*countWritten)
rv = GetPushComplete() ? NS_BASE_STREAM_CLOSED : NS_BASE_STREAM_WOULD_BLOCK;
return rv;
}
//////////////////////////////////////////
// SpdyPush31TransactionBuffer
// This is the nsAHttpTransction owned by the stream when the pushed
// stream has not yet been matched with a pull request
//////////////////////////////////////////
NS_IMPL_ISUPPORTS0(SpdyPush31TransactionBuffer)
SpdyPush31TransactionBuffer::SpdyPush31TransactionBuffer()
: mStatus(NS_OK)
, mRequestHead(nullptr)
, mPushStream(nullptr)
, mIsDone(false)
, mBufferedHTTP1Size(kDefaultBufferSize)
, mBufferedHTTP1Used(0)
, mBufferedHTTP1Consumed(0)
{
mBufferedHTTP1 = new char[mBufferedHTTP1Size];
}
SpdyPush31TransactionBuffer::~SpdyPush31TransactionBuffer()
{
delete mRequestHead;
}
void
SpdyPush31TransactionBuffer::SetConnection(nsAHttpConnection *conn)
{
}
nsAHttpConnection *
SpdyPush31TransactionBuffer::Connection()
{
return nullptr;
}
void
SpdyPush31TransactionBuffer::GetSecurityCallbacks(nsIInterfaceRequestor **outCB)
{
*outCB = nullptr;
}
void
SpdyPush31TransactionBuffer::OnTransportStatus(nsITransport* transport,
nsresult status, uint64_t progress)
{
}
bool
SpdyPush31TransactionBuffer::IsDone()
{
return mIsDone;
}
nsresult
SpdyPush31TransactionBuffer::Status()
{
return mStatus;
}
uint32_t
SpdyPush31TransactionBuffer::Caps()
{
return 0;
}
uint64_t
SpdyPush31TransactionBuffer::Available()
{
return mBufferedHTTP1Used - mBufferedHTTP1Consumed;
}
nsresult
SpdyPush31TransactionBuffer::ReadSegments(nsAHttpSegmentReader *reader,
uint32_t count, uint32_t *countRead)
{
*countRead = 0;
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
SpdyPush31TransactionBuffer::WriteSegments(nsAHttpSegmentWriter *writer,
uint32_t count, uint32_t *countWritten)
{
if ((mBufferedHTTP1Size - mBufferedHTTP1Used) < 20480) {
SpdySession31::EnsureBuffer(mBufferedHTTP1,
mBufferedHTTP1Size + kDefaultBufferSize,
mBufferedHTTP1Used,
mBufferedHTTP1Size);
}
count = std::min(count, mBufferedHTTP1Size - mBufferedHTTP1Used);
nsresult rv = writer->OnWriteSegment(mBufferedHTTP1 + mBufferedHTTP1Used,
count, countWritten);
if (NS_SUCCEEDED(rv)) {
mBufferedHTTP1Used += *countWritten;
}
else if (rv == NS_BASE_STREAM_CLOSED) {
mIsDone = true;
}
if (Available()) {
SpdyStream31 *consumer = mPushStream->GetConsumerStream();
if (consumer) {
LOG3(("SpdyPush31TransactionBuffer::WriteSegments notifying connection "
"consumer data available 0x%X [%u]\n",
mPushStream->StreamID(), Available()));
mPushStream->ConnectPushedStream(consumer);
}
}
return rv;
}
uint32_t
SpdyPush31TransactionBuffer::Http1xTransactionCount()
{
return 0;
}
nsHttpRequestHead *
SpdyPush31TransactionBuffer::RequestHead()
{
if (!mRequestHead)
mRequestHead = new nsHttpRequestHead();
return mRequestHead;
}
nsresult
SpdyPush31TransactionBuffer::TakeSubTransactions(
nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
void
SpdyPush31TransactionBuffer::SetProxyConnectFailed()
{
}
void
SpdyPush31TransactionBuffer::Close(nsresult reason)
{
mStatus = reason;
mIsDone = true;
}
nsresult
SpdyPush31TransactionBuffer::AddTransaction(nsAHttpTransaction *trans)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
uint32_t
SpdyPush31TransactionBuffer::PipelineDepth()
{
return 0;
}
nsresult
SpdyPush31TransactionBuffer::SetPipelinePosition(int32_t position)
{
return NS_OK;
}
int32_t
SpdyPush31TransactionBuffer::PipelinePosition()
{
return 1;
}
nsresult
SpdyPush31TransactionBuffer::GetBufferedData(char *buf,
uint32_t count,
uint32_t *countWritten)
{
*countWritten = std::min(count, static_cast<uint32_t>(Available()));
if (*countWritten) {
memcpy(buf, mBufferedHTTP1 + mBufferedHTTP1Consumed, *countWritten);
mBufferedHTTP1Consumed += *countWritten;
}
// If all the data has been consumed then reset the buffer
if (mBufferedHTTP1Consumed == mBufferedHTTP1Used) {
mBufferedHTTP1Consumed = 0;
mBufferedHTTP1Used = 0;
}
return NS_OK;
}
} // namespace mozilla::net
} // namespace mozilla

View File

@ -0,0 +1,101 @@
/* -*- 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/. */
// spdy/3.1
#ifndef mozilla_net_SpdyPush31_Internal_h
#define mozilla_net_SpdyPush3_Internal_h
#include "mozilla/Attributes.h"
#include "mozilla/TimeStamp.h"
#include "nsHttpRequestHead.h"
#include "nsILoadGroup.h"
#include "nsString.h"
#include "PSpdyPush.h"
#include "SpdySession31.h"
#include "SpdyStream31.h"
namespace mozilla {
namespace net {
class SpdyPush31TransactionBuffer;
class SpdyPushedStream31 MOZ_FINAL : public SpdyStream31
{
public:
SpdyPushedStream31(SpdyPush31TransactionBuffer *aTransaction,
SpdySession31 *aSession,
SpdyStream31 *aAssociatedStream,
uint32_t aID);
virtual ~SpdyPushedStream31() {}
bool GetPushComplete();
SpdyStream31 *GetConsumerStream() { return mConsumerStream; };
void SetConsumerStream(SpdyStream31 *aStream) { mConsumerStream = aStream; }
bool GetHashKey(nsCString &key);
// override of SpdyStream31
nsresult ReadSegments(nsAHttpSegmentReader *, uint32_t, uint32_t *);
nsresult WriteSegments(nsAHttpSegmentWriter *, uint32_t, uint32_t *);
nsILoadGroupConnectionInfo *LoadGroupConnectionInfo() { return mLoadGroupCI; };
void ConnectPushedStream(SpdyStream31 *consumer);
bool DeferCleanupOnSuccess() { return mDeferCleanupOnSuccess; }
void SetDeferCleanupOnSuccess(bool val) { mDeferCleanupOnSuccess = val; }
bool IsOrphaned(TimeStamp now);
nsresult GetBufferedData(char *buf, uint32_t count, uint32_t *countWritten);
// overload of SpdyStream31
virtual bool HasSink() { return !!mConsumerStream; }
private:
SpdyStream31 *mConsumerStream; // paired request stream that consumes from
// real spdy one.. null until a match is made.
nsCOMPtr<nsILoadGroupConnectionInfo> mLoadGroupCI;
SpdyPush31TransactionBuffer *mBufferedPush;
mozilla::TimeStamp mLastRead;
nsCString mHashKey;
nsresult mStatus;
bool mPushCompleted; // server push FIN received
bool mDeferCleanupOnSuccess;
};
class SpdyPush31TransactionBuffer MOZ_FINAL : public nsAHttpTransaction
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSAHTTPTRANSACTION
SpdyPush31TransactionBuffer();
virtual ~SpdyPush31TransactionBuffer();
nsresult GetBufferedData(char *buf, uint32_t count, uint32_t *countWritten);
void SetPushStream(SpdyPushedStream31 *stream) { mPushStream = stream; }
private:
const static uint32_t kDefaultBufferSize = 4096;
nsresult mStatus;
nsHttpRequestHead *mRequestHead;
SpdyPushedStream31 *mPushStream;
bool mIsDone;
nsAutoArrayPtr<char> mBufferedHTTP1;
uint32_t mBufferedHTTP1Size;
uint32_t mBufferedHTTP1Used;
uint32_t mBufferedHTTP1Consumed;
};
} // namespace mozilla::net
} // namespace mozilla
#endif // mozilla_net_SpdyPush3_Internal_h

View File

@ -16,7 +16,7 @@
#include "SpdyPush3.h"
#include "SpdySession3.h"
#include "SpdyStream3.h"
#include "PSpdyPush3.h"
#include "PSpdyPush.h"
#include <algorithm>
@ -988,7 +988,7 @@ SpdySession3::HandleSynStream(SpdySession3 *self)
self->mShouldGoAway = true;
bool resetStream = true;
SpdyPushCache3 *cache = nullptr;
SpdyPushCache *cache = nullptr;
if (!(flags & kFlag_Data_UNI)) {
// pushed streams require UNIDIRECTIONAL flag
@ -1017,10 +1017,10 @@ SpdySession3::HandleSynStream(SpdySession3 *self)
} else {
nsILoadGroupConnectionInfo *loadGroupCI = associatedStream->LoadGroupConnectionInfo();
if (loadGroupCI) {
loadGroupCI->GetSpdyPushCache3(&cache);
loadGroupCI->GetSpdyPushCache(&cache);
if (!cache) {
cache = new SpdyPushCache3();
if (!cache || NS_FAILED(loadGroupCI->SetSpdyPushCache3(cache))) {
cache = new SpdyPushCache();
if (!cache || NS_FAILED(loadGroupCI->SetSpdyPushCache(cache))) {
delete cache;
cache = nullptr;
}
@ -1101,7 +1101,7 @@ SpdySession3::HandleSynStream(SpdySession3 *self)
return NS_OK;
}
if (!cache->RegisterPushedStream(key, pushedStream)) {
if (!cache->RegisterPushedStreamSpdy3(key, pushedStream)) {
LOG(("SpdySession3::HandleSynStream registerPushedStream Failed\n"));
self->CleanupStream(pushedStream, NS_ERROR_FAILURE, RST_INVALID_STREAM);
self->ResetDownstreamState();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,407 @@
/* -*- 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_SpdySession31_h
#define mozilla_net_SpdySession31_h
// spdy/3.1
#include "ASpdySession.h"
#include "mozilla/Attributes.h"
#include "nsAHttpConnection.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
#include "nsDeque.h"
#include "nsHashKeys.h"
#include "zlib.h"
class nsISocketTransport;
namespace mozilla { namespace net {
class SpdyPushedStream31;
class SpdyStream31;
class SpdySession31 MOZ_FINAL : public ASpdySession
, public nsAHttpConnection
, public nsAHttpSegmentReader
, public nsAHttpSegmentWriter
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSAHTTPTRANSACTION
NS_DECL_NSAHTTPCONNECTION(mConnection)
NS_DECL_NSAHTTPSEGMENTREADER
NS_DECL_NSAHTTPSEGMENTWRITER
SpdySession31(nsAHttpTransaction *, nsISocketTransport *, int32_t);
~SpdySession31();
bool AddStream(nsAHttpTransaction *, int32_t);
bool CanReuse() { return !mShouldGoAway && !mClosed; }
bool RoomForMoreStreams();
// When the connection is active this is called every 1 second
void ReadTimeoutTick(PRIntervalTime now);
// Idle time represents time since "goodput".. e.g. a data or header frame
PRIntervalTime IdleTime();
// Registering with a newID of 0 means pick the next available odd ID
uint32_t RegisterStreamID(SpdyStream31 *, uint32_t aNewID = 0);
const static uint8_t kVersion = 3;
const static uint8_t kFlag_Control = 0x80;
const static uint8_t kFlag_Data_FIN = 0x01;
const static uint8_t kFlag_Data_UNI = 0x02;
enum
{
CONTROL_TYPE_FIRST = 0,
CONTROL_TYPE_SYN_STREAM = 1,
CONTROL_TYPE_SYN_REPLY = 2,
CONTROL_TYPE_RST_STREAM = 3,
CONTROL_TYPE_SETTINGS = 4,
CONTROL_TYPE_NOOP = 5, /* deprecated */
CONTROL_TYPE_PING = 6,
CONTROL_TYPE_GOAWAY = 7,
CONTROL_TYPE_HEADERS = 8,
CONTROL_TYPE_WINDOW_UPDATE = 9,
CONTROL_TYPE_CREDENTIAL = 10,
CONTROL_TYPE_LAST = 11
};
enum rstReason
{
RST_PROTOCOL_ERROR = 1,
RST_INVALID_STREAM = 2,
RST_REFUSED_STREAM = 3,
RST_UNSUPPORTED_VERSION = 4,
RST_CANCEL = 5,
RST_INTERNAL_ERROR = 6,
RST_FLOW_CONTROL_ERROR = 7,
RST_STREAM_IN_USE = 8,
RST_STREAM_ALREADY_CLOSED = 9,
RST_INVALID_CREDENTIALS = 10,
RST_FRAME_TOO_LARGE = 11
};
enum goawayReason
{
OK = 0,
PROTOCOL_ERROR = 1,
INTERNAL_ERROR = 2, // sometimes misdocumented as 11
NUM_STATUS_CODES = 3 // reserved by chromium but undocumented
};
enum settingsFlags
{
PERSIST_VALUE = 1,
PERSISTED_VALUE = 2
};
enum
{
SETTINGS_TYPE_UPLOAD_BW = 1, // kb/s
SETTINGS_TYPE_DOWNLOAD_BW = 2, // kb/s
SETTINGS_TYPE_RTT = 3, // ms
SETTINGS_TYPE_MAX_CONCURRENT = 4, // streams
SETTINGS_TYPE_CWND = 5, // packets
SETTINGS_TYPE_DOWNLOAD_RETRANS_RATE = 6, // percentage
SETTINGS_TYPE_INITIAL_WINDOW = 7, // bytes for flow control
SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8
};
// This should be big enough to hold all of your control packets,
// but if it needs to grow for huge headers it can do so dynamically.
// About 1% of responses from SPDY google services seem to be > 1000
// with all less than 2000 when compression is enabled.
const static uint32_t kDefaultBufferSize = 2048;
// kDefaultQueueSize must be >= other queue size constants
const static uint32_t kDefaultQueueSize = 32768;
const static uint32_t kQueueMinimumCleanup = 24576;
const static uint32_t kQueueTailRoom = 4096;
const static uint32_t kQueueReserved = 1024;
const static uint32_t kDefaultMaxConcurrent = 100;
const static uint32_t kMaxStreamID = 0x7800000;
// This is a sentinel for a deleted stream. It is not a valid
// 31 bit stream ID.
const static uint32_t kDeadStreamID = 0xffffdead;
// below the emergency threshold of local window we ack every received
// byte. Above that we coalesce bytes into the MinimumToAck size.
const static int32_t kEmergencyWindowThreshold = 1024 * 1024;
const static uint32_t kMinimumToAck = 64 * 1024;
// The default rwin is 64KB unless updated by a settings frame
const static uint32_t kDefaultRwin = 64 * 1024;
static nsresult HandleSynStream(SpdySession31 *);
static nsresult HandleSynReply(SpdySession31 *);
static nsresult HandleRstStream(SpdySession31 *);
static nsresult HandleSettings(SpdySession31 *);
static nsresult HandleNoop(SpdySession31 *);
static nsresult HandlePing(SpdySession31 *);
static nsresult HandleGoAway(SpdySession31 *);
static nsresult HandleHeaders(SpdySession31 *);
static nsresult HandleWindowUpdate(SpdySession31 *);
static nsresult HandleCredential(SpdySession31 *);
template<typename T>
static void EnsureBuffer(nsAutoArrayPtr<T> &,
uint32_t, uint32_t, uint32_t &);
// For writing the SPDY data stream to LOG4
static void LogIO(SpdySession31 *, SpdyStream31 *, const char *,
const char *, uint32_t);
// an overload of nsAHttpConnection
void TransactionHasDataToWrite(nsAHttpTransaction *);
// a similar version for SpdyStream31
void TransactionHasDataToWrite(SpdyStream31 *);
// an overload of nsAHttpSegementReader
virtual nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment);
uint32_t GetServerInitialStreamWindow() { return mServerInitialStreamWindow; }
void ConnectPushedStream(SpdyStream31 *stream);
uint64_t Serial() { return mSerial; }
void PrintDiagnostics (nsCString &log);
// Streams need access to these
uint32_t SendingChunkSize() { return mSendingChunkSize; }
uint32_t PushAllowance() { return mPushAllowance; }
z_stream *UpstreamZlib() { return &mUpstreamZlib; }
nsISocketTransport *SocketTransport() { return mSocketTransport; }
int64_t RemoteSessionWindow() { return mRemoteSessionWindow; }
void DecrementRemoteSessionWindow (uint32_t bytes) { mRemoteSessionWindow -= bytes; }
private:
enum stateType {
BUFFERING_FRAME_HEADER,
BUFFERING_CONTROL_FRAME,
PROCESSING_DATA_FRAME,
DISCARDING_DATA_FRAME,
PROCESSING_COMPLETE_HEADERS,
PROCESSING_CONTROL_RST_STREAM
};
nsresult ResponseHeadersComplete();
uint32_t GetWriteQueueSize();
void ChangeDownstreamState(enum stateType);
void ResetDownstreamState();
nsresult UncompressAndDiscard(uint32_t, uint32_t);
void DecrementConcurrent(SpdyStream31 *);
void zlibInit();
void GeneratePing(uint32_t);
void GenerateRstStream(uint32_t, uint32_t);
void GenerateGoAway(uint32_t);
void CleanupStream(SpdyStream31 *, nsresult, rstReason);
void CloseStream(SpdyStream31 *, nsresult);
void GenerateSettings();
void RemoveStreamFromQueues(SpdyStream31 *);
void SetWriteCallbacks();
void FlushOutputQueue();
void RealignOutputQueue();
bool RoomForMoreConcurrent();
void ActivateStream(SpdyStream31 *);
void ProcessPending();
nsresult SetInputFrameDataStream(uint32_t);
bool VerifyStream(SpdyStream31 *, uint32_t);
void SetNeedsCleanup();
void UpdateLocalRwin(SpdyStream31 *stream, uint32_t bytes);
void UpdateLocalStreamWindow(SpdyStream31 *stream, uint32_t bytes);
void UpdateLocalSessionWindow(uint32_t bytes);
// a wrapper for all calls to the nshttpconnection level segment writer. Used
// to track network I/O for timeout purposes
nsresult NetworkRead(nsAHttpSegmentWriter *, char *, uint32_t, uint32_t *);
static PLDHashOperator ShutdownEnumerator(nsAHttpTransaction *,
nsAutoPtr<SpdyStream31> &,
void *);
static PLDHashOperator GoAwayEnumerator(nsAHttpTransaction *,
nsAutoPtr<SpdyStream31> &,
void *);
static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
nsAutoPtr<SpdyStream31> &,
void *);
static PLDHashOperator RestartBlockedOnRwinEnumerator(nsAHttpTransaction *,
nsAutoPtr<SpdyStream31> &,
void *);
// This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
// from the first transaction on this session. That object contains the
// pointer to the real network-level nsHttpConnection object.
nsRefPtr<nsAHttpConnection> mConnection;
// The underlying socket transport object is needed to propogate some events
nsISocketTransport *mSocketTransport;
// These are temporary state variables to hold the argument to
// Read/WriteSegments so it can be accessed by On(read/write)segment
// further up the stack.
nsAHttpSegmentReader *mSegmentReader;
nsAHttpSegmentWriter *mSegmentWriter;
uint32_t mSendingChunkSize; /* the transmission chunk size */
uint32_t mNextStreamID; /* 24 bits */
uint32_t mConcurrentHighWater; /* max parallelism on session */
uint32_t mPushAllowance; /* rwin for unmatched pushes */
stateType mDownstreamState; /* in frame, between frames, etc.. */
// Maintain 2 indexes - one by stream ID, one by transaction pointer.
// There are also several lists of streams: ready to write, queued due to
// max parallelism, streams that need to force a read for push, and the full
// set of pushed streams.
// The objects are not ref counted - they get destroyed
// by the nsClassHashtable implementation when they are removed from
// the transaction hash.
nsDataHashtable<nsUint32HashKey, SpdyStream31 *> mStreamIDHash;
nsClassHashtable<nsPtrHashKey<nsAHttpTransaction>,
SpdyStream31> mStreamTransactionHash;
nsDeque mReadyForWrite;
nsDeque mQueuedStreams;
nsDeque mReadyForRead;
nsTArray<SpdyPushedStream31 *> mPushedStreams;
// Compression contexts for header transport using deflate.
// SPDY compresses only HTTP headers and does not reset zlib in between
// frames. Even data that is not associated with a stream (e.g invalid
// stream ID) is passed through these contexts to keep the compression
// context correct.
z_stream mDownstreamZlib;
z_stream mUpstreamZlib;
// mInputFrameBuffer is used to store received control packets and the 8 bytes
// of header on data packets
uint32_t mInputFrameBufferSize;
uint32_t mInputFrameBufferUsed;
nsAutoArrayPtr<char> mInputFrameBuffer;
// mInputFrameDataSize/Read are used for tracking the amount of data consumed
// in a data frame. the data itself is not buffered in spdy
// The frame size is mInputFrameDataSize + the constant 8 byte header
uint32_t mInputFrameDataSize;
uint32_t mInputFrameDataRead;
bool mInputFrameDataLast; // This frame was marked FIN
// When a frame has been received that is addressed to a particular stream
// (e.g. a data frame after the stream-id has been decoded), this points
// to the stream.
SpdyStream31 *mInputFrameDataStream;
// mNeedsCleanup is a state variable to defer cleanup of a closed stream
// If needed, It is set in session::OnWriteSegments() and acted on and
// cleared when the stack returns to session::WriteSegments(). The stream
// cannot be destroyed directly out of OnWriteSegments because
// stream::writeSegments() is on the stack at that time.
SpdyStream31 *mNeedsCleanup;
// The CONTROL_TYPE value for a control frame
uint32_t mFrameControlType;
// This reason code in the last processed RESET frame
uint32_t mDownstreamRstReason;
// for the conversion of downstream http headers into spdy formatted headers
// The data here does not persist between frames
nsCString mFlatHTTPResponseHeaders;
uint32_t mFlatHTTPResponseHeadersOut;
// when set, the session will go away when it reaches 0 streams. This flag
// is set when: the stream IDs are running out (at either the client or the
// server), when DontReuse() is called, a RST that is not specific to a
// particular stream is received, a GOAWAY frame has been received from
// the server.
bool mShouldGoAway;
// the session has received a nsAHttpTransaction::Close() call
bool mClosed;
// the session received a GoAway frame with a valid GoAwayID
bool mCleanShutdown;
// indicates PROCESSING_COMPLETE_HEADERS state was pushed onto the stack
// over an active PROCESSING_DATA_FRAME, which should be restored when
// the processed headers are written to the stream
bool mDataPending;
// If a GoAway message was received this is the ID of the last valid
// stream. 0 otherwise. (0 is never a valid stream id.)
uint32_t mGoAwayID;
// The limit on number of concurrent streams for this session. Normally it
// is basically unlimited, but the SETTINGS control message from the
// server might bring it down.
uint32_t mMaxConcurrent;
// The actual number of concurrent streams at this moment. Generally below
// mMaxConcurrent, but the max can be lowered in real time to a value
// below the current value
uint32_t mConcurrent;
// The number of server initiated SYN-STREAMS, tracked for telemetry
uint32_t mServerPushedResources;
// The server rwin for new streams as determined from a SETTINGS frame
uint32_t mServerInitialStreamWindow;
// The Local Session window is how much data the server is allowed to send
// (across all streams) without getting a window update to stream 0. It is
// signed because asynchronous changes via SETTINGS can drive it negative.
int64_t mLocalSessionWindow;
// The Remote Session Window is how much data the client is allowed to send
// (across all streams) without receiving a window update to stream 0. It is
// signed because asynchronous changes via SETTINGS can drive it negative.
int64_t mRemoteSessionWindow;
// This is a output queue of bytes ready to be written to the SSL stream.
// When that streams returns WOULD_BLOCK on direct write the bytes get
// coalesced together here. This results in larger writes to the SSL layer.
// The buffer is not dynamically grown to accomodate stream writes, but
// does expand to accept infallible session wide frames like GoAway and RST.
uint32_t mOutputQueueSize;
uint32_t mOutputQueueUsed;
uint32_t mOutputQueueSent;
nsAutoArrayPtr<char> mOutputQueueBuffer;
PRIntervalTime mPingThreshold;
PRIntervalTime mLastReadEpoch; // used for ping timeouts
PRIntervalTime mLastDataReadEpoch; // used for IdleTime()
PRIntervalTime mPingSentEpoch;
uint32_t mNextPingID;
// used as a temporary buffer while enumerating the stream hash during GoAway
nsDeque mGoAwayStreamsToRestart;
// Each session gets a unique serial number because the push cache is correlated
// 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;
};
}} // namespace mozilla::net
#endif // mozilla_net_SpdySession31_h

View File

@ -17,7 +17,7 @@
#include "SpdyPush3.h"
#include "SpdySession3.h"
#include "SpdyStream3.h"
#include "PSpdyPush3.h"
#include "PSpdyPush.h"
#include <algorithm>
@ -285,16 +285,16 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
if (mTransaction->RequestHead()->Method() == nsHttp::Get) {
// from :scheme, :host, :path
nsILoadGroupConnectionInfo *loadGroupCI = mTransaction->LoadGroupConnectionInfo();
SpdyPushCache3 *cache = nullptr;
SpdyPushCache *cache = nullptr;
if (loadGroupCI)
loadGroupCI->GetSpdyPushCache3(&cache);
loadGroupCI->GetSpdyPushCache(&cache);
SpdyPushedStream3 *pushedStream = nullptr;
// we remove the pushedstream from the push cache so that
// it will not be used for another GET. This does not destroy the
// stream itself - that is done when the transactionhash is done with it.
if (cache)
pushedStream = cache->RemovePushedStream(hashkey);
pushedStream = cache->RemovePushedStreamSpdy3(hashkey);
if (pushedStream) {
LOG3(("Pushed Stream Match located id=0x%X key=%s\n",

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,258 @@
/* -*- Mode: C++; tab-width: 8; 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_SpdyStream31_h
#define mozilla_net_SpdyStream31_h
#include "mozilla/Attributes.h"
#include "nsAHttpTransaction.h"
namespace mozilla { namespace net {
class SpdyStream31 : public nsAHttpSegmentReader
, public nsAHttpSegmentWriter
{
public:
NS_DECL_NSAHTTPSEGMENTREADER
NS_DECL_NSAHTTPSEGMENTWRITER
SpdyStream31(nsAHttpTransaction *, SpdySession31 *, int32_t);
uint32_t StreamID() { return mStreamID; }
SpdyPushedStream31 *PushSource() { return mPushSource; }
virtual nsresult ReadSegments(nsAHttpSegmentReader *, uint32_t, uint32_t *);
virtual nsresult WriteSegments(nsAHttpSegmentWriter *, uint32_t, uint32_t *);
virtual bool DeferCleanupOnSuccess() { return false; }
const nsAFlatCString &Origin() const { return mOrigin; }
bool RequestBlockedOnRead()
{
return static_cast<bool>(mRequestBlockedOnRead);
}
// returns false if called more than once
bool GetFullyOpen() {return mFullyOpen;}
void SetFullyOpen()
{
MOZ_ASSERT(!mFullyOpen);
mFullyOpen = 1;
}
bool HasRegisteredID() { return mStreamID != 0; }
nsAHttpTransaction *Transaction() { return mTransaction; }
virtual nsILoadGroupConnectionInfo *LoadGroupConnectionInfo()
{
return mTransaction ? mTransaction->LoadGroupConnectionInfo() : nullptr;
}
void Close(nsresult reason);
void SetRecvdFin(bool aStatus) { mRecvdFin = aStatus ? 1 : 0; }
bool RecvdFin() { return mRecvdFin; }
void SetRecvdData(bool aStatus) { mReceivedData = aStatus ? 1 : 0; }
bool RecvdData() { return mReceivedData; }
void UpdateTransportSendEvents(uint32_t count);
void UpdateTransportReadEvents(uint32_t count);
// The zlib header compression dictionary defined by SPDY,
// and hooks to the mozilla allocator for zlib to use.
static const unsigned char kDictionary[1423];
static void *zlib_allocator(void *, uInt, uInt);
static void zlib_destructor(void *, void *);
nsresult Uncompress(z_stream *, char *, uint32_t);
nsresult ConvertHeaders(nsACString &);
void UpdateRemoteWindow(int32_t delta) { mRemoteWindow += delta; }
int64_t RemoteWindow() { return mRemoteWindow; }
void DecrementLocalWindow(uint32_t delta) {
mLocalWindow -= delta;
mLocalUnacked += delta;
}
void IncrementLocalWindow(uint32_t delta) {
mLocalWindow += delta;
mLocalUnacked -= delta;
}
uint64_t LocalUnAcked() { return mLocalUnacked; }
int64_t LocalWindow() { return mLocalWindow; }
bool BlockedOnRwin() { return mBlockedOnRwin; }
// A pull stream has an implicit sink, a pushed stream has a sink
// once it is matched to a pull stream.
virtual bool HasSink() { return true; }
virtual ~SpdyStream31();
protected:
nsresult FindHeader(nsCString, nsDependentCSubstring &);
static void CreatePushHashKey(const nsCString &scheme,
const nsCString &hostHeader,
uint64_t serial,
const nsCSubstring &pathInfo,
nsCString &outOrigin,
nsCString &outKey);
enum stateType {
GENERATING_SYN_STREAM,
GENERATING_REQUEST_BODY,
SENDING_REQUEST_BODY,
SENDING_FIN_STREAM,
UPSTREAM_COMPLETE
};
uint32_t mStreamID;
// The session that this stream is a subset of
SpdySession31 *mSession;
nsCString mOrigin;
// Each stream goes from syn_stream to upstream_complete, perhaps
// looping on multiple instances of generating_request_body and
// sending_request_body for each SPDY chunk in the upload.
enum stateType mUpstreamState;
// Flag is set when all http request headers have been read and ID is stable
uint32_t mSynFrameComplete : 1;
// Flag is set when a FIN has been placed on a data or syn packet
// (i.e after the client has closed)
uint32_t mSentFinOnData : 1;
void ChangeState(enum stateType);
private:
friend class nsAutoPtr<SpdyStream31>;
static PLDHashOperator hdrHashEnumerate(const nsACString &,
nsAutoPtr<nsCString> &,
void *);
nsresult ParseHttpRequestHeaders(const char *, uint32_t, uint32_t *);
void AdjustInitialWindow();
nsresult TransmitFrame(const char *, uint32_t *, bool forceCommitment);
void GenerateDataFrameHeader(uint32_t, bool);
void CompressToFrame(const nsACString &);
void CompressToFrame(const nsACString *);
void CompressToFrame(const char *, uint32_t);
void CompressToFrame(uint32_t);
void CompressFlushFrame();
void ExecuteCompress(uint32_t);
// The underlying HTTP transaction. This pointer is used as the key
// in the SpdySession31 mStreamTransactionHash so it is important to
// keep a reference to it as long as this stream is a member of that hash.
// (i.e. don't change it or release it after it is set in the ctor).
nsRefPtr<nsAHttpTransaction> mTransaction;
// The underlying socket transport object is needed to propogate some events
nsISocketTransport *mSocketTransport;
// These are temporary state variables to hold the argument to
// Read/WriteSegments so it can be accessed by On(read/write)segment
// further up the stack.
nsAHttpSegmentReader *mSegmentReader;
nsAHttpSegmentWriter *mSegmentWriter;
// The quanta upstream data frames are chopped into
uint32_t mChunkSize;
// Flag is set when the HTTP processor has more data to send
// but has blocked in doing so.
uint32_t mRequestBlockedOnRead : 1;
// Flag is set after the response frame bearing the fin bit has
// been processed. (i.e. after the server has closed).
uint32_t mRecvdFin : 1;
// Flag is set after syn reply received
uint32_t mFullyOpen : 1;
// Flag is set after the WAITING_FOR Transport event has been generated
uint32_t mSentWaitingFor : 1;
// Flag is set after 1st DATA frame has been passed to stream, after
// which additional HEADERS data is invalid
uint32_t mReceivedData : 1;
// Flag is set after TCP send autotuning has been disabled
uint32_t mSetTCPSocketBuffer : 1;
// The InlineFrame and associated data is used for composing control
// frames and data frame headers.
nsAutoArrayPtr<uint8_t> mTxInlineFrame;
uint32_t mTxInlineFrameSize;
uint32_t mTxInlineFrameUsed;
// mTxStreamFrameSize tracks the progress of
// transmitting a request body data frame. The data frame itself
// is never copied into the spdy layer.
uint32_t mTxStreamFrameSize;
// Compression context and buffer for request header compression.
// This is a copy of SpdySession31::mUpstreamZlib because it needs
// to remain the same in all streams of a session.
z_stream *mZlib;
nsCString mFlatHttpRequestHeaders;
// These are used for decompressing downstream spdy response headers
uint32_t mDecompressBufferSize;
uint32_t mDecompressBufferUsed;
uint32_t mDecompressedBytes;
nsAutoArrayPtr<char> mDecompressBuffer;
// Track the content-length of a request body so that we can
// 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.
int64_t mRequestBodyLenRemaining;
// based on nsISupportsPriority definitions
int32_t mPriority;
// mLocalWindow, mRemoteWindow, and mLocalUnacked are for flow control.
// *window are signed because the race conditions in asynchronous SETTINGS
// messages can force them temporarily negative.
// LocalWindow is how much data the server will send without getting a
// window update
int64_t mLocalWindow;
// RemoteWindow is how much data the client is allowed to send without
// getting a window update
int64_t mRemoteWindow;
// LocalUnacked is the number of bytes received by the client but not
// yet reflected in a window update. Sending that update will increment
// LocalWindow
uint64_t mLocalUnacked;
// True when sending is suspended becuase the remote flow control window is
// <= 0
bool mBlockedOnRwin;
// For Progress Events
uint64_t mTotalSent;
uint64_t mTotalRead;
// For SpdyPush
SpdyPushedStream31 *mPushSource;
};
}} // namespace mozilla::net
#endif // mozilla_net_SpdyStream31_h

View File

@ -36,7 +36,7 @@ EXPORTS.mozilla.net += [
'HttpChannelParent.h',
'HttpInfo.h',
'PHttpChannelParams.h',
'PSpdyPush3.h',
'PSpdyPush.h',
]
CPP_SOURCES += [
@ -49,10 +49,13 @@ CPP_SOURCES += [
'HttpInfo.cpp',
'NullHttpTransaction.cpp',
'SpdyPush3.cpp',
'SpdyPush31.cpp',
'SpdySession2.cpp',
'SpdySession3.cpp',
'SpdySession31.cpp',
'SpdyStream2.cpp',
'SpdyStream3.cpp',
'SpdyStream31.cpp',
'nsHttp.cpp',
'nsHttpActivityDistributor.cpp',
'nsHttpAuthCache.cpp',

View File

@ -25,7 +25,8 @@ class Mutex;
namespace net {
enum {
SPDY_VERSION_2 = 2,
SPDY_VERSION_3 = 3
SPDY_VERSION_3 = 3,
SPDY_VERSION_31 = 4
};
} // namespace mozilla::net
} // namespace mozilla

View File

@ -272,7 +272,7 @@ nsHttpConnection::EnsureNPNComplete()
if (NS_FAILED(rv))
goto npnComplete;
LOG(("nsHttpConnection::EnsureNPNComplete %p negotiated to '%s'",
LOG(("nsHttpConnection::EnsureNPNComplete %p negotiated to '%s'\n",
this, negotiatedNPN.get()));
uint8_t spdyVersion;
@ -408,12 +408,11 @@ nsHttpConnection::SetupSSL(uint32_t caps)
if (gHttpHandler->IsSpdyEnabled() &&
!(caps & NS_HTTP_DISALLOW_SPDY)) {
LOG(("nsHttpConnection::SetupSSL Allow SPDY NPN selection"));
if (gHttpHandler->SpdyInfo()->ProtocolEnabled(0))
protocolArray.AppendElement(
gHttpHandler->SpdyInfo()->VersionString[0]);
if (gHttpHandler->SpdyInfo()->ProtocolEnabled(1))
protocolArray.AppendElement(
gHttpHandler->SpdyInfo()->VersionString[1]);
for (uint32_t index = 0; index < SpdyInformation::kCount; ++index) {
if (gHttpHandler->SpdyInfo()->ProtocolEnabled(index))
protocolArray.AppendElement(
gHttpHandler->SpdyInfo()->VersionString[index]);
}
}
if (NS_SUCCEEDED(ssl->SetNPNList(protocolArray))) {

View File

@ -186,6 +186,7 @@ nsHttpHandler::nsHttpHandler()
, mEnableSpdy(false)
, mSpdyV2(true)
, mSpdyV3(true)
, mSpdyV31(true)
, mCoalesceSpdy(true)
, mSpdyPersistentSettings(false)
, mAllowSpdyPush(true)
@ -1136,6 +1137,12 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
mSpdyV3 = cVar;
}
if (PREF_CHANGED(HTTP_PREF("spdy.enabled.v3-1"))) {
rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled.v3-1"), &cVar);
if (NS_SUCCEEDED(rv))
mSpdyV31 = cVar;
}
if (PREF_CHANGED(HTTP_PREF("spdy.coalesce-hostnames"))) {
rv = prefs->GetBoolPref(HTTP_PREF("spdy.coalesce-hostnames"), &cVar);
if (NS_SUCCEEDED(rv))

View File

@ -97,6 +97,7 @@ public:
bool IsSpdyEnabled() { return mEnableSpdy; }
bool IsSpdyV2Enabled() { return mSpdyV2; }
bool IsSpdyV3Enabled() { return mSpdyV3; }
bool IsSpdyV31Enabled() { return mSpdyV31; }
bool CoalesceSpdy() { return mCoalesceSpdy; }
bool UseSpdyPersistentSettings() { return mSpdyPersistentSettings; }
uint32_t SpdySendingChunkSize() { return mSpdySendingChunkSize; }
@ -417,6 +418,7 @@ private:
bool mEnableSpdy;
bool mSpdyV2;
bool mSpdyV3;
bool mSpdyV31;
bool mCoalesceSpdy;
bool mSpdyPersistentSettings;
bool mAllowSpdyPush;