зеркало из https://github.com/mozilla/pjs.git
Back out 1bbe7ea3a01e through 672cc4ee2dd9 because of mochitest-browser-chrome leaks
This commit is contained in:
Родитель
772c271b6f
Коммит
f60d72f679
|
@ -2779,10 +2779,6 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
|
|||
}
|
||||
}
|
||||
|
||||
// Blocking gets are common enough out of XHR that we should mark
|
||||
// the channel slow by default for pipeline purposes
|
||||
AddLoadFlags(mChannel, nsIRequest::INHIBIT_PIPELINE);
|
||||
|
||||
if (!IsSystemXHR()) {
|
||||
// Always create a nsCORSListenerProxy here even if it's
|
||||
// a same-origin request right now, since it could be redirected.
|
||||
|
|
|
@ -57,8 +57,6 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIRequest.h"
|
||||
|
||||
#include "nsFrameManager.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIXPConnect.h"
|
||||
|
@ -2852,13 +2850,6 @@ void nsHTMLMediaElement::SetRequestHeaders(nsIHttpChannel* aChannel)
|
|||
// Send Accept header for video and audio types only (Bug 489071)
|
||||
SetAcceptHeader(aChannel);
|
||||
|
||||
// Media elements are likely candidates for HTTP Pipeline head of line
|
||||
// blocking problems, so disable pipelines.
|
||||
nsLoadFlags loadflags;
|
||||
aChannel->GetLoadFlags(&loadflags);
|
||||
loadflags |= nsIRequest::INHIBIT_PIPELINE;
|
||||
aChannel->SetLoadFlags(loadflags);
|
||||
|
||||
// Apache doesn't send Content-Length when gzip transfer encoding is used,
|
||||
// which prevents us from estimating the video length (if explicit Content-Duration
|
||||
// and a length spec in the container are not present either) and from seeking.
|
||||
|
|
|
@ -685,15 +685,6 @@ NS_IMETHODIMP imgRequest::OnStopDecode(imgIRequest *aRequest,
|
|||
aStatusArg);
|
||||
}
|
||||
|
||||
if (NS_FAILED(aStatus)) {
|
||||
// Some kind of problem has happened with image decoding.
|
||||
// Report the URI to net:failed-to-decode-uri observers.
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os)
|
||||
os->NotifyObservers(mURI, "net:failed-to-process-uri", nsnull);
|
||||
}
|
||||
|
||||
// RasterImage and everything below it is completely correct and
|
||||
// bulletproof about its handling of decoder notifications.
|
||||
// Unfortunately, here and above we have to make some gross and
|
||||
|
|
|
@ -118,9 +118,6 @@ _CHROME_FILES = imgutils.js \
|
|||
test_undisplayed_iframe.html \
|
||||
iframe.html \
|
||||
ref-iframe.html \
|
||||
test_net_failedtoprocess.html \
|
||||
invalid.jpg \
|
||||
damon.jpg \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
notajpg
|
|
@ -1,48 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Test that a image decoding error producs a net:failed-to-process-uri
|
||||
observer event with the nsIURI of the failed image as the subject
|
||||
-->
|
||||
<head>
|
||||
<title>Test for image net:failed-to-process-uri</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
|
||||
var observer = {
|
||||
QueryInterface: function (aIID) {
|
||||
if (aIID.equals(Ci.nsISupports) ||
|
||||
aIID.equals(Ci.nsIObserver))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
ok(topic == "net:failed-to-process-uri", "wrong topic");
|
||||
subject = subject.QueryInterface(Ci.nsIURI);
|
||||
ok(subject.asciiSpec == "chrome://mochitests/content/chrome/image/test/mochitest/invalid.jpg", "wrong subject");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
|
||||
var obs = Cc["@mozilla.org/observer-service;1"].getService();
|
||||
obs = obs.QueryInterface(Ci.nsIObserverService);
|
||||
obs.addObserver(observer, "net:failed-to-process-uri", false);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
<img src="damon.jpg">
|
||||
<img src="invalid.jpg">
|
||||
</body>
|
||||
</html>
|
|
@ -806,23 +806,11 @@ pref("network.http.pipelining.ssl" , false); // disable pipelining over SSL
|
|||
pref("network.http.proxy.pipelining", false);
|
||||
|
||||
// Max number of requests in the pipeline
|
||||
pref("network.http.pipelining.maxrequests" , 32);
|
||||
|
||||
// An optimistic request is one pipelined when policy might allow a new
|
||||
// connection instead
|
||||
pref("network.http.pipelining.max-optimistic-requests" , 4);
|
||||
|
||||
pref("network.http.pipelining.aggressive", false);
|
||||
pref("network.http.pipelining.maxsize" , 300000);
|
||||
pref("network.http.pipelining.read-timeout", 10000);
|
||||
pref("network.http.pipelining.maxrequests" , 4);
|
||||
|
||||
// Prompt for 307 redirects
|
||||
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,
|
||||
// since inappropriate marking can easily overwhelm bandwidth reservations
|
||||
// for certain services (i.e. EF for VoIP, AF4x for interactive video,
|
||||
|
|
|
@ -159,13 +159,6 @@ interface nsIRequest : nsISupports
|
|||
* The following flags control the flow of data into the cache.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This flag prevents loading of the request with an HTTP pipeline.
|
||||
* Generally this is because the resource is expected to take a
|
||||
* while to load and may cause head of line blocking problems.
|
||||
*/
|
||||
const unsigned long INHIBIT_PIPELINE = 1 << 6;
|
||||
|
||||
/**
|
||||
* This flag prevents caching of any kind. It does not, however, prevent
|
||||
* cached content from being used to satisfy this request.
|
||||
|
|
|
@ -2034,30 +2034,6 @@ SpdySession::Transport()
|
|||
return mConnection->Transport();
|
||||
}
|
||||
|
||||
PRUint32
|
||||
SpdySession::CancelPipeline(nsresult reason)
|
||||
{
|
||||
// we don't pipeline inside spdy, so this isn't an issue
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsAHttpTransaction::Classifier
|
||||
SpdySession::Classification()
|
||||
{
|
||||
if (!mConnection)
|
||||
return nsAHttpTransaction::CLASS_GENERAL;
|
||||
return mConnection->Classification();
|
||||
}
|
||||
|
||||
void
|
||||
SpdySession::Classify(nsAHttpTransaction::Classifier newclass)
|
||||
{
|
||||
if (!mConnection)
|
||||
return;
|
||||
|
||||
mConnection->Classify(newclass);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// unused methods of nsAHttpTransaction
|
||||
// We can be sure of this because SpdySession is only constructed in
|
||||
|
@ -2088,7 +2064,8 @@ SpdySession::SetSSLConnectFailed()
|
|||
bool
|
||||
SpdySession::IsDone()
|
||||
{
|
||||
return !mStreamTransactionHash.Count();
|
||||
NS_ABORT_IF_FALSE(false, "SpdySession::IsDone()");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -2098,13 +2075,6 @@ SpdySession::Status()
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
PRUint8
|
||||
SpdySession::Caps()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(false, "SpdySession::Caps()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
SpdySession::Available()
|
||||
{
|
||||
|
@ -2162,42 +2132,6 @@ SpdySession::TakeSubTransactions(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SpdySession::AddTransaction(nsAHttpTransaction *)
|
||||
{
|
||||
// This API is meant for pipelining, SpdySession's should be
|
||||
// extended with AddStream()
|
||||
|
||||
NS_ABORT_IF_FALSE(false,
|
||||
"SpdySession::AddTransaction() should not be called");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
SpdySession::PipelineDepth()
|
||||
{
|
||||
return IsDone() ? 0 : 1;
|
||||
}
|
||||
|
||||
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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -2245,13 +2179,6 @@ SpdySession::PushBack(const char *buf, PRUint32 len)
|
|||
return mConnection->PushBack(buf, len);
|
||||
}
|
||||
|
||||
bool
|
||||
SpdySession::IsProxyConnectInProgress()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mConnection, "no connection");
|
||||
return mConnection->IsProxyConnectInProgress();
|
||||
}
|
||||
|
||||
bool
|
||||
SpdySession::LastTransactionExpectedNoContent()
|
||||
{
|
||||
|
|
|
@ -75,9 +75,10 @@ public:
|
|||
|
||||
bool AddStream(nsAHttpTransaction *, PRInt32);
|
||||
bool CanReuse() { return !mShouldGoAway && !mClosed; }
|
||||
void DontReuse();
|
||||
bool RoomForMoreStreams();
|
||||
|
||||
// When the connection is active this is called every 1 second
|
||||
// When the connection is active this is called every 15 seconds
|
||||
void ReadTimeoutTick(PRIntervalTime now);
|
||||
|
||||
// Idle time represents time since "goodput".. e.g. a data or header frame
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
#define nsAHttpConnection_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsAHttpTransaction.h"
|
||||
|
||||
class nsAHttpTransaction;
|
||||
class nsHttpRequestHead;
|
||||
class nsHttpResponseHead;
|
||||
class nsHttpConnectionInfo;
|
||||
|
@ -120,19 +120,13 @@ public:
|
|||
// persistent... important in determining the end of a response.
|
||||
virtual bool IsPersistent() = 0;
|
||||
|
||||
// called to determine or set if a connection has been reused.
|
||||
// called to determine if a connection has been reused.
|
||||
virtual bool IsReused() = 0;
|
||||
virtual void DontReuse() = 0;
|
||||
|
||||
|
||||
// called by a transaction when the transaction reads more from the socket
|
||||
// than it should have (eg. containing part of the next pipelined response).
|
||||
virtual nsresult PushBack(const char *data, PRUint32 length) = 0;
|
||||
|
||||
// Used to determine if the connection wants read events even though
|
||||
// it has not written out a transaction. Used when a connection has issued
|
||||
// a preamble such as a proxy ssl CONNECT sequence.
|
||||
virtual bool IsProxyConnectInProgress() = 0;
|
||||
|
||||
// Used by a transaction to manage the state of previous response bodies on
|
||||
// the same connection and work around buggy servers.
|
||||
virtual bool LastTransactionExpectedNoContent() = 0;
|
||||
|
@ -145,14 +139,6 @@ public:
|
|||
// Get the nsISocketTransport used by the connection without changing
|
||||
// references or ownership.
|
||||
virtual nsISocketTransport *Transport() = 0;
|
||||
|
||||
// Cancel and reschedule transactions deeper than the current response.
|
||||
// Returns the number of canceled transactions.
|
||||
virtual PRUint32 CancelPipeline(nsresult originalReason) = 0;
|
||||
|
||||
// Read and write class of transaction that is carried on this connection
|
||||
virtual nsAHttpTransaction::Classifier Classification() = 0;
|
||||
virtual void Classify(nsAHttpTransaction::Classifier newclass) = 0;
|
||||
};
|
||||
|
||||
#define NS_DECL_NSAHTTPCONNECTION \
|
||||
|
@ -167,15 +153,10 @@ public:
|
|||
void GetSecurityInfo(nsISupports **); \
|
||||
bool IsPersistent(); \
|
||||
bool IsReused(); \
|
||||
void DontReuse(); \
|
||||
nsresult PushBack(const char *, PRUint32); \
|
||||
bool IsProxyConnectInProgress(); \
|
||||
bool LastTransactionExpectedNoContent(); \
|
||||
void SetLastTransactionExpectedNoContent(bool); \
|
||||
void SetLastTransactionExpectedNoContent(bool); \
|
||||
nsHttpConnection *TakeHttpConnection(); \
|
||||
nsISocketTransport *Transport(); \
|
||||
PRUint32 CancelPipeline(nsresult originalReason); \
|
||||
nsAHttpTransaction::Classifier Classification(); \
|
||||
void Classify(nsAHttpTransaction::Classifier);
|
||||
nsISocketTransport *Transport();
|
||||
|
||||
#endif // nsAHttpConnection_h__
|
||||
|
|
|
@ -48,7 +48,6 @@ class nsIInterfaceRequestor;
|
|||
class nsIEventTarget;
|
||||
class nsITransport;
|
||||
class nsHttpRequestHead;
|
||||
class nsHttpPipeline;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Abstract base class for a HTTP transaction:
|
||||
|
@ -64,8 +63,6 @@ class nsAHttpTransaction : public nsISupports
|
|||
public:
|
||||
// called by the connection when it takes ownership of the transaction.
|
||||
virtual void SetConnection(nsAHttpConnection *) = 0;
|
||||
|
||||
// used to obtain the connection associated with this transaction
|
||||
virtual nsAHttpConnection *Connection() = 0;
|
||||
|
||||
// called by the connection to get security callbacks to set on the
|
||||
|
@ -80,7 +77,6 @@ public:
|
|||
// called to check the transaction status.
|
||||
virtual bool IsDone() = 0;
|
||||
virtual nsresult Status() = 0;
|
||||
virtual PRUint8 Caps() = 0;
|
||||
|
||||
// called to find out how much request data is available for writing.
|
||||
virtual PRUint32 Available() = 0;
|
||||
|
@ -118,49 +114,6 @@ public:
|
|||
//
|
||||
virtual nsresult TakeSubTransactions(
|
||||
nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions) = 0;
|
||||
|
||||
// called to add a sub-transaction in the case of pipelined transactions
|
||||
// classes that do not implement sub transactions
|
||||
// return NS_ERROR_NOT_IMPLEMENTED
|
||||
virtual nsresult AddTransaction(nsAHttpTransaction *transaction) = 0;
|
||||
|
||||
// The total length of the outstanding pipeline comprised of transacations
|
||||
// and sub-transactions.
|
||||
virtual PRUint32 PipelineDepth() = 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 (> 1).
|
||||
virtual nsresult SetPipelinePosition(PRInt32) = 0;
|
||||
virtual PRInt32 PipelinePosition() = 0;
|
||||
|
||||
// If we used rtti this would be the result of doing
|
||||
// dynamic_cast<nsHttpPipeline *>(this).. i.e. it can be nsnull for
|
||||
// non pipeline implementations of nsAHttpTransaction
|
||||
virtual nsHttpPipeline *QueryPipeline() { return nsnull; }
|
||||
|
||||
// Every transaction is classified into one of the types below. When using
|
||||
// HTTP pipelines, only transactions with the same type appear on the same
|
||||
// pipeline.
|
||||
enum Classifier {
|
||||
// Transactions that expect a short 304 (no-content) response
|
||||
CLASS_REVALIDATION,
|
||||
|
||||
// Transactions for content expected to be CSS or JS
|
||||
CLASS_SCRIPT,
|
||||
|
||||
// Transactions for content expected to be an image
|
||||
CLASS_IMAGE,
|
||||
|
||||
// Transactions that cannot involve a pipeline
|
||||
CLASS_SOLO,
|
||||
|
||||
// Transactions that do not fit any of the other categories. HTML
|
||||
// is normally GENERAL.
|
||||
CLASS_GENERAL,
|
||||
|
||||
CLASS_MAX
|
||||
};
|
||||
};
|
||||
|
||||
#define NS_DECL_NSAHTTPTRANSACTION \
|
||||
|
@ -172,7 +125,6 @@ public:
|
|||
nsresult status, PRUint64 progress); \
|
||||
bool IsDone(); \
|
||||
nsresult Status(); \
|
||||
PRUint8 Caps(); \
|
||||
PRUint32 Available(); \
|
||||
nsresult ReadSegments(nsAHttpSegmentReader *, PRUint32, PRUint32 *); \
|
||||
nsresult WriteSegments(nsAHttpSegmentWriter *, PRUint32, PRUint32 *); \
|
||||
|
@ -180,11 +132,7 @@ public:
|
|||
void SetSSLConnectFailed(); \
|
||||
nsHttpRequestHead *RequestHead(); \
|
||||
PRUint32 Http1xTransactionCount(); \
|
||||
nsresult TakeSubTransactions(nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions); \
|
||||
nsresult AddTransaction(nsAHttpTransaction *); \
|
||||
PRUint32 PipelineDepth(); \
|
||||
nsresult SetPipelinePosition(PRInt32); \
|
||||
PRInt32 PipelinePosition();
|
||||
nsresult TakeSubTransactions(nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsAHttpSegmentReader
|
||||
|
|
|
@ -187,12 +187,6 @@ nsHttp::DestroyAtomTable()
|
|||
}
|
||||
}
|
||||
|
||||
Mutex *
|
||||
nsHttp::GetLock()
|
||||
{
|
||||
return sLock;
|
||||
}
|
||||
|
||||
// this function may be called from multiple threads
|
||||
nsHttpAtom
|
||||
nsHttp::ResolveAtom(const char *str)
|
||||
|
|
|
@ -140,6 +140,9 @@ typedef PRUint8 nsHttpVersion;
|
|||
// some default values
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// hard upper limit on the number of requests that can be pipelined
|
||||
#define NS_HTTP_MAX_PIPELINED_REQUESTS 8
|
||||
|
||||
#define NS_HTTP_DEFAULT_PORT 80
|
||||
#define NS_HTTPS_DEFAULT_PORT 443
|
||||
|
||||
|
@ -166,11 +169,6 @@ struct nsHttp
|
|||
static nsresult CreateAtomTable();
|
||||
static void DestroyAtomTable();
|
||||
|
||||
// The mutex is valid any time the Atom Table is valid
|
||||
// This mutex is used in the unusual case that the network thread and
|
||||
// main thread might access the same data
|
||||
static mozilla::Mutex *GetLock();
|
||||
|
||||
// will dynamically add atoms to the table if they don't already exist
|
||||
static nsHttpAtom ResolveAtom(const char *);
|
||||
static nsHttpAtom ResolveAtom(const nsACString &s)
|
||||
|
|
|
@ -57,7 +57,6 @@ HTTP_ATOM(Accept_Ranges, "Accept-Ranges")
|
|||
HTTP_ATOM(Age, "Age")
|
||||
HTTP_ATOM(Allow, "Allow")
|
||||
HTTP_ATOM(Alternate_Protocol, "Alternate-Protocol")
|
||||
HTTP_ATOM(Assoc_Req, "Assoc-Req")
|
||||
HTTP_ATOM(Authentication, "Authentication")
|
||||
HTTP_ATOM(Authorization, "Authorization")
|
||||
HTTP_ATOM(Cache_Control, "Cache-Control")
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
|
||||
#include "nsHttpChannel.h"
|
||||
#include "nsHttpHandler.h"
|
||||
#include "nsStandardURL.h"
|
||||
#include "nsIApplicationCacheService.h"
|
||||
#include "nsIApplicationCacheContainer.h"
|
||||
#include "nsIAuthInformation.h"
|
||||
|
@ -71,7 +70,6 @@
|
|||
#include "nsDOMError.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include "sampler.h"
|
||||
#include "nsIConsoleService.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
@ -502,17 +500,16 @@ nsHttpChannel::SetupTransaction()
|
|||
if (mCaps & NS_HTTP_ALLOW_PIPELINING) {
|
||||
//
|
||||
// disable pipelining if:
|
||||
// (1) pipelining has been disabled by config
|
||||
// (2) pipelining has been disabled by connection mgr info
|
||||
// (3) request corresponds to a top-level document load (link click)
|
||||
// (4) request method is non-idempotent
|
||||
// (5) request is marked slow (e.g XHR)
|
||||
// (1) pipelining has been explicitly disabled
|
||||
// (2) request corresponds to a top-level document load (link click)
|
||||
// (3) request method is non-idempotent
|
||||
//
|
||||
if (!mAllowPipelining ||
|
||||
(mLoadFlags & (LOAD_INITIAL_DOCUMENT_URI | INHIBIT_PIPELINE)) ||
|
||||
// XXX does the toplevel document check really belong here? or, should
|
||||
// we push it out entirely to necko consumers?
|
||||
//
|
||||
if (!mAllowPipelining || (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI) ||
|
||||
!(mRequestHead.Method() == nsHttp::Get ||
|
||||
mRequestHead.Method() == nsHttp::Head ||
|
||||
mRequestHead.Method() == nsHttp::Options ||
|
||||
mRequestHead.Method() == nsHttp::Propfind ||
|
||||
mRequestHead.Method() == nsHttp::Proppatch)) {
|
||||
LOG((" pipelining disallowed\n"));
|
||||
|
@ -771,10 +768,6 @@ nsHttpChannel::CallOnStartRequest()
|
|||
rv = ApplyContentConversions();
|
||||
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 (mCacheEntry && mChannelIsForDownload) {
|
||||
mCacheEntry->Doom();
|
||||
|
@ -1719,117 +1712,6 @@ nsHttpChannel::Hash(const char *buf, nsACString &hash)
|
|||
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)
|
||||
gHttpHandler->ConnMgr()->
|
||||
PipelineFeedbackInfo(mConnectionInfo,
|
||||
nsHttpConnectionMgr::RedCorruptedContent,
|
||||
nsnull, 0);
|
||||
|
||||
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)
|
||||
gHttpHandler->ConnMgr()->
|
||||
PipelineFeedbackInfo(mConnectionInfo,
|
||||
nsHttpConnectionMgr::RedCorruptedContent,
|
||||
nsnull, 0);
|
||||
|
||||
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>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1973,33 +1855,6 @@ nsHttpChannel::ProcessNotModified()
|
|||
NS_ENSURE_TRUE(mCachedResponseHead, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
// If the 304 response contains a Last-Modified different than the
|
||||
// one in our cache that is pretty suspicious and is, in at least the
|
||||
// case of bug 716840, a sign of the server having previously corrupted
|
||||
// our cache with a bad response. Take the minor step here of just dooming
|
||||
// that cache entry so there is a fighting chance of getting things on the
|
||||
// right track as well as disabling pipelining for that host.
|
||||
|
||||
nsCAutoString lastModified;
|
||||
nsCAutoString lastModified304;
|
||||
|
||||
rv = mCachedResponseHead->GetHeader(nsHttp::Last_Modified,
|
||||
lastModified);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mResponseHead->GetHeader(nsHttp::Last_Modified,
|
||||
lastModified304);
|
||||
if (NS_SUCCEEDED(rv) && !lastModified304.Equals(lastModified)) {
|
||||
LOG(("Cache Entry and 304 Last-Modified Headers Do Not Match "
|
||||
"%s and %s\n", lastModified.get(), lastModified304.get()));
|
||||
|
||||
mCacheEntry->Doom();
|
||||
if (mConnectionInfo)
|
||||
gHttpHandler->ConnMgr()->
|
||||
PipelineFeedbackInfo(mConnectionInfo,
|
||||
nsHttpConnectionMgr::RedCorruptedContent,
|
||||
nsnull, 0);
|
||||
}
|
||||
|
||||
// merge any new headers with the cached response headers
|
||||
rv = mCachedResponseHead->UpdateHeaders(mResponseHead->Headers());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
|
|
@ -182,7 +182,6 @@ private:
|
|||
nsresult ContinueProcessFallback(nsresult);
|
||||
bool ResponseWouldVary();
|
||||
void HandleAsyncAbort();
|
||||
nsresult EnsureAssocReq();
|
||||
|
||||
nsresult ContinueOnStartRequest1(nsresult);
|
||||
nsresult ContinueOnStartRequest2(nsresult);
|
||||
|
|
|
@ -72,6 +72,8 @@ using namespace mozilla::net;
|
|||
|
||||
nsHttpConnection::nsHttpConnection()
|
||||
: mTransaction(nsnull)
|
||||
, mLastReadTime(0)
|
||||
, mIdleTimeout(0)
|
||||
, mConsiderReusedAfterInterval(0)
|
||||
, mConsiderReusedAfterEpoch(0)
|
||||
, mCurrentBytesRead(0)
|
||||
|
@ -84,10 +86,7 @@ nsHttpConnection::nsHttpConnection()
|
|||
, mCompletedProxyConnect(false)
|
||||
, mLastTransactionExpectedNoContent(false)
|
||||
, mIdleMonitoring(false)
|
||||
, mProxyConnectInProgress(false)
|
||||
, mHttp1xTransactionCount(0)
|
||||
, mRemainingConnectionUses(0xffffffff)
|
||||
, mClassification(nsAHttpTransaction::CLASS_GENERAL)
|
||||
, mNPNComplete(false)
|
||||
, mSetupNPNCalled(false)
|
||||
, mUsingSpdy(false)
|
||||
|
@ -142,25 +141,20 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info,
|
|||
nsIAsyncInputStream *instream,
|
||||
nsIAsyncOutputStream *outstream,
|
||||
nsIInterfaceRequestor *callbacks,
|
||||
nsIEventTarget *callbackTarget,
|
||||
PRIntervalTime rtt)
|
||||
nsIEventTarget *callbackTarget)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(transport && instream && outstream,
|
||||
"invalid socket information");
|
||||
LOG(("nsHttpConnection::Init [this=%p "
|
||||
"transport=%p instream=%p outstream=%p rtt=%d]\n",
|
||||
this, transport, instream, outstream,
|
||||
PR_IntervalToMilliseconds(rtt)));
|
||||
"transport=%p instream=%p outstream=%p]\n",
|
||||
this, transport, instream, outstream));
|
||||
|
||||
NS_ENSURE_ARG_POINTER(info);
|
||||
NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
|
||||
|
||||
mConnInfo = info;
|
||||
mLastReadTime = PR_IntervalNow();
|
||||
mSupportsPipelining =
|
||||
gHttpHandler->ConnMgr()->SupportsPipelining(mConnInfo);
|
||||
mRtt = rtt;
|
||||
mMaxHangTime = PR_SecondsToInterval(maxHangTime);
|
||||
mLastReadTime = PR_IntervalNow();
|
||||
|
||||
mSocketTransport = transport;
|
||||
mSocketIn = instream;
|
||||
|
@ -344,9 +338,6 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, PRUint8 caps, PRInt32 pri)
|
|||
NS_ENSURE_ARG_POINTER(trans);
|
||||
NS_ENSURE_TRUE(!mTransaction, NS_ERROR_IN_PROGRESS);
|
||||
|
||||
// reset the read timers to wash away any idle time
|
||||
mLastReadTime = PR_IntervalNow();
|
||||
|
||||
// Update security callbacks
|
||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
nsCOMPtr<nsIEventTarget> callbackTarget;
|
||||
|
@ -378,7 +369,6 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, PRUint8 caps, PRInt32 pri)
|
|||
rv = SetupProxyConnect();
|
||||
if (NS_FAILED(rv))
|
||||
goto failed_activation;
|
||||
mProxyConnectInProgress = true;
|
||||
}
|
||||
|
||||
// Clear the per activation counter
|
||||
|
@ -535,35 +525,16 @@ nsHttpConnection::DontReuse()
|
|||
mSpdySession->DontReuse();
|
||||
}
|
||||
|
||||
// Checked by the Connection Manager before scheduling a pipelined transaction
|
||||
bool
|
||||
nsHttpConnection::SupportsPipelining()
|
||||
{
|
||||
if (mTransaction &&
|
||||
mTransaction->PipelineDepth() >= mRemainingConnectionUses) {
|
||||
LOG(("nsHttpConnection::SupportsPipelining this=%p deny pipeline "
|
||||
"because current depth %d exceeds max remaining uses %d\n",
|
||||
this, mTransaction->PipelineDepth(), mRemainingConnectionUses));
|
||||
return false;
|
||||
}
|
||||
return mSupportsPipelining && IsKeepAlive();
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnection::CanReuse()
|
||||
{
|
||||
if ((mTransaction ? mTransaction->PipelineDepth() : 0) >=
|
||||
mRemainingConnectionUses) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool canReuse;
|
||||
|
||||
if (mUsingSpdy)
|
||||
canReuse = mSpdySession->CanReuse();
|
||||
else
|
||||
canReuse = IsKeepAlive();
|
||||
|
||||
|
||||
canReuse = canReuse && (IdleTime() < mIdleTimeout) && IsAlive();
|
||||
|
||||
// An idle persistent connection should not have data waiting to be read
|
||||
|
@ -648,19 +619,21 @@ nsHttpConnection::SupportsPipelining(nsHttpResponseHead *responseHead)
|
|||
if (mUsingSpdy)
|
||||
return false;
|
||||
|
||||
// XXX there should be a strict mode available that disables this
|
||||
// blacklisting.
|
||||
|
||||
// assuming connection is HTTP/1.1 with keep-alive enabled
|
||||
if (mConnInfo->UsingHttpProxy() && !mConnInfo->UsingSSL()) {
|
||||
// XXX check for bad proxy servers...
|
||||
return true;
|
||||
}
|
||||
|
||||
// XXX what about checking for a Via header? (transparent proxies)
|
||||
|
||||
// check for bad origin servers
|
||||
const char *val = responseHead->PeekHeader(nsHttp::Server);
|
||||
|
||||
// If there is no server header we will assume it should not be banned
|
||||
// as facebook and some other prominent sites do this
|
||||
if (!val)
|
||||
return true;
|
||||
return false; // no header, no love
|
||||
|
||||
// The blacklist is indexed by the first character. All of these servers are
|
||||
// known to return their identifier as the first thing in the server string,
|
||||
|
@ -687,8 +660,6 @@ nsHttpConnection::SupportsPipelining(nsHttpResponseHead *responseHead)
|
|||
for (int i = 0; bad_servers[index][i] != nsnull; i++) {
|
||||
if (!PL_strncmp (val, bad_servers[index][i], strlen (bad_servers[index][i]))) {
|
||||
LOG(("looks like this server does not support pipelining"));
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::RedBannedServer, this , 0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -744,23 +715,11 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
mKeepAlive = true;
|
||||
else
|
||||
mKeepAlive = false;
|
||||
|
||||
// We need at least version 1.1 to use pipelines
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::RedVersionTooLow, this, 0);
|
||||
}
|
||||
else {
|
||||
// HTTP/1.1 connections are by default persistent
|
||||
if (val && !PL_strcasecmp(val, "close")) {
|
||||
if (val && !PL_strcasecmp(val, "close"))
|
||||
mKeepAlive = false;
|
||||
|
||||
// persistent connections are required for pipelining to work - if
|
||||
// this close was not pre-announced then generate the negative
|
||||
// BadExplicitClose feedback
|
||||
if (mRemainingConnectionUses > 1)
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::BadExplicitClose, this, 0);
|
||||
}
|
||||
else {
|
||||
mKeepAlive = true;
|
||||
|
||||
|
@ -775,31 +734,6 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
}
|
||||
mKeepAliveMask = mKeepAlive;
|
||||
|
||||
// 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
|
||||
if (mSupportsPipelining) {
|
||||
// report the pipelining-compatible header to the connection manager
|
||||
// as positive feedback. This will undo 1 penalty point the host
|
||||
// may have accumulated in the past.
|
||||
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::NeutralExpectedOK, this, 0);
|
||||
|
||||
mSupportsPipelining =
|
||||
gHttpHandler->ConnMgr()->SupportsPipelining(mConnInfo);
|
||||
}
|
||||
|
||||
// If this connection is reserved for revalidations and we are
|
||||
// receiving a document that failed revalidation then switch the
|
||||
// classification to general to avoid pipelining more revalidations behind
|
||||
// it.
|
||||
if (mClassification == nsAHttpTransaction::CLASS_REVALIDATION &&
|
||||
responseHead->Status() != 304) {
|
||||
mClassification = nsAHttpTransaction::CLASS_GENERAL;
|
||||
}
|
||||
|
||||
// if this connection is persistent, then the server may send a "Keep-Alive"
|
||||
// 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
|
||||
|
@ -807,7 +741,6 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
// a "keep-alive" connection is by definition capable of being reused, and
|
||||
// we only care about being able to reuse it once. if a timeout is not
|
||||
// specified then we use our advertized timeout value.
|
||||
bool foundKeepAliveMax = false;
|
||||
if (mKeepAlive) {
|
||||
val = responseHead->PeekHeader(nsHttp::Keep_Alive);
|
||||
|
||||
|
@ -816,28 +749,16 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
if (cp)
|
||||
mIdleTimeout = PR_SecondsToInterval((PRUint32) atoi(cp + 8));
|
||||
else
|
||||
mIdleTimeout = gHttpHandler->SpdyTimeout();
|
||||
|
||||
cp = PL_strcasestr(val, "max=");
|
||||
if (cp) {
|
||||
int val = atoi(cp + 4);
|
||||
if (val > 0) {
|
||||
foundKeepAliveMax = true;
|
||||
mRemainingConnectionUses = static_cast<PRUint32>(val);
|
||||
}
|
||||
}
|
||||
mIdleTimeout = gHttpHandler->IdleTimeout();
|
||||
}
|
||||
else {
|
||||
mIdleTimeout = gHttpHandler->SpdyTimeout();
|
||||
}
|
||||
|
||||
LOG(("Connection can be reused [this=%p idle-timeout=%usec]\n",
|
||||
LOG(("Connection can be reused [this=%x idle-timeout=%usec]\n",
|
||||
this, PR_IntervalToSeconds(mIdleTimeout)));
|
||||
}
|
||||
|
||||
if (!foundKeepAliveMax && mRemainingConnectionUses && !mUsingSpdy)
|
||||
--mRemainingConnectionUses;
|
||||
|
||||
if (!mProxyConnectStream)
|
||||
HandleAlternateProtocol(responseHead);
|
||||
|
||||
|
@ -959,56 +880,8 @@ nsHttpConnection::ReadTimeoutTick(PRIntervalTime now)
|
|||
return;
|
||||
}
|
||||
|
||||
PRIntervalTime delta = PR_IntervalNow() - mLastReadTime;
|
||||
// Pending patches places pipeline rescheduling code will go here
|
||||
|
||||
// we replicate some of the checks both here and in OnSocketReadable() as
|
||||
// they will be discovered under different conditions. The ones here
|
||||
// will generally be discovered if we are totally hung and OSR does
|
||||
// not get called at all, however OSR discovers them with lower latency
|
||||
// if the issue is just very slow (but not stalled) reading.
|
||||
//
|
||||
// Right now we only take action if pipelining is involved, but this would
|
||||
// be the place to add general read timeout handling if it is desired.
|
||||
|
||||
const PRIntervalTime k1000ms = PR_MillisecondsToInterval(1000);
|
||||
|
||||
if (delta < k1000ms)
|
||||
return;
|
||||
|
||||
PRUint32 pipelineDepth = mTransaction->PipelineDepth();
|
||||
|
||||
// this just reschedules blocked transactions. no transaction
|
||||
// is aborted completely.
|
||||
LOG(("cancelling pipeline due to a %ums stall - depth %d\n",
|
||||
PR_IntervalToMilliseconds(delta), pipelineDepth));
|
||||
|
||||
if (pipelineDepth > 1) {
|
||||
nsHttpPipeline *pipeline = mTransaction->QueryPipeline();
|
||||
NS_ABORT_IF_FALSE(pipeline, "pipelinedepth > 1 without pipeline");
|
||||
// code this defensively for the moment and check for null in opt build
|
||||
if (pipeline)
|
||||
pipeline->CancelPipeline(NS_ERROR_NET_TIMEOUT);
|
||||
}
|
||||
|
||||
if (delta < gHttpHandler->GetPipelineTimeout())
|
||||
return;
|
||||
|
||||
if (pipelineDepth <= 1 && !mTransaction->PipelinePosition())
|
||||
return;
|
||||
|
||||
// nothing has transpired on this pipelined socket for many
|
||||
// seconds. Call that a total stall and close the transaction.
|
||||
// There is a chance the transaction will be restarted again
|
||||
// depending on its state.. that will come back araound
|
||||
// without pipelining on, so this won't loop.
|
||||
|
||||
LOG(("canceling transaction stalled for %ums on a pipeline"
|
||||
"of depth %d and scheduled originally at pos %d\n",
|
||||
PR_IntervalToMilliseconds(delta),
|
||||
pipelineDepth, mTransaction->PipelinePosition()));
|
||||
|
||||
// This will also close the connection
|
||||
CloseTransaction(mTransaction, NS_ERROR_NET_TIMEOUT);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1057,14 +930,6 @@ nsHttpConnection::ResumeRecv()
|
|||
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
// the mLastReadTime timestamp is used for finding slowish readers
|
||||
// and can be pretty sensitive. For that reason we actually reset it
|
||||
// when we ask to read (resume recv()) so that when we get called back
|
||||
// with actual read data in OnSocketReadable() we are only measuring
|
||||
// the latency between those two acts and not all the processing that
|
||||
// may get done before the ResumeRecv() call
|
||||
mLastReadTime = PR_IntervalNow();
|
||||
|
||||
if (mSocketIn)
|
||||
return mSocketIn->AsyncWait(this, 0, 0, nsnull);
|
||||
|
||||
|
@ -1187,8 +1052,7 @@ nsHttpConnection::OnReadSegment(const char *buf,
|
|||
nsresult
|
||||
nsHttpConnection::OnSocketWritable()
|
||||
{
|
||||
LOG(("nsHttpConnection::OnSocketWritable [this=%p] host=%s\n",
|
||||
this, mConnInfo->Host()));
|
||||
LOG(("nsHttpConnection::OnSocketWritable [this=%x]\n", this));
|
||||
|
||||
nsresult rv;
|
||||
PRUint32 n;
|
||||
|
@ -1230,7 +1094,6 @@ nsHttpConnection::OnSocketWritable()
|
|||
}
|
||||
|
||||
LOG((" writing transaction request stream\n"));
|
||||
mProxyConnectInProgress = false;
|
||||
rv = mTransaction->ReadSegments(this, nsIOService::gDefaultSegmentSize, &n);
|
||||
}
|
||||
|
||||
|
@ -1268,7 +1131,7 @@ nsHttpConnection::OnSocketWritable()
|
|||
nsISocketTransport::STATUS_WAITING_FOR,
|
||||
LL_ZERO);
|
||||
|
||||
rv = ResumeRecv(); // start reading
|
||||
rv = mSocketIn->AsyncWait(this, 0, 0, nsnull); // start reading
|
||||
again = false;
|
||||
}
|
||||
// write more to the socket until error or end-of-request...
|
||||
|
@ -1307,53 +1170,14 @@ nsHttpConnection::OnSocketReadable()
|
|||
LOG(("nsHttpConnection::OnSocketReadable [this=%x]\n", this));
|
||||
|
||||
PRIntervalTime now = PR_IntervalNow();
|
||||
PRIntervalTime delta = now - mLastReadTime;
|
||||
|
||||
if (mKeepAliveMask && (delta >= mMaxHangTime)) {
|
||||
if (mKeepAliveMask && ((now - mLastReadTime) >= mMaxHangTime)) {
|
||||
LOG(("max hang time exceeded!\n"));
|
||||
// give the handler a chance to create a new persistent connection to
|
||||
// this host if we've been busy for too long.
|
||||
mKeepAliveMask = false;
|
||||
gHttpHandler->ProcessPendingQ(mConnInfo);
|
||||
}
|
||||
|
||||
// Look for data being sent in bursts with large pauses. If the pauses
|
||||
// are caused by server bottlenecks such as think-time, disk i/o, or
|
||||
// cpu exhaustion (as opposed to network latency) then we generate negative
|
||||
// pipelining feedback to prevent head of line problems
|
||||
|
||||
// Reduce the estimate of the time since last read by up to 1 RTT to
|
||||
// accommodate exhausted sender TCP congestion windows or minor I/O delays.
|
||||
|
||||
if (delta > mRtt)
|
||||
delta -= mRtt;
|
||||
else
|
||||
delta = 0;
|
||||
|
||||
const PRIntervalTime k400ms = PR_MillisecondsToInterval(400);
|
||||
const PRIntervalTime k1200ms = PR_MillisecondsToInterval(1200);
|
||||
|
||||
if (delta > k1200ms) {
|
||||
LOG(("Read delta ms of %u causing slow read major "
|
||||
"event and pipeline cancellation",
|
||||
PR_IntervalToMilliseconds(delta)));
|
||||
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::BadSlowReadMajor, this, 0);
|
||||
|
||||
if (mTransaction->PipelineDepth() > 1) {
|
||||
nsHttpPipeline *pipeline = mTransaction->QueryPipeline();
|
||||
NS_ABORT_IF_FALSE(pipeline, "pipelinedepth > 1 without pipeline");
|
||||
// code this defensively for the moment and check for null
|
||||
if (pipeline)
|
||||
pipeline->CancelPipeline(NS_ERROR_NET_TIMEOUT);
|
||||
}
|
||||
}
|
||||
else if (delta > k400ms) {
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::BadSlowReadMinor, this, 0);
|
||||
}
|
||||
|
||||
mLastReadTime = now;
|
||||
|
||||
nsresult rv;
|
||||
|
@ -1375,7 +1199,7 @@ nsHttpConnection::OnSocketReadable()
|
|||
if (NS_FAILED(mSocketInCondition)) {
|
||||
// continue waiting for the socket if necessary...
|
||||
if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK)
|
||||
rv = ResumeRecv();
|
||||
rv = mSocketIn->AsyncWait(this, 0, 0, nsnull);
|
||||
else
|
||||
rv = mSocketInCondition;
|
||||
again = false;
|
||||
|
|
|
@ -41,14 +41,13 @@
|
|||
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpConnectionInfo.h"
|
||||
#include "nsAHttpConnection.h"
|
||||
#include "nsAHttpTransaction.h"
|
||||
#include "nsHttpPipeline.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "prinrval.h"
|
||||
#include "SpdySession.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsISocketTransport.h"
|
||||
|
@ -57,9 +56,6 @@
|
|||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIEventTarget.h"
|
||||
|
||||
class nsHttpRequestHead;
|
||||
class nsHttpResponseHead;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpConnection - represents a connection to a HTTP server (or proxy)
|
||||
//
|
||||
|
@ -94,7 +90,7 @@ public:
|
|||
nsresult Init(nsHttpConnectionInfo *info, PRUint16 maxHangTime,
|
||||
nsISocketTransport *, nsIAsyncInputStream *,
|
||||
nsIAsyncOutputStream *, nsIInterfaceRequestor *,
|
||||
nsIEventTarget *, PRIntervalTime);
|
||||
nsIEventTarget *);
|
||||
|
||||
// Activate causes the given transaction to be processed on this
|
||||
// connection. It fails if there is already an existing transaction unless
|
||||
|
@ -107,7 +103,7 @@ public:
|
|||
//-------------------------------------------------------------------------
|
||||
// XXX document when these are ok to call
|
||||
|
||||
bool SupportsPipelining();
|
||||
bool SupportsPipelining() { return mSupportsPipelining; }
|
||||
bool IsKeepAlive() { return mUsingSpdy ||
|
||||
(mKeepAliveMask && mKeepAlive); }
|
||||
bool CanReuse(); // can this connection be reused?
|
||||
|
@ -119,11 +115,6 @@ public:
|
|||
void DontReuse();
|
||||
void DropTransport() { DontReuse(); mSocketTransport = 0; }
|
||||
|
||||
bool IsProxyConnectInProgress()
|
||||
{
|
||||
return mProxyConnectInProgress;
|
||||
}
|
||||
|
||||
bool LastTransactionExpectedNoContent()
|
||||
{
|
||||
return mLastTransactionExpectedNoContent;
|
||||
|
@ -167,18 +158,9 @@ public:
|
|||
|
||||
bool UsingSpdy() { return mUsingSpdy; }
|
||||
|
||||
// When the connection is active this is called every 1 second
|
||||
// When the connection is active this is called every 15 seconds
|
||||
void ReadTimeoutTick(PRIntervalTime now);
|
||||
|
||||
nsAHttpTransaction::Classifier Classification() { return mClassification; }
|
||||
void Classify(nsAHttpTransaction::Classifier newclass)
|
||||
{
|
||||
mClassification = newclass;
|
||||
}
|
||||
|
||||
// When the connection is active this is called every second
|
||||
void ReadTimeoutTick();
|
||||
|
||||
private:
|
||||
// called to cause the underlying socket to start speaking SSL
|
||||
nsresult ProxyStartSSL();
|
||||
|
@ -228,7 +210,7 @@ private:
|
|||
|
||||
nsRefPtr<nsHttpConnectionInfo> mConnInfo;
|
||||
|
||||
PRIntervalTime mLastReadTime;
|
||||
PRUint32 mLastReadTime;
|
||||
PRIntervalTime mMaxHangTime; // max download time before dropping keep-alive status
|
||||
PRIntervalTime mIdleTimeout; // value of keep-alive: timeout=
|
||||
PRIntervalTime mConsiderReusedAfterInterval;
|
||||
|
@ -239,8 +221,6 @@ private:
|
|||
|
||||
nsRefPtr<nsIAsyncInputStream> mInputOverflow;
|
||||
|
||||
PRIntervalTime mRtt;
|
||||
|
||||
bool mKeepAlive;
|
||||
bool mKeepAliveMask;
|
||||
bool mSupportsPipelining;
|
||||
|
@ -248,19 +228,11 @@ private:
|
|||
bool mCompletedProxyConnect;
|
||||
bool mLastTransactionExpectedNoContent;
|
||||
bool mIdleMonitoring;
|
||||
bool mProxyConnectInProgress;
|
||||
|
||||
// The number of <= HTTP/1.1 transactions performed on this connection. This
|
||||
// excludes spdy transactions.
|
||||
PRUint32 mHttp1xTransactionCount;
|
||||
|
||||
// Keep-Alive: max="mRemainingConnectionUses" provides the number of future
|
||||
// transactions (including the current one) that the server expects to allow
|
||||
// on this persistent connection.
|
||||
PRUint32 mRemainingConnectionUses;
|
||||
|
||||
nsAHttpTransaction::Classifier mClassification;
|
||||
|
||||
// SPDY related
|
||||
bool mNPNComplete;
|
||||
bool mSetupNPNCalled;
|
||||
|
|
|
@ -125,7 +125,6 @@ public:
|
|||
void SetAnonymous(bool anon)
|
||||
{ mHashKey.SetCharAt(anon ? 'A' : '.', 2); }
|
||||
bool GetAnonymous() { return mHashKey.CharAt(2) == 'A'; }
|
||||
|
||||
bool ShouldForceConnectMethod();
|
||||
const nsCString &GetHost() { return mHost; }
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -49,13 +49,12 @@
|
|||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "nsISocketTransportService.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIX509Cert3.h"
|
||||
|
||||
#include "nsHttpPipeline.h"
|
||||
class nsHttpPipeline;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -73,8 +72,7 @@ public:
|
|||
MAX_PERSISTENT_CONNECTIONS_PER_HOST,
|
||||
MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
|
||||
MAX_REQUEST_DELAY,
|
||||
MAX_PIPELINED_REQUESTS,
|
||||
MAX_OPTIMISTIC_PIPELINED_REQUESTS
|
||||
MAX_PIPELINED_REQUESTS
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -89,8 +87,7 @@ public:
|
|||
PRUint16 maxPersistentConnectionsPerHost,
|
||||
PRUint16 maxPersistentConnectionsPerProxy,
|
||||
PRUint16 maxRequestDelay,
|
||||
PRUint16 maxPipelinedRequests,
|
||||
PRUint16 maxOptimisticPipelinedRequests);
|
||||
PRUint16 maxPipelinedRequests);
|
||||
nsresult Shutdown();
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -141,80 +138,17 @@ public:
|
|||
void ReportSpdyAlternateProtocol(nsHttpConnection *);
|
||||
void RemoveSpdyAlternateProtocol(nsACString &key);
|
||||
|
||||
// Pipielining Interfaces and Datatypes
|
||||
|
||||
const static PRUint32 kPipelineInfoTypeMask = 0xffff0000;
|
||||
const static PRUint32 kPipelineInfoIDMask = ~kPipelineInfoTypeMask;
|
||||
|
||||
const static PRUint32 kPipelineInfoTypeRed = 0x00010000;
|
||||
const static PRUint32 kPipelineInfoTypeBad = 0x00020000;
|
||||
const static PRUint32 kPipelineInfoTypeNeutral = 0x00040000;
|
||||
const static PRUint32 kPipelineInfoTypeGood = 0x00080000;
|
||||
|
||||
enum PipelineFeedbackInfoType
|
||||
{
|
||||
// Used when an HTTP response less than 1.1 is received
|
||||
RedVersionTooLow = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0001,
|
||||
|
||||
// Used when a HTTP Server response header that is on the banned from
|
||||
// pipelining list is received
|
||||
RedBannedServer = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0002,
|
||||
|
||||
// Used when a response is terminated early, when it fails an
|
||||
// integrity check such as assoc-req or when a 304 contained a Last-Modified
|
||||
// differnet than the entry being validated.
|
||||
RedCorruptedContent = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0004,
|
||||
|
||||
// Used when a pipeline is only partly satisfied - for instance if the
|
||||
// server closed the connection after responding to the first
|
||||
// request but left some requests unprocessed.
|
||||
RedCanceledPipeline = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0005,
|
||||
|
||||
// Used when a connection that we expected to stay persistently open
|
||||
// was closed by the server. Not used when simply timed out.
|
||||
BadExplicitClose = kPipelineInfoTypeBad | 0x0003,
|
||||
|
||||
// Used when there is a gap of around 400 - 1200ms in between data being
|
||||
// read from the server
|
||||
BadSlowReadMinor = kPipelineInfoTypeBad | 0x0006,
|
||||
|
||||
// Used when there is a gap of > 1200ms in between data being
|
||||
// read from the server
|
||||
BadSlowReadMajor = kPipelineInfoTypeBad | 0x0007,
|
||||
|
||||
// Used when a response is received that is not framed with either chunked
|
||||
// encoding or a complete content length.
|
||||
BadInsufficientFraming = kPipelineInfoTypeBad | 0x0008,
|
||||
|
||||
// Used when a very large response is recevied in a potential pipelining
|
||||
// context. Large responses cause head of line blocking.
|
||||
BadUnexpectedLarge = kPipelineInfoTypeBad | 0x000B,
|
||||
|
||||
// Used when a response is received that has headers that appear to support
|
||||
// pipelining.
|
||||
NeutralExpectedOK = kPipelineInfoTypeNeutral | 0x0009,
|
||||
|
||||
// Used when a response is received successfully to a pipelined request.
|
||||
GoodCompletedOK = kPipelineInfoTypeGood | 0x000A
|
||||
};
|
||||
|
||||
// called to provide information relevant to the pipelining manager
|
||||
// may be called from any thread
|
||||
void PipelineFeedbackInfo(nsHttpConnectionInfo *,
|
||||
PipelineFeedbackInfoType info,
|
||||
nsHttpConnection *,
|
||||
PRUint32);
|
||||
|
||||
void ReportFailedToProcess(nsIURI *uri);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: functions below may be called only on the socket thread.
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// removes the next transaction for the specified connection from the
|
||||
// pending transaction queue.
|
||||
void AddTransactionToPipeline(nsHttpPipeline *);
|
||||
|
||||
// called to force the transaction queue to be processed once more, giving
|
||||
// preference to the specified connection.
|
||||
nsresult ProcessPendingQ(nsHttpConnectionInfo *);
|
||||
bool ProcessPendingQForEntry(nsHttpConnectionInfo *);
|
||||
|
||||
// This is used to force an idle connection to be closed and removed from
|
||||
// the idle connection list. It is called when the idle connection detects
|
||||
|
@ -226,41 +160,26 @@ public:
|
|||
// bit different.
|
||||
void ReportSpdyConnection(nsHttpConnection *, bool usingSpdy);
|
||||
|
||||
|
||||
bool SupportsPipelining(nsHttpConnectionInfo *);
|
||||
|
||||
private:
|
||||
virtual ~nsHttpConnectionMgr();
|
||||
|
||||
enum PipeliningState {
|
||||
// Host has proven itself pipeline capable through past experience and
|
||||
// large pipeline depths are allowed on multiple connections.
|
||||
PS_GREEN,
|
||||
|
||||
// Not enough information is available yet with this host to be certain
|
||||
// of pipeline capability. Small pipelines on a single connection are
|
||||
// allowed in order to decide whether or not to proceed to green.
|
||||
PS_YELLOW,
|
||||
|
||||
// One or more bad events has happened that indicate that pipelining
|
||||
// to this host (or a particular type of transaction with this host)
|
||||
// is a bad idea. Pipelining is not currently allowed, but time and
|
||||
// other positive experiences will eventually allow it to try again.
|
||||
PS_RED
|
||||
};
|
||||
|
||||
class nsHalfOpenSocket;
|
||||
|
||||
|
||||
// nsConnectionEntry
|
||||
//
|
||||
// mCT maps connection info hash key to nsConnectionEntry object, which
|
||||
// contains list of active and idle connections as well as the list of
|
||||
// pending transactions.
|
||||
//
|
||||
class nsConnectionEntry
|
||||
struct nsConnectionEntry
|
||||
{
|
||||
public:
|
||||
nsConnectionEntry(nsHttpConnectionInfo *ci);
|
||||
nsConnectionEntry(nsHttpConnectionInfo *ci)
|
||||
: mConnInfo(ci),
|
||||
mUsingSpdy(false),
|
||||
mTestedSpdy(false),
|
||||
mSpdyPreferred(false)
|
||||
{
|
||||
NS_ADDREF(mConnInfo);
|
||||
}
|
||||
~nsConnectionEntry();
|
||||
|
||||
nsHttpConnectionInfo *mConnInfo;
|
||||
|
@ -269,54 +188,6 @@ private:
|
|||
nsTArray<nsHttpConnection*> mIdleConns; // idle persistent connections
|
||||
nsTArray<nsHalfOpenSocket*> mHalfOpens;
|
||||
|
||||
// Pipeline depths for various states
|
||||
const static PRUint32 kPipelineUnlimited = 1024; // fully open - extended green
|
||||
const static PRUint32 kPipelineOpen = 6; // 6 on each conn - normal green
|
||||
const static PRUint32 kPipelineRestricted = 2; // 2 on just 1 conn in yellow
|
||||
|
||||
nsHttpConnectionMgr::PipeliningState PipelineState();
|
||||
void OnPipelineFeedbackInfo(
|
||||
nsHttpConnectionMgr::PipelineFeedbackInfoType info,
|
||||
nsHttpConnection *, PRUint32);
|
||||
bool SupportsPipelining();
|
||||
PRUint32 MaxPipelineDepth(nsAHttpTransaction::Classifier classification);
|
||||
void CreditPenalty();
|
||||
|
||||
nsHttpConnectionMgr::PipeliningState mPipelineState;
|
||||
|
||||
void SetYellowConnection(nsHttpConnection *);
|
||||
void OnYellowComplete();
|
||||
PRUint32 mYellowGoodEvents;
|
||||
PRUint32 mYellowBadEvents;
|
||||
nsHttpConnection *mYellowConnection;
|
||||
|
||||
// initialGreenDepth is the max depth of a pipeline when you first
|
||||
// transition to green. Normally this is kPipelineOpen, but it can
|
||||
// be kPipelineUnlimited in aggressive mode.
|
||||
PRUint32 mInitialGreenDepth;
|
||||
|
||||
// greenDepth is the current max allowed depth of a pipeline when
|
||||
// in the green state. Normally this starts as kPipelineOpen and
|
||||
// grows to kPipelineUnlimited after a pipeline of depth 3 has been
|
||||
// successfully transacted.
|
||||
PRUint32 mGreenDepth;
|
||||
|
||||
// pipeliningPenalty is the current amount of penalty points this host
|
||||
// entry has earned for participating in events that are not conducive
|
||||
// to good pipelines - such as head of line blocking, canceled pipelines,
|
||||
// etc.. penalties are paid back either through elapsed time or simply
|
||||
// healthy transactions. Having penalty points means that this host is
|
||||
// not currently eligible for pipelines.
|
||||
PRInt16 mPipeliningPenalty;
|
||||
|
||||
// some penalty points only apply to particular classifications of
|
||||
// transactions - this allows a server that perhaps has head of line
|
||||
// blocking problems on CGI queries to still serve JS pipelined.
|
||||
PRInt16 mPipeliningClassPenalty[nsAHttpTransaction::CLASS_MAX];
|
||||
|
||||
// for calculating penalty repair credits
|
||||
mozilla::TimeStamp mLastCreditTime;
|
||||
|
||||
// Spdy sometimes resolves the address in the socket manager in order
|
||||
// to re-coalesce sharded HTTP hosts. The dotted decimal address is
|
||||
// combined with the Anonymous flag from the connection information
|
||||
|
@ -401,9 +272,6 @@ private:
|
|||
nsCOMPtr<nsIAsyncOutputStream> mStreamOut;
|
||||
nsCOMPtr<nsIAsyncInputStream> mStreamIn;
|
||||
|
||||
mozilla::TimeStamp mPrimarySynStarted;
|
||||
mozilla::TimeStamp mBackupSynStarted;
|
||||
|
||||
// for syn retry
|
||||
nsCOMPtr<nsITimer> mSynTimer;
|
||||
nsCOMPtr<nsISocketTransport> mBackupTransport;
|
||||
|
@ -428,7 +296,7 @@ private:
|
|||
PRUint16 mMaxPersistConnsPerProxy;
|
||||
PRUint16 mMaxRequestDelay; // in seconds
|
||||
PRUint16 mMaxPipelinedRequests;
|
||||
PRUint16 mMaxOptimisticPipelinedRequests;
|
||||
|
||||
bool mIsShuttingDown;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -442,18 +310,12 @@ private:
|
|||
static PLDHashOperator PurgeExcessIdleConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
static PLDHashOperator ClosePersistentConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
bool ProcessPendingQForEntry(nsConnectionEntry *);
|
||||
bool IsUnderPressure(nsConnectionEntry *ent,
|
||||
nsHttpTransaction::Classifier classification);
|
||||
bool AtActiveConnectionLimit(nsConnectionEntry *, PRUint8 caps);
|
||||
nsresult TryDispatchTransaction(nsConnectionEntry *ent,
|
||||
bool onlyReusedConnection,
|
||||
nsHttpTransaction *trans);
|
||||
nsresult DispatchTransaction(nsConnectionEntry *,
|
||||
nsHttpTransaction *,
|
||||
nsHttpConnection *);
|
||||
nsresult BuildPipeline(nsConnectionEntry *,
|
||||
nsAHttpTransaction *,
|
||||
nsHttpPipeline **);
|
||||
void GetConnection(nsConnectionEntry *, nsHttpTransaction *,
|
||||
bool, nsHttpConnection **);
|
||||
nsresult DispatchTransaction(nsConnectionEntry *, nsHttpTransaction *,
|
||||
PRUint8 caps, nsHttpConnection *);
|
||||
bool BuildPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **);
|
||||
nsresult ProcessNewTransaction(nsHttpTransaction *);
|
||||
nsresult EnsureSocketThreadTargetIfOnline();
|
||||
void ClosePersistentConnections(nsConnectionEntry *ent);
|
||||
|
@ -462,13 +324,6 @@ private:
|
|||
void StartedConnect();
|
||||
void RecvdConnect();
|
||||
|
||||
bool MakeNewConnection(nsConnectionEntry *ent,
|
||||
nsHttpTransaction *trans);
|
||||
bool AddToShortestPipeline(nsConnectionEntry *ent,
|
||||
nsHttpTransaction *trans,
|
||||
nsHttpTransaction::Classifier classification,
|
||||
PRUint16 depthLimit);
|
||||
|
||||
// Manage the preferred spdy connection entry for this address
|
||||
nsConnectionEntry *GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry);
|
||||
void RemoveSpdyPreferredEnt(nsACString &aDottedDecimal);
|
||||
|
@ -541,7 +396,6 @@ private:
|
|||
void OnMsgReclaimConnection (PRInt32, void *);
|
||||
void OnMsgUpdateParam (PRInt32, void *);
|
||||
void OnMsgClosePersistentConnections (PRInt32, void *);
|
||||
void OnMsgProcessFeedback (PRInt32, void *);
|
||||
|
||||
// Total number of active connections in all of the ConnectionEntry objects
|
||||
// that are accessed from mCT connection table.
|
||||
|
|
|
@ -185,16 +185,11 @@ nsHttpHandler::nsHttpHandler()
|
|||
, mMaxConnectionsPerServer(8)
|
||||
, mMaxPersistentConnectionsPerServer(2)
|
||||
, mMaxPersistentConnectionsPerProxy(4)
|
||||
, mMaxPipelinedRequests(32)
|
||||
, mMaxOptimisticPipelinedRequests(4)
|
||||
, mPipelineAggressive(false)
|
||||
, mMaxPipelineObjectSize(300000)
|
||||
, mPipelineReadTimeout(PR_MillisecondsToInterval(10000))
|
||||
, mMaxPipelinedRequests(2)
|
||||
, mRedirectionLimit(10)
|
||||
, mPhishyUserPassLength(1)
|
||||
, mQoSBits(0x00)
|
||||
, mPipeliningOverSSL(false)
|
||||
, mEnforceAssocReq(false)
|
||||
, mInPrivateBrowsingMode(PRIVATE_BROWSING_UNKNOWN)
|
||||
, mLastUniqueID(NowInSeconds())
|
||||
, mSessionStartTime(0)
|
||||
|
@ -343,7 +338,6 @@ nsHttpHandler::Init()
|
|||
mObserverService->AddObserver(this, "net:clear-active-logins", true);
|
||||
mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true);
|
||||
mObserverService->AddObserver(this, "net:prune-dead-connections", true);
|
||||
mObserverService->AddObserver(this, "net:failed-to-process-uri", true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -369,8 +363,7 @@ nsHttpHandler::InitConnectionMgr()
|
|||
mMaxPersistentConnectionsPerServer,
|
||||
mMaxPersistentConnectionsPerProxy,
|
||||
mMaxRequestDelay,
|
||||
mMaxPipelinedRequests,
|
||||
mMaxOptimisticPipelinedRequests);
|
||||
mMaxPipelinedRequests);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1022,47 +1015,13 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
|
|||
if (PREF_CHANGED(HTTP_PREF("pipelining.maxrequests"))) {
|
||||
rv = prefs->GetIntPref(HTTP_PREF("pipelining.maxrequests"), &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mMaxPipelinedRequests = clamped(val, 1, 0xffff);
|
||||
mMaxPipelinedRequests = clamped(val, 1, NS_HTTP_MAX_PIPELINED_REQUESTS);
|
||||
if (mConnMgr)
|
||||
mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PIPELINED_REQUESTS,
|
||||
mMaxPipelinedRequests);
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("pipelining.max-optimistic-requests"))) {
|
||||
rv = prefs->
|
||||
GetIntPref(HTTP_PREF("pipelining.max-optimistic-requests"), &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mMaxOptimisticPipelinedRequests = clamped(val, 1, 0xffff);
|
||||
if (mConnMgr)
|
||||
mConnMgr->UpdateParam
|
||||
(nsHttpConnectionMgr::MAX_OPTIMISTIC_PIPELINED_REQUESTS,
|
||||
mMaxOptimisticPipelinedRequests);
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("pipelining.aggressive"))) {
|
||||
rv = prefs->GetBoolPref(HTTP_PREF("pipelining.aggressive"), &cVar);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mPipelineAggressive = cVar;
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("pipelining.maxsize"))) {
|
||||
rv = prefs->GetIntPref(HTTP_PREF("pipelining.maxsize"), &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mMaxPipelineObjectSize =
|
||||
static_cast<PRInt64>(clamped(val, 1000, 100000000));
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("pipelining.read-timeout"))) {
|
||||
rv = prefs->GetIntPref(HTTP_PREF("pipelining.read-timeout"), &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mPipelineReadTimeout =
|
||||
PR_MillisecondsToInterval(clamped(val, 500, 0xffff));
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("pipelining.ssl"))) {
|
||||
rv = prefs->GetBoolPref(HTTP_PREF("pipelining.ssl"), &cVar);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
|
@ -1144,13 +1103,6 @@ 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
|
||||
if (PREF_CHANGED(BROWSER_PREF("disk_cache_ssl"))) {
|
||||
cVar = false;
|
||||
|
@ -1635,11 +1587,6 @@ nsHttpHandler::Observe(nsISupports *subject,
|
|||
mConnMgr->PruneDeadConnections();
|
||||
}
|
||||
}
|
||||
else if (strcmp(topic, "net:failed-to-process-uri") == 0) {
|
||||
nsCOMPtr<nsIURI> uri = do_QueryInterface(subject);
|
||||
if (uri && mConnMgr)
|
||||
mConnMgr->ReportFailedToProcess(uri);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -110,7 +110,6 @@ public:
|
|||
PRUint16 GetIdleSynTimeout() { return mIdleSynTimeout; }
|
||||
bool FastFallbackToIPv4() { return mFastFallbackToIPv4; }
|
||||
PRUint32 MaxSocketCount();
|
||||
bool EnforceAssocReq() { return mEnforceAssocReq; }
|
||||
|
||||
bool IsPersistentHttpsCachingEnabled() { return mEnablePersistentHttpsCaching; }
|
||||
bool IsTelemetryEnabled() { return mTelemetryEnabled; }
|
||||
|
@ -232,13 +231,6 @@ public:
|
|||
static nsresult GenerateHostPort(const nsCString& host, PRInt32 port,
|
||||
nsCString& hostLine);
|
||||
|
||||
bool GetPipelineAggressive() { return mPipelineAggressive; }
|
||||
void GetMaxPipelineObjectSize(PRInt64 &outVal)
|
||||
{
|
||||
outVal = mMaxPipelineObjectSize;
|
||||
}
|
||||
PRIntervalTime GetPipelineTimeout() { return mPipelineReadTimeout; }
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
|
@ -295,12 +287,7 @@ private:
|
|||
PRUint8 mMaxConnectionsPerServer;
|
||||
PRUint8 mMaxPersistentConnectionsPerServer;
|
||||
PRUint8 mMaxPersistentConnectionsPerProxy;
|
||||
PRUint16 mMaxPipelinedRequests;
|
||||
PRUint16 mMaxOptimisticPipelinedRequests;
|
||||
bool mPipelineAggressive;
|
||||
PRInt64 mMaxPipelineObjectSize;
|
||||
|
||||
PRIntervalTime mPipelineReadTimeout;
|
||||
PRUint8 mMaxPipelinedRequests;
|
||||
|
||||
PRUint8 mRedirectionLimit;
|
||||
|
||||
|
@ -313,7 +300,6 @@ private:
|
|||
PRUint8 mQoSBits;
|
||||
|
||||
bool mPipeliningOverSSL;
|
||||
bool mEnforceAssocReq;
|
||||
|
||||
// cached value of whether or not the browser is in private browsing mode.
|
||||
enum {
|
||||
|
|
|
@ -98,7 +98,6 @@ nsHttpPipeline::nsHttpPipeline()
|
|||
, mRequestIsPartial(false)
|
||||
, mResponseIsPartial(false)
|
||||
, mClosed(false)
|
||||
, mUtilizedPipeline(false)
|
||||
, mPushBackBuf(nsnull)
|
||||
, mPushBackLen(0)
|
||||
, mPushBackMax(0)
|
||||
|
@ -125,62 +124,19 @@ nsHttpPipeline::AddTransaction(nsAHttpTransaction *trans)
|
|||
{
|
||||
LOG(("nsHttpPipeline::AddTransaction [this=%x trans=%x]\n", this, trans));
|
||||
|
||||
if (mRequestQ.Length() || mResponseQ.Length())
|
||||
mUtilizedPipeline = true;
|
||||
|
||||
NS_ADDREF(trans);
|
||||
mRequestQ.AppendElement(trans);
|
||||
PRUint32 qlen = PipelineDepth();
|
||||
|
||||
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) {
|
||||
trans->SetConnection(this);
|
||||
|
||||
if (mRequestQ.Length() == 1)
|
||||
mConnection->ResumeSend();
|
||||
}
|
||||
|
||||
// trans->SetConnection() needs to be updated to point back at
|
||||
// the pipeline object.
|
||||
trans->SetConnection(this);
|
||||
|
||||
if (mConnection && !mClosed && mRequestQ.Length() == 1)
|
||||
mConnection->ResumeSend();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsHttpPipeline::PipelineDepth()
|
||||
{
|
||||
return mRequestQ.Length() + mResponseQ.Length();
|
||||
}
|
||||
|
||||
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 *
|
||||
nsHttpPipeline::QueryPipeline()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpPipeline::nsISupports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -208,26 +164,9 @@ nsHttpPipeline::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ASSERTION(mConnection, "no connection");
|
||||
|
||||
nsRefPtr<nsHttpConnectionInfo> ci;
|
||||
GetConnectionInfo(getter_AddRefs(ci));
|
||||
|
||||
NS_ABORT_IF_FALSE(ci, "no connection info");
|
||||
|
||||
bool pipeliningBefore = gHttpHandler->ConnMgr()->SupportsPipelining(ci);
|
||||
|
||||
// trans has now received its response headers; forward to the real connection
|
||||
nsresult rv = mConnection->OnHeadersAvailable(trans,
|
||||
requestHead,
|
||||
responseHead,
|
||||
reset);
|
||||
|
||||
if (!pipeliningBefore && gHttpHandler->ConnMgr()->SupportsPipelining(ci))
|
||||
// The received headers have expanded the eligible
|
||||
// pipeline depth for this connection
|
||||
gHttpHandler->ConnMgr()->ProcessPendingQForEntry(ci);
|
||||
|
||||
return rv;
|
||||
return mConnection->OnHeadersAvailable(trans, requestHead, responseHead, reset);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -252,7 +191,7 @@ nsHttpPipeline::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
|
|||
LOG(("nsHttpPipeline::CloseTransaction [this=%x trans=%x reason=%x]\n",
|
||||
this, trans, reason));
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ASSERTION(NS_FAILED(reason), "expecting failure code");
|
||||
|
||||
// the specified transaction is to be closed with the given "reason"
|
||||
|
@ -280,27 +219,21 @@ nsHttpPipeline::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
|
|||
killPipeline = true;
|
||||
}
|
||||
|
||||
// Marking this connection as non-reusable prevents other items from being
|
||||
// added to it and causes it to be torn down soon. Don't tear it down yet
|
||||
// as that would prevent Response(0) from being processed.
|
||||
DontReuse();
|
||||
|
||||
trans->Close(reason);
|
||||
NS_RELEASE(trans);
|
||||
|
||||
if (killPipeline)
|
||||
// reschedule anything from this pipeline onto a different connection
|
||||
CancelPipeline(reason);
|
||||
if (killPipeline) {
|
||||
if (mConnection)
|
||||
mConnection->CloseTransaction(this, reason);
|
||||
else
|
||||
Close(reason);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpPipeline::GetConnectionInfo(nsHttpConnectionInfo **result)
|
||||
{
|
||||
if (!mConnection) {
|
||||
*result = nsnull;
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mConnection, "no connection");
|
||||
mConnection->GetConnectionInfo(result);
|
||||
}
|
||||
|
||||
|
@ -328,16 +261,7 @@ nsHttpPipeline::IsPersistent()
|
|||
bool
|
||||
nsHttpPipeline::IsReused()
|
||||
{
|
||||
if (!mUtilizedPipeline && mConnection)
|
||||
return mConnection->IsReused();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpPipeline::DontReuse()
|
||||
{
|
||||
if (mConnection)
|
||||
mConnection->DontReuse();
|
||||
return true; // pipelining requires this
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -345,7 +269,7 @@ nsHttpPipeline::PushBack(const char *data, PRUint32 length)
|
|||
{
|
||||
LOG(("nsHttpPipeline::PushBack [this=%x len=%u]\n", this, length));
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ASSERTION(mPushBackLen == 0, "push back buffer already has data!");
|
||||
|
||||
// If we have no chance for a pipeline (e.g. due to an Upgrade)
|
||||
|
@ -385,13 +309,6 @@ nsHttpPipeline::PushBack(const char *data, PRUint32 length)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpPipeline::IsProxyConnectInProgress()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mConnection, "no connection");
|
||||
return mConnection->IsProxyConnectInProgress();
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpPipeline::LastTransactionExpectedNoContent()
|
||||
{
|
||||
|
@ -422,24 +339,6 @@ nsHttpPipeline::Transport()
|
|||
return mConnection->Transport();
|
||||
}
|
||||
|
||||
nsAHttpTransaction::Classifier
|
||||
nsHttpPipeline::Classification()
|
||||
{
|
||||
if (mConnection)
|
||||
return mConnection->Classification();
|
||||
|
||||
LOG(("nsHttpPipeline::Classification this=%p "
|
||||
"has null mConnection using CLASS_SOLO default", this));
|
||||
return nsAHttpTransaction::CLASS_SOLO;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpPipeline::Classify(nsAHttpTransaction::Classifier newclass)
|
||||
{
|
||||
if (mConnection)
|
||||
mConnection->Classify(newclass);
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpPipeline::SetSSLConnectFailed()
|
||||
{
|
||||
|
@ -493,7 +392,7 @@ nsHttpPipeline::TakeSubTransactions(
|
|||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpPipeline::nsAHttpTransaction
|
||||
// nsHttpPipeline::nsAHttpConnection
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
|
@ -505,6 +404,10 @@ nsHttpPipeline::SetConnection(nsAHttpConnection *conn)
|
|||
NS_ASSERTION(!mConnection, "already have a connection");
|
||||
|
||||
NS_IF_ADDREF(mConnection = conn);
|
||||
|
||||
PRInt32 i, count = mRequestQ.Length();
|
||||
for (i=0; i<count; ++i)
|
||||
Request(i)->SetConnection(this);
|
||||
}
|
||||
|
||||
nsAHttpConnection *
|
||||
|
@ -522,13 +425,8 @@ nsHttpPipeline::GetSecurityCallbacks(nsIInterfaceRequestor **result,
|
|||
{
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
// depending on timing this could be either the request or the response
|
||||
// that is needed - but they both go to the same host. A request for these
|
||||
// callbacks directly in nsHttpTransaction would not make a distinction
|
||||
// over whether the the request had been transmitted yet.
|
||||
// return security callbacks from first request
|
||||
nsAHttpTransaction *trans = Request(0);
|
||||
if (!trans)
|
||||
trans = Response(0);
|
||||
if (trans)
|
||||
trans->GetSecurityCallbacks(result, target);
|
||||
else {
|
||||
|
@ -648,16 +546,6 @@ nsHttpPipeline::Status()
|
|||
return mStatus;
|
||||
}
|
||||
|
||||
PRUint8
|
||||
nsHttpPipeline::Caps()
|
||||
{
|
||||
nsAHttpTransaction *trans = Request(0);
|
||||
if (!trans)
|
||||
trans = Response(0);
|
||||
|
||||
return trans ? trans->Caps() : 0;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsHttpPipeline::Available()
|
||||
{
|
||||
|
@ -744,17 +632,6 @@ nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer,
|
|||
nsresult rv;
|
||||
|
||||
trans = Response(0);
|
||||
// This code deals with the establishment of a CONNECT tunnel through
|
||||
// an HTTP proxy. It allows the connection to do the CONNECT/200
|
||||
// HTTP transaction to establish an SSL tunnel as a precursor to the
|
||||
// actual pipeline of regular HTTP transactions.
|
||||
if (!trans && mRequestQ.Length() &&
|
||||
mConnection->IsProxyConnectInProgress()) {
|
||||
LOG(("nsHttpPipeline::WriteSegments [this=%p] Forced Delegation\n",
|
||||
this));
|
||||
trans = Request(0);
|
||||
}
|
||||
|
||||
if (!trans) {
|
||||
if (mRequestQ.Length() > 0)
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
|
@ -777,10 +654,7 @@ nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer,
|
|||
|
||||
// ask the connection manager to add additional transactions
|
||||
// to our pipeline.
|
||||
nsRefPtr<nsHttpConnectionInfo> ci;
|
||||
GetConnectionInfo(getter_AddRefs(ci));
|
||||
if (ci)
|
||||
gHttpHandler->ConnMgr()->ProcessPendingQForEntry(ci);
|
||||
gHttpHandler->ConnMgr()->AddTransactionToPipeline(this);
|
||||
}
|
||||
else
|
||||
mResponseIsPartial = true;
|
||||
|
@ -809,52 +683,6 @@ nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer,
|
|||
return rv;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsHttpPipeline::CancelPipeline(nsresult originalReason)
|
||||
{
|
||||
PRUint32 i, reqLen, respLen, total;
|
||||
nsAHttpTransaction *trans;
|
||||
|
||||
reqLen = mRequestQ.Length();
|
||||
respLen = mResponseQ.Length();
|
||||
total = reqLen + respLen;
|
||||
|
||||
// don't count the first response, if presnet
|
||||
if (respLen)
|
||||
total--;
|
||||
|
||||
if (!total)
|
||||
return 0;
|
||||
|
||||
// any pending requests can ignore this error and be restarted
|
||||
// unless it is during a CONNECT tunnel request
|
||||
for (i = 0; i < reqLen; ++i) {
|
||||
trans = Request(i);
|
||||
if (mConnection && mConnection->IsProxyConnectInProgress())
|
||||
trans->Close(originalReason);
|
||||
else
|
||||
trans->Close(NS_ERROR_NET_RESET);
|
||||
NS_RELEASE(trans);
|
||||
}
|
||||
mRequestQ.Clear();
|
||||
|
||||
// any pending responses can be restarted except for the first one,
|
||||
// that we might want to finish on this pipeline or cancel individually
|
||||
for (i = 1; i < respLen; ++i) {
|
||||
trans = Response(i);
|
||||
trans->Close(NS_ERROR_NET_RESET);
|
||||
NS_RELEASE(trans);
|
||||
}
|
||||
|
||||
if (respLen > 1)
|
||||
mResponseQ.TruncateLength(1);
|
||||
|
||||
DontReuse();
|
||||
Classify(nsAHttpTransaction::CLASS_SOLO);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpPipeline::Close(nsresult reason)
|
||||
{
|
||||
|
@ -869,37 +697,38 @@ nsHttpPipeline::Close(nsresult reason)
|
|||
mStatus = reason;
|
||||
mClosed = true;
|
||||
|
||||
nsRefPtr<nsHttpConnectionInfo> ci;
|
||||
GetConnectionInfo(getter_AddRefs(ci));
|
||||
PRUint32 numRescheduled = CancelPipeline(reason);
|
||||
PRUint32 i, count;
|
||||
nsAHttpTransaction *trans;
|
||||
|
||||
// numRescheduled can be 0 if there is just a single response in the
|
||||
// pipeline object. That isn't really a meaningful pipeline that
|
||||
// has been forced to be rescheduled so it does not need to generate
|
||||
// negative feedback.
|
||||
if (ci && numRescheduled)
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
ci, nsHttpConnectionMgr::RedCanceledPipeline, nsnull, 0);
|
||||
|
||||
nsAHttpTransaction *trans = Response(0);
|
||||
if (!trans)
|
||||
return;
|
||||
|
||||
// The current transaction can be restarted via reset
|
||||
// if the response has not started to arrive and the reason
|
||||
// for failure is innocuous (e.g. not an SSL error)
|
||||
if (!mResponseIsPartial &&
|
||||
(reason == NS_ERROR_NET_RESET ||
|
||||
reason == NS_OK ||
|
||||
reason == NS_BASE_STREAM_CLOSED)) {
|
||||
// any pending requests can ignore this error and be restarted
|
||||
count = mRequestQ.Length();
|
||||
for (i=0; i<count; ++i) {
|
||||
trans = Request(i);
|
||||
trans->Close(NS_ERROR_NET_RESET);
|
||||
NS_RELEASE(trans);
|
||||
}
|
||||
else {
|
||||
trans->Close(reason);
|
||||
mRequestQ.Clear();
|
||||
|
||||
trans = Response(0);
|
||||
if (trans) {
|
||||
// if the current response is partially complete, then it cannot be
|
||||
// restarted and will have to fail with the status of the connection.
|
||||
if (mResponseIsPartial)
|
||||
trans->Close(reason);
|
||||
else
|
||||
trans->Close(NS_ERROR_NET_RESET);
|
||||
NS_RELEASE(trans);
|
||||
|
||||
// any remaining pending responses can be restarted
|
||||
count = mResponseQ.Length();
|
||||
for (i=1; i<count; ++i) {
|
||||
trans = Response(i);
|
||||
trans->Close(NS_ERROR_NET_RESET);
|
||||
NS_RELEASE(trans);
|
||||
}
|
||||
mResponseQ.Clear();
|
||||
}
|
||||
|
||||
NS_RELEASE(trans);
|
||||
mResponseQ.Clear();
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -935,13 +764,6 @@ nsHttpPipeline::FillSendBuf()
|
|||
while ((trans = Request(0)) != nsnull) {
|
||||
avail = trans->Available();
|
||||
if (avail) {
|
||||
// if there is already a response in the responseq then this
|
||||
// new data comprises a pipeline. Update the transaction in the
|
||||
// response queue to reflect that if necessary. We are now sending
|
||||
// out a request while we haven't received all responses.
|
||||
nsAHttpTransaction *response = Response(0);
|
||||
if (response && !response->PipelinePosition())
|
||||
response->SetPipelinePosition(1);
|
||||
rv = trans->ReadSegments(this, avail, &n);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
@ -972,10 +794,6 @@ nsHttpPipeline::FillSendBuf()
|
|||
NS_NET_STATUS_WAITING_FOR,
|
||||
mSendingToProgress);
|
||||
}
|
||||
|
||||
// It would be good to re-enable data read handlers via ResumeRecv()
|
||||
// except the read handler code can be synchronously dispatched on
|
||||
// the stack.
|
||||
}
|
||||
else
|
||||
mRequestIsPartial = true;
|
||||
|
|
|
@ -60,6 +60,8 @@ public:
|
|||
nsHttpPipeline();
|
||||
virtual ~nsHttpPipeline();
|
||||
|
||||
nsresult AddTransaction(nsAHttpTransaction *);
|
||||
|
||||
private:
|
||||
nsresult FillSendBuf();
|
||||
|
||||
|
@ -82,9 +84,6 @@ private:
|
|||
return mResponseQ[i];
|
||||
}
|
||||
|
||||
// overload of nsAHttpTransaction::QueryPipeline()
|
||||
nsHttpPipeline *QueryPipeline();
|
||||
|
||||
nsAHttpConnection *mConnection;
|
||||
nsTArray<nsAHttpTransaction*> mRequestQ; // array of transactions
|
||||
nsTArray<nsAHttpTransaction*> mResponseQ; // array of transactions
|
||||
|
@ -100,10 +99,6 @@ private:
|
|||
// indicates whether or not the pipeline has been explicitly closed.
|
||||
bool mClosed;
|
||||
|
||||
// indicates whether or not a true pipeline (more than 1 request without
|
||||
// a synchronous response) has been formed.
|
||||
bool mUtilizedPipeline;
|
||||
|
||||
// used when calling ReadSegments/WriteSegments on a transaction.
|
||||
nsAHttpSegmentReader *mReader;
|
||||
nsAHttpSegmentWriter *mWriter;
|
||||
|
|
|
@ -64,8 +64,6 @@
|
|||
|
||||
#include "mozilla/FunctionTimer.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -121,8 +119,6 @@ nsHttpTransaction::nsHttpTransaction()
|
|||
, mPriority(0)
|
||||
, mRestartCount(0)
|
||||
, mCaps(0)
|
||||
, mClassification(CLASS_GENERAL)
|
||||
, mPipelinePosition(0)
|
||||
, mClosed(false)
|
||||
, mConnected(false)
|
||||
, mHaveStatusLine(false)
|
||||
|
@ -138,14 +134,8 @@ nsHttpTransaction::nsHttpTransaction()
|
|||
, mSSLConnectFailed(false)
|
||||
, mHttpResponseMatched(false)
|
||||
, mPreserveStream(false)
|
||||
, mToReadBeforeRestart(0)
|
||||
, mReportedStart(false)
|
||||
, mReportedResponseHeader(false)
|
||||
, mForTakeResponseHead(nsnull)
|
||||
, mTakenResponseHeader(false)
|
||||
{
|
||||
LOG(("Creating nsHttpTransaction @%x\n", this));
|
||||
gHttpHandler->GetMaxPipelineObjectSize(mMaxPipelineObjectSize);
|
||||
}
|
||||
|
||||
nsHttpTransaction::~nsHttpTransaction()
|
||||
|
@ -156,44 +146,9 @@ nsHttpTransaction::~nsHttpTransaction()
|
|||
NS_IF_RELEASE(mConnInfo);
|
||||
|
||||
delete mResponseHead;
|
||||
delete mForTakeResponseHead;
|
||||
delete mChunkedDecoder;
|
||||
}
|
||||
|
||||
nsHttpTransaction::Classifier
|
||||
nsHttpTransaction::Classify()
|
||||
{
|
||||
if (!(mCaps & NS_HTTP_ALLOW_PIPELINING))
|
||||
return (mClassification = CLASS_SOLO);
|
||||
|
||||
if (mRequestHead->PeekHeader(nsHttp::If_Modified_Since) ||
|
||||
mRequestHead->PeekHeader(nsHttp::If_None_Match))
|
||||
return (mClassification = CLASS_REVALIDATION);
|
||||
|
||||
const char *accept = mRequestHead->PeekHeader(nsHttp::Accept);
|
||||
if (accept && !PL_strncmp(accept, "image/", 6))
|
||||
return (mClassification = CLASS_IMAGE);
|
||||
|
||||
if (accept && !PL_strncmp(accept, "text/css", 8))
|
||||
return (mClassification = CLASS_SCRIPT);
|
||||
|
||||
mClassification = CLASS_GENERAL;
|
||||
|
||||
PRInt32 queryPos = mRequestHead->RequestURI().FindChar('?');
|
||||
if (queryPos == kNotFound) {
|
||||
if (StringEndsWith(mRequestHead->RequestURI(),
|
||||
NS_LITERAL_CSTRING(".js")))
|
||||
mClassification = CLASS_SCRIPT;
|
||||
}
|
||||
else if (queryPos >= 3 &&
|
||||
Substring(mRequestHead->RequestURI(), queryPos - 3, 3).
|
||||
EqualsLiteral(".js")) {
|
||||
mClassification = CLASS_SCRIPT;
|
||||
}
|
||||
|
||||
return mClassification;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpTransaction::Init(PRUint8 caps,
|
||||
nsHttpConnectionInfo *cinfo,
|
||||
|
@ -345,8 +300,6 @@ nsHttpTransaction::Init(PRUint8 caps,
|
|||
nsIOService::gDefaultSegmentCount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
Classify();
|
||||
|
||||
NS_ADDREF(*responseBody = mPipeIn);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -360,30 +313,13 @@ nsHttpTransaction::Connection()
|
|||
nsHttpResponseHead *
|
||||
nsHttpTransaction::TakeResponseHead()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mTakenResponseHeader, "TakeResponseHead called 2x");
|
||||
|
||||
// Lock RestartInProgress() and TakeResponseHead() against main thread
|
||||
MutexAutoLock lock(*nsHttp::GetLock());
|
||||
|
||||
mTakenResponseHeader = true;
|
||||
|
||||
// Even in OnStartRequest() the headers won't be available if we were
|
||||
// canceled
|
||||
if (!mHaveAllHeaders) {
|
||||
NS_WARNING("response headers not available or incomplete");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// Prefer mForTakeResponseHead over mResponseHead
|
||||
nsHttpResponseHead *head;
|
||||
if (mForTakeResponseHead) {
|
||||
head = mForTakeResponseHead;
|
||||
mForTakeResponseHead = nsnull;
|
||||
}
|
||||
else {
|
||||
head = mResponseHead;
|
||||
mResponseHead = nsnull;
|
||||
}
|
||||
nsHttpResponseHead *head = mResponseHead;
|
||||
mResponseHead = nsnull;
|
||||
return head;
|
||||
}
|
||||
|
||||
|
@ -469,14 +405,13 @@ nsHttpTransaction::OnTransportStatus(nsITransport* transport,
|
|||
PR_Now(), LL_ZERO, EmptyCString());
|
||||
|
||||
// report the status and progress
|
||||
if (!mRestartInProgressVerifier.Active())
|
||||
mActivityDistributor->ObserveActivity(
|
||||
mChannel,
|
||||
NS_HTTP_ACTIVITY_TYPE_SOCKET_TRANSPORT,
|
||||
static_cast<PRUint32>(status),
|
||||
PR_Now(),
|
||||
progress,
|
||||
EmptyCString());
|
||||
mActivityDistributor->ObserveActivity(
|
||||
mChannel,
|
||||
NS_HTTP_ACTIVITY_TYPE_SOCKET_TRANSPORT,
|
||||
static_cast<PRUint32>(status),
|
||||
PR_Now(),
|
||||
progress,
|
||||
EmptyCString());
|
||||
}
|
||||
|
||||
// nsHttpChannel synthesizes progress events in OnDataAvailable
|
||||
|
@ -521,12 +456,6 @@ nsHttpTransaction::Status()
|
|||
return mStatus;
|
||||
}
|
||||
|
||||
PRUint8
|
||||
nsHttpTransaction::Caps()
|
||||
{
|
||||
return mCaps;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsHttpTransaction::Available()
|
||||
{
|
||||
|
@ -725,47 +654,16 @@ nsHttpTransaction::Close(nsresult reason)
|
|||
// mReceivedData == FALSE. (see bug 203057 for more info.)
|
||||
//
|
||||
if (reason == NS_ERROR_NET_RESET || reason == NS_OK) {
|
||||
if (!mReceivedData && (!mSentData || connReused || mPipelinePosition)) {
|
||||
if (!mReceivedData && (!mSentData || connReused)) {
|
||||
// if restarting fails, then we must proceed to close the pipe,
|
||||
// which will notify the channel that the transaction failed.
|
||||
|
||||
if (mPipelinePosition) {
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::RedCanceledPipeline,
|
||||
nsnull, 0);
|
||||
}
|
||||
if (NS_SUCCEEDED(Restart()))
|
||||
return;
|
||||
}
|
||||
else if (!mResponseIsComplete && mPipelinePosition &&
|
||||
reason == NS_ERROR_NET_RESET) {
|
||||
// due to unhandled rst on a pipeline - safe to
|
||||
// restart as only idempotent is found there
|
||||
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::RedCorruptedContent, nsnull, 0);
|
||||
if (NS_SUCCEEDED(RestartInProgress()))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool relConn = true;
|
||||
if (NS_SUCCEEDED(reason)) {
|
||||
if (!mResponseIsComplete) {
|
||||
// The response has not been delimited with a high-confidence
|
||||
// algorithm like Content-Length or Chunked Encoding. We
|
||||
// need to use a strong framing mechanism to pipeline.
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::BadInsufficientFraming,
|
||||
nsnull, mClassification);
|
||||
}
|
||||
else if (mPipelinePosition) {
|
||||
// report this success as feedback
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::GoodCompletedOK,
|
||||
nsnull, mPipelinePosition);
|
||||
}
|
||||
|
||||
// the server has not sent the final \r\n terminating the header
|
||||
// section, and there may still be a header line unparsed. let's make
|
||||
// sure we parse the remaining header line, and then hopefully, the
|
||||
|
@ -806,86 +704,10 @@ nsHttpTransaction::Close(nsresult reason)
|
|||
mPipeOut->CloseWithStatus(reason);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpTransaction::AddTransaction(nsAHttpTransaction *trans)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsHttpTransaction::PipelineDepth()
|
||||
{
|
||||
return IsDone() ? 0 : 1;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpTransaction::SetPipelinePosition(PRInt32 position)
|
||||
{
|
||||
mPipelinePosition = position;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
nsHttpTransaction::PipelinePosition()
|
||||
{
|
||||
return mPipelinePosition;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpTransaction <private>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
nsHttpTransaction::RestartInProgress()
|
||||
{
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
// Lock RestartInProgress() and TakeResponseHead() against main thread
|
||||
MutexAutoLock lock(*nsHttp::GetLock());
|
||||
|
||||
// don't try and restart 0.9
|
||||
if (mHaveAllHeaders && !mRestartInProgressVerifier.IsSetup())
|
||||
return NS_ERROR_NET_RESET;
|
||||
|
||||
LOG(("Will restart transaction %p and skip first %lld bytes, "
|
||||
"old Content-Length %lld",
|
||||
this, mContentRead, mContentLength));
|
||||
|
||||
if (mHaveAllHeaders) {
|
||||
mRestartInProgressVerifier.SetAlreadyProcessed(
|
||||
PR_MAX(mRestartInProgressVerifier.AlreadyProcessed(), mContentRead));
|
||||
mToReadBeforeRestart = mRestartInProgressVerifier.AlreadyProcessed();
|
||||
mRestartInProgressVerifier.SetActive(true);
|
||||
|
||||
if (!mTakenResponseHeader && !mForTakeResponseHead) {
|
||||
// TakeResponseHeader() has not been called yet and this
|
||||
// is the first restart. Store the resp headers exclusively
|
||||
// for TakeResponseHeader()
|
||||
mForTakeResponseHead = mResponseHead;
|
||||
mResponseHead = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
if (mResponseHead) {
|
||||
mResponseHead->Reset();
|
||||
}
|
||||
|
||||
mContentRead = 0;
|
||||
mContentLength = -1;
|
||||
delete mChunkedDecoder;
|
||||
mChunkedDecoder = nsnull;
|
||||
mHaveStatusLine = false;
|
||||
mHaveAllHeaders = false;
|
||||
mHttpResponseMatched = false;
|
||||
mResponseIsComplete = false;
|
||||
mDidContentStart = false;
|
||||
mNoContent = false;
|
||||
mSentData = false;
|
||||
mReceivedData = false;
|
||||
|
||||
return Restart();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpTransaction::Restart()
|
||||
{
|
||||
|
@ -1017,9 +839,6 @@ nsHttpTransaction::ParseLineSegment(char *segment, PRUint32 len)
|
|||
nsresult rv = ParseLine(mLineBuf.BeginWriting());
|
||||
mLineBuf.Truncate();
|
||||
if (NS_FAILED(rv)) {
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::RedCorruptedContent,
|
||||
nsnull, 0);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
@ -1068,14 +887,12 @@ nsHttpTransaction::ParseHead(char *buf,
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// report that we have a least some of the response
|
||||
if (mActivityDistributor && !mReportedStart) {
|
||||
mReportedStart = true;
|
||||
if (mActivityDistributor)
|
||||
mActivityDistributor->ObserveActivity(
|
||||
mChannel,
|
||||
NS_HTTP_ACTIVITY_TYPE_HTTP_TRANSACTION,
|
||||
NS_HTTP_ACTIVITY_SUBTYPE_RESPONSE_START,
|
||||
PR_Now(), LL_ZERO, EmptyCString());
|
||||
}
|
||||
}
|
||||
|
||||
if (!mHttpResponseMatched) {
|
||||
|
@ -1189,8 +1006,7 @@ nsHttpTransaction::HandleContentStart()
|
|||
#endif
|
||||
// notify the connection, give it a chance to cause a reset.
|
||||
bool reset = false;
|
||||
if (!mRestartInProgressVerifier.IsSetup())
|
||||
mConnection->OnHeadersAvailable(this, mRequestHead, mResponseHead, &reset);
|
||||
mConnection->OnHeadersAvailable(this, mRequestHead, mResponseHead, &reset);
|
||||
|
||||
// looks like we should ignore this response, resetting...
|
||||
if (reset) {
|
||||
|
@ -1217,10 +1033,6 @@ nsHttpTransaction::HandleContentStart()
|
|||
break;
|
||||
}
|
||||
mConnection->SetLastTransactionExpectedNoContent(mNoContent);
|
||||
if (mInvalidResponseBytesRead)
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo, nsHttpConnectionMgr::BadInsufficientFraming,
|
||||
nsnull, mClassification);
|
||||
|
||||
if (mNoContent)
|
||||
mContentLength = 0;
|
||||
|
@ -1228,10 +1040,6 @@ nsHttpTransaction::HandleContentStart()
|
|||
// grab the content-length from the response headers
|
||||
mContentLength = mResponseHead->ContentLength();
|
||||
|
||||
if ((mClassification != CLASS_SOLO) &&
|
||||
(mContentLength > mMaxPipelineObjectSize))
|
||||
CancelPipeline(nsHttpConnectionMgr::BadUnexpectedLarge);
|
||||
|
||||
// handle chunked encoding here, so we'll know immediately when
|
||||
// we're done with the socket. please note that _all_ other
|
||||
// decoding is done when the channel receives the content data
|
||||
|
@ -1252,15 +1060,9 @@ nsHttpTransaction::HandleContentStart()
|
|||
LOG(("waiting for the server to close the connection.\n"));
|
||||
#endif
|
||||
}
|
||||
if (mRestartInProgressVerifier.Active() &&
|
||||
!mRestartInProgressVerifier.Verify(mContentLength, mResponseHead)) {
|
||||
LOG(("Restart in progress subsequent transaction failed to match"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
mDidContentStart = true;
|
||||
mRestartInProgressVerifier.Set(mContentLength, mResponseHead);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1319,19 +1121,6 @@ nsHttpTransaction::HandleContent(char *buf,
|
|||
// (no explicit content-length given)
|
||||
*contentRead = count;
|
||||
}
|
||||
|
||||
if (mRestartInProgressVerifier.Active() &&
|
||||
mToReadBeforeRestart && *contentRead) {
|
||||
PRUint32 ignore = PR_MIN(*contentRead, PRUint32(mToReadBeforeRestart));
|
||||
LOG(("Due To Restart ignoring %d of remaining %ld",
|
||||
ignore, mToReadBeforeRestart));
|
||||
*contentRead -= ignore;
|
||||
mContentRead += ignore;
|
||||
mToReadBeforeRestart -= ignore;
|
||||
memmove(buf, buf + ignore, *contentRead + *contentRemaining);
|
||||
if (!mToReadBeforeRestart)
|
||||
mRestartInProgressVerifier.SetActive(false);
|
||||
}
|
||||
|
||||
if (*contentRead) {
|
||||
// update count of content bytes read and report progress...
|
||||
|
@ -1345,13 +1134,6 @@ nsHttpTransaction::HandleContent(char *buf,
|
|||
LOG(("nsHttpTransaction::HandleContent [this=%x count=%u read=%u mContentRead=%lld mContentLength=%lld]\n",
|
||||
this, count, *contentRead, mContentRead, mContentLength));
|
||||
|
||||
// Check the size of chunked responses. If we exceed the max pipeline size
|
||||
// for this response reschedule the pipeline
|
||||
if ((mClassification != CLASS_SOLO) &&
|
||||
mChunkedDecoder &&
|
||||
(mContentRead > mMaxPipelineObjectSize))
|
||||
CancelPipeline(nsHttpConnectionMgr::BadUnexpectedLarge);
|
||||
|
||||
// check for end-of-file
|
||||
if ((mContentRead == mContentLength) ||
|
||||
(mChunkedDecoder && mChunkedDecoder->ReachedEOF())) {
|
||||
|
@ -1407,9 +1189,7 @@ nsHttpTransaction::ProcessData(char *buf, PRUint32 count, PRUint32 *countRead)
|
|||
memmove(buf, buf + bytesConsumed, count);
|
||||
|
||||
// report the completed response header
|
||||
if (mActivityDistributor && mResponseHead && mHaveAllHeaders &&
|
||||
!mReportedResponseHeader) {
|
||||
mReportedResponseHeader = true;
|
||||
if (mActivityDistributor && mResponseHead && mHaveAllHeaders) {
|
||||
nsCAutoString completeResponseHeaders;
|
||||
mResponseHead->Flatten(completeResponseHeaders, false);
|
||||
completeResponseHeaders.AppendLiteral("\r\n");
|
||||
|
@ -1453,23 +1233,6 @@ nsHttpTransaction::ProcessData(char *buf, PRUint32 count, PRUint32 *countRead)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpTransaction::CancelPipeline(PRUint32 reason)
|
||||
{
|
||||
// reason is casted through a uint to avoid compiler header deps
|
||||
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
|
||||
mConnInfo,
|
||||
static_cast<nsHttpConnectionMgr::PipelineFeedbackInfoType>(reason),
|
||||
nsnull, mClassification);
|
||||
|
||||
mConnection->CancelPipeline(NS_ERROR_CORRUPTED_CONTENT);
|
||||
|
||||
// Avoid pipelining this transaction on restart by classifying it as solo.
|
||||
// This also prevents BadUnexpectedLarge from being reported more
|
||||
// than one time per transaction.
|
||||
mClassification = CLASS_SOLO;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpTransaction deletion event
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1565,76 +1328,3 @@ nsHttpTransaction::OnOutputStreamReady(nsIAsyncOutputStream *out)
|
|||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsHttpTransaction::RestartVerifier
|
||||
|
||||
static bool
|
||||
matchOld(nsHttpResponseHead *newHead, nsCString &old,
|
||||
nsHttpAtom headerAtom)
|
||||
{
|
||||
const char *val;
|
||||
|
||||
val = newHead->PeekHeader(headerAtom);
|
||||
if (val && old.IsEmpty())
|
||||
return false;
|
||||
if (!val && !old.IsEmpty())
|
||||
return false;
|
||||
if (val && !old.Equals(val))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpTransaction::RestartVerifier::Verify(PRInt64 contentLength,
|
||||
nsHttpResponseHead *newHead)
|
||||
{
|
||||
if (mContentLength != contentLength)
|
||||
return false;
|
||||
|
||||
if (!matchOld(newHead, mContentRange, nsHttp::Content_Range))
|
||||
return false;
|
||||
|
||||
if (!matchOld(newHead, mLastModified, nsHttp::Last_Modified))
|
||||
return false;
|
||||
|
||||
if (!matchOld(newHead, mETag, nsHttp::ETag))
|
||||
return false;
|
||||
|
||||
if (!matchOld(newHead, mContentEncoding, nsHttp::Content_Encoding))
|
||||
return false;
|
||||
|
||||
if (!matchOld(newHead, mTransferEncoding, nsHttp::Transfer_Encoding))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpTransaction::RestartVerifier::Set(PRInt64 contentLength,
|
||||
nsHttpResponseHead *head)
|
||||
{
|
||||
if (mSetup)
|
||||
return;
|
||||
|
||||
mContentLength = contentLength;
|
||||
|
||||
if (head) {
|
||||
const char *val;
|
||||
val = head->PeekHeader(nsHttp::ETag);
|
||||
if (val)
|
||||
mETag.Assign(val);
|
||||
val = head->PeekHeader(nsHttp::Last_Modified);
|
||||
if (val)
|
||||
mLastModified.Assign(val);
|
||||
val = head->PeekHeader(nsHttp::Content_Range);
|
||||
if (val)
|
||||
mContentRange.Assign(val);
|
||||
val = head->PeekHeader(nsHttp::Content_Encoding);
|
||||
if (val)
|
||||
mContentEncoding.Assign(val);
|
||||
val = head->PeekHeader(nsHttp::Transfer_Encoding);
|
||||
if (val)
|
||||
mTransferEncoding.Assign(val);
|
||||
mSetup = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ public:
|
|||
nsIAsyncInputStream **responseBody);
|
||||
|
||||
// attributes
|
||||
PRUint8 Caps() { return mCaps; }
|
||||
nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; }
|
||||
nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nsnull; }
|
||||
nsISupports *SecurityInfo() { return mSecurityInfo; }
|
||||
|
@ -134,11 +135,9 @@ public:
|
|||
PRInt32 Priority() { return mPriority; }
|
||||
|
||||
const TimingStruct& Timings() const { return mTimings; }
|
||||
enum Classifier Classification() { return mClassification; }
|
||||
|
||||
private:
|
||||
nsresult Restart();
|
||||
nsresult RestartInProgress();
|
||||
char *LocateHttpStart(char *buf, PRUint32 len,
|
||||
bool aAllowPartialMatch);
|
||||
nsresult ParseLine(char *line);
|
||||
|
@ -149,9 +148,6 @@ private:
|
|||
nsresult ProcessData(char *, PRUint32, PRUint32 *);
|
||||
void DeleteSelfOnConsumerThread();
|
||||
|
||||
Classifier Classify();
|
||||
void CancelPipeline(PRUint32 reason);
|
||||
|
||||
static NS_METHOD ReadRequestSegment(nsIInputStream *, void *, const char *,
|
||||
PRUint32, PRUint32, PRUint32 *);
|
||||
static NS_METHOD WritePipeSegment(nsIOutputStream *, void *, char *,
|
||||
|
@ -204,9 +200,6 @@ private:
|
|||
|
||||
PRUint16 mRestartCount; // the number of times this transaction has been restarted
|
||||
PRUint8 mCaps;
|
||||
enum Classifier mClassification;
|
||||
PRInt32 mPipelinePosition;
|
||||
PRInt64 mMaxPipelineObjectSize;
|
||||
|
||||
// state flags, all logically boolean, but not packed together into a
|
||||
// bitfield so as to avoid bitfield-induced races. See bug 560579.
|
||||
|
@ -229,66 +222,6 @@ private:
|
|||
// mClosed := transaction has been explicitly closed
|
||||
// mTransactionDone := transaction ran to completion or was interrupted
|
||||
// mResponseComplete := transaction ran to completion
|
||||
|
||||
// For Restart-In-Progress Functionality
|
||||
PRInt64 mToReadBeforeRestart;
|
||||
bool mReportedStart;
|
||||
bool mReportedResponseHeader;
|
||||
|
||||
// protected by nsHttp::GetLock()
|
||||
nsHttpResponseHead *mForTakeResponseHead;
|
||||
bool mTakenResponseHeader;
|
||||
|
||||
class RestartVerifier
|
||||
{
|
||||
|
||||
// When a idemptotent transaction has received part of its response body
|
||||
// and incurs an error it can be restarted. To do this we mark the place
|
||||
// where we stopped feeding the body to the consumer and start the
|
||||
// network call over again. If everything we track (headers, length, etc..)
|
||||
// matches up to the place where we left off then the consumer starts being
|
||||
// fed data again with the new information. This can be done N times up
|
||||
// to the normal restart (i.e. with no response info) limit.
|
||||
|
||||
public:
|
||||
RestartVerifier()
|
||||
: mContentLength(-1)
|
||||
, mAlreadyProcessed(0)
|
||||
, mActive(false)
|
||||
, mSetup(false)
|
||||
{}
|
||||
~RestartVerifier() {}
|
||||
|
||||
void Set(PRInt64 contentLength, nsHttpResponseHead *head);
|
||||
bool Verify(PRInt64 contentLength, nsHttpResponseHead *head);
|
||||
bool Active() { return mActive; }
|
||||
void SetActive(bool val) { mActive = val; }
|
||||
bool IsSetup() { return mSetup; }
|
||||
PRInt64 AlreadyProcessed() { return mAlreadyProcessed; }
|
||||
void SetAlreadyProcessed(PRInt64 val) { mAlreadyProcessed = val; }
|
||||
|
||||
private:
|
||||
// This is the data from the first complete response header
|
||||
// used to make sure that all subsequent response headers match
|
||||
|
||||
PRInt64 mContentLength;
|
||||
nsCString mETag;
|
||||
nsCString mLastModified;
|
||||
nsCString mContentRange;
|
||||
nsCString mContentEncoding;
|
||||
nsCString mTransferEncoding;
|
||||
|
||||
// This is the amount of data that has been passed to the channel
|
||||
// from previous iterations of the transaction and must therefore
|
||||
// be skipped in the new one.
|
||||
PRInt64 mAlreadyProcessed;
|
||||
|
||||
// true when iteration > 0 has started
|
||||
bool mActive;
|
||||
|
||||
// true when ::Set has been called with a response header
|
||||
bool mSetup;
|
||||
} mRestartInProgressVerifier;
|
||||
};
|
||||
|
||||
#endif // nsHttpTransaction_h__
|
||||
|
|
|
@ -26,7 +26,6 @@ const CL_EXPECT_GZIP = 0x2;
|
|||
const CL_EXPECT_3S_DELAY = 0x4;
|
||||
const CL_SUSPEND = 0x8;
|
||||
const CL_ALLOW_UNKNOWN_CL = 0x10;
|
||||
const CL_EXPECT_LATE_FAILURE = 0x20;
|
||||
|
||||
const SUSPEND_DELAY = 3000;
|
||||
|
||||
|
@ -39,8 +38,7 @@ const SUSPEND_DELAY = 3000;
|
|||
*
|
||||
* This listener makes sure that various parts of the channel API are
|
||||
* implemented correctly and that the channel's status is a success code
|
||||
* (you can pass CL_EXPECT_FAILURE or CL_EXPECT_LATE_FAILURE as flags
|
||||
* to allow a failure code)
|
||||
* (you can pass CL_EXPECT_FAILURE as flags to allow a failure code)
|
||||
*
|
||||
* Note that it also requires a valid content length on the channel and
|
||||
* is thus not fully generic.
|
||||
|
@ -133,15 +131,15 @@ ChannelListener.prototype = {
|
|||
if (this._got_onstoprequest)
|
||||
do_throw("Got second onStopRequest event!");
|
||||
this._got_onstoprequest = true;
|
||||
if ((this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) && success)
|
||||
if ((this._flags & CL_EXPECT_FAILURE) && success)
|
||||
do_throw("Should have failed to load URL (status is " + status.toString(16) + ")");
|
||||
else if (!(this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) && !success)
|
||||
else if (!(this._flags & CL_EXPECT_FAILURE) && !success)
|
||||
do_throw("Failed to load URL: " + status.toString(16));
|
||||
if (status != request.status)
|
||||
do_throw("request.status does not match status arg to onStopRequest!");
|
||||
if (request.isPending())
|
||||
do_throw("request reports itself as pending from onStopRequest!");
|
||||
if (!(this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) &&
|
||||
if (!(this._flags & CL_EXPECT_FAILURE) &&
|
||||
!(this._flags & CL_EXPECT_GZIP) &&
|
||||
this._contentLen != -1)
|
||||
do_check_eq(this._buffer.length, this._contentLen)
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
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);
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
do_load_httpd_js();
|
||||
var httpserver = new nsHttpServer();
|
||||
var cacheService;
|
||||
var ios;
|
||||
|
||||
// Test the handling of a cache revalidation with mismatching last-modified
|
||||
// headers. If we get such a revalidation the cache entry should be purged.
|
||||
// see bug 717350
|
||||
|
||||
// In this test the wrong data is from 11-16-1994 with a value of 'A',
|
||||
// and the right data is from 11-15-1994 with a value of 'B'.
|
||||
|
||||
// the same URL is requested 3 times. the first time the wrong data comes
|
||||
// back, the second time that wrong data is revalidated with a 304 but
|
||||
// a L-M header of the right data (this triggers a cache purge), and
|
||||
// the third time the right data is returned.
|
||||
|
||||
var listener_3 = {
|
||||
// this listener is used to process the the request made after
|
||||
// the cache invalidation. it expects to see the 'right data'
|
||||
|
||||
onStartRequest: function test_onStartR(request, ctx) {},
|
||||
|
||||
onDataAvailable: function test_ODA(request, cx, inputStream,
|
||||
offset, count) {
|
||||
var data = new BinaryInputStream(inputStream).readByteArray(count);
|
||||
|
||||
// This is 'B'
|
||||
do_check_eq(data, 66);
|
||||
},
|
||||
|
||||
onStopRequest: function test_onStopR(request, ctx, status) {
|
||||
httpserver.stop(do_test_finished);
|
||||
}
|
||||
};
|
||||
|
||||
var listener_2 = {
|
||||
// this listener is used to process the revalidation of the
|
||||
// corrupted cache entry. its revalidation prompts it to be cleaned
|
||||
|
||||
onStartRequest: function test_onStartR(request, ctx) {},
|
||||
|
||||
onDataAvailable: function test_ODA(request, cx, inputStream,
|
||||
offset, count) {
|
||||
var data = new BinaryInputStream(inputStream).readByteArray(count);
|
||||
|
||||
// This is 'A' from a cache revalidation, but that reval will clean the cache
|
||||
// because of mismatched last-modified response headers
|
||||
|
||||
do_check_eq(data, 65);
|
||||
},
|
||||
|
||||
onStopRequest: function test_onStopR(request, ctx, status) {
|
||||
var channel = request.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
||||
var chan = ios.newChannel("http://localhost:4444/test1", "", null);
|
||||
var httpChan = chan.QueryInterface(Ci.nsIHttpChannel);
|
||||
httpChan.requestMethod = "GET";
|
||||
httpChan.asyncOpen(listener_3, null);
|
||||
}
|
||||
};
|
||||
|
||||
var listener_1 = {
|
||||
// this listener processes the initial request from a empty cache.
|
||||
// the server responds with the wrong data ('A')
|
||||
|
||||
onStartRequest: function test_onStartR(request, ctx) {},
|
||||
|
||||
onDataAvailable: function test_ODA(request, cx, inputStream,
|
||||
offset, count) {
|
||||
var data = new BinaryInputStream(inputStream).readByteArray(count);
|
||||
do_check_eq(data, 65);
|
||||
},
|
||||
|
||||
onStopRequest: function test_onStopR(request, ctx, status) {
|
||||
var channel = request.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
||||
var chan = ios.newChannel("http://localhost:4444/test1", "", null);
|
||||
var httpChan = chan.QueryInterface(Ci.nsIHttpChannel);
|
||||
httpChan.requestMethod = "GET";
|
||||
httpChan.asyncOpen(listener_2, null);
|
||||
}
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
cacheService = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
ios = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
cacheService.evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
|
||||
httpserver.registerPathHandler("/test1", handler);
|
||||
httpserver.start(4444);
|
||||
|
||||
var chan = ios.newChannel("http://localhost:4444/test1", "", null);
|
||||
var httpChan = chan.QueryInterface(Ci.nsIHttpChannel);
|
||||
httpChan.requestMethod = "GET";
|
||||
httpChan.asyncOpen(listener_1, null);
|
||||
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
var iter=0;
|
||||
function handler(metadata, response) {
|
||||
iter++;
|
||||
if (metadata.hasHeader("If-Modified-Since")) {
|
||||
response.setStatusLine(metadata.httpVersion, 304, "Not Modified");
|
||||
response.setHeader("Last-Modified", "Tue, 15 Nov 1994 12:45:26 GMT", false);
|
||||
}
|
||||
else {
|
||||
response.setStatusLine(metadata.httpVersion, 200, "OK");
|
||||
response.setHeader("Cache-Control", "max-age=0", false)
|
||||
if (iter == 1) {
|
||||
// simulated wrong response
|
||||
response.setHeader("Last-Modified", "Wed, 16 Nov 1994 00:00:00 GMT", false);
|
||||
response.bodyOutputStream.write("A", 1);
|
||||
}
|
||||
if (iter == 3) {
|
||||
// 'correct' response
|
||||
response.setHeader("Last-Modified", "Tue, 15 Nov 1994 12:45:26 GMT", false);
|
||||
response.bodyOutputStream.write("B", 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@ tail =
|
|||
[test_NetUtil.js]
|
||||
[test_URIs.js]
|
||||
[test_aboutblank.js]
|
||||
[test_assoc.js]
|
||||
[test_auth_proxy.js]
|
||||
[test_authentication.js]
|
||||
# Bug 675039: test hangs consistently on Android
|
||||
|
@ -132,7 +131,6 @@ skip-if = os == "android"
|
|||
[test_httpsuspend.js]
|
||||
[test_idnservice.js]
|
||||
[test_localstreams.js]
|
||||
[test_mismatch_lm.js]
|
||||
[test_MIME_params.js]
|
||||
[test_multipart_streamconv.js]
|
||||
[test_multipart_streamconv_missing_lead_boundary.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче