initial framework patch for http/1.1 pipelining (bug 93054) r=gagan, sr=rpotts

This commit is contained in:
darin%netscape.com 2001-10-02 00:31:30 +00:00
Родитель 070dba8b90
Коммит 5ac2b46834
8 изменённых файлов: 455 добавлений и 327 удалений

Просмотреть файл

@ -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
@ -486,14 +494,18 @@ nsHttpConnection::SetupSSLProxyConnect()
request.SetRequestURI(buf.get());
request.SetHeader(nsHttp::User_Agent, nsHttpHandler::get()->UserAgent());
val = mTransaction->RequestHead()->PeekHeader(nsHttp::Host);
// 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 = 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);
// we must release the connection before calling initiate transaction
// since we will be getting a new connection.
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);
rv = nsHttpHandler::get()->InitiateTransaction(this, ci);
NS_ASSERTION(NS_SUCCEEDED(rv), "InitiateTransaction failed");
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