Laying the foundation for the incorporation of caching, by

reorganizing/splitting protocol handler methods, though not yet adding any
new functionality:

    Allow for multiple instances of nsHTTPResponse to be associated
    with the same connection, i.e. so that response headers from the
    cache and response headers from the server can coexist
    simultaneously.  To wit:

        Moved content-length, charset and content-type information
        from nsHTTPChannel into nsHTTPResponse

        Split into separate functions the accumulation of a single line of
        HTTP header data (from the input stream) and the parsing of
        that line.  This permits cached response headers and server
        response headers to be parsed from separate data sources, the
        latter arriving from a nsIBufferInputStream and the former
        retrieved from the cache as a string.

        Moved the newly-created header-parsing methods to
        nsHTTPResponse from nsHTTPResponseListener

    Fixed some bugs in the interaction between AsyncOpen and
    AsyncRead.  It was possible for an OnHeadersAvailable event to be
    triggered *after* the associated OnDataAvailable, rather than the
    other way around.  It was also possible, in a rare case, for
    mOpenObserver->OnStopRequest() to be called without ever having
    called mOpenObserver->OnStartRequest().  I think my changes made
    the logic a bit more foolproof.

    Removed ancient ifdef NSPIPE2
This commit is contained in:
fur%netscape.com 1999-12-02 03:53:28 +00:00
Родитель 0de3c034b5
Коммит cb5751940a
7 изменённых файлов: 351 добавлений и 303 удалений

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

@ -45,6 +45,7 @@ HTTP_ATOM(Age, "age")
HTTP_ATOM(Allow, "allow")
HTTP_ATOM(Authentication, "authentication")
HTTP_ATOM(Authorization, "authorization")
HTTP_ATOM(Cache_Control, "cache-control")
HTTP_ATOM(Connection, "connection")
HTTP_ATOM(Content_Base, "content-base")
HTTP_ATOM(Content_Encoding, "content-encoding")

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

@ -90,9 +90,6 @@ nsHTTPChannel::nsHTTPChannel(nsIURI* i_URL,
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("Creating nsHTTPChannel [this=%x].\n", this));
// The content length is unknown...
mContentLength = -1;
mVerb = i_Verb;
}
@ -278,12 +275,9 @@ nsHTTPChannel::GetContentType(char * *aContentType)
//
// If the content type has been returned by the server then return that...
//
if (mContentType.Length()) {
*aContentType = mContentType.ToNewCString();
if (!*aContentType) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
return rv;
if (mResponse) {
rv = mResponse->GetContentType(aContentType);
if (rv != NS_ERROR_NOT_AVAILABLE) return rv;
}
//
@ -312,8 +306,9 @@ nsHTTPChannel::GetContentType(char * *aContentType)
NS_IMETHODIMP
nsHTTPChannel::GetContentLength(PRInt32 *aContentLength)
{
*aContentLength = mContentLength;
return NS_OK;
if (!mResponse)
return NS_ERROR_NOT_AVAILABLE;
return mResponse->GetContentLength(aContentLength);
}
@ -538,14 +533,9 @@ nsHTTPChannel::GetResponseDataListener(nsIStreamListener* *aListener)
NS_IMETHODIMP
nsHTTPChannel::GetCharset(char* *o_String)
{
nsresult rv = NS_OK;
*o_String = mCharset.ToNewCString();
if (!*o_String) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
return rv;
if (!mResponse)
return NS_ERROR_NOT_AVAILABLE;
return mResponse->GetCharset(o_String);
}
NS_IMETHODIMP
@ -678,7 +668,8 @@ nsHTTPChannel::Open(void)
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISimpleEnumerator> pModules;
rv = pNetModuleMgr->EnumerateModules(NS_NETWORK_MODULE_MANAGER_HTTP_REQUEST_PROGID, getter_AddRefs(pModules));
rv = pNetModuleMgr->EnumerateModules(NS_NETWORK_MODULE_MANAGER_HTTP_REQUEST_PROGID,
getter_AddRefs(pModules));
if (NS_FAILED(rv)) return rv;
// Go through the external modules and notify each one.
@ -705,15 +696,11 @@ nsHTTPChannel::Open(void)
rv = pModules->GetNext(getter_AddRefs(supEntry)); // go around again
}
if (transport) {
rv = mRequest->WriteRequest(transport, mUsingProxy);
if (NS_FAILED(rv)) return rv;
mState = HS_WAITING_FOR_RESPONSE;
mConnected = PR_TRUE;
}
else
NS_ERROR("Failed to create/get a transport!");
rv = mRequest->WriteRequest(transport, mUsingProxy);
if (NS_FAILED(rv)) return rv;
mState = HS_WAITING_FOR_RESPONSE;
mConnected = PR_TRUE;
return rv;
}
@ -868,27 +855,6 @@ nsresult nsHTTPChannel::GetResponseContext(nsISupports** aContext)
return NS_ERROR_NULL_POINTER;
}
nsresult nsHTTPChannel::SetContentLength(PRInt32 aContentLength)
{
mContentLength = aContentLength;
return NS_OK;
}
nsresult nsHTTPChannel::SetContentType(const char* aContentType)
{
nsCAutoString cType(aContentType);
cType.ToLowerCase();
mContentType = cType.GetBuffer();
return NS_OK;
}
nsresult nsHTTPChannel::SetCharset(const char *aCharset)
{
mCharset = aCharset;
return NS_OK;
}
nsresult nsHTTPChannel::OnHeadersAvailable()
{
nsresult rv = NS_OK;

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

@ -41,6 +41,8 @@
#include "nsIStreamObserver.h"
class nsHTTPRequest;
class nsHTTPResponse;
/*
The nsHTTPChannel class is an example implementation of a
protocol instnce that is active on a per-URL basis.
@ -85,9 +87,6 @@ public:
const PRUnichar* aMsg);
nsresult SetResponse(nsHTTPResponse* i_pResp);
nsresult GetResponseContext(nsISupports** aContext);
nsresult SetContentLength(PRInt32 aContentLength);
nsresult SetContentType(const char* aContentType);
nsresult SetCharset(const char *aCharset);
nsresult OnHeadersAvailable();
@ -107,7 +106,6 @@ protected:
nsCOMPtr<nsIURI> mURI;
PRBool mConnected;
HTTPState mState;
nsCString mVerb;
nsCOMPtr<nsIHTTPEventSink> mEventSink;
nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
@ -121,9 +119,6 @@ protected:
nsCOMPtr<nsISupports> mResponseContext;
nsCOMPtr<nsILoadGroup> mLoadGroup;
PRInt32 mContentLength;
nsCString mContentType;
nsCString mCharset;
nsCOMPtr<nsISupports> mOwner;
// Auth related stuff-

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

@ -20,6 +20,7 @@
* Contributor(s):
*/
#include "prlog.h"
#include "nsHTTPResponse.h"
#include "nsIInputStream.h"
#include "nsIURL.h"
@ -29,12 +30,19 @@
#include "nsXPIDLString.h"
#include "nsHTTPAtoms.h"
#if defined(PR_LOGGING)
extern PRLogModuleInfo* gHTTPLog;
#endif /* PR_LOGGING */
nsHTTPResponse::nsHTTPResponse()
{
NS_INIT_REFCNT();
mStatus = 0;
mServerVersion = HTTP_ONE_ZERO;
// The content length is unknown...
mContentLength = -1;
}
nsHTTPResponse::~nsHTTPResponse()
@ -44,25 +52,72 @@ nsHTTPResponse::~nsHTTPResponse()
NS_IMPL_ISUPPORTS(nsHTTPResponse, NS_GET_IID(nsISupports))
nsresult nsHTTPResponse::GetContentLength(PRInt32* o_Value)
nsresult nsHTTPResponse::GetCharset(char* *o_Charset)
{
nsresult rv = NS_OK;
if (o_Value) {
PRInt32 err;
nsXPIDLCString value;
nsAutoString str;
NS_ENSURE_ARG_POINTER(o_Charset);
// Check if status header has been parsed yet
if (mCharset.Length() == 0)
return NS_ERROR_NOT_AVAILABLE;
*o_Charset = mCharset.ToNewCString();
if (!*o_Charset)
rv = NS_ERROR_OUT_OF_MEMORY;
mHeaders.GetHeader(nsHTTPAtoms::Content_Length, getter_Copies(value));
str = value;
*o_Value = str.ToInteger(&err);
}
else {
rv = NS_ERROR_NULL_POINTER;
}
return rv;
}
nsresult nsHTTPResponse::SetCharset(const char* i_Charset)
{
mCharset = i_Charset;
return NS_OK;
}
nsresult nsHTTPResponse::GetContentType(char* *o_ContentType)
{
nsresult rv = NS_OK;
NS_ENSURE_ARG_POINTER(o_ContentType);
// Check if status header has been parsed yet
if (mContentType.Length() == 0)
return NS_ERROR_NOT_AVAILABLE;
*o_ContentType = mContentType.ToNewCString();
if (!*o_ContentType)
rv = NS_ERROR_OUT_OF_MEMORY;
return rv;
}
nsresult nsHTTPResponse::SetContentType(const char* i_ContentType)
{
nsCAutoString cType(i_ContentType);
cType.ToLowerCase();
mContentType = cType.GetBuffer();
return NS_OK;
}
nsresult nsHTTPResponse::GetContentLength(PRInt32* o_ContentLength)
{
NS_ENSURE_ARG_POINTER(o_ContentLength);
// Check if content-length header was received yet
if (mContentLength == -1)
return NS_ERROR_NOT_AVAILABLE;
*o_ContentLength = mContentLength;
return NS_OK;
}
nsresult nsHTTPResponse::SetContentLength(PRInt32 i_ContentLength)
{
mContentLength = i_ContentLength;
return NS_OK;
}
nsresult nsHTTPResponse::GetStatus(PRUint32* o_Value)
{
nsresult rv = NS_OK;
@ -128,3 +183,172 @@ nsresult nsHTTPResponse::GetHeaderEnumerator(nsISimpleEnumerator** aResult)
{
return mHeaders.GetEnumerator(aResult);
}
nsresult nsHTTPResponse::ParseStatusLine(nsCString& aStatusLine)
{
//
// The Status Line has the following: format:
// HTTP-Version SP Status-Code SP Reason-Phrase CRLF
//
const char *token;
nsCAutoString str;
PRInt32 offset, error;
//
// Parse the HTTP-Version:: "HTTP" "/" 1*DIGIT "." 1*DIGIT
//
offset = aStatusLine.FindChar(' ');
(void) aStatusLine.Left(str, offset);
if (!str.Length()) {
// The status line is bogus...
return NS_ERROR_FAILURE;
}
token = str.GetBuffer();
SetServerVersion(token);
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("\tParseStatusLine [this=%x].\tHTTP-Version: %s\n",
this, token));
aStatusLine.Cut(0, offset+1);
//
// Parse the Status-Code:: 3DIGIT
//
PRInt32 statusCode;
offset = aStatusLine.FindChar(' ');
(void) aStatusLine.Left(str, offset);
if (3 != str.Length()) {
// The status line is bogus...
return NS_ERROR_FAILURE;
}
statusCode = str.ToInteger(&error);
if (NS_FAILED(error)) return NS_ERROR_FAILURE;
SetStatus(statusCode);
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("\tParseStatusLine [this=%x].\tStatus-Code: %d\n",
this, statusCode));
aStatusLine.Cut(0, offset+1);
//
// Parse the Reason-Phrase:: *<TEXT excluding CR,LF>
//
token = aStatusLine.GetBuffer();
SetStatusString(token);
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("\tParseStatusLine [this=%x].\tReason-Phrase: %s\n",
this, token));
aStatusLine.Truncate();
return NS_OK;
}
nsresult nsHTTPResponse::ParseHeader(nsCString& aHeaderString)
{
nsresult rv;
//
// Extract the key field - everything up to the ':'
// The header name is case-insensitive...
//
PRInt32 colonOffset;
nsCAutoString headerKey;
nsCOMPtr<nsIAtom> headerAtom;
colonOffset = aHeaderString.FindChar(':');
if (kNotFound == colonOffset) {
//
// The header is malformed... Just clear it.
//
aHeaderString.Truncate();
return NS_ERROR_FAILURE;
}
(void) aHeaderString.Left(headerKey, colonOffset);
headerKey.ToLowerCase();
//
// Extract the value field - everything past the ':'
// Trim any leading or trailing whitespace...
//
aHeaderString.Cut(0, colonOffset+1);
aHeaderString.Trim(" ");
headerAtom = NS_NewAtom(headerKey.GetBuffer());
if (headerAtom) {
rv = ProcessHeader(headerAtom, aHeaderString);
} else {
rv = NS_ERROR_OUT_OF_MEMORY;
}
aHeaderString.Truncate();
return rv;
}
nsresult nsHTTPResponse::ProcessHeader(nsIAtom* aHeader, nsCString& aValue)
{
nsresult rv;
//
// When the Content-Type response header is processed, the Content-Type
// and Charset information must be set into the nsHTTPChannel...
//
if (nsHTTPAtoms::Content_Type == aHeader) {
nsCAutoString buffer;
PRInt32 semicolon;
// Set the content-type in the HTTPChannel...
semicolon = aValue.FindChar(';');
if (kNotFound != semicolon) {
aValue.Left(buffer, semicolon);
SetContentType(buffer.GetBuffer());
// Does the Content-Type contain a charset attribute?
aValue.Mid(buffer, semicolon+1, -1);
buffer.Trim(" ");
if (0 == buffer.Find("charset=", PR_TRUE)) {
//
// Set the charset in the HTTPChannel...
//
// XXX: Currently, the charset is *everything* past the "charset="
// This includes comments :-(
//
buffer.Cut(0, 8);
SetCharset(buffer.GetBuffer());
}
}
else {
SetContentType(aValue.GetBuffer());
}
}
//
// When the Content-Length response header is processed, set the
// ContentLength in the Channel...
//
else if (nsHTTPAtoms::Content_Length == aHeader) {
PRInt32 length, status;
length = aValue.ToInteger(&status);
rv = (nsresult)status;
if (NS_SUCCEEDED(rv)) {
SetContentLength(length);
}
}
//
// Set the response header...
//
rv = SetHeader(aHeader, aValue.GetBuffer());
return rv;
}

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

@ -52,7 +52,12 @@ public:
// Finally our own methods...
nsresult GetContentType(char* *o_ContentType);
nsresult SetContentType(const char* i_ContentType);
nsresult GetCharset(char* *o_Charset);
nsresult SetCharset(const char* i_Charset);
nsresult GetContentLength(PRInt32* o_Value);
nsresult SetContentLength(PRInt32 i_Value);
nsresult GetStatus(PRUint32* o_Value);
nsresult GetStatusString(char* *o_String);
nsresult GetServer(char* *o_String);
@ -65,12 +70,19 @@ public:
nsresult SetStatus(PRInt32 i_Value) { mStatus = i_Value; return NS_OK;};
nsresult SetStatusString(const char* i_Value);
nsresult ParseStatusLine(nsCString& aStatusLine);
nsresult ParseHeader(nsCString& aHeaderString);
nsresult ProcessHeader(nsIAtom* aHeader, nsCString& aValue);
protected:
virtual ~nsHTTPResponse();
HTTPVersion mServerVersion;
nsCString mStatusString;
nsCString mContentType;
nsCString mCharset;
PRUint32 mStatus;
PRInt32 mContentLength;
nsHTTPHeaderArray mHeaders;
};

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

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
@ -59,7 +59,9 @@ static const int kMAX_HEADER_SIZE = 60000;
nsHTTPResponseListener::nsHTTPResponseListener(nsHTTPChannel* aConnection):
mFirstLineParsed(PR_FALSE),
mHeadersDone(PR_FALSE),
mDataOnly(PR_FALSE),
mFiredOnHeadersAvailable(PR_FALSE),
mFiredOpenOnStartRequest(PR_FALSE),
mAsyncReadAfterAsyncOpen(PR_FALSE),
mReadLength(0),
mResponse(nsnull),
mResponseContext(nsnull),
@ -147,35 +149,21 @@ nsHTTPResponseListener::OnDataAvailable(nsIChannel* channel,
}
if (NS_FAILED(rv)) return rv;
// Don't do anything else until all headers have been parsed
if (!mHeadersDone)
return NS_OK;
//
// All the headers have been read.
//
// All the headers have been read. Check the status code of the
// response to see if any special action should be taken.
// We want to defer header completion notification until the
// caller actually does an AsyncRead();
if (mHeadersDone) {
if (mConnection->mOpenObserver) {
mConnection->mRawResponseListener = this;
rv = mConnection->mOpenObserver->OnStartRequest(mConnection,
mConnection->mOpenContext);
mDataStream = i_pStream;
} else {
rv = FinishedResponseHeaders();
}
if (NS_FAILED(rv)) return rv;
}
}
if (mDataOnly && mDataStream) {
// fire on headers *once* if we're in data only mode.
mDataStream = 0; // we're done w/ this stream.
rv = FinishedResponseHeaders();
if (NS_FAILED(rv)) return rv;
}
// At this point we've digested headers from the server and we're
// onto the actual data. If this transaction was initiated without
// an AsyncOpen, we just want to pass the OnData() notifications
// an AsyncRead, we just want to pass the OnData() notifications
// straight through to the consumer.
//
// .... otherwise...
@ -184,8 +172,9 @@ nsHTTPResponseListener::OnDataAvailable(nsIChannel* channel,
// so when we finally push the stream to the consumer via AsyncRead,
// we're sure to pass him all the data that has queued up.
if (mConnection->mOpenObserver && !mDataOnly) {
if (mConnection->mOpenObserver && !mAsyncReadAfterAsyncOpen) {
mBytesReceived += i_Length;
mDataStream = i_pStream;
} else {
//
@ -271,9 +260,8 @@ nsHTTPResponseListener::OnStopRequest(nsIChannel* channel,
mConnection->ResponseCompleted(channel, i_Status, i_pMsg);
}
if (mDataOnly) {
if (mConnection->mOpenObserver) {
// we're done processing the data
NS_ASSERTION(mConnection->mOpenObserver, "HTTP: HTTP should still have an observer.");
rv = mConnection->mOpenObserver->OnStopRequest(mConnection,
mConnection->mOpenContext,
i_Status, i_pMsg);
@ -295,11 +283,22 @@ nsHTTPResponseListener::OnStopRequest(nsIChannel* channel,
nsresult nsHTTPResponseListener::FireSingleOnData(nsIStreamListener *aListener, nsISupports *aContext)
{
nsresult rv;
mConsumer = aListener;
mResponseContext = aContext;
rv = mConsumer->OnDataAvailable(mConnection, mResponseContext,
mDataStream, 0, mBytesReceived);
mDataOnly = PR_TRUE;
if (mHeadersDone) {
rv = FinishedResponseHeaders();
if (NS_FAILED(rv)) return rv;
if (mBytesReceived) {
rv = mConsumer->OnDataAvailable(mConnection, mResponseContext,
mDataStream, 0, mBytesReceived);
}
mDataStream = 0;
}
mAsyncReadAfterAsyncOpen = PR_TRUE;
return rv;
}
@ -390,95 +389,12 @@ nsresult nsHTTPResponseListener::ParseStatusLine(nsIBufferInputStream* in,
mHeaderBuffer.CompressSet(" \t", ' ');
mHeaderBuffer.StripChars("\r\n");
//
// The Status Line has the following: format:
// HTTP-Version SP Status-Code SP Reason-Phrase CRLF
//
rv = mResponse->ParseStatusLine(mHeaderBuffer);
if (NS_FAILED(rv)) return rv;
const char *token;
nsCAutoString str;
PRInt32 offset, error;
//
// Parse the HTTP-Version:: "HTTP" "/" 1*DIGIT "." 1*DIGIT
//
offset = mHeaderBuffer.FindChar(' ');
(void) mHeaderBuffer.Left(str, offset);
if (!str.Length()) {
// The status line is bogus...
return NS_ERROR_FAILURE;
}
token = str.GetBuffer();
mResponse->SetServerVersion(token);
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("\tParseStatusLine [this=%x].\tHTTP-Version: %s\n",
this, token));
mHeaderBuffer.Cut(0, offset+1);
//
// Parse the Status-Code:: 3DIGIT
//
PRInt32 statusCode;
offset = mHeaderBuffer.FindChar(' ');
(void) mHeaderBuffer.Left(str, offset);
if (3 != str.Length()) {
// The status line is bogus...
return NS_ERROR_FAILURE;
}
statusCode = str.ToInteger(&error);
if (NS_FAILED(error)) return NS_ERROR_FAILURE;
mResponse->SetStatus(statusCode);
PRBool authAttempt = PR_FALSE;
mConnection->GetAuthTriedWithPrehost(&authAttempt);
if ( statusCode != 401 && authAttempt) {
// we know this auth challenge response wassuccessful. cache any authentication
// now so URLs within this body can use it.
nsAuthEngine* pEngine;
NS_ASSERTION(mConnection->mHandler, "HTTP handler went away");
if (NS_SUCCEEDED(mConnection->mHandler->GetAuthEngine(&pEngine)) )
{
nsXPIDLCString authString;
NS_ASSERTION(mConnection->mRequest, "HTTP request went away");
rv = mConnection->mRequest->GetHeader(nsHTTPAtoms::Authorization,
getter_Copies(authString));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIURI> luri;
rv = mConnection->GetURI(getter_AddRefs(luri));
if (NS_FAILED(rv)) return rv;
pEngine->SetAuthString(luri, authString);
}
}
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("\tParseStatusLine [this=%x].\tStatus-Code: %d\n",
this, statusCode));
mHeaderBuffer.Cut(0, offset+1);
//
// Parse the Reason-Phrase:: *<TEXT excluding CR,LF>
//
token = mHeaderBuffer.GetBuffer();
mResponse->SetStatusString(token);
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("\tParseStatusLine [this=%x].\tReason-Phrase: %s\n",
this, token));
mHeaderBuffer.Truncate();
mFirstLineParsed = PR_TRUE;
return rv;
return NS_OK;
}
@ -502,7 +418,7 @@ nsresult nsHTTPResponseListener::ParseHTTPHeader(nsIBufferInputStream* in,
//
// Read the header from the input buffer... A header is terminated by
// a CRLF. Header values may be extended over multiple lines by preceeding
// each extran line with LWS...
// each extra line with linear white space...
//
do {
//
@ -572,59 +488,42 @@ nsresult nsHTTPResponseListener::ParseHTTPHeader(nsIBufferInputStream* in,
mHeaderBuffer.CompressSet(" \t", ' ');
mHeaderBuffer.StripChars("\r\n");
if (!mHeaderBuffer.Length()) {
if (mHeaderBuffer.Length() == 0) {
mHeadersDone = PR_TRUE;
return NS_OK;
}
//
// Extract the key field - everything up to the ':'
// The header name is case-insensitive...
//
PRInt32 colonOffset;
nsCAutoString headerKey;
nsCOMPtr<nsIAtom> headerAtom;
colonOffset = mHeaderBuffer.FindChar(':');
if (kNotFound == colonOffset) {
//
// The header is malformed... Just clear it.
//
mHeaderBuffer.Truncate();
return NS_ERROR_FAILURE;
}
(void) mHeaderBuffer.Left(headerKey, colonOffset);
headerKey.ToLowerCase();
//
// Extract the value field - everything past the ':'
// Trim any leading or trailing whitespace...
//
mHeaderBuffer.Cut(0, colonOffset+1);
mHeaderBuffer.Trim(" ");
headerAtom = NS_NewAtom(headerKey.GetBuffer());
if (headerAtom) {
rv = ProcessHeader(headerAtom, mHeaderBuffer);
} else {
rv = NS_ERROR_OUT_OF_MEMORY;
}
mHeaderBuffer.Truncate();
return rv;
return mResponse->ParseHeader(mHeaderBuffer);
}
nsresult nsHTTPResponseListener::FinishedResponseHeaders(void)
{
nsresult rv = NS_OK;
nsresult rv;
if (mFiredOnHeadersAvailable)
return NS_OK;
rv = NS_OK;
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("nsHTTPResponseListener::FinishedResponseHeaders [this=%x].\n",
this));
if (mConnection->mOpenObserver && !mFiredOpenOnStartRequest) {
mConnection->mRawResponseListener = this;
rv = mConnection->mOpenObserver->OnStartRequest(mConnection,
mConnection->mOpenContext);
mFiredOpenOnStartRequest = PR_TRUE;
// We want to defer header completion notification until the
// caller actually does an AsyncRead();
if (!mAsyncReadAfterAsyncOpen)
return rv;
}
// Notify the consumer that headers are available...
FireOnHeadersAvailable();
mFiredOnHeadersAvailable = PR_TRUE;
//
// Check the status code to see if any special processing is necessary.
@ -649,68 +548,6 @@ nsresult nsHTTPResponseListener::FinishedResponseHeaders(void)
return rv;
}
nsresult nsHTTPResponseListener::ProcessHeader(nsIAtom* aHeader,
nsCString& aValue)
{
nsresult rv;
//
// When the Content-Type response header is processed, the Content-Type
// and Charset information must be set into the nsHTTPChannel...
//
if (nsHTTPAtoms::Content_Type == aHeader) {
nsCAutoString buffer;
PRInt32 semicolon;
// Set the content-type in the HTTPChannel...
semicolon = aValue.FindChar(';');
if (kNotFound != semicolon) {
aValue.Left(buffer, semicolon);
mConnection->SetContentType(buffer.GetBuffer());
// Does the Content-Type contain a charset attribute?
aValue.Mid(buffer, semicolon+1, -1);
buffer.Trim(" ");
if (0 == buffer.Find("charset=", PR_TRUE)) {
//
// Set the charset in the HTTPChannel...
//
// XXX: Currently, the charset is *everything* past the "charset="
// This includes comments :-(
//
buffer.Cut(0, 8);
mConnection->SetCharset(buffer.GetBuffer());
}
}
else {
mConnection->SetContentType(aValue.GetBuffer());
}
}
//
// When the Content-Length response header is processed, set the
// ContentLength in the Channel...
//
else if (nsHTTPAtoms::Content_Length == aHeader) {
PRInt32 length, status;
length = aValue.ToInteger(&status);
rv = (nsresult)status;
if (NS_SUCCEEDED(rv)) {
mConnection->SetContentLength(length);
}
}
//
// Set the response header...
//
rv = mResponse->SetHeader(aHeader, aValue.GetBuffer());
return rv;
}
nsresult nsHTTPResponseListener::ProcessStatusCode(void)
{
nsresult rv = NS_OK;
@ -718,8 +555,32 @@ nsresult nsHTTPResponseListener::ProcessStatusCode(void)
statusCode = 0;
rv = mResponse->GetStatus(&statusCode);
statusClass = statusCode / 100;
PRBool authAttempt = PR_FALSE;
mConnection->GetAuthTriedWithPrehost(&authAttempt);
if ( statusCode != 401 && authAttempt) {
// we know this auth challenge response was successful. cache any authentication
// now so URLs within this body can use it.
nsAuthEngine* pEngine;
NS_ASSERTION(mConnection->mHandler, "HTTP handler went away");
if (NS_SUCCEEDED(mConnection->mHandler->GetAuthEngine(&pEngine)) )
{
nsXPIDLCString authString;
NS_ASSERTION(mConnection->mRequest, "HTTP request went away");
rv = mConnection->mRequest->GetHeader(nsHTTPAtoms::Authorization,
getter_Copies(authString));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIURI> luri;
rv = mConnection->GetURI(getter_AddRefs(luri));
if (NS_FAILED(rv)) return rv;
pEngine->SetAuthString(luri, authString);
}
}
statusClass = statusCode / 100;
switch (statusClass) {
//

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

@ -23,7 +23,6 @@
#ifndef _nsHTTPResponseListener_h_
#define _nsHTTPResponseListener_h_
#define NSPIPE2
#include "nsIChannel.h"
#include "nsIStreamListener.h"
@ -31,11 +30,7 @@
#include "nsCOMPtr.h"
#include "nsIInputStream.h"
#ifndef NSPIPE2
class nsIBuffer;
#else
class nsIBufferInputStream;
#endif
class nsHTTPResponse;
class nsHTTPChannel;
@ -73,23 +68,15 @@ protected:
// nsHTTPResponseListener methods...
nsresult FireOnHeadersAvailable();
#ifndef NSPIPE2
nsresult ParseStatusLine(nsIBuffer* aBuffer, PRUint32 aLength,
PRUint32 *aBytesRead);
nsresult ParseHTTPHeader(nsIBuffer* aBuffer, PRUint32 aLength,
PRUint32* aBytesRead);
#else
nsresult ParseStatusLine(nsIBufferInputStream* in, PRUint32 aLength,
PRUint32 *aBytesRead);
nsresult ParseHTTPHeader(nsIBufferInputStream* in, PRUint32 aLength,
PRUint32* aBytesRead);
#endif
nsresult FinishedResponseHeaders();
nsresult ProcessHeader(nsIAtom* aHeader, nsCString& aValue);
nsresult ProcessHeader(nsIAtom* aHeader, nsCString& aValue, nsHTTPResponse& aResponse);
nsresult ProcessStatusCode();
nsresult ProcessRedirection(PRInt32 aStatusCode);
nsresult ProcessAuthentication(PRInt32 aStatusCode);
@ -101,7 +88,9 @@ protected:
nsCOMPtr<nsIStreamListener> mConsumer;
PRBool mFirstLineParsed;
PRBool mHeadersDone;
PRBool mDataOnly; // we're only listening for data
PRBool mAsyncReadAfterAsyncOpen; // we're only listening for data
PRBool mFiredOnHeadersAvailable; // Called OnHeadersAvailable()
PRBool mFiredOpenOnStartRequest; // Called mOpenObserver->OnStartRequest
PRUint32 mReadLength; // Already read
nsHTTPResponse* mResponse;
nsCOMPtr<nsISupports> mResponseContext;