mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 561276 - Cookie dependency on cache determination for image redirects r=bz
This commit is contained in:
parent
a119175fc3
commit
884a180af5
@ -76,6 +76,7 @@ HttpBaseChannel::HttpBaseChannel()
|
|||||||
, mChooseApplicationCache(PR_FALSE)
|
, mChooseApplicationCache(PR_FALSE)
|
||||||
, mLoadedFromApplicationCache(PR_FALSE)
|
, mLoadedFromApplicationCache(PR_FALSE)
|
||||||
, mChannelIsForDownload(PR_FALSE)
|
, mChannelIsForDownload(PR_FALSE)
|
||||||
|
, mRedirectedCachekeys(nsnull)
|
||||||
{
|
{
|
||||||
LOG(("Creating HttpBaseChannel @%x\n", this));
|
LOG(("Creating HttpBaseChannel @%x\n", this));
|
||||||
|
|
||||||
@ -87,6 +88,9 @@ HttpBaseChannel::~HttpBaseChannel()
|
|||||||
{
|
{
|
||||||
LOG(("Destroying HttpBaseChannel @%x\n", this));
|
LOG(("Destroying HttpBaseChannel @%x\n", this));
|
||||||
|
|
||||||
|
// Make sure we don't leak
|
||||||
|
CleanRedirectCacheChainIfNecessary();
|
||||||
|
|
||||||
gHttpHandler->Release();
|
gHttpHandler->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1166,6 +1170,13 @@ HttpBaseChannel::SetChannelIsForDownload(PRBool aChannelIsForDownload)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
HttpBaseChannel::SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys)
|
||||||
|
{
|
||||||
|
mRedirectedCachekeys = cacheKeys;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// HttpBaseChannel::nsISupportsPriority
|
// HttpBaseChannel::nsISupportsPriority
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -1384,6 +1395,15 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
|
|||||||
httpInternal->SetDocumentURI(newURI);
|
httpInternal->SetDocumentURI(newURI);
|
||||||
else
|
else
|
||||||
httpInternal->SetDocumentURI(mDocumentURI);
|
httpInternal->SetDocumentURI(mDocumentURI);
|
||||||
|
|
||||||
|
// if there is a chain of keys for redirect-responses we transfer it to
|
||||||
|
// the new channel (see bug #561276)
|
||||||
|
if (mRedirectedCachekeys) {
|
||||||
|
LOG(("HttpBaseChannel::SetupReplacementChannel "
|
||||||
|
"[this=%p] transferring chain of redirect cache-keys", this));
|
||||||
|
httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys);
|
||||||
|
mRedirectedCachekeys = nsnull;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// transfer application cache information
|
// transfer application cache information
|
||||||
|
@ -154,6 +154,14 @@ public:
|
|||||||
NS_IMETHOD GetCanceled(PRBool *aCanceled);
|
NS_IMETHOD GetCanceled(PRBool *aCanceled);
|
||||||
NS_IMETHOD GetChannelIsForDownload(PRBool *aChannelIsForDownload);
|
NS_IMETHOD GetChannelIsForDownload(PRBool *aChannelIsForDownload);
|
||||||
NS_IMETHOD SetChannelIsForDownload(PRBool aChannelIsForDownload);
|
NS_IMETHOD SetChannelIsForDownload(PRBool aChannelIsForDownload);
|
||||||
|
NS_IMETHOD SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys);
|
||||||
|
inline void CleanRedirectCacheChainIfNecessary()
|
||||||
|
{
|
||||||
|
if (mRedirectedCachekeys) {
|
||||||
|
delete mRedirectedCachekeys;
|
||||||
|
mRedirectedCachekeys = nsnull;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// nsISupportsPriority
|
// nsISupportsPriority
|
||||||
NS_IMETHOD GetPriority(PRInt32 *value);
|
NS_IMETHOD GetPriority(PRInt32 *value);
|
||||||
@ -250,6 +258,8 @@ protected:
|
|||||||
PRUint32 mChooseApplicationCache : 1;
|
PRUint32 mChooseApplicationCache : 1;
|
||||||
PRUint32 mLoadedFromApplicationCache : 1;
|
PRUint32 mLoadedFromApplicationCache : 1;
|
||||||
PRUint32 mChannelIsForDownload : 1;
|
PRUint32 mChannelIsForDownload : 1;
|
||||||
|
|
||||||
|
nsTArray<nsCString> *mRedirectedCachekeys;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -384,6 +384,9 @@ nsHttpChannel::DoNotifyListener()
|
|||||||
// We have to make sure to drop the reference to the callbacks too
|
// We have to make sure to drop the reference to the callbacks too
|
||||||
mCallbacks = nsnull;
|
mCallbacks = nsnull;
|
||||||
mProgressSink = nsnull;
|
mProgressSink = nsnull;
|
||||||
|
|
||||||
|
// We don't need this info anymore
|
||||||
|
CleanRedirectCacheChainIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2637,12 +2640,27 @@ nsHttpChannel::CheckCache()
|
|||||||
(buf.IsEmpty() && mRequestHead.PeekHeader(nsHttp::Authorization));
|
(buf.IsEmpty() && mRequestHead.PeekHeader(nsHttp::Authorization));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!doValidation) {
|
// Bug #561276: We maintain a chain of cache-keys which returns cached
|
||||||
// Sites redirect back to the original URI after setting a session/tracking
|
// 3xx-responses (redirects) in order to detect cycles. If a cycle is
|
||||||
// cookie. In such cases, force revalidation so that we hit the net and do not
|
// found, ignore the cached response and hit the net. Otherwise, use
|
||||||
// cycle thru cached responses.
|
// the cached response and add the cache-key to the chain. Note that
|
||||||
if (isCachedRedirect && mRequestHead.PeekHeader(nsHttp::Cookie))
|
// a limited number of redirects (cached or not) is allowed and is
|
||||||
|
// enforced independently of this mechanism
|
||||||
|
if (!doValidation && isCachedRedirect) {
|
||||||
|
nsCAutoString cacheKey;
|
||||||
|
GenerateCacheKey(mPostID, cacheKey);
|
||||||
|
|
||||||
|
if (!mRedirectedCachekeys)
|
||||||
|
mRedirectedCachekeys = new nsTArray<nsCString>();
|
||||||
|
else if (mRedirectedCachekeys->Contains(cacheKey))
|
||||||
doValidation = PR_TRUE;
|
doValidation = PR_TRUE;
|
||||||
|
|
||||||
|
LOG(("Redirection-chain %s key %s\n",
|
||||||
|
doValidation ? "contains" : "does not contain", cacheKey.get()));
|
||||||
|
|
||||||
|
// Append cacheKey if not in the chain already
|
||||||
|
if (!doValidation)
|
||||||
|
mRedirectedCachekeys->AppendElement(cacheKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
mCachedContentIsValid = !doValidation;
|
mCachedContentIsValid = !doValidation;
|
||||||
@ -2678,6 +2696,9 @@ nsHttpChannel::CheckCache()
|
|||||||
mRequestHead.SetHeader(nsHttp::If_None_Match,
|
mRequestHead.SetHeader(nsHttp::If_None_Match,
|
||||||
nsDependentCString(val));
|
nsDependentCString(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't need this info anymore
|
||||||
|
CleanRedirectCacheChainIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(("nsHTTPChannel::CheckCache exit [this=%p doValidation=%d]\n", this, doValidation));
|
LOG(("nsHTTPChannel::CheckCache exit [this=%p doValidation=%d]\n", this, doValidation));
|
||||||
@ -4043,6 +4064,9 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
|
|||||||
if (mLoadGroup)
|
if (mLoadGroup)
|
||||||
mLoadGroup->RemoveRequest(this, nsnull, status);
|
mLoadGroup->RemoveRequest(this, nsnull, status);
|
||||||
|
|
||||||
|
// We don't need this info anymore
|
||||||
|
CleanRedirectCacheChainIfNecessary();
|
||||||
|
|
||||||
mCallbacks = nsnull;
|
mCallbacks = nsnull;
|
||||||
mProgressSink = nsnull;
|
mProgressSink = nsnull;
|
||||||
|
|
||||||
|
@ -37,6 +37,12 @@
|
|||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
|
%{C++
|
||||||
|
#include "nsTArray.h"
|
||||||
|
class nsCString;
|
||||||
|
%}
|
||||||
|
[ptr] native StringArray(nsTArray<nsCString>);
|
||||||
|
|
||||||
interface nsIURI;
|
interface nsIURI;
|
||||||
interface nsIProxyInfo;
|
interface nsIProxyInfo;
|
||||||
|
|
||||||
@ -45,7 +51,7 @@ interface nsIProxyInfo;
|
|||||||
* using any feature exposed by this interface, be aware that this interface
|
* using any feature exposed by this interface, be aware that this interface
|
||||||
* will change and you will be broken. You have been warned.
|
* will change and you will be broken. You have been warned.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(9fb2a161-d075-4bf2-b07a-26bac650cc81)]
|
[scriptable, uuid(44e35ead-6656-4f9e-b51d-ebaf1bee6e2e)]
|
||||||
interface nsIHttpChannelInternal : nsISupports
|
interface nsIHttpChannelInternal : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -93,4 +99,9 @@ interface nsIHttpChannelInternal : nsISupports
|
|||||||
* Lets externalhandler tell the channel it is open on behalf of a download
|
* Lets externalhandler tell the channel it is open on behalf of a download
|
||||||
*/
|
*/
|
||||||
attribute boolean channelIsForDownload;
|
attribute boolean channelIsForDownload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transfer chain of redirected cache-keys
|
||||||
|
*/
|
||||||
|
[noscript] void setCacheKeysRedirectChain(in StringArray cacheKeys);
|
||||||
};
|
};
|
||||||
|
74
netwerk/test/unit/test_bug561276.js
Normal file
74
netwerk/test/unit/test_bug561276.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// Verify that we hit the net if we discover a cycle of redirects
|
||||||
|
// coming from cache.
|
||||||
|
//
|
||||||
|
|
||||||
|
do_load_httpd_js();
|
||||||
|
|
||||||
|
var httpserver = new nsHttpServer();
|
||||||
|
var iteration = 0;
|
||||||
|
|
||||||
|
function getCacheService()
|
||||||
|
{
|
||||||
|
return Components.classes["@mozilla.org/network/cache-service;1"]
|
||||||
|
.getService(Components.interfaces.nsICacheService);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupChannel(suffix)
|
||||||
|
{
|
||||||
|
var ios =
|
||||||
|
Components.classes["@mozilla.org/network/io-service;1"]
|
||||||
|
.getService(Ci.nsIIOService);
|
||||||
|
var chan = ios.newChannel("http://localhost:4444" + suffix, "", null);
|
||||||
|
var httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel);
|
||||||
|
httpChan.requestMethod = "GET";
|
||||||
|
return httpChan;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkValueAndTrigger(request, data, ctx)
|
||||||
|
{
|
||||||
|
do_check_eq("Ok", data);
|
||||||
|
httpserver.stop(do_test_finished);
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_test()
|
||||||
|
{
|
||||||
|
httpserver.registerPathHandler("/redirect1", redirectHandler1);
|
||||||
|
httpserver.registerPathHandler("/redirect2", redirectHandler2);
|
||||||
|
httpserver.start(4444);
|
||||||
|
|
||||||
|
// clear cache
|
||||||
|
getCacheService().
|
||||||
|
evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||||
|
|
||||||
|
// load first time
|
||||||
|
var channel = setupChannel("/redirect1");
|
||||||
|
channel.asyncOpen(new ChannelListener(checkValueAndTrigger, null), null);
|
||||||
|
|
||||||
|
do_test_pending();
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectHandler1(metadata, response)
|
||||||
|
{
|
||||||
|
// first time we return a cacheable 302 pointing to next redirect
|
||||||
|
if (iteration < 1) {
|
||||||
|
response.setStatusLine(metadata.httpVersion, 302, "Found");
|
||||||
|
response.setHeader("Cache-Control", "max-age=600", false);
|
||||||
|
response.setHeader("Location", "/redirect2", false);
|
||||||
|
|
||||||
|
// next time called we return 200
|
||||||
|
} else {
|
||||||
|
response.setStatusLine(metadata.httpVersion, 200, "Ok");
|
||||||
|
response.setHeader("Cache-Control", "max-age=600", false);
|
||||||
|
response.setHeader("Content-Type", "text/plain");
|
||||||
|
response.bodyOutputStream.write("Ok", "Ok".length);
|
||||||
|
}
|
||||||
|
iteration += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectHandler2(metadata, response)
|
||||||
|
{
|
||||||
|
response.setStatusLine(metadata.httpVersion, 302, "Found");
|
||||||
|
response.setHeader("Cache-Control", "max-age=600", false);
|
||||||
|
response.setHeader("Location", "/redirect1", false);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user