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 // called from any thread, with the connection lock held
nsresult nsresult
nsHttpConnection::SetTransaction(nsHttpTransaction *transaction) nsHttpConnection::SetTransaction(nsAHttpTransaction *transaction,
PRUint8 caps)
{ {
LOG(("nsHttpConnection::SetTransaction [this=%x trans=%x]\n", LOG(("nsHttpConnection::SetTransaction [this=%x trans=%x]\n",
this, transaction)); this, transaction));
@ -112,160 +113,11 @@ nsHttpConnection::SetTransaction(nsHttpTransaction *transaction)
NS_ADDREF(mTransaction); NS_ADDREF(mTransaction);
// default mKeepAlive according to what will be requested // default mKeepAlive according to what will be requested
mKeepAliveMask = mKeepAlive = mKeepAliveMask = mKeepAlive = (caps & NS_HTTP_ALLOW_KEEPALIVE);
mTransaction->Capabilities() & NS_HTTP_ALLOW_KEEPALIVE;
return ActivateConnection(); 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 // called from the socket thread
nsresult nsresult
nsHttpConnection::ProxyStepUp() nsHttpConnection::ProxyStepUp()
@ -304,10 +156,166 @@ nsHttpConnection::IsAlive()
return 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 // called on the socket thread
void 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 // the assertion here is that the transaction will not be destroyed
// by this release. we unfortunately don't have a threadsafe way of // by this release. we unfortunately don't have a threadsafe way of
// asserting this. // asserting this.
@ -361,7 +369,7 @@ nsHttpConnection::ActivateConnection()
// by the same token, we need to ensure that the transaction stays around. // 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 // and we must not access it via mTransaction, since mTransaction is null'd
// in our OnStopRequest. // in our OnStopRequest.
nsHttpTransaction *trans = mTransaction; nsAHttpTransaction *trans = mTransaction;
NS_ADDREF(trans); NS_ADDREF(trans);
// We need to tell the socket transport what origin server we're // We need to tell the socket transport what origin server we're
@ -485,15 +493,19 @@ nsHttpConnection::SetupSSLProxyConnect()
request.SetVersion(nsHttpHandler::get()->DefaultVersion()); request.SetVersion(nsHttpHandler::get()->DefaultVersion());
request.SetRequestURI(buf.get()); request.SetRequestURI(buf.get());
request.SetHeader(nsHttp::User_Agent, nsHttpHandler::get()->UserAgent()); 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) { if (val) {
// all HTTP/1.1 requests must include a Host header (even though it // all HTTP/1.1 requests must include a Host header (even though it
// may seem redundant in this case; see bug 82388). // may seem redundant in this case; see bug 82388).
request.SetHeader(nsHttp::Host, val); request.SetHeader(nsHttp::Host, val);
} }
val = mTransaction->RequestHead()->PeekHeader(nsHttp::Proxy_Authorization); val = trans->RequestHead()->PeekHeader(nsHttp::Proxy_Authorization);
if (val) { if (val) {
// we don't know for sure if this authorization is intended for the // we don't know for sure if this authorization is intended for the
// SSL proxy, so we add it just in case. // 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 // make sure mTransaction is clear before calling OnStopTransaction
if (mTransaction) { if (mTransaction) {
nsHttpTransaction *trans = mTransaction; nsAHttpTransaction *trans = mTransaction;
mTransaction = nsnull; mTransaction = nsnull;
trans->OnStopTransaction(status); trans->OnStopTransaction(status);
@ -702,8 +714,11 @@ nsHttpConnection::GetInterface(const nsIID &iid, void **result)
if (iid.Equals(NS_GET_IID(nsIProgressEventSink))) if (iid.Equals(NS_GET_IID(nsIProgressEventSink)))
return QueryInterface(iid, result); return QueryInterface(iid, result);
if (mTransaction && mTransaction->Callbacks()) if (mTransaction) {
return mTransaction->Callbacks()->GetInterface(iid, result); nsCOMPtr<nsIInterfaceRequestor> callbacks;
mTransaction->GetNotificationCallbacks(getter_AddRefs(callbacks));
return callbacks->GetInterface(iid, result);
}
return NS_ERROR_NO_INTERFACE; return NS_ERROR_NO_INTERFACE;
} }

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

@ -25,6 +25,9 @@
#define nsHttpConnection_h__ #define nsHttpConnection_h__
#include "nsHttp.h" #include "nsHttp.h"
#include "nsHttpConnectionInfo.h"
#include "nsAHttpConnection.h"
#include "nsAHttpTransaction.h"
#include "nsIStreamListener.h" #include "nsIStreamListener.h"
#include "nsIStreamProvider.h" #include "nsIStreamProvider.h"
#include "nsISocketTransport.h" #include "nsISocketTransport.h"
@ -33,23 +36,18 @@
#include "nsIInterfaceRequestorUtils.h" #include "nsIInterfaceRequestorUtils.h"
#include "nsIEventQueue.h" #include "nsIEventQueue.h"
#include "nsIInputStream.h" #include "nsIInputStream.h"
#include "nsIProxyInfo.h"
#include "nsCOMPtr.h"
#include "nsXPIDLString.h" #include "nsXPIDLString.h"
#include "plstr.h" #include "nsCOMPtr.h"
#include "prclist.h"
#include "nsCRT.h"
#include "prlock.h" #include "prlock.h"
class nsHttpHandler; class nsHttpHandler;
class nsHttpConnectionInfo;
class nsHttpTransaction;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// nsHttpConnection - represents a connection to a HTTP server (or proxy) // nsHttpConnection - represents a connection to a HTTP server (or proxy)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class nsHttpConnection : public nsIStreamListener class nsHttpConnection : public nsAHttpConnection
, public nsIStreamListener
, public nsIStreamProvider , public nsIStreamProvider
, public nsIProgressEventSink , public nsIProgressEventSink
, public nsIInterfaceRequestor , public nsIInterfaceRequestor
@ -74,18 +72,7 @@ public:
// SetTransaction causes the given transaction to be processed on this // SetTransaction causes the given transaction to be processed on this
// connection. It fails if there is already an existing transaction. // connection. It fails if there is already an existing transaction.
nsresult SetTransaction(nsHttpTransaction *); nsresult SetTransaction(nsAHttpTransaction *, PRUint8 capabilities);
// 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();
// called to cause the underlying socket to start speaking SSL // called to cause the underlying socket to start speaking SSL
nsresult ProxyStepUp(); nsresult ProxyStepUp();
@ -96,11 +83,19 @@ public:
mKeepAlive = PR_FALSE; mKeepAlive = PR_FALSE;
mIdleTimeout = 0; } mIdleTimeout = 0; }
void DropTransaction(); nsAHttpTransaction *Transaction() { return mTransaction; }
nsHttpTransaction *Transaction() { return mTransaction; }
nsHttpConnectionInfo *ConnectionInfo() { return mConnectionInfo; } 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: private:
nsresult ActivateConnection(); nsresult ActivateConnection();
nsresult CreateTransport(); nsresult CreateTransport();
@ -116,7 +111,7 @@ private:
nsCOMPtr<nsIInputStream> mSSLProxyConnectStream; nsCOMPtr<nsIInputStream> mSSLProxyConnectStream;
nsHttpTransaction *mTransaction; // hard ref nsAHttpTransaction *mTransaction; // hard ref
nsHttpConnectionInfo *mConnectionInfo; // hard ref nsHttpConnectionInfo *mConnectionInfo; // hard ref
PRLock *mLock; PRLock *mLock;
@ -132,99 +127,4 @@ private:
PRPackedBool mReadDone; 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__ #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 nsresult
nsHttpHandler::CancelTransaction(nsHttpTransaction *trans, nsresult status) nsHttpHandler::CancelTransaction(nsHttpTransaction *trans, nsresult status)
{ {
nsHttpConnection *conn; nsAHttpConnection *conn;
LOG(("nsHttpHandler::CancelTransaction [trans=%x status=%x]\n", LOG(("nsHttpHandler::CancelTransaction [trans=%x status=%x]\n",
trans, status)); trans, status));
@ -797,7 +797,7 @@ nsHttpHandler::InitiateTransaction_Locked(nsHttpTransaction *trans,
// we must not hold the connection lock while making this call // we must not hold the connection lock while making this call
// as it could lead to deadlocks. // as it could lead to deadlocks.
PR_Unlock(mConnectionLock); PR_Unlock(mConnectionLock);
rv = conn->SetTransaction(trans); rv = conn->SetTransaction(trans, trans->Capabilities());
PR_Lock(mConnectionLock); PR_Lock(mConnectionLock);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {

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

@ -178,17 +178,6 @@ nsHttpTransaction::SetupRequest(nsHttpRequestHead *requestHead,
return rv; 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 * nsHttpResponseHead *
nsHttpTransaction::TakeResponseHead() nsHttpTransaction::TakeResponseHead()
{ {
@ -200,6 +189,10 @@ nsHttpTransaction::TakeResponseHead()
return head; return head;
} }
//----------------------------------------------------------------------------
// nsHttpTransaction::nsAHttpTransaction
//----------------------------------------------------------------------------
// called on the socket transport thread // called on the socket transport thread
nsresult nsresult
nsHttpTransaction::OnDataWritable(nsIOutputStream *os) nsHttpTransaction::OnDataWritable(nsIOutputStream *os)
@ -328,19 +321,21 @@ nsHttpTransaction::Restart()
NS_ADDREF_THIS(); NS_ADDREF_THIS();
// we don't want the connection to send anymore notifications to us. // we don't want the connection to send anymore notifications to us.
mConnection->DropTransaction(); mConnection->DropTransaction(this);
nsHttpConnectionInfo *ci = mConnection->ConnectionInfo(); nsHttpConnectionInfo *ci = nsnull;
NS_ADDREF(ci); 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 rv = nsHttpHandler::get()->InitiateTransaction(this, ci);
// since we will be getting a new connection. NS_ASSERTION(NS_SUCCEEDED(rv), "InitiateTransaction failed");
NS_RELEASE(mConnection);
rv = nsHttpHandler::get()->InitiateTransaction(this, ci); NS_RELEASE(ci);
NS_ASSERTION(NS_SUCCEEDED(rv), "InitiateTransaction failed"); }
NS_RELEASE(ci);
NS_RELEASE_THIS(); NS_RELEASE_THIS();
return NS_OK; return NS_OK;
} }
@ -492,7 +487,7 @@ nsHttpTransaction::HandleContentStart()
#endif #endif
// notify the connection, give it a chance to cause a reset. // notify the connection, give it a chance to cause a reset.
PRBool reset = PR_FALSE; PRBool reset = PR_FALSE;
mConnection->OnHeadersAvailable(this, &reset); mConnection->OnHeadersAvailable(this, mResponseHead, &reset);
// looks like we should ignore this response, resetting... // looks like we should ignore this response, resetting...
if (reset) { if (reset) {
@ -578,10 +573,10 @@ nsHttpTransaction::HandleContent(char *buf,
} }
else if (mContentLength >= 0) { else if (mContentLength >= 0) {
// HTTP/1.0 servers have been known to send erroneous Content-Length // 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 // allowances for a possibly invalid Content-Length header. Thus, if
// NOT keep-alive, we simply accept everything in |buf|. // NOT persistent, we simply accept everything in |buf|.
if (mConnection->IsKeepAlive()) { if (mConnection->IsPersistent()) {
*countRead = PRUint32(mContentLength) - mContentRead; *countRead = PRUint32(mContentLength) - mContentRead;
*countRead = PR_MIN(count, *countRead); *countRead = PR_MIN(count, *countRead);
} }
@ -761,7 +756,7 @@ nsHttpTransaction::Suspend()
{ {
LOG(("nsHttpTransaction::Suspend [this=%x]\n", this)); LOG(("nsHttpTransaction::Suspend [this=%x]\n", this));
if (mConnection && !mTransactionDone) if (mConnection && !mTransactionDone)
mConnection->Suspend(); mConnection->OnSuspend();
return NS_OK; return NS_OK;
} }
@ -771,7 +766,7 @@ nsHttpTransaction::Resume()
{ {
LOG(("nsHttpTransaction::Resume [this=%x]\n", this)); LOG(("nsHttpTransaction::Resume [this=%x]\n", this));
if (mConnection && !mTransactionDone) if (mConnection && !mTransactionDone)
mConnection->Resume(); mConnection->OnResume();
return NS_OK; return NS_OK;
} }

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

@ -26,6 +26,8 @@
#include "nsHttp.h" #include "nsHttp.h"
#include "nsHttpHeaderArray.h" #include "nsHttpHeaderArray.h"
#include "nsAHttpTransaction.h"
#include "nsAHttpConnection.h"
#include "nsIStreamListener.h" #include "nsIStreamListener.h"
#include "nsIInputStream.h" #include "nsIInputStream.h"
#include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestor.h"
@ -37,7 +39,6 @@
class nsHttpRequestHead; class nsHttpRequestHead;
class nsHttpResponseHead; class nsHttpResponseHead;
class nsHttpConnection;
class nsHttpChunkedDecoder; class nsHttpChunkedDecoder;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -45,7 +46,8 @@ class nsHttpChunkedDecoder;
// intended to run on the socket thread. // intended to run on the socket thread.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class nsHttpTransaction : public nsIRequest class nsHttpTransaction : public nsAHttpTransaction
, public nsIRequest
, public nsIInputStream , public nsIInputStream
{ {
public: public:
@ -57,43 +59,32 @@ public:
nsHttpTransaction(nsIStreamListener *, nsIInterfaceRequestor *, PRUint8 caps); nsHttpTransaction(nsIStreamListener *, nsIInterfaceRequestor *, PRUint8 caps);
virtual ~nsHttpTransaction(); 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 // Called to initialize the transaction
nsresult SetupRequest(nsHttpRequestHead *, nsIInputStream *); nsresult SetupRequest(nsHttpRequestHead *, nsIInputStream *);
nsIStreamListener *Listener() { return mListener; } nsIStreamListener *Listener() { return mListener; }
nsHttpConnection *Connection() { return mConnection; } nsAHttpConnection *Connection() { return mConnection; }
nsHttpRequestHead *RequestHead() { return mRequestHead; } nsHttpRequestHead *RequestHead() { return mRequestHead; }
nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nsnull; } nsHttpResponseHead *ResponseHead() { return mHaveAllHeaders ? mResponseHead : nsnull; }
nsIInterfaceRequestor *Callbacks() { return mCallbacks; } nsIInterfaceRequestor *Callbacks() { return mCallbacks; }
nsIEventQueue *ConsumerEventQ() { return mConsumerEventQ; } nsIEventQueue *ConsumerEventQ() { return mConsumerEventQ; }
nsISupports *SecurityInfo() { return mSecurityInfo; } nsISupports *SecurityInfo() { return mSecurityInfo; }
PRBool IsDone() { return mTransactionDone; }
nsresult Status() { return mStatus; }
PRUint8 Capabilities() { return mCapabilities; } PRUint8 Capabilities() { return mCapabilities; }
// Called to take ownership of the response headers; the transaction // Called to take ownership of the response headers; the transaction
// will drop any reference to the response headers after this call. // will drop any reference to the response headers after this call.
nsHttpResponseHead *TakeResponseHead(); 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 *); nsresult OnDataWritable(nsIOutputStream *);
// Called to read data from the socket buffer
nsresult OnDataReadable(nsIInputStream *); nsresult OnDataReadable(nsIInputStream *);
// Called when the transaction should stop, possibly prematurely with an error.
nsresult OnStopTransaction(nsresult); nsresult OnStopTransaction(nsresult);
// Called by the connection to report socket status
void OnStatus(nsresult status, const PRUnichar *statusText); void OnStatus(nsresult status, const PRUnichar *statusText);
PRBool IsDone() { return mTransactionDone; }
nsresult Status() { return mStatus; }
private: private:
nsresult Restart(); nsresult Restart();
@ -114,7 +105,7 @@ private:
nsCOMPtr<nsIEventQueue> mConsumerEventQ; nsCOMPtr<nsIEventQueue> mConsumerEventQ;
nsCOMPtr<nsISupports> mSecurityInfo; nsCOMPtr<nsISupports> mSecurityInfo;
nsHttpConnection *mConnection; // hard ref nsAHttpConnection *mConnection; // hard ref
nsCString mReqHeaderBuf; // flattened request headers nsCString mReqHeaderBuf; // flattened request headers
nsCOMPtr<nsIInputStream> mReqHeaderStream; // header data stream nsCOMPtr<nsIInputStream> mReqHeaderStream; // header data stream