diff --git a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp index c77a74a0ef4..a5a4627350f 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -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 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 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 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 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)); diff --git a/mozilla/netwerk/protocol/http/src/nsHttpChannel.h b/mozilla/netwerk/protocol/http/src/nsHttpChannel.h index 69395108746..bf3b513803b 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpChannel.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpChannel.h @@ -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(); diff --git a/mozilla/netwerk/protocol/http/src/nsHttpHeaderArray.cpp b/mozilla/netwerk/protocol/http/src/nsHttpHeaderArray.cpp index ea8308f715f..706e7b3841a 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpHeaderArray.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpHeaderArray.cpp @@ -25,7 +25,7 @@ #include "nsHttp.h" //----------------------------------------------------------------------------- -// nsHttpHeaderArray +// nsHttpHeaderArray //----------------------------------------------------------------------------- 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 +//----------------------------------------------------------------------------- + PRInt32 nsHttpHeaderArray::LookupEntry(nsHttpAtom header, nsEntry **entry) { diff --git a/mozilla/netwerk/protocol/http/src/nsHttpHeaderArray.h b/mozilla/netwerk/protocol/http/src/nsHttpHeaderArray.h index 600698d007f..9096c700a33 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpHeaderArray.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpHeaderArray.h @@ -45,6 +45,10 @@ public: nsresult Flatten(nsACString &); + PRUint32 Count() { return (PRUint32) mHeaders.Count(); } + + const char *PeekHeaderAt(PRUint32 i, nsHttpAtom &header); + private: struct nsEntry { diff --git a/mozilla/netwerk/protocol/http/src/nsHttpResponseHead.cpp b/mozilla/netwerk/protocol/http/src/nsHttpResponseHead.cpp index 646da971f02..b2d67b23ac7 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpResponseHead.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpResponseHead.cpp @@ -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 //----------------------------------------------------------------------------- diff --git a/mozilla/netwerk/protocol/http/src/nsHttpResponseHead.h b/mozilla/netwerk/protocol/http/src/nsHttpResponseHead.h index 17c63fea639..7073f88b41a 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpResponseHead.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpResponseHead.h @@ -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 *);