--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1491,17 +1491,16 @@ pref("network.http.fast-fallback-to-IPv4
#ifdef RELEASE_BUILD
pref("network.http.bypass-cachelock-threshold", 200000);
#else
pref("network.http.bypass-cachelock-threshold", 250);
#endif
// Try and use SPDY when using SSL
pref("network.http.spdy.enabled", true);
-pref("network.http.spdy.enabled.v3-1", false);
pref("network.http.spdy.enabled.http2", true);
pref("network.http.spdy.enabled.deps", true);
pref("network.http.spdy.enforce-tls-profile", true);
pref("network.http.spdy.chunk-size", 16000);
pref("network.http.spdy.timeout", 180);
pref("network.http.spdy.coalesce-hostnames", true);
pref("network.http.spdy.persistent-settings", false);
pref("network.http.spdy.ping-threshold", 58);
--- a/netwerk/base/Dashboard.cpp
+++ b/netwerk/base/Dashboard.cpp
@@ -772,22 +772,18 @@ HttpConnInfo::SetHTTP1ProtocolVersion(ui
default:
protocolVersion.AssignLiteral(u"unknown protocol version");
}
}
void
HttpConnInfo::SetHTTP2ProtocolVersion(uint8_t pv)
{
- if (pv == SPDY_VERSION_31) {
- protocolVersion.AssignLiteral(u"spdy/3.1");
- } else {
- MOZ_ASSERT (pv == HTTP_VERSION_2);
- protocolVersion.Assign(u"h2");
- }
+ MOZ_ASSERT (pv == HTTP_VERSION_2);
+ protocolVersion.Assign(u"h2");
}
NS_IMETHODIMP
Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort,
const char *aProtocol, uint32_t aTimeout,
NetDashboardCallback *aCallback)
{
nsresult rv;
--- a/netwerk/protocol/http/ASpdySession.cpp
+++ b/netwerk/protocol/http/ASpdySession.cpp
@@ -3,27 +3,25 @@
/* 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"
/*
- Currently supported are h2 and spdy/3.1
+ Currently supported is h2
*/
#include "nsHttp.h"
#include "nsHttpHandler.h"
#include "ASpdySession.h"
#include "PSpdyPush.h"
-#include "SpdyPush31.h"
#include "Http2Push.h"
-#include "SpdySession31.h"
#include "Http2Session.h"
#include "mozilla/Telemetry.h"
namespace mozilla {
namespace net {
ASpdySession::ASpdySession()
@@ -35,65 +33,44 @@ ASpdySession::~ASpdySession()
}
ASpdySession *
ASpdySession::NewSpdySession(uint32_t version,
nsISocketTransport *aTransport)
{
// This is a necko only interface, so we can enforce version
// requests as a precondition
- MOZ_ASSERT(version == SPDY_VERSION_31 ||
- version == HTTP_VERSION_2,
+ MOZ_ASSERT(version == HTTP_VERSION_2,
"Unsupported spdy version");
// Don't do a runtime check of IsSpdyV?Enabled() here because pref value
// may have changed since starting negotiation. The selected protocol comes
// from a list provided in the SERVER HELLO filtered by our acceptable
// versions, so there is no risk of the server ignoring our prefs.
Telemetry::Accumulate(Telemetry::SPDY_VERSION2, version);
- if (version == SPDY_VERSION_31) {
- return new SpdySession31(aTransport);
- } else if (version == HTTP_VERSION_2) {
- return new Http2Session(aTransport, version);
- }
-
- return nullptr;
-}
-static bool SpdySessionTrue(nsISupports *securityInfo)
-{
- return true;
+ return new Http2Session(aTransport, version);
}
SpdyInformation::SpdyInformation()
{
// highest index of enabled protocols is the
// most preferred for ALPN negotiaton
- Version[0] = SPDY_VERSION_31;
- VersionString[0] = NS_LITERAL_CSTRING("spdy/3.1");
- ALPNCallbacks[0] = SpdySessionTrue;
-
- Version[1] = HTTP_VERSION_2;
- VersionString[1] = NS_LITERAL_CSTRING("h2");
- ALPNCallbacks[1] = Http2Session::ALPNCallback;
+ Version[0] = HTTP_VERSION_2;
+ VersionString[0] = NS_LITERAL_CSTRING("h2");
+ ALPNCallbacks[0] = Http2Session::ALPNCallback;
}
bool
SpdyInformation::ProtocolEnabled(uint32_t index) const
{
MOZ_ASSERT(index < kCount, "index out of range");
- switch (index) {
- case 0:
- return gHttpHandler->IsSpdyV31Enabled();
- case 1:
- return gHttpHandler->IsHttp2Enabled();
- }
- return false;
+ return gHttpHandler->IsHttp2Enabled();
}
nsresult
SpdyInformation::GetNPNIndex(const nsACString &npnString,
uint32_t *result) const
{
if (npnString.IsEmpty())
return NS_ERROR_FAILURE;
@@ -113,47 +90,20 @@ SpdyInformation::GetNPNIndex(const nsACS
//////////////////////////////////////////
SpdyPushCache::SpdyPushCache()
{
}
SpdyPushCache::~SpdyPushCache()
{
- mHashSpdy31.Clear();
mHashHttp2.Clear();
}
bool
-SpdyPushCache::RegisterPushedStreamSpdy31(nsCString key,
- SpdyPushedStream31 *stream)
-{
- LOG3(("SpdyPushCache::RegisterPushedStreamSpdy31 %s 0x%X\n",
- key.get(), stream->StreamID()));
- if(mHashSpdy31.Get(key)) {
- LOG3(("SpdyPushCache::RegisterPushedStreamSpdy31 %s 0x%X duplicate key\n",
- key.get(), stream->StreamID()));
- 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;
-}
-
-bool
SpdyPushCache::RegisterPushedStreamHttp2(nsCString key,
Http2PushedStream *stream)
{
LOG3(("SpdyPushCache::RegisterPushedStreamHttp2 %s 0x%X\n",
key.get(), stream->StreamID()));
if(mHashHttp2.Get(key)) {
LOG3(("SpdyPushCache::RegisterPushedStreamHttp2 %s 0x%X duplicate key\n",
key.get(), stream->StreamID()));
--- a/netwerk/protocol/http/ASpdySession.h
+++ b/netwerk/protocol/http/ASpdySession.h
@@ -90,32 +90,31 @@ typedef bool (*ALPNCallback) (nsISupport
// It could be all static except using static ctors of XPCOM objects is a
// bad idea.
class SpdyInformation
{
public:
SpdyInformation();
~SpdyInformation() {}
- static const uint32_t kCount = 2;
+ static const uint32_t kCount = 1;
// determine the index (0..kCount-1) of the spdy information that
// correlates to the npn string. NS_FAILED() if no match is found.
nsresult GetNPNIndex(const nsACString &npnString, uint32_t *result) const;
// determine if a version of the protocol is enabled for index < kCount
bool ProtocolEnabled(uint32_t index) const;
uint8_t Version[kCount]; // telemetry enum e.g. SPDY_VERSION_31
nsCString VersionString[kCount]; // npn string e.g. "spdy/3.1"
// the ALPNCallback function allows the protocol stack to decide whether or
// not to offer a particular protocol based on the known TLS information
// that we will offer in the client hello (such as version). There has
// not been a Server Hello received yet, so not much else can be considered.
- // Stacks without restrictions can just use SpdySessionTrue()
ALPNCallback ALPNCallbacks[kCount];
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_ASpdySession_h
--- a/netwerk/protocol/http/AlternateServices.cpp
+++ b/netwerk/protocol/http/AlternateServices.cpp
@@ -313,20 +313,20 @@ public:
reason = NS_OK;
}
if (NS_FAILED(reason) || !mRunning || !mConnection) {
LOG(("AltSvcTransaction::MaybeValidate %p Failed due to precondition", this));
return;
}
- // insist on spdy/3* or >= http/2
+ // insist on >= http/2
uint32_t version = mConnection->Version();
LOG(("AltSvcTransaction::MaybeValidate() %p version %d\n", this, version));
- if ((version < HTTP_VERSION_2) && (version != SPDY_VERSION_31)) {
+ if (version < HTTP_VERSION_2) {
LOG(("AltSvcTransaction::MaybeValidate %p Failed due to protocol version", this));
return;
}
nsCOMPtr<nsISupports> secInfo;
mConnection->GetSecurityInfo(getter_AddRefs(secInfo));
nsCOMPtr<nsISSLSocketControl> socketControl = do_QueryInterface(secInfo);
bool bypassAuth = false;
--- a/netwerk/protocol/http/ConnectionDiagnostics.cpp
+++ b/netwerk/protocol/http/ConnectionDiagnostics.cpp
@@ -4,17 +4,16 @@
* 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 "nsHttpConnectionMgr.h"
#include "nsHttpConnection.h"
-#include "SpdySession31.h"
#include "Http2Session.h"
#include "nsHttpHandler.h"
#include "nsIConsoleService.h"
#include "nsHttpRequestHead.h"
#include "nsServiceManagerUtils.h"
#include "nsSocketTransportService2.h"
namespace mozilla {
@@ -153,53 +152,16 @@ nsHttpConnection::PrintDiagnostics(nsCSt
log.AppendPrintf(" supports pipeline = %d classification = 0x%x\n",
mSupportsPipelining, mClassification);
if (mSpdySession)
mSpdySession->PrintDiagnostics(log);
}
void
-SpdySession31::PrintDiagnostics(nsCString &log)
-{
- log.AppendPrintf(" ::: SPDY VERSION 3.1\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
Http2Session::PrintDiagnostics(nsCString &log)
{
log.AppendPrintf(" ::: HTTP2\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);
--- a/netwerk/protocol/http/PSpdyPush.h
+++ b/netwerk/protocol/http/PSpdyPush.h
@@ -29,37 +29,25 @@
#include "nsDataHashtable.h"
#include "nsISupports.h"
class nsCString;
namespace mozilla {
namespace net {
-class SpdyPushedStream31;
class Http2PushedStream;
// One cache per load group
class SpdyPushCache
{
public:
// The cache holds only weak pointers - no references
SpdyPushCache();
virtual ~SpdyPushCache();
-
-// for spdy/3.1
-public:
- bool RegisterPushedStreamSpdy31(nsCString key,
- SpdyPushedStream31 *stream);
- SpdyPushedStream31 *RemovePushedStreamSpdy31(nsCString key);
-private:
- nsDataHashtable<nsCStringHashKey, SpdyPushedStream31 *> mHashSpdy31;
-
-// for http/2
-public:
bool RegisterPushedStreamHttp2(nsCString key,
Http2PushedStream *stream);
Http2PushedStream *RemovePushedStreamHttp2(nsCString key);
private:
nsDataHashtable<nsCStringHashKey, Http2PushedStream *> mHashHttp2;
};
} // namespace net
deleted file mode 100644
--- a/netwerk/protocol/http/SpdyPush31.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-/* -*- 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"
-
-// Log on level :5, instead of default :4.
-#undef LOG
-#define LOG(args) LOG5(args)
-#undef LOG_ENABLED
-#define LOG_ENABLED() LOG5_ENABLED()
-
-#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);
- mRequestContext = aAssociatedStream->RequestContext();
- 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::mRequestHeadersDone = 1;
- SpdyStream31::mSynFrameGenerated = 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 = MakeUnique<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, int64_t progress)
-{
-}
-
-nsHttpConnectionInfo *
-SpdyPush31TransactionBuffer::ConnectionInfo()
-{
- if (!mPushStream) {
- return nullptr;
- }
- if (!mPushStream->Transaction()) {
- return nullptr;
- }
- MOZ_ASSERT(mPushStream->Transaction() != this);
- return mPushStream->Transaction()->ConnectionInfo();
-}
-
-bool
-SpdyPush31TransactionBuffer::IsDone()
-{
- return mIsDone;
-}
-
-nsresult
-SpdyPush31TransactionBuffer::Status()
-{
- return mStatus;
-}
-
-uint32_t
-SpdyPush31TransactionBuffer::Caps()
-{
- return 0;
-}
-
-void
-SpdyPush31TransactionBuffer::SetDNSWasRefreshed()
-{
-}
-
-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) {
- 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() || mIsDone) {
- SpdyStream31 *consumer = mPushStream->GetConsumerStream();
-
- if (consumer) {
- LOG3(("SpdyPush31TransactionBuffer::WriteSegments notifying connection "
- "consumer data available 0x%X [%u] done=%d\n",
- mPushStream->StreamID(), Available(), mIsDone));
- 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<RefPtr<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 net
-} // namespace mozilla
deleted file mode 100644
--- a/netwerk/protocol/http/SpdyPush31.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- 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_SpdyPush31_Internal_h
-
-#include "mozilla/Attributes.h"
-#include "mozilla/TimeStamp.h"
-#include "mozilla/UniquePtr.h"
-#include "nsHttpRequestHead.h"
-#include "nsIRequestContext.h"
-#include "nsString.h"
-#include "PSpdyPush.h"
-#include "SpdySession31.h"
-#include "SpdyStream31.h"
-
-namespace mozilla {
-namespace net {
-
-class SpdyPush31TransactionBuffer;
-
-class SpdyPushedStream31 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 *);
-
- nsIRequestContext *RequestContext() { return mRequestContext; };
- 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<nsIRequestContext> mRequestContext;
-
- SpdyPush31TransactionBuffer *mBufferedPush;
- TimeStamp mLastRead;
-
- nsCString mHashKey;
- nsresult mStatus;
- bool mPushCompleted; // server push FIN received
- bool mDeferCleanupOnSuccess;
-};
-
-class SpdyPush31TransactionBuffer final : public nsAHttpTransaction
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSAHTTPTRANSACTION
-
- SpdyPush31TransactionBuffer();
-
- nsresult GetBufferedData(char *buf, uint32_t count, uint32_t *countWritten);
- void SetPushStream(SpdyPushedStream31 *stream) { mPushStream = stream; }
-
-private:
- virtual ~SpdyPush31TransactionBuffer();
-
- const static uint32_t kDefaultBufferSize = 4096;
-
- nsresult mStatus;
- nsHttpRequestHead *mRequestHead;
- SpdyPushedStream31 *mPushStream;
- bool mIsDone;
-
- UniquePtr<char[]> mBufferedHTTP1;
- uint32_t mBufferedHTTP1Size;
- uint32_t mBufferedHTTP1Used;
- uint32_t mBufferedHTTP1Consumed;
-};
-
-} // namespace net
-} // namespace mozilla
-
-#endif // mozilla_net_SpdyPush3_Internal_h
deleted file mode 100644
--- a/netwerk/protocol/http/SpdySession31.cpp
+++ /dev/null
@@ -1,3077 +0,0 @@
-/* -*- 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"
-
-// Log on level :5, instead of default :4.
-#undef LOG
-#define LOG(args) LOG5(args)
-#undef LOG_ENABLED
-#define LOG_ENABLED() LOG5_ENABLED()
-
-#include "mozilla/Telemetry.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/Snprintf.h"
-#include "nsHttp.h"
-#include "nsHttpHandler.h"
-#include "nsHttpConnection.h"
-#include "nsIRequestContext.h"
-#include "nsISupportsPriority.h"
-#include "prnetdb.h"
-#include "SpdyPush31.h"
-#include "SpdySession31.h"
-#include "SpdyStream31.h"
-#include "SpdyZlibReporter.h"
-#include "nsSocketTransportService2.h"
-
-#include <algorithm>
-
-namespace mozilla {
-namespace net {
-
-// SpdySession31 has multiple inheritance of things that implement
-// nsISupports, so this magic is taken from nsHttpPipeline that
-// implements some of the same abstract classes.
-NS_IMPL_ADDREF(SpdySession31)
-NS_IMPL_RELEASE(SpdySession31)
-NS_INTERFACE_MAP_BEGIN(SpdySession31)
-NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsAHttpConnection)
-NS_INTERFACE_MAP_END
-
-SpdySession31::SpdySession31(nsISocketTransport *aSocketTransport)
- : mSocketTransport(aSocketTransport)
- , mSegmentReader(nullptr)
- , mSegmentWriter(nullptr)
- , mNextStreamID(1)
- , mConcurrentHighWater(0)
- , mDownstreamState(BUFFERING_FRAME_HEADER)
- , mInputFrameBufferSize(kDefaultBufferSize)
- , mInputFrameBufferUsed(0)
- , mInputFrameDataLast(false)
- , mInputFrameDataStream(nullptr)
- , mNeedsCleanup(nullptr)
- , mShouldGoAway(false)
- , mClosed(false)
- , mCleanShutdown(false)
- , mDataPending(false)
- , mGoAwayID(0)
- , mConcurrent(0)
- , mServerPushedResources(0)
- , mServerInitialStreamWindow(kDefaultRwin)
- , mLocalSessionWindow(kDefaultRwin)
- , mRemoteSessionWindow(kDefaultRwin)
- , mOutputQueueSize(kDefaultQueueSize)
- , mOutputQueueUsed(0)
- , mOutputQueueSent(0)
- , mLastReadEpoch(PR_IntervalNow())
- , mPingSentEpoch(0)
- , mNextPingID(1)
- , mPreviousUsed(false)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- static uint64_t sSerial;
- mSerial = ++sSerial;
-
- LOG3(("SpdySession31::SpdySession31 %p serial=0x%X\n", this, mSerial));
-
- mInputFrameBuffer = MakeUnique<char[]>(mInputFrameBufferSize);
- mOutputQueueBuffer = MakeUnique<char[]>(mOutputQueueSize);
- zlibInit();
-
- mPushAllowance = gHttpHandler->SpdyPushAllowance();
- mMaxConcurrent = gHttpHandler->DefaultSpdyConcurrent();
- mSendingChunkSize = gHttpHandler->SpdySendingChunkSize();
- GenerateSettings();
-
- mLastDataReadEpoch = mLastReadEpoch;
-
- mPingThreshold = gHttpHandler->SpdyPingThreshold();
-}
-
-void
-SpdySession31::Shutdown()
-{
- for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
- nsAutoPtr<SpdyStream31>& stream = iter.Data();
-
- // On a clean server hangup the server sets the GoAwayID to be the ID of
- // the last transaction it processed. If the ID of stream in the
- // local stream is greater than that it can safely be restarted because the
- // server guarantees it was not partially processed. Streams that have not
- // registered an ID haven't actually been sent yet so they can always be
- // restarted.
- if (mCleanShutdown &&
- (stream->StreamID() > mGoAwayID || !stream->HasRegisteredID())) {
- CloseStream(stream, NS_ERROR_NET_RESET); // can be restarted
- } else {
- CloseStream(stream, NS_ERROR_ABORT);
- }
- }
-}
-
-SpdySession31::~SpdySession31()
-{
- LOG3(("SpdySession31::~SpdySession31 %p mDownstreamState=%X",
- this, mDownstreamState));
-
- inflateEnd(&mDownstreamZlib);
- deflateEnd(&mUpstreamZlib);
-
- Shutdown();
-
- Telemetry::Accumulate(Telemetry::SPDY_PARALLEL_STREAMS, mConcurrentHighWater);
- Telemetry::Accumulate(Telemetry::SPDY_REQUEST_PER_CONN, (mNextStreamID - 1) / 2);
- Telemetry::Accumulate(Telemetry::SPDY_SERVER_INITIATED_STREAMS,
- mServerPushedResources);
-}
-
-void
-SpdySession31::LogIO(SpdySession31 *self, SpdyStream31 *stream, const char *label,
- const char *data, uint32_t datalen)
-{
- if (!LOG5_ENABLED())
- return;
-
- LOG5(("SpdySession31::LogIO %p stream=%p id=0x%X [%s]",
- self, stream, stream ? stream->StreamID() : 0, label));
-
- // Max line is (16 * 3) + 10(prefix) + newline + null
- char linebuf[128];
- uint32_t index;
- char *line = linebuf;
-
- linebuf[127] = 0;
-
- for (index = 0; index < datalen; ++index) {
- if (!(index % 16)) {
- if (index) {
- *line = 0;
- LOG5(("%s", linebuf));
- }
- line = linebuf;
- snprintf(line, 128, "%08X: ", index);
- line += 10;
- }
- snprintf(line, 128 - (line - linebuf), "%02X ", ((unsigned char *)data)[index]);
- line += 3;
- }
- if (index) {
- *line = 0;
- LOG5(("%s", linebuf));
- }
-}
-
-bool
-SpdySession31::RoomForMoreConcurrent()
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- return (mConcurrent < mMaxConcurrent);
-}
-
-bool
-SpdySession31::RoomForMoreStreams()
-{
- if (mNextStreamID + mStreamTransactionHash.Count() * 2 > kMaxStreamID)
- return false;
-
- return !mShouldGoAway;
-}
-
-PRIntervalTime
-SpdySession31::IdleTime()
-{
- return PR_IntervalNow() - mLastDataReadEpoch;
-}
-
-uint32_t
-SpdySession31::ReadTimeoutTick(PRIntervalTime now)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- MOZ_ASSERT(mNextPingID & 1, "Ping Counter Not Odd");
-
- LOG(("SpdySession31::ReadTimeoutTick %p delta since last read %ds\n",
- this, PR_IntervalToSeconds(now - mLastReadEpoch)));
-
- if (!mPingThreshold)
- return UINT32_MAX;
-
- if ((now - mLastReadEpoch) < mPingThreshold) {
- // recent activity means ping is not an issue
- if (mPingSentEpoch) {
- mPingSentEpoch = 0;
- if (mPreviousUsed) {
- // restore the former value
- mPingThreshold = mPreviousPingThreshold;
- mPreviousUsed = false;
- }
- }
-
- return PR_IntervalToSeconds(mPingThreshold) -
- PR_IntervalToSeconds(now - mLastReadEpoch);
- }
-
- if (mPingSentEpoch) {
- LOG(("SpdySession31::ReadTimeoutTick %p handle outstanding ping\n", this));
- if ((now - mPingSentEpoch) >= gHttpHandler->SpdyPingTimeout()) {
- LOG(("SpdySession31::ReadTimeoutTick %p Ping Timer Exhaustion\n",
- this));
- mPingSentEpoch = 0;
- Close(NS_ERROR_NET_TIMEOUT);
- return UINT32_MAX;
- }
- return 1; // run the tick aggressively while ping is outstanding
- }
-
- LOG(("SpdySession31::ReadTimeoutTick %p generating ping 0x%X\n",
- this, mNextPingID));
-
- if (mNextPingID == 0xffffffff) {
- LOG(("SpdySession31::ReadTimeoutTick %p cannot form ping - ids exhausted\n",
- this));
- return UINT32_MAX;
- }
-
- mPingSentEpoch = PR_IntervalNow();
- if (!mPingSentEpoch)
- mPingSentEpoch = 1; // avoid the 0 sentinel value
- GeneratePing(mNextPingID);
- mNextPingID += 2;
- ResumeRecv(); // read the ping reply
-
- // Check for orphaned push streams. This looks expensive, but generally the
- // list is empty.
- SpdyPushedStream31 *deleteMe;
- TimeStamp timestampNow;
- do {
- deleteMe = nullptr;
-
- for (uint32_t index = mPushedStreams.Length();
- index > 0 ; --index) {
- SpdyPushedStream31 *pushedStream = mPushedStreams[index - 1];
-
- if (timestampNow.IsNull())
- timestampNow = TimeStamp::Now(); // lazy initializer
-
- // if spdy finished, but not connected, and its been like that for too long..
- // cleanup the stream..
- if (pushedStream->IsOrphaned(timestampNow))
- {
- LOG3(("SpdySession31 Timeout Pushed Stream %p 0x%X\n",
- this, pushedStream->StreamID()));
- deleteMe = pushedStream;
- break; // don't CleanupStream() while iterating this vector
- }
- }
- if (deleteMe)
- CleanupStream(deleteMe, NS_ERROR_ABORT, RST_CANCEL);
-
- } while (deleteMe);
-
- if (mNextPingID == 0xffffffff) {
- LOG(("SpdySession31::ReadTimeoutTick %p "
- "ping ids exhausted marking goaway\n", this));
- mShouldGoAway = true;
- }
- return 1; // run the tick aggressively while ping is outstanding
-}
-
-uint32_t
-SpdySession31::RegisterStreamID(SpdyStream31 *stream, uint32_t aNewID)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- MOZ_ASSERT(mNextStreamID < 0xfffffff0,
- "should have stopped admitting streams");
-
- MOZ_ASSERT(!(aNewID & 1),
- "0 for autoassign pull, otherwise explicit even push assignment");
- if (!aNewID) {
- // auto generate a new pull stream ID
- aNewID = mNextStreamID;
- MOZ_ASSERT(aNewID & 1, "pull ID must be odd.");
- mNextStreamID += 2;
- }
-
- LOG3(("SpdySession31::RegisterStreamID session=%p stream=%p id=0x%X "
- "concurrent=%d",this, stream, aNewID, mConcurrent));
-
- // We've used up plenty of ID's on this session. Start
- // moving to a new one before there is a crunch involving
- // server push streams or concurrent non-registered submits
- if (aNewID >= kMaxStreamID)
- mShouldGoAway = true;
-
- // integrity check
- if (mStreamIDHash.Get(aNewID)) {
- LOG3((" New ID already present\n"));
- MOZ_ASSERT(false, "New ID already present in mStreamIDHash");
- mShouldGoAway = true;
- return kDeadStreamID;
- }
-
- mStreamIDHash.Put(aNewID, stream);
- return aNewID;
-}
-
-bool
-SpdySession31::AddStream(nsAHttpTransaction *aHttpTransaction,
- int32_t aPriority,
- bool aUseTunnel,
- nsIInterfaceRequestor *aCallbacks)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- // integrity check
- if (mStreamTransactionHash.Get(aHttpTransaction)) {
- LOG3((" New transaction already present\n"));
- MOZ_ASSERT(false, "AddStream duplicate transaction pointer");
- return false;
- }
-
- if (!mConnection) {
- mConnection = aHttpTransaction->Connection();
- }
-
- if (mClosed || mShouldGoAway) {
- nsHttpTransaction *trans = aHttpTransaction->QueryHttpTransaction();
- if (trans && !trans->GetPushedStream()) {
- LOG3(("SpdySession31::AddStream %p atrans=%p trans=%p session unusable - resched.\n",
- this, aHttpTransaction, trans));
- aHttpTransaction->SetConnection(nullptr);
- gHttpHandler->InitiateTransaction(trans, trans->Priority());
- return true;
- }
- }
-
- 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);
-
- LOG3(("SpdySession31::AddStream session=%p stream=%p serial=%u "
- "NextID=0x%X (tentative)", this, stream, mSerial, mNextStreamID));
-
- mStreamTransactionHash.Put(aHttpTransaction, stream);
-
- mReadyForWrite.Push(stream);
- SetWriteCallbacks();
-
- // Kick off the SYN transmit without waiting for the poll loop
- // This won't work for stream id=1 because there is no segment reader
- // yet.
- if (mSegmentReader) {
- uint32_t countRead;
- ReadSegments(nullptr, kDefaultBufferSize, &countRead);
- }
-
- if (!(aHttpTransaction->Caps() & NS_HTTP_ALLOW_KEEPALIVE) &&
- !aHttpTransaction->IsNullTransaction()) {
- LOG3(("SpdySession31::AddStream %p transaction %p forces keep-alive off.\n",
- this, aHttpTransaction));
- DontReuse();
- }
-
- return true;
-}
-
-void
-SpdySession31::QueueStream(SpdyStream31 *stream)
-{
- // will be removed via processpending or a shutdown path
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- MOZ_ASSERT(!stream->CountAsActive());
- MOZ_ASSERT(!stream->Queued());
-
- LOG3(("SpdySession31::QueueStream %p stream %p queued.", this, stream));
-
-#ifdef DEBUG
- size_t qsize = mQueuedStreams.GetSize();
- for (size_t i = 0; i < qsize; i++) {
- SpdyStream31 *qStream = static_cast<SpdyStream31 *>(mQueuedStreams.ObjectAt(i));
- MOZ_ASSERT(qStream != stream);
- MOZ_ASSERT(qStream->Queued());
- }
-#endif
-
- stream->SetQueued(true);
- mQueuedStreams.Push(stream);
-}
-
-void
-SpdySession31::ProcessPending()
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- SpdyStream31 *stream;
- while (RoomForMoreConcurrent() &&
- (stream = static_cast<SpdyStream31 *>(mQueuedStreams.PopFront()))) {
-
- LOG3(("SpdySession31::ProcessPending %p stream %p woken from queue.",
- this, stream));
- MOZ_ASSERT(!stream->CountAsActive());
- MOZ_ASSERT(stream->Queued());
- stream->SetQueued(false);
- mReadyForWrite.Push(stream);
- SetWriteCallbacks();
- }
-}
-
-nsresult
-SpdySession31::NetworkRead(nsAHttpSegmentWriter *writer, char *buf,
- uint32_t count, uint32_t *countWritten)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- if (!count) {
- *countWritten = 0;
- return NS_OK;
- }
-
- nsresult rv = writer->OnWriteSegment(buf, count, countWritten);
- if (NS_SUCCEEDED(rv) && *countWritten > 0)
- mLastReadEpoch = PR_IntervalNow();
- return rv;
-}
-
-void
-SpdySession31::SetWriteCallbacks()
-{
- if (mConnection && (GetWriteQueueSize() || mOutputQueueUsed))
- mConnection->ResumeSend();
-}
-
-void
-SpdySession31::RealignOutputQueue()
-{
- mOutputQueueUsed -= mOutputQueueSent;
- memmove(mOutputQueueBuffer.get(),
- mOutputQueueBuffer.get() + mOutputQueueSent,
- mOutputQueueUsed);
- mOutputQueueSent = 0;
-}
-
-void
-SpdySession31::FlushOutputQueue()
-{
- if (!mSegmentReader || !mOutputQueueUsed)
- return;
-
- nsresult rv;
- uint32_t countRead;
- uint32_t avail = mOutputQueueUsed - mOutputQueueSent;
-
- rv = mSegmentReader->
- OnReadSegment(mOutputQueueBuffer.get() + mOutputQueueSent, avail,
- &countRead);
- LOG3(("SpdySession31::FlushOutputQueue %p sz=%d rv=%x actual=%d",
- this, avail, rv, countRead));
-
- // Dont worry about errors on write, we will pick this up as a read error too
- if (NS_FAILED(rv))
- return;
-
- if (countRead == avail) {
- mOutputQueueUsed = 0;
- mOutputQueueSent = 0;
- return;
- }
-
- mOutputQueueSent += countRead;
-
- // If the output queue is close to filling up and we have sent out a good
- // chunk of data from the beginning then realign it.
-
- if ((mOutputQueueSent >= kQueueMinimumCleanup) &&
- ((mOutputQueueSize - mOutputQueueUsed) < kQueueTailRoom)) {
- RealignOutputQueue();
- }
-}
-
-void
-SpdySession31::DontReuse()
-{
- mShouldGoAway = true;
- if (!mStreamTransactionHash.Count())
- Close(NS_OK);
-}
-
-uint32_t
-SpdySession31::GetWriteQueueSize()
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- return mReadyForWrite.GetSize();
-}
-
-void
-SpdySession31::ChangeDownstreamState(enum stateType newState)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- LOG3(("SpdySession31::ChangeDownstreamState() %p from %X to %X",
- this, mDownstreamState, newState));
- mDownstreamState = newState;
-}
-
-void
-SpdySession31::ResetDownstreamState()
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- LOG3(("SpdySession31::ResetDownstreamState() %p", this));
- ChangeDownstreamState(BUFFERING_FRAME_HEADER);
-
- if (mInputFrameDataLast && mInputFrameDataStream) {
- mInputFrameDataLast = false;
- if (!mInputFrameDataStream->RecvdFin()) {
- LOG3((" SetRecvdFin id=0x%x\n", mInputFrameDataStream->StreamID()));
- mInputFrameDataStream->SetRecvdFin(true);
- DecrementConcurrent(mInputFrameDataStream);
- }
- }
- mInputFrameDataLast = false;
- mInputFrameBufferUsed = 0;
- mInputFrameDataStream = nullptr;
-}
-
-// return true if activated (and counted against max)
-// otherwise return false and queue
-bool
-SpdySession31::TryToActivate(SpdyStream31 *aStream)
-{
- if (aStream->Queued()) {
- LOG3(("SpdySession31::TryToActivate %p stream=%p already queued.\n", this, aStream));
- return false;
- }
-
- if (!RoomForMoreConcurrent()) {
- LOG3(("SpdySession31::TryToActivate %p stream=%p no room for more concurrent "
- "streams %d\n", this, aStream));
- QueueStream(aStream);
- return false;
- }
-
- LOG3(("SpdySession31::TryToActivate %p stream=%p\n", this, aStream));
- IncrementConcurrent(aStream);
- return true;
-}
-
-void
-SpdySession31::IncrementConcurrent(SpdyStream31 *stream)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- MOZ_ASSERT(!stream->StreamID() || (stream->StreamID() & 1),
- "Do not activate pushed streams");
-
- nsAHttpTransaction *trans = stream->Transaction();
- if (!trans || !trans->IsNullTransaction() || trans->QuerySpdyConnectTransaction()) {
-
- MOZ_ASSERT(!stream->CountAsActive());
- stream->SetCountAsActive(true);
- ++mConcurrent;
-
- if (mConcurrent > mConcurrentHighWater) {
- mConcurrentHighWater = mConcurrent;
- }
- LOG3(("SpdySession31::AddStream %p counting stream %p Currently %d "
- "streams in session, high water mark is %d",
- this, stream, mConcurrent, mConcurrentHighWater));
- }
-}
-
-void
-SpdySession31::DecrementConcurrent(SpdyStream31 *aStream)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- if (!aStream->CountAsActive()) {
- return;
- }
-
- MOZ_ASSERT(mConcurrent);
- aStream->SetCountAsActive(false);
- --mConcurrent;
-
- LOG3(("DecrementConcurrent %p id=0x%X concurrent=%d\n",
- this, aStream->StreamID(), mConcurrent));
-
- ProcessPending();
-}
-
-void
-SpdySession31::zlibInit()
-{
- mDownstreamZlib.zalloc = SpdyZlibReporter::Alloc;
- mDownstreamZlib.zfree = SpdyZlibReporter::Free;
- mDownstreamZlib.opaque = Z_NULL;
-
- inflateInit(&mDownstreamZlib);
-
- mUpstreamZlib.zalloc = SpdyZlibReporter::Alloc;
- mUpstreamZlib.zfree = SpdyZlibReporter::Free;
- mUpstreamZlib.opaque = Z_NULL;
-
- // mixing carte blanche compression with tls subjects us to traffic
- // analysis attacks
- deflateInit(&mUpstreamZlib, Z_NO_COMPRESSION);
- deflateSetDictionary(&mUpstreamZlib,
- SpdyStream31::kDictionary,
- sizeof(SpdyStream31::kDictionary));
-}
-
-// Need to decompress some data in order to keep the compression
-// context correct, but we really don't care what the result is
-nsresult
-SpdySession31::UncompressAndDiscard(uint32_t offset,
- uint32_t blockLen)
-{
- char *blockStart = &mInputFrameBuffer[offset];
- unsigned char trash[2048];
- mDownstreamZlib.avail_in = blockLen;
- mDownstreamZlib.next_in = reinterpret_cast<unsigned char *>(blockStart);
- bool triedDictionary = false;
-
- do {
- mDownstreamZlib.next_out = trash;
- mDownstreamZlib.avail_out = sizeof(trash);
- int zlib_rv = inflate(&mDownstreamZlib, Z_NO_FLUSH);
-
- if (zlib_rv == Z_NEED_DICT) {
- if (triedDictionary) {
- LOG3(("SpdySession31::UncompressAndDiscard %p Dictionary Error\n", this));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- triedDictionary = true;
- inflateSetDictionary(&mDownstreamZlib, SpdyStream31::kDictionary,
- sizeof(SpdyStream31::kDictionary));
- }
-
- if (zlib_rv == Z_DATA_ERROR)
- return NS_ERROR_ILLEGAL_VALUE;
-
- if (zlib_rv == Z_MEM_ERROR)
- return NS_ERROR_FAILURE;
- }
- while (mDownstreamZlib.avail_in);
- return NS_OK;
-}
-
-void
-SpdySession31::GeneratePing(uint32_t aID)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- LOG3(("SpdySession31::GeneratePing %p 0x%X\n", this, aID));
-
- EnsureBuffer(mOutputQueueBuffer, mOutputQueueUsed + 12,
- mOutputQueueUsed, mOutputQueueSize);
- char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
- mOutputQueueUsed += 12;
-
- packet[0] = kFlag_Control;
- packet[1] = kVersion;
- packet[2] = 0;
- packet[3] = CONTROL_TYPE_PING;
- packet[4] = 0; /* flags */
- packet[5] = 0;
- packet[6] = 0;
- packet[7] = 4; /* length */
-
- aID = PR_htonl(aID);
- memcpy(packet + 8, &aID, 4);
-
- LogIO(this, nullptr, "Generate Ping", packet, 12);
- FlushOutputQueue();
-}
-
-void
-SpdySession31::GenerateRstStream(uint32_t aStatusCode, uint32_t aID)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- LOG3(("SpdySession31::GenerateRst %p 0x%X %d\n", this, aID, aStatusCode));
-
- EnsureBuffer(mOutputQueueBuffer, mOutputQueueUsed + 16,
- mOutputQueueUsed, mOutputQueueSize);
- char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
- mOutputQueueUsed += 16;
-
- packet[0] = kFlag_Control;
- packet[1] = kVersion;
- packet[2] = 0;
- packet[3] = CONTROL_TYPE_RST_STREAM;
- packet[4] = 0; /* flags */
- packet[5] = 0;
- packet[6] = 0;
- packet[7] = 8; /* length */
-
- aID = PR_htonl(aID);
- memcpy(packet + 8, &aID, 4);
- aStatusCode = PR_htonl(aStatusCode);
- memcpy(packet + 12, &aStatusCode, 4);
-
- LogIO(this, nullptr, "Generate Reset", packet, 16);
- FlushOutputQueue();
-}
-
-void
-SpdySession31::GenerateGoAway(uint32_t aStatusCode)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- LOG3(("SpdySession31::GenerateGoAway %p code=%X\n", this, aStatusCode));
-
- EnsureBuffer(mOutputQueueBuffer, mOutputQueueUsed + 16,
- mOutputQueueUsed, mOutputQueueSize);
- char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
- mOutputQueueUsed += 16;
-
- memset(packet, 0, 16);
- packet[0] = kFlag_Control;
- packet[1] = kVersion;
- packet[3] = CONTROL_TYPE_GOAWAY;
- packet[7] = 8; /* data length */
-
- // last-good-stream-id are bytes 8-11, when we accept server push this will
- // need to be set non zero
-
- // bytes 12-15 are the status code.
- aStatusCode = PR_htonl(aStatusCode);
- memcpy(packet + 12, &aStatusCode, 4);
-
- LogIO(this, nullptr, "Generate GoAway", packet, 16);
- FlushOutputQueue();
-}
-
-void
-SpdySession31::GenerateSettings()
-{
- uint32_t sessionWindowBump = ASpdySession::kInitialRwin - kDefaultRwin;
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- LOG3(("SpdySession31::GenerateSettings %p\n", this));
-
-// sized for 3 settings and a session window update to follow
- static const uint32_t maxDataLen = 4 + 3 * 8 + 16;
- EnsureBuffer(mOutputQueueBuffer, mOutputQueueUsed + 8 + maxDataLen,
- mOutputQueueUsed, mOutputQueueSize);
- char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
-
- memset(packet, 0, 8 + maxDataLen);
- packet[0] = kFlag_Control;
- packet[1] = kVersion;
- packet[3] = CONTROL_TYPE_SETTINGS;
-
- uint8_t numberOfEntries = 0;
-
- // entries need to be listed in order by ID
- // 1st entry is bytes 12 to 19
- // 2nd entry is bytes 20 to 27
- // 3rd entry is bytes 28 to 35
-
- if (!gHttpHandler->AllowPush()) {
- // announcing that we accept 0 incoming streams is done to
- // disable server push
- packet[15 + 8 * numberOfEntries] = SETTINGS_TYPE_MAX_CONCURRENT;
- // The value portion of the setting pair is already initialized to 0
- numberOfEntries++;
- }
-
- // Advertise the Push RWIN and on each client SYN_STREAM pipeline
- // a window update with it in order to use larger initial windows with pulled
- // streams.
- packet[15 + 8 * numberOfEntries] = SETTINGS_TYPE_INITIAL_WINDOW;
- uint32_t rwin = PR_htonl(mPushAllowance);
- memcpy(packet + 16 + 8 * numberOfEntries, &rwin, 4);
- numberOfEntries++;
-
- uint32_t dataLen = 4 + 8 * numberOfEntries;
- mOutputQueueUsed += 8 + dataLen;
- packet[7] = dataLen;
- packet[11] = numberOfEntries;
-
- LogIO(this, nullptr, "Generate Settings", packet, 8 + dataLen);
-
- if (kDefaultRwin >= ASpdySession::kInitialRwin)
- goto generateSettings_complete;
-
- // send a window update for the session (Stream 0) for something large
- sessionWindowBump = PR_htonl(sessionWindowBump);
- mLocalSessionWindow = ASpdySession::kInitialRwin;
-
- packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
- mOutputQueueUsed += 16;
-
- packet[0] = kFlag_Control;
- packet[1] = kVersion;
- packet[3] = CONTROL_TYPE_WINDOW_UPDATE;
- packet[7] = 8; // 8 data bytes after 8 byte header
-
- // 8 to 11 stay 0 bytes for id = 0
- memcpy(packet + 12, &sessionWindowBump, 4);
-
- LOG3(("Session Window increase at start of session %p %u\n",
- this, PR_ntohl(sessionWindowBump)));
- LogIO(this, nullptr, "Session Window Bump ", packet, 16);
-
-generateSettings_complete:
- FlushOutputQueue();
-}
-
-// perform a bunch of integrity checks on the stream.
-// returns true if passed, false (plus LOG and ABORT) if failed.
-bool
-SpdySession31::VerifyStream(SpdyStream31 *aStream, uint32_t aOptionalID = 0)
-{
- // This is annoying, but at least it is O(1)
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
-#ifndef DEBUG
- // Only do the real verification in debug builds
- return true;
-#endif
-
- if (!aStream)
- return true;
-
- uint32_t test = 0;
-
- do {
- if (aStream->StreamID() == kDeadStreamID)
- break;
-
- nsAHttpTransaction *trans = aStream->Transaction();
-
- test++;
- if (!trans)
- break;
-
- test++;
- if (mStreamTransactionHash.Get(trans) != aStream)
- break;
-
- if (aStream->StreamID()) {
- SpdyStream31 *idStream = mStreamIDHash.Get(aStream->StreamID());
-
- test++;
- if (idStream != aStream)
- break;
-
- if (aOptionalID) {
- test++;
- if (idStream->StreamID() != aOptionalID)
- break;
- }
- }
-
- // tests passed
- return true;
- } while (0);
-
- LOG(("SpdySession31 %p VerifyStream Failure %p stream->id=0x%X "
- "optionalID=0x%X trans=%p test=%d\n",
- this, aStream, aStream->StreamID(),
- aOptionalID, aStream->Transaction(), test));
-
- MOZ_ASSERT(false, "VerifyStream");
- return false;
-}
-
-void
-SpdySession31::CleanupStream(SpdyStream31 *aStream, nsresult aResult,
- rstReason aResetCode)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- LOG3(("SpdySession31::CleanupStream %p %p 0x%X %X\n",
- this, aStream, aStream ? aStream->StreamID() : 0, aResult));
- if (!aStream) {
- return;
- }
-
- SpdyPushedStream31 *pushSource = nullptr;
-
- if (NS_SUCCEEDED(aResult) && aStream->DeferCleanupOnSuccess()) {
- LOG(("SpdySession31::CleanupStream 0x%X deferred\n", aStream->StreamID()));
- return;
- }
-
- if (!VerifyStream(aStream)) {
- LOG(("SpdySession31::CleanupStream failed to verify stream\n"));
- return;
- }
-
- pushSource = aStream->PushSource();
-
- if (!aStream->RecvdFin() && aStream->StreamID()) {
- LOG3(("Stream had not processed recv FIN, sending RST code %X\n",
- aResetCode));
- GenerateRstStream(aResetCode, aStream->StreamID());
- DecrementConcurrent(aStream);
- }
-
- CloseStream(aStream, aResult);
-
- // Remove the stream from the ID hash table and, if an even id, the pushed
- // table too.
- uint32_t id = aStream->StreamID();
- if (id > 0) {
- mStreamIDHash.Remove(id);
- if (!(id & 1))
- mPushedStreams.RemoveElement(aStream);
- }
-
- RemoveStreamFromQueues(aStream);
-
- // removing from the stream transaction hash will
- // delete the SpdyStream31 and drop the reference to
- // its transaction
- mStreamTransactionHash.Remove(aStream->Transaction());
-
- if (mShouldGoAway && !mStreamTransactionHash.Count())
- Close(NS_OK);
-
- if (pushSource) {
- pushSource->SetDeferCleanupOnSuccess(false);
- CleanupStream(pushSource, aResult, aResetCode);
- }
-}
-
-static void RemoveStreamFromQueue(SpdyStream31 *aStream, nsDeque &queue)
-{
- size_t size = queue.GetSize();
- for (size_t count = 0; count < size; ++count) {
- SpdyStream31 *stream = static_cast<SpdyStream31 *>(queue.PopFront());
- if (stream != aStream)
- queue.Push(stream);
- }
-}
-
-void
-SpdySession31::RemoveStreamFromQueues(SpdyStream31 *aStream)
-{
- RemoveStreamFromQueue(aStream, mReadyForWrite);
- RemoveStreamFromQueue(aStream, mQueuedStreams);
- RemoveStreamFromQueue(aStream, mReadyForRead);
-}
-
-void
-SpdySession31::CloseStream(SpdyStream31 *aStream, nsresult aResult)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- LOG3(("SpdySession31::CloseStream %p %p 0x%x %X\n",
- this, aStream, aStream->StreamID(), aResult));
-
- // Check if partial frame reader
- if (aStream == mInputFrameDataStream) {
- LOG3(("Stream had active partial read frame on close"));
- ChangeDownstreamState(DISCARDING_DATA_FRAME);
- mInputFrameDataStream = nullptr;
- }
-
- RemoveStreamFromQueues(aStream);
-
- if (aStream->IsTunnel()) {
- UnRegisterTunnel(aStream);
- }
-
- // Send the stream the close() indication
- aStream->Close(aResult);
-}
-
-nsresult
-SpdySession31::HandleSynStream(SpdySession31 *self)
-{
- MOZ_ASSERT(self->mFrameControlType == CONTROL_TYPE_SYN_STREAM);
-
- if (self->mInputFrameDataSize < 18) {
- LOG3(("SpdySession31::HandleSynStream %p SYN_STREAM too short data=%d",
- self, self->mInputFrameDataSize));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- uint32_t streamID =
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
- uint32_t associatedID =
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[3]);
- uint8_t flags = reinterpret_cast<uint8_t *>(self->mInputFrameBuffer.get())[4];
-
- LOG3(("SpdySession31::HandleSynStream %p recv SYN_STREAM (push) "
- "for ID 0x%X associated with 0x%X.\n",
- self, streamID, associatedID));
-
- if (streamID & 0x01) { // test for odd stream ID
- LOG3(("SpdySession31::HandleSynStream %p recvd SYN_STREAM id must be even.",
- self));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- // confirm associated-to
- nsresult rv = self->SetInputFrameDataStream(associatedID);
- if (NS_FAILED(rv))
- return rv;
- SpdyStream31 *associatedStream = self->mInputFrameDataStream;
-
- ++(self->mServerPushedResources);
-
- // Anytime we start using the high bit of stream ID (either client or server)
- // begin to migrate to a new session.
- if (streamID >= kMaxStreamID)
- self->mShouldGoAway = true;
-
- bool resetStream = true;
- SpdyPushCache *cache = nullptr;
-
- if (!(flags & kFlag_Data_UNI)) {
- // pushed streams require UNIDIRECTIONAL flag
- LOG3(("SpdySession31::HandleSynStream %p ID %0x%X associated ID 0x%X failed.\n",
- self, streamID, associatedID));
- self->GenerateRstStream(RST_PROTOCOL_ERROR, streamID);
-
- } else if (!associatedID) {
- // associated stream 0 will never find a match, but the spec requires a
- // PROTOCOL_ERROR in this specific case
- LOG3(("SpdySession31::HandleSynStream %p associated ID of 0 failed.\n", self));
- self->GenerateRstStream(RST_PROTOCOL_ERROR, streamID);
-
- } else if (!gHttpHandler->AllowPush()) {
- // MAX_CONCURRENT_STREAMS of 0 in settings should have disabled push,
- // but some servers are buggy about that.. or the config could have
- // been updated after the settings frame was sent. In both cases just
- // reject the pushed stream as refused
- LOG3(("SpdySession31::HandleSynStream Push Recevied when Disabled\n"));
- self->GenerateRstStream(RST_REFUSED_STREAM, streamID);
-
- } else if (!associatedStream) {
- LOG3(("SpdySession31::HandleSynStream %p lookup associated ID failed.\n", self));
- self->GenerateRstStream(RST_INVALID_STREAM, streamID);
-
- } else {
- nsIRequestContext *requestContext = associatedStream->RequestContext();
- if (requestContext) {
- requestContext->GetSpdyPushCache(&cache);
- if (!cache) {
- cache = new SpdyPushCache();
- if (!cache || NS_FAILED(requestContext->SetSpdyPushCache(cache))) {
- delete cache;
- cache = nullptr;
- }
- }
- }
- if (!cache) {
- // this is unexpected, but we can handle it just be refusing the push
- LOG3(("SpdySession31::HandleSynStream Push Recevied without push cache\n"));
- self->GenerateRstStream(RST_REFUSED_STREAM, streamID);
- }
- else {
- resetStream = false;
- }
- }
-
- if (resetStream) {
- // Need to decompress the headers even though we aren't using them yet in
- // order to keep the compression context consistent for other syn_reply frames
- rv = self->UncompressAndDiscard(18, self->mInputFrameDataSize - 10);
- if (NS_FAILED(rv)) {
- LOG(("SpdySession31::HandleSynStream uncompress failed\n"));
- return rv;
- }
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- // Create the buffering transaction and push stream
- RefPtr<SpdyPush31TransactionBuffer> transactionBuffer =
- new SpdyPush31TransactionBuffer();
- transactionBuffer->SetConnection(self);
- SpdyPushedStream31 *pushedStream =
- new SpdyPushedStream31(transactionBuffer, self,
- associatedStream, streamID);
-
- // ownership of the pushed stream is by the transaction hash, just as it
- // is for a client initiated stream. Errors that aren't fatal to the
- // whole session must call cleanupStream() after this point in order
- // to remove the stream from that hash.
- self->mStreamTransactionHash.Put(transactionBuffer, pushedStream);
- self->mPushedStreams.AppendElement(pushedStream);
-
- // The pushed stream is unidirectional so it is fully open immediately
- 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
- // in spdy format for the time being.
- rv = pushedStream->Uncompress(&self->mDownstreamZlib,
- &self->mInputFrameBuffer[18],
- self->mInputFrameDataSize - 10);
- if (NS_FAILED(rv)) {
- LOG(("SpdySession31::HandleSynStream uncompress failed\n"));
- return rv;
- }
-
- if (self->RegisterStreamID(pushedStream, streamID) == kDeadStreamID) {
- LOG(("SpdySession31::HandleSynStream registerstreamid failed\n"));
- return NS_ERROR_FAILURE;
- }
-
- // Fake the request side of the pushed HTTP transaction. Sets up hash
- // key and origin
- uint32_t notUsed;
- pushedStream->ReadSegments(nullptr, 1, ¬Used);
-
- nsAutoCString key;
- if (!pushedStream->GetHashKey(key)) {
- LOG(("SpdySession31::HandleSynStream one of :host :scheme :path missing from push\n"));
- self->CleanupStream(pushedStream, NS_ERROR_FAILURE, RST_INVALID_STREAM);
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- if (!associatedStream->Origin().Equals(pushedStream->Origin())) {
- LOG(("SpdySession31::HandleSynStream pushed stream mismatched origin\n"));
- self->CleanupStream(pushedStream, NS_ERROR_FAILURE, RST_INVALID_STREAM);
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- if (!cache->RegisterPushedStreamSpdy31(key, pushedStream)) {
- LOG(("SpdySession31::HandleSynStream registerPushedStream Failed\n"));
- self->CleanupStream(pushedStream, NS_ERROR_FAILURE, RST_INVALID_STREAM);
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- self->ResetDownstreamState();
- return NS_OK;
-}
-
-nsresult
-SpdySession31::SetInputFrameDataStream(uint32_t streamID)
-{
- mInputFrameDataStream = mStreamIDHash.Get(streamID);
- if (VerifyStream(mInputFrameDataStream, streamID))
- return NS_OK;
-
- LOG(("SpdySession31::SetInputFrameDataStream failed to verify 0x%X\n",
- streamID));
- mInputFrameDataStream = nullptr;
- return NS_ERROR_UNEXPECTED;
-}
-
-nsresult
-SpdySession31::HandleSynReply(SpdySession31 *self)
-{
- MOZ_ASSERT(self->mFrameControlType == CONTROL_TYPE_SYN_REPLY);
-
- if (self->mInputFrameDataSize < 4) {
- LOG3(("SpdySession31::HandleSynReply %p SYN REPLY too short data=%d",
- self, self->mInputFrameDataSize));
- // A framing error is a session wide error that cannot be recovered
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- uint32_t streamID =
- 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);
- if (NS_FAILED(rv))
- return rv;
-
- if (!self->mInputFrameDataStream) {
- // Cannot find stream. We can continue the SPDY session, but we need to
- // uncompress the header block to maintain the correct compression context
-
- LOG3(("SpdySession31::HandleSynReply %p lookup streamID in syn_reply "
- "0x%X failed. NextStreamID = 0x%X\n",
- self, streamID, self->mNextStreamID));
-
- if (streamID >= self->mNextStreamID)
- self->GenerateRstStream(RST_INVALID_STREAM, streamID);
-
- rv = self->UncompressAndDiscard(12, self->mInputFrameDataSize - 4);
- if (NS_FAILED(rv)) {
- LOG(("SpdySession31::HandleSynReply uncompress failed\n"));
- // this is fatal to the session
- return rv;
- }
-
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- // Uncompress the headers into a stream specific buffer, leaving them in
- // spdy format for the time being. Make certain to do this
- // step before any error handling that might abort the stream but not
- // the session becuase the session compression context will become
- // inconsistent if all of the compressed data is not processed.
- rv = self->mInputFrameDataStream->Uncompress(&self->mDownstreamZlib,
- &self->mInputFrameBuffer[12],
- self->mInputFrameDataSize - 4);
-
- if (NS_FAILED(rv)) {
- LOG(("SpdySession31::HandleSynReply uncompress failed\n"));
- return rv;
- }
-
- if (self->mInputFrameDataStream->GetFullyOpen()) {
- // "If an endpoint receives multiple SYN_REPLY frames for the same active
- // stream ID, it MUST issue a stream error (Section 2.4.2) with the error
- // code STREAM_IN_USE."
- //
- // "STREAM_ALREADY_CLOSED. The endpoint received a data or SYN_REPLY
- // frame for a stream which is half closed."
- //
- // If the stream is open then just RST_STREAM with STREAM_IN_USE
- // If the stream is half closed then RST_STREAM with STREAM_ALREADY_CLOSED
- // abort the session
- //
- LOG3(("SpdySession31::HandleSynReply %p dup SYN_REPLY for 0x%X"
- " recvdfin=%d", self, self->mInputFrameDataStream->StreamID(),
- self->mInputFrameDataStream->RecvdFin()));
-
- self->CleanupStream(self->mInputFrameDataStream, NS_ERROR_ALREADY_OPENED,
- self->mInputFrameDataStream->RecvdFin() ?
- RST_STREAM_ALREADY_CLOSED : RST_STREAM_IN_USE);
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- 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->mInputFrameDataStream->UpdateTransportReadEvents(self->mInputFrameDataSize);
- self->mLastDataReadEpoch = self->mLastReadEpoch;
-
- if (self->mInputFrameBuffer[4] & ~kFlag_Data_FIN) {
- LOG3(("SynReply %p had undefined flag set 0x%X\n", self, streamID));
- self->CleanupStream(self->mInputFrameDataStream, NS_ERROR_ILLEGAL_VALUE,
- RST_PROTOCOL_ERROR);
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- if (!self->mInputFrameDataLast) {
- // don't process the headers yet as there could be more coming from HEADERS
- // frames
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- rv = self->ResponseHeadersComplete();
- if (rv == NS_ERROR_ILLEGAL_VALUE) {
- LOG3(("SpdySession31::HandleSynReply %p PROTOCOL_ERROR detected 0x%X\n",
- self, streamID));
- self->CleanupStream(self->mInputFrameDataStream, rv, RST_PROTOCOL_ERROR);
- self->ResetDownstreamState();
- rv = NS_OK;
- }
- return rv;
-}
-
-// ResponseHeadersComplete() returns NS_ERROR_ILLEGAL_VALUE when the stream
-// should be reset with a PROTOCOL_ERROR, NS_OK when the SYN_REPLY was
-// fine, and any other error is fatal to the session.
-nsresult
-SpdySession31::ResponseHeadersComplete()
-{
- LOG3(("SpdySession31::ResponseHeadersComplete %p for 0x%X fin=%d",
- this, mInputFrameDataStream->StreamID(), mInputFrameDataLast));
-
- // The spdystream needs to see flattened http headers
- // Uncompressed spdy format headers currently live in
- // SpdyStream31::mDecompressBuffer - convert that to HTTP format in
- // mFlatHTTPResponseHeaders via ConvertHeaders()
-
- mFlatHTTPResponseHeadersOut = 0;
- nsresult rv = mInputFrameDataStream->ConvertHeaders(mFlatHTTPResponseHeaders);
- if (NS_FAILED(rv))
- return rv;
-
- ChangeDownstreamState(PROCESSING_COMPLETE_HEADERS);
- return NS_OK;
-}
-
-nsresult
-SpdySession31::HandleRstStream(SpdySession31 *self)
-{
- MOZ_ASSERT(self->mFrameControlType == CONTROL_TYPE_RST_STREAM);
-
- if (self->mInputFrameDataSize != 8) {
- LOG3(("SpdySession31::HandleRstStream %p RST_STREAM wrong length data=%d",
- self, self->mInputFrameDataSize));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- uint8_t flags = reinterpret_cast<uint8_t *>(self->mInputFrameBuffer.get())[4];
-
- uint32_t streamID =
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
-
- self->mDownstreamRstReason =
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[3]);
-
- LOG3(("SpdySession31::HandleRstStream %p RST_STREAM Reason Code %u ID %x "
- "flags %x", self, self->mDownstreamRstReason, streamID, flags));
-
- if (flags != 0) {
- LOG3(("SpdySession31::HandleRstStream %p RST_STREAM with flags is illegal",
- self));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- if (self->mDownstreamRstReason == RST_INVALID_STREAM ||
- self->mDownstreamRstReason == RST_STREAM_IN_USE ||
- self->mDownstreamRstReason == RST_FLOW_CONTROL_ERROR) {
- // basically just ignore this
- LOG3(("SpdySession31::HandleRstStream %p No Reset Processing Needed.\n"));
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- nsresult rv = self->SetInputFrameDataStream(streamID);
-
- if (!self->mInputFrameDataStream) {
- if (NS_FAILED(rv))
- LOG(("SpdySession31::HandleRstStream %p lookup streamID for RST Frame "
- "0x%X failed reason = %d :: VerifyStream Failed\n", self, streamID,
- self->mDownstreamRstReason));
-
- LOG3(("SpdySession31::HandleRstStream %p lookup streamID for RST Frame "
- "0x%X failed reason = %d", self, streamID,
- self->mDownstreamRstReason));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- self->ChangeDownstreamState(PROCESSING_CONTROL_RST_STREAM);
- return NS_OK;
-}
-
-nsresult
-SpdySession31::HandleSettings(SpdySession31 *self)
-{
- MOZ_ASSERT(self->mFrameControlType == CONTROL_TYPE_SETTINGS);
-
- if (self->mInputFrameDataSize < 4) {
- LOG3(("SpdySession31::HandleSettings %p SETTINGS wrong length data=%d",
- self, self->mInputFrameDataSize));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- uint32_t numEntries =
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
-
- // Ensure frame is large enough for supplied number of entries
- // Each entry is 8 bytes, frame data is reduced by 4 to account for
- // the NumEntries value.
- if ((self->mInputFrameDataSize - 4) < (numEntries * 8)) {
- LOG3(("SpdySession31::HandleSettings %p SETTINGS wrong length data=%d",
- self, self->mInputFrameDataSize));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- LOG3(("SpdySession31::HandleSettings %p SETTINGS Control Frame with %d entries",
- self, numEntries));
-
- for (uint32_t index = 0; index < numEntries; ++index) {
- unsigned char *setting = reinterpret_cast<unsigned char *>
- (self->mInputFrameBuffer.get()) + 12 + index * 8;
-
- uint32_t flags = setting[0];
- uint32_t id = PR_ntohl(reinterpret_cast<uint32_t *>(setting)[0]) & 0xffffff;
- uint32_t value = PR_ntohl(reinterpret_cast<uint32_t *>(setting)[1]);
-
- LOG3(("Settings ID %d, Flags %X, Value %d", id, flags, value));
-
- switch (id)
- {
- case SETTINGS_TYPE_MAX_CONCURRENT:
- self->mMaxConcurrent = value;
- self->ProcessPending();
- break;
-
- case SETTINGS_TYPE_INITIAL_WINDOW:
- {
- int32_t delta = value - self->mServerInitialStreamWindow;
- self->mServerInitialStreamWindow = value;
-
- // do not use SETTINGS to adjust the session window.
-
- // we need to add the delta to all open streams (delta can be negative)
- for (auto iter = self->mStreamTransactionHash.Iter();
- !iter.Done();
- iter.Next()) {
- iter.Data()->UpdateRemoteWindow(delta);
- }
- }
- break;
-
- default:
- break;
- }
-
- }
-
- self->ResetDownstreamState();
- return NS_OK;
-}
-
-nsresult
-SpdySession31::HandleNoop(SpdySession31 *self)
-{
- MOZ_ASSERT(self->mFrameControlType == CONTROL_TYPE_NOOP);
-
- // Should not be receiving noop frames in spdy/3.1, so we'll just
- // make a log and ignore it
-
- LOG3(("SpdySession31::HandleNoop %p NOP.", self));
-
- self->ResetDownstreamState();
- return NS_OK;
-}
-
-nsresult
-SpdySession31::HandlePing(SpdySession31 *self)
-{
- MOZ_ASSERT(self->mFrameControlType == CONTROL_TYPE_PING);
-
- if (self->mInputFrameDataSize != 4) {
- LOG3(("SpdySession31::HandlePing %p PING had wrong amount of data %d",
- self, self->mInputFrameDataSize));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- uint32_t pingID =
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
-
- LOG3(("SpdySession31::HandlePing %p PING ID 0x%X.", self, pingID));
-
- if (pingID & 0x01) {
- // presumably a reply to our timeout ping
- self->mPingSentEpoch = 0;
- }
- else {
- // Servers initiate even numbered pings, go ahead and echo it back
- self->GeneratePing(pingID);
- }
-
- self->ResetDownstreamState();
- return NS_OK;
-}
-
-nsresult
-SpdySession31::HandleGoAway(SpdySession31 *self)
-{
- MOZ_ASSERT(self->mFrameControlType == CONTROL_TYPE_GOAWAY);
-
- if (self->mInputFrameDataSize != 8) {
- LOG3(("SpdySession31::HandleGoAway %p GOAWAY had wrong amount of data %d",
- self, self->mInputFrameDataSize));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- self->mShouldGoAway = true;
- self->mGoAwayID =
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
- self->mCleanShutdown = true;
-
- // Find streams greater than the last-good ID and mark them for deletion
- // in the mGoAwayStreamsToRestart queue. The underlying transaction can be
- // restarted.
- for (auto iter = self->mStreamTransactionHash.Iter();
- !iter.Done();
- iter.Next()) {
-
- // These streams were not processed by the server and can be restarted. Do
- // that after the enumerator completes to avoid the risk of a restart event
- // re-entrantly modifying this hash. Be sure not to restart a pushed (even
- // numbered) stream.
- nsAutoPtr<SpdyStream31>& stream = iter.Data();
- if ((stream->StreamID() > self->mGoAwayID && (stream->StreamID() & 1)) ||
- !stream->HasRegisteredID()) {
- self->mGoAwayStreamsToRestart.Push(stream);
- }
- }
-
- // Process the streams marked for deletion and restart.
- size_t size = self->mGoAwayStreamsToRestart.GetSize();
- for (size_t count = 0; count < size; ++count) {
- SpdyStream31 *stream =
- static_cast<SpdyStream31 *>(self->mGoAwayStreamsToRestart.PopFront());
-
- self->CloseStream(stream, NS_ERROR_NET_RESET);
- if (stream->HasRegisteredID())
- self->mStreamIDHash.Remove(stream->StreamID());
- self->mStreamTransactionHash.Remove(stream->Transaction());
- }
-
- // Queued streams can also be deleted from this session and restarted
- // in another one. (they were never sent on the network so they implicitly
- // are not covered by the last-good id.
- size = self->mQueuedStreams.GetSize();
- for (size_t count = 0; count < size; ++count) {
- SpdyStream31 *stream =
- static_cast<SpdyStream31 *>(self->mQueuedStreams.PopFront());
- MOZ_ASSERT(stream->Queued());
- stream->SetQueued(false);
- self->CloseStream(stream, NS_ERROR_NET_RESET);
- self->mStreamTransactionHash.Remove(stream->Transaction());
- }
-
- LOG3(("SpdySession31::HandleGoAway %p GOAWAY Last-Good-ID 0x%X status 0x%X "
- "live streams=%d\n", self, self->mGoAwayID,
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[3]),
- self->mStreamTransactionHash.Count()));
-
- self->ResetDownstreamState();
- return NS_OK;
-}
-
-nsresult
-SpdySession31::HandleHeaders(SpdySession31 *self)
-{
- MOZ_ASSERT(self->mFrameControlType == CONTROL_TYPE_HEADERS);
-
- if (self->mInputFrameDataSize < 4) {
- LOG3(("SpdySession31::HandleHeaders %p HEADERS had wrong amount of data %d",
- self, self->mInputFrameDataSize));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- uint32_t streamID =
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
- LOG3(("SpdySession31::HandleHeaders %p HEADERS for Stream 0x%X.\n",
- self, streamID));
- nsresult rv = self->SetInputFrameDataStream(streamID);
- if (NS_FAILED(rv))
- return rv;
-
- if (!self->mInputFrameDataStream) {
- LOG3(("SpdySession31::HandleHeaders %p lookup streamID 0x%X failed.\n",
- self, streamID));
- if (streamID >= self->mNextStreamID)
- self->GenerateRstStream(RST_INVALID_STREAM, streamID);
-
- rv = self->UncompressAndDiscard(12, self->mInputFrameDataSize - 4);
- if (NS_FAILED(rv)) {
- LOG(("SpdySession31::HandleHeaders uncompress failed\n"));
- // this is fatal to the session
- return rv;
- }
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- // Uncompress the headers into local buffers in the SpdyStream, leaving
- // them in spdy format for the time being. Make certain to do this
- // step before any error handling that might abort the stream but not
- // the session becuase the session compression context will become
- // inconsistent if all of the compressed data is not processed.
- rv = self->mInputFrameDataStream->Uncompress(&self->mDownstreamZlib,
- &self->mInputFrameBuffer[12],
- self->mInputFrameDataSize - 4);
- if (NS_FAILED(rv)) {
- LOG(("SpdySession31::HandleHeaders uncompress failed\n"));
- return rv;
- }
-
- self->mInputFrameDataLast = self->mInputFrameBuffer[4] & kFlag_Data_FIN;
- self->mInputFrameDataStream->
- UpdateTransportReadEvents(self->mInputFrameDataSize);
- self->mLastDataReadEpoch = self->mLastReadEpoch;
-
- if (self->mInputFrameBuffer[4] & ~kFlag_Data_FIN) {
- LOG3(("Headers %p had undefined flag set 0x%X\n", self, streamID));
- self->CleanupStream(self->mInputFrameDataStream, NS_ERROR_ILLEGAL_VALUE,
- RST_PROTOCOL_ERROR);
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- if (!self->mInputFrameDataLast) {
- // don't process the headers yet as there could be more HEADERS frames
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- rv = self->ResponseHeadersComplete();
- if (rv == NS_ERROR_ILLEGAL_VALUE) {
- LOG3(("SpdySession31::HanndleHeaders %p PROTOCOL_ERROR detected 0x%X\n",
- self, streamID));
- self->CleanupStream(self->mInputFrameDataStream, rv, RST_PROTOCOL_ERROR);
- self->ResetDownstreamState();
- rv = NS_OK;
- }
- return rv;
-}
-
-nsresult
-SpdySession31::HandleWindowUpdate(SpdySession31 *self)
-{
- MOZ_ASSERT(self->mFrameControlType == CONTROL_TYPE_WINDOW_UPDATE);
-
- if (self->mInputFrameDataSize < 8) {
- LOG3(("SpdySession31::HandleWindowUpdate %p Window Update wrong length %d\n",
- self, self->mInputFrameDataSize));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- uint32_t delta =
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[3]);
- delta &= 0x7fffffff;
- uint32_t streamID =
- PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
- streamID &= 0x7fffffff;
-
- LOG3(("SpdySession31::HandleWindowUpdate %p len=%d for Stream 0x%X.\n",
- self, delta, streamID));
-
- // ID of 0 is a session window update
- if (streamID) {
- nsresult rv = self->SetInputFrameDataStream(streamID);
- if (NS_FAILED(rv))
- return rv;
-
- if (!self->mInputFrameDataStream) {
- LOG3(("SpdySession31::HandleWindowUpdate %p lookup streamID 0x%X failed.\n",
- self, streamID));
- if (streamID >= self->mNextStreamID)
- self->GenerateRstStream(RST_INVALID_STREAM, streamID);
- self->ResetDownstreamState();
- return NS_OK;
- }
-
- self->mInputFrameDataStream->UpdateRemoteWindow(delta);
- } else {
- int64_t oldRemoteWindow = self->mRemoteSessionWindow;
- self->mRemoteSessionWindow += delta;
- if ((oldRemoteWindow <= 0) && (self->mRemoteSessionWindow > 0)) {
- LOG3(("SpdySession31::HandleWindowUpdate %p restart session window\n",
- self));
- for (auto iter = self->mStreamTransactionHash.Iter();
- !iter.Done();
- iter.Next()) {
- MOZ_ASSERT(self->mRemoteSessionWindow > 0);
-
- nsAutoPtr<SpdyStream31>& stream = iter.Data();
- if (!stream->BlockedOnRwin() || stream->RemoteWindow() <= 0) {
- continue;
- }
-
- self->mReadyForWrite.Push(stream);
- self->SetWriteCallbacks();
- }
- }
- }
-
- self->ResetDownstreamState();
- return NS_OK;
-}
-
-nsresult
-SpdySession31::HandleCredential(SpdySession31 *self)
-{
- MOZ_ASSERT(self->mFrameControlType == CONTROL_TYPE_CREDENTIAL);
-
- // These aren't used yet. Just ignore the frame.
-
- LOG3(("SpdySession31::HandleCredential %p NOP.", self));
-
- self->ResetDownstreamState();
- return NS_OK;
-}
-
-//-----------------------------------------------------------------------------
-// nsAHttpTransaction. It is expected that nsHttpConnection is the caller
-// of these methods
-//-----------------------------------------------------------------------------
-
-void
-SpdySession31::OnTransportStatus(nsITransport* aTransport,
- nsresult aStatus,
- int64_t aProgress)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- switch (aStatus) {
- // These should appear only once, deliver to the first
- // transaction on the session.
- case NS_NET_STATUS_RESOLVING_HOST:
- case NS_NET_STATUS_RESOLVED_HOST:
- case NS_NET_STATUS_CONNECTING_TO:
- case NS_NET_STATUS_CONNECTED_TO:
- {
- SpdyStream31 *target = mStreamIDHash.Get(1);
- nsAHttpTransaction *transaction = target ? target->Transaction() : nullptr;
- if (transaction)
- transaction->OnTransportStatus(aTransport, aStatus, aProgress);
- break;
- }
-
- default:
- // The other transport events are ignored here because there is no good
- // way to map them to the right transaction in spdy. Instead, the events
- // are generated again from the spdy code and passed directly to the
- // correct transaction.
-
- // NS_NET_STATUS_SENDING_TO:
- // This is generated by the socket transport when (part) of
- // a transaction is written out
- //
- // There is no good way to map it to the right transaction in spdy,
- // so it is ignored here and generated separately when the SYN_STREAM
- // is sent from SpdyStream31::TransmitFrame
-
- // NS_NET_STATUS_WAITING_FOR:
- // Created by nsHttpConnection when the request has been totally sent.
- // There is no good way to map it to the right transaction in spdy,
- // so it is ignored here and generated separately when the same
- // condition is complete in SpdyStream31 when there is no more
- // request body left to be transmitted.
-
- // NS_NET_STATUS_RECEIVING_FROM
- // Generated in spdysession whenever we read a data frame or a syn_reply
- // that can be attributed to a particular stream/transaction
-
- break;
- }
-}
-
-// ReadSegments() is used to write data to the network. Generally, HTTP
-// request data is pulled from the approriate transaction and
-// converted to SPDY data. Sometimes control data like window-update are
-// generated instead.
-
-nsresult
-SpdySession31::ReadSegmentsAgain(nsAHttpSegmentReader *reader,
- uint32_t count,
- uint32_t *countRead,
- bool *again)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- MOZ_ASSERT(!mSegmentReader || !reader || (mSegmentReader == reader),
- "Inconsistent Write Function Callback");
-
- if (reader)
- mSegmentReader = reader;
-
- nsresult rv;
- *countRead = 0;
-
- LOG3(("SpdySession31::ReadSegments %p", this));
-
- SpdyStream31 *stream = static_cast<SpdyStream31 *>(mReadyForWrite.PopFront());
- if (!stream) {
- LOG3(("SpdySession31 %p could not identify a stream to write; suspending.",
- this));
- FlushOutputQueue();
- SetWriteCallbacks();
- return NS_BASE_STREAM_WOULD_BLOCK;
- }
-
- LOG3(("SpdySession31 %p will write from SpdyStream31 %p 0x%X "
- "block-input=%d block-output=%d\n", this, stream, stream->StreamID(),
- stream->RequestBlockedOnRead(), stream->BlockedOnRwin()));
-
- rv = stream->ReadSegments(this, count, countRead);
-
- // Not every permutation of stream->ReadSegents produces data (and therefore
- // tries to flush the output queue) - SENDING_FIN_STREAM can be an example
- // of that. But we might still have old data buffered that would be good
- // to flush.
- FlushOutputQueue();
-
- // Allow new server reads - that might be data or control information
- // (e.g. window updates or http replies) that are responses to these writes
- ResumeRecv();
-
- if (stream->RequestBlockedOnRead()) {
-
- // We are blocked waiting for input - either more http headers or
- // any request body data. When more data from the request stream
- // becomes available the httptransaction will call conn->ResumeSend().
-
- LOG3(("SpdySession31::ReadSegments %p dealing with block on read", this));
-
- // call readsegments again if there are other streams ready
- // to run in this session
- if (GetWriteQueueSize())
- rv = NS_OK;
- else
- rv = NS_BASE_STREAM_WOULD_BLOCK;
- SetWriteCallbacks();
- return rv;
- }
-
- if (NS_FAILED(rv)) {
- LOG3(("SpdySession31::ReadSegments %p may return FAIL code %X",
- this, rv));
- if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
- return rv;
- }
-
- CleanupStream(stream, rv, RST_CANCEL);
- if (SoftStreamError(rv)) {
- LOG3(("SpdySession31::ReadSegments %p soft error override\n", this));
- *again = false;
- SetWriteCallbacks();
- rv = NS_OK;
- }
- return rv;
- }
-
- if (*countRead > 0) {
- LOG3(("SpdySession31::ReadSegments %p stream=%p countread=%d",
- this, stream, *countRead));
- mReadyForWrite.Push(stream);
- SetWriteCallbacks();
- return rv;
- }
-
- if (stream->BlockedOnRwin()) {
- LOG3(("SpdySession31 %p will stream %p 0x%X suspended for flow control\n",
- this, stream, stream->StreamID()));
- return NS_BASE_STREAM_WOULD_BLOCK;
- }
-
- LOG3(("SpdySession31::ReadSegments %p stream=%p stream send complete",
- this, stream));
-
- // call readsegments again if there are other streams ready
- // to go in this session
- SetWriteCallbacks();
-
- return rv;
-}
-
-nsresult
-SpdySession31::ReadSegments(nsAHttpSegmentReader *reader,
- uint32_t count, uint32_t *countRead)
-{
- bool again = false;
- return ReadSegmentsAgain(reader, count, countRead, &again);
-}
-
-// WriteSegments() is used to read data off the socket. Generally this is
-// just the SPDY frame header and from there the appropriate SPDYStream
-// is identified from the Stream-ID. The http transaction associated with
-// that read then pulls in the data directly, which it will feed to
-// OnWriteSegment(). That function will gateway it into http and feed
-// it to the appropriate transaction.
-
-// we call writer->OnWriteSegment via NetworkRead() to get a spdy header..
-// and decide if it is data or control.. if it is control, just deal with it.
-// if it is data, identify the spdy stream
-// call stream->WriteSegments which can call this::OnWriteSegment to get the
-// data. It always gets full frames if they are part of the stream
-
-nsresult
-SpdySession31::WriteSegmentsAgain(nsAHttpSegmentWriter *writer,
- uint32_t count,
- uint32_t *countWritten,
- bool *again)
-{
- typedef nsresult (*Control_FX) (SpdySession31 *self);
- static const Control_FX sControlFunctions[] =
- {
- nullptr,
- SpdySession31::HandleSynStream,
- SpdySession31::HandleSynReply,
- SpdySession31::HandleRstStream,
- SpdySession31::HandleSettings,
- SpdySession31::HandleNoop,
- SpdySession31::HandlePing,
- SpdySession31::HandleGoAway,
- SpdySession31::HandleHeaders,
- SpdySession31::HandleWindowUpdate,
- SpdySession31::HandleCredential
- };
-
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- nsresult rv;
- *countWritten = 0;
-
- if (mClosed)
- return NS_ERROR_FAILURE;
-
- SetWriteCallbacks();
-
- // If there are http transactions attached to a push stream with filled buffers
- // trigger that data pump here. This only reads from buffers (not the network)
- // so mDownstreamState doesn't matter.
- SpdyStream31 *pushConnectedStream =
- static_cast<SpdyStream31 *>(mReadyForRead.PopFront());
- if (pushConnectedStream) {
- LOG3(("SpdySession31::WriteSegments %p processing pushed stream 0x%X\n",
- this, pushConnectedStream->StreamID()));
- mSegmentWriter = writer;
- rv = pushConnectedStream->WriteSegments(this, count, countWritten);
- mSegmentWriter = nullptr;
-
- // The pipe in nsHttpTransaction rewrites CLOSED error codes into OK
- // so we need this check to determine the truth.
- if (NS_SUCCEEDED(rv) && !*countWritten &&
- pushConnectedStream->PushSource() &&
- pushConnectedStream->PushSource()->GetPushComplete()) {
- rv = NS_BASE_STREAM_CLOSED;
- }
-
- if (rv == NS_BASE_STREAM_CLOSED) {
- CleanupStream(pushConnectedStream, NS_OK, RST_CANCEL);
- rv = NS_OK;
- }
-
- // if we return OK to nsHttpConnection it will use mSocketInCondition
- // to determine whether to schedule more reads, incorrectly
- // assuming that nsHttpConnection::OnSocketWrite() was called.
- if (NS_SUCCEEDED(rv) || rv == NS_BASE_STREAM_WOULD_BLOCK) {
- rv = NS_BASE_STREAM_WOULD_BLOCK;
- ResumeRecv();
- }
-
- return rv;
- }
-
- // We buffer all control frames and act on them in this layer.
- // We buffer the first 8 bytes of data frames (the header) but
- // the actual data is passed through unprocessed.
-
- if (mDownstreamState == BUFFERING_FRAME_HEADER) {
- // The first 8 bytes of every frame is header information that
- // we are going to want to strip before passing to http. That is
- // true of both control and data packets.
-
- MOZ_ASSERT(mInputFrameBufferUsed < 8,
- "Frame Buffer Used Too Large for State");
-
- rv = NetworkRead(writer, &mInputFrameBuffer[mInputFrameBufferUsed],
- 8 - mInputFrameBufferUsed, countWritten);
-
- if (NS_FAILED(rv)) {
- LOG3(("SpdySession31 %p buffering frame header read failure %x\n",
- this, rv));
- // maybe just blocked reading from network
- if (rv == NS_BASE_STREAM_WOULD_BLOCK)
- rv = NS_OK;
- return rv;
- }
-
- LogIO(this, nullptr, "Reading Frame Header",
- &mInputFrameBuffer[mInputFrameBufferUsed], *countWritten);
-
- mInputFrameBufferUsed += *countWritten;
-
- if (mInputFrameBufferUsed < 8)
- {
- LOG3(("SpdySession31::WriteSegments %p "
- "BUFFERING FRAME HEADER incomplete size=%d",
- this, mInputFrameBufferUsed));
- return rv;
- }
-
- // For both control and data frames the second 32 bit word of the header
- // is 8-flags, 24-length. (network byte order)
- mInputFrameDataSize =
- PR_ntohl(reinterpret_cast<uint32_t *>(mInputFrameBuffer.get())[1]);
- mInputFrameDataSize &= 0x00ffffff;
- mInputFrameDataRead = 0;
-
- if (mInputFrameBuffer[0] & kFlag_Control) {
- EnsureBuffer(mInputFrameBuffer, mInputFrameDataSize + 8, 8,
- mInputFrameBufferSize);
- ChangeDownstreamState(BUFFERING_CONTROL_FRAME);
-
- // The first 32 bit word of the header is
- // 1 ctrl - 15 version - 16 type
- uint16_t version =
- PR_ntohs(reinterpret_cast<uint16_t *>(mInputFrameBuffer.get())[0]);
- version &= 0x7fff;
-
- mFrameControlType =
- PR_ntohs(reinterpret_cast<uint16_t *>(mInputFrameBuffer.get())[1]);
-
- LOG3(("SpdySession31::WriteSegments %p - Control Frame Identified "
- "type %d version %d data len %d",
- this, mFrameControlType, version, mInputFrameDataSize));
-
- if (mFrameControlType >= CONTROL_TYPE_LAST ||
- mFrameControlType <= CONTROL_TYPE_FIRST)
- return NS_ERROR_ILLEGAL_VALUE;
-
- if (version != kVersion)
- return NS_ERROR_ILLEGAL_VALUE;
- }
- else {
- ChangeDownstreamState(PROCESSING_DATA_FRAME);
-
- Telemetry::Accumulate(Telemetry::SPDY_CHUNK_RECVD,
- mInputFrameDataSize >> 10);
- mLastDataReadEpoch = mLastReadEpoch;
-
- uint32_t streamID =
- PR_ntohl(reinterpret_cast<uint32_t *>(mInputFrameBuffer.get())[0]);
- rv = SetInputFrameDataStream(streamID);
- if (NS_FAILED(rv)) {
- LOG(("SpdySession31::WriteSegments %p lookup streamID 0x%X failed. "
- "probably due to verification.\n", this, streamID));
- return rv;
- }
- if (!mInputFrameDataStream) {
- LOG3(("SpdySession31::WriteSegments %p lookup streamID 0x%X failed. "
- "Next = 0x%X", this, streamID, mNextStreamID));
- if (streamID >= mNextStreamID)
- GenerateRstStream(RST_INVALID_STREAM, streamID);
- ChangeDownstreamState(DISCARDING_DATA_FRAME);
- }
- else if (mInputFrameDataStream->RecvdFin()) {
- LOG3(("SpdySession31::WriteSegments %p streamID 0x%X "
- "Data arrived for already server closed stream.\n",
- this, streamID));
- GenerateRstStream(RST_STREAM_ALREADY_CLOSED, streamID);
- ChangeDownstreamState(DISCARDING_DATA_FRAME);
- }
- else if (!mInputFrameDataStream->RecvdData()) {
- LOG3(("SpdySession31 %p First Data Frame Flushes Headers stream 0x%X\n",
- this, streamID));
-
- mInputFrameDataStream->SetRecvdData(true);
- rv = ResponseHeadersComplete();
- if (rv == NS_ERROR_ILLEGAL_VALUE) {
- LOG3(("SpdySession31 %p ResponseHeadersComplete PROTOCOL_ERROR detected 0x%X\n",
- this, streamID));
- CleanupStream(mInputFrameDataStream, rv, RST_PROTOCOL_ERROR);
- ChangeDownstreamState(DISCARDING_DATA_FRAME);
- }
- else {
- mDataPending = true;
- }
- }
-
- mInputFrameDataLast = (mInputFrameBuffer[4] & kFlag_Data_FIN);
- LOG3(("Start Processing Data Frame. "
- "Session=%p Stream ID 0x%X Stream Ptr %p Fin=%d Len=%d",
- this, streamID, mInputFrameDataStream, mInputFrameDataLast,
- mInputFrameDataSize));
- UpdateLocalRwin(mInputFrameDataStream, mInputFrameDataSize);
- }
- }
-
- if (mDownstreamState == PROCESSING_CONTROL_RST_STREAM) {
- if (mDownstreamRstReason == RST_REFUSED_STREAM)
- rv = NS_ERROR_NET_RESET; //we can retry this 100% safely
- else if (mDownstreamRstReason == RST_CANCEL) {
- rv = mInputFrameDataStream->RecvdData() ?
- NS_ERROR_NET_PARTIAL_TRANSFER :
- NS_ERROR_NET_INTERRUPT;
- }
- else if (mDownstreamRstReason == RST_PROTOCOL_ERROR ||
- mDownstreamRstReason == RST_INTERNAL_ERROR ||
- mDownstreamRstReason == RST_UNSUPPORTED_VERSION) {
- rv = NS_ERROR_NET_INTERRUPT;
- }
- else if (mDownstreamRstReason == RST_FRAME_TOO_LARGE)
- rv = NS_ERROR_FILE_TOO_BIG;
- else
- rv = NS_ERROR_ILLEGAL_VALUE;
-
- if (mDownstreamRstReason != RST_REFUSED_STREAM &&
- mDownstreamRstReason != RST_CANCEL)
- mShouldGoAway = true;
-
- // mInputFrameDataStream is reset by ChangeDownstreamState
- SpdyStream31 *stream = mInputFrameDataStream;
- ResetDownstreamState();
- LOG3(("SpdySession31::WriteSegments cleanup stream on recv of rst "
- "session=%p stream=%p 0x%X\n", this, stream,
- stream ? stream->StreamID() : 0));
- CleanupStream(stream, rv, RST_CANCEL);
- return NS_OK;
- }
-
- if (mDownstreamState == PROCESSING_DATA_FRAME ||
- mDownstreamState == PROCESSING_COMPLETE_HEADERS) {
-
- // The cleanup stream should only be set while stream->WriteSegments is
- // on the stack and then cleaned up in this code block afterwards.
- MOZ_ASSERT(!mNeedsCleanup, "cleanup stream set unexpectedly");
- mNeedsCleanup = nullptr; /* just in case */
-
- // The writesegments() stack can clear mInputFrameDataStream so
- // only reference this local copy of it afterwards
- SpdyStream31 *stream = mInputFrameDataStream;
- mSegmentWriter = writer;
- rv = mInputFrameDataStream->WriteSegments(this, count, countWritten);
- bool channelPipeFull = false;
- if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
- LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X "
- "stream channel pipe full\n",
- this, stream, stream ? stream->StreamID() : 0));
- channelPipeFull = stream->ChannelPipeFull();
- }
- mSegmentWriter = nullptr;
-
- mLastDataReadEpoch = mLastReadEpoch;
-
- if (SoftStreamError(rv)) {
- // This will happen when the transaction figures out it is EOF, generally
- // due to a content-length match being made. Return OK from this function
- // otherwise the whole session would be torn down.
-
- // if we were doing PROCESSING_COMPLETE_HEADERS need to pop the state
- // back to PROCESSING_DATA_FRAME where we came from
- mDownstreamState = PROCESSING_DATA_FRAME;
-
- if (mInputFrameDataRead == mInputFrameDataSize)
- ResetDownstreamState();
- LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X "
- "needscleanup=%p. cleanup stream based on "
- "stream->writeSegments returning code %X\n",
- this, stream, stream ? stream->StreamID() : 0,
- mNeedsCleanup, rv));
- CleanupStream(stream, NS_OK, RST_CANCEL);
- MOZ_ASSERT(!mNeedsCleanup || mNeedsCleanup == stream);
- mNeedsCleanup = nullptr;
- *again = false;
- ResumeRecv();
- return NS_OK;
- }
-
- if (mNeedsCleanup) {
- LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X "
- "cleanup stream based on mNeedsCleanup.\n",
- this, mNeedsCleanup, mNeedsCleanup ? mNeedsCleanup->StreamID() : 0));
- CleanupStream(mNeedsCleanup, NS_OK, RST_CANCEL);
- mNeedsCleanup = nullptr;
- }
-
- if (NS_FAILED(rv)) {
- LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X "
- "data frame read failure %x pipefull=%d\n",
- this, stream, stream ? stream->StreamID() : 0, rv, channelPipeFull));
- // maybe just blocked reading from network
- if ((rv == NS_BASE_STREAM_WOULD_BLOCK) && !channelPipeFull) {
- rv = NS_OK;
- }
- }
-
- return rv;
- }
-
- if (mDownstreamState == DISCARDING_DATA_FRAME) {
- char trash[4096];
- uint32_t discardCount = std::min(mInputFrameDataSize - mInputFrameDataRead,
- 4096U);
-
- if (!discardCount) {
- ResetDownstreamState();
- ResumeRecv();
- return NS_BASE_STREAM_WOULD_BLOCK;
- }
-
- rv = NetworkRead(writer, trash, discardCount, countWritten);
-
- if (NS_FAILED(rv)) {
- LOG3(("SpdySession31 %p discard frame read failure %x\n", this, rv));
- // maybe just blocked reading from network
- if (rv == NS_BASE_STREAM_WOULD_BLOCK)
- rv = NS_OK;
- return rv;
- }
-
- LogIO(this, nullptr, "Discarding Frame", trash, *countWritten);
-
- mInputFrameDataRead += *countWritten;
-
- if (mInputFrameDataRead == mInputFrameDataSize)
- ResetDownstreamState();
- return rv;
- }
-
- MOZ_ASSERT(mDownstreamState == BUFFERING_CONTROL_FRAME);
- if (mDownstreamState != BUFFERING_CONTROL_FRAME) {
- // this cannot happen
- return NS_ERROR_UNEXPECTED;
- }
-
- MOZ_ASSERT(mInputFrameBufferUsed == 8,
- "Frame Buffer Header Not Present");
-
- rv = NetworkRead(writer, &mInputFrameBuffer[8 + mInputFrameDataRead],
- mInputFrameDataSize - mInputFrameDataRead, countWritten);
-
- if (NS_FAILED(rv)) {
- LOG3(("SpdySession31 %p buffering control frame read failure %x\n",
- this, rv));
- // maybe just blocked reading from network
- if (rv == NS_BASE_STREAM_WOULD_BLOCK)
- rv = NS_OK;
- return rv;
- }
-
- LogIO(this, nullptr, "Reading Control Frame",
- &mInputFrameBuffer[8 + mInputFrameDataRead], *countWritten);
-
- mInputFrameDataRead += *countWritten;
-
- if (mInputFrameDataRead != mInputFrameDataSize)
- return NS_OK;
-
- // This check is actually redundant, the control type was previously
- // checked to make sure it was in range, but we will check it again
- // at time of use to make sure a regression doesn't creep in.
- if (mFrameControlType >= CONTROL_TYPE_LAST ||
- mFrameControlType <= CONTROL_TYPE_FIRST)
- {
- MOZ_ASSERT(false, "control type out of range");
- return NS_ERROR_ILLEGAL_VALUE;
- }
- rv = sControlFunctions[mFrameControlType](this);
-
- MOZ_ASSERT(NS_FAILED(rv) ||
- mDownstreamState != BUFFERING_CONTROL_FRAME,
- "Control Handler returned OK but did not change state");
-
- if (mShouldGoAway && !mStreamTransactionHash.Count())
- Close(NS_OK);
- return rv;
-}
-
-nsresult
-SpdySession31::WriteSegments(nsAHttpSegmentWriter *writer,
- uint32_t count, uint32_t *countWritten)
-{
- bool again = false;
- return WriteSegmentsAgain(writer, count, countWritten, &again);
-}
-
-void
-SpdySession31::UpdateLocalStreamWindow(SpdyStream31 *stream,
- uint32_t bytes)
-{
- if (!stream) // this is ok - it means there was a data frame for a rst stream
- return;
-
- stream->DecrementLocalWindow(bytes);
-
- // If this data packet was not for a valid or live stream then there
- // is no reason to mess with the flow control
- if (stream->RecvdFin())
- return;
-
- // Don't necessarily ack every data packet. Only do it
- // after a significant amount of data.
- uint64_t unacked = stream->LocalUnAcked();
- int64_t localWindow = stream->LocalWindow();
-
- LOG3(("SpdySession31::UpdateLocalStreamWindow this=%p id=0x%X newbytes=%u "
- "unacked=%llu localWindow=%lld\n",
- this, stream->StreamID(), bytes, unacked, localWindow));
-
- if (!unacked)
- return;
-
- if ((unacked < kMinimumToAck) && (localWindow > kEmergencyWindowThreshold))
- return;
-
- if (!stream->HasSink()) {
- LOG3(("SpdySession31::UpdateLocalStreamWindow %p 0x%X Pushed Stream Has No Sink\n",
- this, stream->StreamID()));
- return;
- }
-
- // Generate window updates directly out of spdysession instead of the stream
- // in order to avoid queue delays in getting the 'ACK' out.
- uint32_t toack = (unacked <= 0x7fffffffU) ? unacked : 0x7fffffffU;
-
- LOG3(("SpdySession31::UpdateLocalStreamWindow Ack this=%p id=0x%X acksize=%d\n",
- this, stream->StreamID(), toack));
- stream->IncrementLocalWindow(toack);
-
- // room for this packet needs to be ensured before calling this function
- static const uint32_t dataLen = 8;
- char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
- mOutputQueueUsed += 8 + dataLen;
- MOZ_ASSERT(mOutputQueueUsed <= mOutputQueueSize);
-
- memset(packet, 0, 8 + dataLen);
- packet[0] = kFlag_Control;
- packet[1] = kVersion;
- packet[3] = CONTROL_TYPE_WINDOW_UPDATE;
- packet[7] = dataLen;
-
- uint32_t id = PR_htonl(stream->StreamID());
- memcpy(packet + 8, &id, 4);
- toack = PR_htonl(toack);
- memcpy(packet + 12, &toack, 4);
-
- LogIO(this, stream, "Stream Window Update", packet, 8 + dataLen);
- // dont flush here, this write can commonly be coalesced with a
- // session window update to immediately follow.
-}
-
-void
-SpdySession31::UpdateLocalSessionWindow(uint32_t bytes)
-{
- if (!bytes)
- return;
-
- mLocalSessionWindow -= bytes;
-
- LOG3(("SpdySession31::UpdateLocalSessionWindow this=%p newbytes=%u "
- "localWindow=%lld\n", this, bytes, mLocalSessionWindow));
-
- // Don't necessarily ack every data packet. Only do it
- // after a significant amount of data.
- if ((mLocalSessionWindow > (ASpdySession::kInitialRwin - kMinimumToAck)) &&
- (mLocalSessionWindow > kEmergencyWindowThreshold))
- return;
-
- // Only send max 31 bits of window updates at a time.
- uint64_t toack64 = ASpdySession::kInitialRwin - mLocalSessionWindow;
- uint32_t toack = (toack64 <= 0x7fffffffU) ? toack64 : 0x7fffffffU;
-
- LOG3(("SpdySession31::UpdateLocalSessionWindow Ack this=%p acksize=%u\n",
- this, toack));
- mLocalSessionWindow += toack;
-
- // room for this packet needs to be ensured before calling this function
- static const uint32_t dataLen = 8;
- char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
- mOutputQueueUsed += 8 + dataLen;
- MOZ_ASSERT(mOutputQueueUsed <= mOutputQueueSize);
-
- memset(packet, 0, 8 + dataLen);
- packet[0] = kFlag_Control;
- packet[1] = kVersion;
- packet[3] = CONTROL_TYPE_WINDOW_UPDATE;
- packet[7] = dataLen;
-
- // packet 8-11 is ID and left at 0 for session ID
- toack = PR_htonl(toack);
- memcpy(packet + 12, &toack, 4);
-
- LogIO(this, nullptr, "Session Window Update", packet, 8 + dataLen);
- // dont flush here, this write can commonly be coalesced with others
-}
-
-void
-SpdySession31::UpdateLocalRwin(SpdyStream31 *stream,
- uint32_t bytes)
-{
- // make sure there is room for 2 window updates even though
- // we may not generate any.
- EnsureBuffer(mOutputQueueBuffer, mOutputQueueUsed + (16 *2),
- mOutputQueueUsed, mOutputQueueSize);
-
- UpdateLocalStreamWindow(stream, bytes);
- UpdateLocalSessionWindow(bytes);
- FlushOutputQueue();
-}
-
-void
-SpdySession31::Close(nsresult aReason)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- if (mClosed)
- return;
-
- LOG3(("SpdySession31::Close %p %X", this, aReason));
-
- mClosed = true;
-
- Shutdown();
-
- mStreamIDHash.Clear();
- mStreamTransactionHash.Clear();
-
- uint32_t goAwayReason;
- if (NS_SUCCEEDED(aReason)) {
- goAwayReason = OK;
- } else if (aReason == NS_ERROR_ILLEGAL_VALUE) {
- goAwayReason = PROTOCOL_ERROR;
- } else {
- goAwayReason = INTERNAL_ERROR;
- }
- GenerateGoAway(goAwayReason);
- mConnection = nullptr;
- mSegmentReader = nullptr;
- mSegmentWriter = nullptr;
-}
-
-nsHttpConnectionInfo *
-SpdySession31::ConnectionInfo()
-{
- RefPtr<nsHttpConnectionInfo> ci;
- GetConnectionInfo(getter_AddRefs(ci));
- return ci.get();
-}
-
-void
-SpdySession31::CloseTransaction(nsAHttpTransaction *aTransaction,
- nsresult aResult)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- LOG3(("SpdySession31::CloseTransaction %p %p %x", this, aTransaction, aResult));
-
- // Generally this arrives as a cancel event from the connection manager.
-
- // need to find the stream and call CleanupStream() on it.
- SpdyStream31 *stream = mStreamTransactionHash.Get(aTransaction);
- if (!stream) {
- LOG3(("SpdySession31::CloseTransaction %p %p %x - not found.",
- this, aTransaction, aResult));
- return;
- }
- LOG3(("SpdySession31::CloseTransaction probably a cancel. "
- "this=%p, trans=%p, result=%x, streamID=0x%X stream=%p",
- this, aTransaction, aResult, stream->StreamID(), stream));
- CleanupStream(stream, aResult, RST_CANCEL);
- ResumeRecv();
-}
-
-//-----------------------------------------------------------------------------
-// nsAHttpSegmentReader
-//-----------------------------------------------------------------------------
-
-nsresult
-SpdySession31::OnReadSegment(const char *buf,
- uint32_t count,
- uint32_t *countRead)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- nsresult rv;
-
- // If we can release old queued data then we can try and write the new
- // data directly to the network without using the output queue at all
- if (mOutputQueueUsed)
- FlushOutputQueue();
-
- if (!mOutputQueueUsed && mSegmentReader) {
- // try and write directly without output queue
- rv = mSegmentReader->OnReadSegment(buf, count, countRead);
-
- if (rv == NS_BASE_STREAM_WOULD_BLOCK)
- *countRead = 0;
- else if (NS_FAILED(rv))
- return rv;
-
- if (*countRead < count) {
- uint32_t required = count - *countRead;
- // assuming a commitment() happened, this ensurebuffer is a nop
- // but just in case the queuesize is too small for the required data
- // call ensurebuffer().
- EnsureBuffer(mOutputQueueBuffer, required, 0, mOutputQueueSize);
- memcpy(mOutputQueueBuffer.get(), buf + *countRead, required);
- mOutputQueueUsed = required;
- }
-
- *countRead = count;
- return NS_OK;
- }
-
- // At this point we are going to buffer the new data in the output
- // queue if it fits. By coalescing multiple small submissions into one larger
- // buffer we can get larger writes out to the network later on.
-
- // This routine should not be allowed to fill up the output queue
- // all on its own - at least kQueueReserved bytes are always left
- // for other routines to use - but this is an all-or-nothing function,
- // so if it will not all fit just return WOULD_BLOCK
-
- if ((mOutputQueueUsed + count) > (mOutputQueueSize - kQueueReserved))
- return NS_BASE_STREAM_WOULD_BLOCK;
-
- memcpy(mOutputQueueBuffer.get() + mOutputQueueUsed, buf, count);
- mOutputQueueUsed += count;
- *countRead = count;
-
- FlushOutputQueue();
-
- return NS_OK;
-}
-
-nsresult
-SpdySession31::CommitToSegmentSize(uint32_t count, bool forceCommitment)
-{
- if (mOutputQueueUsed)
- FlushOutputQueue();
-
- // would there be enough room to buffer this if needed?
- if ((mOutputQueueUsed + count) <= (mOutputQueueSize - kQueueReserved))
- return NS_OK;
-
- // if we are using part of our buffers already, try again later unless
- // forceCommitment is set.
- if (mOutputQueueUsed && !forceCommitment)
- return NS_BASE_STREAM_WOULD_BLOCK;
-
- if (mOutputQueueUsed) {
- // normally we avoid the memmove of RealignOutputQueue, but we'll try
- // it if forceCommitment is set before growing the buffer.
- RealignOutputQueue();
-
- // is there enough room now?
- if ((mOutputQueueUsed + count) <= (mOutputQueueSize - kQueueReserved))
- return NS_OK;
- }
-
- // resize the buffers as needed
- EnsureBuffer(mOutputQueueBuffer, mOutputQueueUsed + count + kQueueReserved,
- mOutputQueueUsed, mOutputQueueSize);
-
- MOZ_ASSERT((mOutputQueueUsed + count) <= (mOutputQueueSize - kQueueReserved),
- "buffer not as large as expected");
-
- return NS_OK;
-}
-
-//-----------------------------------------------------------------------------
-// nsAHttpSegmentWriter
-//-----------------------------------------------------------------------------
-
-nsresult
-SpdySession31::OnWriteSegment(char *buf,
- uint32_t count,
- uint32_t *countWritten)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- nsresult rv;
-
- if (!mSegmentWriter) {
- // the only way this could happen would be if Close() were called on the
- // stack with WriteSegments()
- return NS_ERROR_FAILURE;
- }
-
- if (mDownstreamState == PROCESSING_DATA_FRAME) {
-
- if (mInputFrameDataLast &&
- mInputFrameDataRead == mInputFrameDataSize) {
- *countWritten = 0;
- SetNeedsCleanup();
- return NS_BASE_STREAM_CLOSED;
- }
-
- count = std::min(count, mInputFrameDataSize - mInputFrameDataRead);
- rv = NetworkRead(mSegmentWriter, buf, count, countWritten);
- if (NS_FAILED(rv))
- return rv;
-
- LogIO(this, mInputFrameDataStream, "Reading Data Frame",
- buf, *countWritten);
-
- mInputFrameDataRead += *countWritten;
-
- mInputFrameDataStream->UpdateTransportReadEvents(*countWritten);
- if ((mInputFrameDataRead == mInputFrameDataSize) && !mInputFrameDataLast)
- ResetDownstreamState();
-
- return rv;
- }
-
- if (mDownstreamState == PROCESSING_COMPLETE_HEADERS) {
-
- if (mFlatHTTPResponseHeaders.Length() == mFlatHTTPResponseHeadersOut &&
- mInputFrameDataLast) {
- *countWritten = 0;
- SetNeedsCleanup();
- return NS_BASE_STREAM_CLOSED;
- }
-
- count = std::min(count,
- mFlatHTTPResponseHeaders.Length() -
- mFlatHTTPResponseHeadersOut);
- memcpy(buf,
- mFlatHTTPResponseHeaders.get() + mFlatHTTPResponseHeadersOut,
- count);
- mFlatHTTPResponseHeadersOut += count;
- *countWritten = count;
-
- if (mFlatHTTPResponseHeaders.Length() == mFlatHTTPResponseHeadersOut) {
- if (mDataPending) {
- // Now ready to process data frames - pop PROCESING_DATA_FRAME back onto
- // the stack because receipt of that first data frame triggered the
- // response header processing
- mDataPending = false;
- ChangeDownstreamState(PROCESSING_DATA_FRAME);
- }
- else if (!mInputFrameDataLast) {
- // If more frames are expected in this stream, then reset the state so they can be
- // handled. Otherwise (e.g. a 0 length response with the fin on the SYN_REPLY)
- // stay in PROCESSING_COMPLETE_HEADERS state so the SetNeedsCleanup() code above can
- // cleanup the stream.
- ResetDownstreamState();
- }
- }
-
- return NS_OK;
- }
-
- return NS_ERROR_UNEXPECTED;
-}
-
-void
-SpdySession31::SetNeedsCleanup()
-{
- LOG3(("SpdySession31::SetNeedsCleanup %p - recorded downstream fin of "
- "stream %p 0x%X", this, mInputFrameDataStream,
- mInputFrameDataStream->StreamID()));
-
- // This will result in Close() being called
- MOZ_ASSERT(!mNeedsCleanup, "mNeedsCleanup unexpectedly set");
- mInputFrameDataStream->SetResponseIsComplete();
- mNeedsCleanup = mInputFrameDataStream;
- ResetDownstreamState();
-}
-
-void
-SpdySession31::ConnectPushedStream(SpdyStream31 *stream)
-{
- mReadyForRead.Push(stream);
- 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::CreateTunnel(nsHttpTransaction *trans,
- nsHttpConnectionInfo *ci,
- nsIInterfaceRequestor *aCallbacks)
-{
- LOG(("SpdySession31::CreateTunnel %p %p make new tunnel\n", this, trans));
- // The connect transaction will hold onto the underlying http
- // transaction so that an auth created by the connect can be mappped
- // to the correct security callbacks
-
- RefPtr<SpdyConnectTransaction> connectTrans =
- new SpdyConnectTransaction(ci, aCallbacks, trans->Caps(), trans, this);
- AddStream(connectTrans, nsISupportsPriority::PRIORITY_NORMAL, false, nullptr);
- SpdyStream31 *tunnel = mStreamTransactionHash.Get(connectTrans);
- MOZ_ASSERT(tunnel);
- RegisterTunnel(tunnel);
-}
-
-void
-SpdySession31::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
- nsIInterfaceRequestor *aCallbacks)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- nsHttpTransaction *trans = aHttpTransaction->QueryHttpTransaction();
- 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->SetTunnelProvider(this);
- trans->EnableKeepAlive();
-
- nsHttpConnectionInfo *ci = aHttpTransaction->ConnectionInfo();
- if (FindTunnelCount(ci) < gHttpHandler->MaxConnectionsPerOrigin()) {
- LOG3(("SpdySession31::DispatchOnTunnel %p create on new tunnel %s",
- this, ci->HashKey().get()));
- CreateTunnel(trans, ci, aCallbacks);
- } else {
- // requeue it. The connection manager is responsible for actually putting
- // this on the tunnel connection with the specific ci. If that can't
- // happen the cmgr checks with us via MaybeReTunnel() to see if it should
- // make a new tunnel or just wait longer.
- LOG3(("SpdySession31::DispatchOnTunnel %p trans=%p queue in connection manager",
- this, trans));
- gHttpHandler->InitiateTransaction(trans, trans->Priority());
- }
-}
-
-// From ASpdySession
-bool
-SpdySession31::MaybeReTunnel(nsAHttpTransaction *aHttpTransaction)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- nsHttpTransaction *trans = aHttpTransaction->QueryHttpTransaction();
- LOG(("SpdySession31::MaybeReTunnel %p trans=%p\n", this, trans));
- nsHttpConnectionInfo *ci = aHttpTransaction->ConnectionInfo();
- if (!trans || trans->TunnelProvider() != this) {
- // this isn't really one of our transactions.
- return false;
- }
-
- if (mClosed || mShouldGoAway) {
- LOG(("SpdySession31::MaybeReTunnel %p %p session closed - requeue\n", this, trans));
- trans->SetTunnelProvider(nullptr);
- gHttpHandler->InitiateTransaction(trans, trans->Priority());
- return true;
- }
-
- LOG(("SpdySession31::MaybeReTunnel %p %p count=%d limit %d\n",
- this, trans, FindTunnelCount(ci), gHttpHandler->MaxConnectionsPerOrigin()));
- if (FindTunnelCount(ci) >= gHttpHandler->MaxConnectionsPerOrigin()) {
- // patience - a tunnel will open up.
- return false;
- }
-
- LOG(("SpdySession31::MaybeReTunnel %p %p make new tunnel\n", this, trans));
- CreateTunnel(trans, ci, trans->SecurityCallbacks());
- return true;
-}
-
-nsresult
-SpdySession31::BufferOutput(const char *buf,
- uint32_t count,
- uint32_t *countRead)
-{
- nsAHttpSegmentReader *old = mSegmentReader;
- mSegmentReader = nullptr;
- nsresult rv = OnReadSegment(buf, count, countRead);
- mSegmentReader = old;
- return rv;
-}
-
-//-----------------------------------------------------------------------------
-// Modified methods of nsAHttpConnection
-//-----------------------------------------------------------------------------
-
-void
-SpdySession31::TransactionHasDataToWrite(nsAHttpTransaction *caller)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- LOG3(("SpdySession31::TransactionHasDataToWrite %p trans=%p", this, caller));
-
- // a trapped signal from the http transaction to the connection that
- // it is no longer blocked on read.
-
- SpdyStream31 *stream = mStreamTransactionHash.Get(caller);
- if (!stream || !VerifyStream(stream)) {
- LOG3(("SpdySession31::TransactionHasDataToWrite %p caller %p not found",
- this, caller));
- return;
- }
-
- LOG3(("SpdySession31::TransactionHasDataToWrite %p ID is 0x%X\n",
- this, stream->StreamID()));
-
- if (!mClosed) {
- mReadyForWrite.Push(stream);
- SetWriteCallbacks();
- } else {
- LOG3(("SpdySession31::TransactionHasDataToWrite %p closed so not setting Ready4Write\n",
- this));
- }
-
- // 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
-SpdySession31::TransactionHasDataToWrite(SpdyStream31 *stream)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- LOG3(("SpdySession31::TransactionHasDataToWrite %p stream=%p ID=%x",
- this, stream, stream->StreamID()));
-
- mReadyForWrite.Push(stream);
- SetWriteCallbacks();
- ForceSend();
-}
-
-bool
-SpdySession31::IsPersistent()
-{
- return true;
-}
-
-nsresult
-SpdySession31::TakeTransport(nsISocketTransport **,
- nsIAsyncInputStream **,
- nsIAsyncOutputStream **)
-{
- MOZ_ASSERT(false, "TakeTransport of SpdySession31");
- return NS_ERROR_UNEXPECTED;
-}
-
-already_AddRefed<nsHttpConnection>
-SpdySession31::TakeHttpConnection()
-{
- MOZ_ASSERT(false, "TakeHttpConnection of SpdySession31");
- return nullptr;
-}
-
-uint32_t
-SpdySession31::CancelPipeline(nsresult reason)
-{
- // we don't pipeline inside spdy, so this isn't an issue
- return 0;
-}
-
-nsAHttpTransaction::Classifier
-SpdySession31::Classification()
-{
- if (!mConnection)
- return nsAHttpTransaction::CLASS_GENERAL;
- return mConnection->Classification();
-}
-
-void
-SpdySession31::GetSecurityCallbacks(nsIInterfaceRequestor **aOut)
-{
- *aOut = nullptr;
-}
-
-//-----------------------------------------------------------------------------
-// unused methods of nsAHttpTransaction
-// We can be sure of this because SpdySession31 is only constructed in
-// nsHttpConnection and is never passed out of that object or a TLSFilterTransaction
-// TLS tunnel
-//-----------------------------------------------------------------------------
-
-void
-SpdySession31::SetConnection(nsAHttpConnection *)
-{
- // This is unexpected
- MOZ_ASSERT(false, "SpdySession31::SetConnection()");
-}
-
-void
-SpdySession31::SetProxyConnectFailed()
-{
- MOZ_ASSERT(false, "SpdySession31::SetProxyConnectFailed()");
-}
-
-bool
-SpdySession31::IsDone()
-{
- return !mStreamTransactionHash.Count();
-}
-
-nsresult
-SpdySession31::Status()
-{
- MOZ_ASSERT(false, "SpdySession31::Status()");
- return NS_ERROR_UNEXPECTED;
-}
-
-uint32_t
-SpdySession31::Caps()
-{
- MOZ_ASSERT(false, "SpdySession31::Caps()");
- return 0;
-}
-
-void
-SpdySession31::SetDNSWasRefreshed()
-{
-}
-
-uint64_t
-SpdySession31::Available()
-{
- MOZ_ASSERT(false, "SpdySession31::Available()");
- return 0;
-}
-
-nsHttpRequestHead *
-SpdySession31::RequestHead()
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- MOZ_ASSERT(false,
- "SpdySession31::RequestHead() "
- "should not be called after SPDY is setup");
- return nullptr;
-}
-
-uint32_t
-SpdySession31::Http1xTransactionCount()
-{
- return 0;
-}
-
-nsresult
-SpdySession31::TakeSubTransactions(
- nsTArray<RefPtr<nsAHttpTransaction> > &outTransactions)
-{
- // Generally this cannot be done with spdy as transactions are
- // started right away.
-
- LOG3(("SpdySession31::TakeSubTransactions %p\n", this));
-
- if (mConcurrentHighWater > 0)
- return NS_ERROR_ALREADY_OPENED;
-
- LOG3((" taking %d\n", mStreamTransactionHash.Count()));
-
- for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
- outTransactions.AppendElement(iter.Key());
-
- // Removing the stream from the hash will delete the stream and drop the
- // transaction reference the hash held.
- iter.Remove();
- }
- return NS_OK;
-}
-
-nsresult
-SpdySession31::AddTransaction(nsAHttpTransaction *)
-{
- // This API is meant for pipelining, SpdySession31's should be
- // extended with AddStream()
-
- MOZ_ASSERT(false,
- "SpdySession31::AddTransaction() should not be called");
-
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-uint32_t
-SpdySession31::PipelineDepth()
-{
- return IsDone() ? 0 : 1;
-}
-
-nsresult
-SpdySession31::SetPipelinePosition(int32_t position)
-{
- // This API is meant for pipelining, SpdySession31's should be
- // extended with AddStream()
-
- MOZ_ASSERT(false,
- "SpdySession31::SetPipelinePosition() should not be called");
-
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-int32_t
-SpdySession31::PipelinePosition()
-{
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-// Pass through methods of nsAHttpConnection
-//-----------------------------------------------------------------------------
-
-nsAHttpConnection *
-SpdySession31::Connection()
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- return mConnection;
-}
-
-nsresult
-SpdySession31::OnHeadersAvailable(nsAHttpTransaction *transaction,
- nsHttpRequestHead *requestHead,
- nsHttpResponseHead *responseHead,
- bool *reset)
-{
- return mConnection->OnHeadersAvailable(transaction,
- requestHead,
- responseHead,
- reset);
-}
-
-bool
-SpdySession31::IsReused()
-{
- return mConnection->IsReused();
-}
-
-nsresult
-SpdySession31::PushBack(const char *buf, uint32_t len)
-{
- return mConnection->PushBack(buf, len);
-}
-
-void
-SpdySession31::SendPing()
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- if (mPreviousUsed) {
- // alredy in progress, get out
- return;
- }
-
- mPingSentEpoch = PR_IntervalNow();
- if (!mPingSentEpoch) {
- mPingSentEpoch = 1; // avoid the 0 sentinel value
- }
- if (!mPingThreshold ||
- (mPingThreshold > gHttpHandler->NetworkChangedTimeout())) {
- mPreviousPingThreshold = mPingThreshold;
- mPreviousUsed = true;
- mPingThreshold = gHttpHandler->NetworkChangedTimeout();
- }
-
- GeneratePing(mNextPingID);
- mNextPingID += 2;
- ResumeRecv();
-
- gHttpHandler->ConnMgr()->ActivateTimeoutTick();
-}
-
-} // namespace net
-} // namespace mozilla
deleted file mode 100644
--- a/netwerk/protocol/http/SpdySession31.h
+++ /dev/null
@@ -1,422 +0,0 @@
-/* -*- 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 "mozilla/UniquePtr.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 nsHttpTransaction;
-
-class SpdySession31 final : public ASpdySession
- , public nsAHttpConnection
- , public nsAHttpSegmentReader
- , public nsAHttpSegmentWriter
-{
- ~SpdySession31();
-
-public:
- NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSAHTTPTRANSACTION
- NS_DECL_NSAHTTPCONNECTION(mConnection)
- NS_DECL_NSAHTTPSEGMENTREADER
- NS_DECL_NSAHTTPSEGMENTWRITER
-
- explicit SpdySession31(nsISocketTransport *);
-
- bool AddStream(nsAHttpTransaction *, int32_t,
- bool, nsIInterfaceRequestor *) override;
- bool CanReuse() override { return !mShouldGoAway && !mClosed; }
- bool RoomForMoreStreams() override;
-
- // When the connection is active this is called up to once every 1 second
- // return the interval (in seconds) that the connection next wants to
- // have this invoked. It might happen sooner depending on the needs of
- // other connections.
- uint32_t ReadTimeoutTick(PRIntervalTime now) override;
-
- // Idle time represents time since "goodput".. e.g. a data or header frame
- PRIntervalTime IdleTime() override;
-
- // 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 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 *);
-
- // 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 *) override;
-
- // a similar version for SpdyStream31
- void TransactionHasDataToWrite(SpdyStream31 *);
-
- // an overload of nsAHttpSegementReader
- virtual nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment) override;
- nsresult BufferOutput(const char *, uint32_t, uint32_t *);
- void FlushOutputQueue();
- uint32_t AmountOfOutputBuffered() { return mOutputQueueUsed - mOutputQueueSent; }
-
- uint32_t GetServerInitialStreamWindow() { return mServerInitialStreamWindow; }
-
- bool TryToActivate(SpdyStream31 *stream);
- void ConnectPushedStream(SpdyStream31 *stream);
- void DecrementConcurrent(SpdyStream31 *stream);
-
- uint64_t Serial() { return mSerial; }
-
- void PrintDiagnostics (nsCString &log) override;
-
- // 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; }
-
- void SendPing() override;
-
- bool MaybeReTunnel(nsAHttpTransaction *) override;
-
- // overload of nsAHttpTransaction
- nsresult ReadSegmentsAgain(nsAHttpSegmentReader *, uint32_t, uint32_t *, bool *) override final;
- nsresult WriteSegmentsAgain(nsAHttpSegmentWriter *, uint32_t , uint32_t *, bool *) override final;
-
-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 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 RealignOutputQueue();
-
- 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);
-
- bool RoomForMoreConcurrent();
- void IncrementConcurrent(SpdyStream31 *stream);
- void QueueStream(SpdyStream31 *stream);
-
- // 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 *);
-
- void Shutdown();
-
- // 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.
- RefPtr<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;
- UniquePtr<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;
- UniquePtr<char[]> mOutputQueueBuffer;
-
- PRIntervalTime mPingThreshold;
- PRIntervalTime mLastReadEpoch; // used for ping timeouts
- PRIntervalTime mLastDataReadEpoch; // used for IdleTime()
- PRIntervalTime mPingSentEpoch;
- uint32_t mNextPingID;
-
- PRIntervalTime mPreviousPingThreshold; // backup for the former value
- bool mPreviousUsed; // true when backup is used
-
- // 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;
-
-private:
-/// connect tunnels
- void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);
- void CreateTunnel(nsHttpTransaction *, nsHttpConnectionInfo *, nsIInterfaceRequestor *);
- void RegisterTunnel(SpdyStream31 *);
- void UnRegisterTunnel(SpdyStream31 *);
- uint32_t FindTunnelCount(nsHttpConnectionInfo *);
-
- nsDataHashtable<nsCStringHashKey, uint32_t> mTunnelHash;
-};
-
-} // namespace net
-} // namespace mozilla
-
-#endif // mozilla_net_SpdySession31_h
deleted file mode 100644
--- a/netwerk/protocol/http/SpdyStream31.cpp
+++ /dev/null
@@ -1,1695 +0,0 @@
-/* -*- 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"
-
-// Log on level :5, instead of default :4.
-#undef LOG
-#define LOG(args) LOG5(args)
-#undef LOG_ENABLED
-#define LOG_ENABLED() LOG5_ENABLED()
-
-#include "mozilla/Telemetry.h"
-#include "nsAlgorithm.h"
-#include "nsHttp.h"
-#include "nsHttpHandler.h"
-#include "nsHttpRequestHead.h"
-#include "nsISocketTransport.h"
-#include "nsISupportsPriority.h"
-#include "prnetdb.h"
-#include "SpdyPush31.h"
-#include "SpdySession31.h"
-#include "SpdyStream31.h"
-#include "TunnelUtils.h"
-
-#include <algorithm>
-
-namespace mozilla {
-namespace net {
-
-SpdyStream31::SpdyStream31(nsAHttpTransaction *httpTransaction,
- SpdySession31 *spdySession,
- int32_t priority)
- : mStreamID(0)
- , mSession(spdySession)
- , mUpstreamState(GENERATING_SYN_STREAM)
- , mRequestHeadersDone(0)
- , mSynFrameGenerated(0)
- , mSentFinOnData(0)
- , mQueued(0)
- , mTransaction(httpTransaction)
- , mSocketTransport(spdySession->SocketTransport())
- , mSegmentReader(nullptr)
- , mSegmentWriter(nullptr)
- , mChunkSize(spdySession->SendingChunkSize())
- , mRequestBlockedOnRead(0)
- , mRecvdFin(0)
- , mFullyOpen(0)
- , mSentWaitingFor(0)
- , mReceivedData(0)
- , mSetTCPSocketBuffer(0)
- , mCountAsActive(0)
- , mTxInlineFrameSize(SpdySession31::kDefaultBufferSize)
- , mTxInlineFrameUsed(0)
- , mTxStreamFrameSize(0)
- , mZlib(spdySession->UpstreamZlib())
- , mDecompressBufferSize(SpdySession31::kDefaultBufferSize)
- , mDecompressBufferUsed(0)
- , mDecompressedBytes(0)
- , mRequestBodyLenRemaining(0)
- , mPriority(priority)
- , mLocalUnacked(0)
- , mBlockedOnRwin(false)
- , mTotalSent(0)
- , mTotalRead(0)
- , mPushSource(nullptr)
- , mIsTunnel(false)
- , mPlainTextTunnel(false)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- LOG3(("SpdyStream31::SpdyStream31 %p", this));
-
- mRemoteWindow = spdySession->GetServerInitialStreamWindow();
- mLocalWindow = spdySession->PushAllowance();
-
- mTxInlineFrame = MakeUnique<uint8_t[]>(mTxInlineFrameSize);
- mDecompressBuffer = MakeUnique<char[]>(mDecompressBufferSize);
-}
-
-SpdyStream31::~SpdyStream31()
-{
- ClearTransactionsBlockedOnTunnel();
- mStreamID = SpdySession31::kDeadStreamID;
-}
-
-// ReadSegments() is used to write data down the socket. Generally, HTTP
-// request data is pulled from the approriate transaction and
-// converted to SPDY data. Sometimes control data like a window-update is
-// generated instead.
-
-nsresult
-SpdyStream31::ReadSegments(nsAHttpSegmentReader *reader,
- uint32_t count,
- uint32_t *countRead)
-{
- LOG3(("SpdyStream31 %p ReadSegments reader=%p count=%d state=%x",
- this, reader, count, mUpstreamState));
-
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- nsresult rv = NS_ERROR_UNEXPECTED;
- mRequestBlockedOnRead = 0;
-
- // avoid runt chunks if possible by anticipating
- // full data frames
- if (count > (mChunkSize + 8)) {
- uint32_t numchunks = count / (mChunkSize + 8);
- count = numchunks * (mChunkSize + 8);
- }
-
- switch (mUpstreamState) {
- case GENERATING_SYN_STREAM:
- case GENERATING_REQUEST_BODY:
- case SENDING_REQUEST_BODY:
- // Call into the HTTP Transaction to generate the HTTP request
- // stream. That stream will show up in OnReadSegment().
- mSegmentReader = reader;
- rv = mTransaction->ReadSegments(this, count, countRead);
- 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.
- // If not, mark the stream for callback when writing can proceed.
- if (NS_SUCCEEDED(rv) &&
- mUpstreamState == GENERATING_SYN_STREAM &&
- !mRequestHeadersDone)
- mSession->TransactionHasDataToWrite(this);
-
- // mTxinlineFrameUsed represents any queued un-sent frame. It might
- // be 0 if there is no such frame, which is not a gurantee that we
- // don't have more request body to send - just that any data that was
- // sent comprised a complete SPDY frame. Likewise, a non 0 value is
- // a queued, but complete, spdy frame length.
-
- // Mark that we are blocked on read if the http transaction needs to
- // provide more of the request message body and there is nothing queued
- // for writing
- if (rv == NS_BASE_STREAM_WOULD_BLOCK && !mTxInlineFrameUsed)
- mRequestBlockedOnRead = 1;
-
- // A transaction that had already generated its headers before it was
- // queued at the session level (due to concurrency concerns) may not call
- // onReadSegment off the ReadSegments() stack above.
- if (mUpstreamState == GENERATING_SYN_STREAM && NS_SUCCEEDED(rv)) {
- LOG3(("SpdyStream31 %p ReadSegments forcing OnReadSegment call\n", this));
- uint32_t wasted = 0;
- mSegmentReader = reader;
- OnReadSegment("", 0, &wasted);
- mSegmentReader = nullptr;
- }
-
- // If the sending flow control window is open (!mBlockedOnRwin) then
- // continue sending the request
- if (!mBlockedOnRwin && mSynFrameGenerated &&
- !mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
- LOG3(("SpdyStream31::ReadSegments %p 0x%X: Sending request data complete, "
- "mUpstreamState=%x finondata=%d",this, mStreamID,
- mUpstreamState, mSentFinOnData));
- if (mSentFinOnData) {
- ChangeState(UPSTREAM_COMPLETE);
- } else {
- GenerateDataFrameHeader(0, true);
- ChangeState(SENDING_FIN_STREAM);
- mSession->TransactionHasDataToWrite(this);
- rv = NS_BASE_STREAM_WOULD_BLOCK;
- }
- }
- break;
-
- case SENDING_FIN_STREAM:
- // We were trying to send the FIN-STREAM but were blocked from
- // sending it out - try again.
- if (!mSentFinOnData) {
- mSegmentReader = reader;
- rv = TransmitFrame(nullptr, nullptr, false);
- mSegmentReader = nullptr;
- MOZ_ASSERT(NS_FAILED(rv) || !mTxInlineFrameUsed,
- "Transmit Frame should be all or nothing");
- if (NS_SUCCEEDED(rv))
- ChangeState(UPSTREAM_COMPLETE);
- }
- else {
- rv = NS_OK;
- mTxInlineFrameUsed = 0; // cancel fin data packet
- ChangeState(UPSTREAM_COMPLETE);
- }
-
- *countRead = 0;
-
- // don't change OK to WOULD BLOCK. we are really done sending if OK
- break;
-
- case UPSTREAM_COMPLETE:
- *countRead = 0;
- rv = NS_OK;
- break;
-
- default:
- MOZ_ASSERT(false, "SpdyStream31::ReadSegments unknown state");
- break;
- }
-
- return rv;
-}
-
-// WriteSegments() is used to read data off the socket. Generally this is
-// just a call through to the associated nsHttpTransaction for this stream
-// for the remaining data bytes indicated by the current DATA frame.
-
-nsresult
-SpdyStream31::WriteSegments(nsAHttpSegmentWriter *writer,
- uint32_t count,
- uint32_t *countWritten)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- MOZ_ASSERT(!mSegmentWriter, "segment writer in progress");
-
- LOG3(("SpdyStream31::WriteSegments %p count=%d state=%x",
- this, count, mUpstreamState));
-
- mSegmentWriter = writer;
- nsresult rv = mTransaction->WriteSegments(this, count, countWritten);
- mSegmentWriter = nullptr;
-
- return rv;
-}
-
-bool
-SpdyStream31::ChannelPipeFull()
-{
- nsHttpTransaction *trans = mTransaction ? mTransaction->QueryHttpTransaction() : nullptr;
- return trans ? trans->ChannelPipeFull() : false;
-}
-
-void
-SpdyStream31::CreatePushHashKey(const nsCString &scheme,
- const nsCString &hostHeader,
- uint64_t serial,
- const nsCSubstring &pathInfo,
- nsCString &outOrigin,
- nsCString &outKey)
-{
- outOrigin = scheme;
- outOrigin.AppendLiteral("://");
- outOrigin.Append(hostHeader);
-
- outKey = outOrigin;
- outKey.AppendLiteral("/[spdy3_1.");
- outKey.AppendInt(serial);
- outKey.Append(']');
- outKey.Append(pathInfo);
-}
-
-
-nsresult
-SpdyStream31::ParseHttpRequestHeaders(const char *buf,
- uint32_t avail,
- uint32_t *countUsed)
-{
- // Returns NS_OK even if the headers are incomplete
- // set mRequestHeadersDone flag if they are complete
-
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- MOZ_ASSERT(mUpstreamState == GENERATING_SYN_STREAM);
- MOZ_ASSERT(!mRequestHeadersDone);
-
- LOG3(("SpdyStream31::ParseHttpRequestHeaders %p avail=%d state=%x",
- this, avail, mUpstreamState));
-
- mFlatHttpRequestHeaders.Append(buf, avail);
-
- // We can use the simple double crlf because firefox is the
- // only client we are parsing
- int32_t endHeader = mFlatHttpRequestHeaders.Find("\r\n\r\n");
-
- if (endHeader == kNotFound) {
- // We don't have all the headers yet
- LOG3(("SpdyStream31::ParseHttpRequestHeaders %p "
- "Need more header bytes. Len = %d",
- this, mFlatHttpRequestHeaders.Length()));
- *countUsed = avail;
- return NS_OK;
- }
-
- // We have recvd all the headers, trim the local
- // buffer of the final empty line, and set countUsed to reflect
- // the whole header has been consumed.
- uint32_t oldLen = mFlatHttpRequestHeaders.Length();
- mFlatHttpRequestHeaders.SetLength(endHeader + 2);
- *countUsed = avail - (oldLen - endHeader) + 4;
- mRequestHeadersDone = 1;
-
- nsAutoCString hostHeader;
- nsAutoCString hashkey;
- mTransaction->RequestHead()->GetHeader(nsHttp::Host, hostHeader);
- nsAutoCString requestURI;
- mTransaction->RequestHead()->RequestURI(requestURI);
- CreatePushHashKey(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"),
- hostHeader, mSession->Serial(),
- requestURI,
- mOrigin, hashkey);
-
- // check the push cache for GET
- if (mTransaction->RequestHead()->IsGet()) {
- // from :scheme, :host, :path
- nsIRequestContext *requestContext = mTransaction->RequestContext();
- SpdyPushCache *cache = nullptr;
- if (requestContext)
- requestContext->GetSpdyPushCache(&cache);
-
- SpdyPushedStream31 *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->RemovePushedStreamSpdy31(hashkey);
-
- if (pushedStream) {
- LOG3(("Pushed Stream Match located id=0x%X key=%s\n",
- pushedStream->StreamID(), hashkey.get()));
- pushedStream->SetConsumerStream(this);
- mPushSource = pushedStream;
- mSentFinOnData = 1;
-
- // This stream has been activated (and thus counts against the concurrency
- // limit intentionally), but will not be registered via
- // RegisterStreamID (below) because of the push match. Therefore the
- // concurrency sempahore needs to be balanced.
- mSession->DecrementConcurrent(this);
-
- // There is probably pushed data buffered so trigger a read manually
- // as we can't rely on future network events to do it
- mSession->ConnectPushedStream(this);
- mSynFrameGenerated = 1;
- return NS_OK;
- }
- }
- return NS_OK;
-}
-
-nsresult
-SpdyStream31::GenerateSynFrame()
-{
- // It is now OK to assign a streamID that we are assured will
- // be monotonically increasing amongst syn-streams on this
- // session
- mStreamID = mSession->RegisterStreamID(this);
- MOZ_ASSERT(mStreamID & 1, "Spdy Stream Channel ID must be odd");
- MOZ_ASSERT(!mSynFrameGenerated);
-
- mSynFrameGenerated = 1;
-
- if (mStreamID >= 0x80000000) {
- // streamID must fit in 31 bits. This is theoretically possible
- // because stream ID assignment is asynchronous to stream creation
- // because of the protocol requirement that the ID in syn-stream
- // be monotonically increasing. In reality this is really not possible
- // because new streams stop being added to a session with 0x10000000 / 2
- // IDs still available and no race condition is going to bridge that gap,
- // so we can be comfortable on just erroring out for correctness in that
- // case.
- LOG3(("Stream assigned out of range ID: 0x%X", mStreamID));
- return NS_ERROR_UNEXPECTED;
- }
-
- // Now we need to convert the flat http headers into a set
- // of SPDY headers.. writing to mTxInlineFrame{sz}
-
- mTxInlineFrame[0] = SpdySession31::kFlag_Control;
- mTxInlineFrame[1] = SpdySession31::kVersion;
- mTxInlineFrame[2] = 0;
- mTxInlineFrame[3] = SpdySession31::CONTROL_TYPE_SYN_STREAM;
- // 4 to 7 are length and flags, we'll fill that in later
-
- uint32_t networkOrderID = PR_htonl(mStreamID);
- memcpy(&mTxInlineFrame[8], &networkOrderID, 4);
-
- // this is the associated-to field, which is not used sending
- // from the client in the http binding
- memset (&mTxInlineFrame[12], 0, 4);
-
- // Priority flags are the E0 mask of byte 16.
- // 0 is highest priority, 7 is lowest.
- // The other 5 bits of byte 16 are unused.
-
- if (mPriority >= nsISupportsPriority::PRIORITY_LOWEST)
- mTxInlineFrame[16] = 7 << 5;
- else if (mPriority <= nsISupportsPriority::PRIORITY_HIGHEST)
- mTxInlineFrame[16] = 0 << 5;
- else {
- // The priority mapping relies on the unfiltered ranged to be
- // between -20 .. +20
- PR_STATIC_ASSERT(nsISupportsPriority::PRIORITY_LOWEST == 20);
- PR_STATIC_ASSERT(nsISupportsPriority::PRIORITY_HIGHEST == -20);
-
- // Add one to the priority so that values such as -10 and -11
- // get different spdy priorities - this appears to be an important
- // breaking line in the priorities content assigns to
- // transactions.
- uint8_t calculatedPriority = 3 + ((mPriority + 1) / 5);
- MOZ_ASSERT (!(calculatedPriority & 0xf8),
- "Calculated Priority Out Of Range");
- mTxInlineFrame[16] = calculatedPriority << 5;
- }
-
- // The client cert "slot". Right now we don't send client certs
- mTxInlineFrame[17] = 0;
-
- nsCString versionHeader;
- if (mTransaction->RequestHead()->Version() == NS_HTTP_VERSION_1_1)
- versionHeader = NS_LITERAL_CSTRING("HTTP/1.1");
- else
- versionHeader = NS_LITERAL_CSTRING("HTTP/1.0");
-
- // use mRequestHead() to get a sense of how big to make the hash,
- // even though we are parsing the actual text stream because
- // it is legit to append headers.
- nsClassHashtable<nsCStringHashKey, nsCString>
- hdrHash(mTransaction->RequestHead()->HeaderCount());
-
- const char *beginBuffer = mFlatHttpRequestHeaders.BeginReading();
-
- // need to hash all the headers together to remove duplicates, special
- // headers, etc..
-
- int32_t crlfIndex = mFlatHttpRequestHeaders.Find("\r\n");
- while (true) {
- int32_t startIndex = crlfIndex + 2;
-
- crlfIndex = mFlatHttpRequestHeaders.Find("\r\n", false, startIndex);
- if (crlfIndex == -1)
- break;
-
- int32_t colonIndex = mFlatHttpRequestHeaders.Find(":", false, startIndex,
- crlfIndex - startIndex);
- if (colonIndex == -1)
- break;
-
- nsDependentCSubstring name = Substring(beginBuffer + startIndex,
- beginBuffer + colonIndex);
- // all header names are lower case in spdy
- ToLowerCase(name);
-
- // exclusions.. mostly from 3.2.1
- // we send accept-encoding here because we often include brotli
- // in that list which is greater than the implied accept-encoding: gzip
- if (name.EqualsLiteral("connection") ||
- name.EqualsLiteral("keep-alive") ||
- name.EqualsLiteral("host") ||
- name.EqualsLiteral("te") ||
- name.EqualsLiteral("transfer-encoding"))
- continue;
-
- nsCString *val = hdrHash.Get(name);
- if (!val) {
- val = new nsCString();
- hdrHash.Put(name, val);
- }
-
- int32_t valueIndex = colonIndex + 1;
- while (valueIndex < crlfIndex && beginBuffer[valueIndex] == ' ')
- ++valueIndex;
-
- nsDependentCSubstring v = Substring(beginBuffer + valueIndex,
- beginBuffer + crlfIndex);
- if (!val->IsEmpty())
- val->Append(static_cast<char>(0));
- val->Append(v);
-
- if (name.EqualsLiteral("content-length")) {
- int64_t len;
- if (nsHttp::ParseInt64(val->get(), nullptr, &len))
- mRequestBodyLenRemaining = len;
- }
- }
-
- mTxInlineFrameUsed = 18;
-
- // Do not naively log the request headers here beacuse they might
- // contain auth. The http transaction already logs the sanitized request
- // headers at this same level so it is not necessary to do so here.
-
- nsAutoCString method;
- mTransaction->RequestHead()->Method(method);
- LOG3(("Stream method %p 0x%X %s\n", this, mStreamID, method.get()));
-
- // The header block length
- uint16_t count = hdrHash.Count() + 4; /* :method, :path, :version, :host */
- if (mTransaction->RequestHead()->IsConnect()) {
- mRequestBodyLenRemaining = 0x0fffffffffffffffULL;
- } else {
- ++count; // :scheme used if not connect
- }
- CompressToFrame(count);
-
- // :method, :path, :version comprise a HTTP/1 request line, so send those first
- // to make life easy for any gateways
- CompressToFrame(NS_LITERAL_CSTRING(":method"));
- CompressToFrame(method);
-
- CompressToFrame(NS_LITERAL_CSTRING(":path"));
- if (!mTransaction->RequestHead()->IsConnect()) {
- nsAutoCString path;
- mTransaction->RequestHead()->Path(path);
- CompressToFrame(path);
- } 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->GetOrigin();
- route.Append(':');
- route.AppendInt(ci->OriginPort());
- CompressToFrame(route);
- }
-
- CompressToFrame(NS_LITERAL_CSTRING(":version"));
- CompressToFrame(versionHeader);
-
- nsAutoCString hostHeader;
- mTransaction->RequestHead()->GetHeader(nsHttp::Host, hostHeader);
- CompressToFrame(NS_LITERAL_CSTRING(":host"));
- CompressToFrame(hostHeader);
-
- if (!mTransaction->RequestHead()->IsConnect()) {
- // no :scheme with connect
- CompressToFrame(NS_LITERAL_CSTRING(":scheme"));
- CompressToFrame(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"));
- }
-
- for (auto iter = hdrHash.Iter(); !iter.Done(); iter.Next()) {
- CompressToFrame(iter.Key());
- CompressToFrame(iter.Data().get());
- }
- CompressFlushFrame();
-
- // 4 to 7 are length and flags, which we can now fill in
- (reinterpret_cast<uint32_t *>(mTxInlineFrame.get()))[1] =
- PR_htonl(mTxInlineFrameUsed - 8);
-
- MOZ_ASSERT(!mTxInlineFrame[4], "Size greater than 24 bits");
-
- // Determine whether to put the fin bit on the syn stream frame or whether
- // to wait for a data packet to put it on.
-
- if (mTransaction->RequestHead()->IsGet() ||
- mTransaction->RequestHead()->IsHead()) {
- // for GET and HEAD place the fin bit right on the
- // syn stream packet
-
- mSentFinOnData = 1;
- mTxInlineFrame[4] = SpdySession31::kFlag_Data_FIN;
- }
- else if (mTransaction->RequestHead()->IsPost() ||
- mTransaction->RequestHead()->IsPut() ||
- mTransaction->RequestHead()->IsConnect() ||
- mTransaction->RequestHead()->IsOptions()) {
- // place fin in a data frame even for 0 length messages, I've seen
- // the google gateway be unhappy with fin-on-syn for 0 length POST
- }
- else if (!mRequestBodyLenRemaining) {
- // for other HTTP extension methods, rely on the content-length
- // to determine whether or not to put fin on syn
- mSentFinOnData = 1;
- mTxInlineFrame[4] = SpdySession31::kFlag_Data_FIN;
- }
-
- Telemetry::Accumulate(Telemetry::SPDY_SYN_SIZE, mTxInlineFrameUsed - 18);
-
- nsAutoCString requestURI;
- mTransaction->RequestHead()->RequestURI(requestURI);
- // The size of the input headers is approximate
- uint32_t ratio =
- (mTxInlineFrameUsed - 18) * 100 /
- (11 + requestURI.Length() + mFlatHttpRequestHeaders.Length());
-
- Telemetry::Accumulate(Telemetry::SPDY_SYN_RATIO, ratio);
- return NS_OK;
-}
-
-void
-SpdyStream31::AdjustInitialWindow()
-{
- MOZ_ASSERT(mSession->PushAllowance() <= ASpdySession::kInitialRwin);
-
- // The session initial_window is sized for serverpushed streams. When we
- // generate a client pulled stream we want to adjust the initial window
- // to a huge value in a pipeline with that SYN_STREAM.
-
- // >0 even numbered IDs are pushed streams.
- // odd numbered IDs are pulled streams.
- // 0 is the sink for a pushed stream.
- SpdyStream31 *stream = this;
- if (!mStreamID) {
- MOZ_ASSERT(mPushSource);
- if (!mPushSource)
- return;
- stream = mPushSource;
- MOZ_ASSERT(stream->mStreamID);
- MOZ_ASSERT(!(stream->mStreamID & 1)); // is a push stream
-
- // If the pushed stream has sent a FIN, there is no reason to update
- // the window
- if (stream->RecvdFin())
- return;
- }
-
- // For server pushes we also want to include in the ack any data that has been
- // buffered but unacknowledged.
-
- // mLocalUnacked is technically 64 bits, but because it can never grow larger than
- // our window size (which is closer to 29bits max) we know it fits comfortably in 32.
- // However we don't really enforce that, and track it as a 64 so that broken senders
- // can still interoperate. That means we have to be careful with this calculation.
- uint64_t toack64 = (ASpdySession::kInitialRwin - mSession->PushAllowance()) +
- stream->mLocalUnacked;
- stream->mLocalUnacked = 0;
- if (toack64 > 0x7fffffff) {
- stream->mLocalUnacked = toack64 - 0x7fffffff;
- toack64 = 0x7fffffff;
- }
- uint32_t toack = static_cast<uint32_t>(toack64);
- if (!toack)
- return;
- toack = PR_htonl(toack);
-
- EnsureBuffer(mTxInlineFrame, mTxInlineFrameUsed + 16,
- mTxInlineFrameUsed, mTxInlineFrameSize);
-
- unsigned char *packet = mTxInlineFrame.get() + mTxInlineFrameUsed;
- mTxInlineFrameUsed += 16;
-
- memset(packet, 0, 8);
- packet[0] = SpdySession31::kFlag_Control;
- packet[1] = SpdySession31::kVersion;
- packet[3] = SpdySession31::CONTROL_TYPE_WINDOW_UPDATE;
- packet[7] = 8; // 8 data bytes after 8 byte header
-
- uint32_t id = PR_htonl(stream->mStreamID);
- memcpy(packet + 8, &id, 4);
- memcpy(packet + 12, &toack, 4);
-
- stream->mLocalWindow += PR_ntohl(toack);
- LOG3(("AdjustInitialwindow %p 0x%X %u\n",
- this, stream->mStreamID, PR_ntohl(toack)));
-}
-
-void
-SpdyStream31::UpdateTransportReadEvents(uint32_t count)
-{
- mTotalRead += count;
- if (!mSocketTransport) {
- return;
- }
-
- mTransaction->OnTransportStatus(mSocketTransport,
- NS_NET_STATUS_RECEIVING_FROM,
- mTotalRead);
-}
-
-void
-SpdyStream31::UpdateTransportSendEvents(uint32_t count)
-{
- mTotalSent += count;
-
- // normally on non-windows platform we use TCP autotuning for
- // the socket buffers, and this works well (managing enough
- // buffers for BDP while conserving memory) for HTTP even when
- // it creates really deep queues. However this 'buffer bloat' is
- // a problem for spdy because it ruins the low latency properties
- // necessary for PING and cancel to work meaningfully.
- //
- // If this stream represents a large upload, disable autotuning for
- // the session and cap the send buffers by default at 128KB.
- // (10Mbit/sec @ 100ms)
- //
- uint32_t bufferSize = gHttpHandler->SpdySendBufferSize();
- if ((mTotalSent > bufferSize) && !mSetTCPSocketBuffer) {
- mSetTCPSocketBuffer = 1;
- mSocketTransport->SetSendBufferSize(bufferSize);
- }
-
- if (mUpstreamState != SENDING_FIN_STREAM)
- mTransaction->OnTransportStatus(mSocketTransport,
- NS_NET_STATUS_SENDING_TO,
- mTotalSent);
-
- if (!mSentWaitingFor && !mRequestBodyLenRemaining) {
- mSentWaitingFor = 1;
- mTransaction->OnTransportStatus(mSocketTransport,
- NS_NET_STATUS_WAITING_FOR,
- 0);
- }
-}
-
-nsresult
-SpdyStream31::TransmitFrame(const char *buf,
- uint32_t *countUsed,
- bool forceCommitment)
-{
- // If TransmitFrame returns SUCCESS than all the data is sent (or at least
- // buffered at the session level), if it returns WOULD_BLOCK then none of
- // the data is sent.
-
- // You can call this function with no data and no out parameter in order to
- // flush internal buffers that were previously blocked on writing. You can
- // of course feed new data to it as well.
-
- LOG3(("SpdyStream31::TransmitFrame %p inline=%d stream=%d",
- this, mTxInlineFrameUsed, mTxStreamFrameSize));
- if (countUsed)
- *countUsed = 0;
-
- if (!mTxInlineFrameUsed) {
- MOZ_ASSERT(!buf);
- return NS_OK;
- }
-
- MOZ_ASSERT(mTxInlineFrameUsed, "empty stream frame in transmit");
- MOZ_ASSERT(mSegmentReader, "TransmitFrame with null mSegmentReader");
- MOZ_ASSERT((buf && countUsed) || (!buf && !countUsed),
- "TransmitFrame arguments inconsistent");
-
- uint32_t transmittedCount;
- nsresult rv;
-
- // In the (relatively common) event that we have a small amount of data
- // split between the inlineframe and the streamframe, then move the stream
- // data into the inlineframe via copy in order to coalesce into one write.
- // Given the interaction with ssl this is worth the small copy cost.
- if (mTxStreamFrameSize && mTxInlineFrameUsed &&
- mTxStreamFrameSize < SpdySession31::kDefaultBufferSize &&
- mTxInlineFrameUsed + mTxStreamFrameSize < mTxInlineFrameSize) {
- LOG3(("Coalesce Transmit"));
- memcpy (&mTxInlineFrame[mTxInlineFrameUsed],
- buf, mTxStreamFrameSize);
- if (countUsed)
- *countUsed += mTxStreamFrameSize;
- mTxInlineFrameUsed += mTxStreamFrameSize;
- mTxStreamFrameSize = 0;
- }
-
- rv =
- mSegmentReader->CommitToSegmentSize(mTxStreamFrameSize + mTxInlineFrameUsed,
- forceCommitment);
-
- if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
- MOZ_ASSERT(!forceCommitment, "forceCommitment with WOULD_BLOCK");
- mSession->TransactionHasDataToWrite(this);
- }
- if (NS_FAILED(rv)) // this will include WOULD_BLOCK
- return rv;
-
- // This function calls mSegmentReader->OnReadSegment to report the actual SPDY
- // bytes through to the SpdySession31 and then the HttpConnection which calls
- // the socket write function. It will accept all of the inline and stream
- // data because of the above 'commitment' even if it has to buffer
-
- rv = mSession->BufferOutput(reinterpret_cast<char*>(mTxInlineFrame.get()),
- mTxInlineFrameUsed,
- &transmittedCount);
- LOG3(("SpdyStream31::TransmitFrame for inline BufferOutput session=%p "
- "stream=%p result %x len=%d",
- mSession, this, rv, transmittedCount));
-
- MOZ_ASSERT(rv != NS_BASE_STREAM_WOULD_BLOCK,
- "inconsistent inline commitment result");
-
- if (NS_FAILED(rv))
- return rv;
-
- MOZ_ASSERT(transmittedCount == mTxInlineFrameUsed,
- "inconsistent inline commitment count");
-
- SpdySession31::LogIO(mSession, this, "Writing from Inline Buffer",
- reinterpret_cast<char*>(mTxInlineFrame.get()),
- transmittedCount);
-
- if (mTxStreamFrameSize) {
- if (!buf) {
- // this cannot happen
- MOZ_ASSERT(false, "Stream transmit with null buf argument to "
- "TransmitFrame()");
- LOG(("Stream transmit with null buf argument to TransmitFrame()\n"));
- return NS_ERROR_UNEXPECTED;
- }
-
- // If there is already data buffered, just add to that to form
- // a single TLS Application Data Record - otherwise skip the memcpy
- if (mSession->AmountOfOutputBuffered()) {
- rv = mSession->BufferOutput(buf, mTxStreamFrameSize,
- &transmittedCount);
- } else {
- rv = mSession->OnReadSegment(buf, mTxStreamFrameSize,
- &transmittedCount);
- }
-
- LOG3(("SpdyStream31::TransmitFrame for regular session=%p "
- "stream=%p result %x len=%d",
- mSession, this, rv, transmittedCount));
-
- MOZ_ASSERT(rv != NS_BASE_STREAM_WOULD_BLOCK,
- "inconsistent stream commitment result");
-
- if (NS_FAILED(rv))
- return rv;
-
- MOZ_ASSERT(transmittedCount == mTxStreamFrameSize,
- "inconsistent stream commitment count");
-
- SpdySession31::LogIO(mSession, this, "Writing from Transaction Buffer",
- buf, transmittedCount);
-
- *countUsed += mTxStreamFrameSize;
- }
-
- mSession->FlushOutputQueue();
-
- // calling this will trigger waiting_for if mRequestBodyLenRemaining is 0
- UpdateTransportSendEvents(mTxInlineFrameUsed + mTxStreamFrameSize);
-
- mTxInlineFrameUsed = 0;
- mTxStreamFrameSize = 0;
-
- return NS_OK;
-}
-
-void
-SpdyStream31::ChangeState(enum stateType newState)
-{
- LOG3(("SpdyStream31::ChangeState() %p from %X to %X",
- this, mUpstreamState, newState));
- mUpstreamState = newState;
- return;
-}
-
-void
-SpdyStream31::GenerateDataFrameHeader(uint32_t dataLength, bool lastFrame)
-{
- LOG3(("SpdyStream31::GenerateDataFrameHeader %p len=%d last=%d id=0x%X\n",
- this, dataLength, lastFrame, mStreamID));
-
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- MOZ_ASSERT(!mTxInlineFrameUsed, "inline frame not empty");
- MOZ_ASSERT(!mTxStreamFrameSize, "stream frame not empty");
- MOZ_ASSERT(!(dataLength & 0xff000000), "datalength > 24 bits");
- MOZ_ASSERT(mStreamID != 0);
- MOZ_ASSERT(mStreamID != SpdySession31::kDeadStreamID);
-
- (reinterpret_cast<uint32_t *>(mTxInlineFrame.get()))[0] = PR_htonl(mStreamID);
- (reinterpret_cast<uint32_t *>(mTxInlineFrame.get()))[1] =
- PR_htonl(dataLength);
-
- MOZ_ASSERT(!(mTxInlineFrame[0] & 0x80), "control bit set unexpectedly");
- MOZ_ASSERT(!mTxInlineFrame[4], "flag bits set unexpectedly");
-
- mTxInlineFrameUsed = 8;
- mTxStreamFrameSize = dataLength;
-
- if (lastFrame) {
- mTxInlineFrame[4] |= SpdySession31::kFlag_Data_FIN;
- if (dataLength)
- mSentFinOnData = 1;
- }
-}
-
-void
-SpdyStream31::CompressToFrame(const nsACString &str)
-{
- CompressToFrame(str.BeginReading(), str.Length());
-}
-
-void
-SpdyStream31::CompressToFrame(const nsACString *str)
-{
- CompressToFrame(str->BeginReading(), str->Length());
-}
-
-// Dictionary taken from
-// http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3
-
-const unsigned char SpdyStream31::kDictionary[] = {
- 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // - - - - o p t i
- 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // o n s - - - - h
- 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // e a d - - - - p
- 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // o s t - - - - p
- 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // u t - - - - d e
- 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // l e t e - - - -
- 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // t r a c e - - -
- 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // - a c c e p t -
- 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
- 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t - c h a r s e
- 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t - - - - a c c
- 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e p t - e n c o
- 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // d i n g - - - -
- 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // a c c e p t - l
- 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // a n g u a g e -
- 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
- 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t - r a n g e s
- 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // - - - - a g e -
- 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // - - - a l l o w
- 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // - - - - a u t h
- 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // o r i z a t i o
- 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n - - - - c a c
- 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // h e - c o n t r
- 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // o l - - - - c o
- 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // n n e c t i o n
- 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
- 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // e n t - b a s e
- 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
- 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e n t - e n c o
- 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // d i n g - - - -
- 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // c o n t e n t -
- 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // l a n g u a g e
- 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
- 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // e n t - l e n g
- 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // t h - - - - c o
- 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // n t e n t - l o
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // c a t i o n - -
- 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
- 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t - m d 5 - - -
- 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // - c o n t e n t
- 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // - r a n g e - -
- 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
- 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t - t y p e - -
- 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // - - d a t e - -
- 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // - - e t a g - -
- 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // - - e x p e c t
- 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // - - - - e x p i
- 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // r e s - - - - f
- 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // r o m - - - - h
- 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // o s t - - - - i
- 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f - m a t c h -
- 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // - - - i f - m o
- 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // d i f i e d - s
- 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // i n c e - - - -
- 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // i f - n o n e -
- 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // m a t c h - - -
- 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // - i f - r a n g
- 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e - - - - i f -
- 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // u n m o d i f i
- 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // e d - s i n c e
- 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // - - - - l a s t
- 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // - m o d i f i e
- 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d - - - - l o c
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // a t i o n - - -
- 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // - m a x - f o r
- 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // w a r d s - - -
- 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // - p r a g m a -
- 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // - - - p r o x y
- 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // - a u t h e n t
- 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // i c a t e - - -
- 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // - p r o x y - a
- 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // u t h o r i z a
- 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // t i o n - - - -
- 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // r a n g e - - -
- 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // - r e f e r e r
- 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // - - - - r e t r
- 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y - a f t e r -
- 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // - - - s e r v e
- 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r - - - - t e -
- 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // - - - t r a i l
- 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // e r - - - - t r
- 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // a n s f e r - e
- 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // n c o d i n g -
- 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // - - - u p g r a
- 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // d e - - - - u s
- 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // e r - a g e n t
- 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // - - - - v a r y
- 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // - - - - v i a -
- 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // - - - w a r n i
- 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // n g - - - - w w
- 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w - a u t h e n
- 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // t i c a t e - -
- 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // - - m e t h o d
- 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // - - - - g e t -
- 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // - - - s t a t u
- 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s - - - - 2 0 0
- 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // - O K - - - - v
- 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // e r s i o n - -
- 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // - - H T T P - 1
- 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // - 1 - - - - u r
- 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l - - - - p u b
- 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // l i c - - - - s
- 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // e t - c o o k i
- 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e - - - - k e e
- 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p - a l i v e -
- 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // - - - o r i g i
- 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n 1 0 0 1 0 1 2
- 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 0 1 2 0 2 2 0 5
- 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 2 0 6 3 0 0 3 0
- 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 2 3 0 3 3 0 4 3
- 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 0 5 3 0 6 3 0 7
- 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 4 0 2 4 0 5 4 0
- 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 6 4 0 7 4 0 8 4
- 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 0 9 4 1 0 4 1 1
- 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 4 1 2 4 1 3 4 1
- 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 4 4 1 5 4 1 6 4
- 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 1 7 5 0 2 5 0 4
- 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 5 0 5 2 0 3 - N
- 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // o n - A u t h o
- 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // r i t a t i v e
- 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // - I n f o r m a
- 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // t i o n 2 0 4 -
- 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // N o - C o n t e
- 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // n t 3 0 1 - M o
- 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // v e d - P e r m
- 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // a n e n t l y 4
- 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 0 0 - B a d - R
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // e q u e s t 4 0
- 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1 - U n a u t h
- 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // o r i z e d 4 0
- 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3 - F o r b i d
- 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // d e n 4 0 4 - N
- 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // o t - F o u n d
- 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 5 0 0 - I n t e
- 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // r n a l - S e r
- 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // v e r - E r r o
- 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r 5 0 1 - N o t
- 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // - I m p l e m e
- 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // n t e d 5 0 3 -
- 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // S e r v i c e -
- 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // U n a v a i l a
- 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // b l e J a n - F
- 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // e b - M a r - A
- 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // p r - M a y - J
- 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // u n - J u l - A
- 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // u g - S e p t -
- 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // O c t - N o v -
- 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // D e c - 0 0 - 0
- 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0 - 0 0 - M o n
- 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // - - T u e - - W
- 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // e d - - T h u -
- 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // - F r i - - S a
- 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t - - S u n - -
- 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // G M T c h u n k
- 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // e d - t e x t -
- 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // h t m l - i m a
- 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // g e - p n g - i
- 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // m a g e - j p g
- 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // - i m a g e - g
- 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // i f - a p p l i
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
- 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // m l - a p p l i
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
- 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // h t m l - x m l
- 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // - t e x t - p l
- 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // a i n - t e x t
- 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // - j a v a s c r
- 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // i p t - p u b l
- 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // i c p r i v a t
- 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // e m a x - a g e
- 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // - g z i p - d e
- 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // f l a t e - s d
- 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // c h c h a r s e
- 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t - u t f - 8 c
- 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // h a r s e t - i
- 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // s o - 8 8 5 9 -
- 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1 - u t f - - -
- 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // - e n q - 0 -
-};
-
-// This can be called N times.. 1 for syn_reply and 0->N for headers
-nsresult
-SpdyStream31::Uncompress(z_stream *context,
- char *blockStart,
- uint32_t blockLen)
-{
- // ensure the minimum size
- EnsureBuffer(mDecompressBuffer, SpdySession31::kDefaultBufferSize,
- mDecompressBufferUsed, mDecompressBufferSize);
-
- mDecompressedBytes += blockLen;
-
- context->avail_in = blockLen;
- context->next_in = reinterpret_cast<unsigned char *>(blockStart);
- bool triedDictionary = false;
-
- do {
- context->next_out =
- reinterpret_cast<unsigned char *>(mDecompressBuffer.get()) +
- mDecompressBufferUsed;
- context->avail_out = mDecompressBufferSize - mDecompressBufferUsed;
- int zlib_rv = inflate(context, Z_NO_FLUSH);
- LOG3(("SpdyStream31::Uncompress %p zlib_rv %d\n", this, zlib_rv));
-
- if (zlib_rv == Z_NEED_DICT) {
- if (triedDictionary) {
- LOG3(("SpdyStream31::Uncompress %p Dictionary Error\n", this));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- triedDictionary = true;
- inflateSetDictionary(context, kDictionary, sizeof(kDictionary));
- } else if (zlib_rv == Z_DATA_ERROR) {
- LOG3(("SpdyStream31::Uncompress %p inflate returned data err\n", this));
- return NS_ERROR_ILLEGAL_VALUE;
- } else if (zlib_rv < Z_OK) { // probably Z_MEM_ERROR
- LOG3(("SpdyStream31::Uncompress %p inflate returned %d\n", this, zlib_rv));
- return NS_ERROR_FAILURE;
- }
-
- // zlib's inflate() decreases context->avail_out by the amount it places
- // in the output buffer
-
- mDecompressBufferUsed += mDecompressBufferSize - mDecompressBufferUsed -
- context->avail_out;
-
- // When there is no more output room, but input still available then
- // increase the output space
- if (zlib_rv == Z_OK &&
- !context->avail_out && context->avail_in) {
- LOG3(("SpdyStream31::Uncompress %p Large Headers - so far %d",
- this, mDecompressBufferSize));
- EnsureBuffer(mDecompressBuffer, mDecompressBufferSize + 4096,
- mDecompressBufferUsed, mDecompressBufferSize);
- }
- }
- while (context->avail_in);
- return NS_OK;
-}
-
-// mDecompressBuffer contains 0 to N uncompressed Name/Value Header blocks
-nsresult
-SpdyStream31::FindHeader(nsCString name,
- nsDependentCSubstring &value)
-{
- const unsigned char *nvpair = reinterpret_cast<unsigned char *>
- (mDecompressBuffer.get()) + 4;
- const unsigned char *lastHeaderByte = reinterpret_cast<unsigned char *>
- (mDecompressBuffer.get()) + mDecompressBufferUsed;
- if (lastHeaderByte < nvpair)
- return NS_ERROR_ILLEGAL_VALUE;
-
- do {
- uint32_t numPairs = PR_ntohl(reinterpret_cast<const uint32_t *>(nvpair)[-1]);
-
- for (uint32_t index = 0; index < numPairs; ++index) {
- if (lastHeaderByte < nvpair + 4)
- return NS_ERROR_ILLEGAL_VALUE;
- uint32_t nameLen = (nvpair[0] << 24) + (nvpair[1] << 16) +
- (nvpair[2] << 8) + nvpair[3];
- if (lastHeaderByte < nvpair + 4 + nameLen)
- return NS_ERROR_ILLEGAL_VALUE;
- nsDependentCSubstring nameString =
- Substring(reinterpret_cast<const char *>(nvpair) + 4,
- reinterpret_cast<const char *>(nvpair) + 4 + nameLen);
- if (lastHeaderByte < nvpair + 8 + nameLen)
- return NS_ERROR_ILLEGAL_VALUE;
- uint32_t valueLen = (nvpair[4 + nameLen] << 24) + (nvpair[5 + nameLen] << 16) +
- (nvpair[6 + nameLen] << 8) + nvpair[7 + nameLen];
- if (lastHeaderByte < nvpair + 8 + nameLen + valueLen)
- return NS_ERROR_ILLEGAL_VALUE;
- if (nameString.Equals(name)) {
- value.Assign(((char *)nvpair) + 8 + nameLen, valueLen);
- return NS_OK;
- }
-
- // that pair didn't match - try the next one in this block
- nvpair += 8 + nameLen + valueLen;
- }
-
- // move to the next name/value header block (if there is one) - the
- // first pair is offset 4 bytes into it
- nvpair += 4;
- } while (lastHeaderByte >= nvpair);
-
- return NS_ERROR_NOT_AVAILABLE;
-}
-
-// ConvertHeaders is used to convert the response headers
-// in a syn_reply or in 0..N headers frames that follow it into
-// HTTP/1 format
-nsresult
-SpdyStream31::ConvertHeaders(nsACString &aHeadersOut)
-{
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x\n",
- mSession, this, mStreamID));
-
- // :status and :version are required.
- nsDependentCSubstring status, version;
- nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"),
- status);
- if (NS_FAILED(rv)) {
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x missing :status\n",
- mSession, this, mStreamID));
- return (rv == NS_ERROR_NOT_AVAILABLE) ? NS_ERROR_ILLEGAL_VALUE : rv;
- }
-
- rv = FindHeader(NS_LITERAL_CSTRING(":version"),
- version);
- if (NS_FAILED(rv)) {
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x missing :version\n",
- mSession, this, mStreamID));
- return (rv == NS_ERROR_NOT_AVAILABLE) ? NS_ERROR_ILLEGAL_VALUE : rv;
- }
-
- if (mDecompressedBytes && mDecompressBufferUsed) {
- Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_SIZE, mDecompressedBytes);
- uint32_t ratio =
- mDecompressedBytes * 100 / mDecompressBufferUsed;
- Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_RATIO, ratio);
- }
-
- aHeadersOut.Truncate();
- aHeadersOut.SetCapacity(mDecompressBufferUsed + 64);
-
- // Connection, Keep-Alive and chunked transfer encodings are to be
- // removed.
-
- // Content-Length is 'advisory'.. we will not strip it because it can
- // create UI feedback.
-
- aHeadersOut.Append(version);
- aHeadersOut.Append(' ');
- aHeadersOut.Append(status);
- aHeadersOut.AppendLiteral("\r\n");
-
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x decompressed size %d\n",
- mSession, this, mStreamID, mDecompressBufferUsed));
-
- const unsigned char *nvpair = reinterpret_cast<unsigned char *>
- (mDecompressBuffer.get()) + 4;
- const unsigned char *lastHeaderByte = reinterpret_cast<unsigned char *>
- (mDecompressBuffer.get()) + mDecompressBufferUsed;
- if (lastHeaderByte < nvpair) {
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x format err 1\n",
- mSession, this, mStreamID));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- do {
- uint32_t numPairs = PR_ntohl(reinterpret_cast<const uint32_t *>(nvpair)[-1]);
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x numPairs %d\n",
- mSession, this, mStreamID, numPairs));
-
- for (uint32_t index = 0; index < numPairs; ++index) {
- LOG5(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x index=%u remaining=%u\n",
- mSession, this, mStreamID, index, lastHeaderByte - nvpair));
- if (lastHeaderByte < nvpair + 4) {
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x format err 2\n",
- mSession, this, mStreamID));
- return NS_ERROR_ILLEGAL_VALUE;
- }
- uint32_t nameLen = (nvpair[0] << 24) + (nvpair[1] << 16) +
- (nvpair[2] << 8) + nvpair[3];
- LOG5(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x namelen=%u\n",
- mSession, this, mStreamID, nameLen));
- if (lastHeaderByte < nvpair + 4 + nameLen) {
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x format err 3\n",
- mSession, this, mStreamID));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- nsDependentCSubstring nameString =
- Substring(reinterpret_cast<const char *>(nvpair) + 4,
- reinterpret_cast<const char *>(nvpair) + 4 + nameLen);
-
- if (lastHeaderByte < nvpair + 8 + nameLen) {
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x format err 4\n",
- mSession, this, mStreamID));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- // Look for illegal characters in the nameString.
- // This includes upper case characters and nulls (as they will
- // break the fixup-nulls-in-value-string algorithm)
- // Look for upper case characters in the name. They are illegal.
- for (char *cPtr = nameString.BeginWriting();
- cPtr && cPtr < nameString.EndWriting();
- ++cPtr) {
- if (*cPtr <= 'Z' && *cPtr >= 'A') {
- nsCString toLog(nameString);
-
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p "
- "upper case response header found. [%s]\n",
- mSession, this, toLog.get()));
-
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- // check for null characters
- if (*cPtr == '\0') {
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x unexpected null\n",
- mSession, this, mStreamID));
- return NS_ERROR_ILLEGAL_VALUE;
- }
- }
-
- // HTTP Chunked responses are not legal over spdy. We do not need
- // to look for chunked specifically because it is the only HTTP
- // allowed default encoding and we did not negotiate further encodings
- // via TE
- if (nameString.EqualsLiteral("transfer-encoding")) {
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p "
- "transfer-encoding found. Chunked is invalid and no TE sent.",
- mSession, this));
-
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- uint32_t valueLen =
- (nvpair[4 + nameLen] << 24) + (nvpair[5 + nameLen] << 16) +
- (nvpair[6 + nameLen] << 8) + nvpair[7 + nameLen];
- LOG5(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x valueLen=%u\n",
- mSession, this, mStreamID, valueLen));
- if (lastHeaderByte < nvpair + 8 + nameLen + valueLen) {
- LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p id=0x%x format err 5\n",
- mSession, this, mStreamID));
- return NS_ERROR_ILLEGAL_VALUE;
- }
-
- // spdy transport level headers shouldn't be gatewayed into http/1
- if (!nameString.IsEmpty() && nameString[0] != ':' &&
- !nameString.EqualsLiteral("connection") &&
- !nameString.EqualsLiteral("keep-alive")) {
- nsDependentCSubstring valueString =
- Substring(reinterpret_cast<const char *>(nvpair) + 8 + nameLen,
- reinterpret_cast<const char *>(nvpair) + 8 + nameLen +
- valueLen);
-
- aHeadersOut.Append(nameString);
- aHeadersOut.AppendLiteral(": ");
-
- // expand NULL bytes in the value string
- for (char *cPtr = valueString.BeginWriting();
- cPtr && cPtr < valueString.EndWriting();
- ++cPtr) {
- if (*cPtr != 0) {
- aHeadersOut.Append(*cPtr);
- continue;
- }
-
- // NULLs are really "\r\nhdr: "
- aHeadersOut.AppendLiteral("\r\n");
- aHeadersOut.Append(nameString);
- aHeadersOut.AppendLiteral(": ");
- }
-
- aHeadersOut.AppendLiteral("\r\n");
- }
- // move to the next name/value pair in this block
- nvpair += 8 + nameLen + valueLen;
- }
-
- // move to the next name/value header block (if there is one) - the
- // first pair is offset 4 bytes into it
- nvpair += 4;
- } while (lastHeaderByte >= nvpair);
-
- // The decoding went ok. Now we can customize and clean up.
-
- aHeadersOut.AppendLiteral("X-Firefox-Spdy: 3.1\r\n\r\n");
- LOG (("decoded response headers are:\n%s",
- aHeadersOut.BeginReading()));
-
- // The spdy formatted buffer isnt needed anymore - free it up
- mDecompressBuffer = nullptr;
- mDecompressBufferSize = 0;
- mDecompressBufferUsed = 0;
-
- if (mIsTunnel && !mPlainTextTunnel) {
- aHeadersOut.Truncate();
- LOG(("SpdyStream31::ConvertHeaders %p 0x%X headers removed for tunnel\n",
- this, mStreamID));
- }
-
- return NS_OK;
-}
-
-void
-SpdyStream31::ExecuteCompress(uint32_t flushMode)
-{
- // Expect mZlib->avail_in and mZlib->next_in to be set.
- // Append the compressed version of next_in to mTxInlineFrame
-
- do
- {
- uint32_t avail = mTxInlineFrameSize - mTxInlineFrameUsed;
- if (avail < 1) {
- EnsureBuffer(mTxInlineFrame, mTxInlineFrameSize + 2000,
- mTxInlineFrameUsed, mTxInlineFrameSize);
- avail = mTxInlineFrameSize - mTxInlineFrameUsed;
- }
-
- mZlib->next_out = &mTxInlineFrame[mTxInlineFrameUsed];
- mZlib->avail_out = avail;
- deflate(mZlib, flushMode);
- mTxInlineFrameUsed += avail - mZlib->avail_out;
- } while (mZlib->avail_in > 0 || !mZlib->avail_out);
-}
-
-void
-SpdyStream31::CompressToFrame(uint32_t data)
-{
- // convert the data to 4 byte network byte order and write that
- // to the compressed stream
- data = PR_htonl(data);
-
- mZlib->next_in = reinterpret_cast<unsigned char *> (&data);
- mZlib->avail_in = 4;
- ExecuteCompress(Z_NO_FLUSH);
-}
-
-
-void
-SpdyStream31::CompressToFrame(const char *data, uint32_t len)
-{
- // Format calls for a network ordered 32 bit length
- // followed by the utf8 string
-
- uint32_t networkLen = PR_htonl(len);
-
- // write out the length
- mZlib->next_in = reinterpret_cast<unsigned char *> (&networkLen);
- mZlib->avail_in = 4;
- ExecuteCompress(Z_NO_FLUSH);
-
- // write out the data
- mZlib->next_in = (unsigned char *)data;
- mZlib->avail_in = len;
- ExecuteCompress(Z_NO_FLUSH);
-}
-
-void
-SpdyStream31::CompressFlushFrame()
-{
- mZlib->next_in = (unsigned char *) "";
- mZlib->avail_in = 0;
- ExecuteCompress(Z_SYNC_FLUSH);
-}
-
-bool
-SpdyStream31::GetFullyOpen()
-{
- return mFullyOpen;
-}
-
-nsresult
-SpdyStream31::SetFullyOpen()
-{
- MOZ_ASSERT(!mFullyOpen);
- mFullyOpen = 1;
- if (mIsTunnel) {
- int32_t code = 0;
- nsDependentCSubstring statusSubstring;
- nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"), statusSubstring);
- if (NS_SUCCEEDED(rv)) {
- nsCString status(statusSubstring);
- nsresult errcode;
- code = status.ToInteger(&errcode);
- }
-
- LOG3(("SpdyStream31::SetFullyOpen %p Tunnel Response code %d", this, code));
- if ((code / 100) != 2) {
- MapStreamToPlainText();
- }
-
- MapStreamToHttpConnection();
- ClearTransactionsBlockedOnTunnel();
- }
- return NS_OK;
-}
-
-void
-SpdyStream31::Close(nsresult reason)
-{
- mTransaction->Close(reason);
-}
-
-void
-SpdyStream31::SetResponseIsComplete()
-{
- nsHttpTransaction *trans = mTransaction->QueryHttpTransaction();
- if (trans) {
- trans->SetResponseIsComplete();
- }
-}
-
-void
-SpdyStream31::UpdateRemoteWindow(int32_t delta)
-{
- mRemoteWindow += delta;
-
- // If the stream had a <=0 window, that has now opened
- // schedule it for writing again
- if (mBlockedOnRwin && mSession->RemoteSessionWindow() > 0 &&
- mRemoteWindow > 0) {
- // the window has been opened :)
- mSession->TransactionHasDataToWrite(this);
- }
-}
-
-//-----------------------------------------------------------------------------
-// nsAHttpSegmentReader
-//-----------------------------------------------------------------------------
-
-nsresult
-SpdyStream31::OnReadSegment(const char *buf,
- uint32_t count,
- uint32_t *countRead)
-{
- LOG3(("SpdyStream31::OnReadSegment %p count=%d state=%x",
- this, count, mUpstreamState));
-
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- MOZ_ASSERT(mSegmentReader, "OnReadSegment with null mSegmentReader");
-
- nsresult rv = NS_ERROR_UNEXPECTED;
- uint32_t dataLength;
-
- switch (mUpstreamState) {
- case GENERATING_SYN_STREAM:
- // The buffer is the HTTP request stream, including at least part of the
- // HTTP request header. This state's job is to build a SYN_STREAM frame
- // from the header information. count is the number of http bytes available
- // (which may include more than the header), and in countRead we return
- // the number of those bytes that we consume (i.e. the portion that are
- // header bytes)
-
- if (!mRequestHeadersDone) {
- if (NS_FAILED(rv = ParseHttpRequestHeaders(buf, count, countRead))) {
- return rv;
- }
- }
-
- if (mRequestHeadersDone && !mSynFrameGenerated) {
- if (!mSession->TryToActivate(this)) {
- LOG3(("SpdyStream31::OnReadSegment %p cannot activate now. queued.\n", this));
- return *countRead ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
- }
- if (NS_FAILED(rv = GenerateSynFrame())) {
- return rv;
- }
- }
-
- LOG3(("ParseHttpRequestHeaders %p used %d of %d. "
- "requestheadersdone = %d mSynFrameGenerated = %d\n",
- this, *countRead, count, mRequestHeadersDone, mSynFrameGenerated));
- if (mSynFrameGenerated) {
- AdjustInitialWindow();
- rv = TransmitFrame(nullptr, nullptr, true);
- if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
- // this can't happen
- MOZ_ASSERT(false, "Transmit Frame SYN_FRAME must at least buffer data");
- rv = NS_ERROR_UNEXPECTED;
- }
-
- ChangeState(GENERATING_REQUEST_BODY);
- break;
- }
- MOZ_ASSERT(*countRead == count, "Header parsing not complete but unused data");
- break;
-
- case GENERATING_REQUEST_BODY:
- if ((mRemoteWindow <= 0) || (mSession->RemoteSessionWindow() <= 0)) {
- *countRead = 0;
- LOG3(("SpdyStream31 this=%p, id 0x%X request body suspended because "
- "remote window is stream=%ld session=%ld.\n", this, mStreamID,
- mRemoteWindow, mSession->RemoteSessionWindow()));
- mBlockedOnRwin = true;
- return NS_BASE_STREAM_WOULD_BLOCK;
- }
- mBlockedOnRwin = false;
-
- dataLength = std::min(count, mChunkSize);
-
- if (dataLength > mRemoteWindow)
- dataLength = static_cast<uint32_t>(mRemoteWindow);
-
- if (dataLength > mSession->RemoteSessionWindow())
- dataLength = static_cast<uint32_t>(mSession->RemoteSessionWindow());
-
- LOG3(("SpdyStream31 this=%p id 0x%X remote window is stream %" PRId64 " and "
- "session %" PRId64". Chunk is %u\n",
- this, mStreamID, mRemoteWindow,
- mSession->RemoteSessionWindow(), dataLength));
- mRemoteWindow -= dataLength;
- mSession->DecrementRemoteSessionWindow(dataLength);
-
- LOG3(("SpdyStream31 %p id 0x%x request len remaining %" PRId64 ", "
- "count avail %u, chunk used %u",
- this, mStreamID, mRequestBodyLenRemaining, count, dataLength));
- if (!dataLength && mRequestBodyLenRemaining) {
- return NS_BASE_STREAM_WOULD_BLOCK;
- }
- if (dataLength > mRequestBodyLenRemaining) {
- return NS_ERROR_UNEXPECTED;
- }
- mRequestBodyLenRemaining -= dataLength;
- GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining);
- ChangeState(SENDING_REQUEST_BODY);
- MOZ_FALLTHROUGH;
-
- case SENDING_REQUEST_BODY:
- MOZ_ASSERT(mTxInlineFrameUsed, "OnReadSegment Send Data Header 0b");
- rv = TransmitFrame(buf, countRead, false);
- MOZ_ASSERT(NS_FAILED(rv) || !mTxInlineFrameUsed,
- "Transmit Frame should be all or nothing");
-
- LOG3(("TransmitFrame() rv=%x returning %d data bytes. "
- "Header is %d Body is %d.",
- rv, *countRead, mTxInlineFrameUsed, mTxStreamFrameSize));
-
- // normalize a partial write with a WOULD_BLOCK into just a partial write
- // as some code will take WOULD_BLOCK to mean an error with nothing
- // written (e.g. nsHttpTransaction::ReadRequestSegment()
- if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead)
- rv = NS_OK;
-
- // If that frame was all sent, look for another one
- if (!mTxInlineFrameUsed)
- ChangeState(GENERATING_REQUEST_BODY);
- break;
-
- case SENDING_FIN_STREAM:
- MOZ_ASSERT(false, "resuming partial fin stream out of OnReadSegment");
- break;
-
- default:
- MOZ_ASSERT(false, "SpdyStream31::OnReadSegment non-write state");
- break;
- }
-
- return rv;
-}
-
-//-----------------------------------------------------------------------------
-// nsAHttpSegmentWriter
-//-----------------------------------------------------------------------------
-
-nsresult
-SpdyStream31::OnWriteSegment(char *buf,
- uint32_t count,
- uint32_t *countWritten)
-{
- LOG3(("SpdyStream31::OnWriteSegment %p count=%d state=%x 0x%X\n",
- this, count, mUpstreamState, mStreamID));
-
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- MOZ_ASSERT(mSegmentWriter);
-
- if (!mPushSource)
- return mSegmentWriter->OnWriteSegment(buf, count, countWritten);
-
- nsresult rv;
- rv = mPushSource->GetBufferedData(buf, count, countWritten);
- if (NS_FAILED(rv))
- return rv;
-
- mSession->ConnectPushedStream(this);
- return NS_OK;
-}
-
-/// connect tunnels
-
-void
-SpdyStream31::ClearTransactionsBlockedOnTunnel()
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-
- if (!mIsTunnel) {
- return;
- }
- gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo());
-}
-
-void
-SpdyStream31::MapStreamToPlainText()
-{
- RefPtr<SpdyConnectTransaction> qiTrans(mTransaction->QuerySpdyConnectTransaction());
- MOZ_ASSERT(qiTrans);
- mPlainTextTunnel = true;
- qiTrans->ForcePlainText();
-}
-
-void
-SpdyStream31::MapStreamToHttpConnection()
-{
- RefPtr<SpdyConnectTransaction> qiTrans(mTransaction->QuerySpdyConnectTransaction());
- MOZ_ASSERT(qiTrans);
- qiTrans->MapStreamToHttpConnection(mSocketTransport,
- mTransaction->ConnectionInfo());
-}
-
-} // namespace net
-} // namespace mozilla
deleted file mode 100644
--- a/netwerk/protocol/http/SpdyStream31.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/* -*- 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 "mozilla/UniquePtr.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);
- }
-
- bool GetFullyOpen();
- // returns failure if stream cannot be made ready and stream
- // should be canceled
- nsresult SetFullyOpen();
-
- bool HasRegisteredID() { return mStreamID != 0; }
-
- nsAHttpTransaction *Transaction() { return mTransaction; }
- virtual nsIRequestContext *RequestContext()
- {
- return mTransaction ? mTransaction->RequestContext() : nullptr;
- }
-
- void Close(nsresult reason);
- void SetResponseIsComplete();
-
- 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 SetQueued(bool aStatus) { mQueued = aStatus ? 1 : 0; }
- bool Queued() { return mQueued; }
-
- void SetCountAsActive(bool aStatus) { mCountAsActive = aStatus ? 1 : 0; }
- bool CountAsActive() { return mCountAsActive; }
-
- void UpdateTransportSendEvents(uint32_t count);
- void UpdateTransportReadEvents(uint32_t count);
-
- // The zlib header compression dictionary defined by SPDY.
- static const unsigned char kDictionary[1423];
-
- nsresult Uncompress(z_stream *, char *, uint32_t);
- nsresult ConvertHeaders(nsACString &);
-
- void UpdateRemoteWindow(int32_t 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; }
- bool ChannelPipeFull();
-
- // 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
- uint32_t mRequestHeadersDone : 1;
-
- // Flag is set when stream ID is stable
- uint32_t mSynFrameGenerated : 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;
-
- // Flag is set when stream is queued inside the session due to
- // concurrency limits being exceeded
- uint32_t mQueued : 1;
-
- void ChangeState(enum stateType);
-
-private:
- friend class nsAutoPtr<SpdyStream31>;
-
- nsresult ParseHttpRequestHeaders(const char *, uint32_t, uint32_t *);
- nsresult GenerateSynFrame();
-
- 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).
- RefPtr<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;
-
- // Flag is set when stream is counted towards MAX_CONCURRENT streams in session
- uint32_t mCountAsActive : 1;
-
- // The InlineFrame and associated data is used for composing control
- // frames and data frame headers.
- UniquePtr<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;
- UniquePtr<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. Connect does rely on stream
- // close by setting this to the max value.
- 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;
-
-/// connect tunnels
-public:
- bool IsTunnel() { return mIsTunnel; }
-private:
- void ClearTransactionsBlockedOnTunnel();
- void MapStreamToPlainText();
- void MapStreamToHttpConnection();
-
- bool mIsTunnel;
- bool mPlainTextTunnel;
-};
-
-} // namespace net
-} // namespace mozilla
-
-#endif // mozilla_net_SpdyStream31_h
deleted file mode 100644
--- a/netwerk/protocol/http/SpdyZlibReporter.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- 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/. */
-
-#include "SpdyZlibReporter.h"
-
-namespace mozilla {
-
-NS_IMPL_ISUPPORTS(SpdyZlibReporter, nsIMemoryReporter)
-
-/* static */ Atomic<size_t> SpdyZlibReporter::sAmount;
-
-/* static */ void*
-SpdyZlibReporter::Alloc(void*, uInt items, uInt size)
-{
- void* p = moz_xmalloc(items * size);
- sAmount += MallocSizeOfOnAlloc(p);
- return p;
-}
-
-/* static */ void
-SpdyZlibReporter::Free(void*, void* p)
-{
- sAmount -= MallocSizeOfOnFree(p);
- free(p);
-}
-
-NS_IMETHODIMP
-SpdyZlibReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
- nsISupports* aData, bool aAnonymize)
-{
- return MOZ_COLLECT_REPORT(
- "explicit/network/spdy-zlib-buffers", KIND_HEAP, UNITS_BYTES, sAmount,
- "Memory allocated for SPDY zlib send and receive buffers.");
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/netwerk/protocol/http/SpdyZlibReporter.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- 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/. */
-
-/* A memory allocator for zlib use in SPDY that reports to about:memory. */
-
-#ifndef mozilla_net_SpdyZlibReporter_h
-#define mozilla_net_SpdyZlibReporter_h
-
-#include "mozilla/Assertions.h"
-#include "mozilla/Atomics.h"
-#include "mozilla/Attributes.h"
-#include "nsIMemoryReporter.h"
-#include "zlib.h"
-
-namespace mozilla {
-
-class SpdyZlibReporter final : public nsIMemoryReporter
-{
- ~SpdyZlibReporter() {}
-
-public:
- NS_DECL_ISUPPORTS
-
- SpdyZlibReporter()
- {
-#ifdef DEBUG
- // There must be only one instance of this class, due to |sAmount|
- // being static.
- static bool hasRun = false;
- MOZ_ASSERT(!hasRun);
- hasRun = true;
-#endif
- sAmount = 0;
- }
-
- static void* Alloc(void*, uInt items, uInt size);
- static void Free(void*, void* p);
-
-private:
- // |sAmount| can be (implicitly) accessed by multiple threads, so it
- // must be thread-safe.
- static Atomic<size_t> sAmount;
-
- MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
- MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
- MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
-
- NS_IMETHODIMP
- CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
- bool aAnonymize) override;
-};
-
-} // namespace mozilla
-
-#endif // mozilla_net_SpdyZlibReporter_h
--- a/netwerk/protocol/http/moz.build
+++ b/netwerk/protocol/http/moz.build
@@ -80,20 +80,16 @@ UNIFIED_SOURCES += [
'nsHttpPipeline.cpp',
'nsHttpRequestHead.cpp',
'nsHttpResponseHead.cpp',
'nsHttpTransaction.cpp',
'NullHttpChannel.cpp',
'NullHttpTransaction.cpp',
'PackagedAppService.cpp',
'PackagedAppVerifier.cpp',
- 'SpdyPush31.cpp',
- 'SpdySession31.cpp',
- 'SpdyStream31.cpp',
- 'SpdyZlibReporter.cpp',
'TunnelUtils.cpp',
]
# These files cannot be built in unified mode because of OS X headers.
SOURCES += [
'nsHttpHandler.cpp',
]
--- a/netwerk/protocol/http/nsHttp.cpp
+++ b/netwerk/protocol/http/nsHttp.cpp
@@ -226,18 +226,16 @@ nsHttp::IsValidToken(const char *start,
return true;
}
const char*
nsHttp::GetProtocolVersion(uint32_t pv)
{
switch (pv) {
- case SPDY_VERSION_31:
- return "spdy/3.1";
case HTTP_VERSION_2:
case NS_HTTP_VERSION_2_0:
return "h2";
case NS_HTTP_VERSION_1_0:
return "http/1.0";
case NS_HTTP_VERSION_1_1:
return "http/1.1";
default:
--- a/netwerk/protocol/http/nsHttp.h
+++ b/netwerk/protocol/http/nsHttp.h
@@ -25,17 +25,17 @@
namespace mozilla {
class Mutex;
namespace net {
enum {
// SPDY_VERSION_2 = 2, REMOVED
// SPDY_VERSION_3 = 3, REMOVED
- SPDY_VERSION_31 = 4,
+ // SPDY_VERSION_31 = 4, REMOVED
HTTP_VERSION_2 = 5
// leave room for official versions. telem goes to 48
// 24 was a internal spdy/3.1
// 25 was spdy/4a2
// 26 was http/2-draft08 and http/2-draft07 (they were the same)
// 27 was http/2-draft09, h2-10, and h2-11
// 28 was http/2-draft12
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -39,17 +39,16 @@
#include "Tickler.h"
#include "nsIXULAppInfo.h"
#include "nsICookieService.h"
#include "nsIObserverService.h"
#include "nsISiteSecurityService.h"
#include "nsIStreamConverterService.h"
#include "nsITimer.h"
#include "nsCRT.h"
-#include "SpdyZlibReporter.h"
#include "nsIMemoryReporter.h"
#include "nsIParentalControlsService.h"
#include "nsPIDOMWindow.h"
#include "nsINetworkLinkService.h"
#include "nsHttpChannelAuthProvider.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsSocketTransportService2.h"
@@ -205,17 +204,16 @@ nsHttpHandler::nsHttpHandler()
, mDoNotTrackEnabled(false)
, mSafeHintEnabled(false)
, mParentalControlEnabled(false)
, mHandlerActive(false)
, mTelemetryEnabled(false)
, mAllowExperiments(true)
, mDebugObservations(false)
, mEnableSpdy(false)
- , mSpdyV31(true)
, mHttp2Enabled(true)
, mUseH2Deps(true)
, mEnforceHttp2TlsProfile(true)
, mCoalesceSpdy(true)
, mSpdyPersistentSettings(false)
, mAllowPush(true)
, mEnableAltSvc(false)
, mEnableAltSvcOE(false)
@@ -238,18 +236,16 @@ nsHttpHandler::nsHttpHandler()
, mTCPKeepaliveShortLivedIdleTimeS(10)
, mTCPKeepaliveLongLivedEnabled(false)
, mTCPKeepaliveLongLivedIdleTimeS(600)
, mEnforceH1Framing(FRAMECHECK_BARELY)
, mKeepEmptyResponseHeadersAsEmtpyString(false)
{
LOG(("Creating nsHttpHandler [this=%p].\n", this));
- RegisterStrongMemoryReporter(new SpdyZlibReporter());
-
MOZ_ASSERT(!gHttpHandler, "HTTP handler already created!");
gHttpHandler = this;
}
nsHttpHandler::~nsHttpHandler()
{
LOG(("Deleting nsHttpHandler [this=%p]\n", this));
@@ -1314,22 +1310,16 @@ nsHttpHandler::PrefsChanged(nsIPrefBranc
}
if (PREF_CHANGED(HTTP_PREF("spdy.enabled"))) {
rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled"), &cVar);
if (NS_SUCCEEDED(rv))
mEnableSpdy = 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.enabled.http2"))) {
rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled.http2"), &cVar);
if (NS_SUCCEEDED(rv))
mHttp2Enabled = cVar;
}
if (PREF_CHANGED(HTTP_PREF("spdy.enabled.deps"))) {
rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled.deps"), &cVar);
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -103,17 +103,16 @@ public:
uint32_t MaxSocketCount();
bool EnforceAssocReq() { return mEnforceAssocReq; }
bool IsPersistentHttpsCachingEnabled() { return mEnablePersistentHttpsCaching; }
bool IsTelemetryEnabled() { return mTelemetryEnabled; }
bool AllowExperiments() { return mTelemetryEnabled && mAllowExperiments; }
bool IsSpdyEnabled() { return mEnableSpdy; }
- bool IsSpdyV31Enabled() { return mSpdyV31; }
bool IsHttp2Enabled() { return mHttp2Enabled; }
bool EnforceHttp2TlsProfile() { return mEnforceHttp2TlsProfile; }
bool CoalesceSpdy() { return mCoalesceSpdy; }
bool UseSpdyPersistentSettings() { return mSpdyPersistentSettings; }
uint32_t SpdySendingChunkSize() { return mSpdySendingChunkSize; }
uint32_t SpdySendBufferSize() { return mSpdySendBufferSize; }
uint32_t SpdyPushAllowance() { return mSpdyPushAllowance; }
uint32_t SpdyPullAllowance() { return mSpdyPullAllowance; }
@@ -508,17 +507,16 @@ private:
// The value of network.allow-experiments
uint32_t mAllowExperiments : 1;
// The value of 'hidden' network.http.debug-observations : 1;
uint32_t mDebugObservations : 1;
uint32_t mEnableSpdy : 1;
- uint32_t mSpdyV31 : 1;
uint32_t mHttp2Enabled : 1;
uint32_t mUseH2Deps : 1;
uint32_t mEnforceHttp2TlsProfile : 1;
uint32_t mCoalesceSpdy : 1;
uint32_t mSpdyPersistentSettings : 1;
uint32_t mAllowPush : 1;
uint32_t mEnableAltSvc : 1;
uint32_t mEnableAltSvcOE : 1;
--- a/netwerk/test/unit/test_http2.js
+++ b/netwerk/test/unit/test_http2.js
@@ -995,30 +995,28 @@ function addCertOverride(host, port, bit
req.send(null);
} catch (e) {
// This will fail since the server is not trusted yet
}
}
var prefs;
var spdypref;
-var spdy3pref;
var spdypush;
var http2pref;
var tlspref;
var altsvcpref1;
var altsvcpref2;
var loadGroup;
var serverPort;
var speculativeLimit;
function resetPrefs() {
prefs.setIntPref("network.http.speculative-parallel-limit", speculativeLimit);
prefs.setBoolPref("network.http.spdy.enabled", spdypref);
- prefs.setBoolPref("network.http.spdy.enabled.v3-1", spdy3pref);
prefs.setBoolPref("network.http.spdy.allow-push", spdypush);
prefs.setBoolPref("network.http.spdy.enabled.http2", http2pref);
prefs.setBoolPref("network.http.spdy.enforce-tls-profile", tlspref);
prefs.setBoolPref("network.http.altsvc.enabled", altsvcpref1);
prefs.setBoolPref("network.http.altsvc.oe", altsvcpref2);
}
function run_test() {
@@ -1035,17 +1033,16 @@ function run_test() {
addCertOverride("localhost", serverPort,
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
Ci.nsICertOverrideService.ERROR_MISMATCH |
Ci.nsICertOverrideService.ERROR_TIME);
// Enable all versions of spdy to see that we auto negotiate http/2
spdypref = prefs.getBoolPref("network.http.spdy.enabled");
- spdy3pref = prefs.getBoolPref("network.http.spdy.enabled.v3-1");
spdypush = prefs.getBoolPref("network.http.spdy.allow-push");
http2pref = prefs.getBoolPref("network.http.spdy.enabled.http2");
tlspref = prefs.getBoolPref("network.http.spdy.enforce-tls-profile");
altsvcpref1 = prefs.getBoolPref("network.http.altsvc.enabled");
altsvcpref2 = prefs.getBoolPref("network.http.altsvc.oe", true);
prefs.setBoolPref("network.http.spdy.enabled", true);
prefs.setBoolPref("network.http.spdy.enabled.v3-1", true);
deleted file mode 100644
--- a/netwerk/test/unit/test_spdy.js
+++ /dev/null
@@ -1,476 +0,0 @@
-// test spdy/3.1
-
-Cu.import("resource://gre/modules/NetUtil.jsm");
-
-// Generate a small and a large post with known pre-calculated md5 sums
-function generateContent(size) {
- var content = "";
- for (var i = 0; i < size; i++) {
- content += "0";
- }
- return content;
-}
-
-var posts = [];
-posts.push(generateContent(10));
-posts.push(generateContent(250000));
-
-// pre-calculated md5sums (in hex) of the above posts
-var md5s = ['f1b708bba17f1ce948dc979f4d7092bc',
- '2ef8d3b6c8f329318eb1a119b12622b6'];
-
-var bigListenerData = generateContent(128 * 1024);
-var bigListenerMD5 = '8f607cfdd2c87d6a7eedb657dafbd836';
-var hugeListenerData = generateContent(800 * 1024);
-
-function checkIsSpdy(request) {
- try {
- if (request.getResponseHeader("X-Firefox-Spdy") == "3.1") {
- if (request.getResponseHeader("X-Connection-Spdy") == "yes") {
- return true;
- }
- return false; // Weird case, but the server disagrees with us
- }
- } catch (e) {
- // Nothing to do here
- }
- return false;
-}
-
-var SpdyCheckListener = function() {};
-
-SpdyCheckListener.prototype = {
- onStartRequestFired: false,
- onDataAvailableFired: false,
- isSpdyConnection: false,
-
- onStartRequest: function testOnStartRequest(request, ctx) {
- this.onStartRequestFired = true;
- if (!Components.isSuccessCode(request.status))
- do_throw("Channel should have a success code! (" + request.status + ")");
-
- do_check_true(request instanceof Components.interfaces.nsIHttpChannel);
- do_check_eq(request.responseStatus, 200);
- do_check_eq(request.requestSucceeded, true);
- },
-
- onDataAvailable: function testOnDataAvailable(request, ctx, stream, off, cnt) {
- this.onDataAvailableFired = true;
- this.isSpdyConnection = checkIsSpdy(request);
-
- read_stream(stream, cnt);
- },
-
- onStopRequest: function testOnStopRequest(request, ctx, status) {
- do_check_true(this.onStartRequestFired);
- do_check_true(Components.isSuccessCode(status));
- do_check_true(this.isSpdyConnection);
- do_check_true(this.onDataAvailableFired);
-
- run_next_test();
- do_test_finished();
- }
-};
-
-/*
- * Support for testing valid multiplexing of streams
- */
-
-var multiplexContent = generateContent(30*1024);
-var completed_channels = [];
-function register_completed_channel(listener) {
- completed_channels.push(listener);
- if (completed_channels.length == 2) {
- do_check_neq(completed_channels[0].streamID, completed_channels[1].streamID);
- run_next_test();
- do_test_finished();
- }
-}
-
-/* Listener class to control the testing of multiplexing */
-var SpdyMultiplexListener = function() {};
-
-SpdyMultiplexListener.prototype = new SpdyCheckListener();
-
-SpdyMultiplexListener.prototype.streamID = 0;
-SpdyMultiplexListener.prototype.buffer = "";
-
-SpdyMultiplexListener.prototype.onDataAvailable = function(request, ctx, stream, off, cnt) {
- this.onDataAvailableFired = true;
- this.isSpdyConnection = checkIsSpdy(request);
- this.streamID = parseInt(request.getResponseHeader("X-Spdy-StreamID"));
- var data = read_stream(stream, cnt);
- this.buffer = this.buffer.concat(data);
-};
-
-SpdyMultiplexListener.prototype.onStopRequest = function(request, ctx, status) {
- do_check_true(this.onStartRequestFired);
- do_check_true(this.onDataAvailableFired);
- do_check_true(this.isSpdyConnection);
- do_check_true(this.buffer == multiplexContent);
-
- // This is what does most of the hard work for us
- register_completed_channel(this);
-};
-
-// Does the appropriate checks for header gatewaying
-var SpdyHeaderListener = function(value) {
- this.value = value
-};
-
-SpdyHeaderListener.prototype = new SpdyCheckListener();
-SpdyHeaderListener.prototype.value = "";
-
-SpdyHeaderListener.prototype.onDataAvailable = function(request, ctx, stream, off, cnt) {
- this.onDataAvailableFired = true;
- this.isSpdyConnection = checkIsSpdy(request);
- do_check_eq(request.getResponseHeader("X-Received-Test-Header"), this.value);
- read_stream(stream, cnt);
-};
-
-var SpdyPushListener = function() {};
-
-SpdyPushListener.prototype = new SpdyCheckListener();
-
-SpdyPushListener.prototype.onDataAvailable = function(request, ctx, stream, off, cnt) {
- this.onDataAvailableFired = true;
- this.isSpdyConnection = checkIsSpdy(request);
- if (request.originalURI.spec == "https://localhost:" + serverPort + "/push.js" ||
- request.originalURI.spec == "https://localhost:" + serverPort + "/push2.js") {
- do_check_eq(request.getResponseHeader("pushed"), "yes");
- }
- read_stream(stream, cnt);
-};
-
-// Does the appropriate checks for a large GET response
-var SpdyBigListener = function() {};
-
-SpdyBigListener.prototype = new SpdyCheckListener();
-SpdyBigListener.prototype.buffer = "";
-
-SpdyBigListener.prototype.onDataAvailable = function(request, ctx, stream, off, cnt) {
- this.onDataAvailableFired = true;
- this.isSpdyConnection = checkIsSpdy(request);
- this.buffer = this.buffer.concat(read_stream(stream, cnt));
-};
-
-SpdyBigListener.prototype.onStopRequest = function(request, ctx, status) {
- do_check_true(this.onStartRequestFired);
- do_check_true(this.onDataAvailableFired);
- do_check_true(this.isSpdyConnection);
-
- // Don't want to flood output, so don't use do_check_eq
- if (request.originalURI.spec == "https://localhost:" + serverPort + "/big") {
- // We know the server should send us the same data as our big post will be,
- // so the md5 should be the same
- do_check_eq(bigListenerMD5, request.getResponseHeader("X-Expected-MD5"));
- do_check_true(this.buffer == bigListenerData);
- } else {
- do_check_true(this.buffer == hugeListenerData);
- }
-
- run_next_test();
- do_test_finished();
-};
-
-// Does the appropriate checks for POSTs
-var SpdyPostListener = function(expected_md5) {
- this.expected_md5 = expected_md5;
-};
-
-SpdyPostListener.prototype = new SpdyCheckListener();
-SpdyPostListener.prototype.expected_md5 = "";
-
-SpdyPostListener.prototype.onDataAvailable = function(request, ctx, stream, off, cnt) {
- this.onDataAvailableFired = true;
- this.isSpdyConnection = checkIsSpdy(request);
- read_stream(stream, cnt);
- do_check_eq(this.expected_md5, request.getResponseHeader("X-Calculated-MD5"));
-};
-
-function makeChan(url) {
- return NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true})
- .QueryInterface(Ci.nsIHttpChannel);
-}
-
-// Make sure we make a spdy connection and both us and the server mark it as such
-function test_spdy_basic() {
- var chan = makeChan("https://localhost:" + serverPort + "/");
- var listener = new SpdyCheckListener();
- chan.asyncOpen2(listener);
-}
-
-// Support for making sure XHR works over SPDY
-function checkXhr(xhr) {
- if (xhr.readyState != 4) {
- return;
- }
-
- do_check_eq(xhr.status, 200);
- do_check_eq(checkIsSpdy(xhr), true);
- run_next_test();
- do_test_finished();
-}
-
-// Fires off an XHR request over SPDY
-function test_spdy_xhr() {
- var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
- .createInstance(Ci.nsIXMLHttpRequest);
- req.open("GET", "https://localhost:" + serverPort + "/", true);
- req.addEventListener("readystatechange", function (evt) { checkXhr(req); },
- false);
- req.send(null);
-}
-
-var concurrent_channels = [];
-
-var SpdyConcurrentListener = function() {};
-
-SpdyConcurrentListener.prototype = new SpdyCheckListener();
-SpdyConcurrentListener.prototype.count = 0;
-SpdyConcurrentListener.prototype.target = 0;
-
-SpdyConcurrentListener.prototype.onStopRequest = function(request, ctx, status) {
- this.count++;
- do_check_true(this.isSpdyConnection);
- if (this.count == this.target) {
- run_next_test();
- do_test_finished();
- }
-};
-
-function test_spdy_concurrent() {
- var concurrent_listener = new SpdyConcurrentListener();
- concurrent_listener.target = 201;
- for (var i = 0; i < concurrent_listener.target; i++) {
- concurrent_channels[i] = makeChan("https://localhost:" + serverPort + "/750ms");
- concurrent_channels[i].loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE;
- concurrent_channels[i].asyncOpen2(concurrent_listener);
- }
-}
-
-// Test to make sure we get multiplexing right
-function test_spdy_multiplex() {
- var chan1 = makeChan("https://localhost:" + serverPort + "/multiplex1");
- var chan2 = makeChan("https://localhost:" + serverPort + "/multiplex2");
- var listener1 = new SpdyMultiplexListener();
- var listener2 = new SpdyMultiplexListener();
- chan1.asyncOpen2(listener1);
- chan2.asyncOpen2(listener2);
-}
-
-// Test to make sure we gateway non-standard headers properly
-function test_spdy_header() {
- var chan = makeChan("https://localhost:" + serverPort + "/header");
- var hvalue = "Headers are fun";
- var listener = new SpdyHeaderListener(hvalue);
- chan.setRequestHeader("X-Test-Header", hvalue, false);
- chan.asyncOpen2(listener);
-}
-
-function test_spdy_push1() {
- var chan = makeChan("https://localhost:" + serverPort + "/push");
- chan.loadGroup = loadGroup;
- var listener = new SpdyPushListener();
- chan.asyncOpen2(listener);
-}
-
-function test_spdy_push2() {
- var chan = makeChan("https://localhost:" + serverPort + "/push.js");
- chan.loadGroup = loadGroup;
- var listener = new SpdyPushListener();
- chan.asyncOpen2(listener);
-}
-
-function test_spdy_push3() {
- var chan = makeChan("https://localhost:" + serverPort + "/push2");
- chan.loadGroup = loadGroup;
- var listener = new SpdyPushListener();
- chan.asyncOpen2(listener);
-}
-
-function test_spdy_push4() {
- var chan = makeChan("https://localhost:" + serverPort + "/push2.js");
- chan.loadGroup = loadGroup;
- var listener = new SpdyPushListener();
- chan.asyncOpen2(listener);
-}
-
-// Make sure we handle GETs that cover more than 2 frames properly
-function test_spdy_big() {
- var chan = makeChan("https://localhost:" + serverPort + "/big");
- var listener = new SpdyBigListener();
- chan.asyncOpen2(listener);
-}
-
-// Make sure we handle big GETs with suspend/resume
-function test_spdy_big_and_slow() {
- var chan = makeChan("https://localhost:" + serverPort + "/huge");
- var listener = new SpdyBigListener();
- chan.asyncOpen2(listener);
- chan.suspend();
- do_timeout(750, chan.resume);
-}
-
-// Support for doing a POST
-function do_post(content, chan, listener) {
- var stream = Cc["@mozilla.org/io/string-input-stream;1"]
- .createInstance(Ci.nsIStringInputStream);
- stream.data = content;
-
- var uchan = chan.QueryInterface(Ci.nsIUploadChannel);
- uchan.setUploadStream(stream, "text/plain", stream.available());
-
- chan.requestMethod = "POST";
-
- chan.asyncOpen2(listener);
-}
-
-// Make sure we can do a simple POST
-function test_spdy_post() {
- var chan = makeChan("https://localhost:" + serverPort + "/post");
- var listener = new SpdyPostListener(md5s[0]);
- do_post(posts[0], chan, listener);
-}
-
-// Make sure we can do a POST that covers more than 2 frames
-function test_spdy_post_big() {
- var chan = makeChan("https://localhost:" + serverPort + "/post");
- var listener = new SpdyPostListener(md5s[1]);
- do_post(posts[1], chan, listener);
-}
-
-function test_complete() {
- resetPrefs();
- do_test_finished();
- do_timeout(0,run_next_test);
-}
-
-// hack - the header test resets the multiplex object on the server,
-// so make sure header is always run before the multiplex test.
-//
-// make sure post_big runs first to test race condition in restarting
-// a stalled stream when a SETTINGS frame arrives
-var tests = [ test_spdy_post_big
- , test_spdy_basic
- , test_spdy_concurrent
- , test_spdy_push1
- , test_spdy_push2
- , test_spdy_push3
- , test_spdy_push4
- , test_spdy_xhr
- , test_spdy_header
- , test_spdy_multiplex
- , test_spdy_big
- , test_spdy_big_and_slow
- , test_spdy_post
- // cleanup
- , test_complete
- ];
-var current_test = 0;
-
-function run_next_test() {
- if (current_test < tests.length) {
- tests[current_test]();
- current_test++;
- do_test_pending();
- }
-}
-
-// Support for making sure we can talk to the invalid cert the server presents
-var CertOverrideListener = function(host, port, bits) {
- this.host = host;
- if (port) {
- this.port = port;
- }
- this.bits = bits;
-};
-
-CertOverrideListener.prototype = {
- host: null,
- port: -1,
- bits: null,
-
- getInterface: function(aIID) {
- return this.QueryInterface(aIID);
- },
-
- QueryInterface: function(aIID) {
- if (aIID.equals(Ci.nsIBadCertListener2) ||
- aIID.equals(Ci.nsIInterfaceRequestor) ||
- aIID.equals(Ci.nsISupports))
- return this;
- throw Components.results.NS_ERROR_NO_INTERFACE;
- },
-
- notifyCertProblem: function(socketInfo, sslStatus, targetHost) {
- var cert = sslStatus.QueryInterface(Ci.nsISSLStatus).serverCert;
- var cos = Cc["@mozilla.org/security/certoverride;1"].
- getService(Ci.nsICertOverrideService);
- cos.rememberValidityOverride(this.host, this.port, cert, this.bits, false);
- dump("Certificate Override in place\n");
- return true;
- },
-};
-
-function addCertOverride(host, port, bits) {
- var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
- .createInstance(Ci.nsIXMLHttpRequest);
- try {
- var url;
- if (port) {
- url = "https://" + host + ":" + port + "/";
- } else {
- url = "https://" + host + "/";
- }
- req.open("GET", url, false);
- req.channel.notificationCallbacks = new CertOverrideListener(host, port, bits);
- req.send(null);
- } catch (e) {
- // This will fail since the server is not trusted yet
- }
-}
-
-var prefs;
-var spdypref;
-var spdy3pref;
-var spdypush;
-var loadGroup;
-var serverPort;
-
-function resetPrefs() {
- prefs.setBoolPref("network.http.spdy.enabled", spdypref);
- prefs.setBoolPref("network.http.spdy.enabled.v3-1", spdy3pref);
- prefs.setBoolPref("network.http.spdy.allow-push", spdypush);
-}
-
-function run_test() {
- var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
- serverPort = env.get("MOZSPDY_PORT");
- do_check_neq(serverPort, null);
- dump("using port " + serverPort + "\n");
-
- // Set to allow the cert presented by our SPDY server
- do_get_profile();
- prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
- var oldParallel = prefs.getIntPref("network.http.speculative-parallel-limit");
- prefs.setIntPref("network.http.speculative-parallel-limit", 0);
-
- addCertOverride("localhost", serverPort,
- Ci.nsICertOverrideService.ERROR_UNTRUSTED |
- Ci.nsICertOverrideService.ERROR_MISMATCH |
- Ci.nsICertOverrideService.ERROR_TIME);
- prefs.setIntPref("network.http.speculative-parallel-limit", oldParallel);
-
- // Enable all versions of spdy to see that we auto negotiate spdy/3.1
- spdypref = prefs.getBoolPref("network.http.spdy.enabled");
- spdy3pref = prefs.getBoolPref("network.http.spdy.enabled.v3-1");
- spdypush = prefs.getBoolPref("network.http.spdy.allow-push");
- prefs.setBoolPref("network.http.spdy.enabled", true);
- prefs.setBoolPref("network.http.spdy.enabled.v3-1", true);
- prefs.setBoolPref("network.http.spdy.allow-push", true);
-
- loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup);
-
- run_next_test();
-}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -278,20 +278,17 @@ fail-if = os == "android"
[test_resumable_channel.js]
[test_resumable_truncate.js]
[test_safeoutputstream.js]
[test_simple.js]
[test_sockettransportsvc_available.js]
[test_socks.js]
# Bug 675039: test fails consistently on Android
fail-if = os == "android"
-# spdy and http2 unit tests require us to have node available to run the spdy and http2 server
-[test_spdy.js]
-skip-if = !hasNode
-run-sequentially = node server exceptions dont replay well
+# http2 unit tests require us to have node available to run the spdy and http2 server
[test_http2.js]
skip-if = !hasNode
run-sequentially = node server exceptions dont replay well
[test_altsvc.js]
skip-if = !hasNode
run-sequentially = node server exceptions dont replay well
[test_speculative_connect.js]
[test_standardurl.js]
deleted file mode 100644
--- a/testing/xpcshell/moz-spdy/README.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Test server for SPDY unit tests. To run it, you need node >= 0.7.0 (not provided)
-and node-spdy (provided). Just run
-
-node /path/to/moz-spdy.js
-
-And you will get a SPDY server listening on port 4443, then you can run the
-xpcshell unit tests in netwerk/test/unit/test_spdy.js
-
-*** A NOTE ON TLS CERTIFICATES ***
-
-The certificates used for this test (*.pem in this directory) are the ones
-provided as examples by node-spdy, and are copied directly from keys/ under
-its top-level source directory (slightly renamed to match the option names
-in the options dictionary passed to spdy.createServer).
deleted file mode 100644
--- a/testing/xpcshell/moz-spdy/moz-spdy.js
+++ /dev/null
@@ -1,197 +0,0 @@
-/* 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/. */
-
-var spdy = require('../node-spdy/lib/spdy.js');
-var fs = require('fs');
-var url = require('url');
-var crypto = require('crypto');
-
-function getHttpContent(path) {
- var content = '<!doctype html>' +
- '<html>' +
- '<head><title>HOORAY!</title></head>' +
- '<body>You Win! (by requesting' + path + ')</body>' +
- '</html>';
- return content;
-}
-
-function getHugeContent(size) {
- var content = '';
-
- for (var i = 0; i < size; i++) {
- content += '0';
- }
-
- return content;
-}
-
-/* This takes care of responding to the multiplexed request for us */
-var Multiplex = function() {};
-
-Multiplex.prototype = {
- mp1res: null,
- mp2res: null,
- buf: null,
- mp1start: 0,
- mp2start: 0,
-
- checkReady: function() {
- if (this.mp1res != null && this.mp2res != null) {
- this.buf = getHugeContent(30*1024);
- this.mp1start = 0;
- this.mp2start = 0;
- this.send(this.mp1res, 0);
- setTimeout(function() { this.send(this.mp2res, 0); }.bind(this), 5);
- }
- },
-
- send: function(res, start) {
- var end = start + 1024;
- if (end > this.buf.length)
- end = this.buf.length;
- var content = this.buf.substring(start, end);
- if (end < this.buf.length) {
- res.write(content);
- setTimeout(function() { this.send(res, end); }.bind(this), 10);
- } else {
- res.end(content);
- }
- },
-};
-
-var m = new Multiplex();
-
-var post_hash = null;
-function receivePostData(chunk) {
- post_hash.update(chunk.toString());
-}
-
-function finishPost(res, content) {
- var md5 = post_hash.digest('hex');
- res.setHeader('X-Calculated-MD5', md5);
- res.writeHead(200);
- res.end(content);
-}
-
-var runlater = function() {};
-runlater.prototype = {
- req : null,
- resp : null,
-
- onTimeout : function onTimeout() {
- this.resp.writeHead(200);
- this.resp.end("It's all good spdy 750ms.");
- }
-};
-
-function executeRunLater(arg) {
- arg.onTimeout();
-}
-
-function handleRequest(req, res) {
- var u = url.parse(req.url);
- var content = getHttpContent(u.pathname);
-
- if (req.streamID) {
- res.setHeader('X-Connection-Spdy', 'yes');
- res.setHeader('X-Spdy-StreamId', '' + req.streamID);
- } else {
- res.setHeader('X-Connection-Spdy', 'no');
- }
-
- if (u.pathname === '/750ms') {
- var rl = new runlater();
- rl.req = req;
- rl.resp = res;
- setTimeout(executeRunLater, 750, rl);
- return;
- }
-
- if (u.pathname == '/exit') {
- res.setHeader('Content-Type', 'text/plain');
- res.writeHead(200);
- res.end('ok');
- process.exit();
- } else if (u.pathname == '/multiplex1' && req.streamID) {
- res.setHeader('Content-Type', 'text/plain');
- res.writeHead(200);
- m.mp1res = res;
- m.checkReady();
- return;
- } else if (u.pathname == '/multiplex2' && req.streamID) {
- res.setHeader('Content-Type', 'text/plain');
- res.writeHead(200);
- m.mp2res = res;
- m.checkReady();
- return;
- } else if (u.pathname == "/header") {
- m = new Multiplex();
- var val = req.headers["x-test-header"];
- if (val) {
- res.setHeader("X-Received-Test-Header", val);
- }
- } else if (u.pathname == "/push") {
- var stream = res.push('/push.js',
- { 'content-type': 'application/javascript',
- 'pushed' : 'yes',
- 'content-length' : 11,
- 'X-Connection-Spdy': 'yes'});
- stream.on('error', function(){});
- stream.end('// comments');
- content = '<head> <script src="push.js"/></head>body text';
- } else if (u.pathname == "/push2") {
- var stream = res.push('/push2.js',
- { 'content-type': 'application/javascript',
- 'pushed' : 'yes',
- // no content-length
- 'X-Connection-Spdy': 'yes'});
- stream.on('error', function(){});
- stream.end('// comments');
- content = '<head> <script src="push2.js"/></head>body text';
- } else if (u.pathname == "/big") {
- content = getHugeContent(128 * 1024);
- var hash = crypto.createHash('md5');
- hash.update(content);
- var md5 = hash.digest('hex');
- res.setHeader("X-Expected-MD5", md5);
- } else if (u.pathname == "/huge") {
- content = getHugeContent(800 * 1024);
- } else if (u.pathname == "/post") {
- if (req.method != "POST") {
- res.writeHead(405);
- res.end('Unexpected method: ' + req.method);
- return;
- }
-
- post_hash = crypto.createHash('md5');
- req.on('data', receivePostData);
- req.on('end', function () { finishPost(res, content); });
-
- return;
- }
-
- res.setHeader('Content-Type', 'text/html');
- res.writeHead(200);
- res.end(content);
-}
-
-// Set up the SSL certs for our server
-var options = {
- key: fs.readFileSync(__dirname + '/spdy-key.pem'),
- cert: fs.readFileSync(__dirname + '/spdy-cert.pem'),
- ca: fs.readFileSync(__dirname + '/spdy-ca.pem'),
- windowSize: 16000000,
-};
-
-function listenok() {
- console.log('SPDY server listening on port ' + webServer.address().port);
-}
-
-var webServer = spdy.createServer(options, handleRequest).listen(0, "0.0.0.0", 200, listenok);
-
-// Set up to exit when the user finishes our stdin
-process.stdin.resume();
-process.stdin.on('end', function () {
- process.exit();
-});
deleted file mode 100644
--- a/testing/xpcshell/moz-spdy/spdy-ca.pem
+++ /dev/null
@@ -1,11 +0,0 @@
------BEGIN CERTIFICATE REQUEST-----
-MIIBkzCB/QIBADBUMQswCQYDVQQGEwJSVTETMBEGA1UECBMKU29tZS1TdGF0ZTEN
-MAsGA1UEBxMET21zazEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk
-MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVufbmw+S/jrCXvQF9/Gtp2WRF
-3/Gnld/wcOE9J/M01y0RFiyVdPZ9fsOZ93nDVdNWqoaoniLOnlV7ChU4cDy5q+je
-i+mA1ZqyKXnMANZozVPSedXRGwVtlbM5OabVTcPjwrytbcXmQ5np/jJGr1BPWAX+
-A3vk+3j3hjJjIm79rwIDAQABoAAwDQYJKoZIhvcNAQEFBQADgYEAiNWhz6EppIVa
-FfUaB3sLeqfamb9tg9kBHtvqj/FJni0snqms0kPWaTySEPHZF0irIb7VVdq/sVCb
-3gseMVSyoDvPJ4lHC3PXqGQ7kM1mIPhDnR/4HDA3BhlGhTXSDIHgZnvI+HMBdsyC
-hC3dz5odyKqe4nmoofomALkBL9t4H8s=
------END CERTIFICATE REQUEST-----
deleted file mode 100644
--- a/testing/xpcshell/moz-spdy/spdy-cert.pem
+++ /dev/null
@@ -1,14 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICHzCCAYgCCQCPPSUAa8QZojANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJS
-VTETMBEGA1UECBMKU29tZS1TdGF0ZTENMAsGA1UEBxMET21zazEhMB8GA1UEChMY
-SW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTExMDQwOTEwMDY0NVoXDTExMDUw
-OTEwMDY0NVowVDELMAkGA1UEBhMCUlUxEzARBgNVBAgTClNvbWUtU3RhdGUxDTAL
-BgNVBAcTBE9tc2sxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCB
-nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1bn25sPkv46wl70BffxradlkRd/x
-p5Xf8HDhPSfzNNctERYslXT2fX7Dmfd5w1XTVqqGqJ4izp5VewoVOHA8uavo3ovp
-gNWasil5zADWaM1T0nnV0RsFbZWzOTmm1U3D48K8rW3F5kOZ6f4yRq9QT1gF/gN7
-5Pt494YyYyJu/a8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQBuRZisIViI2G/R+w79
-vk21TzC/cJ+O7tKsseDqotXYTH8SuimEH5IWcXNgnWhNzczwN8s2362NixyvCipV
-yd4wzMpPbjIhnWGM0hluWZiK2RxfcqimIBjDParTv6CMUIuwGQ257THKY8hXGg7j
-Uws6Lif3P9UbsuRiYPxMgg98wg==
------END CERTIFICATE-----
deleted file mode 100644
--- a/testing/xpcshell/moz-spdy/spdy-key.pem
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQDVufbmw+S/jrCXvQF9/Gtp2WRF3/Gnld/wcOE9J/M01y0RFiyV
-dPZ9fsOZ93nDVdNWqoaoniLOnlV7ChU4cDy5q+jei+mA1ZqyKXnMANZozVPSedXR
-GwVtlbM5OabVTcPjwrytbcXmQ5np/jJGr1BPWAX+A3vk+3j3hjJjIm79rwIDAQAB
-AoGAAv2QI9h32epQND9TxwSCKD//dC7W/cZOFNovfKCTeZjNK6EIzKqPTGA6smvR
-C1enFl5adf+IcyWqAoe4lkqTvurIj+2EhtXdQ8DBlVuXKr3xvEFdYxXPautdTCF6
-KbXEyS/s1TZCRFjYftvCrXxc3pK45AQX/wg7z1K+YB5pyIECQQD0OJvLoxLYoXAc
-FZraIOZiDsEbGuSHqoCReFXH75EC3+XGYkH2bQ/nSIZ0h1buuwQ/ylKXOlTPT3Qt
-Xm1OQEBvAkEA4AjWsIO/rRpOm/Q2aCrynWMpoUXTZSbL2yGf8pxp/+8r2br5ier0
-M1LeBb/OPY1+k39NWLXxQoo64xoSFYk2wQJAd2wDCwX4HkR7HNCXw1hZL9QFK6rv
-20NN0VSlpboJD/3KT0MW/FiCcVduoCbaJK0Au+zEjDyy4hj5N4I4Mw6KMwJAXVAx
-I+psTsxzS4/njXG+BgIEl/C+gRYsuMQDnAi8OebDq/et8l0Tg8ETSu++FnM18neG
-ntmBeMacinUUbTXuwQJBAJp/onZdsMzeVulsGrqR1uS+Lpjc5Q1gt5ttt2cxj91D
-rio48C/ZvWuKNE8EYj2ALtghcVKRvgaWfOxt2GPguGg=
------END RSA PRIVATE KEY-----
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/README.md
+++ /dev/null
@@ -1,262 +0,0 @@
-# SPDY Server for node.js [](http://travis-ci.org/indutny/node-spdy)
-
-<a href="http://flattr.com/thing/758213/indutnynode-spdy-on-GitHub" target="_blank">
-<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a>
-
-With this module you can create [SPDY](http://www.chromium.org/spdy) servers
-in node.js with natural http module interface and fallback to regular https
-(for browsers that don't support SPDY yet).
-
-## Usage
-
-Server:
-```javascript
-var spdy = require('spdy'),
- fs = require('fs');
-
-var options = {
- key: fs.readFileSync(__dirname + '/keys/spdy-key.pem'),
- cert: fs.readFileSync(__dirname + '/keys/spdy-cert.pem'),
- ca: fs.readFileSync(__dirname + '/keys/spdy-ca.pem'),
-
- // **optional** SPDY-specific options
- windowSize: 1024 * 1024, // Server's window size
-
- // **optional** if true - server will send 3.1 frames on 3.0 *plain* spdy
- autoSpdy31: false
-};
-
-var server = spdy.createServer(options, function(req, res) {
- res.writeHead(200);
- res.end('hello world!');
-});
-
-server.listen(3000);
-```
-
-Client:
-```javascript
-var spdy = require('spdy');
-var http = require('http');
-
-var agent = spdy.createAgent({
- host: 'www.google.com',
- port: 443,
-
- // Optional SPDY options
- spdy: {
- plain: false or true,
- ssl: false or true,
- version: 3 // Force SPDY version
- }
-});
-
-http.get({
- host: 'www.google.com',
- agent: agent
-}, function(response) {
- console.log('yikes');
- // Here it goes like with any other node.js HTTP request
- // ...
- // And once we're done - we may close TCP connection to server
- // NOTE: All non-closed requests will die!
- agent.close();
-}).end();
-```
-
-And by popular demand - usage with
-[express](https://github.com/visionmedia/express):
-
-```javascript
-var spdy = require('spdy'),
- express = require('express'),
- fs = require('fs');
-
-var options = { /* the same as above */ };
-
-var app = express();
-
-app.use(/* your favorite middleware */);
-
-var server = spdy.createServer(options, app);
-
-server.listen(3000);
-```
-
-## API
-
-API is compatible with `http` and `https` module, but you can use another
-function as base class for SPDYServer.
-
-```javascript
-spdy.createServer(
- [base class constructor, i.e. https.Server],
- { /* keys and options */ }, // <- the only one required argument
- [request listener]
-).listen([port], [host], [callback]);
-```
-
-Request listener will receive two arguments: `request` and `response`. They're
-both instances of `http`'s `IncomingMessage` and `OutgoingMessage`. But three
-custom properties are added to both of them: `streamID`, `isSpdy`,
-`spdyVersion`. The first one indicates on which spdy stream are sitting request
-and response. Second is always true and can be checked to ensure that incoming
-request wasn't received by HTTPS fallback and last one is a number representing
-used SPDY protocol version (2 or 3 for now).
-
-### Push streams
-
-It is possible to initiate 'push' streams to send content to clients _before_
-the client requests it.
-
-```javascript
-spdy.createServer(options, function(req, res) {
- var headers = { 'content-type': 'application/javascript' };
- var stream = res.push('/main.js', headers);
- stream.on('acknowledge', function() {
- });
- stream.on('error', function() {
- });
- stream.end('alert("hello from push stream!");');
-
- res.end('<script src="/main.js"></script>');
-}).listen(3000);
-```
-
-The method is also avaliable when using SPDY with an Express server:
-
-```javascript
-var app = express();
-
-var server = spdy.createServer(options, app);
-
-app.get('/', function(req, res) {
- var headers = { 'content-type': 'application/javascript' };
- res.push('/main.js', headers, function(err, stream) {
- stream.on('acknowledge', function() {
- });
-
- stream.on('error', function() {
- });
-
- stream.end('alert("hello from push stream!");');
- });
-
- res.end('<script src="/main.js"></script>');
-});
-
-server.listen(3000);
-```
-
-
-Push is accomplished via the `push()` method invoked on the current response
-object (this works for express.js response objects as well). The format of the
-`push()` method is:
-
-`.push('full or relative url', { ... headers ... }, optional priority, callback)`
-
-You can use either full ( `http://host/path` ) or relative ( `/path` ) urls with
-`.push()`. `headers` are the same as for regular response object. `callback`
-will receive two arguments: `err` (if any error is happened) and `stream`
-(stream object have API compatible with a
-[net.Socket](http://nodejs.org/docs/latest/api/net.html#net.Socket) ).
-
-Client usage:
-```javascript
-var agent = spdy.createAgent({ /* ... */ });
-agent.on('push', function(stream) {
- stream.on('error', function(err) {
- // Handle error
- });
- // Read data from stream
- // ...
- // stream.associated points to associated client-initiated stream
-});
-```
-
-NOTE: You're responsible for the `stream` object once given it in `.push()`
-callback. Hence ignoring `error` events on it might result in uncaught
-exceptions and crash your program.
-
-### Trailing headers
-
-Server usage:
-```javascript
-function (req, res) {
- // Send trailing headers to client
- res.addTrailers({ header1: 'value1', header2: 'value2' });
-
- // On client's trailing headers
- req.on('trailers', function(headers) {
- // ...
- });
-}
-```
-
-Client usage:
-```javascript
-var req = http.request({ agent: spdyAgent, /* ... */ }).function (res) {
- // On server's trailing headers
- res.on('trailers', function(headers) {
- // ...
- });
-});
-req.write('stuff');
-req.addTrailers({ /* ... */ });
-req.end();
-```
-
-### Options
-
-All options supported by
-[tls](http://nodejs.org/docs/latest/api/tls.html#tls.createServer) are working
-with node-spdy. In addition, `maxStreams` options is available. it allows you
-controlling [maximum concurrent streams](http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft2#TOC-SETTINGS)
-protocol option (if client will start more streams than that limit, RST_STREAM
-will be sent for each additional stream).
-
-Additional options:
-
-* `plain` - if defined, server will ignore NPN and ALPN data and choose whether
- to use spdy or plain http by looking at first data packet.
-* `ssl` - if `false` and `options.plain` is `true`, `http.Server` will be used
- as a `base` class for created server.
-* `maxChunk` - if set and non-falsy, limits number of bytes sent in one DATA
- chunk. Setting it to non-zero value is recommended if you care about
- interleaving of outgoing data from multiple different streams.
- (defaults to 8192)
-
-#### Contributors
-
-* [Fedor Indutny](https://github.com/indutny)
-* [Chris Strom](https://github.com/eee-c)
-* [François de Metz](https://github.com/francois2metz)
-* [Ilya Grigorik](https://github.com/igrigorik)
-* [Roberto Peon](https://github.com/grmocg)
-* [Tatsuhiro Tsujikawa](https://github.com/tatsuhiro-t)
-* [Jesse Cravens](https://github.com/jessecravens)
-
-#### LICENSE
-
-This software is licensed under the MIT License.
-
-Copyright Fedor Indutny, 2014.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to permit
-persons to whom the Software is furnished to do so, subject to the
-following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-USE OR OTHER DEALINGS IN THE SOFTWARE.
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/keys/spdy-cert.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDBjCCAe4CCQCC8qgopCwXKDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
-VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
-cyBQdHkgTHRkMB4XDTEzMDEwODEyMzYyM1oXDTIzMDEwNjEyMzYyM1owRTELMAkG
-A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
-IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
-ALYWwPVTdWu+55Y9WKcZKi+iC/BVoV6uejF/7twOQZRAMAs2rFhCnxmds8d7jcX6
-wBHOejKFYqbm9WPORckieOVmHRHYLhzCXHrhYMHSYW5NxwTCxdka+QEzoFJqBSwO
-AkBQaF9ETA/GDa22TGN0DqUAtH6AiT3FAf4lSng1gLnMaa6+jYDmHmGHf2epRw+N
-U8Kb4g8iNLPP10M3x1DIlVtB2MvXgHFY5/fz4BSD8QweqUGaoIuAcLdJ6qJmbztm
-FWCWmr3uNHo2V6KxjHMMpziCa+280im6OgsdsgMuQO949hk+5k+PZ/WR+Ia4NylE
-FI6cVXpZwALAVWxC9VO1oocCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAluAKUeNS
-brX8+Jr7hOEftd+maTb8ERV4CU2wFSeCqupoSGh4Er37FO+eL1cAzaewpQzx8Uvp
-q7oO+utrOKGA42P0bkdX6vqXZ73seorKl4Mv6Lnq1z1uTRTQyAbvJpv6mYrr+oz5
-QgTGvPqUWqpv+OPf2R9J00IVLlfIjdKGLt0iZ3QEeS6SDkV/MHT4fEc9fImsg6Rq
-xcb8kmcv9GAHo7YzxOw2F85h93epl6zUUlW2QCzUbvEF2S5NQowdkDQz0py6o4tv
-S5Dh5XYLDm7gjcRElLNLaTmdhq9IGBEdbXy6a9kzJqZz4+AOn5+WPnA/KhVhWoTE
-nJHIzjR3CQEkbA==
------END CERTIFICATE-----
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/keys/spdy-csr.pem
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE REQUEST-----
-MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx
-ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBALYWwPVTdWu+55Y9WKcZKi+iC/BVoV6uejF/7twO
-QZRAMAs2rFhCnxmds8d7jcX6wBHOejKFYqbm9WPORckieOVmHRHYLhzCXHrhYMHS
-YW5NxwTCxdka+QEzoFJqBSwOAkBQaF9ETA/GDa22TGN0DqUAtH6AiT3FAf4lSng1
-gLnMaa6+jYDmHmGHf2epRw+NU8Kb4g8iNLPP10M3x1DIlVtB2MvXgHFY5/fz4BSD
-8QweqUGaoIuAcLdJ6qJmbztmFWCWmr3uNHo2V6KxjHMMpziCa+280im6OgsdsgMu
-QO949hk+5k+PZ/WR+Ia4NylEFI6cVXpZwALAVWxC9VO1oocCAwEAAaAAMA0GCSqG
-SIb3DQEBBQUAA4IBAQCuMWhXWTpHDZTYFtkasd/b02D45RyyQTYNvw0qS67rBKnj
-52YvHKXvdjXe+TFuEzq6G7QAa7cgcdv12ffzboa8l9E4hY4OTO/lysCB1gMxgpTg
-ulDFRTQrIgCjrIm4rIGkFj47VL0ieSRhU4bf9npQydXdaYk0DHOxpLdGrs85LbZf
-lt/5Bsls9bSsh+JYcgoOPYxcgKBzhingh/FV93HQ39JHxtcqkrpZqrfNfHSVr9gT
-t+YyvUh0ctO5oGEfQj27Ewk3yt1nwgCETP55yCUhWIhJF5ATSFqm0nfeS1QYHMcU
-27Hcp+20/4D4MbZ04gi4bi6Z92DawssfKfow/B4u
------END CERTIFICATE REQUEST-----
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/keys/spdy-key.pem
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEowIBAAKCAQEAthbA9VN1a77nlj1YpxkqL6IL8FWhXq56MX/u3A5BlEAwCzas
-WEKfGZ2zx3uNxfrAEc56MoVipub1Y85FySJ45WYdEdguHMJceuFgwdJhbk3HBMLF
-2Rr5ATOgUmoFLA4CQFBoX0RMD8YNrbZMY3QOpQC0foCJPcUB/iVKeDWAucxprr6N
-gOYeYYd/Z6lHD41TwpviDyI0s8/XQzfHUMiVW0HYy9eAcVjn9/PgFIPxDB6pQZqg
-i4Bwt0nqomZvO2YVYJaave40ejZXorGMcwynOIJr7bzSKbo6Cx2yAy5A73j2GT7m
-T49n9ZH4hrg3KUQUjpxVelnAAsBVbEL1U7WihwIDAQABAoIBACdvHBDFJ0vTRzI5
-TOa7Q3CXZoCA+vaXUK1BqIgNqlQh5oW3LHHc07nndlTARD7ZBBmXHs2sJ2Y/5Grd
-9C0QAyCjEa6Yo7vkt8SA5MR0/Fa4D17Pk6tl9QE2ngTbIw2cZw5om4HuN46+9J1n
-OnnbW4SOd4hh69btwHW6u7r2007pQXme0AMlAxhgfIEiD6tHjqZDCtK4G0d+GSq6
-Ks/IpXckLcrluqJ2gHVB2sbBbjh1m7dHCVzBKynCwaHrWbNla8P6j3SdabP4Umcb
-tu3hP3nLigMJmA16KdkayUg05OvUTBAkReLcVZYZQ80LmM+NioB6UvwYy677h4ma
-XFihvLkCgYEA3aLOY2rve6DxvTXDJe8D91V//+5B9XBcyLP2cMEXIP+3W9Gto9tz
-vTIOcwj8MLKh22KBBMCP7OQlXFalBoG/d5Y9YKr6X2XHBcEw96Nm1HZctUPRPQdd
-+C8S5ikwTre9QMfLmLGKzgfIpDRYyijv0ZQZw+8qlNATtVrAMQGu6D0CgYEA0lI9
-zXK+4P28+SkkCUIG/Y31wF4KeM8V5s8eUYej8LV67GQIGs9XPCEIJY2cHZpn7qD8
-H90lucr90rwAHN2rLUSdq28NVL0+RTYKNBFRRvPNloLlKOR9RvorsFz5U4z48i9x
-yZ6gk+WL0ycc2oUFfihmQpHhRUiV46IB7deEXhMCgYEA1rW+3V8eC5VaOuOXXutS
-20vwCX7GVUB6ElENICRfBK/V8NSLM98IG7QffV+p+H9E/+RIetMVWveWHgMuMcSG
-ORLJ+RkKHlrZ2IBUsMKSfqb/nvbJACdf6GuqEmC6lLe5VsV3PkBY6MlvnWu8zHOm
-CFFCOKc8iBef0CPPZmpsCD0CgYAOtS+bOWX9x+C6L9VUTGi+vHmuDSWAU0L91AgT
-vX+KaraA53HlphA8pTazoZaEP3L7LgjTlZx4xKhBX2JGon3A+aZpAagV//Hl1ySZ
-hYiAhLYgy2CJHolgOEhr2eSZoicakJTNe6lRDmFbz8Vlxp2et+aGyzrMpInO1Fp8
-LnEUPwKBgExMk6THLz8CzjJhaKDrNn1fSs6jUxgK12+1cIJxb5JEgRJs4W+yFuLw
-exCE5YKPwnZNrbji+bdkk9FwHPLuf20aH5fIB0UlMMVcvLGKyxYl7BG1pShN4k8C
-kKXaClwkngJ2eSs/AsNAe9hhbEpFjAHt+3D7Sbg8EvgeCwdjnIxw
------END RSA PRIVATE KEY-----
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy.js
+++ /dev/null
@@ -1,29 +0,0 @@
-var spdy = exports;
-
-// Exports utils
-spdy.utils = require('./spdy/utils');
-
-// Export parser&framer
-spdy.protocol = require('./spdy/protocol');
-
-// Export ServerResponse
-spdy.response = require('./spdy/response');
-
-// Export Scheduler
-spdy.scheduler = require('./spdy/scheduler');
-
-// Export ZlibPool
-spdy.zlibpool = require('./spdy/zlib-pool');
-
-// Export Connection and Stream
-spdy.Stream = require('./spdy/stream').Stream;
-spdy.Connection = require('./spdy/connection').Connection;
-
-// Export server
-spdy.server = require('./spdy/server');
-spdy.Server = spdy.server.Server;
-spdy.createServer = spdy.server.create;
-
-// Export client
-spdy.Agent = require('./spdy/client').Agent;
-spdy.createAgent = require('./spdy/client').create;
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/client.js
+++ /dev/null
@@ -1,230 +0,0 @@
-var spdy = require('../spdy');
-var assert = require('assert');
-var util = require('util');
-var net = require('net');
-var https = require('https');
-var EventEmitter = require('events').EventEmitter;
-
-var proto = {};
-
-function instantiate(base) {
- function Agent(options) {
- base.call(this, options);
-
- if (!this.options.spdy)
- this.options.spdy = {};
-
- this._init();
-
- // Hack for node.js v0.10
- this.createConnection = proto.createConnection;
-
- // No chunked encoding
- this.keepAlive = false;
- };
- util.inherits(Agent, base);
-
- // Copy prototype methods
- Object.keys(proto).forEach(function(key) {
- this[key] = proto[key];
- }, Agent.prototype);
-
- return Agent;
-};
-
-proto._init = function init() {
- var self = this;
-
- var state = {};
- // Find super's `createConnection` method
- var createConnection;
- var cons = this.constructor.super_;
- do {
- createConnection = cons.prototype.createConnection;
-
- if (cons.super_ === EventEmitter || !cons.super_)
- break;
- cons = cons.super_;
- } while (!createConnection);
-
- if (!createConnection)
- createConnection = this.createConnection || net.createConnection;
-
- // TODO(indutny): Think about falling back to http/https
- var socket = createConnection.call(this, util._extend({
- NPNProtocols: ['spdy/3.1', 'spdy/3', 'spdy/2'],
- ALPNProtocols: ['spdy/3.1', 'spdy/3', 'spdy/2']
- }, this.options));
- state.socket = socket;
-
- // Header compression is disabled by default in clients to prevent CRIME
- // attacks. Don't enable it unless you know what you're doing.
- if (this.options.spdy.headerCompression !== true)
- this.options.spdy.headerCompression = false;
-
- // Create SPDY connection using newly created socket
- var connection = new spdy.Connection(socket,
- util._extend(this.options.spdy, {
- isServer: false
- }));
- state.connection = connection;
-
- connection.on('error', function(err) {
- self.emit('error', err);
- });
-
- // Select SPDY version
- if (this.options.spdy.ssl !== false && !this.options.spdy.version) {
- // SSL, wait for NPN or ALPN to happen
- socket.once('secureConnect', function() {
- var selectedProtocol = socket.npnProtocol || socket.alpnProtocol;
- if (selectedProtocol === 'spdy/2')
- connection._setVersion(2);
- else if (selectedProtocol === 'spdy/3')
- connection._setVersion(3);
- else if (selectedProtocol === 'spdy/3.1')
- connection._setVersion(3.1);
- else
- socket.emit('error', new Error('No supported SPDY version'));
- });
- } else {
- // No SSL, use fixed version
- connection._setVersion(this.options.spdy.version || 3);
- }
-
- // Destroy PUSH streams until the listener will be added
- connection.on('stream', function(stream) {
- stream.on('error', function() {});
- stream.destroy();
- });
- state.pushServer = null;
-
- this.on('newListener', this._onNewListener.bind(this));
- this.on('removeListener', this._onRemoveListener.bind(this));
-
- // Client has odd-numbered stream ids
- state.id = 1;
- this._spdyState = state;
-};
-
-//
-// ### function onNewListener (type, listener)
-// #### @type {String} Event type
-// #### @listener {Function} Listener callback
-//
-proto._onNewListener = function onNewListener(type, listener) {
- if (type !== 'push')
- return;
-
- var state = this._spdyState;
- if (state.pushServer)
- return state.pushServer.on('translated-request', listener);
-
- state.pushServer = require('http').createServer(listener);
- state.connection.removeAllListeners('stream');
- state.connection.on('stream', function(stream) {
- state.pushServer.emit('connection', stream);
- });
-
- state.pushServer.on('request', function(req) {
- // Populate trailing headers
- req.connection.on('headers', function(headers) {
- Object.keys(headers).forEach(function(key) {
- req.trailers[key] = headers[key];
- });
- req.emit('trailers', headers);
- });
-
- this.emit('translated-request', req);
- });
-};
-
-//
-// ### function onRemoveListener (type, listener)
-// #### @type {String} Event type
-// #### @listener {Function} Listener callback
-//
-proto._onRemoveListener = function onRemoveListener(type, listener) {
- if (type !== 'push')
- return;
-
- var state = this._spdyState;
- if (!state.pushServer)
- return;
-
- state.pushServer.removeListener('translated-request', listener);
-};
-
-//
-// ### function createConnection (options)
-//
-proto.createConnection = function createConnection(options) {
- if (!options)
- options = {};
-
- var state = this._spdyState;
- var stream = new spdy.Stream(state.connection, {
- id: state.id,
- priority: options.priority || 7,
- client: true,
- decompress: options.spdy.decompress == undefined ? true :
- options.spdy.decompress
- });
- state.id += 2;
-
- return stream;
-};
-
-//
-// ### function close (callback)
-// #### @callback {Function}
-// Close underlying socket and terminate all streams
-//
-proto.close = function close(callback) {
- this._spdyState.socket.destroySoon();
- if (callback)
- this._spdyState.socket.once('close', callback);
-};
-
-//
-// ### function ping (callback)
-// #### @callback {Function}
-// Send PING frame and invoke callback once received it back
-//
-proto.ping = function ping(callback) {
- return this._spdyState.connection.ping(callback);
-};
-
-//
-// Default Agent
-//
-exports.Agent = instantiate(https.Agent);
-
-//
-// ### function create (base, options)
-// #### @base {Function} (optional) base server class (https.Server)
-// #### @options {Object} tls server options
-// @constructor wrapper
-//
-exports.create = function create(base, options) {
- var agent;
- if (typeof base === 'function') {
- agent = instantiate(base);
- } else {
- agent = exports.Agent;
-
- options = base;
- base = null;
- }
-
- // Instantiate http server if `ssl: false`
- if (!base &&
- options &&
- options.spdy &&
- options.spdy.plain &&
- options.spdy.ssl === false) {
- return exports.create(require('http').Agent, options);
- }
-
- return new agent(options);
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/connection.js
+++ /dev/null
@@ -1,648 +0,0 @@
-var util = require('util');
-var assert = require('assert');
-var spdy = require('../spdy');
-var constants = spdy.protocol.constants;
-
-var Stream = spdy.Stream;
-
-//
-// ### function Connection (socket, state, server)
-// #### @socket {net.Socket} server's connection
-// #### @options {Object} Connection options
-// #### @server {net.Server} server
-// Abstract connection @constructor
-//
-function Connection(socket, options, server) {
- process.EventEmitter.call(this);
-
- var state = {};
- this._spdyState = state;
-
- // NOTE: There's a big trick here. Connection is used as a `this` argument
- // to the wrapped `connection` event listener.
- // socket end doesn't necessarly mean connection drop
- this.httpAllowHalfOpen = true;
-
- // Socket timeout
- this.timeout = server && server.timeout || 0;
-
- // Defaults
- state.maxStreams = options.maxStreams || Infinity;
- state.initialSinkSize = constants.DEFAULT_WINDOW;
- state.initialWindowSize = options.windowSize || 1 << 20;
- state.autoSpdy31 = options.autoSpdy31;
-
- // Connection-level flow control
- state.sinkSize = state.initialSinkSize;
- state.windowSize = constants.DEFAULT_WINDOW;
-
- // Interleaving configuration
- state.maxChunk = options.maxChunk === undefined ? 8 * 1024 : options.maxChunk;
-
- // Various state info
- state.closed = false;
- state.pool = spdy.zlibpool.create(options.headerCompression);
- state.counters = {
- pushCount: 0,
- streamCount: 0
- };
- state.socketBuffering = false;
-
- state.version = null;
- state.deflate = null;
- state.inflate = null;
-
- // Init streams list
- state.isServer = options.isServer;
- state.streams = {};
- state.streamCount = 0;
- state.lastId = 0;
- state.pushId = 0;
- state.pingId = state.isServer ? 0 : 1;
- state.pings = {};
- state.goaway = false;
-
- // X-Forwarded feature
- state.xForward = null;
-
- // Initialize scheduler
- state.scheduler = spdy.scheduler.create(this);
-
- // Create parser and hole for framer
- state.parser = spdy.protocol.parser.create(this);
- state.framer = spdy.protocol.framer.create();
-
- // Lock data
- state.locked = false;
- state.lockQueue = [];
-
- this.socket = socket;
- this.encrypted = socket.encrypted;
- this.readable = true;
- this.writable = true;
-
- this._init();
-}
-util.inherits(Connection, process.EventEmitter);
-exports.Connection = Connection;
-
-Connection.prototype._init = function init() {
- var self = this;
- var state = this._spdyState;
- var pool = state.pool;
- var pair = null;
- var sentSettings = false;
-
- // Initialize parser
- this._spdyState.parser.on('frame', this._handleFrame.bind(this));
-
- this._spdyState.parser.on('version', function onversion(version) {
- var prev = state.version;
- var framer = state.framer;
-
- state.version = version;
-
- // Ignore transition to 3.1
- if (!prev) {
- pair = pool.get('spdy/' + version);
- state.deflate = pair.deflate;
- state.inflate = pair.inflate;
- framer.setCompression(pair.deflate, pair.inflate);
- }
- framer.setVersion(version);
-
- // Send settings frame (once)
- if (!sentSettings) {
- sentSettings = true;
- framer.settingsFrame({
- maxStreams: state.maxStreams,
- windowSize: state.initialWindowSize
- }, function(err, frame) {
- if (err)
- return self.emit('error', err);
- self.write(frame);
- });
-
- // Send WINDOW_UPDATE for 3.1
- self._sendWindowUpdate(true);
- }
- });
-
- // Propagate parser errors
- state.parser.on('error', function onParserError(err) {
- self.emit('error', err);
- });
-
- this.socket.pipe(state.parser);
-
- // 2 minutes socket timeout
- this.socket.setTimeout(this.timeout);
- this.socket.once('timeout', function ontimeout() {
- self.socket.destroy();
- });
-
- // Allow high-level api to catch socket errors
- this.socket.on('error', function onSocketError(e) {
- self.emit('error', e);
- });
-
- this.socket.once('close', function onclose() {
- var err = new Error('socket hang up');
- err.code = 'ECONNRESET';
- self._destroyStreams(err);
- self.emit('close');
-
- state.closed = true;
- if (pair)
- pool.put(pair);
- });
-
- // Do not allow half-open connections
- this.socket.allowHalfOpen = false;
-
- if (spdy.utils.isLegacy) {
- this.socket.on('drain', function ondrain() {
- self.emit('drain');
- });
- }
-
- // for both legacy and non-legacy, when our socket is ready for writes again,
- // drain the sinks in case they were queuing due to socketBuffering.
- this.socket.on('drain', function () {
- if (!state.socketBuffering)
- return;
-
- state.socketBuffering = false;
- Object.keys(state.streams).forEach(function(id) {
- state.streams[id]._drainSink(0);
- });
- });
-};
-
-//
-// ### function handleFrame (frame)
-// #### @frame {Object} SPDY frame
-//
-Connection.prototype._handleFrame = function handleFrame(frame) {
- var state = this._spdyState;
-
- if (state.closed)
- return;
-
- var stream;
-
- // Create new stream
- if (frame.type === 'SYN_STREAM') {
- stream = this._handleSynStream(frame);
- } else {
- if (frame.id !== undefined) {
- // Load created one
- stream = state.streams[frame.id];
-
- // Fail if not found
- if (stream === undefined &&
- !(frame.type === 'WINDOW_UPDATE' && frame.id === 0)) {
- if (frame.type === 'RST_STREAM')
- return;
- this._rst(frame.id, constants.rst.INVALID_STREAM);
- return;
- }
- }
-
- // Emit 'data' event
- if (frame.type === 'DATA') {
- this._handleData(stream, frame);
- // Reply for client stream
- } else if (frame.type === 'SYN_REPLY') {
- // If stream not client - send RST
- if (!stream._spdyState.isClient) {
- this._rst(frame.id, constants.rst.PROTOCOL_ERROR);
- return;
- }
-
- stream._handleResponse(frame);
-
- // Destroy stream if we were asked to do this
- } else if (frame.type === 'RST_STREAM') {
- stream._spdyState.rstCode = 0;
- stream._spdyState.closedBy.us = true;
- stream._spdyState.closedBy.them = true;
-
- // Emit error on destroy
- var err = new Error('Received rst: ' + frame.status);
- err.code = 'RST_STREAM';
- err.status = frame.status;
- stream.destroy(err);
- // Respond with same PING
- } else if (frame.type === 'PING') {
- this._handlePing(frame.pingId);
- } else if (frame.type === 'SETTINGS') {
- this._setDefaultWindow(frame.settings);
- } else if (frame.type === 'GOAWAY') {
- state.goaway = frame.lastId;
- this.writable = false;
- } else if (frame.type === 'WINDOW_UPDATE') {
- if (stream)
- stream._drainSink(frame.delta);
- else
- this._drainSink(frame.delta);
- } else if (frame.type === 'HEADERS') {
- stream.emit('headers', frame.headers);
- } else if (frame.type === 'X_FORWARDED') {
- state.xForward = frame.host;
- } else {
- console.error('Unknown type: ', frame.type);
- }
- }
-
- // Handle half-closed
- if (frame.fin) {
- // Don't allow to close stream twice
- if (stream._spdyState.closedBy.them) {
- stream._spdyState.rstCode = constants.rst.PROTOCOL_ERROR;
- stream.emit('error', 'Already half-closed');
- } else {
- stream._spdyState.closedBy.them = true;
-
- // Receive FIN
- stream._recvEnd();
-
- stream._handleClose();
- }
- }
-};
-
-//
-// ### function handleSynStream (frame)
-// #### @frame {Object} SPDY frame
-//
-Connection.prototype._handleSynStream = function handleSynStream(frame) {
- var state = this._spdyState;
- var associated;
-
- if (state.goaway && state.goaway < frame.id)
- return this._rst(frame.id, constants.rst.REFUSED_STREAM);
-
- // PUSH stream
- if (!state.isServer) {
- // Incorrect frame id
- if (frame.id % 2 === 1 || frame.associated % 2 === 0)
- return this._rst(frame.id, constants.rst.PROTOCOL_ERROR);
-
- associated = state.streams[frame.associated];
-
- // Fail if not found
- if (associated === undefined) {
- if (frame.type === 'RST_STREAM')
- return;
- this._rst(frame.id, constants.rst.INVALID_STREAM);
- return;
- }
- }
-
- var stream = new Stream(this, frame);
-
- // Associate streams
- if (associated) {
- stream.associated = associated;
- }
-
- // TODO(indutny) handle stream limit
- this.emit('stream', stream);
- stream._start(frame.url, frame.headers);
-
- return stream;
-};
-
-//
-// ### function _handleData (stream, frame)
-// #### @stream {Stream} SPDY Stream
-// #### @frame {Object} SPDY frame
-//
-Connection.prototype._handleData = function handleData(stream, frame) {
- var state = this._spdyState;
-
- if (frame.data.length > 0) {
- if (stream._spdyState.closedBy.them) {
- stream._spdyState.rstCode = constants.rst.PROTOCOL_ERROR;
- stream.emit('error', 'Writing to half-closed stream');
- } else {
- // Connection-level flow control
- state.windowSize -= frame.data.length;
- this._sendWindowUpdate();
- stream._recv(frame.data);
- }
- }
-};
-
-//
-// ### function sendWindowUpdate (force)
-// #### @force {Boolean} send even if windowSize is positive
-// Send WINDOW_UPDATE if needed
-//
-Connection.prototype._sendWindowUpdate = function sendWindowUpdate(force) {
- var state = this._spdyState;
-
- if (state.version < 3.1 && (!state.isServer || !state.autoSpdy31) ||
- state.windowSize > state.initialWindowSize / 2 && !force) {
- return;
- }
-
- var self = this;
- var delta = state.initialWindowSize - state.windowSize;
- if (delta === 0)
- return;
-
- state.windowSize += delta;
- state.framer.windowUpdateFrame(0, delta, function(err, frame) {
- if (err)
- return self.emit('error', err);
- self.write(frame);
- });
-};
-
-//
-// ### function _drainSink (delta)
-// #### @delta {Number} WINDOW_UPDATE delta value
-//
-Connection.prototype._drainSink = function drainSink(delta) {
- var state = this._spdyState;
-
- // Switch to 3.1
- if (state.version !== 3.1) {
- this._setVersion(3.1);
- this._sendWindowUpdate();
- }
-
- state.sinkSize += delta;
-
- if (state.sinkSize <= 0)
- return;
-
- this.emit('drain');
-
- // Try to write all pending data to the socket
- Object.keys(state.streams).forEach(function(id) {
- state.streams[id]._drainSink(0);
- });
-};
-
-//
-// ### function setVersion (version)
-// #### @version {Number} Protocol version
-// Set protocol version to use
-//
-Connection.prototype._setVersion = function setVersion(version) {
- this._spdyState.parser.setVersion(version);
-};
-
-//
-// ### function addStream (stream)
-// #### @stream {Stream}
-//
-Connection.prototype._addStream = function addStream(stream) {
- var state = this._spdyState;
- var id = stream._spdyState.id;
- if (state.streams[id])
- return;
- state.streams[id] = stream;
-
- // Update lastId
- state.lastId = Math.max(state.lastId, id);
-
- var isClient = id % 2 == 1;
- if (isClient && state.isServer || !isClient && !state.isServer)
- state.streamCount++;
-};
-
-//
-// ### function removeStream (stream)
-// #### @stream {Stream}
-//
-Connection.prototype._removeStream = function removeStream(stream) {
- var state = this._spdyState;
- var id = stream._spdyState.id;
- if (!state.streams[id])
- return;
-
- delete state.streams[id];
-
- var isClient = id % 2 == 1;
- if (isClient && state.isServer || !isClient && !state.isServer)
- state.streamCount--;
-
- if (!state.isServer &&
- state.goaway &&
- state.streamCount === 0 &&
- this.socket) {
- this.socket.destroySoon();
- }
-};
-
-//
-// ### function destroyStreams (err)
-// #### @err {Error} *optional*
-// Destroys all active streams
-//
-Connection.prototype._destroyStreams = function destroyStreams(err) {
- var state = this._spdyState;
- var streams = state.streams;
- state.streams = {};
- state.streamCount = 0;
- Object.keys(streams).forEach(function(id) {
- streams[id].destroy();
- });
-};
-
-//
-// ### function _rst (streamId, code, extra)
-// #### @streamId {Number}
-// #### @code {Number}
-// #### @extra {String}
-// Send RST frame
-//
-Connection.prototype._rst = function rst(streamId, code, extra) {
- var self = this;
- this._spdyState.framer.rstFrame(streamId, code, extra, function(err, frame) {
- if (err)
- return self.emit('error', err);
- self.write(frame);
- });
-};
-
-//
-// ### function lock (callback)
-// #### @callback {Function} continuation callback
-// Acquire lock
-//
-Connection.prototype._lock = function lock(callback) {
- if (!callback)
- return;
-
- var state = this._spdyState;
- if (state.locked) {
- state.lockQueue.push(callback);
- } else {
- state.locked = true;
- callback(null);
- }
-};
-
-//
-// ### function unlock ()
-// Release lock and call all buffered callbacks
-//
-Connection.prototype._unlock = function unlock() {
- var state = this._spdyState;
- if (state.locked) {
- if (state.lockQueue.length) {
- var cb = state.lockQueue.shift();
- cb(null);
- } else {
- state.locked = false;
- }
- }
-};
-
-//
-// ### function write (data, encoding)
-// #### @data {String|Buffer} data
-// #### @encoding {String} (optional) encoding
-// Writes data to socket
-//
-Connection.prototype.write = function write(data, encoding) {
- if (this.socket.writable) {
- var wroteThrough = this.socket.write(data, encoding);
- // if write returns false, the socket layer is buffering the data, so let's
- // set a flag that we can use to create some backpressure
- if (!wroteThrough)
- this._spdyState.socketBuffering = true;
- return wroteThrough;
- }
-};
-
-//
-// ### function _setDefaultWindow (settings)
-// #### @settings {Object}
-// Update the default transfer window -- in the connection and in the
-// active streams
-//
-Connection.prototype._setDefaultWindow = function _setDefaultWindow(settings) {
- if (!settings)
- return;
- if (!settings.initial_window_size ||
- settings.initial_window_size.persisted) {
- return;
- }
- var state = this._spdyState;
- state.initialSinkSize = settings.initial_window_size.value;
-
- Object.keys(state.streams).forEach(function(id) {
- state.streams[id]._updateSinkSize(settings.initial_window_size.value);
- });
-};
-
-//
-// ### function handlePing (id)
-// #### @id {Number} PING id
-//
-Connection.prototype._handlePing = function handlePing(id) {
- var self = this;
- var state = this._spdyState;
-
- var ours = state.isServer && (id % 2 === 0) ||
- !state.isServer && (id % 2 === 1);
-
- // Handle incoming PING
- if (!ours) {
- state.framer.pingFrame(id, function(err, frame) {
- if (err)
- return self.emit('error', err);
-
- self.emit('ping', id);
- self.write(frame);
- });
- return;
- }
-
- // Handle reply PING
- if (!state.pings[id])
- return;
- var ping = state.pings[id];
- delete state.pings[id];
-
- if (ping.cb)
- ping.cb(null);
-};
-
-//
-// ### function ping (callback)
-// #### @callback {Function}
-// Send PING frame and invoke callback once received it back
-//
-Connection.prototype.ping = function ping(callback) {
- var self = this;
- var state = this._spdyState;
- var id = state.pingId;
-
- state.pingId += 2;
-
- state.framer.pingFrame(id, function(err, frame) {
- if (err)
- return self.emit('error', err);
-
- state.pings[id] = { cb: callback };
- self.write(frame);
- });
-};
-
-//
-// ### function getCounter (name)
-// #### @name {String} Counter name
-// Get counter value
-//
-Connection.prototype.getCounter = function getCounter(name) {
- return this._spdyState.counters[name];
-};
-
-//
-// ### function cork ()
-// Accumulate data before writing out
-//
-Connection.prototype.cork = function cork() {
- if (this.socket && this.socket.cork)
- this.socket.cork();
-};
-
-//
-// ### function uncork ()
-// Write out accumulated data
-//
-Connection.prototype.uncork = function uncork() {
- if (this.socket && this.socket.uncork)
- this.socket.uncork();
-};
-
-Connection.prototype.end = function end() {
- var self = this;
- var state = this._spdyState;
-
- state.framer.goawayFrame(state.lastId,
- constants.goaway.OK,
- function(err, frame) {
- if (err)
- return self.emit('error', err);
-
- self.write(frame, function() {
- state.goaway = state.lastId;
-
- // Destroy socket if there are no streams
- if (!state.isServer &&
- state.goaway &&
- state.streamCount === 0 &&
- self.socket) {
- self.socket.destroySoon();
- }
- });
- });
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/protocol/constants.js
+++ /dev/null
@@ -1,35 +0,0 @@
-exports.rst = {
- PROTOCOL_ERROR: 1,
- INVALID_STREAM: 2,
- REFUSED_STREAM: 3,
- UNSUPPORTED_VERSION: 4,
- CANCEL: 5,
- INTERNAL_ERROR: 6,
- FLOW_CONTROL_ERROR: 7,
- STREAM_IN_USE: 8,
- STREAM_ALREADY_CLOSED: 9,
- INVALID_CREDENTIALS: 10,
- FRAME_TOO_LARGE: 11
-};
-
-exports.settings = {
- FLAG_SETTINGS_PERSIST_VALUE: 1,
- FLAG_SETTINGS_PERSISTED: 2,
-
- SETTINGS_UPLOAD_BANDWIDTH: 1,
- SETTINGS_DOWNLOAD_BANDWIDTH: 2,
- SETTINGS_ROUND_TRIP_TIME: 3,
- SETTINGS_MAX_CONCURRENT_STREAMS: 4,
- SETTINGS_CURRENT_CWND: 5,
- SETTINGS_DOWNLOAD_RETRANS_RATE: 6,
- SETTINGS_INITIAL_WINDOW_SIZE: 7,
- SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE: 8
-};
-
-exports.DEFAULT_WINDOW = 64 * 1024;
-
-exports.goaway = {
- OK: 0,
- PROTOCOL_ERROR: 1,
- INTERNAL_ERROR: 2
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/protocol/dictionary.js
+++ /dev/null
@@ -1,203 +0,0 @@
-var Buffer = require('buffer').Buffer;
-
-var dictionary = {};
-module.exports = dictionary;
-
-dictionary[2] = new Buffer([
- 'optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-',
- 'languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi',
- 'f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser',
- '-agent10010120020120220320420520630030130230330430530630740040140240340440',
- '5406407408409410411412413414415416417500501502503504505accept-rangesageeta',
- 'glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic',
- 'ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran',
- 'sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati',
- 'oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo',
- 'ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe',
- 'pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic',
- 'ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1',
- '.1statusversionurl\x00'
-].join(''));
-
-dictionary[3] = new Buffer([
- 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // ....opti
- 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // ons....h
- 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // ead....p
- 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // ost....p
- 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // ut....de
- 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // lete....
- 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // trace...
- 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // .accept.
- 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // ...accep
- 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t-charse
- 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t....acc
- 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // ept-enco
- 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // ding....
- 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // accept-l
- 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // anguage.
- 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // ...accep
- 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t-ranges
- 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // ....age.
- 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // ...allow
- 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // ....auth
- 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // orizatio
- 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n....cac
- 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // he-contr
- 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // ol....co
- 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // nnection
- 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // ....cont
- 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // ent-base
- 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // ....cont
- 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // ent-enco
- 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // ding....
- 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // content-
- 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // language
- 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // ....cont
- 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // ent-leng
- 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // th....co
- 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // ntent-lo
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // cation..
- 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // ..conten
- 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t-md5...
- 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // .content
- 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // -range..
- 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // ..conten
- 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t-type..
- 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // ..date..
- 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // ..etag..
- 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // ..expect
- 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // ....expi
- 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // res....f
- 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // rom....h
- 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // ost....i
- 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f-match.
- 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // ...if-mo
- 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // dified-s
- 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // ince....
- 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // if-none-
- 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // match...
- 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // .if-rang
- 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e....if-
- 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // unmodifi
- 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // ed-since
- 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // ....last
- 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // -modifie
- 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d....loc
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // ation...
- 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // .max-for
- 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // wards...
- 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // .pragma.
- 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // ...proxy
- 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // -authent
- 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // icate...
- 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // .proxy-a
- 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // uthoriza
- 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // tion....
- 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // range...
- 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // .referer
- 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // ....retr
- 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y-after.
- 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // ...serve
- 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r....te.
- 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // ...trail
- 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // er....tr
- 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // ansfer-e
- 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // ncoding.
- 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // ...upgra
- 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // de....us
- 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // er-agent
- 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // ....vary
- 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // ....via.
- 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // ...warni
- 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // ng....ww
- 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w-authen
- 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // ticate..
- 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // ..method
- 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // ....get.
- 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // ...statu
- 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s....200
- 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // .OK....v
- 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // ersion..
- 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // ..HTTP.1
- 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // .1....ur
- 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l....pub
- 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // lic....s
- 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // et-cooki
- 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e....kee
- 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p-alive.
- 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // ...origi
- 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n1001012
- 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 01202205
- 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 20630030
- 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 23033043
- 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 05306307
- 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 40240540
- 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 64074084
- 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 09410411
- 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 41241341
- 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 44154164
- 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 17502504
- 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 505203.N
- 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // on-Autho
- 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // ritative
- 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // .Informa
- 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // tion204.
- 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // No.Conte
- 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // nt301.Mo
- 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // ved.Perm
- 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // anently4
- 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 00.Bad.R
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // equest40
- 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1.Unauth
- 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // orized40
- 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3.Forbid
- 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // den404.N
- 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // ot.Found
- 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 500.Inte
- 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // rnal.Ser
- 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // ver.Erro
- 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r501.Not
- 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // .Impleme
- 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // nted503.
- 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // Service.
- 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // Unavaila
- 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // bleJan.F
- 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // eb.Mar.A
- 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // pr.May.J
- 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // un.Jul.A
- 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // ug.Sept.
- 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // Oct.Nov.
- 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // Dec.00.0
- 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0.00.Mon
- 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // ..Tue..W
- 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // ed..Thu.
- 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // .Fri..Sa
- 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t..Sun..
- 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // GMTchunk
- 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // ed.text.
- 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // html.ima
- 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // ge.png.i
- 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // mage.jpg
- 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // .image.g
- 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // if.appli
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // cation.x
- 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // ml.appli
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // cation.x
- 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // html.xml
- 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // .text.pl
- 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // ain.text
- 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // .javascr
- 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // ipt.publ
- 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // icprivat
- 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // emax-age
- 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // .gzip.de
- 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // flate.sd
- 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // chcharse
- 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t.utf-8c
- 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // harset.i
- 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // so-8859-
- 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1.utf-..
- 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // .enq.0.
-]);
-
-dictionary[3.1] = dictionary[3];
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/protocol/framer.js
+++ /dev/null
@@ -1,497 +0,0 @@
-var spdy = require('../../spdy');
-var util = require('util');
-var Buffer = require('buffer').Buffer;
-var EventEmitter = require('events').EventEmitter;
-var constants = require('./').constants;
-
-var empty = new Buffer(0);
-
-function Framer() {
- EventEmitter.call(this);
-
- this.version = null;
- this.deflate = null;
- this.inflate = null;
- this.debug = false;
-};
-util.inherits(Framer, EventEmitter);
-module.exports = Framer;
-
-Framer.create = function create(version, deflate, inflate) {
- return new Framer(version, deflate, inflate);
-};
-
-//
-// ### function setCompression (deflate, inflate)
-// #### @deflate {Deflate}
-// #### @inflate {Inflate}
-// Set framer compression
-//
-Framer.prototype.setCompression = function setCompresion(deflate, inflate) {
- this.deflate = spdy.utils.zwrap(deflate);
- this.inflate = spdy.utils.zwrap(inflate);
-};
-
-
-//
-// ### function setCompression (deflate, inflate)
-// #### @deflate {Deflate}
-// #### @inflate {Inflate}
-// Set framer compression
-//
-Framer.prototype.setVersion = function setVersion(version) {
- this.version = version;
- this.emit('version');
-};
-
-//
-// internal, converts object into spdy dictionary
-//
-Framer.prototype.headersToDict = function headersToDict(headers, preprocess) {
- function stringify(value) {
- if (value !== undefined) {
- if (Array.isArray(value)) {
- return value.join('\x00');
- } else if (typeof value === 'string') {
- return value;
- } else {
- return value.toString();
- }
- } else {
- return '';
- }
- }
-
- // Lower case of all headers keys
- var loweredHeaders = {};
- Object.keys(headers || {}).map(function(key) {
- loweredHeaders[key.toLowerCase()] = headers[key];
- });
-
- // Allow outer code to add custom headers or remove something
- if (preprocess)
- preprocess(loweredHeaders);
-
- // Transform object into kv pairs
- var size = this.version === 2 ? 2 : 4,
- len = size,
- pairs = Object.keys(loweredHeaders).filter(function(key) {
- var lkey = key.toLowerCase();
- return lkey !== 'connection' && lkey !== 'keep-alive' &&
- lkey !== 'proxy-connection' && lkey !== 'transfer-encoding';
- }).map(function(key) {
- var klen = Buffer.byteLength(key),
- value = stringify(loweredHeaders[key]),
- vlen = Buffer.byteLength(value);
-
- len += size * 2 + klen + vlen;
- return [klen, key, vlen, value];
- }),
- result = new Buffer(len);
-
- if (this.version === 2)
- result.writeUInt16BE(pairs.length, 0, true);
- else
- result.writeUInt32BE(pairs.length, 0, true);
-
- var offset = size;
- pairs.forEach(function(pair) {
- // Write key length
- if (this.version === 2)
- result.writeUInt16BE(pair[0], offset, true);
- else
- result.writeUInt32BE(pair[0], offset, true);
- // Write key
- result.write(pair[1], offset + size);
-
- offset += pair[0] + size;
-
- // Write value length
- if (this.version === 2)
- result.writeUInt16BE(pair[2], offset, true);
- else
- result.writeUInt32BE(pair[2], offset, true);
- // Write value
- result.write(pair[3], offset + size);
-
- offset += pair[2] + size;
- }, this);
-
- return result;
-};
-
-Framer.prototype._synFrame = function _synFrame(type,
- id,
- assoc,
- priority,
- dict,
- callback) {
- var self = this;
-
- // Compress headers
- this.deflate(dict, function (err, chunks, size) {
- if (err)
- return callback(err);
-
- var offset = type === 'SYN_STREAM' ? 18 : self.version === 2 ? 14 : 12,
- total = offset - 8 + size,
- frame = new Buffer(offset + size);
-
- // Control + Version
- frame.writeUInt16BE(0x8000 | self.version, 0, true);
- // Type
- frame.writeUInt16BE(type === 'SYN_STREAM' ? 1 : 2, 2, true);
- // Size
- frame.writeUInt32BE(total & 0x00ffffff, 4, true);
- // Stream ID
- frame.writeUInt32BE(id & 0x7fffffff, 8, true);
-
- if (type === 'SYN_STREAM') {
- // Unidirectional
- if (assoc !== 0)
- frame[4] = 2;
-
- // Associated Stream-ID
- frame.writeUInt32BE(assoc & 0x7fffffff, 12, true);
-
- // Priority
- var priorityValue;
- if (self.version === 2)
- priorityValue = Math.max(Math.min(priority, 3), 0) << 6;
- else
- priorityValue = Math.max(Math.min(priority, 7), 0) << 5;
- frame.writeUInt8(priorityValue, 16, true);
- }
-
- for (var i = 0; i < chunks.length; i++) {
- chunks[i].copy(frame, offset);
- offset += chunks[i].length;
- }
-
- callback(null, frame);
- });
-};
-
-//
-// ### function replyFrame (id, code, reason, headers, callback)
-// #### @id {Number} Stream ID
-// #### @code {Number} HTTP Status Code
-// #### @reason {String} (optional)
-// #### @headers {Object|Array} (optional) HTTP headers
-// #### @callback {Function} Continuation function
-// Sends SYN_REPLY frame
-//
-Framer.prototype.replyFrame = function replyFrame(id,
- code,
- reason,
- headers,
- callback) {
- if (!this.version) {
- return this.on('version', function() {
- this.replyFrame(id, code, reason, headers, callback);
- });
- }
-
- var self = this;
- var dict = this.headersToDict(headers, function(headers) {
- if (self.version === 2) {
- headers.status = code + ' ' + reason;
- headers.version = 'HTTP/1.1';
- } else {
- headers[':status'] = code + ' ' + reason;
- headers[':version'] = 'HTTP/1.1';
- }
- });
-
-
- this._synFrame('SYN_REPLY', id, null, 0, dict, callback);
-};
-
-//
-// ### function streamFrame (id, assoc, headers, callback)
-// #### @id {Number} stream id
-// #### @assoc {Number} associated stream id
-// #### @meta {Object} meta headers ( method, scheme, url, version )
-// #### @headers {Object} stream headers
-// #### @callback {Function} continuation callback
-// Create SYN_STREAM frame
-// (needed for server push and testing)
-//
-Framer.prototype.streamFrame = function streamFrame(id,
- assoc,
- meta,
- headers,
- callback) {
- if (!this.version) {
- return this.on('version', function() {
- this.streamFrame(id, assoc, meta, headers, callback);
- });
- }
-
- var self = this;
- var dict = this.headersToDict(headers, function(headers) {
- if (self.version === 2) {
- if (meta.status)
- headers.status = meta.status;
- headers.version = meta.version || 'HTTP/1.1';
- headers.url = meta.url;
- if (meta.method)
- headers.method = meta.method;
- } else {
- if (meta.status)
- headers[':status'] = meta.status;
- headers[':version'] = meta.version || 'HTTP/1.1';
- headers[':path'] = meta.path || meta.url;
- headers[':scheme'] = meta.scheme || 'https';
- headers[':host'] = meta.host;
- if (meta.method)
- headers[':method'] = meta.method;
- }
- });
-
- this._synFrame('SYN_STREAM', id, assoc, meta.priority, dict, callback);
-};
-
-//
-// ### function headersFrame (id, headers, callback)
-// #### @id {Number} Stream id
-// #### @headers {Object} Headers
-// #### @callback {Function}
-// Sends HEADERS frame
-//
-Framer.prototype.headersFrame = function headersFrame(id, headers, callback) {
- if (!this.version) {
- return this.on('version', function() {
- this.headersFrame(id, headers, callback);
- });
- }
-
- var self = this;
- var dict = this.headersToDict(headers, function(headers) {});
-
- this.deflate(dict, function (err, chunks, size) {
- if (err)
- return callback(err);
-
- var offset = self.version === 2 ? 14 : 12,
- total = offset - 8 + size,
- frame = new Buffer(offset + size);
-
- // Control + Version
- frame.writeUInt16BE(0x8000 | self.version, 0, true);
- // Type
- frame.writeUInt16BE(8, 2, true);
- // Length
- frame.writeUInt32BE(total & 0x00ffffff, 4, true);
- // Stream ID
- frame.writeUInt32BE(id & 0x7fffffff, 8, true);
-
- // Copy chunks
- for (var i = 0; i < chunks.length; i++) {
- chunks[i].copy(frame, offset);
- offset += chunks[i].length;
- }
-
- callback(null, frame);
- });
-};
-
-//
-// ### function dataFrame (id, fin, data, callback)
-// #### @id {Number} Stream id
-// #### @fin {Bool} Is this data frame last frame
-// #### @data {Buffer} Response data
-// #### @callback {Function}
-// Sends DATA frame
-//
-Framer.prototype.dataFrame = function dataFrame(id, fin, data, callback) {
- if (!this.version) {
- return this.on('version', function() {
- this.dataFrame(id, fin, data, callback);
- });
- }
-
- if (!fin && !data.length)
- return callback(null, empty);
-
- var frame = new Buffer(8 + data.length);
-
- frame.writeUInt32BE(id & 0x7fffffff, 0, true);
- frame.writeUInt32BE(data.length & 0x00ffffff, 4, true);
- frame.writeUInt8(fin ? 0x01 : 0x0, 4, true);
-
- if (data.length)
- data.copy(frame, 8);
-
- return callback(null, frame);
-};
-
-//
-// ### function pingFrame (id)
-// #### @id {Number} Ping ID
-// Sends PING frame
-//
-Framer.prototype.pingFrame = function pingFrame(id, callback) {
- if (!this.version) {
- return this.on('version', function() {
- this.pingFrame(id, callback);
- });
- }
-
- var header = new Buffer(12);
-
- // Version and type
- header.writeUInt32BE(0x80000006 | (this.version << 16), 0, true);
- // Length
- header.writeUInt32BE(0x00000004, 4, true);
- // ID
- header.writeUInt32BE(id, 8, true);
-
- return callback(null, header);
-};
-
-//
-// ### function rstFrame (id, code, extra, callback)
-// #### @id {Number} Stream ID
-// #### @code {Number} RST Code
-// #### @extra {String} Extra debugging info
-// #### @callback {Function}
-// Sends PING frame
-//
-Framer.prototype.rstFrame = function rstFrame(id, code, extra, callback) {
- if (!this.version) {
- return this.on('version', function() {
- this.rstFrame(id, code, extra, callback);
- });
- }
-
- var header = new Buffer(16 +
- (this.debug ? Buffer.byteLength(extra || '') : 0));
-
- // Version and type
- header.writeUInt32BE(0x80000003 | (this.version << 16), 0, true);
- // Length
- header.writeUInt32BE(0x00000008, 4, true);
- // Stream ID
- header.writeUInt32BE(id & 0x7fffffff, 8, true);
- // Status Code
- header.writeUInt32BE(code, 12, true);
-
- // Extra debugging information
- if (this.debug && extra)
- header.write(extra, 16);
-
- return callback(null, header);
-};
-
-//
-// ### function settingsFrame (options, callback)
-// #### @options {Object} settings frame options
-// #### @callback {Function}
-// Sends SETTINGS frame with MAX_CONCURRENT_STREAMS and initial window
-//
-Framer.prototype.settingsFrame = function settingsFrame(options, callback) {
- if (!this.version) {
- return this.on('version', function() {
- this.settingsFrame(options, callback);
- });
- }
-
- var settings,
- key = this.version === 2 ? '2/' + options.maxStreams :
- '3/' + options.maxStreams + ':' +
- options.windowSize;
-
- if (!(settings = Framer.settingsCache[key])) {
- var params = [];
- if (isFinite(options.maxStreams)) {
- params.push({
- key: constants.settings.SETTINGS_MAX_CONCURRENT_STREAMS,
- value: options.maxStreams
- });
- }
- if (this.version > 2) {
- params.push({
- key: constants.settings.SETTINGS_INITIAL_WINDOW_SIZE,
- value: options.windowSize
- });
- }
-
- settings = new Buffer(12 + 8 * params.length);
-
- // Version and type
- settings.writeUInt32BE(0x80000004 | (this.version << 16), 0, true);
- // Length
- settings.writeUInt32BE((4 + 8 * params.length) & 0x00FFFFFF, 4, true);
- // Count of entries
- settings.writeUInt32BE(params.length, 8, true);
-
- var offset = 12;
- params.forEach(function(param) {
- var flag = constants.settings.FLAG_SETTINGS_PERSIST_VALUE << 24;
-
- if (this.version === 2)
- settings.writeUInt32LE(flag | param.key, offset, true);
- else
- settings.writeUInt32BE(flag | param.key, offset, true);
- offset += 4;
- settings.writeUInt32BE(param.value & 0x7fffffff, offset, true);
- offset += 4;
- }, this);
-
- Framer.settingsCache[key] = settings;
- }
-
- return callback(null, settings);
-};
-Framer.settingsCache = {};
-
-//
-// ### function windowUpdateFrame (id)
-// #### @id {Buffer} WindowUpdate ID
-// Sends WINDOW_UPDATE frame
-//
-Framer.prototype.windowUpdateFrame = function windowUpdateFrame(id, delta, cb) {
- if (!this.version) {
- return this.on('version', function() {
- this.windowUpdateFrame(id, delta, cb);
- });
- }
-
- var header = new Buffer(16);
-
- // Version and type
- header.writeUInt32BE(0x80000009 | (this.version << 16), 0, true);
- // Length
- header.writeUInt32BE(0x00000008, 4, true);
- // ID
- header.writeUInt32BE(id & 0x7fffffff, 8, true);
- // Delta
- if (delta > 0)
- header.writeUInt32BE(delta & 0x7fffffff, 12, true);
- else
- header.writeUInt32BE(delta, 12, true);
-
- return cb(null, header);
-};
-
-Framer.prototype.goawayFrame = function goawayFrame(lastId, status, cb) {
- if (!this.version) {
- return this.on('version', function() {
- this.goawayFrame(lastId, status, cb);
- });
- }
-
- var header = new Buffer(16);
-
- // Version and type
- header.writeUInt32BE(0x80000007 | (this.version << 16), 0, true);
- // Length
- header.writeUInt32BE(0x00000008, 4, true);
- // Last-good-stream-ID
- header.writeUInt32BE(lastId & 0x7fffffff, 8, true);
- // Status
- header.writeUInt32BE(status, 12, true);
-
- return cb(null, header);
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/protocol/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-exports.dictionary = require('./dictionary');
-exports.constants = require('./constants');
-exports.parser = require('./parser');
-exports.framer = require('./framer');
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/protocol/parser.js
+++ /dev/null
@@ -1,588 +0,0 @@
-var parser = exports;
-
-var spdy = require('../../spdy'),
- utils = spdy.utils,
- util = require('util'),
- stream = require('stream'),
- Buffer = require('buffer').Buffer;
-
-var legacy = !stream.Duplex;
-
-if (legacy) {
- var DuplexStream = stream;
-} else {
- var DuplexStream = stream.Duplex;
-}
-
-//
-// ### function Parser (connection)
-// #### @connection {spdy.Connection} connection
-// SPDY protocol frames parser's @constructor
-//
-function Parser(connection) {
- DuplexStream.call(this);
-
- this.paused = false;
- this.buffer = [];
- this.buffered = 0;
- this.waiting = 8;
-
- this.state = { type: 'frame-head' };
- this.socket = connection.socket;
- this.connection = connection;
-
- this.version = null;
- this.deflate = null;
- this.inflate = null;
-
- this.connection = connection;
-
- if (legacy) {
- this.readable = this.writable = true;
- }
-}
-util.inherits(Parser, DuplexStream);
-
-//
-// ### function create (connection)
-// #### @connection {spdy.Connection} connection
-// @constructor wrapper
-//
-parser.create = function create(connection) {
- return new Parser(connection);
-};
-
-//
-// ### function destroy ()
-// Just a stub.
-//
-Parser.prototype.destroy = function destroy() {
-};
-
-Parser.prototype._slice = function _slice(waiting) {
- var buffer = new Buffer(waiting);
- var sliced = 0;
- var offset = 0;
-
- while (waiting > offset && sliced < this.buffer.length) {
- var chunk = this.buffer[sliced++],
- overmatched = false;
-
- // Copy chunk into `buffer`
- if (chunk.length > waiting - offset) {
- chunk.copy(buffer, offset, 0, waiting - offset);
-
- this.buffer[--sliced] = chunk.slice(waiting - offset);
- this.buffered += this.buffer[sliced].length;
-
- overmatched = true;
- } else {
- chunk.copy(buffer, offset);
- }
-
- // Move offset and decrease amount of buffered data
- offset += chunk.length;
- this.buffered -= chunk.length;
-
- if (overmatched) break;
- }
-
- // Remove used buffers
- this.buffer = this.buffer.slice(sliced);
-
- return buffer;
-};
-
-//
-// ### function _write (data, encoding, cb)
-// #### @data {Buffer} chunk of data
-// #### @encoding {Null} encoding
-// #### @cb {Function} callback
-// Writes or buffers data to parser
-//
-Parser.prototype._write = function write(data, encoding, cb) {
- // Legacy compatibility
- if (!cb) cb = function() {};
-
- if (data !== undefined) {
- // Buffer data
- this.buffer.push(data);
- this.buffered += data.length;
- }
-
- // Notify caller about state (for piping)
- if (this.paused) {
- this.needDrain = true;
- cb();
- return false;
- }
-
- if (this.needDrain) {
- // Mark parser as drained
- this.needDrain = false;
- this.emit('drain');
- }
-
- // We shall not do anything until we get all expected data
- if (this.buffered < this.waiting) {
- // Emit DATA by chunks as they come
- if (this.buffered !== 0 &&
- this.state.header &&
- !this.state.header.control) {
- var buffer = this._slice(this.buffered);
- this.waiting -= buffer.length;
-
- this.emit('frame', {
- type: 'DATA',
- id: this.state.header.id,
- fin: false,
- compressed: (this.state.header.flags & 0x02) === 0x02,
- data: buffer
- });
- }
-
- cb();
- return;
- }
-
- var self = this;
- var buffer = this._slice(this.waiting);
-
- // Executed parser for buffered data
- this.paused = true;
- var sync = true;
- this.execute(this.state, buffer, function (err, waiting) {
- // Propagate errors
- if (err) {
- // And unpause once execution finished
- self.paused = false;
-
- cb();
- return self.emit('error', err);
- }
-
- // Set new `waiting`
- self.waiting = waiting;
-
- if (sync) {
- utils.nextTick(function() {
- // Unpause right before entering new `_write()` call
- self.paused = false;
- self._write(undefined, null, cb);
- });
- } else {
- // Unpause right before entering new `_write()` call
- self.paused = false;
- self._write(undefined, null, cb);
- }
- });
- sync = false;
-};
-
-if (legacy) {
- //
- // ### function write (data, encoding, cb)
- // #### @data {Buffer} chunk of data
- // #### @encoding {Null} encoding
- // #### @cb {Function} callback
- // Legacy method
- //
- Parser.prototype.write = Parser.prototype._write;
-
- //
- // ### function end ()
- // Stream's end() implementation
- //
- Parser.prototype.end = function end() {
- this.emit('end');
- };
-}
-
-//
-// ### function setVersion (version)
-// #### @version {Number} Protocol version
-// Set protocol version to use
-//
-Parser.prototype.setVersion = function setVersion(version) {
- this.version = version;
- this.emit('version', version);
- this.deflate = spdy.utils.zwrap(this.connection._spdyState.deflate);
- this.inflate = spdy.utils.zwrap(this.connection._spdyState.inflate);
-};
-
-//
-// ### function execute (state, data, callback)
-// #### @state {Object} Parser's state
-// #### @data {Buffer} Incoming data
-// #### @callback {Function} continuation callback
-// Parse buffered data
-//
-Parser.prototype.execute = function execute(state, data, callback) {
- if (state.type === 'frame-head') {
- var header = state.header = this.parseHeader(data);
-
- if (this.version === null && header.control) {
- if (header.version !== 2 && header.version !== 3) {
- return callback(new Error('Unsupported spdy version: ' +
- header.version));
- }
- this.setVersion(header.version);
- }
-
- state.type = 'frame-body';
- callback(null, header.length);
- } else if (state.type === 'frame-body') {
- var self = this;
-
- // Data frame
- if (!state.header.control) {
- return onFrame(null, {
- type: 'DATA',
- id: state.header.id,
- fin: (state.header.flags & 0x01) === 0x01,
- compressed: (state.header.flags & 0x02) === 0x02,
- data: data
- });
- } else {
- // Control frame
- this.parseBody(state.header, data, onFrame);
- }
-
- function onFrame(err, frame) {
- if (err) return callback(err);
-
- self.emit('frame', frame);
-
- state.type = 'frame-head';
- state.header = null;
- callback(null, 8);
- };
- }
-};
-
-
-//
-// ### function parseHeader (data)
-// ### @data {Buffer} incoming data
-// Returns parsed SPDY frame header
-//
-Parser.prototype.parseHeader = function parseHeader(data) {
- var header = {
- control: (data.readUInt8(0) & 0x80) === 0x80 ? true : false,
- version: null,
- type: null,
- id: null,
- flags: data.readUInt8(4),
- length: data.readUInt32BE(4) & 0x00ffffff
- };
-
- if (header.control) {
- header.version = data.readUInt16BE(0) & 0x7fff;
- header.type = data.readUInt16BE(2);
- } else {
- header.id = data.readUInt32BE(0) & 0x7fffffff;
- }
-
- return header;
-};
-
-
-//
-// ### function execute (header, body, callback)
-// #### @header {Object} Frame headers
-// #### @body {Buffer} Frame's body
-// #### @callback {Function} Continuation callback
-// Parse frame (decompress data and create streams)
-//
-Parser.prototype.parseBody = function parseBody(header, body, callback) {
- // SYN_STREAM or SYN_REPLY
- if (header.type === 0x01 || header.type === 0x02)
- this.parseSynHead(header.type, header.flags, body, callback);
- // RST_STREAM
- else if (header.type === 0x03)
- this.parseRst(body, callback);
- // SETTINGS
- else if (header.type === 0x04)
- this.parseSettings(body, callback);
- else if (header.type === 0x05)
- callback(null, { type: 'NOOP' });
- // PING
- else if (header.type === 0x06)
- this.parsePing(body, callback);
- // GOAWAY
- else if (header.type === 0x07)
- this.parseGoaway(body, callback);
- // HEADERS
- else if (header.type === 0x08)
- this.parseHeaders(body, callback);
- // WINDOW_UPDATE
- else if (header.type === 0x09)
- this.parseWindowUpdate(body, callback);
- // X-FORWARDED
- else if (header.type === 0xf000)
- this.parseXForwarded(body, callback);
- else
- callback(null, { type: 'unknown: ' + header.type, body: body });
-};
-
-
-//
-// ### function parseSynHead (type, flags, data)
-// #### @type {Number} Frame type
-// #### @flags {Number} Frame flags
-// #### @data {Buffer} input data
-// Returns parsed syn_* frame's head
-//
-Parser.prototype.parseSynHead = function parseSynHead(type,
- flags,
- data,
- callback) {
- var stream = type === 0x01;
- var offset = stream ? 10 : this.version === 2 ? 6 : 4;
-
- if (data.length < offset)
- return callback(new Error('SynHead OOB'));
-
- var kvs = data.slice(offset);
- this.parseKVs(kvs, function(err, headers) {
- if (err)
- return callback(err);
-
- if (stream === 'SYN_STREAM' &&
- (!headers.method || !(headers.path || headers.url))) {
- return callback(new Error('Missing `:method` and/or `:path` header'));
- }
-
- callback(null, {
- type: stream ? 'SYN_STREAM' : 'SYN_REPLY',
- id: data.readUInt32BE(0, true) & 0x7fffffff,
- associated: stream ? data.readUInt32BE(4, true) & 0x7fffffff : 0,
- priority: stream ? data[8] >> 5 : 0,
- fin: (flags & 0x01) === 0x01,
- unidir: (flags & 0x02) === 0x02,
- headers: headers,
- url: headers.path || headers.url || ''
- });
- });
-};
-
-
-//
-// ### function parseHeaders (data, callback)
-// #### @data {Buffer} input data
-// #### @callback {Function} continuation
-// Parse HEADERS
-//
-Parser.prototype.parseHeaders = function parseHeaders(data, callback) {
- var offset = this.version === 2 ? 6 : 4;
- if (data.length < offset)
- return callback(new Error('HEADERS OOB'));
-
- var streamId = data.readUInt32BE(0, true) & 0x7fffffff;
-
- this.parseKVs(data.slice(offset), function(err, headers) {
- if (err)
- return callback(err);
-
- callback(null, {
- type: 'HEADERS',
- id: streamId,
- headers: headers
- });
- });
-};
-
-
-//
-// ### function parseKVs (pairs, callback)
-// #### @pairs {Buffer} header pairs
-// #### @callback {Function} continuation
-// Returns hashmap of parsed headers
-//
-Parser.prototype.parseKVs = function parseKVs(pairs, callback) {
- var self = this;
- this.inflate(pairs, function(err, chunks, length) {
- if (err)
- return callback(err);
-
- var pairs = Buffer.concat(chunks, length);
-
- var size = self.version === 2 ? 2 : 4;
- if (pairs.length < size)
- return callback(new Error('KV OOB'));
-
- var count = size === 2 ? pairs.readUInt16BE(0, true) :
- pairs.readUInt32BE(0, true),
- headers = {};
-
- pairs = pairs.slice(size);
-
- function readString() {
- if (pairs.length < size)
- return null;
- var len = size === 2 ? pairs.readUInt16BE(0, true) :
- pairs.readUInt32BE(0, true);
-
- if (pairs.length < size + len) {
- return null;
- }
- var value = pairs.slice(size, size + len);
-
- pairs = pairs.slice(size + len);
-
- return value.toString();
- }
-
- while(count > 0) {
- var key = readString(),
- value = readString();
-
- if (key === null || value === null)
- return callback(new Error('Headers OOB'));
-
- if (self.version >= 3)
- headers[key.replace(/^:/, '')] = value;
- else
- headers[key] = value;
- count--;
- }
-
- callback(null, headers);
- });
-};
-
-
-//
-// ### function parseRst (data, callback)
-// #### @data {Buffer} input data
-// #### @callback {Function} continuation
-// Parse RST
-//
-Parser.prototype.parseRst = function parseRst(data, callback) {
- if (data.length < 8)
- return callback(new Error('RST OOB'));
-
- callback(null, {
- type: 'RST_STREAM',
- id: data.readUInt32BE(0, true) & 0x7fffffff,
- status: data.readUInt32BE(4, true),
- extra: data.length > 8 ? data.slice(8) : null
- });
-};
-
-
-//
-// ### function parseSettings (data, callback)
-// #### @data {Buffer} input data
-// #### @callback {Function} continuation
-// Parse SETTINGS
-//
-Parser.prototype.parseSettings = function parseSettings(data, callback) {
- if (data.length < 4)
- return callback(new Error('SETTINGS OOB'));
-
- var settings = {},
- number = data.readUInt32BE(0, true),
- idMap = {
- 1: 'upload_bandwidth',
- 2: 'download_bandwidth',
- 3: 'round_trip_time',
- 4: 'max_concurrent_streams',
- 5: 'current_cwnd',
- 6: 'download_retrans_rate',
- 7: 'initial_window_size',
- 8: 'client_certificate_vector_size'
- };
-
- if (data.length < 4 + number * 8)
- return callback(new Error('SETTINGS OOB#2'));
-
- for (var i = 0; i < number; i++) {
- var id = (this.version === 2 ? data.readUInt32LE(4 + i * 8, true) :
- data.readUInt32BE(4 + i * 8, true)),
- flags = (id >> 24) & 0xff;
- id = id & 0xffffff;
-
- var name = idMap[id];
-
- settings[id] = settings[name] = {
- persist: !!(flags & 0x1),
- persisted: !!(flags & 0x2),
- value: data.readUInt32BE(8 + (i*8), true)
- };
- }
-
- callback(null, {
- type: 'SETTINGS',
- settings: settings
- });
-};
-
-
-//
-// ### function parseGoaway (data, callback)
-// #### @data {Buffer} input data
-// #### @callback {Function} continuation
-// Parse PING
-//
-Parser.prototype.parsePing = function parsePing(body, callback) {
- if (body.length < 4)
- return callback(new Error('PING OOB'));
- callback(null, { type: 'PING', pingId: body.readUInt32BE(0, true) });
-};
-
-
-//
-// ### function parseGoaway (data, callback)
-// #### @data {Buffer} input data
-// #### @callback {Function} continuation
-// Parse GOAWAY
-//
-Parser.prototype.parseGoaway = function parseGoaway(data, callback) {
- if (data.length < 4)
- return callback(new Error('GOAWAY OOB'));
-
- callback(null, {
- type: 'GOAWAY',
- lastId: data.readUInt32BE(0, true) & 0x7fffffff
- });
-};
-
-
-//
-// ### function parseWindowUpdate (data, callback)
-// #### @data {Buffer} input data
-// #### @callback {Function} continuation
-// Parse WINDOW_UPDATE
-//
-Parser.prototype.parseWindowUpdate = function parseWindowUpdate(data, callback) {
- if (data.length < 8)
- return callback(new Error('WINDOW_UPDATE OOB'));
-
- callback(null, {
- type: 'WINDOW_UPDATE',
- id: data.readUInt32BE(0, true) & 0x7fffffff,
- delta: data.readUInt32BE(4, true) & 0x7fffffff
- });
-};
-
-
-//
-// ### function parseXForwarded (data, callback)
-// #### @data {Buffer} input data
-// #### @callback {Function} continuation
-// Parse X_FORWARDED
-//
-Parser.prototype.parseXForwarded = function parseXForwarded(data, callback) {
- if (data.length < 4)
- return callback(new Error('X_FORWARDED OOB'));
-
- var len = data.readUInt32BE(0, true);
- if (len + 4 > data.length)
- return callback(new Error('X_FORWARDED host length OOB'));
-
- callback(null, {
- type: 'X_FORWARDED',
- host: data.slice(4, 4 + len).toString()
- });
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/response.js
+++ /dev/null
@@ -1,208 +0,0 @@
-var spdy = require('../spdy'),
- utils = spdy.utils,
- http = require('http'),
- Stream = require('stream').Stream,
- res = http.ServerResponse.prototype;
-
-//
-// ### function _renderHeaders ()
-// Copy pasted from lib/http.js
-// (added lowercase)
-//
-exports._renderHeaders = function renderHeaders() {
- if (this._header)
- throw new Error("Can't render headers after they are sent to the client.");
-
- var keys = Object.keys(this._headerNames);
- for (var i = 0, l = keys.length; i < l; i++) {
- var key = keys[i];
- this._headerNames[key] = this._headerNames[key].toLowerCase();
- }
-
- return res._renderHeaders.call(this);
-};
-
-//
-// ### function writeHead (statusCode)
-// #### @statusCode {Number} HTTP Status code
-// .writeHead() wrapper
-// (Sorry, copy pasted from lib/http.js)
-//
-exports.writeHead = function writeHead(statusCode) {
- if (this._headerSent)
- return;
- this._headerSent = true;
-
- var reasonPhrase, headers = {}, headerIndex;
-
- if (typeof arguments[1] == 'string') {
- reasonPhrase = arguments[1];
- headerIndex = 2;
- } else {
- reasonPhrase = http.STATUS_CODES[statusCode] || 'unknown';
- headerIndex = 1;
- }
- this.statusCode = statusCode;
-
- var obj = arguments[headerIndex];
-
- if (obj && this._headers) {
- // Slow-case: when progressive API and header fields are passed.
- headers = this._renderHeaders();
-
- // handle object case
- var keys = Object.keys(obj);
- for (var i = 0; i < keys.length; i++) {
- var k = keys[i];
- if (k)
- headers[k] = obj[k];
- }
- } else if (this._headers) {
- // only progressive api is used
- headers = this._renderHeaders();
- } else {
- // only writeHead() called
- headers = obj;
- }
-
- // cleanup
- this._header = '';
-
- // Do not send data to new connections after GOAWAY
- if (this.socket._isGoaway())
- return;
-
- // Date header
- if (this.sendDate === true) {
- if (headers === undefined)
- headers = {};
- if (headers.date === undefined)
- headers.date = new Date().toUTCString();
- }
-
- this.socket._lock(function() {
- var socket = this;
-
- this._spdyState.framer.replyFrame(
- this._spdyState.id,
- statusCode,
- reasonPhrase,
- headers,
- function (err, frame) {
- if (err) {
- socket._unlock();
- socket.emit('error', err);
- return;
- }
-
- socket.connection.cork();
- socket.connection.write(frame);
- utils.nextTick(function() {
- socket.connection.uncork();
- });
- socket._unlock();
- }
- );
- });
-};
-
-//
-// ### function end (data, encoding, cb)
-// #### @data {Buffer|String} (optional) data
-// #### @encoding {String} (optional) string encoding
-// #### @cb {Function}
-// Send final data
-//
-exports.end = function end(data, encoding, cb) {
- if (this.socket)
- this.socket._spdyState.ending = true;
-
- this.constructor.prototype.end.call(this, data, encoding, cb);
-};
-
-//
-// ### function push (url, headers, callback)
-// #### @url {String} absolute or relative url (from root anyway)
-// #### @headers {Object} response headers
-// #### @callbacks {Function} continuation that will receive stream object
-// Initiates push stream
-//
-exports.push = function push(url, headers, priority, callback) {
- var socket = this.socket;
-
- if (!callback && typeof priority === 'function') {
- callback = priority;
- priority = null;
- }
- if (!priority && typeof priority !== 'number')
- priority = 7;
-
- if (!callback)
- callback = function() {};
-
- if (!socket || socket._destroyed) {
- var stub = new Stream();
- var err = Error('Can\'t open push stream, parent socket destroyed');
- utils.nextTick(function() {
- if (stub.listeners('error').length !== 0)
- stub.emit('error', err);
- callback(err);
- });
- return stub;
- }
-
- var id = socket.connection._spdyState.pushId += 2,
- scheme = socket._spdyState.scheme,
- host = headers.host || socket._spdyState.host || 'localhost',
- fullUrl = /^\//.test(url) ? scheme + '://' + host + url : url;
-
- var stream = new spdy.Stream(socket.connection, {
- type: 'SYN_STREAM',
- id: id,
- associated: socket._spdyState.id,
- priority: priority,
- headers: {}
- });
-
- stream.associated = socket;
-
- socket._lock(function() {
- this._spdyState.framer.streamFrame(
- id,
- this._spdyState.id,
- {
- method: 'GET',
- path: url,
- url: fullUrl,
- scheme: scheme,
- host: host,
- version: 'HTTP/1.1',
- priority: priority,
- status: 200
- },
- headers,
- function(err, frame) {
- if (err) {
- socket._unlock();
- if (callback)
- callback(err);
- stream.destroy(err);
- return;
- } else {
- socket.connection.cork();
- socket.connection.write(frame);
- utils.nextTick(function() {
- socket.connection.uncork();
- });
- socket._unlock();
- }
-
- stream.emit('acknowledge');
- if (callback)
- callback(null, stream);
- }
- );
- });
-
- return stream;
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/scheduler.js
+++ /dev/null
@@ -1,101 +0,0 @@
-var spdy = require('../spdy');
-var utils = spdy.utils;
-var scheduler = exports;
-
-//
-// ### function Scheduler (connection)
-// #### @connection {spdy.Connection} active connection
-// Connection's streams scheduler
-//
-function Scheduler(connection) {
- this.connection = connection;
- this.priorities = [[], [], [], [], [], [], [], []];
- this._tickListener = this._tickListener.bind(this);
- this._tickListening = false;
- this._tickCallbacks = [];
- this._corked = false;
-}
-
-//
-// ### function create (connection)
-// #### @connection {spdy.Connection} active connection
-//
-exports.create = function create(connection) {
- return new Scheduler(connection);
-};
-
-//
-// ### function schedule (stream, data)
-// #### @stream {spdy.Stream} Source stream
-// #### @data {Buffer} data to write on tick
-// Use stream priority to invoke callbacks in right order
-//
-Scheduler.prototype.schedule = function schedule(stream, data) {
- // Ignore data from destroyed stream
- if (stream._spdyState.destroyed)
- return;
- this.scheduleLast(stream, data);
-};
-
-//
-// ### function scheduleLast (stream, data)
-// #### @stream {spdy.Stream} Source stream
-// #### @data {Buffer} data to write on tick
-// Use stream priority to invoke callbacks in right order
-//
-Scheduler.prototype.scheduleLast = function scheduleLast(stream, data) {
- var priority = stream._spdyState.priority;
- priority = Math.min(priority, 7);
- priority = Math.max(priority, 0);
- this.priorities[priority].push(data);
-};
-
-//
-// ### function tickListener ()
-//
-Scheduler.prototype._tickListener = function tickListener() {
- var priorities = this.priorities;
- var tickCallbacks = this._tickCallbacks;
-
- this._tickListening = false;
- this.priorities = [[], [], [], [], [], [], [], []];
- this._tickCallbacks = [];
-
- // Run all priorities
- for (var i = 0; i < 8; i++)
- for (var j = 0; j < priorities[i].length; j++)
- this.connection.write(priorities[i][j]);
-
- // Invoke callbacks
- for (var i = 0; i < tickCallbacks.length; i++)
- tickCallbacks[i]();
- if (this._corked) {
- this.connection.uncork();
- if (this._tickListening)
- this.connection.cork();
- else
- this._corked = false;
- }
-};
-
-//
-// ### function tick ()
-// Add .nextTick callback if not already present
-//
-Scheduler.prototype.tick = function tick(cb) {
- if (cb)
- this._tickCallbacks.push(cb);
- if (this._tickListening)
- return;
- this._tickListening = true;
-
- if (!this._corked) {
- this.connection.cork();
- this._corked = true;
- }
- if (!this.connection._spdyState.parser.needDrain) {
- utils.nextTick(this._tickListener);
- } else {
- this.connection._spdyState.parser.once('drain', this._tickListener);
- }
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/server.js
+++ /dev/null
@@ -1,329 +0,0 @@
-var spdy = require('../spdy'),
- util = require('util'),
- https = require('https');
-
-var Connection = spdy.Connection;
-
-//
-// ### function instantiate (HTTPSServer)
-// #### @HTTPSServer {https.Server|Function} Base server class
-// Will return constructor for SPDY Server, based on the HTTPSServer class
-//
-function instantiate(HTTPSServer) {
- //
- // ### function Server (options, requestListener)
- // #### @options {Object} tls server options
- // #### @requestListener {Function} (optional) request callback
- // SPDY Server @constructor
- //
- function Server(options, requestListener) {
- // Initialize
- this._init(HTTPSServer, options, requestListener);
-
- // Wrap connection handler
- this._wrap();
- };
- util.inherits(Server, HTTPSServer);
-
- // Copy prototype methods
- Object.keys(proto).forEach(function(key) {
- this[key] = proto[key];
- }, Server.prototype);
-
- return Server;
-}
-exports.instantiate = instantiate;
-
-// Common prototype for all servers
-var proto = {};
-
-//
-// ### function _init(base, options, listener)
-// #### @base {Function} (optional) base server class (https.Server)
-// #### @options {Object} tls server options
-// #### @handler {Function} (optional) request handler
-// Initializer.
-//
-proto._init = function _init(base, options, handler) {
- var state = {};
- this._spdyState = state;
-
- if (!options)
- options = {};
-
- // Copy user supplied options
- options = util._extend({}, options);
-
- var supportedProtocols = [
- 'spdy/3.1', 'spdy/3', 'spdy/2',
- 'http/1.1', 'http/1.0'
- ];
- options.NPNProtocols = supportedProtocols;
- options.ALPNProtocols = supportedProtocols;
- options.isServer = true;
-
- // Header compression is enabled by default in servers, in contrast to clients
- // where it is disabled to prevent CRIME attacks.
- // See: https://groups.google.com/d/msg/spdy-dev/6mVYRv-lbuc/qGcW2ldOpt8J
- if (options.headerCompression !== false)
- options.headerCompression = true;
-
- state.options = options;
- state.reqHandler = handler;
-
- if (options.plain && !options.ssl)
- base.call(this, handler);
- else
- base.call(this, options, handler);
-
- // Use https if neither NPN or ALPN is supported
- if (!process.features.tls_npn && !process.features.tls_alpn &&
- !options.debug && !options.plain)
- return;
-};
-
-//
-// ### function _wrap()
-// Wrap connection handler and add logic.
-//
-proto._wrap = function _wrap() {
- var self = this,
- state = this._spdyState;
-
- // Wrap connection handler
- var event = state.options.plain && !state.options.ssl ? 'connection' :
- 'secureConnection',
- handler = this.listeners(event)[0];
-
- state.handler = handler;
-
- this.removeAllListeners(event);
-
- // 2 minutes default timeout
- if (state.options.timeout !== undefined)
- this.timeout = state.options.timeout;
- else
- this.timeout = this.timeout || 2 * 60 * 1000;
-
- // Normal mode, use NPN or ALPN to fallback to HTTPS
- if (!state.options.plain)
- return this.on(event, this._onConnection.bind(this));
-
- // In case of plain connection, we must fallback to HTTPS if first byte
- // is not equal to 0x80.
- this.on(event, function(socket) {
- var history = [],
- _emit = socket.emit;
-
- // Add 'data' listener, otherwise 'data' events won't be emitted
- if (spdy.utils.isLegacy) {
- function ondata() {};
- socket.once('data', ondata);
- }
-
- // 2 minutes timeout, as http.js does by default
- socket.setTimeout(self.timeout);
-
- socket.emit = function emit(event, data) {
- history.push(Array.prototype.slice.call(arguments));
-
- if (event === 'data') {
- // Legacy
- if (spdy.utils.isLegacy)
- onFirstByte.call(socket, data);
- } else if (event === 'readable') {
- // Streams
- onReadable.call(socket);
- } else if (event === 'end' ||
- event === 'close' ||
- event === 'error' ||
- event === 'timeout') {
- // We shouldn't get there if any data was received
- fail();
- }
- };
-
- function fail() {
- socket.emit = _emit;
- history = null;
- socket.removeListener('readable', onReadable);
-
- try {
- socket.destroy();
- } catch (e) {
- }
- }
-
- function restore() {
- var copy = history.slice();
- history = null;
-
- socket.removeListener('readable', onReadable);
- if (spdy.utils.isLegacy)
- socket.removeListener('data', ondata);
- socket.emit = _emit;
- for (var i = 0; i < copy.length; i++) {
- if (copy[i][0] !== 'data' || spdy.utils.isLegacy)
- socket.emit.apply(socket, copy[i]);
- if (copy[i][0] === 'end' && socket.onend)
- socket.onend();
- }
- }
-
- function onFirstByte(data) {
- // Ignore empty packets
- if (data.length === 0)
- return;
-
- if (data[0] === 0x80)
- self._onConnection(socket);
- else
- handler.call(self, socket);
-
- // Fire events
- restore();
-
- // NOTE: If we came there - .ondata() will be called anyway in this tick,
- // so there're no need to call it manually
- };
-
- // Hack to make streams2 work properly
- if (!spdy.utils.isLegacy)
- socket.on('readable', onReadable);
-
- function onReadable() {
- var data = socket.read(1);
-
- // Ignore empty packets
- if (!data)
- return;
- socket.removeListener('readable', onReadable);
-
- // `.unshift()` emits `readable` event. Thus `emit` method should
- // be restored before calling it.
- socket.emit = _emit;
-
- // Put packet back where it was before
- socket.unshift(data);
-
- if (data[0] === 0x80)
- self._onConnection(socket);
- else
- handler.call(self, socket);
-
- // Fire events
- restore();
-
- if (socket.ondata) {
- data = socket.read(socket._readableState.length);
- if (data)
- socket.ondata(data, 0, data.length);
- }
- }
- });
-};
-
-//
-// ### function _onConnection (socket)
-// #### @socket {Stream} incoming socket
-// Server's connection handler wrapper.
-//
-proto._onConnection = function _onConnection(socket) {
- var self = this,
- state = this._spdyState;
-
- // Fallback to HTTPS if needed
- var selectedProtocol = socket.npnProtocol || socket.alpnProtocol;
- if ((!selectedProtocol || !selectedProtocol.match(/spdy/)) &&
- !state.options.debug && !state.options.plain) {
- return state.handler.call(this, socket);
- }
-
- // Wrap incoming socket into abstract class
- var connection = new Connection(socket, state.options, this);
- if (selectedProtocol === 'spdy/3.1')
- connection._setVersion(3.1);
- else if (selectedProtocol === 'spdy/3')
- connection._setVersion(3);
- else if (selectedProtocol === 'spdy/2')
- connection._setVersion(2);
-
- // Emulate each stream like connection
- connection.on('stream', state.handler);
-
- connection.on('connect', function onconnect(req, socket) {
- socket.streamID = req.streamID = req.socket._spdyState.id;
- socket.isSpdy = req.isSpdy = true;
- socket.spdyVersion = req.spdyVersion = req.socket._spdyState.framer.version;
-
- socket.once('finish', function onfinish() {
- req.connection.end();
- });
-
- self.emit('connect', req, socket);
- });
-
- connection.on('request', function onrequest(req, res) {
- // Copy extension methods
- res._renderHeaders = spdy.response._renderHeaders;
- res.writeHead = spdy.response.writeHead;
- res.end = spdy.response.end;
- res.push = spdy.response.push;
- res.streamID = req.streamID = req.socket._spdyState.id;
- res.spdyVersion = req.spdyVersion = req.socket._spdyState.framer.version;
- res.isSpdy = req.isSpdy = true;
- res.addTrailers = function addTrailers(headers) {
- res.socket.sendHeaders(headers);
- };
-
- // Make sure that keep-alive won't apply to the response
- res._last = true;
-
- // Chunked encoding is not supported in SPDY
- res.useChunkedEncodingByDefault = false;
-
- // Populate trailing headers
- req.connection.on('headers', function(headers) {
- Object.keys(headers).forEach(function(key) {
- req.trailers[key] = headers[key];
- });
- req.emit('trailers', headers);
- });
-
- self.emit('request', req, res);
- });
-
- connection.on('error', function onerror(e) {
- socket.destroy(e.errno === 'EPIPE' ? undefined : e);
- });
-};
-
-// Export Server instantiated from https.Server
-var Server = instantiate(https.Server);
-exports.Server = Server;
-
-//
-// ### function create (base, options, requestListener)
-// #### @base {Function} (optional) base server class (https.Server)
-// #### @options {Object} tls server options
-// #### @requestListener {Function} (optional) request callback
-// @constructor wrapper
-//
-exports.create = function create(base, options, requestListener) {
- var server;
- if (typeof base === 'function') {
- server = instantiate(base);
- } else {
- server = Server;
-
- requestListener = options;
- options = base;
- base = null;
- }
-
- // Instantiate http server if `ssl: false`
- if (!base && options && options.plain && options.ssl === false)
- return exports.create(require('http').Server, options, requestListener);
-
- return new server(options, requestListener);
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/stream.js
+++ /dev/null
@@ -1,1180 +0,0 @@
-var spdy = require('../spdy');
-var zlib = require('zlib');
-var utils = spdy.utils;
-var assert = require('assert');
-var util = require('util');
-var stream = require('stream');
-var Buffer = require('buffer').Buffer;
-var constants = spdy.protocol.constants;
-
-var empty = new Buffer(0);
-
-if (!/^v(0\.10|0\.8|0\.9)\./.test(process.version))
- var httpCommon = require('_http_common');
-
-
-//
-// ### function Stream (connection, options)
-// #### @connection {Connection} SPDY Connection
-// #### @options {Object} Stream options
-// Abstract stream @constructor
-//
-function Stream(connection, options) {
- var self = this;
-
- utils.DuplexStream.call(this);
-
- this.connection = connection;
- this.socket = connection.socket;
- this.encrypted = connection.encrypted;
- this.associated = null;
-
- // 0.10 hack
- this._handle = {
- readStop: function() { self._readStop() },
- readStart: function() { self._readStart() }
- };
-
- var state = {};
- this._spdyState = state;
- state.timeout = connection.timeout;
- state.timeoutTimer = null;
- state.framer = connection._spdyState.framer;
- state.initialized = false;
- state.ending = false;
- state.ended = false;
- state.paused = false;
- state.finishAttached = false;
- state.decompress = options.decompress;
- state.decompressor = null;
-
- // Store id
- state.id = options.id;
- state.associated = options.associated;
- state.headers = options.headers || {};
-
- // Protocol standard compliance:
- // Client does not have to send this header, we must assume,
- // that it can handle compression
- if (connection._spdyState.isServer && !state.associated &&
- !state.headers['accept-encoding']) {
- state.headers['accept-encoding'] = 'gzip, deflate';
- }
-
- if (connection._spdyState.xForward !== null)
- state.headers['x-forwarded-for'] = connection._spdyState.xForward;
-
- // Increment counters
- state.isPush = !connection._spdyState.isServer && state.associated;
- connection._spdyState.counters.streamCount++;
- if (state.isPush)
- connection._spdyState.counters.pushCount++;
- connection._addStream(this);
-
- // Useful for PUSH streams
- state.scheme = state.headers.scheme;
- state.host = state.headers.host;
-
- if (state.isPush && state.headers['content-encoding']) {
- var compression = state.headers['content-encoding'];
-
- // If compression was requested - setup decompressor
- if (compression === 'gzip' || compression === 'deflate')
- this._setupDecompressor(compression);
- }
-
- // True if inside chunked write
- state.chunkedWrite = false;
-
- // Store options
- state.options = options;
- state.isClient = !!options.client;
- state.parseRequest = !!options.client;
-
- // RST_STREAM code if any
- state.rstCode = constants.rst.PROTOCOL_ERROR;
- state.destroyed = false;
-
- state.closedBy = {
- them: false,
- us: false
- };
-
- // Store priority
- state.priority = options.priority;
-
- // How much data can be sent TO client before next WINDOW_UPDATE
- state.sinkSize = connection._spdyState.initialSinkSize;
- state.initialSinkSize = state.sinkSize;
-
- // When data needs to be send, but window is too small for it - it'll be
- // queued in this buffer
- state.sinkBuffer = [];
- state.sinkDraining = false;
-
- // How much data can be sent BY client before next WINDOW_UPDATE
- state.windowSize = connection._spdyState.initialWindowSize;
- state.initialWindowSize = state.windowSize;
-
- this._init();
-};
-util.inherits(Stream, utils.DuplexStream);
-exports.Stream = Stream;
-
-// Parser lookup methods
-Stream.prototype._parserHeadersComplete = function parserHeadersComplete() {
- var method;
- if (this.parser)
- method = this.parser.onHeadersComplete || this.parser[1];
- if (!method || !utils.isArgvParser)
- return method;
-
- return function onHeadersCompleteWrap(info) {
- // NOTE: shouldKeepAlive = false
- return method.call(this,
- info.versionMajor,
- info.versionMinor,
- info.headers,
- info.method,
- info.url,
- info.statusCode,
- info.statusMessage,
- info.upgrade,
- false);
- };
-};
-
-Stream.prototype._parserBody = function parserBody() {
- if (this.parser)
- return this.parser.onBody || this.parser[2];
-};
-
-Stream.prototype._parserMessageComplete = function parserMessageComplete() {
- if (this.parser)
- return this.parser.onMessageComplete || this.parser[3];
-};
-
-//
-// ### function init ()
-// Initialize stream
-//
-Stream.prototype._init = function init() {
- var state = this._spdyState;
-
- this.setTimeout();
- this.ondata = this.onend = null;
-
- if (utils.isLegacy)
- this.readable = this.writable = true;
-
- // Call .onend()
- this.once('end', function() {
- var self = this;
- utils.nextTick(function() {
- var onHeadersComplete = self._parserHeadersComplete();
- if (!onHeadersComplete && self.onend)
- self.onend();
- });
- });
-
- // Handle half-close
- this.once('finish', function onfinish() {
- if (state.chunkedWrite)
- return this.once('_chunkDone', onfinish);
-
- var self = this;
- this._writeData(true, empty, function() {
- state.closedBy.us = true;
- if (state.sinkBuffer.length !== 0)
- return;
- if (utils.isLegacy)
- self.emit('full-finish');
- self._handleClose();
- });
- });
-
- if (state.isClient) {
- var httpMessage;
- Object.defineProperty(this, '_httpMessage', {
- set: function(val) {
- if (val)
- this._attachToRequest(val);
- httpMessage = val;
- },
- get: function() {
- return httpMessage;
- },
- configurable: true,
- enumerable: true
- });
- }
-};
-
-Stream.prototype._readStop = function readStop() {
- this._spdyState.paused = true;
-};
-
-Stream.prototype._readStart = function readStart() {
- this._spdyState.paused = false;
-
- // Send window update if needed
- this._read();
-};
-
-if (utils.isLegacy) {
- Stream.prototype.pause = function pause() {
- this._readStop();
- };
- Stream.prototype.resume = function resume() {
- this._readStart();
- };
-}
-
-//
-// ### function _isGoaway ()
-// Returns true if any writes to that stream should be ignored
-//
-Stream.prototype._isGoaway = function _isGoaway() {
- return this.connection._spdyState.goaway &&
- this._spdyState.id > this.connection._spdyState.goaway;
-};
-
-//
-// ### function start (url, headers)
-// #### @url {String}
-// #### @headers {Object}
-// Start stream, internal
-//
-Stream.prototype._start = function start(url, headers) {
- var state = this._spdyState;
- var headerList = [];
-
- // Create list of headeres
- Object.keys(headers).map(function(key) {
- if (key !== 'method' &&
- key !== 'url' &&
- key !== 'version' &&
- key !== 'scheme' &&
- key !== 'status' &&
- key !== 'path') {
- headerList.push(key, headers[key]);
- }
- });
-
- var info = {
- url: url,
- headers: headerList,
- versionMajor: 1,
- versionMinor: 1,
- method: httpCommon ? httpCommon.methods.indexOf(headers.method) :
- headers.method,
- statusCode: false,
- upgrade: headers.method === 'CONNECT'
- };
-
- // Write data directly to the parser callbacks
- var onHeadersComplete = this._parserHeadersComplete();
- if (onHeadersComplete) {
- onHeadersComplete.call(this.parser, info);
-
- // onHeadersComplete doesn't handle CONNECT
- if (headers.method === 'CONNECT') {
- // We don't need to handle a lack of listeners here, since there
- // should always be a listener in server.js
- var req = this.parser.incoming;
- if (this.listeners('data').length) {
- // 0.11+ only (assuming nobody other than the http lib has attached)
- this.removeAllListeners('data');
- this.skipBodyParsing = true;
- }
- this.connection.emit('connect', req, req.socket);
- }
- } else {
- this.emit('headersComplete', info);
- }
-
- state.initialized = true;
-};
-
-//
-// ### function attachToRequest (req)
-// #### @req {ClientRequest}
-// Attach to node.js' response
-//
-Stream.prototype._attachToRequest = function attachToRequest(res) {
- var self = this;
-
- res.addTrailers = function addTrailers(headers) {
- self.sendHeaders(headers);
- };
-
- this.on('headers', function(headers) {
- var req = res.parser.incoming;
- if (req) {
- Object.keys(headers).forEach(function(key) {
- req.trailers[key] = headers[key];
- });
- req.emit('trailers', headers);
- }
- });
-};
-
-//
-// ### function sendHeaders (headers)
-// #### @headers {Object}
-//
-Stream.prototype.sendHeaders = function sendHeaders(headers) {
- var self = this;
- var state = this._spdyState;
-
- // Reset timeout
- this.setTimeout();
-
- var connection = this.connection;
- this._lock(function() {
- state.framer.headersFrame(state.id, headers, function(err, frame) {
- if (err) {
- self._unlock();
- return self.emit('error', err);
- }
-
- connection.write(frame);
- self._unlock();
- });
- });
-};
-
-//
-// ### function setTimeout (timeout, callback)
-// #### @timeout {Number}
-// #### @callback {Function}
-//
-Stream.prototype.setTimeout = function _setTimeout(timeout, callback) {
- var self = this;
- var state = this._spdyState;
-
- if (callback)
- this.once('timeout', callback);
-
- // Keep PUSH's parent alive
- if (this.associated)
- this.associated.setTimeout();
-
- state.timeout = timeout !== undefined ? timeout : state.timeout;
-
- if (state.timeoutTimer) {
- clearTimeout(state.timeoutTimer);
- state.timeoutTimer = null;
- }
-
- if (!state.timeout)
- return;
-
- state.timeoutTimer = setTimeout(function() {
- self.emit('timeout');
- }, state.timeout);
-};
-
-//
-// ### function _handleClose ()
-// Close stream if it was closed by both server and client
-//
-Stream.prototype._handleClose = function _handleClose() {
- var state = this._spdyState;
- if (state.closedBy.them && state.closedBy.us)
- this.close();
-};
-
-//
-// ### function close ()
-// Destroys stream
-//
-Stream.prototype.close = function close() {
- this.destroy();
-};
-
-//
-// ### function destroy (error)
-// #### @error {Error} (optional) error
-// Destroys stream
-//
-Stream.prototype.destroy = function destroy(error) {
- var state = this._spdyState;
- if (state.destroyed)
- return;
- state.destroyed = true;
-
- // Reset timeout
- this.setTimeout(0);
-
- // Decrement counters
- this.connection._spdyState.counters.streamCount--;
- if (state.isPush)
- this.connection._spdyState.counters.pushCount--;
-
- // Just for http.js in v0.10
- this.writable = false;
- this.connection._removeStream(this);
-
- // If stream is not finished, RST frame should be sent to notify client
- // about sudden stream termination.
- if (error || !state.closedBy.us) {
- if (!state.closedBy.us)
- // CANCEL
- if (state.isClient)
- state.rstCode = constants.rst.CANCEL;
- // REFUSED_STREAM if terminated before 'finish' event
- else
- state.rstCode = constants.rst.REFUSED_STREAM;
-
- if (state.rstCode) {
- var self = this;
- state.framer.rstFrame(state.id,
- state.rstCode,
- null,
- function(err, frame) {
- if (err)
- return self.emit('error', err);
- var scheduler = self.connection._spdyState.scheduler;
-
- scheduler.scheduleLast(self, frame);
- scheduler.tick();
- });
- }
- }
-
- var self = this;
- this._recvEnd(function() {
- if (error)
- self.emit('error', error);
-
- utils.nextTick(function() {
- self.emit('close', !!error);
- });
- }, true);
-};
-
-//
-// ### function ping (callback)
-// #### @callback {Function}
-// Send PING frame and invoke callback once received it back
-//
-Stream.prototype.ping = function ping(callback) {
- return this.connection.ping(callback);
-};
-
-//
-// ### function destroySoon ()
-//
-Stream.prototype.destroySoon = function destroySoon() {
- var self = this;
- var state = this._spdyState;
-
- // Hack for http.js, when running in client mode
- this.writable = false;
-
- // Already closed - just ignore
- if (state.closedBy.us)
- return;
-
- // Reset timeout
- this.setTimeout();
- this.end();
-};
-
-//
-// ### function drainSink (size)
-// #### @size {Number}
-// Change sink size
-//
-Stream.prototype._drainSink = function drainSink(size) {
- var state = this._spdyState;
- var oldBuffer = state.sinkBuffer;
-
- state.sinkBuffer = [];
- state.sinkSize += size;
- state.sinkDraining = true;
-
- for (var i = 0; i < oldBuffer.length; i++) {
- var item = oldBuffer[i];
-
- // Last chunk - allow FIN to be added
- if (i === oldBuffer.length - 1)
- state.sinkDraining = false;
- this._writeData(item.fin, item.buffer, item.cb, item.chunked);
- }
-
- // Handle half-close
- if (state.sinkBuffer.length === 0 && state.closedBy.us)
- this._handleClose();
-
- if (utils.isLegacy)
- this.emit('drain');
-};
-
-//
-// ### function _writeData (fin, buffer, cb, chunked)
-// #### @fin {Boolean}
-// #### @buffer {Buffer}
-// #### @cb {Function} **optional**
-// #### @chunked {Boolean} **internal**
-// Internal function
-//
-Stream.prototype._writeData = function _writeData(fin, buffer, cb, chunked) {
- // If client is gone - notify caller about it
- if (!this.connection.socket || !this.connection.socket.writable)
- return false;
-
- var state = this._spdyState;
- if (!state.framer.version) {
- var self = this;
- state.framer.on('version', function() {
- self._writeData(fin, buffer, cb, chunked);
- if (utils.isLegacy)
- self.emit('drain');
- });
- return false;
- }
-
- // Already closed
- if (state.closedBy.us) {
- this.emit('error', new Error('Write after end!'));
- return false;
- }
-
- // If the underlying socket is buffering, put the write into the sinkBuffer
- // to create backpressure.
- if (this.connection._spdyState.socketBuffering) {
- state.sinkBuffer.push({
- fin: fin,
- buffer: buffer,
- cb: cb,
- chunked: chunked
- });
- return false;
- }
-
- if (state.framer.version >= 3) {
- // Window was exhausted, queue data
- if (state.sinkSize <= 0 ||
- (state.framer.version >= 3.1 &&
- this.connection._spdyState.sinkSize <= 0)) {
- state.sinkBuffer.push({
- fin: fin,
- buffer: buffer,
- cb: cb,
- chunked: chunked
- });
- return false;
- }
- }
- if (state.chunkedWrite && !chunked) {
- var self = this;
- function attach() {
- self.once('_chunkDone', function() {
- if (state.chunkedWrite)
- return attach();
- self._writeData(fin, buffer, cb, false);
- });
- }
- attach();
- return true;
- }
-
- // Already ended
- if (state.ended && !chunked)
- return false;
-
- // Ending, add FIN if not set
- if (!fin && !chunked && state.ending) {
- if (utils.isLegacy)
- fin = this.listeners('_chunkDone').length === 0;
- else
- fin = this._writableState.length === 0;
- fin = fin && false && state.sinkBuffer.length === 0 && !state.sinkDraining;
- }
- if (!chunked && fin)
- state.ended = true;
-
- var maxChunk = this.connection._spdyState.maxChunk;
- // Slice buffer into parts with size <= `maxChunk`
- if (maxChunk && maxChunk < buffer.length) {
- var preend = buffer.length - maxChunk;
- var chunks = [];
- for (var i = 0; i < preend; i += maxChunk)
- chunks.push(buffer.slice(i, i + maxChunk));
-
- // Last chunk
- chunks.push(buffer.slice(i));
-
- var self = this;
- function send(err) {
- function done(err) {
- state.chunkedWrite = false;
- self.emit('_chunkDone');
- if (cb)
- cb(err);
- }
-
- if (err)
- return done(err);
-
- var chunk = chunks.shift();
- if (chunks.length === 0) {
- self._writeData(fin, chunk, function(err) {
- // Ensure that `finish` listener will catch this
- done(err);
- }, true);
- } else {
- self._writeData(false, chunk, send, true);
- }
- }
-
- state.chunkedWrite = true;
- send();
- return true;
- }
-
- if (state.framer.version >= 3) {
- var len = Math.min(state.sinkSize, buffer.length);
- if (state.framer.version >= 3.1)
- len = Math.min(this.connection._spdyState.sinkSize, len);
- this.connection._spdyState.sinkSize -= len;
- state.sinkSize -= len;
-
- // Only partial write is possible, queue rest for later
- if (len < buffer.length) {
- state.sinkBuffer.push({
- fin: fin,
- buffer: buffer.slice(len),
- cb: cb,
- chunked: chunked
- });
- buffer = buffer.slice(0, len);
- fin = false;
- cb = null;
- }
- }
-
- // Reset timeout
- this.setTimeout();
-
- this._lock(function() {
- var stream = this;
-
- state.framer.dataFrame(state.id, fin, buffer, function(err, frame) {
- if (err) {
- stream._unlock();
- return stream.emit('error', err);
- }
-
- var scheduler = stream.connection._spdyState.scheduler;
- scheduler.schedule(stream, frame);
- scheduler.tick(cb);
-
- stream._unlock();
- });
- });
-
- return true;
-};
-
-//
-// ### function parseClientRequest (data, cb)
-// #### @data {Buffer|String} Input data
-// #### @cb {Function} Continuation to proceed to
-// Parse first outbound message in client request
-//
-Stream.prototype._parseClientRequest = function parseClientRequest(data, cb) {
- var state = this._spdyState;
-
- state.parseRequest = false;
-
- var lines = data.toString().split(/\r\n\r\n/);
- var body = data.slice(Buffer.byteLength(lines[0]) + 4);
- lines = lines[0].split(/\r\n/g);
- var status = lines[0].match(/^([a-z]+)\s([^\s]+)\s(.*)$/i);
- var headers = {};
-
- assert(status !== null);
- var method = status[1].toUpperCase();
- var url = status[2];
- var version = status[3].toUpperCase();
- var host = '';
-
- // Transform headers and determine host
- lines.slice(1).forEach(function(line) {
- // Last line
- if (!line)
- return;
-
- // Normal line - `Key: Value`
- var match = line.match(/^(.*?):\s*(.*)$/);
- assert(match !== null);
-
- var key = match[1].toLowerCase();
- var value = match[2];
-
- if (key === 'host')
- host = value;
- else if (key !== 'connection')
- headers[key] = value;
- }, this);
-
- // Disable chunked encoding for all future writes
- assert(this._httpMessage);
- var chunkedEncoding = this._httpMessage.chunkedEncoding;
- this._httpMessage.chunkedEncoding = false;
-
- // Reset timeout
- this.setTimeout();
-
- var self = this;
- var connection = this.connection;
- this._lock(function() {
- state.framer.streamFrame(state.id, 0, {
- method: method,
- host: host,
- url: url,
- version: version,
- priority: self.priority
- }, headers, function(err, frame) {
- if (err) {
- self._unlock();
- return self.emit('error', err);
- }
- connection.write(frame);
- self._unlock();
-
- self.emit('_spdyRequest');
- state.initialized = true;
- if (cb)
- cb();
- })
- });
-
- // Yeah, node.js gave us a body with the request
- if (body) {
- if (chunkedEncoding) {
- var i = 0;
- while (i < body.length) {
- var lenStart = i;
-
- // Skip length and \r\n
- for (; i + 1 < body.length; i++)
- if (body[i] === 0xd && body[i + 1] === 0xa)
- break;
- if (i === body.length - 1)
- return self.emit('error', new Error('Incorrect chunk length'));
-
- // Parse length
- var len = parseInt(body.slice(lenStart, i).toString(), 16);
-
- // Get body chunk
- if (i + 2 + len >= body.length)
- return self.emit('error', new Error('Chunk length OOB'));
-
- // Ignore empty chunks
- if (len !== 0) {
- var chunk = body.slice(i + 2, i + 2 + len);
- this._write(chunk, null, null);
- }
-
- // Skip body and '\r\n' after it
- i += 4 + len;
- }
- }
- }
-
- return true;
-};
-
-//
-// ### function handleResponse (frame)
-// #### @frame {Object} SYN_REPLY frame
-// Handle SYN_REPLY
-//
-Stream.prototype._handleResponse = function handleResponse(frame) {
- var state = this._spdyState;
- assert(state.isClient);
-
- var headers = frame.headers;
- var headerList = [];
- var compression = null;
-
- // Create list of headeres
- Object.keys(headers).map(function(key) {
- var val = headers[key];
-
- if (state.decompress &&
- key === 'content-encoding' &&
- (val === 'gzip' || val === 'deflate'))
- compression = val;
- else if (key !== 'status' && key !== 'version')
- headerList.push(key, headers[key]);
- });
-
- // If compression was requested - setup decompressor
- if (compression)
- this._setupDecompressor(compression);
-
- var isConnectRequest = this._httpMessage &&
- this._httpMessage.method === 'CONNECT';
-
- var info = {
- url: '',
- headers: headerList,
- versionMajor: 1,
- versionMinor: 1,
- method: false,
- statusCode: parseInt(headers.status, 10),
- statusMessage: headers.status.split(/ /)[1],
- upgrade: isConnectRequest
- };
-
- // Write data directly to the parser callbacks
- var onHeadersComplete = this._parserHeadersComplete();
- if (onHeadersComplete) {
- onHeadersComplete.call(this.parser, info);
-
- // onHeadersComplete doesn't handle CONNECT
- if (isConnectRequest) {
- var req = this._httpMessage;
- var res = this.parser.incoming;
- req.res = res;
- if (this.listeners('data').length) {
- // 0.11+ only (assuming nobody other than the http lib has attached)
- this.removeAllListeners('data');
- this.skipBodyParsing = true;
- }
- if (this._httpMessage.listeners('connect').length > 0)
- this._httpMessage.emit('connect', res, res.socket);
- else
- this.destroy();
- }
- } else {
- this.emit('headersComplete', info);
- }
-
- state.initialized = true;
-};
-
-//
-// ### function setupDecompressor (type)
-// #### @type {String} 'gzip' or 'deflate'
-// Setup decompressor
-//
-Stream.prototype._setupDecompressor = function setupDecompressor(type) {
- var self = this;
- var state = this._spdyState;
- var options = { flush: zlib.Z_SYNC_FLUSH };
-
- if (state.decompressor !== null)
- return this.emit('error', new Error('Decompressor already created'));
-
- state.decompressor = type === 'gzip' ? zlib.createGunzip(options) :
- zlib.createInflate(options);
- if (spdy.utils.isLegacy)
- state.decompressor._flush = options.flush;
- state.decompressor.on('data', function(chunk) {
- self._recv(chunk, true);
- });
- state.decompressor.on('error', function(err) {
- self.emit('error', err);
- });
-}
-
-//
-// ### function decompress(data)
-// #### @data {Buffer} Input data
-// Decompress input data and call `._recv(result, true)`
-//
-Stream.prototype._decompress = function decompress(data) {
- var state = this._spdyState;
-
- // Put data in
- state.decompressor.write(data);
-};
-
-//
-// ### function write (data, encoding)
-// #### @data {Buffer|String} data
-// #### @encoding {String} data encoding
-// Writes data to connection
-//
-Stream.prototype._write = function write(data, encoding, cb) {
- var r = true;
- var state = this._spdyState;
-
- // Ignore all outgoing data for PUSH streams, they're unidirectional
- if (state.isClient && state.associated) {
- cb();
- return r;
- }
-
- // First write is a client request
- if (state.parseRequest) {
- this._parseClientRequest(data, cb);
- } else {
- // No chunked encoding is allowed at this point
- assert(!this._httpMessage || !this._httpMessage.chunkedEncoding);
-
- // Do not send data to new connections after GOAWAY
- if (this._isGoaway()) {
- if (cb)
- cb();
- r = false;
- } else {
- r = this._writeData(false, data, cb);
- }
- }
-
- if (this._httpMessage && state.isClient && !state.finishAttached) {
- state.finishAttached = true;
- var self = this;
-
- // If client request was ended - send FIN data frame
- this._httpMessage.once('finish', function() {
- if (self._httpMessage.output &&
- !self._httpMessage.output.length &&
- self._httpMessage.method !== 'CONNECT')
- self.end();
- });
- }
-
- return r;
-};
-
-if (spdy.utils.isLegacy) {
- Stream.prototype.write = function write(data, encoding, cb) {
- if (typeof encoding === 'function' && !cb) {
- cb = encoding;
- encoding = null;
- }
- if (!Buffer.isBuffer(data))
- return this._write(new Buffer(data, encoding), null, cb);
- else
- return this._write(data, encoding, cb);
- };
-
- //
- // ### function end (data, encoding, cb)
- // #### @data {Buffer|String} (optional) data to write before ending stream
- // #### @encoding {String} (optional) string encoding
- // #### @cb {Function}
- // Send FIN data frame
- //
- Stream.prototype.end = function end(data, encoding, cb) {
- // Do not send data to new connections after GOAWAY
- if (this._isGoaway())
- return;
-
- this._spdyState.ending = true;
-
- if (data)
- this.write(data, encoding, cb);
- this.emit('finish');
- };
-} else {
-
- //
- // ### function end (data, encoding, cb)
- // #### @data {Buffer|String} (optional) data to write before ending stream
- // #### @encoding {String} (optional) string encoding
- // #### @cb {Function}
- // Send FIN data frame
- //
- Stream.prototype.end = function end(data, encoding, cb) {
- this._spdyState.ending = true;
-
- Stream.super_.prototype.end.call(this, data, encoding, cb);
- };
-}
-
-//
-// ### function _recv (data, decompressed)
-// #### @data {Buffer} buffer to receive
-// #### @decompressed {Boolean} **internal** `true` if already decompressed
-// (internal)
-//
-Stream.prototype._recv = function _recv(data, decompressed) {
- var state = this._spdyState;
-
- // Update window if exhausted
- if (state.framer.version >= 3 && state.initialized) {
- state.windowSize -= data.length;
-
- // If running on node.js 0.8 - don't send WINDOW_UPDATE if paused
- if (spdy.utils.isLegacy && !state.paused)
- this._read();
- }
-
- // Decompress data if needed
- if (state.decompressor && !decompressed)
- return this._decompress(data);
-
- // Reset timeout
- this.setTimeout();
-
- if (this.parser && !this.skipBodyParsing) {
- var onBody = this._parserBody();
- if (onBody)
- onBody.call(this.parser, data, 0, data.length);
- }
-
- if (spdy.utils.isLegacy) {
- var self = this;
- utils.nextTick(function() {
- self.emit('data', data);
- if (self.ondata && !onBody)
- self.ondata(data, 0, data.length);
- });
- } else {
- // 0.11 - 0.12 - do not emit events at all
- if (!onBody || !this.parser[2]) {
- // Right now, http module expects socket to be working in streams1 mode.
- if (this.ondata && !onBody)
- this.ondata(data, 0, data.length);
- else
- this.push(data);
- }
- }
-
- // Call `._read()` if high watermark isn't reached
- if (!spdy.utils.isLegacy)
- this.read(0);
-};
-
-//
-// ### function _recvEnd (callback, quite)
-// #### @callback {Function}
-// #### @quite {Boolean} If true - do not emit any events
-// Receive FIN frame
-//
-Stream.prototype._recvEnd = function _recvEnd(callback, quite) {
- var state = this._spdyState;
-
- // Sync with the decompressor
- if (state.decompressor) {
- var self = this;
- state.decompressor.write('', function() {
- state.decompressor = null;
- self._recvEnd(callback, quite);
- });
- return;
- }
- if (!quite) {
- var onMessageComplete = this._parserMessageComplete();
- if (onMessageComplete)
- onMessageComplete.call(this.parser);
-
- if (spdy.utils.isLegacy)
- this.emit('end');
- else
- this.push(null);
- }
- if (callback)
- callback();
-};
-
-//
-// ### function _read (bytes)
-// #### @bytes {Number} number of bytes to read
-// Streams2 API
-//
-Stream.prototype._read = function read(bytes) {
- var state = this._spdyState;
-
- // Send update frame if read is requested
- if (state.framer.version >= 3 &&
- state.initialized &&
- state.windowSize <= state.initialWindowSize / 2) {
- var delta = state.initialWindowSize - state.windowSize;
- state.windowSize += delta;
- var self = this;
- state.framer.windowUpdateFrame(state.id, delta, function(err, frame) {
- if (err)
- return self.emit('error', err);
- self.connection.write(frame);
- });
- }
-
- if (!spdy.utils.isLegacy)
- this.push('');
-};
-
-//
-// ### function _updateSinkSize (size)
-// #### @size {Integer}
-// Update the internal data transfer window
-//
-Stream.prototype._updateSinkSize = function _updateSinkSize(size) {
- var state = this._spdyState;
- var delta = size - state.initialSinkSize;
-
- state.initialSinkSize = size;
- this._drainSink(delta);
-};
-
-//
-// ### function lock (callback)
-// #### @callback {Function} continuation callback
-// Acquire lock
-//
-Stream.prototype._lock = function lock(callback) {
- if (!callback)
- return;
-
- var self = this;
- this.connection._lock(function(err) {
- callback.call(self, err);
- });
-};
-
-//
-// ### function unlock ()
-// Release lock and call all buffered callbacks
-//
-Stream.prototype._unlock = function unlock() {
- this.connection._unlock();
-};
-
-//
-// `net` compatibility layer
-// (Copy pasted from lib/tls.js from node.js)
-//
-Stream.prototype.address = function address() {
- return this.socket && this.socket.address();
-};
-
-Stream.prototype.__defineGetter__('remoteAddress', function remoteAddress() {
- return this.socket && this.socket.remoteAddress;
-});
-
-Stream.prototype.__defineGetter__('remotePort', function remotePort() {
- return this.socket && this.socket.remotePort;
-});
-
-Stream.prototype.setNoDelay = function setNoDelay(enable) {
- return this.socket && this.socket.setNoDelay(enable);
-};
-
-Stream.prototype.setKeepAlive = function(setting, msecs) {
- return this.socket && this.socket.setKeepAlive(setting, msecs);
-};
-
-Stream.prototype.getPeerCertificate = function() {
- return this.socket && this.socket.getPeerCertificate();
-};
-
-Stream.prototype.getSession = function() {
- return this.socket && this.socket.getSession();
-};
-
-Stream.prototype.isSessionReused = function() {
- return this.socket && this.socket.isSessionReused();
-};
-
-Stream.prototype.getCipher = function() {
- return this.socket && this.socket.getCipher();
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/utils.js
+++ /dev/null
@@ -1,142 +0,0 @@
-var spdy = require('../spdy'),
- utils = exports;
-
-var stream = require('stream'),
- zlib = require('zlib'),
- Buffer = require('buffer').Buffer;
-
-// Export streams related stuff
-utils.isLegacy = !stream.Duplex;
-if (utils.isLegacy)
- utils.DuplexStream = stream;
-else
- utils.DuplexStream = stream.Duplex;
-
-utils.isArgvParser = !/^v(0\.12|0\.11|0\.10|0\.8|0\.9)\./.test(process.version);
-
-//
-// ### function createDeflate (version, compression)
-// #### @version {Number} SPDY version
-// #### @compression {Boolean} whether to enable compression
-// Creates deflate stream with SPDY dictionary
-//
-utils.createDeflate = function createDeflate(version, compression) {
- var deflate = zlib.createDeflate({
- dictionary: spdy.protocol.dictionary[version],
- flush: zlib.Z_SYNC_FLUSH,
- windowBits: 11,
- level: compression ? zlib.Z_DEFAULT_COMPRESSION : zlib.Z_NO_COMPRESSION
- });
-
- // Define lock information early
- deflate.locked = false;
- deflate.lockQueue = [];
- if (spdy.utils.isLegacy)
- deflate._flush = zlib.Z_SYNC_FLUSH;
-
- return deflate;
-};
-
-//
-// ### function createInflate (version)
-// #### @version {Number} SPDY version
-// Creates inflate stream with SPDY dictionary
-//
-utils.createInflate = function createInflate(version) {
- var inflate = zlib.createInflate({
- dictionary: spdy.protocol.dictionary[version],
- flush: zlib.Z_SYNC_FLUSH,
- windowBits: 0
- });
-
- // Define lock information early
- inflate.locked = false;
- inflate.lockQueue = [];
- if (spdy.utils.isLegacy)
- inflate._flush = zlib.Z_SYNC_FLUSH;
-
- return inflate;
-};
-
-//
-// ### function resetZlibStream (stream)
-// #### @stream {zlib.Stream} stream
-// Resets zlib stream and associated locks
-//
-utils.resetZlibStream = function resetZlibStream(stream, callback) {
- if (stream.locked) {
- stream.lockQueue.push(function() {
- resetZlibStream(stream, callback);
- });
- return;
- }
-
- stream.reset();
- stream.lockQueue = [];
-
- callback(null);
-};
-
-var delta = 0;
-//
-// ### function zstream (stream, buffer, callback)
-// #### @stream {Deflate|Inflate} One of streams above
-// #### @buffer {Buffer} Input data (to compress or to decompress)
-// #### @callback {Function} Continuation to callback
-// Compress/decompress data and pass it to callback
-//
-utils.zstream = function zstream(stream, buffer, callback) {
- var chunks = [],
- total = 0;
-
- if (stream.locked) {
- stream.lockQueue.push(function() {
- zstream(stream, buffer, callback);
- });
- return;
- }
- stream.locked = true;
-
- function collect(chunk) {
- chunks.push(chunk);
- total += chunk.length;
- }
- stream.on('data', collect);
-
- stream.write(buffer, done);
-
- function done() {
- stream.removeAllListeners('data');
- stream.removeAllListeners('error');
-
- if (callback)
- callback(null, chunks, total);
-
- stream.locked = false;
- var deferred = stream.lockQueue.shift();
- if (deferred)
- deferred();
- };
-
- stream.once('error', function(err) {
- stream.removeAllListeners('data');
- callback(err);
- callback = null;
- });
-};
-
-//
-// ### function zwrap (stream)
-// #### @stream {zlib.Stream} stream to wrap
-// Wraps stream within function to allow simple deflate/inflate
-//
-utils.zwrap = function zwrap(stream) {
- return function(data, callback) {
- utils.zstream(stream, data, callback);
- };
-};
-
-if (typeof setImmediate === 'undefined')
- utils.nextTick = process.nextTick.bind(process);
-else
- utils.nextTick = setImmediate;
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/lib/spdy/zlib-pool.js
+++ /dev/null
@@ -1,61 +0,0 @@
-var zlibpool = exports,
- spdy = require('../spdy');
-
-//
-// ### function Pool (compression)
-// #### @compression {Boolean} whether to enable compression
-// Zlib streams pool
-//
-function Pool(compression) {
- this.compression = compression;
- this.pool = {
- 'spdy/2': [],
- 'spdy/3': [],
- 'spdy/3.1': []
- };
-}
-
-//
-// ### function create (compression)
-// #### @compression {Boolean} whether to enable compression
-// Returns instance of Pool
-//
-zlibpool.create = function create(compression) {
- return new Pool(compression);
-};
-
-var x = 0;
-//
-// ### function get ()
-// Returns pair from pool or a new one
-//
-Pool.prototype.get = function get(version, callback) {
- if (this.pool[version].length > 0) {
- return this.pool[version].pop();
- } else {
- var id = version.split('/', 2)[1];
-
- return {
- version: version,
- deflate: spdy.utils.createDeflate(id, this.compression),
- inflate: spdy.utils.createInflate(id)
- };
- }
-};
-
-//
-// ### function put (pair)
-// Puts pair into pool
-//
-Pool.prototype.put = function put(pair) {
- var self = this,
- waiting = 2;
-
- spdy.utils.resetZlibStream(pair.inflate, done);
- spdy.utils.resetZlibStream(pair.deflate, done);
-
- function done() {
- if (--waiting === 0)
- self.pool[pair.version].push(pair);
- }
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/package.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "name": "spdy",
- "version": "1.32.5",
- "description": "Implementation of the SPDY protocol on node.js.",
- "license": "MIT",
- "keywords": [
- "spdy"
- ],
- "repository": {
- "type": "git",
- "url": "git://github.com/indutny/node-spdy.git"
- },
- "homepage": "https://github.com/indutny/node-spdy",
- "bugs": {
- "email": "node-spdy+bugs@indutny.com",
- "url": "https://github.com/indutny/node-spdy/issues"
- },
- "author": "Fedor Indutny <fedor.indutny@gmail.com>",
- "contributors": [
- "Chris Storm <github@eeecooks.com>",
- "François de Metz <francois@2metz.fr>",
- "Ilya Grigorik <ilya@igvita.com>",
- "Roberto Peon",
- "Tatsuhiro Tsujikawa",
- "Jesse Cravens <jesse.cravens@gmail.com>"
- ],
- "dependencies": {},
- "devDependencies": {
- "mocha": "1.3.x"
- },
- "scripts": {
- "test": "mocha --ui tdd --growl --reporter spec test/unit/*-test.js"
- },
- "engines": [
- "node >= 0.7.0"
- ],
- "main": "./lib/spdy",
- "optionalDependencies": {}
-}
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/test/benchmarks/syn.js
+++ /dev/null
@@ -1,51 +0,0 @@
-var tls = require('tls'),
- frames = require('../fixtures/frames');
-
-var uri = require('url').parse(process.argv[2]),
- host = uri.hostname,
- port = +uri.port,
- url = uri.path;
-
-frames.createSynStream(host, url, function(syn_stream) {
- var start = +new Date,
- num = 3000;
-
- batch(port, host, syn_stream, 100, num, function() {
- var end = +new Date;
- console.log('requests/sec : %d', 1000 * num / (end - start));
- });
-});
-
-function request(port, host, data, callback) {
- var socket = tls.connect(port, host, {
- NPNProtocols: ['spdy/2'],
- ALPNProtocols: ['spdy/2']
- }, function() {
- socket.write(data);
- socket.once('data', function() {
- socket.destroy();
- callback();
- });
- });
-
- return socket;
-};
-
-function batch(port, host, data, parallel, num, callback) {
- var left = num,
- done = 0;
-
- for (var i = 0; i < parallel; i++) {
- run(i);
- }
-
- function run(i) {
- left--;
- if (left < 0) return;
-
- request(port, host, data, function() {
- if (++done === num) return callback();
- run(i);
- });
- }
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/test/fixtures/frames.js
+++ /dev/null
@@ -1,38 +0,0 @@
-var spdy = require('../../lib/spdy'),
- Buffer = require('buffer').Buffer;
-
-exports.createSynStream = function(host, url, callback) {
- var deflate = spdy.utils.createDeflate(),
- chunks = [],
- chunksTotal = 0,
- syn_stream;
-
- deflate.on('data', function(chunk) {
- chunks.push(chunk);
- chunksTotal += chunk.length;
- });
- deflate.write(new Buffer([ 0x00, 0x02, 0x00, 0x04 ]));
- deflate.write('host');
- deflate.write(new Buffer([ 0x00, host.length ]));
- deflate.write(host);
- deflate.write(new Buffer([ 0x00, 0x03 ]));
- deflate.write('url');
- deflate.write(new Buffer([ 0x00, url.length ]));
- deflate.write(url);
-
- deflate.flush(function() {
- syn_stream = new Buffer(18 + chunksTotal);
- syn_stream.writeUInt32BE(0x80020001, 0);
- syn_stream.writeUInt32BE(chunksTotal + 8, 4);
- syn_stream.writeUInt32BE(0x00000001, 8);
- syn_stream.writeUInt32BE(0x00000000, 12);
-
- var offset = 18;
- chunks.forEach(function(chunk) {
- chunk.copy(syn_stream, offset);
- offset += chunk.length;
- });
-
- callback(syn_stream);
- });
-};
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/test/fixtures/keys.js
+++ /dev/null
@@ -1,12 +0,0 @@
-var fs = require('fs'),
- path = require('path');
-
-var keysDir = require('path').resolve(__dirname, '../../keys/'),
- options = {
- key: fs.readFileSync(keysDir + '/spdy-key.pem'),
- cert: fs.readFileSync(keysDir + '/spdy-cert.pem'),
- ca: fs.readFileSync(keysDir + '/spdy-csr.pem'),
- rejectUnauthorized: false
- };
-
-module.exports = options;
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/test/unit/connect-test.js
+++ /dev/null
@@ -1,239 +0,0 @@
-var assert = require('assert'),
- spdy = require('../../'),
- zlib = require('zlib'),
- keys = require('../fixtures/keys'),
- https = require('https'),
- tls = require('tls'),
- Buffer = require('buffer').Buffer,
- PORT = 8081;
-
-suite('A SPDY Server / Connect', function() {
- var server;
- var fox = 'The quick brown fox jumps over the lazy dog';
-
- setup(function(done) {
- server = spdy.createServer(keys, function(req, res) {
- var comp = req.url === '/gzip' ? zlib.createGzip() :
- req.url === '/deflate' ? zlib.createDeflate() :
- null;
-
- if (req.url == '/headerTest') {
- if (req.headers['accept-encoding'] == 'gzip, deflate')
- return res.end(fox);
- else
- return res.end();
- }
-
- // Terminate connection gracefully
- if (req.url === '/goaway')
- req.socket.connection.end();
-
- if (!comp)
- return res.end(fox);
-
- res.writeHead(200, { 'Content-Encoding' : req.url.slice(1) });
- comp.on('data', function(chunk) {
- res.write(chunk);
- });
- comp.once('end', function() {
- res.end();
- });
- comp.end(fox);
- });
-
- server.listen(PORT, done);
- });
-
- teardown(function(done) {
- server.close(done);
- });
-
- test('should respond on regular https requests', function(done) {
- var req = https.request({
- host: '127.0.0.1',
- port: PORT,
- path: '/',
- method: 'GET',
- agent: false,
- rejectUnauthorized: false
- }, function(res) {
- var received = '';
- res.on('data', function(chunk) {
- received += chunk;
- });
- res.once('end', function() {
- assert.equal(received, fox);
- done();
- });
- assert.equal(res.statusCode, 200);
- });
- req.end();
- });
-
- function spdyReqTest(url) {
- test('should respond on spdy requests on ' + url, function(done) {
- var agent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- rejectUnauthorized: false
- });
-
- var req = https.request({
- path: url,
- method: 'GET',
- agent: agent,
- }, function(res) {
- var received = '';
- res.on('data', function(chunk) {
- received += chunk;
- });
- res.once('end', function() {
- assert.equal(received, fox);
- agent.close();
- done();
- });
- assert.equal(res.statusCode, 200);
- });
- req.end();
- });
- }
-
- spdyReqTest('/');
- spdyReqTest('/gzip');
- spdyReqTest('/deflate');
-
- test('should not fail at a lot of RSTs', function(done) {
- var s = tls.connect({
- host: '127.0.0.1',
- port: PORT,
- NPNProtocols: [ 'spdy/3' ],
- rejectUnauthorized: false
- }, function() {
- var rst = new Buffer([
- 0x80, 0x03, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x08,
- 0x00, 0x00, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x00
- ]);
- var rsts = [];
- for (var i = 0; i < 1000; i++)
- rsts.push(rst);
- rsts = Buffer.concat(rsts, rst.length * rsts.length);
- for (var i = 0; i < 10; i++)
- s.write(rsts);
- s.write(rsts, function() {
- s.destroy();
- done();
- });
- });
- });
-
- test('should not decompress stream when decompress is false', function(done) {
- var agent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- rejectUnauthorized: false,
- spdy: {
- decompress: false
- }
- });
-
- var req = https.request({
- path: '/gzip',
- method: 'GET',
- agent: agent,
- }, function(res) {
- var received = [];
- res.on('data', function(chunk) {
- received.push(chunk);
- });
- res.once('end', function() {
- agent.close();
-
- zlib.gunzip(Buffer.concat(received), function(err, decompressed) {
- assert.equal(decompressed, fox);
- done();
- });
- });
- assert.equal(res.statusCode, 200);
- assert.equal(res.headers['content-encoding'], 'gzip');
- });
- req.end();
- });
-
- test('should not create RangeErrors on client errors', function(done) {
- // https://github.com/indutny/node-spdy/issues/147
- var agent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- rejectUnauthorized: true
- }).on('error', function (err) {
- assert(err.message === 'self signed certificate' ||
- err.message === 'DEPTH_ZERO_SELF_SIGNED_CERT');
- });
-
- var req = https.request({
- path: '/',
- method: 'GET',
- agent: agent
- });
- req.on('error', function (err) {
- assert.equal(err.code, 'ECONNRESET');
- done();
- });
- req.end();
- });
-
- test('should not support GOAWAY', function(done) {
- // https://github.com/indutny/node-spdy/issues/147
- var agent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- rejectUnauthorized: false
- });
-
- var total = '';
- var req = https.request({
- path: '/goaway',
- method: 'GET',
- agent: agent
- }, function(res) {
- res.on('data', function(chunk) {
- total += chunk;
- });
- });
- req.end();
-
- agent._spdyState.socket.once('close', function() {
- assert.equal(total, fox);
- done();
- });
- });
-
- test('should add accept-encoding header to request headers, ' +
- 'if none present',
- function(done) {
- var agent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- rejectUnauthorized: false
- });
-
- var req = https.request({
- path: '/headerTest',
- method: 'GET',
- agent: agent,
- }, function(res) {
- var total = '';
- res.on('data', function(chunk){
- total += chunk;
- });
- res.once('end', function() {
- agent.close();
- assert.equal(total, fox);
- done();
- });
- });
- req.end();
- });
-});
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/test/unit/plain-test.js
+++ /dev/null
@@ -1,142 +0,0 @@
-var assert = require('assert'),
- spdy = require('../../'),
- keys = require('../fixtures/keys'),
- http = require('http'),
- tls = require('tls'),
- Buffer = require('buffer').Buffer,
- PORT = 8081;
-
-suite('A SPDY Server / Plain', function() {
- var server;
- setup(function(done) {
- server = spdy.createServer({ plain: true, ssl: false }, function(req, res) {
- res.end('ok');
- });
-
- server.listen(PORT, done);
- });
-
- teardown(function(done) {
- server.close(done);
- });
-
- test('should respond on regular http requests', function(done) {
- var req = http.request({
- host: '127.0.0.1',
- port: PORT,
- path: '/',
- method: 'GET',
- agent: false,
- rejectUnauthorized: false
- }, function(res) {
- res.on('data', function() {
- // Ignore incoming data
- });
- assert.equal(res.statusCode, 200);
- done();
- });
- req.end();
- });
-
- test('should respond on spdy requests', function(done) {
- var agent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- spdy: {
- ssl: false,
- plain: true,
- version: 3
- }
- });
-
- var req = http.request({
- path: '/',
- method: 'GET',
- agent: agent,
- }, function(res) {
- res.on('data', function() {
- // Ignore incoming data
- });
- assert.equal(res.statusCode, 200);
- agent.close();
- done();
- });
- req.end();
- });
-
- test('should handle header values with colons', function(done) {
- var agent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- spdy: {
- ssl: false,
- plain: true
- }
- });
-
- var refererValue = 'http://127.0.0.1:' + PORT + '/header-with-colon';
-
- server.on('request', function(req) {
- assert.equal(req.headers.referer, refererValue);
- });
-
- http.request({
- path: '/',
- method: 'GET',
- agent: agent,
- headers: { 'referer': refererValue }
- }, function(res) {
- assert.equal(res.statusCode, 200);
- agent.close();
- done();
- }).end();
- });
-
- test('should send date header as default', function(done) {
- var agent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- spdy: {
- ssl: false,
- plain: true
- }
- });
-
- http.request({
- path: '/',
- method: 'GET',
- agent: agent
- }, function(res) {
- assert.equal(typeof res.headers.date, 'string');
- agent.close();
- done();
- }).end();
- });
-
- test('should not send date header if res.sendDate is false', function(done) {
- var agent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- spdy: {
- ssl: false,
- plain: true
- }
- });
-
- server.removeAllListeners('request');
- server.on('request', function(req, res) {
- res.sendDate = false;
- res.end('ok');
- });
-
- http.request({
- path: '/',
- method: 'GET',
- agent: agent
- }, function(res) {
- assert.equal(typeof res.headers.date, 'undefined');
- agent.close();
- done();
- }).end();
- });
-});
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/test/unit/proxy-test.js
+++ /dev/null
@@ -1,70 +0,0 @@
-var assert = require('assert'),
- https = require('https'),
- spdy = require('../../'),
- keys = require('../fixtures/keys'),
- net = require('net'),
- url = require('url'),
- PORT = 8081;
-
-suite('A SPDY server / Proxy', function() {
- test('should emit connect event on CONNECT requests', function(done) {
- var proxyServer = spdy.createServer(keys);
- proxyServer.on('connect', function(req, socket) {
- var srvUrl = url.parse('http://' + req.url);
- var srvSocket = net.connect(srvUrl.port, srvUrl.hostname, function() {
- socket._lock(function() {
- var headers = {
- 'Connection': 'keep-alive',
- 'Proxy-Agent': 'SPDY Proxy'
- }
- socket._spdyState.framer.replyFrame(
- socket._spdyState.id, 200, "Connection Established", headers,
- function (err, frame) {
- socket.connection.write(frame);
- socket._unlock();
- srvSocket.pipe(socket);
- socket.pipe(srvSocket);
- }
- );
- });
- });
- });
-
- proxyServer.listen(PORT, '127.0.0.1', function() {
- var spdyAgent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- rejectUnauthorized: false
- });
-
- var options = {
- method: 'CONNECT',
- path: 'www.google.com:80',
- agent: spdyAgent
- };
-
- var req = https.request(options);
- req.end();
-
- req.on('connect', function(res, socket) {
- var googlePage = "";
- socket.write('GET / HTTP/1.1\r\n' +
- 'Host: www.google.com:80\r\n' +
- 'Connection: close\r\n' +
- '\r\n');
-
- socket.on('data', function(chunk) {
- googlePage = googlePage + chunk.toString();
- });
-
- socket.on('end', function() {
- assert.notEqual(googlePage.search('google'), -1,
- "Google page should contain string 'google'");
- spdyAgent.close(function() {
- proxyServer.close(done);
- });
- });
- });
- });
- });
-});
deleted file mode 100644
--- a/testing/xpcshell/node-spdy/test/unit/stream-test.js
+++ /dev/null
@@ -1,411 +0,0 @@
-var assert = require('assert'),
- zlib = require('zlib'),
- spdy = require('../../'),
- keys = require('../fixtures/keys'),
- https = require('https'),
- util = require('util'),
- Buffer = require('buffer').Buffer,
- PORT = 8081;
-
-suite('A SPDY Server / Stream', function() {
- var server;
- var agent;
- var pair = null;
-
- suite('normal', function() {
- run({});
- });
- suite('maxChunk = false', function() {
- run({ maxChunk: false });
- });
-
- function run(options) {
- setup(function(done) {
- var waiting = 2;
- pair = { server: null, client: null };
-
- server = spdy.createServer(util._extend(keys, options),
- function(req, res) {
- assert.equal(req.method, 'POST');
- pair.server = { req: req, res: res };
-
- // Just to remove junk from stream's buffer
- if (spdy.utils.isLegacy)
- req.once('data', function(data) {
- assert.equal(data.toString(), 'shame');
- if (--waiting === 0)
- done();
- });
- else
- req.once('readable', function() {
- assert.equal(req.read().toString(), 'shame');
- if (--waiting === 0)
- done();
- });
-
- res.writeHead(200);
- });
-
- server.listen(PORT, function() {
- agent = spdy.createAgent({
- host: '127.0.0.1',
- port: PORT,
- rejectUnauthorized: false
- });
-
- pair.client = {
- req: https.request({
- path: '/',
- method: 'POST',
- agent: agent
- }, function(res) {
- pair.client.res = res;
- if (--waiting === 0)
- done();
- }),
- res: null
- };
- pair.client.req.write('shame');
- });
- });
-
- teardown(function(done) {
- pair = null;
- agent.close(function() {
- server.close(done);
- });
- });
-
- test('should support PING from client', function(done) {
- agent.ping(done);
- });
-
- test('should support PING from server', function(done) {
- pair.server.res.socket.ping(done);
- });
-
- test('piping a lot of data', function(done) {
- var big = new Buffer(2 * 1024 * 1024);
- for (var i = 0; i < big.length; i++)
- big[i] = ~~(Math.random() * 256);
-
- var offset = 0;
- if (spdy.utils.isLegacy) {
- pair.client.res.on('data', function(chunk) {
- for (var i = 0; i < chunk.length; i++) {
- assert(i + offset < big.length);
- assert.equal(big[i + offset], chunk[i]);
- }
- offset += i;
- });
- } else {
- pair.client.res.on('readable', function() {
- var bigEcho = pair.client.res.read(big.length);
- if (bigEcho) {
- assert.equal(big.length, bigEcho.length);
- for (var i = 0; i < big.length; i += 256) {
- assert.equal(big.slice(i, i + 256).toString('hex'),
- bigEcho.slice(i, i + 256).toString('hex'));
- }
- offset += bigEcho.length;
- }
- });
- }
- pair.client.res.on('end', function() {
- assert.equal(offset, big.length);
- done();
- });
-
- pair.server.req.pipe(pair.server.res);
- pair.client.req.end(big);
- });
-
- test('destroy in the middle', function(done) {
- var big = new Buffer(2 * 1024 * 1024);
- for (var i = 0; i < big.length; i++)
- big[i] = ~~(Math.random() * 256);
-
- var offset = 0;
- pair.server.req.on('data', function(chunk) {
- for (var i = 0; i < chunk.length; i++) {
- assert(i + offset < big.length);
- assert.equal(big[i + offset], chunk[i]);
- }
- offset += i;
- });
-
- pair.server.req.on('close', function() {
- assert(offset < big.length);
- done();
- });
-
- pair.client.req.write(big.slice(0, big.length >> 1));
- pair.client.req.write(big.slice(big.length >> 1));
- pair.client.req.socket.destroy();
- });
-
- test('destroySoon in the middle', function(done) {
- var big = new Buffer(2 * 1024 * 1024);
- for (var i = 0; i < big.length; i++)
- big[i] = ~~(Math.random() * 256);
-
- var offset = 0;
- pair.server.req.on('data', function(chunk) {
- for (var i = 0; i < chunk.length; i++) {
- assert(i + offset < big.length);
- assert.equal(big[i + offset], chunk[i]);
- }
- offset += i;
- });
-
- pair.server.req.on('end', function() {
- assert.equal(offset, big.length);
- done();
- });
-
- pair.client.req.write(big.slice(0, big.length >> 1));
- pair.client.req.write(big.slice(big.length >> 1));
- pair.client.req.socket.destroySoon();
- });
-
- test('ending', function(done) {
- var data = '';
- pair.server.req.on('data', function(chunk) {
- data += chunk;
- });
-
- pair.server.req.on('end', function() {
- assert.equal(data, 'hello');
- pair.server.res.end();
- done();
- });
-
- pair.client.req.end('hello');
- });
-
- test('trailing headers from client', function(done) {
- pair.server.req.once('trailers', function(headers) {
- assert.equal(headers.wtf, 'yes');
- assert.equal(pair.server.req.trailers.wtf, 'yes');
- done();
- });
- pair.client.req.addTrailers({ wtf: 'yes' });
- });
-
- test('trailing headers from server', function(done) {
- pair.client.res.once('trailers', function(headers) {
- assert.equal(headers.wtf, 'yes');
- assert.equal(pair.client.res.trailers.wtf, 'yes');
- done();
- });
- pair.server.res.addTrailers({ wtf: 'yes' });
- });
-
- test('push stream', function(done) {
- agent.once('push', function(req) {
- var gotTrailers = false;
- assert.equal(req.headers.wtf, 'true');
-
- var chunks = '';
- req.once('data', function(chunk) {
- chunks += chunk;
- });
- req.once('trailers', function(trailers) {
- assert.equal(trailers.ok, 'yes');
- gotTrailers = true;
- });
- req.once('end', function() {
- assert(gotTrailers);
- assert.equal(req.trailers.ok, 'yes');
- assert.equal(chunks, 'yes, wtf');
- done();
- });
- });
-
- pair.server.res.push('/wtf', { wtf: true }, function(err, stream) {
- assert(!err);
- stream.on('error', function(err) {
- throw err;
- });
- stream.sendHeaders({ ok: 'yes' });
- stream.end('yes, wtf');
- });
- });
-
- test('push stream with compression', function(done) {
- agent.once('push', function(req) {
- req.once('data', function(chunk) {
- assert.equal(chunk.toString(), 'yes, wtf');
- done();
- });
- });
- pair.server.res.push('/wtf', {
- 'Content-Encoding': 'gzip'
- }, function(err, stream) {
- assert(!err);
- stream.on('error', function(err) {
- throw err;
- });
- var gzip = zlib.createGzip();
- gzip.on('data', function(data) {
- stream.write(data);
- });
- gzip.on('end', function() {
- stream.end();
- });
- gzip.end('yes, wtf');
- });
- });
-
- test('push stream - big chunks', function(done) {
- var count = 10;
- var chunk = new Buffer(256 * 1024 - 7);
- for (var i = 0; i < chunk.length; i++)
- chunk[i] = ~~(Math.random() * 256);
-
- agent.once('push', function(req) {
- assert.equal(req.headers.wtf, 'true');
- var offset = 0;
- var total = 0;
- req.on('data', function(data) {
- for (var i = 0; i < data.length; i++) {
- assert.equal(data[i],
- chunk[(offset + i) % chunk.length],
- 'Mismatch at: ' + (offset + i));
- }
- offset = (offset + i) % chunk.length;
- total += i;
- });
- req.once('end', function() {
- assert.equal(total, count * chunk.length);
- done();
- });
- });
-
- pair.server.res.push('/wtf', { wtf: true }, function(err, stream) {
- assert(!err);
- stream.on('error', function(err) {
- throw err;
- });
-
- function start(count) {
- if (count === 1)
- return stream.end(chunk);
- stream.write(chunk);
- setTimeout(function() {
- start(count - 1);
- }, 5);
- }
- start(count);
- });
- });
-
- test('push stream - early close', function(done) {
- agent.once('push', function(req) {
- var chunks = '';
- req.on('data', function(chunk) {
- chunks += chunk;
- });
- req.once('end', function() {
- assert.equal(chunks, 'yes, wtf');
- done();
- });
- });
- var stream = pair.server.res.push('/wtf', {});
- pair.client.res.on('data', function() {});
- pair.client.res.once('end', function() {
- stream.end('yes, wtf');
- });
- pair.client.req.end();
- pair.server.res.end();
- });
-
- test('timing out', function(done) {
- var data = '';
-
- pair.server.req.socket.setTimeout(300);
- pair.client.req.on('error', function() {
- done();
- });
- });
-
- test('timing out after write', function(done) {
- var data = '';
- var chunks = 0;
-
- pair.server.req.socket.setTimeout(150);
- setTimeout(function() {
- pair.server.res.write('ok1');
- setTimeout(function() {
- pair.server.res.write('ok2');
- }, 100);
- }, 100);
-
- pair.client.res.on('data', function(chunk) {
- chunk = chunk.toString();
- assert(chunks === 0 && chunk === 'ok1' ||
- chunks === 1 && chunk === 'ok2');
- chunks++;
- });
-
- pair.client.req.on('error', function() {
- assert.equal(chunks, 2);
- done();
- });
- });
-
- test('req[spdyVersion/streamID]', function(done) {
- var data = '';
- assert.equal(pair.server.req.spdyVersion, 3.1);
- assert(pair.server.req.streamID > 0);
-
- pair.server.req.resume();
- pair.server.req.on('end', function() {
- pair.server.res.end();
- done();
- });
-
- pair.client.req.end();
- });
- }
-
- test('it should not attempt to send empty arrays', function(done) {
- var server = spdy.createServer(keys);
- var agent;
-
- server.on('request', function(req, res) {
- setTimeout(function() {
- res.end();
- done();
- server.close();
- agent.close();
- }, 100);
- });
-
- server.listen(PORT, function() {
- agent = spdy.createAgent({
- port: PORT,
- rejectUnauthorized: false
- }).on('error', function(err) {
- done(err);
- });
-
- var body = new Buffer([1,2,3,4]);
-
- var opts = {
- method: 'POST',
- headers: {
- 'Host': 'localhost',
- 'Content-Length': body.length
- },
- path: '/some-url',
- agent: agent
- };
-
- var req = https.request(opts, function(res) {
- }).on('error', function(err) {
- });
- req.end(body);
- });
- });
-});
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -979,58 +979,54 @@ class XPCShellTests(object):
"""
Simple wrapper to get the absolute path for a given directory name.
On a remote system, we need to overload this to work on the remote filesystem.
"""
return os.path.abspath(dirname)
def trySetupNode(self):
"""
- Run node for SPDY tests, if available, and updates mozinfo as appropriate.
+ Run node for HTTP/2 tests, if available, and updates mozinfo as appropriate.
"""
nodeMozInfo = {'hasNode': False} # Assume the worst
nodeBin = None
# We try to find the node executable in the path given to us by the user in
# the MOZ_NODE_PATH environment variable
localPath = os.getenv('MOZ_NODE_PATH', None)
if localPath and os.path.exists(localPath) and os.path.isfile(localPath):
nodeBin = localPath
if nodeBin:
self.log.info('Found node at %s' % (nodeBin,))
def startServer(name, serverJs):
if os.path.exists(serverJs):
- # OK, we found our SPDY server, let's try to get it running
+ # OK, we found our server, let's try to get it running
self.log.info('Found %s at %s' % (name, serverJs))
try:
- # We pipe stdin to node because the spdy server will exit when its
+ # We pipe stdin to node because the server will exit when its
# stdin reaches EOF
process = Popen([nodeBin, serverJs], stdin=PIPE, stdout=PIPE,
stderr=PIPE, env=self.env, cwd=os.getcwd())
self.nodeProc[name] = process
# Check to make sure the server starts properly by waiting for it to
# tell us it's started
msg = process.stdout.readline()
if 'server listening' in msg:
nodeMozInfo['hasNode'] = True
- searchObj = re.search( r'SPDY server listening on port (.*)', msg, 0)
- if searchObj:
- self.env["MOZSPDY_PORT"] = searchObj.group(1)
searchObj = re.search( r'HTTP2 server listening on port (.*)', msg, 0)
if searchObj:
self.env["MOZHTTP2_PORT"] = searchObj.group(1)
except OSError, e:
# This occurs if the subprocess couldn't be started
self.log.error('Could not run %s server: %s' % (name, str(e)))
myDir = os.path.split(os.path.abspath(__file__))[0]
- startServer('moz-spdy', os.path.join(myDir, 'moz-spdy', 'moz-spdy.js'))
startServer('moz-http2', os.path.join(myDir, 'moz-http2', 'moz-http2.js'))
elif os.getenv('MOZ_ASSUME_NODE_RUNNING', None):
self.log.info('Assuming required node servers are already running')
nodeMozInfo['hasNode'] = True
mozinfo.update(nodeMozInfo)
def shutdownNode(self):
@@ -1232,17 +1228,17 @@ class XPCShellTests(object):
# sections that defines a relative application directory for test runs. If
# defined we pass 'grePath/$appDirKey' for the -a parameter of the xpcshell
# test harness.
appDirKey = None
if "appname" in self.mozInfo:
appDirKey = self.mozInfo["appname"] + "-appdir"
# We have to do this before we build the test list so we know whether or
- # not to run tests that depend on having the node spdy server
+ # not to run tests that depend on having the node http/2 server
self.trySetupNode()
pStdout, pStderr = self.getPipes()
self.buildTestList(test_tags, testPaths)
if self.singleFile:
self.sequential = True