зеркало из https://github.com/mozilla/pjs.git
Bug 513086 - Make redirect API async, r=bz, sr=biesi
--HG-- rename : netwerk/test/unit/test_redirect_caching.js => netwerk/test/unit/test_redirect-caching_passing.js
This commit is contained in:
Родитель
95422562da
Коммит
f56aa1a89b
|
@ -72,6 +72,7 @@ XPIDLSRCS = \
|
|||
nsIAuthPromptAdapterFactory.idl \
|
||||
nsIAuthPromptCallback.idl \
|
||||
nsIAsyncStreamCopier.idl \
|
||||
nsIAsyncVerifyRedirectCallback.idl \
|
||||
nsIBufferedStreams.idl \
|
||||
nsICancelable.idl \
|
||||
nsIChannelPolicy.idl \
|
||||
|
@ -149,6 +150,7 @@ EXPORTS = \
|
|||
nsURIHashKey.h \
|
||||
nsReadLine.h \
|
||||
nsASocketHandler.h \
|
||||
nsAsyncRedirectVerifyHelper.h \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org networking code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Honza Bambas <honzab@firemni.cz>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsAsyncRedirectVerifyHelper_h
|
||||
#define nsAsyncRedirectVerifyHelper_h
|
||||
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIChannel;
|
||||
|
||||
/**
|
||||
* This class simplifies call of OnChannelRedirect of IOService and
|
||||
* the sink bound with the channel being redirected while the result of
|
||||
* redirect decision is returned through the callback.
|
||||
*/
|
||||
class nsAsyncRedirectVerifyHelper : public nsIRunnable
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initialize and runs the chain of OnChannelRedirect calls. OldChannel
|
||||
* is QI'ed for nsIAsyncVerifyRedirectCallback. The result of the redirect
|
||||
* decision is passed through this interface back to the oldChannel.
|
||||
*
|
||||
* @param oldChan
|
||||
* channel being redirected, MUST implement
|
||||
* nsIAsyncVerifyRedirectCallback
|
||||
* @param newChan
|
||||
* target of the redirect channel
|
||||
* @param flags
|
||||
* redirect flags
|
||||
* @param synchronize
|
||||
* set to TRUE if you want the Init method wait synchronously for
|
||||
* all redirect callbacks
|
||||
*/
|
||||
nsresult Init(nsIChannel* oldChan,
|
||||
nsIChannel* newChan,
|
||||
PRUint32 flags,
|
||||
PRBool synchronize = PR_FALSE);
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIChannel> mOldChan;
|
||||
nsCOMPtr<nsIChannel> mNewChan;
|
||||
PRUint32 mFlags;
|
||||
PRBool mWaitingForRedirectCallback;
|
||||
|
||||
void Callback(nsresult result);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,52 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Honza Bambas <honzab@firemni.cz>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(8d171460-a716-41f1-92be-8c659db39b45)]
|
||||
interface nsIAsyncVerifyRedirectCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Complement to nsIChannelEventSink asynchronous callback. The result of
|
||||
* the redirect decision is passed through this callback.
|
||||
*
|
||||
* @param result
|
||||
* Result of the redirect veto decision. If FAILED the redirect has been
|
||||
* vetoed. If SUCCEEDED the redirect has been allowed by all consumers.
|
||||
*/
|
||||
void onRedirectVerifyCallback(in nsresult result);
|
||||
};
|
|
@ -54,6 +54,7 @@ endif
|
|||
CPPSRCS = \
|
||||
nsTransportUtils.cpp \
|
||||
nsAsyncStreamCopier.cpp \
|
||||
nsAsyncRedirectVerifyHelper.cpp \
|
||||
nsAuthInformationHolder.cpp \
|
||||
nsBaseChannel.cpp \
|
||||
nsBaseContentStream.cpp \
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org networking code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Honza Bambas <honzab@firemni.cz>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsAsyncRedirectVerifyHelper.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#include "nsIOService.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsAsyncRedirectVerifyHelper, nsIRunnable)
|
||||
|
||||
nsresult
|
||||
nsAsyncRedirectVerifyHelper::Init(nsIChannel* oldChan, nsIChannel* newChan,
|
||||
PRUint32 flags, PRBool synchronize)
|
||||
{
|
||||
mOldChan = oldChan;
|
||||
mNewChan = newChan;
|
||||
mFlags = flags;
|
||||
|
||||
if (synchronize)
|
||||
mWaitingForRedirectCallback = PR_TRUE;
|
||||
|
||||
nsresult rv;
|
||||
rv = NS_DispatchToMainThread(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (synchronize) {
|
||||
nsIThread *thread = NS_GetCurrentThread();
|
||||
while (mWaitingForRedirectCallback) {
|
||||
if (!NS_ProcessNextEvent(thread)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsAsyncRedirectVerifyHelper::Callback(nsresult result)
|
||||
{
|
||||
// TODO E10S OnRedirectCallback has to be called on the original process
|
||||
nsCOMPtr<nsIAsyncVerifyRedirectCallback> callback(do_QueryInterface(mOldChan));
|
||||
NS_ASSERTION(callback, "nsAsyncRedirectVerifyHelper: oldChannel doesn't"
|
||||
" implement nsIAsyncVerifyRedirectCallback");
|
||||
|
||||
if (callback)
|
||||
callback->OnRedirectVerifyCallback(result);
|
||||
|
||||
mWaitingForRedirectCallback = PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncRedirectVerifyHelper::Run()
|
||||
{
|
||||
/* If the channel got canceled after it fired AsyncOnChannelRedirect
|
||||
* (bug 546606) and before we got here, mostly because docloader
|
||||
* load has been canceled, we must completely ignore this notification
|
||||
* and prevent any further notification.
|
||||
*
|
||||
* TODO Bug 546606, this must be checked before every single call!
|
||||
*/
|
||||
PRBool canceled;
|
||||
nsCOMPtr<nsIHttpChannelInternal> oldChannelInternal =
|
||||
do_QueryInterface(mOldChan);
|
||||
if (oldChannelInternal) {
|
||||
oldChannelInternal->GetCanceled(&canceled);
|
||||
if (canceled) {
|
||||
Callback(NS_BINDING_ABORTED);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// First, the global observer
|
||||
NS_ASSERTION(gIOService, "Must have an IO service at this point");
|
||||
nsresult rv = gIOService->OnChannelRedirect(mOldChan, mNewChan, mFlags);
|
||||
if (NS_FAILED(rv)) {
|
||||
Callback(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now, the per-channel observers
|
||||
nsCOMPtr<nsIChannelEventSink> sink;
|
||||
NS_QueryNotificationCallbacks(mOldChan, sink);
|
||||
if (sink)
|
||||
rv = sink->OnChannelRedirect(mOldChan, mNewChan, mFlags);
|
||||
|
||||
Callback(rv);
|
||||
return NS_OK;
|
||||
}
|
|
@ -47,6 +47,7 @@
|
|||
#include "nsIStreamConverterService.h"
|
||||
#include "nsIContentSniffer.h"
|
||||
#include "nsChannelClassifier.h"
|
||||
#include "nsAsyncRedirectVerifyHelper.h"
|
||||
|
||||
static PLDHashOperator
|
||||
CopyProperties(const nsAString &key, nsIVariant *data, void *closure)
|
||||
|
@ -115,49 +116,60 @@ nsBaseChannel::Redirect(nsIChannel *newChannel, PRUint32 redirectFlags,
|
|||
// we support nsIHttpEventSink if we are an HTTP channel and if this is not
|
||||
// an internal redirect.
|
||||
|
||||
// Global observers. These come first so that other observers don't see
|
||||
// redirects that get aborted for security reasons anyway.
|
||||
NS_ASSERTION(gIOService, "Must have an IO service");
|
||||
nsresult rv = gIOService->OnChannelRedirect(this, newChannel, redirectFlags);
|
||||
nsRefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
|
||||
new nsAsyncRedirectVerifyHelper();
|
||||
|
||||
PRBool checkRedirectSynchronously = !openNewChannel;
|
||||
|
||||
mRedirectChannel = newChannel;
|
||||
mRedirectFlags = redirectFlags;
|
||||
mOpenRedirectChannel = openNewChannel;
|
||||
nsresult rv = redirectCallbackHelper->Init(this, newChannel, redirectFlags,
|
||||
checkRedirectSynchronously);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (checkRedirectSynchronously && NS_FAILED(mStatus))
|
||||
return mStatus;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBaseChannel::ContinueRedirect()
|
||||
{
|
||||
// Backwards compat for non-internal redirects from a HTTP channel.
|
||||
if (!(redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
|
||||
// XXX Is our http channel implementation going to derive from nsBaseChannel?
|
||||
// If not, this code can be removed.
|
||||
if (!(mRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface();
|
||||
if (httpChannel) {
|
||||
nsCOMPtr<nsIHttpEventSink> httpEventSink;
|
||||
GetCallback(httpEventSink);
|
||||
if (httpEventSink) {
|
||||
rv = httpEventSink->OnRedirect(httpChannel, newChannel);
|
||||
if (NS_FAILED(rv))
|
||||
nsresult rv = httpEventSink->OnRedirect(httpChannel, mRedirectChannel);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannelEventSink> channelEventSink;
|
||||
// Give our consumer a chance to observe/block this redirect.
|
||||
GetCallback(channelEventSink);
|
||||
if (channelEventSink) {
|
||||
rv = channelEventSink->OnChannelRedirect(this, newChannel, redirectFlags);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Make sure to do this _after_ making all the OnChannelRedirect calls
|
||||
newChannel->SetOriginalURI(OriginalURI());
|
||||
mRedirectChannel->SetOriginalURI(OriginalURI());
|
||||
|
||||
// If we fail to open the new channel, then we want to leave this channel
|
||||
// unaffected, so we defer tearing down our channel until we have succeeded
|
||||
// with the redirect.
|
||||
|
||||
if (openNewChannel) {
|
||||
rv = newChannel->AsyncOpen(mListener, mListenerContext);
|
||||
if (mOpenRedirectChannel) {
|
||||
nsresult rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
||||
mRedirectChannel = nsnull;
|
||||
|
||||
// close down this channel
|
||||
Cancel(NS_BINDING_REDIRECTED);
|
||||
mListener = nsnull;
|
||||
|
@ -256,20 +268,30 @@ void
|
|||
nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel)
|
||||
{
|
||||
NS_ASSERTION(!mPump, "Shouldn't have gotten here");
|
||||
PRBool doNotify = PR_TRUE;
|
||||
|
||||
nsresult rv = mStatus;
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
nsresult rv = Redirect(newChannel,
|
||||
rv = Redirect(newChannel,
|
||||
nsIChannelEventSink::REDIRECT_TEMPORARY,
|
||||
PR_TRUE);
|
||||
if (NS_FAILED(rv))
|
||||
Cancel(rv);
|
||||
else
|
||||
doNotify = PR_FALSE;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// OnRedirectVerifyCallback will be called asynchronously
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContinueHandleAsyncRedirect(rv);
|
||||
}
|
||||
|
||||
void
|
||||
nsBaseChannel::ContinueHandleAsyncRedirect(nsresult result)
|
||||
{
|
||||
mWaitingOnAsyncRedirect = PR_FALSE;
|
||||
|
||||
if (doNotify) {
|
||||
if (NS_FAILED(result))
|
||||
Cancel(result);
|
||||
|
||||
if (NS_FAILED(result) && mListener) {
|
||||
// Notify our consumer ourselves
|
||||
mListener->OnStartRequest(this, mListenerContext);
|
||||
mListener->OnStopRequest(this, mListenerContext, mStatus);
|
||||
|
@ -306,14 +328,15 @@ nsBaseChannel::ClassifyURI()
|
|||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsISupports
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED6(nsBaseChannel,
|
||||
NS_IMPL_ISUPPORTS_INHERITED7(nsBaseChannel,
|
||||
nsHashPropertyBag,
|
||||
nsIRequest,
|
||||
nsIChannel,
|
||||
nsIInterfaceRequestor,
|
||||
nsITransportEventSink,
|
||||
nsIRequestObserver,
|
||||
nsIStreamListener)
|
||||
nsIStreamListener,
|
||||
nsIAsyncVerifyRedirectCallback)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsIRequest
|
||||
|
@ -738,3 +761,21 @@ nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
|||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::OnRedirectVerifyCallback(nsresult result)
|
||||
{
|
||||
if (NS_SUCCEEDED(result))
|
||||
result = ContinueRedirect();
|
||||
|
||||
if (NS_FAILED(result) && !mWaitingOnAsyncRedirect) {
|
||||
if (NS_SUCCEEDED(mStatus))
|
||||
mStatus = result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mWaitingOnAsyncRedirect)
|
||||
ContinueHandleAsyncRedirect(result);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsITransport.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -70,6 +71,7 @@ class nsBaseChannel : public nsHashPropertyBag
|
|||
, public nsIChannel
|
||||
, public nsIInterfaceRequestor
|
||||
, public nsITransportEventSink
|
||||
, public nsIAsyncVerifyRedirectCallback
|
||||
, private nsIStreamListener
|
||||
{
|
||||
public:
|
||||
|
@ -78,6 +80,7 @@ public:
|
|||
NS_DECL_NSICHANNEL
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSITRANSPORTEVENTSINK
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||
|
||||
nsBaseChannel();
|
||||
|
||||
|
@ -246,6 +249,8 @@ private:
|
|||
// Handle an async redirect callback. This will only be called if we
|
||||
// returned success from AsyncOpen while posting a redirect runnable.
|
||||
void HandleAsyncRedirect(nsIChannel* newChannel);
|
||||
void ContinueHandleAsyncRedirect(nsresult result);
|
||||
nsresult ContinueRedirect();
|
||||
|
||||
// start URI classifier if requested
|
||||
void ClassifyURI();
|
||||
|
@ -281,6 +286,7 @@ private:
|
|||
nsCOMPtr<nsISupports> mSecurityInfo;
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsISupports> mListenerContext;
|
||||
nsCOMPtr<nsIChannel> mRedirectChannel;
|
||||
nsCString mContentType;
|
||||
nsCString mContentCharset;
|
||||
PRUint32 mLoadFlags;
|
||||
|
@ -289,6 +295,8 @@ private:
|
|||
PRPackedBool mSynthProgressEvents;
|
||||
PRPackedBool mWasOpened;
|
||||
PRPackedBool mWaitingOnAsyncRedirect;
|
||||
PRPackedBool mOpenRedirectChannel;
|
||||
PRUint32 mRedirectFlags;
|
||||
};
|
||||
|
||||
#endif // !nsBaseChannel_h__
|
||||
|
|
|
@ -55,6 +55,7 @@ HttpBaseChannel::HttpBaseChannel()
|
|||
, mPriority(PRIORITY_NORMAL)
|
||||
, mCaps(0)
|
||||
, mRedirectionLimit(gHttpHandler->RedirectionLimit())
|
||||
, mCanceled(PR_FALSE)
|
||||
, mIsPending(PR_FALSE)
|
||||
, mWasOpened(PR_FALSE)
|
||||
, mResponseHeadersModified(PR_FALSE)
|
||||
|
@ -919,6 +920,13 @@ HttpBaseChannel::SetForceAllowThirdPartyCookie(PRBool aForce)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::GetCanceled(PRBool *aCanceled)
|
||||
{
|
||||
*aCanceled = mCanceled;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HttpBaseChannel::nsISupportsPriority
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -161,6 +161,7 @@ public:
|
|||
NS_IMETHOD SetCookie(const char *aCookieHeader);
|
||||
NS_IMETHOD GetForceAllowThirdPartyCookie(PRBool *aForce);
|
||||
NS_IMETHOD SetForceAllowThirdPartyCookie(PRBool aForce);
|
||||
NS_IMETHOD GetCanceled(PRBool *aCanceled);
|
||||
|
||||
// nsISupportsPriority
|
||||
NS_IMETHOD GetPriority(PRInt32 *value);
|
||||
|
@ -205,12 +206,13 @@ protected:
|
|||
PRUint8 mCaps;
|
||||
PRUint8 mRedirectionLimit;
|
||||
|
||||
PRUint8 mCanceled : 1;
|
||||
PRUint8 mIsPending : 1;
|
||||
PRUint8 mWasOpened : 1;
|
||||
PRUint8 mResponseHeadersModified : 1;
|
||||
PRUint8 mAllowPipelining : 1;
|
||||
PRUint8 mForceAllowThirdPartyCookie : 1;
|
||||
PRUint32 mUploadStreamHasHeaders : 1;
|
||||
PRUint8 mUploadStreamHasHeaders : 1;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -92,7 +92,6 @@ nsHttpChannel::nsHttpChannel()
|
|||
, mApplyConversion(PR_TRUE)
|
||||
, mCachedContentIsValid(PR_FALSE)
|
||||
, mCachedContentIsPartial(PR_FALSE)
|
||||
, mCanceled(PR_FALSE)
|
||||
, mTransactionReplaced(PR_FALSE)
|
||||
, mAuthRetryPending(PR_FALSE)
|
||||
, mResuming(PR_FALSE)
|
||||
|
@ -105,6 +104,8 @@ nsHttpChannel::nsHttpChannel()
|
|||
, mLoadedFromApplicationCache(PR_FALSE)
|
||||
, mTracingEnabled(PR_TRUE)
|
||||
, mCustomConditionalRequest(PR_FALSE)
|
||||
, mFallingBack(PR_FALSE)
|
||||
, mWaitingForRedirectCallback(PR_FALSE)
|
||||
, mRemoteChannel(PR_FALSE)
|
||||
{
|
||||
LOG(("Creating nsHttpChannel [this=%p]\n", this));
|
||||
|
@ -299,6 +300,10 @@ nsHttpChannel::HandleAsyncNotifyListener()
|
|||
void
|
||||
nsHttpChannel::DoNotifyListener()
|
||||
{
|
||||
// Make sure mIsPending is set to PR_FALSE. At this moment we are done from
|
||||
// the point of view of our consumer and we have to report our self
|
||||
// as not-pending.
|
||||
mIsPending = PR_FALSE;
|
||||
if (mListener) {
|
||||
mListener->OnStartRequest(this, mListenerContext);
|
||||
mListener->OnStopRequest(this, mListenerContext, mStatus);
|
||||
|
@ -329,15 +334,28 @@ nsHttpChannel::HandleAsyncRedirect()
|
|||
// channel could have been canceled, in which case there would be no point
|
||||
// in processing the redirect.
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
rv = ProcessRedirection(mResponseHead->Status());
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncRedirect);
|
||||
rv = AsyncProcessRedirection(mResponseHead->Status());
|
||||
if (NS_FAILED(rv)) {
|
||||
// If ProcessRedirection fails, then we have to send out the
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncRedirect);
|
||||
ContinueHandleAsyncRedirect(rv);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ContinueHandleAsyncRedirect(NS_OK);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueHandleAsyncRedirect(nsresult rv)
|
||||
{
|
||||
if (NS_FAILED(rv)) {
|
||||
// If AsyncProcessRedirection fails, then we have to send out the
|
||||
// OnStart/OnStop notifications.
|
||||
LOG(("ProcessRedirection failed [rv=%x]\n", rv));
|
||||
LOG(("ContinueHandleAsyncRedirect got failure result [rv=%x]\n", rv));
|
||||
mStatus = rv;
|
||||
DoNotifyListener();
|
||||
}
|
||||
}
|
||||
|
||||
// close the cache entry. Blow it away if we couldn't process the redirect
|
||||
// for some reason (the cache entry might be corrupt).
|
||||
|
@ -351,6 +369,8 @@ nsHttpChannel::HandleAsyncRedirect()
|
|||
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -396,21 +416,34 @@ nsHttpChannel::HandleAsyncFallback()
|
|||
// channel could have been canceled, in which case there would be no point
|
||||
// in processing the fallback.
|
||||
if (!mCanceled) {
|
||||
PRBool fallingBack;
|
||||
rv = ProcessFallback(&fallingBack);
|
||||
if (NS_FAILED(rv) || !fallingBack) {
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncFallback);
|
||||
PRBool waitingForRedirectCallback;
|
||||
rv = ProcessFallback(&waitingForRedirectCallback);
|
||||
if (waitingForRedirectCallback)
|
||||
return;
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncFallback);
|
||||
}
|
||||
|
||||
ContinueHandleAsyncFallback(rv);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueHandleAsyncFallback(nsresult rv)
|
||||
{
|
||||
if (!mCanceled && (NS_FAILED(rv) || !mFallingBack)) {
|
||||
// If ProcessFallback fails, then we have to send out the
|
||||
// OnStart/OnStop notifications.
|
||||
LOG(("ProcessFallback failed [rv=%x, %d]\n", rv, fallingBack));
|
||||
LOG(("ProcessFallback failed [rv=%x, %d]\n", rv, mFallingBack));
|
||||
mStatus = NS_FAILED(rv) ? rv : NS_ERROR_DOCUMENT_NOT_CACHED;
|
||||
DoNotifyListener();
|
||||
}
|
||||
}
|
||||
|
||||
mIsPending = PR_FALSE;
|
||||
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -891,22 +924,12 @@ nsHttpChannel::ProcessResponse()
|
|||
#endif
|
||||
// don't store the response body for redirects
|
||||
MaybeInvalidateCacheEntryForSubsequentGet();
|
||||
rv = ProcessRedirection(httpStatus);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
InitCacheEntry();
|
||||
CloseCacheEntry(PR_FALSE);
|
||||
|
||||
if (mCacheForOfflineUse) {
|
||||
// Store response in the offline cache
|
||||
InitOfflineCacheEntry();
|
||||
CloseOfflineCacheEntry();
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG(("ProcessRedirection failed [rv=%x]\n", rv));
|
||||
if (mTransaction->SSLConnectFailed())
|
||||
return ProcessFailedSSLConnect(httpStatus);
|
||||
rv = ProcessNormal();
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessResponse);
|
||||
rv = AsyncProcessRedirection(httpStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueProcessResponse);
|
||||
LOG(("AsyncProcessRedirection failed [rv=%x]\n", rv));
|
||||
rv = ContinueProcessResponse(rv);
|
||||
}
|
||||
break;
|
||||
case 304:
|
||||
|
@ -953,6 +976,28 @@ nsHttpChannel::ProcessResponse()
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueProcessResponse(nsresult rv)
|
||||
{
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
InitCacheEntry();
|
||||
CloseCacheEntry(PR_FALSE);
|
||||
|
||||
if (mCacheForOfflineUse) {
|
||||
// Store response in the offline cache
|
||||
InitOfflineCacheEntry();
|
||||
CloseOfflineCacheEntry();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
LOG(("ContinueProcessResponse got failure result [rv=%x]\n", rv));
|
||||
if (mTransaction->SSLConnectFailed()) {
|
||||
return ProcessFailedSSLConnect(mRedirectType);
|
||||
}
|
||||
return ProcessNormal();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ProcessNormal()
|
||||
{
|
||||
|
@ -963,19 +1008,35 @@ nsHttpChannel::ProcessNormal()
|
|||
PRBool succeeded;
|
||||
rv = GetRequestSucceeded(&succeeded);
|
||||
if (NS_SUCCEEDED(rv) && !succeeded) {
|
||||
PRBool fallingBack;
|
||||
rv = ProcessFallback(&fallingBack);
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessNormal);
|
||||
PRBool waitingForRedirectCallback;
|
||||
rv = ProcessFallback(&waitingForRedirectCallback);
|
||||
if (waitingForRedirectCallback) {
|
||||
// The transaction has been suspended by ProcessFallback.
|
||||
return NS_OK;
|
||||
}
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueProcessNormal);
|
||||
}
|
||||
|
||||
return ContinueProcessNormal(NS_OK);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueProcessNormal(nsresult rv)
|
||||
{
|
||||
if (NS_FAILED(rv)) {
|
||||
// Fill the failure status here, we have failed to fall back, thus we
|
||||
// have to report our status as failed.
|
||||
mStatus = rv;
|
||||
DoNotifyListener();
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (fallingBack) {
|
||||
if (mFallingBack) {
|
||||
// Do not continue with normal processing, fallback is in
|
||||
// progress now.
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// if we're here, then any byte-range requests failed to result in a partial
|
||||
// response. we must clear this flag to prevent BufferPartialContent from
|
||||
|
@ -1086,7 +1147,7 @@ nsHttpChannel::ProxyFailover()
|
|||
|
||||
// XXXbz so where does this codepath remove us from the loadgroup,
|
||||
// exactly?
|
||||
return DoReplaceWithProxy(pi);
|
||||
return AsyncDoReplaceWithProxy(pi);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1107,21 +1168,41 @@ nsHttpChannel::HandleAsyncReplaceWithProxy()
|
|||
nsCOMPtr<nsIProxyInfo> pi;
|
||||
pi.swap(mTargetProxyInfo);
|
||||
if (!mCanceled) {
|
||||
status = DoReplaceWithProxy(pi);
|
||||
if (mLoadGroup && NS_SUCCEEDED(status)) {
|
||||
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
|
||||
}
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncReplaceWithProxy);
|
||||
status = AsyncDoReplaceWithProxy(pi);
|
||||
if (NS_SUCCEEDED(status))
|
||||
return;
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncReplaceWithProxy);
|
||||
}
|
||||
|
||||
if (NS_FAILED(status)) {
|
||||
AsyncAbort(status);
|
||||
ContinueHandleAsyncReplaceWithProxy(status);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::DoReplaceWithProxy(nsIProxyInfo* pi)
|
||||
nsHttpChannel::ContinueHandleAsyncReplaceWithProxy(nsresult status)
|
||||
{
|
||||
LOG(("nsHttpChannel::DoReplaceWithProxy [this=%p pi=%p]", this, pi));
|
||||
if (mLoadGroup && NS_SUCCEEDED(status)) {
|
||||
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
|
||||
}
|
||||
else if (NS_FAILED(status)) {
|
||||
AsyncAbort(status);
|
||||
}
|
||||
|
||||
// Return NS_OK here, even it seems to be breaking the async function stack
|
||||
// contract (i.e. passing the result code to a function bellow).
|
||||
// ContinueHandleAsyncReplaceWithProxy will always be at the bottom of the
|
||||
// stack. If we would return the failure code, the async function stack
|
||||
// logic would cancel the channel synchronously, which is undesired after
|
||||
// invoking AsyncAbort above.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::AsyncDoReplaceWithProxy(nsIProxyInfo* pi)
|
||||
{
|
||||
LOG(("nsHttpChannel::AsyncDoReplaceWithProxy [this=%p pi=%p]", this, pi));
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
|
@ -1134,16 +1215,37 @@ nsHttpChannel::DoReplaceWithProxy(nsIProxyInfo* pi)
|
|||
return rv;
|
||||
|
||||
// Inform consumers about this fake redirect
|
||||
mRedirectChannel = newChannel;
|
||||
PRUint32 flags = nsIChannelEventSink::REDIRECT_INTERNAL;
|
||||
rv = gHttpHandler->OnChannelRedirect(this, newChannel, flags);
|
||||
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueDoReplaceWithProxy);
|
||||
rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, flags);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = WaitForRedirectCallback();
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueDoReplaceWithProxy);
|
||||
mRedirectChannel = nsnull;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueDoReplaceWithProxy(nsresult rv)
|
||||
{
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
NS_PRECONDITION(mRedirectChannel, "No redirect channel?");
|
||||
|
||||
// Make sure to do this _after_ calling OnChannelRedirect
|
||||
newChannel->SetOriginalURI(mOriginalURI);
|
||||
mRedirectChannel->SetOriginalURI(mOriginalURI);
|
||||
|
||||
// open new channel
|
||||
rv = newChannel->AsyncOpen(mListener, mListenerContext);
|
||||
rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
|
||||
mRedirectChannel = nsnull;
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
@ -1405,12 +1507,13 @@ nsHttpChannel::ProcessNotModified()
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ProcessFallback(PRBool *fallingBack)
|
||||
nsHttpChannel::ProcessFallback(PRBool *waitingForRedirectCallback)
|
||||
{
|
||||
LOG(("nsHttpChannel::ProcessFallback [this=%p]\n", this));
|
||||
nsresult rv;
|
||||
|
||||
*fallingBack = PR_FALSE;
|
||||
*waitingForRedirectCallback = PR_FALSE;
|
||||
mFallingBack = PR_FALSE;
|
||||
|
||||
// At this point a load has failed (either due to network problems
|
||||
// or an error returned on the server). Perform an application
|
||||
|
@ -1475,15 +1578,40 @@ nsHttpChannel::ProcessFallback(PRBool *fallingBack)
|
|||
rv = newChannel->SetLoadFlags(newLoadFlags);
|
||||
|
||||
// Inform consumers about this fake redirect
|
||||
mRedirectChannel = newChannel;
|
||||
PRUint32 redirectFlags = nsIChannelEventSink::REDIRECT_INTERNAL;
|
||||
rv = gHttpHandler->OnChannelRedirect(this, newChannel, redirectFlags);
|
||||
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessFallback);
|
||||
rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, redirectFlags);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = WaitForRedirectCallback();
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueProcessFallback);
|
||||
mRedirectChannel = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Indicate we are now waiting for the asynchronous redirect callback
|
||||
// if all went OK.
|
||||
*waitingForRedirectCallback = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueProcessFallback(nsresult rv)
|
||||
{
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Make sure to do this _after_ calling OnChannelRedirect
|
||||
newChannel->SetOriginalURI(mOriginalURI);
|
||||
NS_PRECONDITION(mRedirectChannel, "No redirect channel?");
|
||||
|
||||
rv = newChannel->AsyncOpen(mListener, mListenerContext);
|
||||
// Make sure to do this _after_ calling OnChannelRedirect
|
||||
mRedirectChannel->SetOriginalURI(mOriginalURI);
|
||||
|
||||
rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
|
||||
mRedirectChannel = nsnull;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// close down this channel
|
||||
|
@ -1496,7 +1624,7 @@ nsHttpChannel::ProcessFallback(PRBool *fallingBack)
|
|||
mCallbacks = nsnull;
|
||||
mProgressSink = nsnull;
|
||||
|
||||
*fallingBack = PR_TRUE;
|
||||
mFallingBack = PR_TRUE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2768,9 +2896,9 @@ nsHttpChannel::SetupReplacementChannel(nsIURI *newURI,
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
|
||||
nsHttpChannel::AsyncProcessRedirection(PRUint32 redirectType)
|
||||
{
|
||||
LOG(("nsHttpChannel::ProcessRedirection [this=%p type=%u]\n",
|
||||
LOG(("nsHttpChannel::AsyncProcessRedirection [this=%p type=%u]\n",
|
||||
this, redirectType));
|
||||
|
||||
const char *location = mResponseHead->PeekHeader(nsHttp::Location);
|
||||
|
@ -2792,12 +2920,12 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
|
|||
return NS_ERROR_REDIRECT_LOOP;
|
||||
}
|
||||
|
||||
mRedirectType = redirectType;
|
||||
|
||||
LOG(("redirecting to: %s [redirection-limit=%u]\n",
|
||||
location, PRUint32(mRedirectionLimit)));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
|
||||
// create a new URI using the location header and the current URL
|
||||
// as a base...
|
||||
|
@ -2811,36 +2939,49 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
|
|||
if (NS_FAILED(rv))
|
||||
originCharset.Truncate();
|
||||
|
||||
rv = ioService->NewURI(nsDependentCString(location), originCharset.get(), mURI,
|
||||
getter_AddRefs(newURI));
|
||||
rv = ioService->NewURI(nsDependentCString(location),
|
||||
originCharset.get(),
|
||||
mURI,
|
||||
getter_AddRefs(mRedirectURI));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (mApplicationCache) {
|
||||
// if we are redirected to a different origin check if there is a fallback
|
||||
// cache entry to fall back to. we don't care about file strict
|
||||
// checking, at least mURI is not a file URI.
|
||||
if (!NS_SecurityCompareURIs(mURI, newURI, PR_FALSE)) {
|
||||
PRBool fallingBack;
|
||||
rv = ProcessFallback(&fallingBack);
|
||||
if (NS_SUCCEEDED(rv) && fallingBack) {
|
||||
if (!NS_SecurityCompareURIs(mURI, mRedirectURI, PR_FALSE)) {
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessRedirectionAfterFallback);
|
||||
PRBool waitingForRedirectCallback;
|
||||
rv = ProcessFallback(&waitingForRedirectCallback);
|
||||
if (waitingForRedirectCallback)
|
||||
return NS_OK;
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueProcessRedirectionAfterFallback);
|
||||
}
|
||||
}
|
||||
|
||||
return ContinueProcessRedirectionAfterFallback(NS_OK);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueProcessRedirectionAfterFallback(nsresult rv)
|
||||
{
|
||||
if (NS_SUCCEEDED(rv) && mFallingBack) {
|
||||
// do not continue with redirect processing, fallback is in
|
||||
// progress now.
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kill the current cache entry if we are redirecting
|
||||
// back to ourself.
|
||||
PRBool redirectingBackToSameURI = PR_FALSE;
|
||||
if (mCacheEntry && (mCacheAccess & nsICache::ACCESS_WRITE) &&
|
||||
NS_SUCCEEDED(mURI->Equals(newURI, &redirectingBackToSameURI)) &&
|
||||
NS_SUCCEEDED(mURI->Equals(mRedirectURI, &redirectingBackToSameURI)) &&
|
||||
redirectingBackToSameURI)
|
||||
mCacheEntry->Doom();
|
||||
|
||||
// move the reference of the old location to the new one if the new
|
||||
// one has none.
|
||||
nsCOMPtr<nsIURL> newURL = do_QueryInterface(newURI);
|
||||
nsCOMPtr<nsIURL> newURL = do_QueryInterface(mRedirectURI);
|
||||
if (newURL) {
|
||||
nsCAutoString ref;
|
||||
rv = newURL->GetRef(ref);
|
||||
|
@ -2855,31 +2996,56 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
|
|||
}
|
||||
|
||||
// if we need to re-send POST data then be sure to ask the user first.
|
||||
PRBool preserveMethod = (redirectType == 307);
|
||||
PRBool preserveMethod = (mRedirectType == 307);
|
||||
if (preserveMethod && mUploadStream) {
|
||||
rv = PromptTempRedirect();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
rv = ioService->NewChannelFromURI(newURI, getter_AddRefs(newChannel));
|
||||
nsCOMPtr<nsIIOService> ioService;
|
||||
rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = SetupReplacementChannel(newURI, newChannel, preserveMethod);
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
rv = ioService->NewChannelFromURI(mRedirectURI, getter_AddRefs(newChannel));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = SetupReplacementChannel(mRedirectURI, newChannel, preserveMethod);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 redirectFlags;
|
||||
if (redirectType == 301) // Moved Permanently
|
||||
if (mRedirectType == 301) // Moved Permanently
|
||||
redirectFlags = nsIChannelEventSink::REDIRECT_PERMANENT;
|
||||
else
|
||||
redirectFlags = nsIChannelEventSink::REDIRECT_TEMPORARY;
|
||||
|
||||
// verify that this is a legal redirect
|
||||
rv = gHttpHandler->OnChannelRedirect(this, newChannel, redirectFlags);
|
||||
mRedirectChannel = newChannel;
|
||||
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessRedirection);
|
||||
rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, redirectFlags);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = WaitForRedirectCallback();
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueProcessRedirection);
|
||||
mRedirectChannel = nsnull;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueProcessRedirection(nsresult rv)
|
||||
{
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
NS_PRECONDITION(mRedirectChannel, "No redirect channel?");
|
||||
|
||||
// Make sure to do this _after_ calling OnChannelRedirect
|
||||
newChannel->SetOriginalURI(mOriginalURI);
|
||||
mRedirectChannel->SetOriginalURI(mOriginalURI);
|
||||
|
||||
// And now, the deprecated way
|
||||
nsCOMPtr<nsIHttpEventSink> httpEventSink;
|
||||
|
@ -2887,15 +3053,19 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
|
|||
if (httpEventSink) {
|
||||
// NOTE: nsIHttpEventSink is only used for compatibility with pre-1.8
|
||||
// versions.
|
||||
rv = httpEventSink->OnRedirect(this, newChannel);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = httpEventSink->OnRedirect(this, mRedirectChannel);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
// XXX we used to talk directly with the script security manager, but that
|
||||
// should really be handled by the event sink implementation.
|
||||
|
||||
// begin loading the new channel
|
||||
rv = newChannel->AsyncOpen(mListener, mListenerContext);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
|
||||
mRedirectChannel = nsnull;
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// close down this channel
|
||||
Cancel(NS_BINDING_REDIRECTED);
|
||||
|
@ -2978,6 +3148,7 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
|
|||
NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
|
||||
NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -2992,6 +3163,9 @@ nsHttpChannel::Cancel(nsresult status)
|
|||
LOG((" ignoring; already canceled\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
if (mWaitingForRedirectCallback) {
|
||||
LOG(("channel canceled during wait for redirect callback"));
|
||||
}
|
||||
mCanceled = PR_TRUE;
|
||||
mStatus = status;
|
||||
if (mProxyRequest)
|
||||
|
@ -3400,19 +3574,49 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
(mStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
|
||||
mStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
|
||||
mStatus == NS_ERROR_NET_TIMEOUT)) {
|
||||
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueOnStartRequest1);
|
||||
if (NS_SUCCEEDED(ProxyFailover()))
|
||||
return NS_OK;
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueOnStartRequest1);
|
||||
}
|
||||
|
||||
// on other request errors, try to fall back
|
||||
PRBool fallingBack;
|
||||
if (NS_FAILED(mStatus) &&
|
||||
NS_SUCCEEDED(ProcessFallback(&fallingBack)) &&
|
||||
fallingBack) {
|
||||
return ContinueOnStartRequest2(NS_OK);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueOnStartRequest1(nsresult result)
|
||||
{
|
||||
// Success indicates we passed ProxyFailover, in that case we must not continue
|
||||
// with this code chain.
|
||||
if (NS_SUCCEEDED(result))
|
||||
return NS_OK;
|
||||
|
||||
return ContinueOnStartRequest2(result);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueOnStartRequest2(nsresult result)
|
||||
{
|
||||
// on other request errors, try to fall back
|
||||
if (NS_FAILED(mStatus)) {
|
||||
PushRedirectAsyncFunc(&nsHttpChannel::ContinueOnStartRequest3);
|
||||
PRBool waitingForRedirectCallback;
|
||||
nsresult rv = ProcessFallback(&waitingForRedirectCallback);
|
||||
if (waitingForRedirectCallback)
|
||||
return NS_OK;
|
||||
PopRedirectAsyncFunc(&nsHttpChannel::ContinueOnStartRequest3);
|
||||
}
|
||||
|
||||
return ContinueOnStartRequest3(NS_OK);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::ContinueOnStartRequest3(nsresult result)
|
||||
{
|
||||
if (mFallingBack)
|
||||
return NS_OK;
|
||||
|
||||
return CallOnStartRequest();
|
||||
}
|
||||
|
||||
|
@ -4126,6 +4330,98 @@ nsHttpChannel::SetChooseApplicationCache(PRBool aChoose)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsIAsyncVerifyRedirectCallback
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::WaitForRedirectCallback()
|
||||
{
|
||||
nsresult rv;
|
||||
if (mTransactionPump) {
|
||||
rv = mTransactionPump->Suspend();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
if (mCachePump) {
|
||||
rv = mCachePump->Suspend();
|
||||
if (NS_FAILED(rv) && mTransactionPump) {
|
||||
nsresult resume = mTransactionPump->Resume();
|
||||
NS_ASSERTION(NS_SUCCEEDED(resume),
|
||||
"Failed to resume transaction pump");
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mWaitingForRedirectCallback = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::OnRedirectVerifyCallback(nsresult result)
|
||||
{
|
||||
NS_ASSERTION(mWaitingForRedirectCallback,
|
||||
"Someone forgot to call WaitForRedirectCallback() ?!");
|
||||
mWaitingForRedirectCallback = PR_FALSE;
|
||||
|
||||
if (mCanceled && NS_SUCCEEDED(result))
|
||||
result = NS_BINDING_ABORTED;
|
||||
|
||||
for (PRUint32 i = mRedirectFuncStack.Length(); i > 0;) {
|
||||
--i;
|
||||
// Pop the last function pushed to the stack
|
||||
nsContinueRedirectionFunc func = mRedirectFuncStack[i];
|
||||
mRedirectFuncStack.RemoveElementAt(mRedirectFuncStack.Length() - 1);
|
||||
|
||||
// Call it with the result we got from the callback or the deeper
|
||||
// function call.
|
||||
result = (this->*func)(result);
|
||||
|
||||
// If a new function has been pushed to the stack and placed us in the
|
||||
// waiting state, we need to break the chain and wait for the callback
|
||||
// again.
|
||||
if (mWaitingForRedirectCallback)
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_FAILED(result) && !mCanceled) {
|
||||
// First, cancel this channel if we are in failure state to set mStatus
|
||||
// and let it be propagated to pumps.
|
||||
Cancel(result);
|
||||
}
|
||||
|
||||
if (!mWaitingForRedirectCallback) {
|
||||
// We are not waiting for the callback. At this moment we must release
|
||||
// reference to the redirect target channel, otherwise we may leak.
|
||||
mRedirectChannel = nsnull;
|
||||
}
|
||||
|
||||
// We always resume the pumps here. If all functions on stack have been
|
||||
// called we need OnStopRequest to be triggered, and if we broke out of the
|
||||
// loop above (and are thus waiting for a new callback) the suspension
|
||||
// count must be balanced in the pumps.
|
||||
if (mTransactionPump)
|
||||
mTransactionPump->Resume();
|
||||
if (mCachePump)
|
||||
mCachePump->Resume();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpChannel::PushRedirectAsyncFunc(nsContinueRedirectionFunc func)
|
||||
{
|
||||
mRedirectFuncStack.AppendElement(func);
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpChannel::PopRedirectAsyncFunc(nsContinueRedirectionFunc func)
|
||||
{
|
||||
NS_ASSERTION(func == mRedirectFuncStack[mRedirectFuncStack.Length() - 1],
|
||||
"Trying to pop wrong method from redirect async stack!");
|
||||
|
||||
mRedirectFuncStack.TruncateLength(mRedirectFuncStack.Length() - 1);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsContentEncodings <public>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "nsHttpTransaction.h"
|
||||
#include "nsInputStreamPump.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "nsIHttpEventSink.h"
|
||||
#include "nsICachingChannel.h"
|
||||
|
@ -64,6 +65,7 @@
|
|||
#include "nsIHttpAuthenticableChannel.h"
|
||||
#include "nsITraceableChannel.h"
|
||||
#include "nsIHttpChannelAuthProvider.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
|
||||
class nsAHttpConnection;
|
||||
|
||||
|
@ -84,6 +86,7 @@ class nsHttpChannel : public HttpBaseChannel
|
|||
, public nsIHttpAuthenticableChannel
|
||||
, public nsITraceableChannel
|
||||
, public nsIApplicationCacheChannel
|
||||
, public nsIAsyncVerifyRedirectCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -100,6 +103,7 @@ public:
|
|||
NS_DECL_NSITRACEABLECHANNEL
|
||||
NS_DECL_NSIAPPLICATIONCACHECONTAINER
|
||||
NS_DECL_NSIAPPLICATIONCACHECHANNEL
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||
|
||||
// nsIHttpAuthenticableChannel. We can't use
|
||||
// NS_DECL_NSIHTTPAUTHENTICABLECHANNEL because it duplicates cancel() and
|
||||
|
@ -160,6 +164,8 @@ public: /* internal necko use only */
|
|||
}
|
||||
|
||||
private:
|
||||
typedef nsresult (nsHttpChannel::*nsContinueRedirectionFunc)(nsresult result);
|
||||
|
||||
// AsyncCall may be used to call a member function asynchronously.
|
||||
// retval isn't refcounted and is set only when event was successfully
|
||||
// posted, the event is returned for the purpose of cancelling when needed
|
||||
|
@ -176,25 +182,38 @@ private:
|
|||
nsresult ApplyContentConversions();
|
||||
nsresult CallOnStartRequest();
|
||||
nsresult ProcessResponse();
|
||||
nsresult ContinueProcessResponse(nsresult);
|
||||
nsresult ProcessNormal();
|
||||
nsresult ContinueProcessNormal(nsresult);
|
||||
nsresult ProcessNotModified();
|
||||
nsresult ProcessRedirection(PRUint32 httpStatus);
|
||||
nsresult AsyncProcessRedirection(PRUint32 httpStatus);
|
||||
nsresult ContinueProcessRedirection(nsresult);
|
||||
nsresult ContinueProcessRedirectionAfterFallback(nsresult);
|
||||
PRBool ShouldSSLProxyResponseContinue(PRUint32 httpStatus);
|
||||
nsresult ProcessFailedSSLConnect(PRUint32 httpStatus);
|
||||
nsresult ProcessFallback(PRBool *fallingBack);
|
||||
nsresult ProcessFallback(PRBool *waitingForRedirectCallback);
|
||||
nsresult ContinueProcessFallback(nsresult);
|
||||
PRBool ResponseWouldVary();
|
||||
|
||||
nsresult ContinueOnStartRequest1(nsresult);
|
||||
nsresult ContinueOnStartRequest2(nsresult);
|
||||
nsresult ContinueOnStartRequest3(nsresult);
|
||||
|
||||
// redirection specific methods
|
||||
void HandleAsyncRedirect();
|
||||
nsresult ContinueHandleAsyncRedirect(nsresult);
|
||||
void HandleAsyncNotModified();
|
||||
void HandleAsyncFallback();
|
||||
nsresult ContinueHandleAsyncFallback(nsresult);
|
||||
nsresult PromptTempRedirect();
|
||||
nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, PRBool preserveMethod);
|
||||
|
||||
// proxy specific methods
|
||||
nsresult ProxyFailover();
|
||||
nsresult DoReplaceWithProxy(nsIProxyInfo *);
|
||||
nsresult AsyncDoReplaceWithProxy(nsIProxyInfo *);
|
||||
nsresult ContinueDoReplaceWithProxy(nsresult);
|
||||
void HandleAsyncReplaceWithProxy();
|
||||
nsresult ContinueHandleAsyncReplaceWithProxy(nsresult);
|
||||
nsresult ResolveProxy();
|
||||
|
||||
// cache specific methods
|
||||
|
@ -276,11 +295,14 @@ private:
|
|||
// cache entry.
|
||||
nsCString mFallbackKey;
|
||||
|
||||
nsCOMPtr<nsIURI> mRedirectURI;
|
||||
nsCOMPtr<nsIChannel> mRedirectChannel;
|
||||
PRUint32 mRedirectType;
|
||||
|
||||
// state flags
|
||||
PRUint32 mApplyConversion : 1;
|
||||
PRUint32 mCachedContentIsValid : 1;
|
||||
PRUint32 mCachedContentIsPartial : 1;
|
||||
PRUint32 mCanceled : 1;
|
||||
PRUint32 mTransactionReplaced : 1;
|
||||
PRUint32 mAuthRetryPending : 1;
|
||||
PRUint32 mResuming : 1;
|
||||
|
@ -300,6 +322,8 @@ private:
|
|||
// headers. In such a case we must not override them in the cache code
|
||||
// and also we want to pass possible 304 code response through.
|
||||
PRUint32 mCustomConditionalRequest : 1;
|
||||
PRUint32 mFallingBack : 1;
|
||||
PRUint32 mWaitingForRedirectCallback : 1;
|
||||
// True iff this channel is servicing a remote HttpChannelChild
|
||||
PRUint32 mRemoteChannel : 1;
|
||||
|
||||
|
@ -326,6 +350,12 @@ private:
|
|||
|
||||
PRPackedBool mReady;
|
||||
};
|
||||
|
||||
nsTArray<nsContinueRedirectionFunc> mRedirectFuncStack;
|
||||
|
||||
nsresult WaitForRedirectCallback();
|
||||
void PushRedirectAsyncFunc(nsContinueRedirectionFunc func);
|
||||
void PopRedirectAsyncFunc(nsContinueRedirectionFunc func);
|
||||
};
|
||||
|
||||
#endif // nsHttpChannel_h__
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
#include "nsQuickSort.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIOService.h"
|
||||
#include "nsAsyncRedirectVerifyHelper.h"
|
||||
|
||||
#include "nsIXULAppInfo.h"
|
||||
|
||||
|
@ -530,22 +531,14 @@ nsHttpHandler::NotifyObservers(nsIHttpChannel *chan, const char *event)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsHttpHandler::OnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
||||
nsHttpHandler::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
||||
PRUint32 flags)
|
||||
{
|
||||
// First, the global observer
|
||||
NS_ASSERTION(gIOService, "Must have an IO service at this point");
|
||||
nsresult rv = gIOService->OnChannelRedirect(oldChan, newChan, flags);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
// TODO E10S This helper has to be initialized on the other process
|
||||
nsRefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
|
||||
new nsAsyncRedirectVerifyHelper();
|
||||
|
||||
// Now, the per-channel observers
|
||||
nsCOMPtr<nsIChannelEventSink> sink;
|
||||
NS_QueryNotificationCallbacks(oldChan, sink);
|
||||
if (sink)
|
||||
rv = sink->OnChannelRedirect(oldChan, newChan, flags);
|
||||
|
||||
return rv;
|
||||
return redirectCallbackHelper->Init(oldChan, newChan, flags);
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
|
|
|
@ -195,7 +195,7 @@ public:
|
|||
|
||||
// Called by channels before a redirect happens. This notifies both the
|
||||
// channel's and the global redirect observers.
|
||||
nsresult OnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
||||
nsresult AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
||||
PRUint32 flags);
|
||||
|
||||
// Called by the channel when the response is read from the cache without
|
||||
|
|
|
@ -45,7 +45,7 @@ interface nsIProxyInfo;
|
|||
* using any feature exposed by this interface, be aware that this interface
|
||||
* will change and you will be broken. You have been warned.
|
||||
*/
|
||||
[scriptable, uuid(0eb66361-faaa-4e52-8c7e-6c25f11f8e3c)]
|
||||
[scriptable, uuid(91dbb42a-dffc-4f47-8b27-9579c0d92c3f)]
|
||||
interface nsIHttpChannelInternal : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -83,4 +83,9 @@ interface nsIHttpChannelInternal : nsISupports
|
|||
* wouldn't be.
|
||||
*/
|
||||
attribute boolean forceAllowThirdPartyCookie;
|
||||
|
||||
/**
|
||||
* Returns true iff the channel has been canceled.
|
||||
*/
|
||||
readonly attribute boolean canceled;
|
||||
};
|
||||
|
|
|
@ -66,8 +66,14 @@ ChannelListener.prototype = {
|
|||
this._got_onstartrequest = true;
|
||||
|
||||
request.QueryInterface(Components.interfaces.nsIChannel);
|
||||
try {
|
||||
this._contentLen = request.contentLength;
|
||||
if (this._contentLen == -1)
|
||||
}
|
||||
catch (ex) {
|
||||
if (!(this._flags & CL_EXPECT_FAILURE))
|
||||
do_throw("Could not get contentLength");
|
||||
}
|
||||
if (this._contentLen == -1 && !(this._flags & CL_EXPECT_FAILURE))
|
||||
do_throw("Content length is unknown in onStartRequest!");
|
||||
} catch (ex) {
|
||||
do_throw("Error in onStartRequest: " + ex);
|
||||
|
@ -121,3 +127,31 @@ ChannelListener.prototype = {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
var ES_ABORT_REDIRECT = 0x01;
|
||||
|
||||
function ChannelEventSink(flags)
|
||||
{
|
||||
this._flags = flags;
|
||||
}
|
||||
|
||||
ChannelEventSink.prototype = {
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsIInterfaceRequestor) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
getInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsIChannelEventSink))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
onChannelRedirect: function(oldChannel, newChannel, flags) {
|
||||
if (this._flags & ES_ABORT_REDIRECT) {
|
||||
throw Cr.NS_BINDING_ABORTED;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
var cacheUpdateObserver = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
var responseBody = "Content body";
|
||||
|
||||
// start the test with loading this master entry referencing the manifest
|
||||
function masterEntryHandler(metadata, response)
|
||||
{
|
||||
var masterEntryContent = "<html manifest='/manifest'></html>";
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.bodyOutputStream.write(masterEntryContent, masterEntryContent.length);
|
||||
}
|
||||
|
||||
// manifest defines fallback namespace from any /redirect path to /content
|
||||
function manifestHandler(metadata, response)
|
||||
{
|
||||
var manifestContent = "CACHE MANIFEST\nFALLBACK:\nredirect /content\n";
|
||||
response.setHeader("Content-Type", "text/cache-manifest");
|
||||
response.bodyOutputStream.write(manifestContent, manifestContent.length);
|
||||
}
|
||||
|
||||
// content handler correctly returns some plain text data
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
// finally check we got fallback content
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, "");
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/masterEntry", masterEntryHandler);
|
||||
httpServer.registerPathHandler("/manifest", manifestHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var uri = make_uri("http://localhost:4444");
|
||||
if (pm.testPermission(uri, "offline-app") != 0) {
|
||||
dump("Previous test failed to clear offline-app permission! Expect failures.\n");
|
||||
}
|
||||
pm.add(uri, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
var ps = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefBranch);
|
||||
dump(ps.getBoolPref("browser.cache.offline.enable"));
|
||||
ps.setBoolPref("browser.cache.offline.enable", true);
|
||||
ps.setComplexValue("browser.cache.offline.parent_directory", Ci.nsILocalFile, do_get_profile());
|
||||
|
||||
cacheUpdateObserver = {observe: function() {
|
||||
dump("got offline-cache-update-completed\n");
|
||||
// offline cache update completed.
|
||||
// In this test the randomURI doesn't exists
|
||||
var chan = make_channel(randomURI);
|
||||
chan.loadFlags = (Ci.nsIRequest.INHIBIT_CACHING |
|
||||
Ci.nsIRequest.LOAD_FROM_CACHE |
|
||||
Ci.nsICachingChannel.LOAD_ONLY_FROM_CACHE);
|
||||
chan.notificationCallbacks = new ChannelEventSink(ES_ABORT_REDIRECT);
|
||||
var chanac = chan.QueryInterface(Ci.nsIApplicationCacheChannel);
|
||||
chanac.chooseApplicationCache = true;
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null, CL_EXPECT_FAILURE), null);
|
||||
}}
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(cacheUpdateObserver, "offline-cache-update-completed", false);
|
||||
|
||||
var us = Cc["@mozilla.org/offlinecacheupdate-service;1"].
|
||||
getService(Ci.nsIOfflineCacheUpdateService);
|
||||
us.scheduleUpdate(make_uri("http://localhost:4444/manifest"),
|
||||
make_uri("http://localhost:4444/masterEntry"));
|
||||
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
var cacheUpdateObserver = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
var responseBody = "Content body";
|
||||
|
||||
// start the test with loading this master entry referencing the manifest
|
||||
function masterEntryHandler(metadata, response)
|
||||
{
|
||||
var masterEntryContent = "<html manifest='/manifest'></html>";
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.bodyOutputStream.write(masterEntryContent, masterEntryContent.length);
|
||||
}
|
||||
|
||||
// manifest defines fallback namespace from any /redirect path to /content
|
||||
function manifestHandler(metadata, response)
|
||||
{
|
||||
var manifestContent = "CACHE MANIFEST\nFALLBACK:\nredirect /content\n";
|
||||
response.setHeader("Content-Type", "text/cache-manifest");
|
||||
response.bodyOutputStream.write(manifestContent, manifestContent.length);
|
||||
}
|
||||
|
||||
// content handler correctly returns some plain text data
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
// finally check we got fallback content
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/masterEntry", masterEntryHandler);
|
||||
httpServer.registerPathHandler("/manifest", manifestHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var uri = make_uri("http://localhost:4444");
|
||||
if (pm.testPermission(uri, "offline-app") != 0) {
|
||||
dump("Previous test failed to clear offline-app permission! Expect failures.\n");
|
||||
}
|
||||
pm.add(uri, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
var ps = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefBranch);
|
||||
dump(ps.getBoolPref("browser.cache.offline.enable"));
|
||||
ps.setBoolPref("browser.cache.offline.enable", true);
|
||||
ps.setComplexValue("browser.cache.offline.parent_directory", Ci.nsILocalFile, do_get_profile());
|
||||
|
||||
cacheUpdateObserver = {observe: function() {
|
||||
dump("got offline-cache-update-completed\n");
|
||||
// offline cache update completed.
|
||||
// In this test the randomURI doesn't exists
|
||||
var chan = make_channel(randomURI);
|
||||
chan.loadFlags = (Ci.nsIRequest.INHIBIT_CACHING |
|
||||
Ci.nsIRequest.LOAD_FROM_CACHE |
|
||||
Ci.nsICachingChannel.LOAD_ONLY_FROM_CACHE);
|
||||
var chanac = chan.QueryInterface(Ci.nsIApplicationCacheChannel);
|
||||
chanac.chooseApplicationCache = true;
|
||||
chan.asyncOpen(new ChannelListener(finish_test), null);
|
||||
}}
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(cacheUpdateObserver, "offline-cache-update-completed", false);
|
||||
|
||||
var us = Cc["@mozilla.org/offlinecacheupdate-service;1"].
|
||||
getService(Ci.nsIOfflineCacheUpdateService);
|
||||
us.scheduleUpdate(make_uri("http://localhost:4444/manifest"),
|
||||
make_uri("http://localhost:4444/masterEntry"));
|
||||
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
var cacheUpdateObserver = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
const responseBody = "Content body";
|
||||
|
||||
// start the test with loading this master entry referencing the manifest
|
||||
function masterEntryHandler(metadata, response)
|
||||
{
|
||||
var masterEntryContent = "<html manifest='/manifest'></html>";
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.bodyOutputStream.write(masterEntryContent, masterEntryContent.length);
|
||||
}
|
||||
|
||||
// manifest defines fallback namespace from any /redirect path to /content
|
||||
function manifestHandler(metadata, response)
|
||||
{
|
||||
var manifestContent = "CACHE MANIFEST\nFALLBACK:\nredirect /content\n";
|
||||
response.setHeader("Content-Type", "text/cache-manifest");
|
||||
response.bodyOutputStream.write(manifestContent, manifestContent.length);
|
||||
}
|
||||
|
||||
// content handler correctly returns some plain text data
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
// redirect handler returns redirect
|
||||
function redirectHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 301, "Moved");
|
||||
response.setHeader("Location", "http://example.com/", false);
|
||||
}
|
||||
|
||||
// finally check we got fallback content
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, "");
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/masterEntry", masterEntryHandler);
|
||||
httpServer.registerPathHandler("/manifest", manifestHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.registerPathHandler(randomPath, redirectHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var uri = make_uri("http://localhost:4444");
|
||||
if (pm.testPermission(uri, "offline-app") != 0) {
|
||||
dump("Previous test failed to clear offline-app permission! Expect failures.\n");
|
||||
}
|
||||
pm.add(uri, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
var ps = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefBranch);
|
||||
dump(ps.getBoolPref("browser.cache.offline.enable"));
|
||||
ps.setBoolPref("browser.cache.offline.enable", true);
|
||||
ps.setComplexValue("browser.cache.offline.parent_directory", Ci.nsILocalFile, do_get_profile());
|
||||
|
||||
cacheUpdateObserver = {observe: function() {
|
||||
dump("got offline-cache-update-completed\n");
|
||||
// offline cache update completed.
|
||||
var chan = make_channel(randomURI);
|
||||
chan.notificationCallbacks = new ChannelEventSink(ES_ABORT_REDIRECT);
|
||||
var chanac = chan.QueryInterface(Ci.nsIApplicationCacheChannel);
|
||||
chanac.chooseApplicationCache = true;
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null, CL_EXPECT_FAILURE), null);
|
||||
}}
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(cacheUpdateObserver, "offline-cache-update-completed", false);
|
||||
|
||||
var us = Cc["@mozilla.org/offlinecacheupdate-service;1"].
|
||||
getService(Ci.nsIOfflineCacheUpdateService);
|
||||
us.scheduleUpdate(make_uri("http://localhost:4444/manifest"),
|
||||
make_uri("http://localhost:4444/masterEntry"));
|
||||
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
var cacheUpdateObserver = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
var responseBody = "Content body";
|
||||
|
||||
// start the test with loading this master entry referencing the manifest
|
||||
function masterEntryHandler(metadata, response)
|
||||
{
|
||||
var masterEntryContent = "<html manifest='/manifest'></html>";
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.bodyOutputStream.write(masterEntryContent, masterEntryContent.length);
|
||||
}
|
||||
|
||||
// manifest defines fallback namespace from any /redirect path to /content
|
||||
function manifestHandler(metadata, response)
|
||||
{
|
||||
var manifestContent = "CACHE MANIFEST\nFALLBACK:\nredirect /content\n";
|
||||
response.setHeader("Content-Type", "text/cache-manifest");
|
||||
response.bodyOutputStream.write(manifestContent, manifestContent.length);
|
||||
}
|
||||
|
||||
// content handler correctly returns some plain text data
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
// redirect handler returns redirect
|
||||
function redirectHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 301, "Moved");
|
||||
response.setHeader("Location", "http://example.com/", false);
|
||||
}
|
||||
|
||||
// finally check we got fallback content
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/masterEntry", masterEntryHandler);
|
||||
httpServer.registerPathHandler("/manifest", manifestHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.registerPathHandler(randomPath, redirectHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var uri = make_uri("http://localhost:4444");
|
||||
if (pm.testPermission(uri, "offline-app") != 0) {
|
||||
dump("Previous test failed to clear offline-app permission! Expect failures.\n");
|
||||
}
|
||||
pm.add(uri, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
var ps = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefBranch);
|
||||
dump(ps.getBoolPref("browser.cache.offline.enable"));
|
||||
ps.setBoolPref("browser.cache.offline.enable", true);
|
||||
ps.setComplexValue("browser.cache.offline.parent_directory", Ci.nsILocalFile, do_get_profile());
|
||||
|
||||
cacheUpdateObserver = {observe: function() {
|
||||
dump("got offline-cache-update-completed\n");
|
||||
// offline cache update completed.
|
||||
var chan = make_channel(randomURI);
|
||||
var chanac = chan.QueryInterface(Ci.nsIApplicationCacheChannel);
|
||||
chanac.chooseApplicationCache = true;
|
||||
chan.asyncOpen(new ChannelListener(finish_test), null);
|
||||
}}
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(cacheUpdateObserver, "offline-cache-update-completed", false);
|
||||
|
||||
var us = Cc["@mozilla.org/offlinecacheupdate-service;1"].
|
||||
getService(Ci.nsIOfflineCacheUpdateService);
|
||||
us.scheduleUpdate(make_uri("http://localhost:4444/manifest"),
|
||||
make_uri("http://localhost:4444/masterEntry"));
|
||||
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
var cacheUpdateObserver = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
var responseBody = "Content body";
|
||||
|
||||
// start the test with loading this master entry referencing the manifest
|
||||
function masterEntryHandler(metadata, response)
|
||||
{
|
||||
var masterEntryContent = "<html manifest='/manifest'></html>";
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.bodyOutputStream.write(masterEntryContent, masterEntryContent.length);
|
||||
}
|
||||
|
||||
// manifest defines fallback namespace from any /redirect path to /content
|
||||
function manifestHandler(metadata, response)
|
||||
{
|
||||
var manifestContent = "CACHE MANIFEST\nFALLBACK:\nredirect /content\n";
|
||||
response.setHeader("Content-Type", "text/cache-manifest");
|
||||
response.bodyOutputStream.write(manifestContent, manifestContent.length);
|
||||
}
|
||||
|
||||
// content handler correctly returns some plain text data
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
// redirect handler returns redirect
|
||||
function redirectHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 301, "Moved");
|
||||
response.setHeader("Location", "http://example.com/", false);
|
||||
}
|
||||
|
||||
// finally check we got fallback content
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, "");
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/masterEntry", masterEntryHandler);
|
||||
httpServer.registerPathHandler("/manifest", manifestHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var uri = make_uri("http://localhost:4444");
|
||||
if (pm.testPermission(uri, "offline-app") != 0) {
|
||||
dump("Previous test failed to clear offline-app permission! Expect failures.\n");
|
||||
}
|
||||
pm.add(uri, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
var ps = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefBranch);
|
||||
dump(ps.getBoolPref("browser.cache.offline.enable"));
|
||||
ps.setBoolPref("browser.cache.offline.enable", true);
|
||||
ps.setComplexValue("browser.cache.offline.parent_directory", Ci.nsILocalFile, do_get_profile());
|
||||
|
||||
cacheUpdateObserver = {observe: function() {
|
||||
dump("got offline-cache-update-completed\n");
|
||||
// offline cache update completed.
|
||||
httpServer.stop(function() {
|
||||
// Now shut the server down to have an error in onStartRequest
|
||||
var chan = make_channel(randomURI);
|
||||
chan.notificationCallbacks = new ChannelEventSink(ES_ABORT_REDIRECT);
|
||||
var chanac = chan.QueryInterface(Ci.nsIApplicationCacheChannel);
|
||||
chanac.chooseApplicationCache = true;
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null, CL_EXPECT_FAILURE), null);
|
||||
});
|
||||
}}
|
||||
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(cacheUpdateObserver, "offline-cache-update-completed", false);
|
||||
|
||||
var us = Cc["@mozilla.org/offlinecacheupdate-service;1"].
|
||||
getService(Ci.nsIOfflineCacheUpdateService);
|
||||
us.scheduleUpdate(make_uri("http://localhost:4444/manifest"),
|
||||
make_uri("http://localhost:4444/masterEntry"));
|
||||
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
var cacheUpdateObserver = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
var responseBody = "Content body";
|
||||
|
||||
// start the test with loading this master entry referencing the manifest
|
||||
function masterEntryHandler(metadata, response)
|
||||
{
|
||||
var masterEntryContent = "<html manifest='/manifest'></html>";
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.bodyOutputStream.write(masterEntryContent, masterEntryContent.length);
|
||||
}
|
||||
|
||||
// manifest defines fallback namespace from any /redirect path to /content
|
||||
function manifestHandler(metadata, response)
|
||||
{
|
||||
var manifestContent = "CACHE MANIFEST\nFALLBACK:\nredirect /content\n";
|
||||
response.setHeader("Content-Type", "text/cache-manifest");
|
||||
response.bodyOutputStream.write(manifestContent, manifestContent.length);
|
||||
}
|
||||
|
||||
// content handler correctly returns some plain text data
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
// redirect handler returns redirect
|
||||
function redirectHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 301, "Moved");
|
||||
response.setHeader("Location", "http://example.com/", false);
|
||||
}
|
||||
|
||||
// finally check we got fallback content
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/masterEntry", masterEntryHandler);
|
||||
httpServer.registerPathHandler("/manifest", manifestHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var uri = make_uri("http://localhost:4444");
|
||||
if (pm.testPermission(uri, "offline-app") != 0) {
|
||||
dump("Previous test failed to clear offline-app permission! Expect failures.\n");
|
||||
}
|
||||
pm.add(uri, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
var ps = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefBranch);
|
||||
dump(ps.getBoolPref("browser.cache.offline.enable"));
|
||||
ps.setBoolPref("browser.cache.offline.enable", true);
|
||||
ps.setComplexValue("browser.cache.offline.parent_directory", Ci.nsILocalFile, do_get_profile());
|
||||
|
||||
cacheUpdateObserver = {observe: function() {
|
||||
dump("got offline-cache-update-completed\n");
|
||||
// offline cache update completed.
|
||||
httpServer.stop(function() {
|
||||
// Now shut the server down to have an error in onstartrequest
|
||||
var chan = make_channel(randomURI);
|
||||
var chanac = chan.QueryInterface(Ci.nsIApplicationCacheChannel);
|
||||
chanac.chooseApplicationCache = true;
|
||||
chan.asyncOpen(new ChannelListener(finish_test), null);
|
||||
});
|
||||
}}
|
||||
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(cacheUpdateObserver, "offline-cache-update-completed", false);
|
||||
|
||||
var us = Cc["@mozilla.org/offlinecacheupdate-service;1"].
|
||||
getService(Ci.nsIOfflineCacheUpdateService);
|
||||
us.scheduleUpdate(make_uri("http://localhost:4444/manifest"),
|
||||
make_uri("http://localhost:4444/masterEntry"));
|
||||
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/error/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
var cacheUpdateObserver = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
var responseBody = "Content body";
|
||||
|
||||
// start the test with loading this master entry referencing the manifest
|
||||
function masterEntryHandler(metadata, response)
|
||||
{
|
||||
var masterEntryContent = "<html manifest='/manifest'></html>";
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.bodyOutputStream.write(masterEntryContent, masterEntryContent.length);
|
||||
}
|
||||
|
||||
// manifest defines fallback namespace from any /error path to /content
|
||||
function manifestHandler(metadata, response)
|
||||
{
|
||||
var manifestContent = "CACHE MANIFEST\nFALLBACK:\nerror /content\n";
|
||||
response.setHeader("Content-Type", "text/cache-manifest");
|
||||
response.bodyOutputStream.write(manifestContent, manifestContent.length);
|
||||
}
|
||||
|
||||
// content handler correctly returns some plain text data
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
// error handler returns error
|
||||
function errorHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 404, "Bad request");
|
||||
}
|
||||
|
||||
// finally check we got fallback content
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, "");
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/masterEntry", masterEntryHandler);
|
||||
httpServer.registerPathHandler("/manifest", manifestHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.registerPathHandler(randomPath, errorHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var uri = make_uri("http://localhost:4444");
|
||||
if (pm.testPermission(uri, "offline-app") != 0) {
|
||||
dump("Previous test failed to clear offline-app permission! Expect failures.\n");
|
||||
}
|
||||
pm.add(uri, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
var ps = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefBranch);
|
||||
dump(ps.getBoolPref("browser.cache.offline.enable"));
|
||||
ps.setBoolPref("browser.cache.offline.enable", true);
|
||||
ps.setComplexValue("browser.cache.offline.parent_directory", Ci.nsILocalFile, do_get_profile());
|
||||
|
||||
cacheUpdateObserver = {observe: function() {
|
||||
dump("got offline-cache-update-completed\n");
|
||||
// offline cache update completed.
|
||||
var chan = make_channel(randomURI);
|
||||
chan.notificationCallbacks = new ChannelEventSink(ES_ABORT_REDIRECT);
|
||||
var chanac = chan.QueryInterface(Ci.nsIApplicationCacheChannel);
|
||||
chanac.chooseApplicationCache = true;
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null, CL_EXPECT_FAILURE), null);
|
||||
}}
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(cacheUpdateObserver, "offline-cache-update-completed", false);
|
||||
|
||||
var us = Cc["@mozilla.org/offlinecacheupdate-service;1"].
|
||||
getService(Ci.nsIOfflineCacheUpdateService);
|
||||
us.scheduleUpdate(make_uri("http://localhost:4444/manifest"),
|
||||
make_uri("http://localhost:4444/masterEntry"));
|
||||
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/error/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
var cacheUpdateObserver = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
var responseBody = "Content body";
|
||||
|
||||
// start the test with loading this master entry referencing the manifest
|
||||
function masterEntryHandler(metadata, response)
|
||||
{
|
||||
var masterEntryContent = "<html manifest='/manifest'></html>";
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.bodyOutputStream.write(masterEntryContent, masterEntryContent.length);
|
||||
}
|
||||
|
||||
// manifest defines fallback namespace from any /error path to /content
|
||||
function manifestHandler(metadata, response)
|
||||
{
|
||||
var manifestContent = "CACHE MANIFEST\nFALLBACK:\nerror /content\n";
|
||||
response.setHeader("Content-Type", "text/cache-manifest");
|
||||
response.bodyOutputStream.write(manifestContent, manifestContent.length);
|
||||
}
|
||||
|
||||
// content handler correctly returns some plain text data
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
// error handler returns error
|
||||
function errorHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 404, "Bad request");
|
||||
}
|
||||
|
||||
// finally check we got fallback content
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/masterEntry", masterEntryHandler);
|
||||
httpServer.registerPathHandler("/manifest", manifestHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.registerPathHandler(randomPath, errorHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var uri = make_uri("http://localhost:4444");
|
||||
if (pm.testPermission(uri, "offline-app") != 0) {
|
||||
dump("Previous test failed to clear offline-app permission! Expect failures.\n");
|
||||
}
|
||||
pm.add(uri, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
var ps = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefBranch);
|
||||
dump(ps.getBoolPref("browser.cache.offline.enable"));
|
||||
ps.setBoolPref("browser.cache.offline.enable", true);
|
||||
ps.setComplexValue("browser.cache.offline.parent_directory", Ci.nsILocalFile, do_get_profile());
|
||||
|
||||
cacheUpdateObserver = {observe: function() {
|
||||
dump("got offline-cache-update-completed\n");
|
||||
// offline cache update completed.
|
||||
var chan = make_channel(randomURI);
|
||||
var chanac = chan.QueryInterface(Ci.nsIApplicationCacheChannel);
|
||||
chanac.chooseApplicationCache = true;
|
||||
chan.asyncOpen(new ChannelListener(finish_test), null);
|
||||
}}
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(cacheUpdateObserver, "offline-cache-update-completed", false);
|
||||
|
||||
var us = Cc["@mozilla.org/offlinecacheupdate-service;1"].
|
||||
getService(Ci.nsIOfflineCacheUpdateService);
|
||||
us.scheduleUpdate(make_uri("http://localhost:4444/manifest"),
|
||||
make_uri("http://localhost:4444/masterEntry"));
|
||||
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
const responseBody = "response body";
|
||||
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, "");
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var nc = new ChannelEventSink();
|
||||
var on_modify_request_count = 0;
|
||||
|
||||
modifyrequestobserver = {observe: function() {
|
||||
// We get 2 on-modify-request notifications:
|
||||
// 1. when proxy service resolves the proxy settings from PAC function
|
||||
// 2. when we try to fail over the first proxy (moving to the second one)
|
||||
//
|
||||
// In the second case we want to cancel the proxy engage, so, do not allow
|
||||
// redirects from now.
|
||||
|
||||
if (++on_modify_request_count == 2)
|
||||
nc._flags = ES_ABORT_REDIRECT;
|
||||
}}
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(modifyrequestobserver, "http-on-modify-request", false);
|
||||
|
||||
var prefserv = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService);
|
||||
var prefs = prefserv.getBranch("network.proxy.");
|
||||
prefs.setIntPref("type", 2);
|
||||
prefs.setCharPref("autoconfig_url", "data:text/plain," +
|
||||
"function FindProxyForURL(url, host) {return 'PROXY a_non_existent_domain_x7x6c572v:80; PROXY localhost:4444';}"
|
||||
);
|
||||
|
||||
var chan = make_channel("http://localhost:4444/content");
|
||||
chan.notificationCallbacks = nc;
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null, CL_EXPECT_FAILURE), null);
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
const responseBody = "response body";
|
||||
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var prefserv = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService);
|
||||
var prefs = prefserv.getBranch("network.proxy.");
|
||||
prefs.setIntPref("type", 2);
|
||||
prefs.setCharPref("autoconfig_url", "data:text/plain," +
|
||||
"function FindProxyForURL(url, host) {return 'PROXY a_non_existent_domain_x7x6c572v:80; PROXY localhost:4444';}"
|
||||
);
|
||||
|
||||
var chan = make_channel("http://localhost:4444/content");
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null), null);
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
const responseBody = "response body";
|
||||
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, "");
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var prefserv = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService);
|
||||
var prefs = prefserv.getBranch("network.proxy.");
|
||||
prefs.setIntPref("type", 2);
|
||||
prefs.setCharPref("autoconfig_url", "data:text/plain," +
|
||||
"function FindProxyForURL(url, host) {return 'PROXY localhost:4444';}"
|
||||
);
|
||||
|
||||
var chan = make_channel("http://localhost:4444/content");
|
||||
chan.notificationCallbacks = new ChannelEventSink(ES_ABORT_REDIRECT);
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null, CL_EXPECT_FAILURE), null);
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
const responseBody = "response body";
|
||||
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var prefserv = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService);
|
||||
var prefs = prefserv.getBranch("network.proxy.");
|
||||
prefs.setIntPref("type", 2);
|
||||
prefs.setCharPref("autoconfig_url", "data:text/plain," +
|
||||
"function FindProxyForURL(url, host) {return 'PROXY localhost:4444';}"
|
||||
);
|
||||
|
||||
var chan = make_channel("http://localhost:4444/content");
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null), null);
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
const responseBody = "response body";
|
||||
|
||||
function redirectHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 301, "Moved");
|
||||
response.setHeader("Location", "http://localhost:4444/content", false);
|
||||
response.setHeader("Cache-control", "max-age=1000", false);
|
||||
return;
|
||||
}
|
||||
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function firstTimeThrough(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
var chan = make_channel(randomURI);
|
||||
chan.asyncOpen(new ChannelListener(secondTimeThrough, null), null);
|
||||
}
|
||||
|
||||
function secondTimeThrough(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
var chan = make_channel(randomURI);
|
||||
chan.loadFlags |= Ci.nsIRequest.LOAD_FROM_CACHE;
|
||||
chan.notificationCallbacks = new ChannelEventSink(ES_ABORT_REDIRECT);
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null, CL_EXPECT_FAILURE), null);
|
||||
}
|
||||
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, "");
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler(randomPath, redirectHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var chan = make_channel(randomURI);
|
||||
chan.asyncOpen(new ChannelListener(firstTimeThrough, null), null);
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
function redirectHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 301, "Moved");
|
||||
response.setHeader("Location", "httpx://localhost:4444/content", false);
|
||||
response.setHeader("Cache-control", "max-age=1000", false);
|
||||
}
|
||||
|
||||
function firstTimeThrough(request, buffer)
|
||||
{
|
||||
var chan = make_channel(randomURI);
|
||||
chan.loadFlags |= Ci.nsIRequest.LOAD_FROM_CACHE;
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null, CL_EXPECT_FAILURE), null);
|
||||
}
|
||||
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, "");
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler(randomPath, redirectHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var chan = make_channel(randomURI);
|
||||
chan.asyncOpen(new ChannelListener(firstTimeThrough), null);
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
const responseBody = "response body";
|
||||
|
||||
function redirectHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 301, "Moved");
|
||||
response.setHeader("Location", "http://localhost:4444/content", false);
|
||||
}
|
||||
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, "");
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler(randomPath, redirectHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var chan = make_channel(randomURI);
|
||||
chan.notificationCallbacks = new ChannelEventSink(ES_ABORT_REDIRECT);
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null), null);
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
function redirectHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 301, "Moved");
|
||||
response.setHeader("Location", "httpx://localhost:4444/content", false);
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
}
|
||||
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, "");
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler(randomPath, redirectHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var chan = make_channel(randomURI);
|
||||
chan.asyncOpen(new ChannelListener(finish_test), null);
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
// Need to randomize, because apparently no one clears our cache
|
||||
var randomPath = "/redirect/" + Math.random();
|
||||
var randomURI = "http://localhost:4444" + randomPath;
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newChannel(url, "", null);
|
||||
}
|
||||
|
||||
const responseBody = "response body";
|
||||
|
||||
function redirectHandler(metadata, response)
|
||||
{
|
||||
response.setStatusLine(metadata.httpVersion, 301, "Moved");
|
||||
response.setHeader("Location", "http://localhost:4444/content", false);
|
||||
}
|
||||
|
||||
function contentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function firstTimeThrough(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
var chan = make_channel(randomURI);
|
||||
chan.asyncOpen(new ChannelListener(finish_test, null), null);
|
||||
}
|
||||
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler(randomPath, redirectHandler);
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(4444);
|
||||
|
||||
var chan = make_channel(randomURI);
|
||||
chan.asyncOpen(new ChannelListener(firstTimeThrough, null), null);
|
||||
do_test_pending();
|
||||
}
|
Загрузка…
Ссылка в новой задаче