bug #24711 (r=gagan). Changed cache channels to behave like transports rather than protocol channels...

This commit is contained in:
rpotts%netscape.com 2000-02-29 04:44:37 +00:00
Родитель a14179a92e
Коммит 7cf8d22c22
8 изменённых файлов: 550 добавлений и 195 удалений

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

@ -91,7 +91,7 @@ nsHTTPChannel::nsHTTPChannel(nsIURI* i_URL,
PRUint32 bufferMaxSize):
mResponse(nsnull),
mHandler(dont_QueryInterface(i_Handler)),
mRawResponseListener(nsnull),
mHTTPServerListener(nsnull),
mResponseContext(nsnull),
mOriginalURI(dont_QueryInterface(originalURI ? originalURI : i_URL)),
mURI(dont_QueryInterface(i_URL)),
@ -112,8 +112,14 @@ nsHTTPChannel::nsHTTPChannel(nsIURI* i_URL,
{
NS_INIT_REFCNT();
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("Creating nsHTTPChannel [this=%x].\n", this));
#if defined(PR_LOGGING)
nsXPIDLCString urlCString;
mURI->GetSpec(getter_Copies(urlCString));
PR_LOG(gHTTPLog, PR_LOG_DEBUG,
("Creating nsHTTPChannel [this=%x] for URI: %s.\n",
this, (const char *)urlCString));
#endif
mVerb = i_Verb;
}
@ -280,8 +286,12 @@ nsHTTPChannel::AsyncRead(PRUint32 startPosition, PRInt32 readCount,
ReadFromCache(startPosition, readCount);
} else if (mOpenObserver) {
// we were AsyncOpen()'d
NS_ASSERTION(mRawResponseListener, "our pointer to the response was never set");
return mRawResponseListener->FireSingleOnData(listener, aContext);
NS_ASSERTION(mHTTPServerListener, "ResponseListener was not set!.");
if (mHTTPServerListener) {
rv = mHTTPServerListener->FireSingleOnData(listener, aContext);
} else {
rv = NS_ERROR_NULL_POINTER;
}
}
return rv;
@ -873,47 +883,6 @@ nsHTTPChannel::CheckCache()
return NS_OK;
}
class nsCachedHTTPListener : public nsIStreamListener {
public:
nsCachedHTTPListener(nsIStreamListener *aListener, nsHTTPChannel* aChannel):
mListener(aListener), mChannel(aChannel) {
NS_INIT_REFCNT();
NS_IF_ADDREF(mChannel);
}
virtual ~nsCachedHTTPListener() { NS_IF_RELEASE(mChannel); }
private:
NS_DECL_ISUPPORTS
NS_IMETHOD
OnDataAvailable(nsIChannel *aChannel, nsISupports *aContext,
nsIInputStream *aStream, PRUint32 aSourceOffset,
PRUint32 aCount)
{
return mListener->OnDataAvailable(mChannel, aContext,
aStream, aSourceOffset, aCount);
}
NS_IMETHOD
OnStartRequest(nsIChannel *aChannel, nsISupports *aContext) {
return mListener->OnStartRequest(mChannel, aContext);
}
NS_IMETHOD
OnStopRequest(nsIChannel *aChannel, nsISupports *aContext,
nsresult aStatus, const PRUnichar *aErrorMsg) {
return mChannel->ResponseCompleted(nsnull, mListener, aStatus, aErrorMsg);
}
protected:
nsCOMPtr<nsIStreamListener> mListener;
nsHTTPChannel* mChannel;
};
NS_IMPL_ISUPPORTS2(nsCachedHTTPListener, nsIStreamListener, nsIStreamObserver)
// If the data in the cache hasn't expired, then there's no need to
// talk with the server, not even to do an if-modified-since. This
@ -934,48 +903,52 @@ nsHTTPChannel::ReadFromCache(PRUint32 aStartPosition, PRInt32 aReadCount)
if (!mResponseDataListener)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIChannel> cacheChannel;
rv = mCacheEntry->NewChannel(mLoadGroup, this, getter_AddRefs(cacheChannel));
#if defined(PR_LOGGING)
nsresult log_rv;
char *URLSpec;
log_rv = mURI->GetSpec(&URLSpec);
if (NS_FAILED(log_rv)) {
URLSpec = nsCRT::strdup("?");
}
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("nsHTTPChannel::ReadFromCache [this=%x].\t"
"Using cache copy for: %s\n",
this, URLSpec));
nsAllocator::Free(URLSpec);
#endif /* PR_LOGGING */
// Create a cache transport to read the cached response...
nsCOMPtr<nsIChannel> cacheTransport;
rv = mCacheEntry->NewChannel(mLoadGroup, this, getter_AddRefs(cacheTransport));
if (NS_FAILED(rv)) return rv;
mRequest->SetTransport(cacheTransport);
// Fake it so that HTTP headers come from cached versions
NS_IF_RELEASE(mResponse);
mResponse = mCachedResponse;
NS_ADDREF(mResponse);
SetResponse(mCachedResponse);
nsCOMPtr<nsIStreamListener> loadGroupListener = mResponseDataListener;
if (mLoadGroup) {
nsCOMPtr<nsILoadGroupListenerFactory> factory;
//
// Create a load group "proxy" listener...
//
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
if (NS_SUCCEEDED(rv) && factory) {
factory->CreateLoadGroupListener(mResponseDataListener,
getter_AddRefs(loadGroupListener));
}
}
// Create a listener that intercepts cache reads and fires off the appropriate
// events such as OnHeadersAvailable
nsCachedHTTPListener* listener;
listener = new nsCachedHTTPListener(loadGroupListener, this);
nsHTTPResponseListener* listener;
listener = new nsHTTPCacheListener(this);
if (!listener)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(listener);
listener->SetListener(mResponseDataListener);
mConnected = PR_TRUE;
// Fire all the normal events for header arrival
FinishedResponseHeaders();
// Pump the cache data downstream
rv = cacheChannel->AsyncRead(aStartPosition, aReadCount,
rv = cacheTransport->AsyncRead(aStartPosition, aReadCount,
mResponseContext, listener);
NS_RELEASE(listener);
if (NS_FAILED(rv)) {
ResponseCompleted(0, nsnull, rv, 0);
ResponseCompleted(nsnull, rv, 0);
}
return rv;
}
@ -1161,7 +1134,7 @@ nsHTTPChannel::Open(void)
}
if (NS_FAILED(rv)) {
// Unable to create a transport... End the request...
(void) ResponseCompleted(nsnull, mResponseDataListener, rv, nsnull);
(void) ResponseCompleted(mResponseDataListener, rv, nsnull);
return rv;
}
@ -1169,7 +1142,8 @@ nsHTTPChannel::Open(void)
rv = transport->SetNotificationCallbacks(this);
if (NS_FAILED(rv)) {
// Unable to create a transport... End the request...
(void) ResponseCompleted(nsnull, mResponseDataListener, rv, nsnull);
(void) ResponseCompleted(mResponseDataListener, rv, nsnull);
(void) ReleaseTransport(transport);
return rv;
}
@ -1207,7 +1181,9 @@ nsHTTPChannel::Open(void)
rv = pModules->GetNext(getter_AddRefs(supEntry)); // go around again
}
rv = mRequest->WriteRequest(transport, (mProxy && *mProxy));
mRequest->SetTransport(transport);
rv = mRequest->WriteRequest((mProxy && *mProxy));
if (NS_FAILED(rv)) return rv;
mState = HS_WAITING_FOR_RESPONSE;
@ -1324,8 +1300,7 @@ nsresult nsHTTPChannel::Redirect(const char *aNewLocation,
}
nsresult nsHTTPChannel::ResponseCompleted(nsIChannel* aTransport,
nsIStreamListener *aListener,
nsresult nsHTTPChannel::ResponseCompleted(nsIStreamListener *aListener,
nsresult aStatus,
const PRUnichar* aMsg)
{
@ -1346,11 +1321,6 @@ nsresult nsHTTPChannel::ResponseCompleted(nsIChannel* aTransport,
}
}
// Release the transport...
if (aTransport) {
(void)mHandler->ReleaseTransport(aTransport);
}
//
// After the consumer has been notified, remove the channel from its
// load group... This will trigger an OnStopRequest from the load group.
@ -1378,6 +1348,17 @@ nsresult nsHTTPChannel::ResponseCompleted(nsIChannel* aTransport,
return rv;
}
nsresult nsHTTPChannel::ReleaseTransport(nsIChannel *aTransport)
{
nsresult rv = NS_OK;
if (aTransport) {
(void) mRequest->ReleaseTransport(aTransport);
rv = mHandler->ReleaseTransport(aTransport);
}
return rv;
}
nsresult nsHTTPChannel::SetResponse(nsHTTPResponse* i_pResp)
{
NS_IF_RELEASE(mResponse);
@ -1404,8 +1385,8 @@ nsresult nsHTTPChannel::Abort()
// Disconnect the consumer from this response listener...
// This allows the entity that follows to be discarded
// without notifying the consumer...
if (mRawResponseListener) {
mRawResponseListener->Abort();
if (mHTTPServerListener) {
mHTTPServerListener->Abort();
}
// Null out pointers that are no longer needed...
@ -1687,21 +1668,8 @@ nsHTTPChannel::ProcessStatusCode(void)
}
nsCOMPtr<nsIStreamListener> listener = mResponseDataListener;
if (mLoadGroup) {
nsCOMPtr<nsILoadGroupListenerFactory> factory;
//
// Create a load group "proxy" listener...
//
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
if (NS_SUCCEEDED(rv) && factory) {
factory->CreateLoadGroupListener(mResponseDataListener,
getter_AddRefs(listener));
}
}
statusClass = statusCode / 100;
switch (statusClass) {
//
// Informational: 1xx
@ -1744,10 +1712,11 @@ nsHTTPChannel::ProcessStatusCode(void)
if (statusCode == 304) {
rv = ProcessNotModifiedResponse(listener);
if (NS_FAILED(rv)) return rv;
break;
}
// 300 (Multiple choices) or 301 (Redirect) results can be cached
else if ((statusCode == 300) || (statusCode == 301)) {
if ((statusCode == 300) || (statusCode == 301)) {
nsCOMPtr<nsIStreamListener> listener2;
CacheReceivedResponse(listener, getter_AddRefs(listener2));
if (listener2) {
@ -1792,8 +1761,8 @@ nsHTTPChannel::ProcessStatusCode(void)
// If mResponseDataListener is null this means that the response has been
// aborted... So, do not update the response listener because this
// is being discarded...
if (mResponseDataListener && mRawResponseListener) {
mRawResponseListener->SetResponseDataListener(listener);
if (mResponseDataListener && mHTTPServerListener) {
mHTTPServerListener->SetListener(listener);
}
return rv;
}
@ -1804,21 +1773,75 @@ nsHTTPChannel::ProcessNotModifiedResponse(nsIStreamListener *aListener)
nsresult rv;
NS_ASSERTION(!mCachedContentIsValid, "We should never have cached a 304 response");
// Abort the current response... This will disconnect the consumer from
// the response listener... Thus allowing the entity that follows to
// be discarded without notifying the consumer...
Abort();
#if defined(PR_LOGGING)
nsresult log_rv;
char *URLSpec;
log_rv = mURI->GetSpec(&URLSpec);
if (NS_FAILED(log_rv)) {
URLSpec = nsCRT::strdup("?");
}
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("nsHTTPChannel::ProcessNotModifiedResponse [this=%x].\t"
"Using cache copy for: %s\n",
this, URLSpec));
nsAllocator::Free(URLSpec);
#endif /* PR_LOGGING */
// Orphan the current nsHTTPServerListener instance... It will be
// replaced with a nsHTTPCacheListener instance.
NS_ASSERTION(mHTTPServerListener, "No nsHTTPServerResponse available!");
if (mHTTPServerListener) {
mHTTPServerListener->Abort();
}
// Update the cached headers with any more recent ones from the
// server - see RFC2616 [13.5.3]
nsCOMPtr<nsISimpleEnumerator> enumerator;
rv = mResponse->GetHeaderEnumerator(getter_AddRefs(enumerator));
if (NS_FAILED(rv)) return rv;
mCachedResponse->UpdateHeaders(enumerator);
// Store the updated HTTP headers in the cache
// XXX: Should the Expires value be recaluclated too?
nsCString allHeaders;
rv = mCachedResponse->EmitHeaders(allHeaders);
if (NS_FAILED(rv)) return rv;
rv = mCacheEntry->SetAnnotation("HTTP headers", allHeaders.Length()+1,
allHeaders.GetBuffer());
if (NS_FAILED(rv)) return rv;
// Fake it so that HTTP headers come from cached versions
SetResponse(mCachedResponse);
// We don't set a load group for the cache channel because the HTTP
// channel is handling the load group interactions
nsCOMPtr<nsIChannel> cacheChannel;
rv = mCacheEntry->NewChannel(mLoadGroup, this, getter_AddRefs(cacheChannel));
// Create a cache transport to read the cached response...
nsCOMPtr<nsIChannel> cacheTransport;
rv = mCacheEntry->NewChannel(mLoadGroup, this, getter_AddRefs(cacheTransport));
if (NS_FAILED(rv)) return rv;
return cacheChannel->AsyncRead(0, -1, mResponseContext, aListener);
mRequest->SetTransport(cacheTransport);
// Create a new HTTPCacheListener...
nsHTTPResponseListener *cacheListener;
cacheListener = new nsHTTPCacheListener(this);
if (!cacheListener) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(cacheListener);
cacheListener->SetListener(aListener);
mResponseDataListener = aListener;
rv = cacheTransport->AsyncRead(0, -1, mResponseContext, cacheListener);
if (NS_FAILED(rv)) {
ResponseCompleted(cacheListener, rv, nsnull);
}
NS_RELEASE(cacheListener);
return rv;
}
nsresult

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

@ -94,10 +94,10 @@ public:
nsresult Redirect(const char *aURL,
nsIChannel **aResult);
nsresult ResponseCompleted(nsIChannel* aTransport,
nsIStreamListener* aListener,
nsresult ResponseCompleted(nsIStreamListener* aListener,
nsresult aStatus,
const PRUnichar* aMsg);
nsresult ReleaseTransport(nsIChannel *aTransport);
nsresult SetResponse(nsHTTPResponse* i_pResp);
nsresult GetResponseContext(nsISupports** aContext);
@ -125,7 +125,7 @@ public:
nsHTTPHandler* mHandler;
nsHTTPRequest* mRequest;
nsHTTPResponseListener* mRawResponseListener;
nsHTTPResponseListener* mHTTPServerListener;
nsCOMPtr<nsISupports> mResponseContext;
protected:

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

@ -50,23 +50,25 @@ static NS_DEFINE_CID(kHTTPHandlerCID, NS_IHTTPHANDLER_CID);
extern nsresult DupString(char* *o_Dest, const char* i_Src);
nsHTTPRequest::nsHTTPRequest(nsIURI* i_URL, HTTPMethod i_Method,
nsIChannel* i_Transport):
nsHTTPRequest::nsHTTPRequest(nsIURI* i_URL, HTTPMethod i_Method):
mMethod(i_Method),
mVersion(HTTP_ONE_ZERO),
mUsingProxy(PR_FALSE),
mRequestSpec(0)
{
NS_INIT_REFCNT();
NS_ASSERTION(i_URL, "No URL for the request!!");
mURI = do_QueryInterface(i_URL);
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("Creating nsHTTPRequest [this=%x].\n", this));
#if defined(PR_LOGGING)
nsXPIDLCString urlCString;
mURI->GetSpec(getter_Copies(urlCString));
PR_LOG(gHTTPLog, PR_LOG_DEBUG,
("Creating nsHTTPRequest [this=%x] for URI: %s.\n",
this, (const char *)urlCString));
#endif
mTransport = i_Transport;
NS_ASSERTION(mURI, "No URI for the request!!");
nsXPIDLCString host;
mURI->GetHost(getter_Copies(host));
@ -143,7 +145,7 @@ nsHTTPRequest::~nsHTTPRequest()
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("Deleting nsHTTPRequest [this=%x].\n", this));
mTransport = null_nsCOMPtr();
mTransport = 0;
CRTFREEIF(mRequestSpec);
}
@ -230,7 +232,7 @@ nsHTTPRequest::Resume(void)
// Finally our own methods...
nsresult nsHTTPRequest::WriteRequest(nsIChannel *aTransport, PRBool aIsProxied)
nsresult nsHTTPRequest::WriteRequest(PRBool aIsProxied)
{
nsresult rv;
if (!mURI) {
@ -238,10 +240,7 @@ nsresult nsHTTPRequest::WriteRequest(nsIChannel *aTransport, PRBool aIsProxied)
return NS_ERROR_NULL_POINTER;
}
NS_ASSERTION(!mTransport, "Transport being overwritten!");
mTransport = aTransport;
mUsingProxy = aIsProxied;
NS_ASSERTION(mTransport, "No transport has been set on this request.");
PRUint32 loadAttributes;
mConnection->GetLoadAttributes(&loadAttributes);
@ -287,7 +286,7 @@ nsresult nsHTTPRequest::WriteRequest(nsIChannel *aTransport, PRBool aIsProxied)
mRequestBuffer.Append(mRequestSpec);
else
{
if (mUsingProxy) {
if (aIsProxied) {
rv = mURI->GetSpec(getter_Copies(autoBuffer));
} else {
rv = mURI->GetPath(getter_Copies(autoBuffer));
@ -372,7 +371,7 @@ nsresult nsHTTPRequest::WriteRequest(nsIChannel *aTransport, PRBool aIsProxied)
//
// Write the request to the server.
//
rv = aTransport->AsyncWrite(stream, 0, mRequestBuffer.Length(),
rv = mTransport->AsyncWrite(stream, 0, mRequestBuffer.Length(),
(nsISupports*)(nsIRequest*)mConnection, this);
return rv;
}
@ -492,7 +491,7 @@ nsHTTPRequest::OnStopRequest(nsIChannel* channel, nsISupports* i_Context,
"\tStatus: %x\n",
this, iStatus));
nsHTTPResponseListener* pListener = new nsHTTPResponseListener(mConnection);
nsHTTPResponseListener* pListener = new nsHTTPServerListener(mConnection);
if (pListener) {
NS_ADDREF(pListener);
rv = mTransport->AsyncRead(0, -1, i_Context, pListener);
@ -511,16 +510,24 @@ nsHTTPRequest::OnStopRequest(nsIChannel* channel, nsISupports* i_Context,
"\tStatus: %x\n",
this, iStatus));
rv = iStatus;
}
//
// An error occurred... Finish the transaction and notify the consumer
// of the failure...
//
if (NS_FAILED(rv)) {
// Notify the HTTPChannel that the request has finished
nsCOMPtr<nsIStreamListener> consumer;
mConnection->GetResponseDataListener(getter_AddRefs(consumer));
mConnection->ResponseCompleted(mTransport, consumer, iStatus, i_Msg);
mConnection->ResponseCompleted(consumer, rv, i_Msg);
mConnection->ReleaseTransport(mTransport);
mTransport = null_nsCOMPtr();
rv = iStatus;
NS_ASSERTION(!mTransport, "nsHTTRequest::ReleaseTransport() "
"was not called!");
}
//
@ -539,6 +546,19 @@ nsresult nsHTTPRequest::SetConnection(nsHTTPChannel* i_Connection)
return NS_OK;
}
nsresult nsHTTPRequest::SetTransport(nsIChannel *aTransport)
{
mTransport = aTransport;
return NS_OK;
}
nsresult nsHTTPRequest::ReleaseTransport(nsIChannel *aTransport)
{
if (aTransport == mTransport) {
mTransport = 0;
}
return NS_OK;
}
nsresult nsHTTPRequest::GetHeaderEnumerator(nsISimpleEnumerator** aResult)
{

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

@ -64,7 +64,7 @@ class nsHTTPRequest : public nsIStreamObserver,
public:
// Constructor
nsHTTPRequest(nsIURI* i_URL=0, HTTPMethod i_Method=HM_GET, nsIChannel* i_Tranport = nsnull);
nsHTTPRequest(nsIURI* i_URL, HTTPMethod i_Method=HM_GET);
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMOBSERVER
@ -104,9 +104,11 @@ public:
nsresult SetConnection(nsHTTPChannel* i_Connection);
nsresult SetTransport(nsIChannel *aTransport);
nsresult ReleaseTransport(nsIChannel *aTransport);
// Build the actual request string based on the settings.
nsresult WriteRequest(nsIChannel *aChannel,
PRBool aIsProxied = PR_FALSE);
nsresult WriteRequest(PRBool aIsProxied = PR_FALSE);
nsresult GetPostDataStream(nsIInputStream* *aResult);
nsresult SetPostDataStream(nsIInputStream* aStream);
@ -145,7 +147,6 @@ protected:
nsHTTPChannel* mConnection;
nsHTTPHeaderArray mHeaders;
PRBool mUsingProxy;
nsCString mRequestBuffer;
nsCOMPtr<nsIInputStream> mPostDataStream;

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

@ -715,6 +715,8 @@ nsresult nsHTTPResponse::EmitHeaders(nsCString& aResponseBuffer)
headerAtomRaw == nsHTTPAtoms::Trailer ||
headerAtomRaw == nsHTTPAtoms::Transfer_Encoding ||
headerAtomRaw == nsHTTPAtoms::Upgrade ||
// XXX: This seems wrong. See RFC 2109 [4.3.2]
// Should depend on Cache-control: no-cache="set-cookie"
headerAtomRaw == nsHTTPAtoms::Set_Cookie)
continue;
@ -753,3 +755,102 @@ nsresult nsHTTPResponse::ParseHeaders(nsCString& aAllHeaders)
beginLineOffset = endLineOffset + 2; // Skip past CRLF
}
}
//
// This routine is used to update the Response Headers after a 304
// Response has been received.
//
// + The nsISimpleEnumerator contains the response headers from the
// 304 response.
// + These headers replace the cached headers. See RFC 2616 [13.5.3]
// + Wacky headers which are send by certain servers are also ignored.
//
nsresult nsHTTPResponse::UpdateHeaders(nsISimpleEnumerator *aEnumerator)
{
nsresult rv;
PRBool bMoreHeaders = PR_FALSE;
nsCOMPtr<nsISupports> item;
nsCOMPtr<nsIHTTPHeader> header;
nsCOMPtr<nsIAtom> headerAtom;
nsXPIDLCString headerValue;
PR_LOG(gHTTPLog, PR_LOG_DEBUG,
("nsHTTPResponse::UpdateHeaders [this=%x].\n", this));
rv = aEnumerator->HasMoreElements(&bMoreHeaders);
while (NS_SUCCEEDED(rv) && bMoreHeaders) {
rv = aEnumerator->GetNext(getter_AddRefs(item));
if (NS_FAILED(rv)) return rv;
header = do_QueryInterface(item, &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "Bad HTTP header.");
if (NS_SUCCEEDED(rv)) {
rv = header->GetField(getter_AddRefs(headerAtom));
if (NS_FAILED(rv)) return rv;
nsIAtom *atom = headerAtom;
// Ignore any hop-by-hop headers...
if (atom == nsHTTPAtoms::Connection ||
atom == nsHTTPAtoms::Keep_Alive ||
atom == nsHTTPAtoms::Proxy_Authenticate ||
atom == nsHTTPAtoms::Proxy_Authorization ||
atom == nsHTTPAtoms::TE ||
atom == nsHTTPAtoms::Trailer ||
atom == nsHTTPAtoms::Transfer_Encoding ||
atom == nsHTTPAtoms::Upgrade ||
// Ignore any non-modifiable headers
atom == nsHTTPAtoms::Content_Location ||
atom == nsHTTPAtoms::Content_MD5 ||
atom == nsHTTPAtoms::ETag ||
atom == nsHTTPAtoms::Last_Modified ||
// Assume Cache-Control: "no-transform"
atom == nsHTTPAtoms::Content_Encoding ||
atom == nsHTTPAtoms::Content_Range ||
atom == nsHTTPAtoms::Content_Type ||
// Ignore wacky headers too...
// This one is for MS Servers that send a Content-Length:0
// on 304 responses...
atom == nsHTTPAtoms::Content_Length) {
#if defined(PR_LOGGING)
nsCAutoString nameBuffer;
const PRUnichar *name = nsnull;
// Convert the atom name from unicode to ascii...
atom->GetUnicode(&name);
nameBuffer.Assign(name);
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("\tUpdateHeaders [this=%x]."
"\tIgnoring response header: \'%s\'\n",
this, nameBuffer.GetBuffer()));
#endif /* PR_LOGGING */
} else {
// Delete the current header value (if any)...
mHeaders.SetHeader(headerAtom, nsnull);
// Copy the new header value...
rv = header->GetValue(getter_Copies(headerValue));
if (NS_SUCCEEDED(rv)) {
rv = mHeaders.SetHeader(headerAtom, headerValue);
}
if (NS_FAILED(rv)) return rv;
#if defined(PR_LOGGING)
nsCAutoString nameBuffer;
const PRUnichar *name = nsnull;
atom->GetUnicode(&name);
nameBuffer.Assign(name);
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("\tUpdateHeaders [this=%x].\tNew response header: \'%s: %s\'\n",
this, nameBuffer.GetBuffer(), (const char*)headerValue));
#endif /* PR_LOGGING */
}
}
rv = aEnumerator->HasMoreElements(&bMoreHeaders);
}
return rv;
}

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

@ -76,7 +76,9 @@ public:
nsresult ParseHeaders(nsCString& aAllHeaders);
nsresult ProcessHeader(nsIAtom* aHeader, nsCString& aValue);
nsresult EmitHeaders(nsCString& aResult);
nsresult UpdateHeaders(nsISimpleEnumerator *aEnumerator);
PRBool IsStale(PRBool aUseHeuristicExpiration);
nsresult ParseDateHeader(nsIAtom *aAtom, PRTime *aResultTime, PRBool *aHeaderIsPresent);

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

@ -55,35 +55,52 @@ extern PRLogModuleInfo* gHTTPLog;
static const int kMAX_HEADER_SIZE = 60000;
nsHTTPResponseListener::nsHTTPResponseListener(nsHTTPChannel* aConnection):
mResponse(nsnull),
mFirstLineParsed(PR_FALSE),
mHeadersDone(PR_FALSE),
mBytesReceived(0)
///////////////////////////////////////////////////////////////////////////////
//
// nsHTTPResponseListener Implementation (abstract base class)
//
///////////////////////////////////////////////////////////////////////////////
nsHTTPResponseListener::nsHTTPResponseListener(nsHTTPChannel *aChannel)
: mChannel(aChannel)
{
NS_INIT_REFCNT();
NS_INIT_REFCNT();
NS_ASSERTION(aConnection, "HTTPChannel is null.");
mChannel = aConnection;
NS_ADDREF(mChannel);
mChannel->mRawResponseListener = this;
// mChannel is not an interface pointer, so COMPtrs cannot be used :-(
NS_ASSERTION(aChannel, "HTTPChannel is null.");
NS_ADDREF(mChannel);
#if defined(PR_LOGGING)
nsCOMPtr<nsIURI> url;
nsXPIDLCString urlCString;
aChannel->GetURI(getter_AddRefs(url));
if (url) {
url->GetSpec(getter_Copies(urlCString));
}
PR_LOG(gHTTPLog, PR_LOG_DEBUG,
("Creating nsHTTPResponseListener [this=%x] for URI: %s.\n",
this, (const char *)urlCString));
#endif
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("Creating nsHTTPResponseListener [this=%x].\n", this));
}
nsHTTPResponseListener::~nsHTTPResponseListener()
{
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("Deleting nsHTTPResponseListener [this=%x].\n", this));
// These two should go away in the OnStopRequest() callback.
// But, just in case...
NS_IF_RELEASE(mChannel);
NS_IF_RELEASE(mResponse);
// mChannel is not an interface pointer, so COMPtrs cannot be used :-(
NS_IF_RELEASE(mChannel);
}
void nsHTTPResponseListener::SetListener(nsIStreamListener *aListener)
{
mResponseDataListener = aListener;
}
////////////////////////////////////////////////////////////////////////////////
// nsISupports methods:
NS_IMPL_THREADSAFE_ADDREF(nsHTTPResponseListener)
NS_IMPL_THREADSAFE_RELEASE(nsHTTPResponseListener)
@ -91,6 +108,135 @@ NS_IMPL_QUERY_INTERFACE2(nsHTTPResponseListener,
nsIStreamListener,
nsIStreamObserver);
///////////////////////////////////////////////////////////////////////////////
//
// nsHTTPCacheListener Implementation
//
// This subclass of nsHTTPResponseListener processes responses from
// the cache.
//
///////////////////////////////////////////////////////////////////////////////
nsHTTPCacheListener::nsHTTPCacheListener(nsHTTPChannel* aChannel)
: nsHTTPResponseListener(aChannel)
{
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("Creating nsHTTPCacheListener [this=%x].\n", this));
}
nsHTTPCacheListener::~nsHTTPCacheListener()
{
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("Deleting nsHTTPCacheListener [this=%x].\n", this));
}
////////////////////////////////////////////////////////////////////////////////
// nsIStreamObserver methods:
NS_IMETHODIMP
nsHTTPCacheListener::OnStartRequest(nsIChannel *aChannel,
nsISupports *aContext)
{
PR_LOG(gHTTPLog, PR_LOG_DEBUG,
("nsHTTPCacheListener::OnStartRequest [this=%x].\n",
this));
return mResponseDataListener->OnStartRequest(mChannel, aContext);
}
NS_IMETHODIMP
nsHTTPCacheListener::OnStopRequest(nsIChannel *aChannel,
nsISupports *aContext,
nsresult aStatus,
const PRUnichar *aErrorMsg)
{
PR_LOG(gHTTPLog, PR_LOG_DEBUG,
("nsHTTPCacheListener::OnStopRequest [this=%x]."
"\tStatus = %x\n", this, aStatus));
//
// Notify the channel that the response has finished. Since there
// is no socket transport involved nsnull is passed as the
// transport...
//
return mChannel->ResponseCompleted(mResponseDataListener,
aStatus,
aErrorMsg);
}
////////////////////////////////////////////////////////////////////////////////
// nsIStreamListener methods:
NS_IMETHODIMP
nsHTTPCacheListener::OnDataAvailable(nsIChannel *aChannel,
nsISupports *aContext,
nsIInputStream *aStream,
PRUint32 aSourceOffset,
PRUint32 aCount)
{
return mResponseDataListener->OnDataAvailable(mChannel,
aContext,
aStream,
aSourceOffset,
aCount);
}
////////////////////////////////////////////////////////////////////////////////
// nsHTTPResponseListener methods:
nsresult
nsHTTPCacheListener::FireSingleOnData(nsIStreamListener *aListener,
nsISupports *aContext)
{
NS_ASSERTION(0, "nsHTTPCacheListener::FireSingleOnData(...) "
"should never be called.");
return NS_ERROR_FAILURE;
}
nsresult nsHTTPCacheListener::Abort()
{
NS_ASSERTION(0, "nsHTTPCachedResponseListener::Abort() "
"should never be called.");
return NS_ERROR_FAILURE;
}
////////////////////////////////////////////////////////////////////////////////
//
// nsHTTPServerListener Implementation
//
// This subclass of nsHTTPResponseListener processes responses from
// HTTP servers.
//
////////////////////////////////////////////////////////////////////////////////
nsHTTPServerListener::nsHTTPServerListener(nsHTTPChannel* aChannel)
: nsHTTPResponseListener(aChannel),
mResponse(nsnull),
mFirstLineParsed(PR_FALSE),
mHeadersDone(PR_FALSE),
mBytesReceived(0)
{
mChannel->mHTTPServerListener = this;
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("Creating nsHTTPServerListener [this=%x].\n", this));
}
nsHTTPServerListener::~nsHTTPServerListener()
{
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("Deleting nsHTTPServerListener [this=%x].\n", this));
// These two should go away in the OnStopRequest() callback.
// But, just in case...
NS_IF_RELEASE(mResponse);
}
static NS_DEFINE_IID(kProxyObjectManagerIID, NS_IPROXYEVENT_MANAGER_IID);
static NS_DEFINE_CID(kEventQueueService, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_CID(kNetModuleMgrCID, NS_NETMODULEMGR_CID);
@ -99,11 +245,11 @@ static NS_DEFINE_CID(kNetModuleMgrCID, NS_NETMODULEMGR_CID);
// nsIStreamListener methods:
NS_IMETHODIMP
nsHTTPResponseListener::OnDataAvailable(nsIChannel* channel,
nsISupports* context,
nsIInputStream *i_pStream,
PRUint32 i_SourceOffset,
PRUint32 i_Length)
nsHTTPServerListener::OnDataAvailable(nsIChannel* channel,
nsISupports* context,
nsIInputStream *i_pStream,
PRUint32 i_SourceOffset,
PRUint32 i_Length)
{
nsresult rv = NS_OK;
PRUint32 actualBytesRead;
@ -111,7 +257,7 @@ nsHTTPResponseListener::OnDataAvailable(nsIChannel* channel,
nsCOMPtr<nsIBufferInputStream> bufferInStream = do_QueryInterface(i_pStream);
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("nsHTTPResponseListener::OnDataAvailable [this=%x].\n"
("nsHTTPServerListener::OnDataAvailable [this=%x].\n"
"\tstream=%x. \toffset=%d. \tlength=%d.\n",
this, i_pStream, i_SourceOffset, i_Length));
@ -211,10 +357,10 @@ nsHTTPResponseListener::OnDataAvailable(nsIChannel* channel,
NS_IMETHODIMP
nsHTTPResponseListener::OnStartRequest(nsIChannel* channel, nsISupports* i_pContext)
nsHTTPServerListener::OnStartRequest(nsIChannel* channel, nsISupports* i_pContext)
{
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("nsHTTPResponseListener::OnStartRequest [this=%x].\n", this));
("nsHTTPServerListener::OnStartRequest [this=%x].\n", this));
// Initialize header varaibles...
mHeadersDone = PR_FALSE;
@ -224,15 +370,15 @@ nsHTTPResponseListener::OnStartRequest(nsIChannel* channel, nsISupports* i_pCont
}
NS_IMETHODIMP
nsHTTPResponseListener::OnStopRequest(nsIChannel* channel,
nsISupports* i_pContext,
nsresult i_Status,
const PRUnichar* i_pMsg)
nsHTTPServerListener::OnStopRequest(nsIChannel* channel,
nsISupports* i_pContext,
nsresult i_Status,
const PRUnichar* i_pMsg)
{
nsresult rv = NS_OK;
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("nsHTTPResponseListener::OnStopRequest [this=%x]."
("nsHTTPServerListener::OnStopRequest [this=%x]."
"\tStatus = %x\n", this, i_Status));
if (NS_SUCCEEDED(rv) && !mHeadersDone) {
@ -253,11 +399,23 @@ nsHTTPResponseListener::OnStopRequest(nsIChannel* channel,
// Notify the HTTPChannel that the response has completed...
NS_ASSERTION(mChannel, "HTTPChannel is null.");
if (mChannel) {
mChannel->ResponseCompleted(channel, mResponseDataListener,
i_Status, i_pMsg);
PRUint32 status = 0;
// The HTTPChannel is no longer needed...
mChannel->mRawResponseListener = 0;
if (mResponse) {
mResponse->GetStatus(&status);
}
if (status != 304) {
mChannel->ResponseCompleted(mResponseDataListener,
i_Status, i_pMsg);
// The HTTPChannel no longer needs a reference to this object.
mChannel->mHTTPServerListener = 0;
} else {
PR_LOG(gHTTPLog, PR_LOG_DEBUG,
("nsHTTPServerListener::OnStopRequest [this=%x]. "
"Discarding 304 response\n", this));
}
mChannel->ReleaseTransport(channel);
}
NS_IF_RELEASE(mChannel);
@ -267,12 +425,12 @@ nsHTTPResponseListener::OnStopRequest(nsIChannel* channel,
}
////////////////////////////////////////////////////////////////////////////////
// nsHTTPResponseListener methods:
// nsHTTPServerListener methods:
nsresult nsHTTPResponseListener::Abort()
nsresult nsHTTPServerListener::Abort()
{
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("nsHTTPResponseListener::Abort [this=%x].", this));
("nsHTTPServerListener::Abort [this=%x].", this));
//
// Clearing the data consumer will cause the response to abort. This
@ -284,7 +442,7 @@ nsresult nsHTTPResponseListener::Abort()
}
nsresult nsHTTPResponseListener::FireSingleOnData(nsIStreamListener *aListener, nsISupports *aContext)
nsresult nsHTTPServerListener::FireSingleOnData(nsIStreamListener *aListener, nsISupports *aContext)
{
nsresult rv;
@ -318,9 +476,9 @@ nsWriteToString(void* closure,
}
nsresult nsHTTPResponseListener::ParseStatusLine(nsIBufferInputStream* in,
PRUint32 aLength,
PRUint32 *aBytesRead)
nsresult nsHTTPServerListener::ParseStatusLine(nsIBufferInputStream* in,
PRUint32 aLength,
PRUint32 *aBytesRead)
{
nsresult rv = NS_OK;
@ -328,7 +486,7 @@ nsresult nsHTTPResponseListener::ParseStatusLine(nsIBufferInputStream* in,
PRUint32 offsetOfEnd, totalBytesToRead, actualBytesRead;
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("nsHTTPResponseListener::ParseStatusLine [this=%x].\taLength=%d\n",
("nsHTTPServerListener::ParseStatusLine [this=%x].\taLength=%d\n",
this, aLength));
*aBytesRead = 0;
@ -405,9 +563,9 @@ nsresult nsHTTPResponseListener::ParseStatusLine(nsIBufferInputStream* in,
nsresult nsHTTPResponseListener::ParseHTTPHeader(nsIBufferInputStream* in,
PRUint32 aLength,
PRUint32 *aBytesRead)
nsresult nsHTTPServerListener::ParseHTTPHeader(nsIBufferInputStream* in,
PRUint32 aLength,
PRUint32 *aBytesRead)
{
nsresult rv = NS_OK;
@ -508,7 +666,7 @@ nsresult nsHTTPResponseListener::ParseHTTPHeader(nsIBufferInputStream* in,
return mResponse->ParseHeader(mHeaderBuffer);
}
nsresult nsHTTPResponseListener::FinishedResponseHeaders(void)
nsresult nsHTTPServerListener::FinishedResponseHeaders(void)
{
nsresult rv;
@ -529,3 +687,6 @@ nsresult nsHTTPResponseListener::FinishedResponseHeaders(void)
return rv;
}

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

@ -52,21 +52,48 @@ class nsHTTPChannel;
*/
class nsHTTPResponseListener : public nsIStreamListener
{
public:
nsHTTPResponseListener(nsHTTPChannel* aConnection);
virtual ~nsHTTPResponseListener();
// nsISupport methods...
NS_DECL_ISUPPORTS
// abstract methods implemented by the various ResponseListener
// subclasses...
virtual nsresult FireSingleOnData(nsIStreamListener *aListener,
nsISupports *aContext) = 0;
virtual nsresult Abort() = 0;
void SetListener(nsIStreamListener *aListener);
protected:
nsCOMPtr<nsIStreamListener> mResponseDataListener;
nsHTTPChannel* mChannel;
};
/*
* This class pocesses responses from HTTP servers...
*/
class nsHTTPServerListener : public nsHTTPResponseListener
{
public:
nsHTTPServerListener(nsHTTPChannel* aConnection);
virtual ~nsHTTPServerListener();
NS_DECL_NSISTREAMOBSERVER
NS_DECL_NSISTREAMLISTENER
nsresult FireSingleOnData(nsIStreamListener *aListener, nsISupports *aContext);
nsresult Abort();
void SetResponseDataListener(nsIStreamListener *aListener) {
mResponseDataListener = aListener;
}
virtual nsresult FireSingleOnData(nsIStreamListener *aListener,
nsISupports *aContext);
virtual nsresult Abort();
nsresult Discard304Response(void);
protected:
// nsHTTPResponseListener methods...
@ -80,15 +107,35 @@ protected:
PRUint32* aBytesRead);
protected:
nsCOMPtr<nsIStreamListener> mResponseDataListener;
nsCString mHeaderBuffer;
nsHTTPChannel* mChannel;
nsHTTPResponse* mResponse;
PRBool mFirstLineParsed;
PRBool mHeadersDone;
PRBool mFirstLineParsed;
PRBool mHeadersDone;
nsCOMPtr<nsIInputStream> mDataStream;
PRUint32 mBytesReceived;
};
/*
* This class processes responses from the cache...
*/
class nsHTTPCacheListener : public nsHTTPResponseListener
{
public:
nsHTTPCacheListener(nsHTTPChannel* aChannel);
virtual ~nsHTTPCacheListener();
// nsIStreamObserver methods...
NS_DECL_NSISTREAMOBSERVER
// nsIStreamListener methods...
NS_DECL_NSISTREAMLISTENER
virtual nsresult FireSingleOnData(nsIStreamListener *aListener,
nsISupports *aContext);
virtual nsresult Abort();
};
#endif /* _nsHTTPResponseListener_h_ */