304 support
git-svn-id: svn://10.0.0.236/branches/HttpConnectionMagic_20010415_BRANCH@94090 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -270,6 +270,40 @@ nsHttpChannel::SetupTransaction()
|
||||
return mTransaction->SetupRequest(&mRequestHead, mUploadStream);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ApplyContentConversions()
|
||||
{
|
||||
LOG(("nsHttpChannel::ApplyContentConversions [this=%x]\n", this));
|
||||
|
||||
if (!mApplyConversion) {
|
||||
LOG(("not applying conversion per mApplyConversion\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const char *val = mResponseHead->PeekHeader(nsHttp::Content_Encoding);
|
||||
if (val) {
|
||||
nsCOMPtr<nsIStreamConverterService> serv;
|
||||
nsresult rv = nsHttpHandler::get()->
|
||||
GetStreamConverterService(getter_AddRefs(serv));
|
||||
// we won't fail to load the page just because we couldn't load the
|
||||
// stream converter service.. carry on..
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIStreamListener> converter;
|
||||
nsAutoString from = NS_ConvertASCIItoUCS2(val);
|
||||
rv = serv->AsyncConvertData(from.get(),
|
||||
NS_LITERAL_STRING("uncompressed").get(),
|
||||
mListener,
|
||||
mListenerContext,
|
||||
getter_AddRefs(converter));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
LOG(("converter installed from \'%s\' to \'uncompressed\'\n", val));
|
||||
mListener = converter;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ProcessResponse()
|
||||
{
|
||||
@@ -303,7 +337,6 @@ nsHttpChannel::ProcessResponse()
|
||||
rv = ProcessNormal();
|
||||
break;
|
||||
case 304:
|
||||
CloseCacheEntry(NS_ERROR_ABORT);
|
||||
rv = ProcessNotModified();
|
||||
break;
|
||||
case 401:
|
||||
@@ -329,28 +362,8 @@ nsHttpChannel::ProcessNormal()
|
||||
|
||||
LOG(("nsHttpChannel::ProcessNormal [this=%x]\n", this));
|
||||
|
||||
// install stream converter(s) if required
|
||||
if (mApplyConversion) {
|
||||
const char *val = mResponseHead->PeekHeader(nsHttp::Content_Encoding);
|
||||
if (val) {
|
||||
nsCOMPtr<nsIStreamConverterService> serv;
|
||||
rv = nsHttpHandler::get()->
|
||||
GetStreamConverterService(getter_AddRefs(serv));
|
||||
// we won't fail to load the page just because we couldn't load the
|
||||
// stream converter service.. carry on..
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIStreamListener> converter;
|
||||
nsAutoString from = NS_ConvertASCIItoUCS2(val);
|
||||
rv = serv->AsyncConvertData(from.get(),
|
||||
NS_LITERAL_STRING("uncompressed").get(),
|
||||
mListener,
|
||||
mListenerContext,
|
||||
getter_AddRefs(converter));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mListener = converter;
|
||||
}
|
||||
}
|
||||
}
|
||||
// install stream converter if required
|
||||
ApplyContentConversions();
|
||||
|
||||
// install cache listener if we still have a cache entry open
|
||||
if (mCacheEntry) {
|
||||
@@ -358,6 +371,9 @@ nsHttpChannel::ProcessNormal()
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// notify nsIHttpNotify implementations
|
||||
nsHttpHandler::get()->OnExamineResponse(this);
|
||||
|
||||
return mListener->OnStartRequest(this, mListenerContext);
|
||||
}
|
||||
|
||||
@@ -368,8 +384,45 @@ nsHttpChannel::ProcessNormal()
|
||||
nsresult
|
||||
nsHttpChannel::ProcessNotModified()
|
||||
{
|
||||
NS_NOTREACHED("not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
nsresult rv;
|
||||
|
||||
LOG(("nsHttpChannel::ProcessNotModified [this=%x]\n", this));
|
||||
|
||||
NS_ENSURE_TRUE(mCachedResponseHead, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
// merge any new headers with the cached response headers
|
||||
rv = mCachedResponseHead->UpdateHeaders(mResponseHead->Headers());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// update the cached response headers
|
||||
nsCAutoString headers;
|
||||
rv = mCachedResponseHead->Flatten(headers);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mCacheEntry->SetMetaDataElement("http-headers", headers.get());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// make the cached response be the current response
|
||||
delete mResponseHead;
|
||||
mResponseHead = mCachedResponseHead;
|
||||
mCachedResponseHead = 0;
|
||||
|
||||
rv = UpdateExpirationTime();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// drop our reference to the current transaction... ie. let it finish
|
||||
// in the background.
|
||||
// XXX we shouldn't have to cancel the transaction
|
||||
mTransaction->Cancel(NS_BINDING_ABORTED);
|
||||
NS_RELEASE(mTransaction);
|
||||
mTransaction = 0;
|
||||
|
||||
// notify nsIHttpNotify implementations as response headers may have changed
|
||||
nsHttpHandler::get()->OnExamineResponse(this);
|
||||
|
||||
mCachedContentIsValid = PR_TRUE;
|
||||
return ReadFromCache();
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -705,6 +758,15 @@ nsHttpChannel::ReadFromCache()
|
||||
LOG(("nsHttpChannel::ReadFromCache [this=%x] "
|
||||
"Using cached copy of: %s\n", this, mSpec.get()));
|
||||
|
||||
if (mCachedResponseHead) {
|
||||
NS_ASSERTION(!mResponseHead, "memory leak");
|
||||
mResponseHead = mCachedResponseHead;
|
||||
mCachedResponseHead = 0;
|
||||
}
|
||||
|
||||
// install stream converter if required
|
||||
ApplyContentConversions();
|
||||
|
||||
if (mCacheAccess & nsICache::ACCESS_WRITE) {
|
||||
// We have write access to the cache, but we don't need to go to the
|
||||
// server to validate at this time, so just mark the cache entry as
|
||||
@@ -734,6 +796,11 @@ nsHttpChannel::CloseCacheEntry(nsresult status)
|
||||
rv = mCacheEntry->Doom();
|
||||
}
|
||||
|
||||
if (mCachedResponseHead) {
|
||||
delete mCachedResponseHead;
|
||||
mCachedResponseHead = 0;
|
||||
}
|
||||
|
||||
mCacheReadRequest = 0;
|
||||
mCacheTransport = 0;
|
||||
mCacheEntry = 0;
|
||||
@@ -841,6 +908,9 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
|
||||
if (!location)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// notify nsIHttpNotify implementations before this channel goes away
|
||||
nsHttpHandler::get()->OnExamineResponse(this);
|
||||
|
||||
LOG(("redirecting to: %s\n", location));
|
||||
|
||||
nsresult rv;
|
||||
@@ -1764,21 +1834,14 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||
|
||||
LOG(("nsHttpChannel::OnStartRequest [this=%x]\n", this));
|
||||
|
||||
// all of the response headers have been acquired, so we can take ownership
|
||||
// of them from the transaction.
|
||||
if (mTransaction)
|
||||
if (mTransaction) {
|
||||
// all of the response headers have been acquired, so we can take ownership
|
||||
// of them from the transaction.
|
||||
mResponseHead = mTransaction->TakeResponseHead();
|
||||
else {
|
||||
NS_ASSERTION(!mResponseHead, "memory leak");
|
||||
mResponseHead = mCachedResponseHead;
|
||||
mCachedResponseHead = 0;
|
||||
}
|
||||
|
||||
if (mResponseHead && mTransaction) {
|
||||
// notify nsIHttpNotify implementations
|
||||
nsHttpHandler::get()->OnExamineResponse(this);
|
||||
|
||||
return ProcessResponse();
|
||||
// the response head may be null if the transaction was cancelled. in
|
||||
// which case we just need to call OnStartRequest/OnStopRequest.
|
||||
if (mResponseHead)
|
||||
return ProcessResponse();
|
||||
}
|
||||
|
||||
// there won't be a response head if we've been cancelled
|
||||
@@ -1829,8 +1892,10 @@ nsHttpChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||
{
|
||||
// if the request is for something we no longer reference, then simply
|
||||
// drop this event.
|
||||
if ((request != mTransaction) && (request != mCacheReadRequest))
|
||||
return NS_OK;
|
||||
if ((request != mTransaction) && (request != mCacheReadRequest)) {
|
||||
NS_WARNING("got stale request... why wasn't it cancelled?");
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
LOG(("nsHttpChannel::OnDataAvailable [this=%x offset=%u count=%u]\n",
|
||||
this, offset, count));
|
||||
|
||||
@@ -81,7 +81,7 @@ private:
|
||||
nsresult Connect(PRBool firstTime = PR_TRUE);
|
||||
nsresult AsyncAbort(nsresult status);
|
||||
nsresult SetupTransaction();
|
||||
nsresult BuildConnectionInfo(nsHttpConnectionInfo **);
|
||||
nsresult ApplyContentConversions();
|
||||
nsresult ProcessResponse();
|
||||
nsresult ProcessNormal();
|
||||
nsresult ProcessNotModified();
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "nsHttp.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpHeaderArray
|
||||
// nsHttpHeaderArray <public>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
@@ -120,6 +120,21 @@ nsHttpHeaderArray::Flatten(nsACString &buf)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const char *
|
||||
nsHttpHeaderArray::PeekHeaderAt(PRUint32 index, nsHttpAtom &header)
|
||||
{
|
||||
nsEntry *entry = (nsEntry *) mHeaders[index];
|
||||
if (!entry)
|
||||
return nsnull;
|
||||
|
||||
header = entry->header;
|
||||
return entry->value.get();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpHeaderArray <private>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PRInt32
|
||||
nsHttpHeaderArray::LookupEntry(nsHttpAtom header, nsEntry **entry)
|
||||
{
|
||||
|
||||
@@ -45,6 +45,10 @@ public:
|
||||
|
||||
nsresult Flatten(nsACString &);
|
||||
|
||||
PRUint32 Count() { return (PRUint32) mHeaders.Count(); }
|
||||
|
||||
const char *PeekHeaderAt(PRUint32 i, nsHttpAtom &header);
|
||||
|
||||
private:
|
||||
struct nsEntry
|
||||
{
|
||||
|
||||
@@ -264,6 +264,59 @@ nsHttpResponseHead::ComputeFreshnessLifetime(PRUint32 *result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpResponseHead::UpdateHeaders(nsHttpHeaderArray &headers)
|
||||
{
|
||||
LOG(("nsHttpResponseHead::UpdateHeaders [this=%x]\n", this));
|
||||
|
||||
PRUint32 i, count = headers.Count();
|
||||
for (i=0; i<count; ++i) {
|
||||
nsHttpAtom header;
|
||||
const char *val = headers.PeekHeaderAt(i, header);
|
||||
|
||||
if (!val) {
|
||||
NS_NOTREACHED("null header value");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore any hop-by-hop headers...
|
||||
if (header == nsHttp::Connection ||
|
||||
header == nsHttp::Keep_Alive ||
|
||||
header == nsHttp::Proxy_Authenticate ||
|
||||
header == nsHttp::Proxy_Authorization || // not a response header!
|
||||
header == nsHttp::TE ||
|
||||
header == nsHttp::Trailer ||
|
||||
header == nsHttp::Transfer_Encoding ||
|
||||
header == nsHttp::Upgrade ||
|
||||
// Ignore any non-modifiable headers...
|
||||
header == nsHttp::Content_Location ||
|
||||
header == nsHttp::Content_MD5 ||
|
||||
header == nsHttp::ETag ||
|
||||
header == nsHttp::Last_Modified ||
|
||||
// Assume Cache-Control: "no-transform"
|
||||
header == nsHttp::Content_Encoding ||
|
||||
header == nsHttp::Content_Range ||
|
||||
header == nsHttp::Content_Type ||
|
||||
// Ignore wacky headers too...
|
||||
// this one is for MS servers that send "Content-Length: 0"
|
||||
// on 304 responses
|
||||
header == nsHttp::Content_Length) {
|
||||
LOG(("ignoring response header [%s: %s]\n", header.get(), val));
|
||||
}
|
||||
else {
|
||||
LOG(("new response header [%s: %s]\n", header.get(), val));
|
||||
|
||||
// delete the current header value (if any)
|
||||
mHeaders.SetHeader(header, nsnull);
|
||||
|
||||
// copy the new header value...
|
||||
mHeaders.SetHeader(header, val);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpResponseHead <private>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -67,6 +67,9 @@ public:
|
||||
nsresult ComputeFreshnessLifetime(PRUint32 *);
|
||||
nsresult ComputeCurrentAge(PRUint32 now, PRUint32 requestTime, PRUint32 *result);
|
||||
|
||||
// update headers...
|
||||
nsresult UpdateHeaders(nsHttpHeaderArray &headers);
|
||||
|
||||
private:
|
||||
nsresult ParseVersion(const char *);
|
||||
nsresult ParseContentType(char *);
|
||||
|
||||
Reference in New Issue
Block a user