зеркало из 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 \
|
nsIAuthPromptAdapterFactory.idl \
|
||||||
nsIAuthPromptCallback.idl \
|
nsIAuthPromptCallback.idl \
|
||||||
nsIAsyncStreamCopier.idl \
|
nsIAsyncStreamCopier.idl \
|
||||||
|
nsIAsyncVerifyRedirectCallback.idl \
|
||||||
nsIBufferedStreams.idl \
|
nsIBufferedStreams.idl \
|
||||||
nsICancelable.idl \
|
nsICancelable.idl \
|
||||||
nsIChannelPolicy.idl \
|
nsIChannelPolicy.idl \
|
||||||
|
@ -149,6 +150,7 @@ EXPORTS = \
|
||||||
nsURIHashKey.h \
|
nsURIHashKey.h \
|
||||||
nsReadLine.h \
|
nsReadLine.h \
|
||||||
nsASocketHandler.h \
|
nsASocketHandler.h \
|
||||||
|
nsAsyncRedirectVerifyHelper.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
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 = \
|
CPPSRCS = \
|
||||||
nsTransportUtils.cpp \
|
nsTransportUtils.cpp \
|
||||||
nsAsyncStreamCopier.cpp \
|
nsAsyncStreamCopier.cpp \
|
||||||
|
nsAsyncRedirectVerifyHelper.cpp \
|
||||||
nsAuthInformationHolder.cpp \
|
nsAuthInformationHolder.cpp \
|
||||||
nsBaseChannel.cpp \
|
nsBaseChannel.cpp \
|
||||||
nsBaseContentStream.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 "nsIStreamConverterService.h"
|
||||||
#include "nsIContentSniffer.h"
|
#include "nsIContentSniffer.h"
|
||||||
#include "nsChannelClassifier.h"
|
#include "nsChannelClassifier.h"
|
||||||
|
#include "nsAsyncRedirectVerifyHelper.h"
|
||||||
|
|
||||||
static PLDHashOperator
|
static PLDHashOperator
|
||||||
CopyProperties(const nsAString &key, nsIVariant *data, void *closure)
|
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
|
// we support nsIHttpEventSink if we are an HTTP channel and if this is not
|
||||||
// an internal redirect.
|
// an internal redirect.
|
||||||
|
|
||||||
// Global observers. These come first so that other observers don't see
|
nsRefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
|
||||||
// redirects that get aborted for security reasons anyway.
|
new nsAsyncRedirectVerifyHelper();
|
||||||
NS_ASSERTION(gIOService, "Must have an IO service");
|
|
||||||
nsresult rv = gIOService->OnChannelRedirect(this, newChannel, redirectFlags);
|
PRBool checkRedirectSynchronously = !openNewChannel;
|
||||||
|
|
||||||
|
mRedirectChannel = newChannel;
|
||||||
|
mRedirectFlags = redirectFlags;
|
||||||
|
mOpenRedirectChannel = openNewChannel;
|
||||||
|
nsresult rv = redirectCallbackHelper->Init(this, newChannel, redirectFlags,
|
||||||
|
checkRedirectSynchronously);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return 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.
|
// 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();
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface();
|
||||||
if (httpChannel) {
|
if (httpChannel) {
|
||||||
nsCOMPtr<nsIHttpEventSink> httpEventSink;
|
nsCOMPtr<nsIHttpEventSink> httpEventSink;
|
||||||
GetCallback(httpEventSink);
|
GetCallback(httpEventSink);
|
||||||
if (httpEventSink) {
|
if (httpEventSink) {
|
||||||
rv = httpEventSink->OnRedirect(httpChannel, newChannel);
|
nsresult rv = httpEventSink->OnRedirect(httpChannel, mRedirectChannel);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIChannelEventSink> channelEventSink;
|
// Make sure to do this _after_ making all the OnChannelRedirect calls
|
||||||
// Give our consumer a chance to observe/block this redirect.
|
mRedirectChannel->SetOriginalURI(OriginalURI());
|
||||||
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());
|
|
||||||
|
|
||||||
// If we fail to open the new channel, then we want to leave this channel
|
// 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
|
// unaffected, so we defer tearing down our channel until we have succeeded
|
||||||
// with the redirect.
|
// with the redirect.
|
||||||
|
|
||||||
if (openNewChannel) {
|
if (mOpenRedirectChannel) {
|
||||||
rv = newChannel->AsyncOpen(mListener, mListenerContext);
|
nsresult rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mRedirectChannel = nsnull;
|
||||||
|
|
||||||
// close down this channel
|
// close down this channel
|
||||||
Cancel(NS_BINDING_REDIRECTED);
|
Cancel(NS_BINDING_REDIRECTED);
|
||||||
mListener = nsnull;
|
mListener = nsnull;
|
||||||
|
@ -256,20 +268,30 @@ void
|
||||||
nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel)
|
nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(!mPump, "Shouldn't have gotten here");
|
NS_ASSERTION(!mPump, "Shouldn't have gotten here");
|
||||||
PRBool doNotify = PR_TRUE;
|
|
||||||
|
nsresult rv = mStatus;
|
||||||
if (NS_SUCCEEDED(mStatus)) {
|
if (NS_SUCCEEDED(mStatus)) {
|
||||||
nsresult rv = Redirect(newChannel,
|
rv = Redirect(newChannel,
|
||||||
nsIChannelEventSink::REDIRECT_TEMPORARY,
|
nsIChannelEventSink::REDIRECT_TEMPORARY,
|
||||||
PR_TRUE);
|
PR_TRUE);
|
||||||
if (NS_FAILED(rv))
|
if (NS_SUCCEEDED(rv)) {
|
||||||
Cancel(rv);
|
// OnRedirectVerifyCallback will be called asynchronously
|
||||||
else
|
return;
|
||||||
doNotify = PR_FALSE;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContinueHandleAsyncRedirect(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsBaseChannel::ContinueHandleAsyncRedirect(nsresult result)
|
||||||
|
{
|
||||||
mWaitingOnAsyncRedirect = PR_FALSE;
|
mWaitingOnAsyncRedirect = PR_FALSE;
|
||||||
|
|
||||||
if (doNotify) {
|
if (NS_FAILED(result))
|
||||||
|
Cancel(result);
|
||||||
|
|
||||||
|
if (NS_FAILED(result) && mListener) {
|
||||||
// Notify our consumer ourselves
|
// Notify our consumer ourselves
|
||||||
mListener->OnStartRequest(this, mListenerContext);
|
mListener->OnStartRequest(this, mListenerContext);
|
||||||
mListener->OnStopRequest(this, mListenerContext, mStatus);
|
mListener->OnStopRequest(this, mListenerContext, mStatus);
|
||||||
|
@ -306,14 +328,15 @@ nsBaseChannel::ClassifyURI()
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// nsBaseChannel::nsISupports
|
// nsBaseChannel::nsISupports
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS_INHERITED6(nsBaseChannel,
|
NS_IMPL_ISUPPORTS_INHERITED7(nsBaseChannel,
|
||||||
nsHashPropertyBag,
|
nsHashPropertyBag,
|
||||||
nsIRequest,
|
nsIRequest,
|
||||||
nsIChannel,
|
nsIChannel,
|
||||||
nsIInterfaceRequestor,
|
nsIInterfaceRequestor,
|
||||||
nsITransportEventSink,
|
nsITransportEventSink,
|
||||||
nsIRequestObserver,
|
nsIRequestObserver,
|
||||||
nsIStreamListener)
|
nsIStreamListener,
|
||||||
|
nsIAsyncVerifyRedirectCallback)
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// nsBaseChannel::nsIRequest
|
// nsBaseChannel::nsIRequest
|
||||||
|
@ -738,3 +761,21 @@ nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||||
|
|
||||||
return rv;
|
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 "nsIInterfaceRequestor.h"
|
||||||
#include "nsIProgressEventSink.h"
|
#include "nsIProgressEventSink.h"
|
||||||
#include "nsITransport.h"
|
#include "nsITransport.h"
|
||||||
|
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -70,6 +71,7 @@ class nsBaseChannel : public nsHashPropertyBag
|
||||||
, public nsIChannel
|
, public nsIChannel
|
||||||
, public nsIInterfaceRequestor
|
, public nsIInterfaceRequestor
|
||||||
, public nsITransportEventSink
|
, public nsITransportEventSink
|
||||||
|
, public nsIAsyncVerifyRedirectCallback
|
||||||
, private nsIStreamListener
|
, private nsIStreamListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -78,6 +80,7 @@ public:
|
||||||
NS_DECL_NSICHANNEL
|
NS_DECL_NSICHANNEL
|
||||||
NS_DECL_NSIINTERFACEREQUESTOR
|
NS_DECL_NSIINTERFACEREQUESTOR
|
||||||
NS_DECL_NSITRANSPORTEVENTSINK
|
NS_DECL_NSITRANSPORTEVENTSINK
|
||||||
|
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||||
|
|
||||||
nsBaseChannel();
|
nsBaseChannel();
|
||||||
|
|
||||||
|
@ -246,6 +249,8 @@ private:
|
||||||
// Handle an async redirect callback. This will only be called if we
|
// Handle an async redirect callback. This will only be called if we
|
||||||
// returned success from AsyncOpen while posting a redirect runnable.
|
// returned success from AsyncOpen while posting a redirect runnable.
|
||||||
void HandleAsyncRedirect(nsIChannel* newChannel);
|
void HandleAsyncRedirect(nsIChannel* newChannel);
|
||||||
|
void ContinueHandleAsyncRedirect(nsresult result);
|
||||||
|
nsresult ContinueRedirect();
|
||||||
|
|
||||||
// start URI classifier if requested
|
// start URI classifier if requested
|
||||||
void ClassifyURI();
|
void ClassifyURI();
|
||||||
|
@ -281,6 +286,7 @@ private:
|
||||||
nsCOMPtr<nsISupports> mSecurityInfo;
|
nsCOMPtr<nsISupports> mSecurityInfo;
|
||||||
nsCOMPtr<nsIStreamListener> mListener;
|
nsCOMPtr<nsIStreamListener> mListener;
|
||||||
nsCOMPtr<nsISupports> mListenerContext;
|
nsCOMPtr<nsISupports> mListenerContext;
|
||||||
|
nsCOMPtr<nsIChannel> mRedirectChannel;
|
||||||
nsCString mContentType;
|
nsCString mContentType;
|
||||||
nsCString mContentCharset;
|
nsCString mContentCharset;
|
||||||
PRUint32 mLoadFlags;
|
PRUint32 mLoadFlags;
|
||||||
|
@ -289,6 +295,8 @@ private:
|
||||||
PRPackedBool mSynthProgressEvents;
|
PRPackedBool mSynthProgressEvents;
|
||||||
PRPackedBool mWasOpened;
|
PRPackedBool mWasOpened;
|
||||||
PRPackedBool mWaitingOnAsyncRedirect;
|
PRPackedBool mWaitingOnAsyncRedirect;
|
||||||
|
PRPackedBool mOpenRedirectChannel;
|
||||||
|
PRUint32 mRedirectFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !nsBaseChannel_h__
|
#endif // !nsBaseChannel_h__
|
||||||
|
|
|
@ -55,6 +55,7 @@ HttpBaseChannel::HttpBaseChannel()
|
||||||
, mPriority(PRIORITY_NORMAL)
|
, mPriority(PRIORITY_NORMAL)
|
||||||
, mCaps(0)
|
, mCaps(0)
|
||||||
, mRedirectionLimit(gHttpHandler->RedirectionLimit())
|
, mRedirectionLimit(gHttpHandler->RedirectionLimit())
|
||||||
|
, mCanceled(PR_FALSE)
|
||||||
, mIsPending(PR_FALSE)
|
, mIsPending(PR_FALSE)
|
||||||
, mWasOpened(PR_FALSE)
|
, mWasOpened(PR_FALSE)
|
||||||
, mResponseHeadersModified(PR_FALSE)
|
, mResponseHeadersModified(PR_FALSE)
|
||||||
|
@ -919,6 +920,13 @@ HttpBaseChannel::SetForceAllowThirdPartyCookie(PRBool aForce)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
HttpBaseChannel::GetCanceled(PRBool *aCanceled)
|
||||||
|
{
|
||||||
|
*aCanceled = mCanceled;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// HttpBaseChannel::nsISupportsPriority
|
// HttpBaseChannel::nsISupportsPriority
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
|
@ -161,6 +161,7 @@ public:
|
||||||
NS_IMETHOD SetCookie(const char *aCookieHeader);
|
NS_IMETHOD SetCookie(const char *aCookieHeader);
|
||||||
NS_IMETHOD GetForceAllowThirdPartyCookie(PRBool *aForce);
|
NS_IMETHOD GetForceAllowThirdPartyCookie(PRBool *aForce);
|
||||||
NS_IMETHOD SetForceAllowThirdPartyCookie(PRBool aForce);
|
NS_IMETHOD SetForceAllowThirdPartyCookie(PRBool aForce);
|
||||||
|
NS_IMETHOD GetCanceled(PRBool *aCanceled);
|
||||||
|
|
||||||
// nsISupportsPriority
|
// nsISupportsPriority
|
||||||
NS_IMETHOD GetPriority(PRInt32 *value);
|
NS_IMETHOD GetPriority(PRInt32 *value);
|
||||||
|
@ -205,12 +206,13 @@ protected:
|
||||||
PRUint8 mCaps;
|
PRUint8 mCaps;
|
||||||
PRUint8 mRedirectionLimit;
|
PRUint8 mRedirectionLimit;
|
||||||
|
|
||||||
|
PRUint8 mCanceled : 1;
|
||||||
PRUint8 mIsPending : 1;
|
PRUint8 mIsPending : 1;
|
||||||
PRUint8 mWasOpened : 1;
|
PRUint8 mWasOpened : 1;
|
||||||
PRUint8 mResponseHeadersModified : 1;
|
PRUint8 mResponseHeadersModified : 1;
|
||||||
PRUint8 mAllowPipelining : 1;
|
PRUint8 mAllowPipelining : 1;
|
||||||
PRUint8 mForceAllowThirdPartyCookie : 1;
|
PRUint8 mForceAllowThirdPartyCookie : 1;
|
||||||
PRUint32 mUploadStreamHasHeaders : 1;
|
PRUint8 mUploadStreamHasHeaders : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,6 @@ nsHttpChannel::nsHttpChannel()
|
||||||
, mApplyConversion(PR_TRUE)
|
, mApplyConversion(PR_TRUE)
|
||||||
, mCachedContentIsValid(PR_FALSE)
|
, mCachedContentIsValid(PR_FALSE)
|
||||||
, mCachedContentIsPartial(PR_FALSE)
|
, mCachedContentIsPartial(PR_FALSE)
|
||||||
, mCanceled(PR_FALSE)
|
|
||||||
, mTransactionReplaced(PR_FALSE)
|
, mTransactionReplaced(PR_FALSE)
|
||||||
, mAuthRetryPending(PR_FALSE)
|
, mAuthRetryPending(PR_FALSE)
|
||||||
, mResuming(PR_FALSE)
|
, mResuming(PR_FALSE)
|
||||||
|
@ -105,6 +104,8 @@ nsHttpChannel::nsHttpChannel()
|
||||||
, mLoadedFromApplicationCache(PR_FALSE)
|
, mLoadedFromApplicationCache(PR_FALSE)
|
||||||
, mTracingEnabled(PR_TRUE)
|
, mTracingEnabled(PR_TRUE)
|
||||||
, mCustomConditionalRequest(PR_FALSE)
|
, mCustomConditionalRequest(PR_FALSE)
|
||||||
|
, mFallingBack(PR_FALSE)
|
||||||
|
, mWaitingForRedirectCallback(PR_FALSE)
|
||||||
, mRemoteChannel(PR_FALSE)
|
, mRemoteChannel(PR_FALSE)
|
||||||
{
|
{
|
||||||
LOG(("Creating nsHttpChannel [this=%p]\n", this));
|
LOG(("Creating nsHttpChannel [this=%p]\n", this));
|
||||||
|
@ -299,6 +300,10 @@ nsHttpChannel::HandleAsyncNotifyListener()
|
||||||
void
|
void
|
||||||
nsHttpChannel::DoNotifyListener()
|
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) {
|
if (mListener) {
|
||||||
mListener->OnStartRequest(this, mListenerContext);
|
mListener->OnStartRequest(this, mListenerContext);
|
||||||
mListener->OnStopRequest(this, mListenerContext, mStatus);
|
mListener->OnStopRequest(this, mListenerContext, mStatus);
|
||||||
|
@ -329,15 +334,28 @@ nsHttpChannel::HandleAsyncRedirect()
|
||||||
// channel could have been canceled, in which case there would be no point
|
// channel could have been canceled, in which case there would be no point
|
||||||
// in processing the redirect.
|
// in processing the redirect.
|
||||||
if (NS_SUCCEEDED(mStatus)) {
|
if (NS_SUCCEEDED(mStatus)) {
|
||||||
rv = ProcessRedirection(mResponseHead->Status());
|
PushRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncRedirect);
|
||||||
|
rv = AsyncProcessRedirection(mResponseHead->Status());
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
// If ProcessRedirection fails, then we have to send out the
|
PopRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncRedirect);
|
||||||
// OnStart/OnStop notifications.
|
ContinueHandleAsyncRedirect(rv);
|
||||||
LOG(("ProcessRedirection failed [rv=%x]\n", rv));
|
|
||||||
mStatus = rv;
|
|
||||||
DoNotifyListener();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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(("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
|
// close the cache entry. Blow it away if we couldn't process the redirect
|
||||||
// for some reason (the cache entry might be corrupt).
|
// for some reason (the cache entry might be corrupt).
|
||||||
|
@ -351,6 +369,8 @@ nsHttpChannel::HandleAsyncRedirect()
|
||||||
|
|
||||||
if (mLoadGroup)
|
if (mLoadGroup)
|
||||||
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
|
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -396,21 +416,34 @@ nsHttpChannel::HandleAsyncFallback()
|
||||||
// channel could have been canceled, in which case there would be no point
|
// channel could have been canceled, in which case there would be no point
|
||||||
// in processing the fallback.
|
// in processing the fallback.
|
||||||
if (!mCanceled) {
|
if (!mCanceled) {
|
||||||
PRBool fallingBack;
|
PushRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncFallback);
|
||||||
rv = ProcessFallback(&fallingBack);
|
PRBool waitingForRedirectCallback;
|
||||||
if (NS_FAILED(rv) || !fallingBack) {
|
rv = ProcessFallback(&waitingForRedirectCallback);
|
||||||
// If ProcessFallback fails, then we have to send out the
|
if (waitingForRedirectCallback)
|
||||||
// OnStart/OnStop notifications.
|
return;
|
||||||
LOG(("ProcessFallback failed [rv=%x, %d]\n", rv, fallingBack));
|
PopRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncFallback);
|
||||||
mStatus = NS_FAILED(rv) ? rv : NS_ERROR_DOCUMENT_NOT_CACHED;
|
}
|
||||||
DoNotifyListener();
|
|
||||||
}
|
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, mFallingBack));
|
||||||
|
mStatus = NS_FAILED(rv) ? rv : NS_ERROR_DOCUMENT_NOT_CACHED;
|
||||||
|
DoNotifyListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
mIsPending = PR_FALSE;
|
mIsPending = PR_FALSE;
|
||||||
|
|
||||||
if (mLoadGroup)
|
if (mLoadGroup)
|
||||||
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
|
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
|
||||||
|
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -891,22 +924,12 @@ nsHttpChannel::ProcessResponse()
|
||||||
#endif
|
#endif
|
||||||
// don't store the response body for redirects
|
// don't store the response body for redirects
|
||||||
MaybeInvalidateCacheEntryForSubsequentGet();
|
MaybeInvalidateCacheEntryForSubsequentGet();
|
||||||
rv = ProcessRedirection(httpStatus);
|
PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessResponse);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
rv = AsyncProcessRedirection(httpStatus);
|
||||||
InitCacheEntry();
|
if (NS_FAILED(rv)) {
|
||||||
CloseCacheEntry(PR_FALSE);
|
PopRedirectAsyncFunc(&nsHttpChannel::ContinueProcessResponse);
|
||||||
|
LOG(("AsyncProcessRedirection failed [rv=%x]\n", rv));
|
||||||
if (mCacheForOfflineUse) {
|
rv = ContinueProcessResponse(rv);
|
||||||
// Store response in the offline cache
|
|
||||||
InitOfflineCacheEntry();
|
|
||||||
CloseOfflineCacheEntry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOG(("ProcessRedirection failed [rv=%x]\n", rv));
|
|
||||||
if (mTransaction->SSLConnectFailed())
|
|
||||||
return ProcessFailedSSLConnect(httpStatus);
|
|
||||||
rv = ProcessNormal();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 304:
|
case 304:
|
||||||
|
@ -953,6 +976,28 @@ nsHttpChannel::ProcessResponse()
|
||||||
return rv;
|
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
|
nsresult
|
||||||
nsHttpChannel::ProcessNormal()
|
nsHttpChannel::ProcessNormal()
|
||||||
{
|
{
|
||||||
|
@ -963,18 +1008,34 @@ nsHttpChannel::ProcessNormal()
|
||||||
PRBool succeeded;
|
PRBool succeeded;
|
||||||
rv = GetRequestSucceeded(&succeeded);
|
rv = GetRequestSucceeded(&succeeded);
|
||||||
if (NS_SUCCEEDED(rv) && !succeeded) {
|
if (NS_SUCCEEDED(rv) && !succeeded) {
|
||||||
PRBool fallingBack;
|
PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessNormal);
|
||||||
rv = ProcessFallback(&fallingBack);
|
PRBool waitingForRedirectCallback;
|
||||||
if (NS_FAILED(rv)) {
|
rv = ProcessFallback(&waitingForRedirectCallback);
|
||||||
DoNotifyListener();
|
if (waitingForRedirectCallback) {
|
||||||
return rv;
|
// The transaction has been suspended by ProcessFallback.
|
||||||
}
|
|
||||||
|
|
||||||
if (fallingBack) {
|
|
||||||
// Do not continue with normal processing, fallback is in
|
|
||||||
// progress now.
|
|
||||||
return NS_OK;
|
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 (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
|
// if we're here, then any byte-range requests failed to result in a partial
|
||||||
|
@ -1086,7 +1147,7 @@ nsHttpChannel::ProxyFailover()
|
||||||
|
|
||||||
// XXXbz so where does this codepath remove us from the loadgroup,
|
// XXXbz so where does this codepath remove us from the loadgroup,
|
||||||
// exactly?
|
// exactly?
|
||||||
return DoReplaceWithProxy(pi);
|
return AsyncDoReplaceWithProxy(pi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1107,21 +1168,41 @@ nsHttpChannel::HandleAsyncReplaceWithProxy()
|
||||||
nsCOMPtr<nsIProxyInfo> pi;
|
nsCOMPtr<nsIProxyInfo> pi;
|
||||||
pi.swap(mTargetProxyInfo);
|
pi.swap(mTargetProxyInfo);
|
||||||
if (!mCanceled) {
|
if (!mCanceled) {
|
||||||
status = DoReplaceWithProxy(pi);
|
PushRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncReplaceWithProxy);
|
||||||
if (mLoadGroup && NS_SUCCEEDED(status)) {
|
status = AsyncDoReplaceWithProxy(pi);
|
||||||
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
|
if (NS_SUCCEEDED(status))
|
||||||
}
|
return;
|
||||||
|
PopRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncReplaceWithProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_FAILED(status)) {
|
if (NS_FAILED(status)) {
|
||||||
AsyncAbort(status);
|
ContinueHandleAsyncReplaceWithProxy(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
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;
|
nsresult rv;
|
||||||
|
|
||||||
nsCOMPtr<nsIChannel> newChannel;
|
nsCOMPtr<nsIChannel> newChannel;
|
||||||
|
@ -1134,16 +1215,37 @@ nsHttpChannel::DoReplaceWithProxy(nsIProxyInfo* pi)
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
// Inform consumers about this fake redirect
|
// Inform consumers about this fake redirect
|
||||||
|
mRedirectChannel = newChannel;
|
||||||
PRUint32 flags = nsIChannelEventSink::REDIRECT_INTERNAL;
|
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))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
|
NS_PRECONDITION(mRedirectChannel, "No redirect channel?");
|
||||||
|
|
||||||
// Make sure to do this _after_ calling OnChannelRedirect
|
// Make sure to do this _after_ calling OnChannelRedirect
|
||||||
newChannel->SetOriginalURI(mOriginalURI);
|
mRedirectChannel->SetOriginalURI(mOriginalURI);
|
||||||
|
|
||||||
// open new channel
|
// open new channel
|
||||||
rv = newChannel->AsyncOpen(mListener, mListenerContext);
|
rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
|
||||||
|
mRedirectChannel = nsnull;
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
|
@ -1405,12 +1507,13 @@ nsHttpChannel::ProcessNotModified()
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsHttpChannel::ProcessFallback(PRBool *fallingBack)
|
nsHttpChannel::ProcessFallback(PRBool *waitingForRedirectCallback)
|
||||||
{
|
{
|
||||||
LOG(("nsHttpChannel::ProcessFallback [this=%p]\n", this));
|
LOG(("nsHttpChannel::ProcessFallback [this=%p]\n", this));
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
*fallingBack = PR_FALSE;
|
*waitingForRedirectCallback = PR_FALSE;
|
||||||
|
mFallingBack = PR_FALSE;
|
||||||
|
|
||||||
// At this point a load has failed (either due to network problems
|
// At this point a load has failed (either due to network problems
|
||||||
// or an error returned on the server). Perform an application
|
// or an error returned on the server). Perform an application
|
||||||
|
@ -1475,15 +1578,40 @@ nsHttpChannel::ProcessFallback(PRBool *fallingBack)
|
||||||
rv = newChannel->SetLoadFlags(newLoadFlags);
|
rv = newChannel->SetLoadFlags(newLoadFlags);
|
||||||
|
|
||||||
// Inform consumers about this fake redirect
|
// Inform consumers about this fake redirect
|
||||||
|
mRedirectChannel = newChannel;
|
||||||
PRUint32 redirectFlags = nsIChannelEventSink::REDIRECT_INTERNAL;
|
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))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
|
NS_PRECONDITION(mRedirectChannel, "No redirect channel?");
|
||||||
|
|
||||||
// Make sure to do this _after_ calling OnChannelRedirect
|
// Make sure to do this _after_ calling OnChannelRedirect
|
||||||
newChannel->SetOriginalURI(mOriginalURI);
|
mRedirectChannel->SetOriginalURI(mOriginalURI);
|
||||||
|
|
||||||
rv = newChannel->AsyncOpen(mListener, mListenerContext);
|
rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
|
||||||
|
mRedirectChannel = nsnull;
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// close down this channel
|
// close down this channel
|
||||||
|
@ -1496,7 +1624,7 @@ nsHttpChannel::ProcessFallback(PRBool *fallingBack)
|
||||||
mCallbacks = nsnull;
|
mCallbacks = nsnull;
|
||||||
mProgressSink = nsnull;
|
mProgressSink = nsnull;
|
||||||
|
|
||||||
*fallingBack = PR_TRUE;
|
mFallingBack = PR_TRUE;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -2768,9 +2896,9 @@ nsHttpChannel::SetupReplacementChannel(nsIURI *newURI,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
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));
|
this, redirectType));
|
||||||
|
|
||||||
const char *location = mResponseHead->PeekHeader(nsHttp::Location);
|
const char *location = mResponseHead->PeekHeader(nsHttp::Location);
|
||||||
|
@ -2792,12 +2920,12 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
|
||||||
return NS_ERROR_REDIRECT_LOOP;
|
return NS_ERROR_REDIRECT_LOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mRedirectType = redirectType;
|
||||||
|
|
||||||
LOG(("redirecting to: %s [redirection-limit=%u]\n",
|
LOG(("redirecting to: %s [redirection-limit=%u]\n",
|
||||||
location, PRUint32(mRedirectionLimit)));
|
location, PRUint32(mRedirectionLimit)));
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsCOMPtr<nsIChannel> newChannel;
|
|
||||||
nsCOMPtr<nsIURI> newURI;
|
|
||||||
|
|
||||||
// create a new URI using the location header and the current URL
|
// create a new URI using the location header and the current URL
|
||||||
// as a base...
|
// as a base...
|
||||||
|
@ -2811,36 +2939,49 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
originCharset.Truncate();
|
originCharset.Truncate();
|
||||||
|
|
||||||
rv = ioService->NewURI(nsDependentCString(location), originCharset.get(), mURI,
|
rv = ioService->NewURI(nsDependentCString(location),
|
||||||
getter_AddRefs(newURI));
|
originCharset.get(),
|
||||||
|
mURI,
|
||||||
|
getter_AddRefs(mRedirectURI));
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
if (mApplicationCache) {
|
if (mApplicationCache) {
|
||||||
// if we are redirected to a different origin check if there is a fallback
|
// 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
|
// cache entry to fall back to. we don't care about file strict
|
||||||
// checking, at least mURI is not a file URI.
|
// checking, at least mURI is not a file URI.
|
||||||
if (!NS_SecurityCompareURIs(mURI, newURI, PR_FALSE)) {
|
if (!NS_SecurityCompareURIs(mURI, mRedirectURI, PR_FALSE)) {
|
||||||
PRBool fallingBack;
|
PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessRedirectionAfterFallback);
|
||||||
rv = ProcessFallback(&fallingBack);
|
PRBool waitingForRedirectCallback;
|
||||||
if (NS_SUCCEEDED(rv) && fallingBack) {
|
rv = ProcessFallback(&waitingForRedirectCallback);
|
||||||
// do not continue with redirect processing, fallback is in
|
if (waitingForRedirectCallback)
|
||||||
// progress now.
|
|
||||||
return NS_OK;
|
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
|
// Kill the current cache entry if we are redirecting
|
||||||
// back to ourself.
|
// back to ourself.
|
||||||
PRBool redirectingBackToSameURI = PR_FALSE;
|
PRBool redirectingBackToSameURI = PR_FALSE;
|
||||||
if (mCacheEntry && (mCacheAccess & nsICache::ACCESS_WRITE) &&
|
if (mCacheEntry && (mCacheAccess & nsICache::ACCESS_WRITE) &&
|
||||||
NS_SUCCEEDED(mURI->Equals(newURI, &redirectingBackToSameURI)) &&
|
NS_SUCCEEDED(mURI->Equals(mRedirectURI, &redirectingBackToSameURI)) &&
|
||||||
redirectingBackToSameURI)
|
redirectingBackToSameURI)
|
||||||
mCacheEntry->Doom();
|
mCacheEntry->Doom();
|
||||||
|
|
||||||
// move the reference of the old location to the new one if the new
|
// move the reference of the old location to the new one if the new
|
||||||
// one has none.
|
// one has none.
|
||||||
nsCOMPtr<nsIURL> newURL = do_QueryInterface(newURI);
|
nsCOMPtr<nsIURL> newURL = do_QueryInterface(mRedirectURI);
|
||||||
if (newURL) {
|
if (newURL) {
|
||||||
nsCAutoString ref;
|
nsCAutoString ref;
|
||||||
rv = newURL->GetRef(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.
|
// 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) {
|
if (preserveMethod && mUploadStream) {
|
||||||
rv = PromptTempRedirect();
|
rv = PromptTempRedirect();
|
||||||
if (NS_FAILED(rv)) return rv;
|
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;
|
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;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
PRUint32 redirectFlags;
|
PRUint32 redirectFlags;
|
||||||
if (redirectType == 301) // Moved Permanently
|
if (mRedirectType == 301) // Moved Permanently
|
||||||
redirectFlags = nsIChannelEventSink::REDIRECT_PERMANENT;
|
redirectFlags = nsIChannelEventSink::REDIRECT_PERMANENT;
|
||||||
else
|
else
|
||||||
redirectFlags = nsIChannelEventSink::REDIRECT_TEMPORARY;
|
redirectFlags = nsIChannelEventSink::REDIRECT_TEMPORARY;
|
||||||
|
|
||||||
// verify that this is a legal redirect
|
// 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))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
|
NS_PRECONDITION(mRedirectChannel, "No redirect channel?");
|
||||||
|
|
||||||
// Make sure to do this _after_ calling OnChannelRedirect
|
// Make sure to do this _after_ calling OnChannelRedirect
|
||||||
newChannel->SetOriginalURI(mOriginalURI);
|
mRedirectChannel->SetOriginalURI(mOriginalURI);
|
||||||
|
|
||||||
// And now, the deprecated way
|
// And now, the deprecated way
|
||||||
nsCOMPtr<nsIHttpEventSink> httpEventSink;
|
nsCOMPtr<nsIHttpEventSink> httpEventSink;
|
||||||
|
@ -2887,15 +3053,19 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
|
||||||
if (httpEventSink) {
|
if (httpEventSink) {
|
||||||
// NOTE: nsIHttpEventSink is only used for compatibility with pre-1.8
|
// NOTE: nsIHttpEventSink is only used for compatibility with pre-1.8
|
||||||
// versions.
|
// versions.
|
||||||
rv = httpEventSink->OnRedirect(this, newChannel);
|
rv = httpEventSink->OnRedirect(this, mRedirectChannel);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
// XXX we used to talk directly with the script security manager, but that
|
// XXX we used to talk directly with the script security manager, but that
|
||||||
// should really be handled by the event sink implementation.
|
// should really be handled by the event sink implementation.
|
||||||
|
|
||||||
// begin loading the new channel
|
// begin loading the new channel
|
||||||
rv = newChannel->AsyncOpen(mListener, mListenerContext);
|
rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
|
||||||
if (NS_FAILED(rv)) return rv;
|
mRedirectChannel = nsnull;
|
||||||
|
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
// close down this channel
|
// close down this channel
|
||||||
Cancel(NS_BINDING_REDIRECTED);
|
Cancel(NS_BINDING_REDIRECTED);
|
||||||
|
@ -2978,6 +3148,7 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
|
NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
|
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
|
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
|
||||||
NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
|
NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -2992,6 +3163,9 @@ nsHttpChannel::Cancel(nsresult status)
|
||||||
LOG((" ignoring; already canceled\n"));
|
LOG((" ignoring; already canceled\n"));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
if (mWaitingForRedirectCallback) {
|
||||||
|
LOG(("channel canceled during wait for redirect callback"));
|
||||||
|
}
|
||||||
mCanceled = PR_TRUE;
|
mCanceled = PR_TRUE;
|
||||||
mStatus = status;
|
mStatus = status;
|
||||||
if (mProxyRequest)
|
if (mProxyRequest)
|
||||||
|
@ -3397,22 +3571,52 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||||
|
|
||||||
// on proxy errors, try to failover
|
// on proxy errors, try to failover
|
||||||
if (mConnectionInfo->ProxyInfo() &&
|
if (mConnectionInfo->ProxyInfo() &&
|
||||||
(mStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
|
(mStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
|
||||||
mStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
|
mStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
|
||||||
mStatus == NS_ERROR_NET_TIMEOUT)) {
|
mStatus == NS_ERROR_NET_TIMEOUT)) {
|
||||||
|
|
||||||
|
PushRedirectAsyncFunc(&nsHttpChannel::ContinueOnStartRequest1);
|
||||||
if (NS_SUCCEEDED(ProxyFailover()))
|
if (NS_SUCCEEDED(ProxyFailover()))
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
PopRedirectAsyncFunc(&nsHttpChannel::ContinueOnStartRequest1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// on other request errors, try to fall back
|
return ContinueOnStartRequest2(NS_OK);
|
||||||
PRBool fallingBack;
|
}
|
||||||
if (NS_FAILED(mStatus) &&
|
|
||||||
NS_SUCCEEDED(ProcessFallback(&fallingBack)) &&
|
|
||||||
fallingBack) {
|
|
||||||
|
|
||||||
|
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 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();
|
return CallOnStartRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4126,6 +4330,98 @@ nsHttpChannel::SetChooseApplicationCache(PRBool aChoose)
|
||||||
return NS_OK;
|
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>
|
// nsHttpChannel::nsContentEncodings <public>
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "nsHttpTransaction.h"
|
#include "nsHttpTransaction.h"
|
||||||
#include "nsInputStreamPump.h"
|
#include "nsInputStreamPump.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
|
||||||
#include "nsIHttpEventSink.h"
|
#include "nsIHttpEventSink.h"
|
||||||
#include "nsICachingChannel.h"
|
#include "nsICachingChannel.h"
|
||||||
|
@ -64,6 +65,7 @@
|
||||||
#include "nsIHttpAuthenticableChannel.h"
|
#include "nsIHttpAuthenticableChannel.h"
|
||||||
#include "nsITraceableChannel.h"
|
#include "nsITraceableChannel.h"
|
||||||
#include "nsIHttpChannelAuthProvider.h"
|
#include "nsIHttpChannelAuthProvider.h"
|
||||||
|
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||||
|
|
||||||
class nsAHttpConnection;
|
class nsAHttpConnection;
|
||||||
|
|
||||||
|
@ -84,6 +86,7 @@ class nsHttpChannel : public HttpBaseChannel
|
||||||
, public nsIHttpAuthenticableChannel
|
, public nsIHttpAuthenticableChannel
|
||||||
, public nsITraceableChannel
|
, public nsITraceableChannel
|
||||||
, public nsIApplicationCacheChannel
|
, public nsIApplicationCacheChannel
|
||||||
|
, public nsIAsyncVerifyRedirectCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
|
@ -100,6 +103,7 @@ public:
|
||||||
NS_DECL_NSITRACEABLECHANNEL
|
NS_DECL_NSITRACEABLECHANNEL
|
||||||
NS_DECL_NSIAPPLICATIONCACHECONTAINER
|
NS_DECL_NSIAPPLICATIONCACHECONTAINER
|
||||||
NS_DECL_NSIAPPLICATIONCACHECHANNEL
|
NS_DECL_NSIAPPLICATIONCACHECHANNEL
|
||||||
|
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||||
|
|
||||||
// nsIHttpAuthenticableChannel. We can't use
|
// nsIHttpAuthenticableChannel. We can't use
|
||||||
// NS_DECL_NSIHTTPAUTHENTICABLECHANNEL because it duplicates cancel() and
|
// NS_DECL_NSIHTTPAUTHENTICABLECHANNEL because it duplicates cancel() and
|
||||||
|
@ -160,6 +164,8 @@ public: /* internal necko use only */
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef nsresult (nsHttpChannel::*nsContinueRedirectionFunc)(nsresult result);
|
||||||
|
|
||||||
// AsyncCall may be used to call a member function asynchronously.
|
// AsyncCall may be used to call a member function asynchronously.
|
||||||
// retval isn't refcounted and is set only when event was successfully
|
// retval isn't refcounted and is set only when event was successfully
|
||||||
// posted, the event is returned for the purpose of cancelling when needed
|
// posted, the event is returned for the purpose of cancelling when needed
|
||||||
|
@ -176,25 +182,38 @@ private:
|
||||||
nsresult ApplyContentConversions();
|
nsresult ApplyContentConversions();
|
||||||
nsresult CallOnStartRequest();
|
nsresult CallOnStartRequest();
|
||||||
nsresult ProcessResponse();
|
nsresult ProcessResponse();
|
||||||
|
nsresult ContinueProcessResponse(nsresult);
|
||||||
nsresult ProcessNormal();
|
nsresult ProcessNormal();
|
||||||
|
nsresult ContinueProcessNormal(nsresult);
|
||||||
nsresult ProcessNotModified();
|
nsresult ProcessNotModified();
|
||||||
nsresult ProcessRedirection(PRUint32 httpStatus);
|
nsresult AsyncProcessRedirection(PRUint32 httpStatus);
|
||||||
|
nsresult ContinueProcessRedirection(nsresult);
|
||||||
|
nsresult ContinueProcessRedirectionAfterFallback(nsresult);
|
||||||
PRBool ShouldSSLProxyResponseContinue(PRUint32 httpStatus);
|
PRBool ShouldSSLProxyResponseContinue(PRUint32 httpStatus);
|
||||||
nsresult ProcessFailedSSLConnect(PRUint32 httpStatus);
|
nsresult ProcessFailedSSLConnect(PRUint32 httpStatus);
|
||||||
nsresult ProcessFallback(PRBool *fallingBack);
|
nsresult ProcessFallback(PRBool *waitingForRedirectCallback);
|
||||||
|
nsresult ContinueProcessFallback(nsresult);
|
||||||
PRBool ResponseWouldVary();
|
PRBool ResponseWouldVary();
|
||||||
|
|
||||||
|
nsresult ContinueOnStartRequest1(nsresult);
|
||||||
|
nsresult ContinueOnStartRequest2(nsresult);
|
||||||
|
nsresult ContinueOnStartRequest3(nsresult);
|
||||||
|
|
||||||
// redirection specific methods
|
// redirection specific methods
|
||||||
void HandleAsyncRedirect();
|
void HandleAsyncRedirect();
|
||||||
|
nsresult ContinueHandleAsyncRedirect(nsresult);
|
||||||
void HandleAsyncNotModified();
|
void HandleAsyncNotModified();
|
||||||
void HandleAsyncFallback();
|
void HandleAsyncFallback();
|
||||||
|
nsresult ContinueHandleAsyncFallback(nsresult);
|
||||||
nsresult PromptTempRedirect();
|
nsresult PromptTempRedirect();
|
||||||
nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, PRBool preserveMethod);
|
nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, PRBool preserveMethod);
|
||||||
|
|
||||||
// proxy specific methods
|
// proxy specific methods
|
||||||
nsresult ProxyFailover();
|
nsresult ProxyFailover();
|
||||||
nsresult DoReplaceWithProxy(nsIProxyInfo *);
|
nsresult AsyncDoReplaceWithProxy(nsIProxyInfo *);
|
||||||
|
nsresult ContinueDoReplaceWithProxy(nsresult);
|
||||||
void HandleAsyncReplaceWithProxy();
|
void HandleAsyncReplaceWithProxy();
|
||||||
|
nsresult ContinueHandleAsyncReplaceWithProxy(nsresult);
|
||||||
nsresult ResolveProxy();
|
nsresult ResolveProxy();
|
||||||
|
|
||||||
// cache specific methods
|
// cache specific methods
|
||||||
|
@ -276,11 +295,14 @@ private:
|
||||||
// cache entry.
|
// cache entry.
|
||||||
nsCString mFallbackKey;
|
nsCString mFallbackKey;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIURI> mRedirectURI;
|
||||||
|
nsCOMPtr<nsIChannel> mRedirectChannel;
|
||||||
|
PRUint32 mRedirectType;
|
||||||
|
|
||||||
// state flags
|
// state flags
|
||||||
PRUint32 mApplyConversion : 1;
|
PRUint32 mApplyConversion : 1;
|
||||||
PRUint32 mCachedContentIsValid : 1;
|
PRUint32 mCachedContentIsValid : 1;
|
||||||
PRUint32 mCachedContentIsPartial : 1;
|
PRUint32 mCachedContentIsPartial : 1;
|
||||||
PRUint32 mCanceled : 1;
|
|
||||||
PRUint32 mTransactionReplaced : 1;
|
PRUint32 mTransactionReplaced : 1;
|
||||||
PRUint32 mAuthRetryPending : 1;
|
PRUint32 mAuthRetryPending : 1;
|
||||||
PRUint32 mResuming : 1;
|
PRUint32 mResuming : 1;
|
||||||
|
@ -300,6 +322,8 @@ private:
|
||||||
// headers. In such a case we must not override them in the cache code
|
// 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.
|
// and also we want to pass possible 304 code response through.
|
||||||
PRUint32 mCustomConditionalRequest : 1;
|
PRUint32 mCustomConditionalRequest : 1;
|
||||||
|
PRUint32 mFallingBack : 1;
|
||||||
|
PRUint32 mWaitingForRedirectCallback : 1;
|
||||||
// True iff this channel is servicing a remote HttpChannelChild
|
// True iff this channel is servicing a remote HttpChannelChild
|
||||||
PRUint32 mRemoteChannel : 1;
|
PRUint32 mRemoteChannel : 1;
|
||||||
|
|
||||||
|
@ -326,6 +350,12 @@ private:
|
||||||
|
|
||||||
PRPackedBool mReady;
|
PRPackedBool mReady;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nsTArray<nsContinueRedirectionFunc> mRedirectFuncStack;
|
||||||
|
|
||||||
|
nsresult WaitForRedirectCallback();
|
||||||
|
void PushRedirectAsyncFunc(nsContinueRedirectionFunc func);
|
||||||
|
void PopRedirectAsyncFunc(nsContinueRedirectionFunc func);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsHttpChannel_h__
|
#endif // nsHttpChannel_h__
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
#include "nsQuickSort.h"
|
#include "nsQuickSort.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsIOService.h"
|
#include "nsIOService.h"
|
||||||
|
#include "nsAsyncRedirectVerifyHelper.h"
|
||||||
|
|
||||||
#include "nsIXULAppInfo.h"
|
#include "nsIXULAppInfo.h"
|
||||||
|
|
||||||
|
@ -530,22 +531,14 @@ nsHttpHandler::NotifyObservers(nsIHttpChannel *chan, const char *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsHttpHandler::OnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
nsHttpHandler::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
||||||
PRUint32 flags)
|
PRUint32 flags)
|
||||||
{
|
{
|
||||||
// First, the global observer
|
// TODO E10S This helper has to be initialized on the other process
|
||||||
NS_ASSERTION(gIOService, "Must have an IO service at this point");
|
nsRefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
|
||||||
nsresult rv = gIOService->OnChannelRedirect(oldChan, newChan, flags);
|
new nsAsyncRedirectVerifyHelper();
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
// Now, the per-channel observers
|
return redirectCallbackHelper->Init(oldChan, newChan, flags);
|
||||||
nsCOMPtr<nsIChannelEventSink> sink;
|
|
||||||
NS_QueryNotificationCallbacks(oldChan, sink);
|
|
||||||
if (sink)
|
|
||||||
rv = sink->OnChannelRedirect(oldChan, newChan, flags);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ nsresult
|
/* static */ nsresult
|
||||||
|
|
|
@ -195,7 +195,7 @@ public:
|
||||||
|
|
||||||
// Called by channels before a redirect happens. This notifies both the
|
// Called by channels before a redirect happens. This notifies both the
|
||||||
// channel's and the global redirect observers.
|
// channel's and the global redirect observers.
|
||||||
nsresult OnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
nsresult AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
||||||
PRUint32 flags);
|
PRUint32 flags);
|
||||||
|
|
||||||
// Called by the channel when the response is read from the cache without
|
// 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
|
* using any feature exposed by this interface, be aware that this interface
|
||||||
* will change and you will be broken. You have been warned.
|
* will change and you will be broken. You have been warned.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(0eb66361-faaa-4e52-8c7e-6c25f11f8e3c)]
|
[scriptable, uuid(91dbb42a-dffc-4f47-8b27-9579c0d92c3f)]
|
||||||
interface nsIHttpChannelInternal : nsISupports
|
interface nsIHttpChannelInternal : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -83,4 +83,9 @@ interface nsIHttpChannelInternal : nsISupports
|
||||||
* wouldn't be.
|
* wouldn't be.
|
||||||
*/
|
*/
|
||||||
attribute boolean forceAllowThirdPartyCookie;
|
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;
|
this._got_onstartrequest = true;
|
||||||
|
|
||||||
request.QueryInterface(Components.interfaces.nsIChannel);
|
request.QueryInterface(Components.interfaces.nsIChannel);
|
||||||
this._contentLen = request.contentLength;
|
try {
|
||||||
if (this._contentLen == -1)
|
this._contentLen = request.contentLength;
|
||||||
|
}
|
||||||
|
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!");
|
do_throw("Content length is unknown in onStartRequest!");
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
do_throw("Error in onStartRequest: " + 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();
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче