From 9deb4986e3d90b58f4bda0d6c19d421f8b35c9a9 Mon Sep 17 00:00:00 2001 From: "darin%netscape.com" Date: Sat, 14 Apr 2001 02:02:19 +0000 Subject: [PATCH] Patch to finalize necko loadFlags and fix HTTP validation correctness w.r.t. cache validation preferences and browsing via history. r=gagan,gordon. Fixes several bugs that I would mention here if bugzilla weren't down ;-) --- docshell/base/nsDSURIContentListener.cpp | 4 +- docshell/base/nsDocShell.cpp | 28 +- gfx/src/nsImageNetContextAsync.cpp | 6 +- modules/libpr0n/src/imgLoader.cpp | 4 +- modules/libpr0n/src/imgRequest.cpp | 7 +- modules/libpr0n/src/imgRequestProxy.cpp | 3 +- netwerk/base/public/nsIChannel.idl | 28 +- netwerk/base/public/nsIRequest.idl | 97 ++--- netwerk/base/src/nsLoadGroup.cpp | 44 +-- netwerk/protocol/http/src/nsHTTPChannel.cpp | 352 +++++++----------- netwerk/protocol/http/src/nsHTTPChannel.h | 2 - netwerk/protocol/http/src/nsHTTPHandler.cpp | 2 +- netwerk/protocol/http/src/nsHTTPHandler.h | 4 +- netwerk/protocol/http/src/nsHTTPRequest.cpp | 17 +- netwerk/protocol/http/src/nsHTTPRequest.h | 4 +- netwerk/protocol/http/src/nsHTTPResponse.cpp | 112 +++++- netwerk/protocol/http/src/nsHTTPResponse.h | 2 + .../http/src/nsHTTPResponseListener.cpp | 11 +- .../converters/nsMultiMixedConv.cpp | 2 +- uriloader/base/nsDocLoader.cpp | 4 +- uriloader/base/nsURILoader.cpp | 2 +- .../bookmarks/src/nsBookmarksService.cpp | 2 +- .../resources/content/pref-cache.xul | 3 +- .../resources/locale/en-US/pref-cache.dtd | 2 + .../search/src/nsInternetSearchService.cpp | 4 +- xpfe/components/xfer/src/nsStreamTransfer.cpp | 4 +- 26 files changed, 394 insertions(+), 356 deletions(-) diff --git a/docshell/base/nsDSURIContentListener.cpp b/docshell/base/nsDSURIContentListener.cpp index 5e27fd3d3dfe..e30be6401830 100644 --- a/docshell/base/nsDSURIContentListener.cpp +++ b/docshell/base/nsDSURIContentListener.cpp @@ -98,7 +98,7 @@ NS_IMETHODIMP nsDSURIContentListener::DoContent(const char* aContentType, PRUint32 loadType = mDocShell->ConvertDocShellLoadInfoToLoadType((nsDocShellInfoLoadType) aCommand); mDocShell->SetLoadType(loadType); - if(loadFlags & nsIRequest::LOAD_RETARGETED_DOCUMENT_URI) + if(loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) { mDocShell->StopLoad(); } @@ -107,7 +107,7 @@ NS_IMETHODIMP nsDSURIContentListener::DoContent(const char* aContentType, request, aContentHandler); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; // it's okay if we don't know how to handle the content - if(loadFlags & nsIRequest::LOAD_RETARGETED_DOCUMENT_URI) + if(loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) mDocShell->SetFocus(); return NS_OK; diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index dfdbcd074c95..1fb55a778977 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -2847,7 +2847,7 @@ NS_IMETHODIMP nsDocShell::CreateContentViewer(const char* aContentType, // Mark the channel as being a document URI... aOpenedChannel->GetLoadFlags(&loadFlags); - loadFlags |= nsIRequest::LOAD_DOCUMENT_URI; + loadFlags |= nsIChannel::LOAD_DOCUMENT_URI; aOpenedChannel->SetLoadFlags(loadFlags); @@ -3592,34 +3592,32 @@ NS_IMETHODIMP nsDocShell::DoChannelLoad(nsIChannel *aChannel, nsURILoadCommand a // Mark the channel as being a document URI... nsLoadFlags loadFlags = 0; (void)aChannel->GetLoadFlags(&loadFlags); - loadFlags |= nsIRequest::LOAD_DOCUMENT_URI; + loadFlags |= nsIChannel::LOAD_DOCUMENT_URI; - // "View source" always wants VALIDATE_NEVER. + // "View source" always wants the currently cached content. if ( mViewMode == viewSource ) { - loadFlags |= nsIRequest::VALIDATE_NEVER; + loadFlags |= nsIRequest::LOAD_FROM_CACHE; } else { // Load attributes depend on load type... switch ( mLoadType ) { case LOAD_HISTORY: - loadFlags |= nsIRequest::VALIDATE_NEVER; + loadFlags |= nsIRequest::LOAD_FROM_CACHE; break; case LOAD_RELOAD_NORMAL: - loadFlags |= nsIRequest::FORCE_VALIDATION; + loadFlags |= nsIRequest::VALIDATE_ALWAYS; break; case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: - loadFlags |= nsIRequest::FORCE_RELOAD; - break; case LOAD_REFRESH: - loadFlags |= nsIRequest::FORCE_RELOAD; + loadFlags |= nsIRequest::LOAD_BYPASS_CACHE; break; case LOAD_NORMAL: case LOAD_LINK: - // Set cache checking flags - if ( mPrefs ) - { + // Set cache checking flags + if ( mPrefs ) + { PRInt32 prefSetting; if ( NS_SUCCEEDED( mPrefs->GetIntPref( "browser.cache.check_doc_frequency" , &prefSetting) ) ) { @@ -3636,8 +3634,8 @@ NS_IMETHODIMP nsDocShell::DoChannelLoad(nsIChannel *aChannel, nsURILoadCommand a break; } } - } - break; + } + break; } } @@ -3974,7 +3972,7 @@ NS_IMETHODIMP nsDocShell::OnLoadingSite(nsIChannel* aChannel) // overrides it. Until OnRedirect() gets settles out, let us do this. nsLoadFlags loadFlags = 0; aChannel->GetLoadFlags(&loadFlags); - if (loadFlags & nsIRequest::LOAD_REPLACE) + if (loadFlags & nsIChannel::LOAD_REPLACE) aChannel->GetURI(getter_AddRefs(uri)); else aChannel->GetOriginalURI(getter_AddRefs(uri)); diff --git a/gfx/src/nsImageNetContextAsync.cpp b/gfx/src/nsImageNetContextAsync.cpp index 5ac8f2f159cc..e5345d300b8f 100644 --- a/gfx/src/nsImageNetContextAsync.cpp +++ b/gfx/src/nsImageNetContextAsync.cpp @@ -763,7 +763,7 @@ ImageNetContextImpl::GetURL (ilIURL * aURL, nsLoadFlags flags=0; if(IsAnimationLoop) - flags |= nsIRequest::VALIDATE_NEVER; + flags |= nsIRequest::LOAD_FROM_CACHE; rv = NS_OpenURI(getter_AddRefs(channel), nsurl, nsnull, group, sink, flags); if (NS_FAILED(rv)) goto error; @@ -885,9 +885,9 @@ Need code to check freshness of necko cache. image_net_context_async_log_module = PR_NewLogModule("IMAGENETCTXASYNC"); } #endif - if((nsIRequest::FORCE_VALIDATION & defchan_attribs)|| + if((nsIRequest::VALIDATE_ALWAYS & defchan_attribs)|| (nsIRequest::INHIBIT_PERSISTENT_CACHING & defchan_attribs)|| - (nsIRequest::FORCE_RELOAD & defchan_attribs)) { + (nsIRequest::LOAD_BYPASS_CACHE & defchan_attribs)) { imglib_attribs = DONT_USE_IMG_CACHE; #if defined( DEBUG ) PR_LOG(image_net_context_async_log_module, 1, ("ImageNetContextAsync: NS_NewImageNetContext: DONT_USE_IMAGE_CACHE\n")); diff --git a/modules/libpr0n/src/imgLoader.cpp b/modules/libpr0n/src/imgLoader.cpp index 93a8c08fe6a4..e0bece7919c5 100644 --- a/modules/libpr0n/src/imgLoader.cpp +++ b/modules/libpr0n/src/imgLoader.cpp @@ -85,14 +85,14 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI, nsILoadGroup *aLoadGroup, imgID PRUint32 flags = 0; PRBool doomRequest = PR_FALSE; aLoadGroup->GetLoadFlags(&flags); - if (flags & nsIRequest::FORCE_RELOAD) + if (flags & nsIRequest::LOAD_BYPASS_CACHE) doomRequest = PR_TRUE; else { nsCOMPtr r; aLoadGroup->GetDefaultLoadRequest(getter_AddRefs(r)); if (r) { r->GetLoadFlags(&flags); - if (flags & nsIRequest::FORCE_RELOAD) + if (flags & nsIRequest::LOAD_BYPASS_CACHE) doomRequest = PR_TRUE; } } diff --git a/modules/libpr0n/src/imgRequest.cpp b/modules/libpr0n/src/imgRequest.cpp index 8cdf0dadfb9a..53428a82d67a 100644 --- a/modules/libpr0n/src/imgRequest.cpp +++ b/modules/libpr0n/src/imgRequest.cpp @@ -314,13 +314,12 @@ NS_IMETHODIMP imgRequest::SetLoadGroup(nsILoadGroup *loadGroup) /* attribute nsLoadFlags loadFlags */ NS_IMETHODIMP imgRequest::GetLoadFlags(nsLoadFlags *flags) { - NS_NOTYETIMPLEMENTED("imgRequest::GetLoadFlags"); - return NS_ERROR_NOT_IMPLEMENTED; + *flags = LOAD_NORMAL; + return NS_OK; } NS_IMETHODIMP imgRequest::SetLoadFlags(nsLoadFlags flags) { - NS_NOTYETIMPLEMENTED("imgRequest::SetLoadFlags"); - return NS_ERROR_NOT_IMPLEMENTED; + return NS_OK; } /** imgIRequest methods **/ diff --git a/modules/libpr0n/src/imgRequestProxy.cpp b/modules/libpr0n/src/imgRequestProxy.cpp index e27ca6948b45..4efced12bb62 100644 --- a/modules/libpr0n/src/imgRequestProxy.cpp +++ b/modules/libpr0n/src/imgRequestProxy.cpp @@ -180,8 +180,7 @@ NS_IMETHODIMP imgRequestProxy::GetLoadFlags(nsLoadFlags *flags) } NS_IMETHODIMP imgRequestProxy::SetLoadFlags(nsLoadFlags flags) { - NS_NOTYETIMPLEMENTED("imgRequestProxy::SetLoadFlags"); - return NS_ERROR_NOT_IMPLEMENTED; + return NS_OK; } /** imgIRequest methods **/ diff --git a/netwerk/base/public/nsIChannel.idl b/netwerk/base/public/nsIChannel.idl index c6f387304d51..5f1b1e759ed7 100644 --- a/netwerk/base/public/nsIChannel.idl +++ b/netwerk/base/public/nsIChannel.idl @@ -112,10 +112,32 @@ interface nsIChannel : nsIRequest void asyncOpen(in nsIStreamListener listener, in nsISupports ctxt); /************************************************************************** - * These flags are OBSOLETE and will be removed once the old cache is + * Channel specific load flags: + */ + + /** + * Used exclusively by the uriloader and docshell to indicate whether or + * not this request corresponds to the toplevel document. + */ + const unsigned long LOAD_DOCUMENT_URI = 1 << 16; + + /** + * If the end consumer for this load has been retargeted after discovering + * it's content, this flag will be set: + */ + const unsigned long LOAD_RETARGETED_DOCUMENT_URI = 1 << 17; + + /** + * This flag is set to indicate that onStopRequest may be followed by + * another onStartRequest/onStopRequest pair. This flag is, for example, + * used by the multipart/replace stream converter. + */ + const unsigned long LOAD_REPLACE = 1 << 18; + + /************************************************************************** + * This flag is OBSOLETE and will be removed once the old cache is * removed from the code base. Support for CACHE_AS_FILE is now provided * via nsICachingChannel. */ - const unsigned long CACHE_AS_FILE = 1 << 14; - const unsigned long VALIDATE_HEURISTICALLY = 1 << 15; + const unsigned long CACHE_AS_FILE = 1 << 19; }; diff --git a/netwerk/base/public/nsIRequest.idl b/netwerk/base/public/nsIRequest.idl index a74c67d804e4..b12e217ad06e 100644 --- a/netwerk/base/public/nsIRequest.idl +++ b/netwerk/base/public/nsIRequest.idl @@ -81,12 +81,14 @@ interface nsIRequest : nsISupports attribute nsILoadGroup loadGroup; /** - * Accesses the load flags for this request. + * Accesses the load flags for this request. Bits 0-15 are defined (or + * reserved) by nsIRequest. When added to a load group, this request's + * load flags are merged with the load flags of the load group. */ attribute nsLoadFlags loadFlags; /************************************************************************** - * Below are the various load flags which may be or'd together. + * Listed below are the various load flags which may be or'd together. */ /** @@ -96,67 +98,70 @@ interface nsIRequest : nsISupports /** * Don't deliver status notifications to the nsIProgressEventSink, or keep - * this load from completing the nsILoadGroup it may belong to: + * this load from completing the nsILoadGroup it may belong to. */ const unsigned long LOAD_BACKGROUND = 1 << 0; /************************************************************************** - * For requests that are channels, the following flags may apply. + * The following flags control the flow of data into the cache. */ /** - * Used exclusively by the uriloader and docshell to indicate whether or - * not this request corresponds to the toplevel document. + * This flag prevents caching of any kind. It does not, however, prevent + * cached content from being used to satisfy this request. */ - const unsigned long LOAD_DOCUMENT_URI = 1 << 1; + const unsigned long INHIBIT_CACHING = 1 << 7; - /** - * If the end consumer for this load has been retargeted after discovering - * it's content, this flag will be set: - */ - const unsigned long LOAD_RETARGETED_DOCUMENT_URI = 1 << 2; - - /** - * This flag is used to tell the webshell not to cancel the load in cases - * when the request is receiving multipart/replace document - */ - const unsigned long LOAD_REPLACE = 1 << 3; - - /************************************************************************** - * The following flags control caching behavior. With the exception of - * INHIBIT_PERSISTENT_CACHING, they are all mutually exclusive. - */ - - /* - * Don't store data in the disk cache. This can be used to preserve - * privacy, e.g. so that no https transactions are recorded, or to avoid - * caching a stream to disk that is already stored in a local file, - * e.g. the mailbox: protocol. + /** + * This flag prevents caching on disk (or other persistent media), which + * may be needed to preserve privacy. For HTTPS, this flag is set auto- + * matically. */ const unsigned long INHIBIT_PERSISTENT_CACHING = 1 << 8; - /** - * Force an end-to-end download of content data from the origin server (and - * any intervening proxies that sit between it and the client), e.g. this - * flag is used for a shift-reload. + /************************************************************************** + * The following flags control what happens when the cache contains data + * that could perhaps satisfy this request. They are listed in descending + * order of precidence. */ - const unsigned long FORCE_RELOAD = 1 << 9; /** - * Force revalidation with server (or proxy) to verify that cached content - * is up-to-date, e.g. by comparing last-modified date on server with that - * of the cached version. This flag is used when the reload button is - * pressed. + * Force an end-to-end download of content data from the origin server. + * This flag is used for a shift-reload. */ - const unsigned long FORCE_VALIDATION = 1 << 10; + const unsigned long LOAD_BYPASS_CACHE = 1 << 9; /** - * When cache data is potentially out of date, it can be revalidated with - * the origin server to see if the content needs to be reloaded. The - * following three flags control how often this validation occurs. - * These flags are commonly used for "normal" loading. + * Load from the cache, bypassing protocol specific validation logic. This + * flag is used when browsing via history. It is not recommended for normal + * browsing as it may likely violate reasonable assumptions made by the + * server and confuse users. */ - const unsigned long VALIDATE_NEVER = 1 << 11; - const unsigned long VALIDATE_ALWAYS = 1 << 12; - const unsigned long VALIDATE_ONCE_PER_SESSION = 1 << 13; + const unsigned long LOAD_FROM_CACHE = 1 << 10; + + /** + * The following flags control the frequency of cached content validation + * when neither LOAD_BYPASS_CACHE or LOAD_FROM_CACHE are set. By default, + * cached content is automatically validated if necessary before reuse. + * + * VALIDATE_ALWAYS forces validation of any cached content independent of + * its expiration time. + * + * VALIDATE_NEVER disables validation of expired content. + * + * VALIDATE_ONCE_PER_SESSION disables validation of expired content, + * provided it has already been validated (at least once) since the start + * of this session. + * + * NOTE TO IMPLEMENTORS: + * These flags are intended for normal browsing, and they should therefore + * not apply to content that must be validated before each use. Consider, + * for example, a HTTP response with a "Cache-control: no-cache" header. + * According to RFC2616, this response must be validated before it can + * be taken from a cache. Breaking this requirement could result in + * incorrect and potentially unpleasant side-effects. + */ + const unsigned long VALIDATE_ALWAYS = 1 << 11; + const unsigned long VALIDATE_NEVER = 1 << 12; + const unsigned long VALIDATE_ONCE_PER_SESSION = 1 << 13; }; diff --git a/netwerk/base/src/nsLoadGroup.cpp b/netwerk/base/src/nsLoadGroup.cpp index b24d36a07445..b832527b0dbd 100644 --- a/netwerk/base/src/nsLoadGroup.cpp +++ b/netwerk/base/src/nsLoadGroup.cpp @@ -54,8 +54,8 @@ PRLogModuleInfo* gLoadGroupLog = nsnull; //////////////////////////////////////////////////////////////////////////////// nsLoadGroup::nsLoadGroup(nsISupports* outer) - : mLoadFlags(LOAD_NORMAL) - , mForegroundCount(0) + : mForegroundCount(0) + , mLoadFlags(LOAD_NORMAL) , mRequests(nsnull) , mStatus(NS_OK) { @@ -377,6 +377,11 @@ NS_IMETHODIMP nsLoadGroup::SetDefaultLoadRequest(nsIRequest *aRequest) { mDefaultLoadRequest = aRequest; + // Inherit the group load flags from the default load request + if (mDefaultLoadRequest) + mDefaultLoadRequest->GetLoadFlags(&mLoadFlags); + else + mLoadFlags = LOAD_NORMAL; return NS_OK; } @@ -550,35 +555,14 @@ nsresult nsLoadGroup::MergeLoadFlags(nsIRequest *aRequest, nsLoadFlags& outFlags return rv; oldFlags = flags; - // - // Inherit the group cache validation policy - // - if ( !((nsIRequest::VALIDATE_NEVER | - nsIRequest::VALIDATE_ALWAYS | - nsIRequest::VALIDATE_ONCE_PER_SESSION) & flags) ) { - flags |= (nsIRequest::VALIDATE_NEVER | - nsIRequest::VALIDATE_ALWAYS | - nsIRequest::VALIDATE_ONCE_PER_SESSION) & mLoadFlags; - } - // - // Inherit the group reload policy - // - if (!(nsIRequest::FORCE_VALIDATION & flags)) - flags |= (nsIRequest::FORCE_VALIDATION & mLoadFlags); - if (!(nsIRequest::FORCE_RELOAD & flags)) - flags |= (nsIRequest::FORCE_RELOAD & mLoadFlags); - // - // Inherit the group persistent cache policy - // - if (!(nsIRequest::INHIBIT_PERSISTENT_CACHING & flags)) - flags |= (nsIRequest::INHIBIT_PERSISTENT_CACHING & mLoadFlags); - - // - // Inherit the group loading policy - // - if (!(nsIRequest::LOAD_BACKGROUND & flags)) - flags |= (nsIRequest::LOAD_BACKGROUND & mLoadFlags); + // Inherit the following bits... + flags |= (mLoadFlags & (LOAD_BACKGROUND | + LOAD_BYPASS_CACHE | + LOAD_FROM_CACHE | + VALIDATE_ALWAYS | + VALIDATE_ONCE_PER_SESSION | + VALIDATE_NEVER)); if (flags != oldFlags) rv = aRequest->SetLoadFlags(flags); diff --git a/netwerk/protocol/http/src/nsHTTPChannel.cpp b/netwerk/protocol/http/src/nsHTTPChannel.cpp index 2acceb98326f..7323fa52e638 100644 --- a/netwerk/protocol/http/src/nsHTTPChannel.cpp +++ b/netwerk/protocol/http/src/nsHTTPChannel.cpp @@ -866,7 +866,7 @@ nsHTTPChannel::OpenCacheEntry() accessRequested = nsICache::ACCESS_READ; mFromCacheOnly = PR_TRUE; } - else if (mLoadFlags & FORCE_RELOAD) + else if (mLoadFlags & LOAD_BYPASS_CACHE) accessRequested = nsICache::ACCESS_WRITE; // replace cache entry else if (mFromCacheOnly) accessRequested = nsICache::ACCESS_READ; // read from cache @@ -889,122 +889,16 @@ nsHTTPChannel::GenerateCacheKey(nsAWritableCString &cacheKey) cacheKey.Append(buf); cacheKey.Append("&url="); } + // Use the override request spec if set. + const char *spec = mRequest->OverrideRequestSpec(); + if (!spec) + spec = mRequest->Spec(); // Strip any trailing #ref from the URL before using it as the key - char *p = PL_strchr(mRequest->Spec(), '#'); + char *p = PL_strchr(spec, '#'); if (p) - cacheKey.Append(mRequest->Spec(), p - mRequest->Spec()); + cacheKey.Append(spec, p - spec); else - cacheKey.Append(mRequest->Spec()); - return NS_OK; -} - -// From section 13.2.3 of RFC2616, we compute the current age of a cached -// response as follows: -// -// currentAge = max(max(0, responseTime - dateValue), ageValue) -// + now - requestTime -// -// where responseTime == now -// -// This is typically a very small number. -// -nsresult -nsHTTPChannel::ComputeCurrentAge(PRUint32 now, - PRUint32 *result) -{ - NS_ENSURE_TRUE(mResponse, NS_ERROR_NOT_AVAILABLE); - - PRUint32 dateValue; - PRUint32 ageValue = 0; - PRBool avail = PR_FALSE; - nsresult rv; - - *result = 0; - - rv = mResponse->GetDateValue(&dateValue, &avail); - if (NS_FAILED(rv)) return rv; - - if (!avail) { - LOG(("nsHTTPChannel::ComputeAge [this=%x] Date response header not set!\n", this)); - // Assume we have a very fast connection !! - dateValue = now; - } - - rv = mResponse->GetAgeValue(&ageValue, &avail); - if (NS_FAILED(rv)) return rv; - - // Compute apparent age - if (now > dateValue) - *result = now - dateValue; - - // Compute corrected received age - if (avail) - *result = PR_MAX(*result, ageValue); - - NS_ASSERTION(now >= mRequestTime, "bogus request time"); - - // Compute current age - *result += (now - mRequestTime); - - return NS_OK; -} - -// From section 13.2.4 of RFC2616, we compute the freshness lifetime of a cached -// response as follows: -// -// freshnessLifetime = max_age_value -// -// freshnessLifetime = expires_value - date_value -// -// freshnessLifetime = (date - lastModified) * 0.10 -// -// freshnessLifetime = 0 -// -nsresult -nsHTTPChannel::ComputeFreshnessLifetime(PRUint32 *result) -{ - NS_ENSURE_ARG_POINTER(result); - NS_ENSURE_TRUE(mResponse, NS_ERROR_NOT_AVAILABLE); - - nsresult rv; - PRBool avail = PR_FALSE; - - *result = 0; - - // Try HTTP/1.1 style max-age directive... - rv = mResponse->GetMaxAge(result, &avail); - if (NS_FAILED(rv)) return rv; - if (avail) - return NS_OK; - - PRUint32 date, date2; - - rv = mResponse->GetDateValue(&date, &avail); - if (NS_FAILED(rv)) return rv; - if (avail) { - // Try HTTP/1.0 style expires header... - rv = mResponse->GetExpiresValue(&date2, &avail); - if (NS_FAILED(rv)) return rv; - if (avail) { - *result = date2 - date; - return NS_OK; - } - - // Fallback on heuristic using last modified header... - rv = mResponse->GetLastModifiedValue(&date2, &avail); - if (NS_FAILED(rv)) return rv; - if (avail) { - LOG(("using last-modified to determine freshness-lifetime\n")); - LOG(("last-modified = %u, date = %u\n", date2, date)); - *result = (date - date2) / 10; - return NS_OK; - } - } - - LOG(("nsHTTPChannel::ComputeFreshnessLifetime [this = %x] " - "Insufficient information to compute a non-zero freshness " - "lifetime!\n", this)); - + cacheKey.Append(spec); return NS_OK; } @@ -1024,10 +918,10 @@ nsHTTPChannel::UpdateExpirationTime() PRUint32 now = NowInSeconds(); PRUint32 freshnessLifetime, currentAge, timeRemaining = 0; - rv = ComputeCurrentAge(now, ¤tAge); + rv = mResponse->ComputeCurrentAge(now, mRequestTime, ¤tAge); if (NS_FAILED(rv)) return rv; - rv = ComputeFreshnessLifetime(&freshnessLifetime); + rv = mResponse->ComputeFreshnessLifetime(&freshnessLifetime); if (NS_FAILED(rv)) return rv; LOG(("freshnessLifetime = %u, currentAge = %u\n", @@ -1093,8 +987,6 @@ nsHTTPChannel::CheckCache() rv = mCacheEntry->GetDataSize(&size); if (NS_FAILED(rv)) return rv; - LOG(("Content-length=%d, CacheEntryDataSize=%u\n", contentLength, size)); - if (size != (PRUint32) contentLength) { LOG(("Cached data size does not match the Content-Length header " "[content-length=%u size=%u]\n", contentLength, size)); @@ -1103,44 +995,59 @@ nsHTTPChannel::CheckCache() } } - // If validation is inhibited, we'll just use whatever data is in - // the cache, regardless of whether or not it has expired. - if (mLoadFlags & nsIRequest::VALIDATE_NEVER) { - mCachedContentIsValid = PR_TRUE; - return NS_OK; - } + PRBool doValidation = PR_FALSE; - PRBool doIfModifiedSince = PR_FALSE; - - // Be optimistic: assume that we won't need to send If-Modified-Since - mCachedContentIsValid = PR_TRUE; + // Be optimistic: assume that we won't need to do validation SetRequestHeader(nsHTTPAtoms::If_Modified_Since, nsnull); + SetRequestHeader(nsHTTPAtoms::If_None_Match, nsnull); - // If there is no Last-Modified response header, then we cannot send an - // If-Modified-Since request header. - nsXPIDLCString lastModified; - mCachedResponse->GetHeader(nsHTTPAtoms::Last_Modified, - getter_Copies(lastModified)); - if (!lastModified) { - LOG(("No Last-Lodified header sent, try using the Date header.\n")); - mCachedResponse->GetHeader(nsHTTPAtoms::Date, - getter_Copies(lastModified)); - if (!lastModified) { - LOG(("BAD SERVER!! No Date header sent... reloading the document.\n")); - doIfModifiedSince = PR_FALSE; - goto end; - } - } - - // If the FORCE_VALIDATION flag is set, any cached data won't be used until - // it's revalidated with the server. - if (mLoadFlags & nsIRequest::FORCE_VALIDATION) { - LOG(("honoring nsIRequest::FORCE_VALIDATION\n")); - doIfModifiedSince = PR_TRUE; + // If the LOAD_FROM_CACHE flag is set, any cached data can simply be used. + if (mLoadFlags & LOAD_FROM_CACHE) { + LOG(("NOT validating based on LOAD_FROM_CACHE load flag\n")); + doValidation = PR_FALSE; goto end; } - // + // If the VALIDATE_ALWAYS flag is set, any cached data won't be used until + // it's revalidated with the server. + if (mLoadFlags & VALIDATE_ALWAYS) { + LOG(("Validating based on VALIDATE_ALWAYS load flag\n")); + doValidation = PR_TRUE; + goto end; + } + + // If the must-revalidate directive is present in the cached response, data + // must always be revalidated with the server, even if the user has + // configured validation to be turned off (See RFC 2616, section 14.9.4). + mCachedResponse->GetHeader(nsHTTPAtoms::Cache_Control, getter_Copies(str)); + if (str && PL_strstr(str, "must-revalidate")) { + LOG(("Validating based on \"%s\" header\n", (const char *) str)); + doValidation = PR_TRUE; + goto end; + } + // The no-cache directive within the 'Cache-Control:' header indicates + // that we must validate this cached response before reusing. + if (str && PL_strstr(str, "no-cache")) { + LOG(("Validating based on \"%s\" header\n", (const char *) str)); + doValidation = PR_TRUE; + goto end; + } + // XXX we are not quite handling no-cache correctly in this case. We really + // should check for field-names and only force validation if they match + // existing response headers. See RFC2616 section 14.9.1 for details. + str = 0; + + // Although 'Pragma:no-cache' is not a standard HTTP response header (it's + // a request header), caching is inhibited when this header is present so + // as to match existing Navigator behavior. + GetResponseHeader(nsHTTPAtoms::Pragma, getter_Copies(str)); + if (str && PL_strstr(str, "no-cache")) { + LOG(("Validating based on \"%s\" header\n", (const char *) str)); + doValidation = PR_TRUE; + goto end; + } + str = 0; + // Check the Vary header. Per comments on bug 37609, most of the request // headers that we generate do not vary with the exception of Accept-Charset // and Accept-Language, so we force validation only if these headers or "*" @@ -1152,68 +1059,74 @@ nsHTTPChannel::CheckCache() // XXX will need to add the Accept header to this list if we start sending // a full Accept header, since the addition of plugins could change this // header (see bug 58040). - // mCachedResponse->GetHeader(nsHTTPAtoms::Vary, getter_Copies(str)); - if (str) { - nsSubsumeCStr haystack((char *) (const char *) str, PR_FALSE); - if ((haystack.Find("*", PR_TRUE) != kNotFound) || - (haystack.Find("accept-charset", PR_TRUE) != kNotFound) || - (haystack.Find("accept-language", PR_TRUE) != kNotFound)) { - LOG(("Need to validate content based on Vary header\n")); - doIfModifiedSince = PR_TRUE; - goto end; - } + if (str && (PL_strstr(str, "*") || + PL_strstr(str, "accept-charset") || + PL_strstr(str, "accept-language"))) { + LOG(("Validating based on \"%s\" header\n", (const char *) str)); + doValidation = PR_TRUE; + goto end; + } + str = 0; + + if (mLoadFlags & VALIDATE_NEVER) { + doValidation = PR_FALSE; + goto end; } - // Determine if this is the first time that this cache entry has been - // accessed in this session. + // Check if the cache entry has expired... { - PRBool firstAccessThisSession; - PRUint32 sessionStartTime, lastWritten, expirationTime, now = NowInSeconds(); + PRUint32 time = 0; // a temporary variable for storing time values... - rv = mCacheEntry->GetLastModified(&lastWritten); + rv = mCacheEntry->GetExpirationTime(&time); if (NS_FAILED(rv)) return rv; - rv = mCacheEntry->GetExpirationTime(&expirationTime); - if (NS_FAILED(rv)) return rv; + if (NowInSeconds() <= time) + doValidation = PR_FALSE; + else if (mLoadFlags & VALIDATE_ONCE_PER_SESSION) { + // If the cached response does not include expiration infor- + // mation, then we must validate the response, despite whether + // or not this is the first access this session. This behavior + // is consistent with existing browsers and is generally expected + // by web authors. + rv = mCachedResponse->ComputeFreshnessLifetime(&time); + if (NS_FAILED(rv)) return rv; - sessionStartTime = PRTimeToSeconds(mHandler->GetSessionStartTime()); - firstAccessThisSession = (sessionStartTime > lastWritten); - - LOG(("firstAccessThisSession = %u\n", firstAccessThisSession)); - - // Check to see if we can use the cache data without revalidating - // it with the server. - //PRBool useHeuristicExpiration = - // mLoadFlags & nsIRequest::VALIDATE_HEURISTICALLY; - - // If the content is stale, issue an if-modified-since request - if (now > expirationTime) { - if (mLoadFlags & nsIRequest::VALIDATE_ONCE_PER_SESSION) - doIfModifiedSince = firstAccessThisSession; - else - // VALIDATE_ALWAYS || VALIDATE_HEURISTICALLY || default - doIfModifiedSince = PR_TRUE; + if (time == 0) + doValidation = PR_TRUE; + else { + rv = mCacheEntry->GetLastModified(&time); + if (NS_FAILED(rv)) return rv; + // Determine if this is the first time that this cache entry + // has been accessed in this session, and validate if so. + doValidation = (mHandler->SessionStartTime() > time); + } } + else + doValidation = PR_TRUE; } end: - if (doIfModifiedSince) { - SetRequestHeader(nsHTTPAtoms::If_Modified_Since, lastModified); + mCachedContentIsValid = !doValidation; + + if (doValidation) { + // Add If-Modified-Since header if a Last-Modified was given + mCachedResponse->GetHeader(nsHTTPAtoms::Last_Modified, getter_Copies(str)); + if (!str) { + LOG(("No Last-Lodified header sent, using the Date header instead...\n")); + mCachedResponse->GetHeader(nsHTTPAtoms::Date, getter_Copies(str)); + } + if (str) + SetRequestHeader(nsHTTPAtoms::If_Modified_Since, str); + str = 0; // Add If-None-Match header if an ETag was given in the response mCachedResponse->GetHeader(nsHTTPAtoms::ETag, getter_Copies(str)); if (str) SetRequestHeader(nsHTTPAtoms::If_None_Match, str); - - // Specify the need to validate this cache entry with the server. - mCachedContentIsValid = PR_FALSE; } - LOG(("nsHTTPChannel::CheckCache [this=%x if-modified-since=%d" - " cache-entry-is-valid=%d]\n", - this, doIfModifiedSince, mCachedContentIsValid)); - + LOG(("CheckCache [this=%x doValidation=%d\n", this, doValidation)); return NS_OK; } @@ -1272,13 +1185,14 @@ nsHTTPChannel::ReadFromCache() return rv; } +#if 0 PRBool nsHTTPChannel::ResponseIsCacheable() { nsXPIDLCString str; - // The no-store directive within the 'Cache-Control:' header indicates - // that we should not store the response in the cache + // The no-cache directive within the 'Cache-Control:' header indicates + // that we should not cache the response in a persistent cache GetResponseHeader(nsHTTPAtoms::Cache_Control, getter_Copies(str)); if (str) { nsSubsumeCStr ss((char *) (const char *) str, PR_FALSE); @@ -1328,6 +1242,7 @@ nsHTTPChannel::ResponseIsCacheable() return PR_TRUE; } +#endif nsresult nsHTTPChannel::CacheAbort(PRUint32 statusCode) @@ -1352,6 +1267,7 @@ nsresult nsHTTPChannel::CacheReceivedResponse(nsIStreamListener *aListener, nsIStreamListener **aResult) { + nsXPIDLCString str; nsresult rv; NS_ENSURE_ARG_POINTER(aListener); @@ -1371,25 +1287,23 @@ nsHTTPChannel::CacheReceivedResponse(nsIStreamListener *aListener, LOG(("nsHTTPChannel::CacheReceivedResponse [this=%x entry=%x]\n", this, mCacheEntry.get())); - // Every POST transaction has a unique ID associated with it. If this - // is not a POST transaction (or if the POST transaction should not be - // cached) then the ID will be zero. - if (!mPostID && !ResponseIsCacheable()) { - CacheAbort(0); - return NS_OK; + // The no-store directive within the 'Cache-Control:' header indicates + // that we should not store the response in a persistent cache + GetResponseHeader(nsHTTPAtoms::Cache_Control, getter_Copies(str)); + if (str && PL_strstr(str, "no-store")) { + mLoadFlags |= INHIBIT_PERSISTENT_CACHING; + LOG(("Inhibiting persistent caching because of \"%s\"\n", (const char *) str)); } // Store secure data in memory only nsCOMPtr securityInfo; - rv = GetSecurityInfo(getter_AddRefs(securityInfo)); - if (NS_SUCCEEDED(rv) && securityInfo) { - rv = mCacheEntry->SetSecurityInfo(securityInfo); - if (NS_FAILED(rv)) return rv; - } + GetSecurityInfo(getter_AddRefs(securityInfo)); + if (securityInfo) + mCacheEntry->SetSecurityInfo(securityInfo); - // For HTTPS connections, the storage policy will already be IN_MEMORY. + // For HTTPS transactions, the storage policy will already be IN_MEMORY. // We are concerned instead about load attributes which may have changed. - if (mLoadFlags & nsIRequest::INHIBIT_PERSISTENT_CACHING) { + if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) { rv = mCacheEntry->SetStoragePolicy(nsICache::STORE_IN_MEMORY); if (NS_FAILED(rv)) return rv; } @@ -1541,7 +1455,7 @@ nsHTTPChannel::CheckCache() // If we can't use the cache data (because an end-to-end reload // has been requested) // there's no point in inspecting it since it's about to be overwritten. - if (mLoadFlags & nsIRequest::FORCE_RELOAD) + if (mLoadFlags & LOAD_BYPASS_CACHE) return NS_OK; // Due to architectural limitations in the cache manager, a cache entry can @@ -1629,11 +1543,11 @@ nsHTTPChannel::CheckCache() if (varyHeader) mustRevalidate = PR_TRUE; - // If the FORCE_VALIDATION flag is set, any cached data won't be used until + // If the VALIDATE_ALWAYS flag is set, any cached data won't be used until // it's revalidated with the server, so there's no point in checking if it's // expired. PRBool doIfModifiedSince; - if ((mLoadFlags & nsIRequest::FORCE_VALIDATION) || mustRevalidate) + if ((mLoadFlags & nsIRequest::VALIDATE_ALWAYS) || mustRevalidate) doIfModifiedSince = PR_TRUE; else { doIfModifiedSince = PR_FALSE; @@ -1665,7 +1579,6 @@ nsHTTPChannel::CheckCache() if (mLoadFlags & nsIRequest::VALIDATE_ONCE_PER_SESSION) doIfModifiedSince = firstAccessThisSession; else - // VALIDATE_ALWAYS || VALIDATE_HEURISTICALLY || default doIfModifiedSince = PR_TRUE; } } @@ -2077,8 +1990,7 @@ nsHTTPChannel::Connect() } // if using proxy... - nsXPIDLCString requestSpec; - rv = mRequest->GetOverrideRequestSpec(getter_Copies(requestSpec)); + const char *requestSpec = mRequest->OverrideRequestSpec(); // no one has overwritten this value as yet... if (!requestSpec && mProxy && *mProxy && !mProxyTransparent) { nsXPIDLCString strurl; @@ -2265,7 +2177,7 @@ nsresult nsHTTPChannel::Redirect(const char *aNewLocation, // Add in LOAD_REPLACE to loadattributes indicate that this is a redirect nsLoadFlags loadFlags = mLoadFlags; - loadFlags |= nsIRequest::LOAD_REPLACE; + loadFlags |= LOAD_REPLACE; rv = NS_OpenURI(getter_AddRefs(channel), newURI, serv, mLoadGroup, mCallbacks, loadFlags); @@ -2332,7 +2244,7 @@ nsresult nsHTTPChannel::ResponseCompleted(nsIStreamListener *aListener, nsresult nsresult rv = NS_OK; LOG(("nsHTTPChannel::ResponseComplete() [this=%x] " - "mDataListenet=%x, Status=%o\n", + "mDataListenet=%x, Status=%x\n", this, (void*)mResponseDataListener, aStatus)); #if 0 @@ -2946,6 +2858,7 @@ nsHTTPChannel::ProcessStatusCode(void) // indicates that the cached response can be used. if (statusCode == 304) { rv = ProcessNotModifiedResponse(listener); + LOG(("ProcessNotModifiedResponse returned rv=%x\n", rv)); if (NS_FAILED(rv)) return rv; break; } @@ -3015,11 +2928,14 @@ nsHTTPChannel::ProcessNotModifiedResponse(nsIStreamListener *aListener) "Using cache copy for: %s\n", this, mRequest->Spec())); + // XXX this should be unnecessary.. the response was successful!! +#if 0 // Orphan the current nsHTTPServerListener instance... It will be // replaced with a nsHTTPCacheListener instance. NS_ASSERTION(mHTTPServerListener, "No nsHTTPServerResponse available!"); if (mHTTPServerListener) mHTTPServerListener->Abort(); +#endif // Update the cached headers with any more recent ones from the // server - see RFC2616 [13.5.3] @@ -3202,8 +3118,8 @@ nsHTTPChannel::SetProxyRequestURI(const char * i_Spec) NS_IMETHODIMP nsHTTPChannel::GetProxyRequestURI(char * *o_Spec) { - return mRequest ? - mRequest->GetOverrideRequestSpec(o_Spec) : NS_ERROR_FAILURE; + return mRequest ? + DupString(o_Spec, mRequest->OverrideRequestSpec()) : NS_ERROR_FAILURE; } NS_IMETHODIMP diff --git a/netwerk/protocol/http/src/nsHTTPChannel.h b/netwerk/protocol/http/src/nsHTTPChannel.h index bd6611c84ff6..76654af728f3 100644 --- a/netwerk/protocol/http/src/nsHTTPChannel.h +++ b/netwerk/protocol/http/src/nsHTTPChannel.h @@ -139,8 +139,6 @@ protected: nsresult OpenCacheEntry(); nsresult GenerateCacheKey(nsAWritableCString &); - nsresult ComputeCurrentAge(PRUint32 now, PRUint32 *); - nsresult ComputeFreshnessLifetime(PRUint32 *); nsresult UpdateExpirationTime(); PRBool ResponseIsCacheable(); diff --git a/netwerk/protocol/http/src/nsHTTPHandler.cpp b/netwerk/protocol/http/src/nsHTTPHandler.cpp index 2dddded54a57..c6c5e0d385f7 100644 --- a/netwerk/protocol/http/src/nsHTTPHandler.cpp +++ b/netwerk/protocol/http/src/nsHTTPHandler.cpp @@ -954,7 +954,7 @@ nsHTTPHandler::Init() gHTTPLog = PR_NewLogModule("nsHTTPProtocol"); #endif /* PR_LOGGING */ - mSessionStartTime = PR_Now(); + mSessionStartTime = NowInSeconds(); PR_LOG(gHTTPLog, PR_LOG_ALWAYS, ("Creating nsHTTPHandler [this=%x].\n", this)); diff --git a/netwerk/protocol/http/src/nsHTTPHandler.h b/netwerk/protocol/http/src/nsHTTPHandler.h index 75e1f664683a..d009fba943ed 100644 --- a/netwerk/protocol/http/src/nsHTTPHandler.h +++ b/netwerk/protocol/http/src/nsHTTPHandler.h @@ -128,7 +128,7 @@ public: /* Remove this transport from the list. */ virtual nsresult ReleaseTransport(nsITransport* i_pTrans, PRUint32 capabilies = 0, PRBool aDontRestartChannels = PR_FALSE, PRUint32 aKeepAliveTimeout = 0, PRInt32 aKeepAliveMaxCon = -1); virtual nsresult CancelPendingChannel(nsHTTPChannel* aChannel); - PRTime GetSessionStartTime() { return mSessionStartTime; } + PRUint32 SessionStartTime() { return mSessionStartTime; } void PrefsChanged(const char* pref = 0); @@ -188,7 +188,7 @@ protected: nsCOMPtr mPrefs; nsCOMPtr mProxySvc; PRUint32 mReferrerLevel; - PRTime mSessionStartTime; + PRUint32 mSessionStartTime; nsresult BuildUserAgent(); nsCString mAppName; diff --git a/netwerk/protocol/http/src/nsHTTPRequest.cpp b/netwerk/protocol/http/src/nsHTTPRequest.cpp index ffa809f2475a..b2f7547d759b 100644 --- a/netwerk/protocol/http/src/nsHTTPRequest.cpp +++ b/netwerk/protocol/http/src/nsHTTPRequest.cpp @@ -311,12 +311,6 @@ nsHTTPRequest::SetOverrideRequestSpec(const char *aSpec) return DupString(&mRequestSpec, aSpec); } -nsresult -nsHTTPRequest::GetOverrideRequestSpec(char **aSpec) -{ - return DupString(aSpec, mRequestSpec); -} - nsresult nsHTTPRequest::formHeaders(PRUint32 capabilities) { @@ -352,24 +346,23 @@ nsHTTPRequest::formHeaders(PRUint32 capabilities) PRUint32 loadFlags; mConnection->GetLoadFlags(&loadFlags); - if (loadFlags & - (nsIRequest::FORCE_VALIDATION | nsIRequest::FORCE_RELOAD)) { + if (loadFlags & LOAD_BYPASS_CACHE) { // We need to send 'Pragma:no-cache' to inhibit proxy caching even if // no proxy is configured since we might be talking with a transparent // proxy, i.e. one that operates at the network level. See bug #14772 SetHeader(nsHTTPAtoms::Pragma, "no-cache"); - } - - if (loadFlags & nsIRequest::FORCE_RELOAD) { // If doing a reload, force end-to-end SetHeader(nsHTTPAtoms::Cache_Control, "no-cache"); } - else if (loadFlags & nsIRequest::FORCE_VALIDATION) { + // XXX it should be sufficient to just validate with the immediate host. +#if 0 + else if (loadFlags & VALIDATE_ALWAYS) { // A "max-age=0" cache-control directive forces each cache along the // path to the origin server to revalidate its own entry, if any, with // the next cache or server. SetHeader(nsHTTPAtoms::Cache_Control, "max-age=0"); } +#endif // Send */*. We're no longer chopping MIME-types for acceptance. // MIME based content negotiation has died. diff --git a/netwerk/protocol/http/src/nsHTTPRequest.h b/netwerk/protocol/http/src/nsHTTPRequest.h index 81b5ecf98d1a..a15eb5795659 100644 --- a/netwerk/protocol/http/src/nsHTTPRequest.h +++ b/netwerk/protocol/http/src/nsHTTPRequest.h @@ -118,9 +118,9 @@ public: nsresult SetUploadStream(nsIInputStream* i_UploadStream); nsresult SetOverrideRequestSpec(const char* i_Spec); - nsresult GetOverrideRequestSpec(char** o_Spec); - const char *Spec() { return (const char *) mSpec; } + const char *OverrideRequestSpec() { return (const char *) mRequestSpec; } + const char *Spec() { return (const char *) mSpec; } // for POST or PUT data... nsCOMPtr mInputStream; diff --git a/netwerk/protocol/http/src/nsHTTPResponse.cpp b/netwerk/protocol/http/src/nsHTTPResponse.cpp index 696e4f35729a..5f7d217d0d11 100644 --- a/netwerk/protocol/http/src/nsHTTPResponse.cpp +++ b/netwerk/protocol/http/src/nsHTTPResponse.cpp @@ -35,7 +35,9 @@ #if defined(PR_LOGGING) extern PRLogModuleInfo* gHTTPLog; -#endif /* PR_LOGGING */ +#endif + +#define LOG(args) PR_LOG(gHTTPLog, PR_LOG_DEBUG, args) // When deciding heuristically whether or not to validate an HTTP response with // the server, this constant can be used to tune how conservative the algorithm @@ -935,4 +937,112 @@ nsHTTPResponse::GetExpiresValue(PRUint32 *result, PRBool *isAvail) return ParseDateHeader(nsHTTPAtoms::Expires, result, isAvail); } +// From section 13.2.3 of RFC2616, we compute the current age of a cached +// response as follows: +// +// currentAge = max(max(0, responseTime - dateValue), ageValue) +// + now - requestTime +// +// where responseTime == now +// +// This is typically a very small number. +// +nsresult +nsHTTPResponse::ComputeCurrentAge(PRUint32 now, + PRUint32 requestTime, + PRUint32 *result) +{ + PRUint32 dateValue; + PRUint32 ageValue = 0; + PRBool avail = PR_FALSE; + nsresult rv; + + *result = 0; + + rv = GetDateValue(&dateValue, &avail); + if (NS_FAILED(rv)) return rv; + + if (!avail) { + LOG(("nsHTTPResponse::ComputeCurrentAge [this=%x] Date response header not set!\n", this)); + // Assume we have a very fast connection !! + dateValue = now; + } + + rv = GetAgeValue(&ageValue, &avail); + if (NS_FAILED(rv)) return rv; + + // Compute apparent age + if (now > dateValue) + *result = now - dateValue; + + // Compute corrected received age + if (avail) + *result = PR_MAX(*result, ageValue); + + NS_ASSERTION(now >= requestTime, "bogus request time"); + + // Compute current age + *result += (now - requestTime); + + return NS_OK; +} + +// From section 13.2.4 of RFC2616, we compute the freshness lifetime of a cached +// response as follows: +// +// freshnessLifetime = max_age_value +// +// freshnessLifetime = expires_value - date_value +// +// freshnessLifetime = (date_value - last_modified_value) * 0.10 +// +// freshnessLifetime = 0 +// +nsresult +nsHTTPResponse::ComputeFreshnessLifetime(PRUint32 *result) +{ + NS_ENSURE_ARG_POINTER(result); + + nsresult rv; + PRBool avail = PR_FALSE; + + *result = 0; + + // Try HTTP/1.1 style max-age directive... + rv = GetMaxAge(result, &avail); + if (NS_FAILED(rv)) return rv; + if (avail) + return NS_OK; + + PRUint32 date, date2; + + rv = GetDateValue(&date, &avail); + if (NS_FAILED(rv)) return rv; + if (avail) { + // Try HTTP/1.0 style expires header... + rv = GetExpiresValue(&date2, &avail); + if (NS_FAILED(rv)) return rv; + if (avail) { + *result = date2 - date; + return NS_OK; + } + + // Fallback on heuristic using last modified header... + rv = GetLastModifiedValue(&date2, &avail); + if (NS_FAILED(rv)) return rv; + if (avail) { + LOG(("using last-modified to determine freshness-lifetime\n")); + LOG(("last-modified = %u, date = %u\n", date2, date)); + *result = (date - date2) / 10; + return NS_OK; + } + } + + LOG(("nsHTTPResponse::ComputeFreshnessLifetime [this = %x] " + "Insufficient information to compute a non-zero freshness " + "lifetime!\n", this)); + + return NS_OK; +} + #endif diff --git a/netwerk/protocol/http/src/nsHTTPResponse.h b/netwerk/protocol/http/src/nsHTTPResponse.h index a29ec7c389ef..8dce74ba8899 100644 --- a/netwerk/protocol/http/src/nsHTTPResponse.h +++ b/netwerk/protocol/http/src/nsHTTPResponse.h @@ -90,6 +90,8 @@ public: nsresult GetDateValue(PRUint32 *, PRBool *isAvail); nsresult GetLastModifiedValue(PRUint32 *, PRBool *isAvail); nsresult GetExpiresValue(PRUint32 *, PRBool *isAvail); + nsresult ComputeFreshnessLifetime(PRUint32 *); + nsresult ComputeCurrentAge(PRUint32 now, PRUint32 requestTime, PRUint32 *result); #endif nsresult GetMaxAge(PRUint32 *, PRBool *isAvail); diff --git a/netwerk/protocol/http/src/nsHTTPResponseListener.cpp b/netwerk/protocol/http/src/nsHTTPResponseListener.cpp index 7e4ad05c411d..7eac0cb677f1 100644 --- a/netwerk/protocol/http/src/nsHTTPResponseListener.cpp +++ b/netwerk/protocol/http/src/nsHTTPResponseListener.cpp @@ -447,6 +447,7 @@ nsHTTPServerListener::OnDataAvailable(nsIRequest *request, // if (!mResponseDataListener) { // XXX: What should the return code be? + LOG(("nsHTTPServerListener::OnDataAvailable -- returning NS_BINDING_ABORTED\n")); rv = NS_BINDING_ABORTED; } @@ -698,7 +699,13 @@ nsHTTPServerListener::OnStopRequest(nsIRequest* request, nsISupports* i_pContext mResponse->GetStatus(&status); if (status != 304 || mChannel->HasCachedResponse()) { - mChannel->ResponseCompleted(mResponseDataListener, i_Status); + // For 304 responses, we'll call ResponseCompleted after the response + // has been completely read from the cache. + if (status != 304) { + LOG(("Calling ResponseCompleted [httpStatus=%d status=%x]\n", status, i_Status)); + mChannel->ResponseCompleted(mResponseDataListener, i_Status); + } + // The channel is done with us. mChannel->SetHTTPServerListener(nsnull); } @@ -807,6 +814,8 @@ nsresult nsHTTPServerListener::Abort() nsresult nsHTTPServerListener::FireSingleOnData(nsIStreamListener *aListener, nsISupports *aContext) { + LOG(("nsHTTPServerListener::FireSingleOnData [this=%x]\n", this)); + nsresult rv = NS_OK; if (mHeadersDone) { diff --git a/netwerk/streamconv/converters/nsMultiMixedConv.cpp b/netwerk/streamconv/converters/nsMultiMixedConv.cpp index 449fee9ad94b..523d35c4823b 100644 --- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp +++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp @@ -371,7 +371,7 @@ nsMultiMixedConv::SendStart(nsIChannel *aChannel) { nsLoadFlags loadFlags = 0; mPartChannel->GetLoadFlags(&loadFlags); - loadFlags |= nsIRequest::LOAD_REPLACE; + loadFlags |= nsIChannel::LOAD_REPLACE; mPartChannel->SetLoadFlags(loadFlags); nsCOMPtr loadGroup; diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp index c08cf031fab5..eaf1bf78445a 100644 --- a/uriloader/base/nsDocLoader.cpp +++ b/uriloader/base/nsDocLoader.cpp @@ -465,7 +465,7 @@ nsDocLoaderImpl::OnStartRequest(nsIRequest *request, nsISupports *aCtxt) PRUint32 loadFlags = 0; request->GetLoadFlags(&loadFlags); - if (!mIsLoadingDocument && (loadFlags & nsIRequest::LOAD_DOCUMENT_URI)) { + if (!mIsLoadingDocument && (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)) { mIsLoadingDocument = PR_TRUE; ClearInternalProgress(); // only clear our progress if we are starting a new load.... } @@ -486,7 +486,7 @@ nsDocLoaderImpl::OnStartRequest(nsIRequest *request, nsISupports *aCtxt) // AddRequestInfo(request); - if ((1 == count) && (loadFlags & nsIRequest::LOAD_DOCUMENT_URI)) { + if ((1 == count) && (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)) { // This request is associated with the entire document... mDocumentRequest = do_QueryInterface(request); mLoadGroup->SetDefaultLoadRequest(mDocumentRequest); diff --git a/uriloader/base/nsURILoader.cpp b/uriloader/base/nsURILoader.cpp index 1a1c0fb1ddd1..6749b2f7e6b5 100644 --- a/uriloader/base/nsURILoader.cpp +++ b/uriloader/base/nsURILoader.cpp @@ -363,7 +363,7 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports * // we must be retargeting...so set an appropriate flag on the channel nsLoadFlags loadFlags = 0; aChannel->GetLoadFlags(&loadFlags); - loadFlags |= nsIRequest::LOAD_RETARGETED_DOCUMENT_URI; + loadFlags |= nsIChannel::LOAD_RETARGETED_DOCUMENT_URI; aChannel->SetLoadFlags(loadFlags); } diff --git a/xpfe/components/bookmarks/src/nsBookmarksService.cpp b/xpfe/components/bookmarks/src/nsBookmarksService.cpp index 0672f2e40002..df70cf1087ee 100644 --- a/xpfe/components/bookmarks/src/nsBookmarksService.cpp +++ b/xpfe/components/bookmarks/src/nsBookmarksService.cpp @@ -1987,7 +1987,7 @@ nsBookmarksService::FireTimer(nsITimer* aTimer, void* aClosure) nsCOMPtr channel; if (NS_SUCCEEDED(rv = NS_OpenURI(getter_AddRefs(channel), uri, nsnull))) { - channel->SetLoadFlags(nsIRequest::FORCE_VALIDATION | nsIRequest::VALIDATE_ALWAYS); + channel->SetLoadFlags(nsIRequest::VALIDATE_ALWAYS); nsCOMPtr httpChannel = do_QueryInterface(channel); if (httpChannel) { diff --git a/xpfe/components/prefwindow/resources/content/pref-cache.xul b/xpfe/components/prefwindow/resources/content/pref-cache.xul index 6f5ab2923332..603c89e92d56 100644 --- a/xpfe/components/prefwindow/resources/content/pref-cache.xul +++ b/xpfe/components/prefwindow/resources/content/pref-cache.xul @@ -91,8 +91,9 @@ - + + diff --git a/xpfe/components/prefwindow/resources/locale/en-US/pref-cache.dtd b/xpfe/components/prefwindow/resources/locale/en-US/pref-cache.dtd index a32b03f54902..5145795bb2ad 100644 --- a/xpfe/components/prefwindow/resources/locale/en-US/pref-cache.dtd +++ b/xpfe/components/prefwindow/resources/locale/en-US/pref-cache.dtd @@ -24,3 +24,5 @@ + + diff --git a/xpfe/components/search/src/nsInternetSearchService.cpp b/xpfe/components/search/src/nsInternetSearchService.cpp index 3c8b6c885532..4dc404d9bc55 100755 --- a/xpfe/components/search/src/nsInternetSearchService.cpp +++ b/xpfe/components/search/src/nsInternetSearchService.cpp @@ -626,7 +626,7 @@ InternetSearchDataSource::FireTimer(nsITimer* aTimer, void* aClosure) nsCOMPtr channel; if (NS_FAILED(rv = NS_OpenURI(getter_AddRefs(channel), uri, nsnull))) return; - channel->SetLoadFlags(nsIRequest::FORCE_VALIDATION | nsIRequest::VALIDATE_ALWAYS); + channel->SetLoadFlags(nsIRequest::VALIDATE_ALWAYS); nsCOMPtr httpChannel (do_QueryInterface(channel)); if (!httpChannel) return; @@ -3562,7 +3562,7 @@ InternetSearchDataSource::DoSearch(nsIRDFResource *source, nsIRDFResource *engin } // get it just from the cache if we can (do not validate) - channel->SetLoadFlags(nsIRequest::VALIDATE_NEVER); + channel->SetLoadFlags(nsIRequest::LOAD_FROM_CACHE); if (methodStr.EqualsIgnoreCase("post")) { diff --git a/xpfe/components/xfer/src/nsStreamTransfer.cpp b/xpfe/components/xfer/src/nsStreamTransfer.cpp index 3256698e0f27..bcba84a451ea 100644 --- a/xpfe/components/xfer/src/nsStreamTransfer.cpp +++ b/xpfe/components/xfer/src/nsStreamTransfer.cpp @@ -176,9 +176,9 @@ nsStreamTransfer::SelectFileAndTransferLocationSpec( char const *aURL, rv = NS_OpenURI( getter_AddRefs( channel ), uri, nsnull ); if ( NS_SUCCEEDED( rv ) && channel ) { - // See if VALIDATE_NEVER is called for. + // See if LOAD_FROM_CACHE is called for. if ( doNotValidate ) { - channel->SetLoadFlags( nsIRequest::VALIDATE_NEVER ); + channel->SetLoadFlags( nsIRequest::LOAD_FROM_CACHE ); } // Post data provided? if ( postData ) {