mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 13:25:37 +00:00
bug 597684 Implement HTTP Assoc-req and Banned Pipelines on nsHttpConnectionInfo r=honzab
--HG-- extra : rebase_source : 26243e1af9e0554553520dae435cc4dcfd551746
This commit is contained in:
parent
0fb95ce9a6
commit
92aaf5d2fc
@ -811,6 +811,10 @@ pref("network.http.pipelining.maxrequests" , 4);
|
|||||||
// Prompt for 307 redirects
|
// Prompt for 307 redirects
|
||||||
pref("network.http.prompt-temp-redirect", true);
|
pref("network.http.prompt-temp-redirect", true);
|
||||||
|
|
||||||
|
// If true generate CORRUPTED_CONTENT errors for entities that
|
||||||
|
// contain an invalid Assoc-Req response header
|
||||||
|
pref("network.http.assoc-req.enforce", false);
|
||||||
|
|
||||||
// On networks deploying QoS, it is recommended that these be lockpref()'d,
|
// On networks deploying QoS, it is recommended that these be lockpref()'d,
|
||||||
// since inappropriate marking can easily overwhelm bandwidth reservations
|
// since inappropriate marking can easily overwhelm bandwidth reservations
|
||||||
// for certain services (i.e. EF for VoIP, AF4x for interactive video,
|
// for certain services (i.e. EF for VoIP, AF4x for interactive video,
|
||||||
|
@ -2159,6 +2159,24 @@ SpdySession::PipelineDepthAvailable()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SpdySession::SetPipelinePosition(PRInt32 position)
|
||||||
|
{
|
||||||
|
// This API is meant for pipelining, SpdySession's should be
|
||||||
|
// extended with AddStream()
|
||||||
|
|
||||||
|
NS_ABORT_IF_FALSE(false,
|
||||||
|
"SpdySession::SetPipelinePosition() should not be called");
|
||||||
|
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRInt32
|
||||||
|
SpdySession::PipelinePosition()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Pass through methods of nsAHttpConnection
|
// Pass through methods of nsAHttpConnection
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -123,6 +123,12 @@ public:
|
|||||||
|
|
||||||
// called to count the number of sub transactions that can be added
|
// called to count the number of sub transactions that can be added
|
||||||
virtual PRUint16 PipelineDepthAvailable() = 0;
|
virtual PRUint16 PipelineDepthAvailable() = 0;
|
||||||
|
|
||||||
|
// Used to inform the connection that it is being used in a pipelined
|
||||||
|
// context. That may influence the handling of some errors.
|
||||||
|
// The value is the pipeline position.
|
||||||
|
virtual nsresult SetPipelinePosition(PRInt32) = 0;
|
||||||
|
virtual PRInt32 PipelinePosition() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NS_DECL_NSAHTTPTRANSACTION \
|
#define NS_DECL_NSAHTTPTRANSACTION \
|
||||||
@ -144,7 +150,9 @@ public:
|
|||||||
PRUint32 Http1xTransactionCount(); \
|
PRUint32 Http1xTransactionCount(); \
|
||||||
nsresult TakeSubTransactions(nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions); \
|
nsresult TakeSubTransactions(nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions); \
|
||||||
nsresult AddTransaction(nsAHttpTransaction *); \
|
nsresult AddTransaction(nsAHttpTransaction *); \
|
||||||
PRUint16 PipelineDepthAvailable();
|
PRUint16 PipelineDepthAvailable(); \
|
||||||
|
nsresult SetPipelinePosition(PRInt32); \
|
||||||
|
PRInt32 PipelinePosition();
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// nsAHttpSegmentReader
|
// nsAHttpSegmentReader
|
||||||
|
@ -57,6 +57,7 @@ HTTP_ATOM(Accept_Ranges, "Accept-Ranges")
|
|||||||
HTTP_ATOM(Age, "Age")
|
HTTP_ATOM(Age, "Age")
|
||||||
HTTP_ATOM(Allow, "Allow")
|
HTTP_ATOM(Allow, "Allow")
|
||||||
HTTP_ATOM(Alternate_Protocol, "Alternate-Protocol")
|
HTTP_ATOM(Alternate_Protocol, "Alternate-Protocol")
|
||||||
|
HTTP_ATOM(Assoc_Req, "Assoc-Req")
|
||||||
HTTP_ATOM(Authentication, "Authentication")
|
HTTP_ATOM(Authentication, "Authentication")
|
||||||
HTTP_ATOM(Authorization, "Authorization")
|
HTTP_ATOM(Authorization, "Authorization")
|
||||||
HTTP_ATOM(Cache_Control, "Cache-Control")
|
HTTP_ATOM(Cache_Control, "Cache-Control")
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
|
|
||||||
#include "nsHttpChannel.h"
|
#include "nsHttpChannel.h"
|
||||||
#include "nsHttpHandler.h"
|
#include "nsHttpHandler.h"
|
||||||
|
#include "nsStandardURL.h"
|
||||||
#include "nsIApplicationCacheService.h"
|
#include "nsIApplicationCacheService.h"
|
||||||
#include "nsIApplicationCacheContainer.h"
|
#include "nsIApplicationCacheContainer.h"
|
||||||
#include "nsIAuthInformation.h"
|
#include "nsIAuthInformation.h"
|
||||||
@ -70,6 +71,7 @@
|
|||||||
#include "nsDOMError.h"
|
#include "nsDOMError.h"
|
||||||
#include "nsAlgorithm.h"
|
#include "nsAlgorithm.h"
|
||||||
#include "sampler.h"
|
#include "sampler.h"
|
||||||
|
#include "nsIConsoleService.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
@ -768,6 +770,10 @@ nsHttpChannel::CallOnStartRequest()
|
|||||||
rv = ApplyContentConversions();
|
rv = ApplyContentConversions();
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
|
rv = EnsureAssocReq();
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
// if this channel is for a download, close off access to the cache.
|
// if this channel is for a download, close off access to the cache.
|
||||||
if (mCacheEntry && mChannelIsForDownload) {
|
if (mCacheEntry && mChannelIsForDownload) {
|
||||||
mCacheEntry->Doom();
|
mCacheEntry->Doom();
|
||||||
@ -1712,6 +1718,111 @@ nsHttpChannel::Hash(const char *buf, nsACString &hash)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsHttpChannel::EnsureAssocReq()
|
||||||
|
{
|
||||||
|
// Confirm Assoc-Req response header on pipelined transactions
|
||||||
|
// per draft-nottingham-http-pipeline-01.txt
|
||||||
|
// of the form: GET http://blah.com/foo/bar?qv
|
||||||
|
// return NS_OK as long as we don't find a violation
|
||||||
|
// (i.e. no header is ok, as are malformed headers, as are
|
||||||
|
// transactions that have not been pipelined (unless those have been
|
||||||
|
// opted in via pragma))
|
||||||
|
|
||||||
|
if (!mResponseHead)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
const char *assoc_val = mResponseHead->PeekHeader(nsHttp::Assoc_Req);
|
||||||
|
if (!assoc_val)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
if (!mTransaction || !mURI)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
if (!mTransaction->PipelinePosition()) {
|
||||||
|
// "Pragma: X-Verify-Assoc-Req" can be used to verify even non pipelined
|
||||||
|
// transactions. It is used by test harness.
|
||||||
|
|
||||||
|
const char *pragma_val = mResponseHead->PeekHeader(nsHttp::Pragma);
|
||||||
|
if (!pragma_val ||
|
||||||
|
!nsHttp::FindToken(pragma_val, "X-Verify-Assoc-Req",
|
||||||
|
HTTP_HEADER_VALUE_SEPS))
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *method = net_FindCharNotInSet(assoc_val, HTTP_LWS);
|
||||||
|
if (!method)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
bool equals;
|
||||||
|
char *endofmethod;
|
||||||
|
|
||||||
|
assoc_val = nsnull;
|
||||||
|
endofmethod = net_FindCharInSet(method, HTTP_LWS);
|
||||||
|
if (endofmethod)
|
||||||
|
assoc_val = net_FindCharNotInSet(endofmethod, HTTP_LWS);
|
||||||
|
if (!assoc_val)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
// check the method
|
||||||
|
PRInt32 methodlen = PL_strlen(mRequestHead.Method().get());
|
||||||
|
if ((methodlen != (endofmethod - method)) ||
|
||||||
|
PL_strncmp(method,
|
||||||
|
mRequestHead.Method().get(),
|
||||||
|
endofmethod - method)) {
|
||||||
|
LOG((" Assoc-Req failure Method %s", method));
|
||||||
|
if (mConnectionInfo)
|
||||||
|
mConnectionInfo->BanPipelining();
|
||||||
|
|
||||||
|
nsCOMPtr<nsIConsoleService> consoleService =
|
||||||
|
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||||
|
if (consoleService) {
|
||||||
|
nsAutoString message
|
||||||
|
(NS_LITERAL_STRING("Failed Assoc-Req. Received "));
|
||||||
|
AppendASCIItoUTF16(
|
||||||
|
mResponseHead->PeekHeader(nsHttp::Assoc_Req),
|
||||||
|
message);
|
||||||
|
message += NS_LITERAL_STRING(" expected method ");
|
||||||
|
AppendASCIItoUTF16(mRequestHead.Method().get(), message);
|
||||||
|
consoleService->LogStringMessage(message.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gHttpHandler->EnforceAssocReq())
|
||||||
|
return NS_ERROR_CORRUPTED_CONTENT;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the URL
|
||||||
|
nsCOMPtr<nsIURI> assoc_url;
|
||||||
|
if (NS_FAILED(NS_NewURI(getter_AddRefs(assoc_url), assoc_val)) ||
|
||||||
|
!assoc_url)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
mURI->Equals(assoc_url, &equals);
|
||||||
|
if (!equals) {
|
||||||
|
LOG((" Assoc-Req failure URL %s", assoc_val));
|
||||||
|
if (mConnectionInfo)
|
||||||
|
mConnectionInfo->BanPipelining();
|
||||||
|
|
||||||
|
nsCOMPtr<nsIConsoleService> consoleService =
|
||||||
|
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||||
|
if (consoleService) {
|
||||||
|
nsAutoString message
|
||||||
|
(NS_LITERAL_STRING("Failed Assoc-Req. Received "));
|
||||||
|
AppendASCIItoUTF16(
|
||||||
|
mResponseHead->PeekHeader(nsHttp::Assoc_Req),
|
||||||
|
message);
|
||||||
|
message += NS_LITERAL_STRING(" expected URL ");
|
||||||
|
AppendASCIItoUTF16(mSpec.get(), message);
|
||||||
|
consoleService->LogStringMessage(message.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gHttpHandler->EnforceAssocReq())
|
||||||
|
return NS_ERROR_CORRUPTED_CONTENT;
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// nsHttpChannel <byte-range>
|
// nsHttpChannel <byte-range>
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -182,6 +182,7 @@ private:
|
|||||||
nsresult ContinueProcessFallback(nsresult);
|
nsresult ContinueProcessFallback(nsresult);
|
||||||
bool ResponseWouldVary();
|
bool ResponseWouldVary();
|
||||||
void HandleAsyncAbort();
|
void HandleAsyncAbort();
|
||||||
|
nsresult EnsureAssocReq();
|
||||||
|
|
||||||
nsresult ContinueOnStartRequest1(nsresult);
|
nsresult ContinueOnStartRequest1(nsresult);
|
||||||
nsresult ContinueOnStartRequest2(nsresult);
|
nsresult ContinueOnStartRequest2(nsresult);
|
||||||
|
@ -736,8 +736,13 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mKeepAliveMask = mKeepAlive;
|
mKeepAliveMask = mKeepAlive;
|
||||||
mConnInfo->SetSupportsPipelining(mSupportsPipelining);
|
|
||||||
|
|
||||||
|
// Update the pipelining status in the connection info object
|
||||||
|
// and also read it back. It is possible the ci status is
|
||||||
|
// locked to false if pipelining has been banned on this ci due to
|
||||||
|
// some kind of observed flaky behavior
|
||||||
|
mSupportsPipelining = mConnInfo->SetSupportsPipelining(mSupportsPipelining);
|
||||||
|
|
||||||
// if this connection is persistent, then the server may send a "Keep-Alive"
|
// if this connection is persistent, then the server may send a "Keep-Alive"
|
||||||
// header specifying the maximum number of times the connection can be
|
// header specifying the maximum number of times the connection can be
|
||||||
// reused as well as the maximum amount of time the connection can be idle
|
// reused as well as the maximum amount of time the connection can be idle
|
||||||
|
@ -100,6 +100,27 @@ nsHttpConnectionInfo::Clone() const
|
|||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsHttpConnectionInfo::SupportsPipelining()
|
||||||
|
{
|
||||||
|
return mSupportsPipelining;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsHttpConnectionInfo::SetSupportsPipelining(bool support)
|
||||||
|
{
|
||||||
|
if (!mBannedPipelining)
|
||||||
|
mSupportsPipelining = support;
|
||||||
|
return mSupportsPipelining;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsHttpConnectionInfo::BanPipelining()
|
||||||
|
{
|
||||||
|
mBannedPipelining = true;
|
||||||
|
mSupportsPipelining = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
nsHttpConnectionInfo::ShouldForceConnectMethod()
|
nsHttpConnectionInfo::ShouldForceConnectMethod()
|
||||||
{
|
{
|
||||||
|
@ -61,6 +61,7 @@ public:
|
|||||||
, mProxyInfo(proxyInfo)
|
, mProxyInfo(proxyInfo)
|
||||||
, mUsingSSL(usingSSL)
|
, mUsingSSL(usingSSL)
|
||||||
, mSupportsPipelining(false)
|
, mSupportsPipelining(false)
|
||||||
|
, mBannedPipelining(false)
|
||||||
{
|
{
|
||||||
LOG(("Creating nsHttpConnectionInfo @%x\n", this));
|
LOG(("Creating nsHttpConnectionInfo @%x\n", this));
|
||||||
|
|
||||||
@ -127,13 +128,13 @@ public:
|
|||||||
{ mHashKey.SetCharAt(anon ? 'A' : '.', 2); }
|
{ mHashKey.SetCharAt(anon ? 'A' : '.', 2); }
|
||||||
bool GetAnonymous() { return mHashKey.CharAt(2) == 'A'; }
|
bool GetAnonymous() { return mHashKey.CharAt(2) == 'A'; }
|
||||||
|
|
||||||
bool SupportsPipelining() { return mSupportsPipelining; }
|
|
||||||
void SetSupportsPipelining(bool support)
|
|
||||||
{ mSupportsPipelining = support; }
|
|
||||||
|
|
||||||
bool ShouldForceConnectMethod();
|
bool ShouldForceConnectMethod();
|
||||||
const nsCString &GetHost() { return mHost; }
|
const nsCString &GetHost() { return mHost; }
|
||||||
|
|
||||||
|
bool SupportsPipelining();
|
||||||
|
bool SetSupportsPipelining(bool support);
|
||||||
|
void BanPipelining();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsrefcnt mRef;
|
nsrefcnt mRef;
|
||||||
nsCString mHashKey;
|
nsCString mHashKey;
|
||||||
@ -143,6 +144,7 @@ private:
|
|||||||
bool mUsingHttpProxy;
|
bool mUsingHttpProxy;
|
||||||
bool mUsingSSL;
|
bool mUsingSSL;
|
||||||
bool mSupportsPipelining;
|
bool mSupportsPipelining;
|
||||||
|
bool mBannedPipelining;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsHttpConnectionInfo_h__
|
#endif // nsHttpConnectionInfo_h__
|
||||||
|
@ -190,6 +190,7 @@ nsHttpHandler::nsHttpHandler()
|
|||||||
, mPhishyUserPassLength(1)
|
, mPhishyUserPassLength(1)
|
||||||
, mQoSBits(0x00)
|
, mQoSBits(0x00)
|
||||||
, mPipeliningOverSSL(false)
|
, mPipeliningOverSSL(false)
|
||||||
|
, mEnforceAssocReq(false)
|
||||||
, mInPrivateBrowsingMode(PRIVATE_BROWSING_UNKNOWN)
|
, mInPrivateBrowsingMode(PRIVATE_BROWSING_UNKNOWN)
|
||||||
, mLastUniqueID(NowInSeconds())
|
, mLastUniqueID(NowInSeconds())
|
||||||
, mSessionStartTime(0)
|
, mSessionStartTime(0)
|
||||||
@ -1103,6 +1104,13 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PREF_CHANGED(HTTP_PREF("assoc-req.enforce"))) {
|
||||||
|
cVar = false;
|
||||||
|
rv = prefs->GetBoolPref(HTTP_PREF("assoc-req.enforce"), &cVar);
|
||||||
|
if (NS_SUCCEEDED(rv))
|
||||||
|
mEnforceAssocReq = cVar;
|
||||||
|
}
|
||||||
|
|
||||||
// enable Persistent caching for HTTPS - bug#205921
|
// enable Persistent caching for HTTPS - bug#205921
|
||||||
if (PREF_CHANGED(BROWSER_PREF("disk_cache_ssl"))) {
|
if (PREF_CHANGED(BROWSER_PREF("disk_cache_ssl"))) {
|
||||||
cVar = false;
|
cVar = false;
|
||||||
|
@ -110,6 +110,7 @@ public:
|
|||||||
PRUint16 GetIdleSynTimeout() { return mIdleSynTimeout; }
|
PRUint16 GetIdleSynTimeout() { return mIdleSynTimeout; }
|
||||||
bool FastFallbackToIPv4() { return mFastFallbackToIPv4; }
|
bool FastFallbackToIPv4() { return mFastFallbackToIPv4; }
|
||||||
PRUint32 MaxSocketCount();
|
PRUint32 MaxSocketCount();
|
||||||
|
bool EnforceAssocReq() { return mEnforceAssocReq; }
|
||||||
|
|
||||||
bool IsPersistentHttpsCachingEnabled() { return mEnablePersistentHttpsCaching; }
|
bool IsPersistentHttpsCachingEnabled() { return mEnablePersistentHttpsCaching; }
|
||||||
bool IsTelemetryEnabled() { return mTelemetryEnabled; }
|
bool IsTelemetryEnabled() { return mTelemetryEnabled; }
|
||||||
@ -300,6 +301,7 @@ private:
|
|||||||
PRUint8 mQoSBits;
|
PRUint8 mQoSBits;
|
||||||
|
|
||||||
bool mPipeliningOverSSL;
|
bool mPipeliningOverSSL;
|
||||||
|
bool mEnforceAssocReq;
|
||||||
|
|
||||||
// cached value of whether or not the browser is in private browsing mode.
|
// cached value of whether or not the browser is in private browsing mode.
|
||||||
enum {
|
enum {
|
||||||
|
@ -131,11 +131,20 @@ nsHttpPipeline::AddTransaction(nsAHttpTransaction *trans)
|
|||||||
|
|
||||||
NS_ADDREF(trans);
|
NS_ADDREF(trans);
|
||||||
mRequestQ.AppendElement(trans);
|
mRequestQ.AppendElement(trans);
|
||||||
|
PRInt32 qlen = mRequestQ.Length();
|
||||||
|
|
||||||
|
if (qlen != 1) {
|
||||||
|
trans->SetPipelinePosition(qlen);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// do it for this case in case an idempotent cancellation
|
||||||
|
// is being repeated and an old value needs to be cleared
|
||||||
|
trans->SetPipelinePosition(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (mConnection && !mClosed) {
|
if (mConnection && !mClosed) {
|
||||||
trans->SetConnection(this);
|
trans->SetConnection(this);
|
||||||
|
if (qlen == 1)
|
||||||
if (mRequestQ.Length() == 1)
|
|
||||||
mConnection->ResumeSend();
|
mConnection->ResumeSend();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +172,24 @@ nsHttpPipeline::PipelineDepthAvailable()
|
|||||||
return mMaxPipelineDepth - currentTransactions;
|
return mMaxPipelineDepth - currentTransactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsHttpPipeline::SetPipelinePosition(PRInt32 position)
|
||||||
|
{
|
||||||
|
nsAHttpTransaction *trans = Response(0);
|
||||||
|
if (trans)
|
||||||
|
return trans->SetPipelinePosition(position);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRInt32
|
||||||
|
nsHttpPipeline::PipelinePosition()
|
||||||
|
{
|
||||||
|
nsAHttpTransaction *trans = Response(0);
|
||||||
|
if (trans)
|
||||||
|
return trans->PipelinePosition();
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// nsHttpPipeline::nsISupports
|
// nsHttpPipeline::nsISupports
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -119,6 +119,7 @@ nsHttpTransaction::nsHttpTransaction()
|
|||||||
, mPriority(0)
|
, mPriority(0)
|
||||||
, mRestartCount(0)
|
, mRestartCount(0)
|
||||||
, mCaps(0)
|
, mCaps(0)
|
||||||
|
, mPipelinePosition(0)
|
||||||
, mClosed(false)
|
, mClosed(false)
|
||||||
, mConnected(false)
|
, mConnected(false)
|
||||||
, mHaveStatusLine(false)
|
, mHaveStatusLine(false)
|
||||||
@ -722,6 +723,19 @@ nsHttpTransaction::PipelineDepthAvailable()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsHttpTransaction::SetPipelinePosition(PRInt32 position)
|
||||||
|
{
|
||||||
|
mPipelinePosition = position;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRInt32
|
||||||
|
nsHttpTransaction::PipelinePosition()
|
||||||
|
{
|
||||||
|
return mPipelinePosition;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// nsHttpTransaction <private>
|
// nsHttpTransaction <private>
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -199,6 +199,7 @@ private:
|
|||||||
|
|
||||||
PRUint16 mRestartCount; // the number of times this transaction has been restarted
|
PRUint16 mRestartCount; // the number of times this transaction has been restarted
|
||||||
PRUint8 mCaps;
|
PRUint8 mCaps;
|
||||||
|
PRInt32 mPipelinePosition;
|
||||||
|
|
||||||
// state flags, all logically boolean, but not packed together into a
|
// state flags, all logically boolean, but not packed together into a
|
||||||
// bitfield so as to avoid bitfield-induced races. See bug 560579.
|
// bitfield so as to avoid bitfield-induced races. See bug 560579.
|
||||||
|
@ -26,6 +26,7 @@ const CL_EXPECT_GZIP = 0x2;
|
|||||||
const CL_EXPECT_3S_DELAY = 0x4;
|
const CL_EXPECT_3S_DELAY = 0x4;
|
||||||
const CL_SUSPEND = 0x8;
|
const CL_SUSPEND = 0x8;
|
||||||
const CL_ALLOW_UNKNOWN_CL = 0x10;
|
const CL_ALLOW_UNKNOWN_CL = 0x10;
|
||||||
|
const CL_EXPECT_LATE_FAILURE = 0x20;
|
||||||
|
|
||||||
const SUSPEND_DELAY = 3000;
|
const SUSPEND_DELAY = 3000;
|
||||||
|
|
||||||
@ -38,7 +39,8 @@ const SUSPEND_DELAY = 3000;
|
|||||||
*
|
*
|
||||||
* This listener makes sure that various parts of the channel API are
|
* This listener makes sure that various parts of the channel API are
|
||||||
* implemented correctly and that the channel's status is a success code
|
* implemented correctly and that the channel's status is a success code
|
||||||
* (you can pass CL_EXPECT_FAILURE as flags to allow a failure code)
|
* (you can pass CL_EXPECT_FAILURE or CL_EXPECT_LATE_FAILURE as flags
|
||||||
|
* to allow a failure code)
|
||||||
*
|
*
|
||||||
* Note that it also requires a valid content length on the channel and
|
* Note that it also requires a valid content length on the channel and
|
||||||
* is thus not fully generic.
|
* is thus not fully generic.
|
||||||
@ -131,15 +133,15 @@ ChannelListener.prototype = {
|
|||||||
if (this._got_onstoprequest)
|
if (this._got_onstoprequest)
|
||||||
do_throw("Got second onStopRequest event!");
|
do_throw("Got second onStopRequest event!");
|
||||||
this._got_onstoprequest = true;
|
this._got_onstoprequest = true;
|
||||||
if ((this._flags & CL_EXPECT_FAILURE) && success)
|
if ((this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) && success)
|
||||||
do_throw("Should have failed to load URL (status is " + status.toString(16) + ")");
|
do_throw("Should have failed to load URL (status is " + status.toString(16) + ")");
|
||||||
else if (!(this._flags & CL_EXPECT_FAILURE) && !success)
|
else if (!(this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) && !success)
|
||||||
do_throw("Failed to load URL: " + status.toString(16));
|
do_throw("Failed to load URL: " + status.toString(16));
|
||||||
if (status != request.status)
|
if (status != request.status)
|
||||||
do_throw("request.status does not match status arg to onStopRequest!");
|
do_throw("request.status does not match status arg to onStopRequest!");
|
||||||
if (request.isPending())
|
if (request.isPending())
|
||||||
do_throw("request reports itself as pending from onStopRequest!");
|
do_throw("request reports itself as pending from onStopRequest!");
|
||||||
if (!(this._flags & CL_EXPECT_FAILURE) &&
|
if (!(this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) &&
|
||||||
!(this._flags & CL_EXPECT_GZIP) &&
|
!(this._flags & CL_EXPECT_GZIP) &&
|
||||||
this._contentLen != -1)
|
this._contentLen != -1)
|
||||||
do_check_eq(this._buffer.length, this._contentLen)
|
do_check_eq(this._buffer.length, this._contentLen)
|
||||||
|
90
netwerk/test/unit/test_assoc.js
Normal file
90
netwerk/test/unit/test_assoc.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
do_load_httpd_js();
|
||||||
|
|
||||||
|
var httpserver = new nsHttpServer();
|
||||||
|
var currentTestIndex = 0;
|
||||||
|
var tests = [
|
||||||
|
// this is valid
|
||||||
|
{url: "/assoc/assoctest?valid",
|
||||||
|
responseheader: [ "Assoc-Req: GET http://localhost:4444/assoc/assoctest?valid",
|
||||||
|
"Pragma: X-Verify-Assoc-Req" ],
|
||||||
|
flags : 0},
|
||||||
|
|
||||||
|
// this is invalid because the method is wrong
|
||||||
|
{url: "/assoc/assoctest?invalid",
|
||||||
|
responseheader: [ "Assoc-Req: POST http://localhost:4444/assoc/assoctest?invalid",
|
||||||
|
"Pragma: X-Verify-Assoc-Req" ],
|
||||||
|
flags : CL_EXPECT_LATE_FAILURE},
|
||||||
|
|
||||||
|
// this is invalid because the url is wrong
|
||||||
|
{url: "/assoc/assoctest?notvalid",
|
||||||
|
responseheader: [ "Assoc-Req: GET http://localhost:4444/wrongpath/assoc/assoctest?notvalid",
|
||||||
|
"Pragma: X-Verify-Assoc-Req" ],
|
||||||
|
flags : CL_EXPECT_LATE_FAILURE},
|
||||||
|
|
||||||
|
// this is invalid because the space between method and URL is missing
|
||||||
|
{url: "/assoc/assoctest?invalid2",
|
||||||
|
responseheader: [ "Assoc-Req: GEThttp://localhost:4444/assoc/assoctest?invalid2",
|
||||||
|
"Pragma: X-Verify-Assoc-Req" ],
|
||||||
|
flags : CL_EXPECT_LATE_FAILURE},
|
||||||
|
];
|
||||||
|
|
||||||
|
var oldPrefVal;
|
||||||
|
var domBranch;
|
||||||
|
|
||||||
|
function setupChannel(url)
|
||||||
|
{
|
||||||
|
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||||
|
getService(Ci.nsIIOService);
|
||||||
|
var chan = ios.newChannel("http://localhost:4444" + url, "", null);
|
||||||
|
return chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
function startIter()
|
||||||
|
{
|
||||||
|
var channel = setupChannel(tests[currentTestIndex].url);
|
||||||
|
channel.asyncOpen(new ChannelListener(completeIter,
|
||||||
|
channel, tests[currentTestIndex].flags), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function completeIter(request, data, ctx)
|
||||||
|
{
|
||||||
|
if (++currentTestIndex < tests.length ) {
|
||||||
|
startIter();
|
||||||
|
} else {
|
||||||
|
domBranch.setBoolPref("enforce", oldPrefVal);
|
||||||
|
httpserver.stop(do_test_finished);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_test()
|
||||||
|
{
|
||||||
|
var prefService =
|
||||||
|
Components.classes["@mozilla.org/preferences-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIPrefService);
|
||||||
|
domBranch = prefService.getBranch("network.http.assoc-req.");
|
||||||
|
oldPrefVal = domBranch.getBoolPref("enforce");
|
||||||
|
domBranch.setBoolPref("enforce", true);
|
||||||
|
|
||||||
|
httpserver.registerPathHandler("/assoc/assoctest", handler);
|
||||||
|
httpserver.start(4444);
|
||||||
|
|
||||||
|
startIter();
|
||||||
|
do_test_pending();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handler(metadata, response)
|
||||||
|
{
|
||||||
|
var body = "thequickbrownfox";
|
||||||
|
response.setHeader("Content-Type", "text/plain", false);
|
||||||
|
|
||||||
|
var header = tests[currentTestIndex].responseheader;
|
||||||
|
if (header != undefined) {
|
||||||
|
for (var i = 0; i < header.length; i++) {
|
||||||
|
var splitHdr = header[i].split(": ");
|
||||||
|
response.setHeader(splitHdr[0], splitHdr[1], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.setStatusLine(metadata.httpVersion, 200, "OK");
|
||||||
|
response.bodyOutputStream.write(body, body.length);
|
||||||
|
}
|
@ -6,6 +6,7 @@ tail =
|
|||||||
[test_NetUtil.js]
|
[test_NetUtil.js]
|
||||||
[test_URIs.js]
|
[test_URIs.js]
|
||||||
[test_aboutblank.js]
|
[test_aboutblank.js]
|
||||||
|
[test_assoc.js]
|
||||||
[test_auth_proxy.js]
|
[test_auth_proxy.js]
|
||||||
[test_authentication.js]
|
[test_authentication.js]
|
||||||
# Bug 675039: test hangs consistently on Android
|
# Bug 675039: test hangs consistently on Android
|
||||||
|
Loading…
Reference in New Issue
Block a user