зеркало из https://github.com/mozilla/pjs.git
initial framework patch for http/1.1 pipelining (bug 93054) r=gagan, sr=rpotts
This commit is contained in:
Родитель
070dba8b90
Коммит
5ac2b46834
|
@ -0,0 +1,48 @@
|
|||
#ifndef nsAHttpConnection_h__
|
||||
#define nsAHttpConnection_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsAHttpTransaction;
|
||||
class nsHttpResponseHead;
|
||||
class nsHttpConnectionInfo;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Abstract base class for a HTTP connection
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class nsAHttpConnection : public nsISupports
|
||||
{
|
||||
public:
|
||||
// called by a transaction when the response headers have all been read.
|
||||
// the connection can force the transaction to reset it's response headers,
|
||||
// and prepare for a new set of response headers, by setting |*reset=TRUE|.
|
||||
virtual nsresult OnHeadersAvailable(nsAHttpTransaction *,
|
||||
nsHttpResponseHead *,
|
||||
PRBool *reset) = 0;
|
||||
|
||||
// called by a transaction when it completes normally.
|
||||
virtual nsresult OnTransactionComplete(nsAHttpTransaction *,
|
||||
nsresult status) = 0;
|
||||
|
||||
// called by a transaction to suspend/resume the connection.
|
||||
virtual nsresult OnSuspend() = 0;
|
||||
virtual nsresult OnResume() = 0;
|
||||
|
||||
// get a reference to the connection's connection-info object.
|
||||
virtual void GetConnectionInfo(nsHttpConnectionInfo **) = 0;
|
||||
|
||||
// called by a transaction to remove itself from the connection (eg. when
|
||||
// it reads premature EOF and must restart itself).
|
||||
virtual void DropTransaction(nsAHttpTransaction *) = 0;
|
||||
|
||||
// called by a transaction to determine whether or not the connection is
|
||||
// persistent... important in determining the end of a response.
|
||||
virtual PRBool IsPersistent() = 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(char *data, PRUint32 length) = 0;
|
||||
};
|
||||
|
||||
#endif // nsAHttpConnection_h__
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef nsAHttpTransaction_h__
|
||||
#define nsAHttpTransaction_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsAHttpConnection;
|
||||
class nsIInputStream;
|
||||
class nsIOutputStream;
|
||||
class nsIInterfaceRequestor;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Abstract base class for a HTTP transaction
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class nsAHttpTransaction : public nsISupports
|
||||
{
|
||||
public:
|
||||
// called by the connection when it takes ownership of the transaction.
|
||||
virtual void SetConnection(nsAHttpConnection *) = 0;
|
||||
|
||||
// called by the connection to pass socket security-info to the transaction.
|
||||
virtual void SetSecurityInfo(nsISupports *) = 0;
|
||||
|
||||
// called by the connection to get notification callbacks to set on the
|
||||
// socket transport.
|
||||
virtual void GetNotificationCallbacks(nsIInterfaceRequestor **) = 0;
|
||||
|
||||
// called by the connection to indicate that the socket can be written to.
|
||||
// the transaction returns NS_BASE_STREAM_CLOSED when it is finished
|
||||
// writing its request(s).
|
||||
virtual nsresult OnDataWritable(nsIOutputStream *) = 0;
|
||||
|
||||
// called by the connection to indicate that the socket can be read from.
|
||||
// the transaction can return NS_BASE_STREAM_WOULD_BLOCK to suspend the
|
||||
// socket read request.
|
||||
virtual nsresult OnDataReadable(nsIInputStream *) = 0;
|
||||
|
||||
// called by the connection when the transaction should stop, either due
|
||||
// to normal completion, cancelation, or some socket transport error.
|
||||
virtual nsresult OnStopTransaction(nsresult status) = 0;
|
||||
|
||||
// called by the connection to report socket status.
|
||||
virtual void OnStatus(nsresult status, const PRUnichar *statusText) = 0;
|
||||
|
||||
// called by the connection to check the transaction status.
|
||||
virtual PRBool IsDone() = 0;
|
||||
virtual nsresult Status() = 0;
|
||||
};
|
||||
|
||||
#endif // nsAHttpTransaction_h__
|
|
@ -99,7 +99,8 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info, PRUint16 maxHangTime)
|
|||
|
||||
// called from any thread, with the connection lock held
|
||||
nsresult
|
||||
nsHttpConnection::SetTransaction(nsHttpTransaction *transaction)
|
||||
nsHttpConnection::SetTransaction(nsAHttpTransaction *transaction,
|
||||
PRUint8 caps)
|
||||
{
|
||||
LOG(("nsHttpConnection::SetTransaction [this=%x trans=%x]\n",
|
||||
this, transaction));
|
||||
|
@ -112,160 +113,11 @@ nsHttpConnection::SetTransaction(nsHttpTransaction *transaction)
|
|||
NS_ADDREF(mTransaction);
|
||||
|
||||
// default mKeepAlive according to what will be requested
|
||||
mKeepAliveMask = mKeepAlive =
|
||||
mTransaction->Capabilities() & NS_HTTP_ALLOW_KEEPALIVE;
|
||||
mKeepAliveMask = mKeepAlive = (caps & NS_HTTP_ALLOW_KEEPALIVE);
|
||||
|
||||
return ActivateConnection();
|
||||
}
|
||||
|
||||
// called from the socket thread
|
||||
nsresult
|
||||
nsHttpConnection::OnHeadersAvailable(nsHttpTransaction *trans, PRBool *reset)
|
||||
{
|
||||
LOG(("nsHttpConnection::OnHeadersAvailable [this=%x trans=%x]\n",
|
||||
this, trans));
|
||||
|
||||
NS_ENSURE_ARG_POINTER(trans);
|
||||
|
||||
// we won't change our keep-alive policy unless the server has explicitly
|
||||
// told us to do so.
|
||||
|
||||
if (!trans || !trans->ResponseHead()) {
|
||||
LOG(("trans->ResponseHead() = %x\n", trans));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// inspect the connection headers for keep-alive info provided the
|
||||
// transaction completed successfully.
|
||||
const char *val = trans->ResponseHead()->PeekHeader(nsHttp::Connection);
|
||||
if (!val)
|
||||
val = trans->ResponseHead()->PeekHeader(nsHttp::Proxy_Connection);
|
||||
|
||||
if ((trans->ResponseHead()->Version() < NS_HTTP_VERSION_1_1) ||
|
||||
(nsHttpHandler::get()->DefaultVersion() < NS_HTTP_VERSION_1_1)) {
|
||||
// HTTP/1.0 connections are by default NOT persistent
|
||||
if (val && !PL_strcasecmp(val, "keep-alive"))
|
||||
mKeepAlive = PR_TRUE;
|
||||
else
|
||||
mKeepAlive = PR_FALSE;
|
||||
}
|
||||
else {
|
||||
// HTTP/1.1 connections are by default persistent
|
||||
if (val && !PL_strcasecmp(val, "close"))
|
||||
mKeepAlive = PR_FALSE;
|
||||
else
|
||||
mKeepAlive = PR_TRUE;
|
||||
}
|
||||
mKeepAliveMask = mKeepAlive;
|
||||
|
||||
// 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
|
||||
// before the server will close it. we ignore the max reuse count, because
|
||||
// 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.
|
||||
if (mKeepAlive) {
|
||||
val = trans->ResponseHead()->PeekHeader(nsHttp::Keep_Alive);
|
||||
|
||||
const char *cp = PL_strcasestr(val, "timeout=");
|
||||
if (cp)
|
||||
mIdleTimeout = (PRUint32) atoi(cp + 8);
|
||||
else
|
||||
mIdleTimeout = nsHttpHandler::get()->IdleTimeout();
|
||||
|
||||
LOG(("Connection can be reused [this=%x idle-timeout=%u\n", this, mIdleTimeout));
|
||||
}
|
||||
|
||||
// if we're doing an SSL proxy connect, then we need to check whether or not
|
||||
// the connect was successful. if so, then we have to reset the transaction
|
||||
// and step-up the socket connection to SSL. finally, we have to wake up the
|
||||
// socket write request.
|
||||
if (mSSLProxyConnectStream) {
|
||||
mSSLProxyConnectStream = 0;
|
||||
if (trans->ResponseHead()->Status() == 200) {
|
||||
LOG(("SSL proxy CONNECT succeeded!\n"));
|
||||
*reset = PR_TRUE;
|
||||
ProxyStepUp();
|
||||
mWriteRequest->Resume();
|
||||
}
|
||||
else {
|
||||
LOG(("SSL proxy CONNECT failed!\n"));
|
||||
// close out the write request
|
||||
mWriteRequest->Cancel(NS_OK);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// called from any thread
|
||||
nsresult
|
||||
nsHttpConnection::OnTransactionComplete(nsHttpTransaction *trans, nsresult status)
|
||||
{
|
||||
LOG(("nsHttpConnection::OnTransactionComplete [this=%x trans=%x status=%x]\n",
|
||||
this, trans, status));
|
||||
|
||||
// trans may not be mTransaction
|
||||
if (trans != mTransaction)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIRequest> writeReq, readReq;
|
||||
|
||||
// clear the read/write requests atomically.
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
writeReq = mWriteRequest;
|
||||
readReq = mReadRequest;
|
||||
}
|
||||
|
||||
// cancel the requests... this will cause OnStopRequest to be fired
|
||||
if (writeReq)
|
||||
writeReq->Cancel(status);
|
||||
if (readReq)
|
||||
readReq->Cancel(status);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// not called from the socket thread
|
||||
nsresult
|
||||
nsHttpConnection::Suspend()
|
||||
{
|
||||
// we only bother to suspend the read request, since that's the only
|
||||
// one that will effect our consumers.
|
||||
|
||||
nsCOMPtr<nsIRequest> readReq;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
readReq = mReadRequest;
|
||||
}
|
||||
|
||||
if (readReq)
|
||||
readReq->Suspend();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// not called from the socket thread
|
||||
nsresult
|
||||
nsHttpConnection::Resume()
|
||||
{
|
||||
// we only need to worry about resuming the read request, since that's
|
||||
// the only one that can be suspended.
|
||||
|
||||
nsCOMPtr<nsIRequest> readReq;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
readReq = mReadRequest;
|
||||
}
|
||||
|
||||
if (readReq)
|
||||
readReq->Resume();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// called from the socket thread
|
||||
nsresult
|
||||
nsHttpConnection::ProxyStepUp()
|
||||
|
@ -304,10 +156,166 @@ nsHttpConnection::IsAlive()
|
|||
return isAlive;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nsHttpConnection::nsAHttpConnection
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// called from the socket thread
|
||||
nsresult
|
||||
nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
||||
nsHttpResponseHead *responseHead,
|
||||
PRBool *reset)
|
||||
{
|
||||
LOG(("nsHttpConnection::OnHeadersAvailable [this=%p trans=%p response-head=%p]\n",
|
||||
this, trans, responseHead));
|
||||
|
||||
NS_ENSURE_ARG_POINTER(trans);
|
||||
|
||||
// we won't change our keep-alive policy unless the server has explicitly
|
||||
// told us to do so.
|
||||
|
||||
if (!trans || !responseHead) {
|
||||
LOG(("nothing to do\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// inspect the connection headers for keep-alive info provided the
|
||||
// transaction completed successfully.
|
||||
const char *val = responseHead->PeekHeader(nsHttp::Connection);
|
||||
if (!val)
|
||||
val = responseHead->PeekHeader(nsHttp::Proxy_Connection);
|
||||
|
||||
if ((responseHead->Version() < NS_HTTP_VERSION_1_1) ||
|
||||
(nsHttpHandler::get()->DefaultVersion() < NS_HTTP_VERSION_1_1)) {
|
||||
// HTTP/1.0 connections are by default NOT persistent
|
||||
if (val && !PL_strcasecmp(val, "keep-alive"))
|
||||
mKeepAlive = PR_TRUE;
|
||||
else
|
||||
mKeepAlive = PR_FALSE;
|
||||
}
|
||||
else {
|
||||
// HTTP/1.1 connections are by default persistent
|
||||
if (val && !PL_strcasecmp(val, "close"))
|
||||
mKeepAlive = PR_FALSE;
|
||||
else
|
||||
mKeepAlive = PR_TRUE;
|
||||
}
|
||||
mKeepAliveMask = mKeepAlive;
|
||||
|
||||
// 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
|
||||
// before the server will close it. we ignore the max reuse count, because
|
||||
// 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.
|
||||
if (mKeepAlive) {
|
||||
val = responseHead->PeekHeader(nsHttp::Keep_Alive);
|
||||
|
||||
const char *cp = PL_strcasestr(val, "timeout=");
|
||||
if (cp)
|
||||
mIdleTimeout = (PRUint32) atoi(cp + 8);
|
||||
else
|
||||
mIdleTimeout = nsHttpHandler::get()->IdleTimeout();
|
||||
|
||||
LOG(("Connection can be reused [this=%x idle-timeout=%u\n", this, mIdleTimeout));
|
||||
}
|
||||
|
||||
// if we're doing an SSL proxy connect, then we need to check whether or not
|
||||
// the connect was successful. if so, then we have to reset the transaction
|
||||
// and step-up the socket connection to SSL. finally, we have to wake up the
|
||||
// socket write request.
|
||||
if (mSSLProxyConnectStream) {
|
||||
mSSLProxyConnectStream = 0;
|
||||
if (responseHead->Status() == 200) {
|
||||
LOG(("SSL proxy CONNECT succeeded!\n"));
|
||||
*reset = PR_TRUE;
|
||||
ProxyStepUp();
|
||||
mWriteRequest->Resume();
|
||||
}
|
||||
else {
|
||||
LOG(("SSL proxy CONNECT failed!\n"));
|
||||
// close out the write request
|
||||
mWriteRequest->Cancel(NS_OK);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// called from any thread
|
||||
nsresult
|
||||
nsHttpConnection::OnTransactionComplete(nsAHttpTransaction *trans, nsresult status)
|
||||
{
|
||||
LOG(("nsHttpConnection::OnTransactionComplete [this=%x trans=%x status=%x]\n",
|
||||
this, trans, status));
|
||||
|
||||
// trans may not be mTransaction
|
||||
if (trans != mTransaction)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIRequest> writeReq, readReq;
|
||||
|
||||
// clear the read/write requests atomically.
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
writeReq = mWriteRequest;
|
||||
readReq = mReadRequest;
|
||||
}
|
||||
|
||||
// cancel the requests... this will cause OnStopRequest to be fired
|
||||
if (writeReq)
|
||||
writeReq->Cancel(status);
|
||||
if (readReq)
|
||||
readReq->Cancel(status);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// not called from the socket thread
|
||||
nsresult
|
||||
nsHttpConnection::OnSuspend()
|
||||
{
|
||||
// we only bother to suspend the read request, since that's the only
|
||||
// one that will effect our consumers.
|
||||
|
||||
nsCOMPtr<nsIRequest> readReq;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
readReq = mReadRequest;
|
||||
}
|
||||
|
||||
if (readReq)
|
||||
readReq->Suspend();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// not called from the socket thread
|
||||
nsresult
|
||||
nsHttpConnection::OnResume()
|
||||
{
|
||||
// we only need to worry about resuming the read request, since that's
|
||||
// the only one that can be suspended.
|
||||
|
||||
nsCOMPtr<nsIRequest> readReq;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
readReq = mReadRequest;
|
||||
}
|
||||
|
||||
if (readReq)
|
||||
readReq->Resume();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// called on the socket thread
|
||||
void
|
||||
nsHttpConnection::DropTransaction()
|
||||
nsHttpConnection::DropTransaction(nsAHttpTransaction *trans)
|
||||
{
|
||||
LOG(("nsHttpConnection::DropTransaction [trans=%p]\n", trans));
|
||||
|
||||
// the assertion here is that the transaction will not be destroyed
|
||||
// by this release. we unfortunately don't have a threadsafe way of
|
||||
// asserting this.
|
||||
|
@ -361,7 +369,7 @@ nsHttpConnection::ActivateConnection()
|
|||
// by the same token, we need to ensure that the transaction stays around.
|
||||
// and we must not access it via mTransaction, since mTransaction is null'd
|
||||
// in our OnStopRequest.
|
||||
nsHttpTransaction *trans = mTransaction;
|
||||
nsAHttpTransaction *trans = mTransaction;
|
||||
NS_ADDREF(trans);
|
||||
|
||||
// We need to tell the socket transport what origin server we're
|
||||
|
@ -485,15 +493,19 @@ nsHttpConnection::SetupSSLProxyConnect()
|
|||
request.SetVersion(nsHttpHandler::get()->DefaultVersion());
|
||||
request.SetRequestURI(buf.get());
|
||||
request.SetHeader(nsHttp::User_Agent, nsHttpHandler::get()->UserAgent());
|
||||
|
||||
// NOTE: this cast is valid since this connection cannot be processing a
|
||||
// transaction pipeline until after the first HTTP/1.1 response.
|
||||
nsHttpTransaction *trans = NS_STATIC_CAST(nsHttpTransaction *, mTransaction);
|
||||
|
||||
val = mTransaction->RequestHead()->PeekHeader(nsHttp::Host);
|
||||
val = trans->RequestHead()->PeekHeader(nsHttp::Host);
|
||||
if (val) {
|
||||
// all HTTP/1.1 requests must include a Host header (even though it
|
||||
// may seem redundant in this case; see bug 82388).
|
||||
request.SetHeader(nsHttp::Host, val);
|
||||
}
|
||||
|
||||
val = mTransaction->RequestHead()->PeekHeader(nsHttp::Proxy_Authorization);
|
||||
val = trans->RequestHead()->PeekHeader(nsHttp::Proxy_Authorization);
|
||||
if (val) {
|
||||
// we don't know for sure if this authorization is intended for the
|
||||
// SSL proxy, so we add it just in case.
|
||||
|
@ -597,7 +609,7 @@ nsHttpConnection::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
|||
|
||||
// make sure mTransaction is clear before calling OnStopTransaction
|
||||
if (mTransaction) {
|
||||
nsHttpTransaction *trans = mTransaction;
|
||||
nsAHttpTransaction *trans = mTransaction;
|
||||
mTransaction = nsnull;
|
||||
|
||||
trans->OnStopTransaction(status);
|
||||
|
@ -702,8 +714,11 @@ nsHttpConnection::GetInterface(const nsIID &iid, void **result)
|
|||
if (iid.Equals(NS_GET_IID(nsIProgressEventSink)))
|
||||
return QueryInterface(iid, result);
|
||||
|
||||
if (mTransaction && mTransaction->Callbacks())
|
||||
return mTransaction->Callbacks()->GetInterface(iid, result);
|
||||
if (mTransaction) {
|
||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
mTransaction->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
||||
return callbacks->GetInterface(iid, result);
|
||||
}
|
||||
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#define nsHttpConnection_h__
|
||||
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpConnectionInfo.h"
|
||||
#include "nsAHttpConnection.h"
|
||||
#include "nsAHttpTransaction.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIStreamProvider.h"
|
||||
#include "nsISocketTransport.h"
|
||||
|
@ -33,23 +36,18 @@
|
|||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIProxyInfo.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "plstr.h"
|
||||
#include "prclist.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "prlock.h"
|
||||
|
||||
class nsHttpHandler;
|
||||
class nsHttpConnectionInfo;
|
||||
class nsHttpTransaction;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpConnection - represents a connection to a HTTP server (or proxy)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsHttpConnection : public nsIStreamListener
|
||||
class nsHttpConnection : public nsAHttpConnection
|
||||
, public nsIStreamListener
|
||||
, public nsIStreamProvider
|
||||
, public nsIProgressEventSink
|
||||
, public nsIInterfaceRequestor
|
||||
|
@ -74,18 +72,7 @@ public:
|
|||
|
||||
// SetTransaction causes the given transaction to be processed on this
|
||||
// connection. It fails if there is already an existing transaction.
|
||||
nsresult SetTransaction(nsHttpTransaction *);
|
||||
|
||||
// called by the transaction to inform the connection that all of the
|
||||
// headers are available.
|
||||
nsresult OnHeadersAvailable(nsHttpTransaction *, PRBool *reset);
|
||||
|
||||
// called by the transaction to inform the connection that it is done.
|
||||
nsresult OnTransactionComplete(nsHttpTransaction *, nsresult status);
|
||||
|
||||
// called by the transaction to suspend/resume a read-in-progress
|
||||
nsresult Suspend();
|
||||
nsresult Resume();
|
||||
nsresult SetTransaction(nsAHttpTransaction *, PRUint8 capabilities);
|
||||
|
||||
// called to cause the underlying socket to start speaking SSL
|
||||
nsresult ProxyStepUp();
|
||||
|
@ -96,11 +83,19 @@ public:
|
|||
mKeepAlive = PR_FALSE;
|
||||
mIdleTimeout = 0; }
|
||||
|
||||
void DropTransaction();
|
||||
|
||||
nsHttpTransaction *Transaction() { return mTransaction; }
|
||||
nsAHttpTransaction *Transaction() { return mTransaction; }
|
||||
nsHttpConnectionInfo *ConnectionInfo() { return mConnectionInfo; }
|
||||
|
||||
// nsAHttpConnection methods:
|
||||
nsresult OnHeadersAvailable(nsAHttpTransaction *, nsHttpResponseHead *, PRBool *reset);
|
||||
nsresult OnTransactionComplete(nsAHttpTransaction *, nsresult status);
|
||||
nsresult OnSuspend();
|
||||
nsresult OnResume();
|
||||
void GetConnectionInfo(nsHttpConnectionInfo **ci) { NS_IF_ADDREF(*ci = mConnectionInfo); }
|
||||
void DropTransaction(nsAHttpTransaction *);
|
||||
PRBool IsPersistent() { return IsKeepAlive(); }
|
||||
nsresult PushBack(char *data, PRUint32 length) { return NS_OK; }
|
||||
|
||||
private:
|
||||
nsresult ActivateConnection();
|
||||
nsresult CreateTransport();
|
||||
|
@ -116,7 +111,7 @@ private:
|
|||
|
||||
nsCOMPtr<nsIInputStream> mSSLProxyConnectStream;
|
||||
|
||||
nsHttpTransaction *mTransaction; // hard ref
|
||||
nsAHttpTransaction *mTransaction; // hard ref
|
||||
nsHttpConnectionInfo *mConnectionInfo; // hard ref
|
||||
|
||||
PRLock *mLock;
|
||||
|
@ -132,99 +127,4 @@ private:
|
|||
PRPackedBool mReadDone;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpConnectionInfo - holds the properties of a connection
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsHttpConnectionInfo
|
||||
{
|
||||
public:
|
||||
nsHttpConnectionInfo(const char *host, PRInt32 port,
|
||||
nsIProxyInfo* proxyInfo,
|
||||
PRBool usingSSL=PR_FALSE)
|
||||
: mRef(0)
|
||||
, mProxyInfo(proxyInfo)
|
||||
, mUsingSSL(usingSSL)
|
||||
{
|
||||
LOG(("Creating nsHttpConnectionInfo @%x\n", this));
|
||||
|
||||
mUsingHttpProxy = (proxyInfo && !nsCRT::strcmp(proxyInfo->Type(), "http"));
|
||||
|
||||
SetOriginServer(host, port);
|
||||
}
|
||||
|
||||
~nsHttpConnectionInfo()
|
||||
{
|
||||
LOG(("Destroying nsHttpConnectionInfo @%x\n", this));
|
||||
}
|
||||
|
||||
nsrefcnt AddRef()
|
||||
{
|
||||
return PR_AtomicIncrement((PRInt32 *) &mRef);
|
||||
}
|
||||
|
||||
nsrefcnt Release()
|
||||
{
|
||||
nsrefcnt n = PR_AtomicDecrement((PRInt32 *) &mRef);
|
||||
if (n == 0)
|
||||
delete this;
|
||||
return n;
|
||||
}
|
||||
|
||||
nsresult SetOriginServer(const char* host, PRInt32 port)
|
||||
{
|
||||
if (host)
|
||||
mHost.Adopt(nsCRT::strdup(host));
|
||||
mPort = port == -1 ? DefaultPort() : port;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host() : nsnull; }
|
||||
PRInt32 ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; }
|
||||
const char *ProxyType() const { return mProxyInfo ? mProxyInfo->Type() : nsnull; }
|
||||
|
||||
// Compare this connection info to another...
|
||||
// Two connections are 'equal' if they end up talking the same
|
||||
// protocol to the same server. This is needed to properly manage
|
||||
// persistent connections to proxies
|
||||
// Note that we don't care about transparent proxies -
|
||||
// it doesn't matter if we're talking via socks or not, since
|
||||
// a request will end up at the same host.
|
||||
PRBool Equals(const nsHttpConnectionInfo *info)
|
||||
{
|
||||
// Strictly speaking, we could talk to a proxy on the same port
|
||||
// and reuse the connection. Its not worth the extra strcmp.
|
||||
if ((info->mUsingHttpProxy != mUsingHttpProxy) ||
|
||||
(info->mUsingSSL != mUsingSSL))
|
||||
return PR_FALSE;
|
||||
|
||||
// if its a proxy, then compare the proxy servers.
|
||||
if (mUsingHttpProxy && !mUsingSSL)
|
||||
return (!PL_strcasecmp(info->ProxyHost(), ProxyHost()) &&
|
||||
info->ProxyPort() == ProxyPort());
|
||||
|
||||
// otherwise, just check the hosts
|
||||
return (!PL_strcasecmp(info->mHost, mHost) &&
|
||||
info->mPort == mPort);
|
||||
|
||||
}
|
||||
|
||||
const char *Host() { return mHost; }
|
||||
PRInt32 Port() { return mPort; }
|
||||
nsIProxyInfo *ProxyInfo() { return mProxyInfo; }
|
||||
PRBool UsingHttpProxy() { return mUsingHttpProxy; }
|
||||
PRBool UsingSSL() { return mUsingSSL; }
|
||||
|
||||
PRInt32 DefaultPort() { return mUsingSSL ? 443 : 80; }
|
||||
|
||||
private:
|
||||
nsrefcnt mRef;
|
||||
nsXPIDLCString mHost;
|
||||
PRInt32 mPort;
|
||||
nsCOMPtr<nsIProxyInfo> mProxyInfo;
|
||||
PRPackedBool mUsingHttpProxy;
|
||||
PRPackedBool mUsingSSL;
|
||||
};
|
||||
|
||||
#endif // nsHttpConnection_h__
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@netscape.com> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsHttpConnectionInfo_h__
|
||||
#define nsHttpConnectionInfo_h__
|
||||
|
||||
#include "nsHttp.h"
|
||||
#include "nsIProxyInfo.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "plstr.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpConnectionInfo - holds the properties of a connection
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsHttpConnectionInfo
|
||||
{
|
||||
public:
|
||||
nsHttpConnectionInfo(const char *host, PRInt32 port,
|
||||
nsIProxyInfo* proxyInfo,
|
||||
PRBool usingSSL=PR_FALSE)
|
||||
: mRef(0)
|
||||
, mProxyInfo(proxyInfo)
|
||||
, mUsingSSL(usingSSL)
|
||||
{
|
||||
LOG(("Creating nsHttpConnectionInfo @%x\n", this));
|
||||
|
||||
mUsingHttpProxy = (proxyInfo && !nsCRT::strcmp(proxyInfo->Type(), "http"));
|
||||
|
||||
SetOriginServer(host, port);
|
||||
}
|
||||
|
||||
~nsHttpConnectionInfo()
|
||||
{
|
||||
LOG(("Destroying nsHttpConnectionInfo @%x\n", this));
|
||||
}
|
||||
|
||||
nsrefcnt AddRef()
|
||||
{
|
||||
return PR_AtomicIncrement((PRInt32 *) &mRef);
|
||||
}
|
||||
|
||||
nsrefcnt Release()
|
||||
{
|
||||
nsrefcnt n = PR_AtomicDecrement((PRInt32 *) &mRef);
|
||||
if (n == 0)
|
||||
delete this;
|
||||
return n;
|
||||
}
|
||||
|
||||
nsresult SetOriginServer(const char* host, PRInt32 port)
|
||||
{
|
||||
if (host)
|
||||
mHost.Adopt(nsCRT::strdup(host));
|
||||
mPort = port == -1 ? DefaultPort() : port;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host() : nsnull; }
|
||||
PRInt32 ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; }
|
||||
const char *ProxyType() const { return mProxyInfo ? mProxyInfo->Type() : nsnull; }
|
||||
|
||||
// Compare this connection info to another...
|
||||
// Two connections are 'equal' if they end up talking the same
|
||||
// protocol to the same server. This is needed to properly manage
|
||||
// persistent connections to proxies
|
||||
// Note that we don't care about transparent proxies -
|
||||
// it doesn't matter if we're talking via socks or not, since
|
||||
// a request will end up at the same host.
|
||||
PRBool Equals(const nsHttpConnectionInfo *info)
|
||||
{
|
||||
// Strictly speaking, we could talk to a proxy on the same port
|
||||
// and reuse the connection. Its not worth the extra strcmp.
|
||||
if ((info->mUsingHttpProxy != mUsingHttpProxy) ||
|
||||
(info->mUsingSSL != mUsingSSL))
|
||||
return PR_FALSE;
|
||||
|
||||
// if its a proxy, then compare the proxy servers.
|
||||
if (mUsingHttpProxy && !mUsingSSL)
|
||||
return (!PL_strcasecmp(info->ProxyHost(), ProxyHost()) &&
|
||||
info->ProxyPort() == ProxyPort());
|
||||
|
||||
// otherwise, just check the hosts
|
||||
return (!PL_strcasecmp(info->mHost, mHost) &&
|
||||
info->mPort == mPort);
|
||||
|
||||
}
|
||||
|
||||
const char *Host() { return mHost; }
|
||||
PRInt32 Port() { return mPort; }
|
||||
nsIProxyInfo *ProxyInfo() { return mProxyInfo; }
|
||||
PRBool UsingHttpProxy() { return mUsingHttpProxy; }
|
||||
PRBool UsingSSL() { return mUsingSSL; }
|
||||
|
||||
PRInt32 DefaultPort() { return mUsingSSL ? 443 : 80; }
|
||||
|
||||
private:
|
||||
nsrefcnt mRef;
|
||||
nsXPIDLCString mHost;
|
||||
PRInt32 mPort;
|
||||
nsCOMPtr<nsIProxyInfo> mProxyInfo;
|
||||
PRPackedBool mUsingHttpProxy;
|
||||
PRPackedBool mUsingSSL;
|
||||
};
|
||||
|
||||
#endif // nsHttpConnectionInfo_h__
|
|
@ -476,7 +476,7 @@ nsHttpHandler::ProcessTransactionQ()
|
|||
nsresult
|
||||
nsHttpHandler::CancelTransaction(nsHttpTransaction *trans, nsresult status)
|
||||
{
|
||||
nsHttpConnection *conn;
|
||||
nsAHttpConnection *conn;
|
||||
|
||||
LOG(("nsHttpHandler::CancelTransaction [trans=%x status=%x]\n",
|
||||
trans, status));
|
||||
|
@ -797,7 +797,7 @@ nsHttpHandler::InitiateTransaction_Locked(nsHttpTransaction *trans,
|
|||
// we must not hold the connection lock while making this call
|
||||
// as it could lead to deadlocks.
|
||||
PR_Unlock(mConnectionLock);
|
||||
rv = conn->SetTransaction(trans);
|
||||
rv = conn->SetTransaction(trans, trans->Capabilities());
|
||||
PR_Lock(mConnectionLock);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -178,17 +178,6 @@ nsHttpTransaction::SetupRequest(nsHttpRequestHead *requestHead,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpTransaction::SetConnection(nsHttpConnection *conn)
|
||||
{
|
||||
LOG(("nsHttpTransaction::SetConnection [this=%x mConnection=%x conn=%x]\n",
|
||||
this, mConnection, conn));
|
||||
|
||||
mConnection = conn;
|
||||
NS_IF_ADDREF(mConnection);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsHttpResponseHead *
|
||||
nsHttpTransaction::TakeResponseHead()
|
||||
{
|
||||
|
@ -200,6 +189,10 @@ nsHttpTransaction::TakeResponseHead()
|
|||
return head;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nsHttpTransaction::nsAHttpTransaction
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// called on the socket transport thread
|
||||
nsresult
|
||||
nsHttpTransaction::OnDataWritable(nsIOutputStream *os)
|
||||
|
@ -328,19 +321,21 @@ nsHttpTransaction::Restart()
|
|||
NS_ADDREF_THIS();
|
||||
|
||||
// we don't want the connection to send anymore notifications to us.
|
||||
mConnection->DropTransaction();
|
||||
mConnection->DropTransaction(this);
|
||||
|
||||
nsHttpConnectionInfo *ci = mConnection->ConnectionInfo();
|
||||
NS_ADDREF(ci);
|
||||
nsHttpConnectionInfo *ci = nsnull;
|
||||
mConnection->GetConnectionInfo(&ci);
|
||||
NS_ASSERTION(ci, "connection info should be non-null");
|
||||
if (ci) {
|
||||
// we must release the connection before re-initiating this transaction
|
||||
// since we'll be getting a new connection.
|
||||
NS_RELEASE(mConnection);
|
||||
|
||||
// we must release the connection before calling initiate transaction
|
||||
// since we will be getting a new connection.
|
||||
NS_RELEASE(mConnection);
|
||||
rv = nsHttpHandler::get()->InitiateTransaction(this, ci);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "InitiateTransaction failed");
|
||||
|
||||
rv = nsHttpHandler::get()->InitiateTransaction(this, ci);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "InitiateTransaction failed");
|
||||
|
||||
NS_RELEASE(ci);
|
||||
NS_RELEASE(ci);
|
||||
}
|
||||
NS_RELEASE_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -492,7 +487,7 @@ nsHttpTransaction::HandleContentStart()
|
|||
#endif
|
||||
// notify the connection, give it a chance to cause a reset.
|
||||
PRBool reset = PR_FALSE;
|
||||
mConnection->OnHeadersAvailable(this, &reset);
|
||||
mConnection->OnHeadersAvailable(this, mResponseHead, &reset);
|
||||
|
||||
// looks like we should ignore this response, resetting...
|
||||
if (reset) {
|
||||
|
@ -578,10 +573,10 @@ nsHttpTransaction::HandleContent(char *buf,
|
|||
}
|
||||
else if (mContentLength >= 0) {
|
||||
// HTTP/1.0 servers have been known to send erroneous Content-Length
|
||||
// headers. So, unless the connection is keep-alive, we must make
|
||||
// headers. So, unless the connection is persistent, we must make
|
||||
// allowances for a possibly invalid Content-Length header. Thus, if
|
||||
// NOT keep-alive, we simply accept everything in |buf|.
|
||||
if (mConnection->IsKeepAlive()) {
|
||||
// NOT persistent, we simply accept everything in |buf|.
|
||||
if (mConnection->IsPersistent()) {
|
||||
*countRead = PRUint32(mContentLength) - mContentRead;
|
||||
*countRead = PR_MIN(count, *countRead);
|
||||
}
|
||||
|
@ -761,7 +756,7 @@ nsHttpTransaction::Suspend()
|
|||
{
|
||||
LOG(("nsHttpTransaction::Suspend [this=%x]\n", this));
|
||||
if (mConnection && !mTransactionDone)
|
||||
mConnection->Suspend();
|
||||
mConnection->OnSuspend();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -771,7 +766,7 @@ nsHttpTransaction::Resume()
|
|||
{
|
||||
LOG(("nsHttpTransaction::Resume [this=%x]\n", this));
|
||||
if (mConnection && !mTransactionDone)
|
||||
mConnection->Resume();
|
||||
mConnection->OnResume();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpHeaderArray.h"
|
||||
#include "nsAHttpTransaction.h"
|
||||
#include "nsAHttpConnection.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
|
@ -37,7 +39,6 @@
|
|||
|
||||
class nsHttpRequestHead;
|
||||
class nsHttpResponseHead;
|
||||
class nsHttpConnection;
|
||||
class nsHttpChunkedDecoder;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -45,7 +46,8 @@ class nsHttpChunkedDecoder;
|
|||
// intended to run on the socket thread.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsHttpTransaction : public nsIRequest
|
||||
class nsHttpTransaction : public nsAHttpTransaction
|
||||
, public nsIRequest
|
||||
, public nsIInputStream
|
||||
{
|
||||
public:
|
||||
|
@ -57,43 +59,32 @@ public:
|
|||
nsHttpTransaction(nsIStreamListener *, nsIInterfaceRequestor *, PRUint8 caps);
|
||||
virtual ~nsHttpTransaction();
|
||||
|
||||
nsrefcnt RefCnt() { return mRefCnt; }
|
||||
|
||||
// Called when assigned to a connection
|
||||
nsresult SetConnection(nsHttpConnection *);
|
||||
|
||||
// Called by the connection to set the associated socket security info
|
||||
void SetSecurityInfo(nsISupports *info) { mSecurityInfo = info; }
|
||||
|
||||
// Called to initialize the transaction
|
||||
nsresult SetupRequest(nsHttpRequestHead *, nsIInputStream *);
|
||||
|
||||
nsIStreamListener *Listener() { return mListener; }
|
||||
nsHttpConnection *Connection() { return mConnection; }
|
||||
nsAHttpConnection *Connection() { return mConnection; }
|
||||
nsHttpRequestHead *RequestHead() { return mRequestHead; }
|
||||
nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nsnull; }
|
||||
nsIInterfaceRequestor *Callbacks() { return mCallbacks; }
|
||||
nsIEventQueue *ConsumerEventQ() { return mConsumerEventQ; }
|
||||
nsISupports *SecurityInfo() { return mSecurityInfo; }
|
||||
PRBool IsDone() { return mTransactionDone; }
|
||||
nsresult Status() { return mStatus; }
|
||||
PRUint8 Capabilities() { return mCapabilities; }
|
||||
|
||||
// Called to take ownership of the response headers; the transaction
|
||||
// will drop any reference to the response headers after this call.
|
||||
nsHttpResponseHead *TakeResponseHead();
|
||||
|
||||
// Called to write data to the socket until return NS_BASE_STREAM_CLOSED
|
||||
// nsAHttpTransaction methods:
|
||||
void SetConnection(nsAHttpConnection *conn) { NS_IF_ADDREF(mConnection = conn); }
|
||||
void SetSecurityInfo(nsISupports *info) { mSecurityInfo = info; }
|
||||
void GetNotificationCallbacks(nsIInterfaceRequestor **cb) { NS_IF_ADDREF(*cb = mCallbacks); }
|
||||
nsresult OnDataWritable(nsIOutputStream *);
|
||||
|
||||
// Called to read data from the socket buffer
|
||||
nsresult OnDataReadable(nsIInputStream *);
|
||||
|
||||
// Called when the transaction should stop, possibly prematurely with an error.
|
||||
nsresult OnStopTransaction(nsresult);
|
||||
|
||||
// Called by the connection to report socket status
|
||||
void OnStatus(nsresult status, const PRUnichar *statusText);
|
||||
PRBool IsDone() { return mTransactionDone; }
|
||||
nsresult Status() { return mStatus; }
|
||||
|
||||
private:
|
||||
nsresult Restart();
|
||||
|
@ -114,7 +105,7 @@ private:
|
|||
nsCOMPtr<nsIEventQueue> mConsumerEventQ;
|
||||
nsCOMPtr<nsISupports> mSecurityInfo;
|
||||
|
||||
nsHttpConnection *mConnection; // hard ref
|
||||
nsAHttpConnection *mConnection; // hard ref
|
||||
|
||||
nsCString mReqHeaderBuf; // flattened request headers
|
||||
nsCOMPtr<nsIInputStream> mReqHeaderStream; // header data stream
|
||||
|
|
Загрузка…
Ссылка в новой задаче