Backed out 4 changesets (bug 497003) for intermittent OSX crashes.

Backed out changeset 43223a927976 (bug 497003)
Backed out changeset 26c1d80edf1f (bug 497003)
Backed out changeset 841ed173ba2b (bug 497003)
Backed out changeset f70770fc6dce (bug 497003)
This commit is contained in:
Ryan VanderMeulen 2013-06-17 15:44:07 -04:00
parent 30e55b0314
commit ca0cc81efe
22 changed files with 59 additions and 771 deletions

View File

@ -95,8 +95,6 @@ XPIDL_SOURCES += [
'nsIStrictTransportSecurityService.idl',
'nsISyncStreamListener.idl',
'nsISystemProxySettings.idl',
'nsIThreadRetargetableRequest.idl',
'nsIThreadRetargetableStreamListener.idl',
'nsITimedChannel.idl',
'nsITraceableChannel.idl',
'nsITransport.idl',

View File

@ -11,11 +11,10 @@ interface nsIStreamListener;
* nsIInputStreamPump
*
* This interface provides a means to configure and use a input stream pump
* instance. The input stream pump will asynchronously read from an input
* stream, and push data to an nsIStreamListener instance. It utilizes the
* instance. The input stream pump will asynchronously read from a input
* stream, and push data to a nsIStreamListener instance. It utilizes the
* current thread's nsIEventTarget in order to make reading from the stream
* asynchronous. A different thread can be used if the pump also implements
* nsIThreadRetargetableRequest.
* asynchronous.
*
* If the given stream supports nsIAsyncInputStream, then the stream pump will
* call the stream's AsyncWait method to drive the stream listener. Otherwise,

View File

@ -1,34 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
#include "nsIEventTarget.idl"
/**
* nsIThreadRetargetableRequest
*
* Should be implemented by requests that support retargeting delivery of
* OnDataAvailable and OnStopRequest off the main thread.
*/
[uuid(27b84c48-5a73-4ba4-a8a4-8b5e649a145e)]
interface nsIThreadRetargetableRequest : nsISupports
{
/**
* Called to retarget delivery of OnDataAvailable and OnStopRequest to
* another thread. Should only be called within the context of OnStartRequest
* on the main thread.
*
* @param aNewTarget New event target, e.g. thread or threadpool.
*
* Note: no return value is given. If the retargeting cannot be handled,
* normal delivery to the main thread will continue. As such, listeners
* should be ready to deal with OnDataAvailable and OnStopRequest on
* either the main thread or the new target thread.
*/
void retargetDeliveryTo(in nsIEventTarget aNewTarget);
};

View File

@ -1,34 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
/**
* nsIThreadRetargetableListener
*
* To be used by classes which implement nsIStreamListener and whose
* OnDataAvailable and OnStopRequest may be retargeted for delivery off the
* main thread.
*/
[uuid(fb2304b8-f82f-4433-af68-d874a2ebbdc1)]
interface nsIThreadRetargetableStreamListener : nsISupports
{
/**
* Checks this listener and any next listeners it may have to verify that
* they can receive OnDataAvailable and OnStopRequest off the main thread.
* It is the responsibility of the implementing class to decide on the
* criteria to determine if retargeted delivery of these methods is
* possible, but it must check any and all nsIStreamListener objects that
* might be called in the listener chain.
*
* An exception should be thrown if a listener in the chain does not
* support retargeted delivery, i.e. if the next listener does not implement
* nsIThreadRetargetableStreamListener, or a call to its checkListenerChain()
* fails.
*/
void checkListenerChain();
};

View File

@ -8,13 +8,11 @@
#include "nsCOMPtr.h"
#include "nsIStreamListener.h"
#include "nsIRequestObserver.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "mozilla/Attributes.h"
// Wrapper class to make replacement of nsHttpChannel's listener
// from JavaScript possible. It is workaround for bug 433711 and 682305.
class nsStreamListenerWrapper MOZ_FINAL : public nsIStreamListener
, public nsIThreadRetargetableStreamListener
{
public:
nsStreamListenerWrapper(nsIStreamListener *listener)
@ -26,7 +24,6 @@ public:
NS_DECL_ISUPPORTS
NS_FORWARD_NSIREQUESTOBSERVER(mListener->)
NS_FORWARD_NSISTREAMLISTENER(mListener->)
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
private:
~nsStreamListenerWrapper() {}

View File

@ -11,13 +11,10 @@
#include "nsIInterfaceRequestorUtils.h"
#include "nsISeekableStream.h"
#include "nsITransport.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "nsStreamUtils.h"
#include "nsNetUtil.h"
#include "nsThreadUtils.h"
#include "nsCOMPtr.h"
#include "prlog.h"
#include "nsPrintfCString.h"
#include "GeckoProfiler.h"
#include <algorithm>
@ -44,7 +41,6 @@ nsInputStreamPump::nsInputStreamPump()
, mLoadFlags(LOAD_NORMAL)
, mWaiting(false)
, mCloseWhenDone(false)
, mRetargeting(false)
{
#if defined(PR_LOGGING)
if (!gStreamPumpLog)
@ -123,18 +119,14 @@ nsresult
nsInputStreamPump::EnsureWaiting()
{
// no need to worry about multiple threads... an input stream pump lives
// on only one thread at a time.
MOZ_ASSERT(mAsyncStream);
// on only one thread.
if (!mWaiting) {
MOZ_ASSERT(mTargetThread);
nsresult rv = mAsyncStream->AsyncWait(this, 0, 0, mTargetThread);
if (NS_FAILED(rv)) {
NS_ERROR("AsyncWait failed");
return rv;
}
// Any retargeting during STATE_START or START_TRANSFER is complete
// after the call to AsyncWait; next callback wil be on mTargetThread.
mRetargeting = false;
mWaiting = true;
}
return NS_OK;
@ -147,9 +139,8 @@ nsInputStreamPump::EnsureWaiting()
// although this class can only be accessed from one thread at a time, we do
// allow its ownership to move from thread to thread, assuming the consumer
// understands the limitations of this.
NS_IMPL_THREADSAFE_ISUPPORTS4(nsInputStreamPump,
NS_IMPL_THREADSAFE_ISUPPORTS3(nsInputStreamPump,
nsIRequest,
nsIThreadRetargetableRequest,
nsIInputStreamCallback,
nsIInputStreamPump)
@ -389,30 +380,15 @@ nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream)
return NS_ERROR_UNEXPECTED;
}
bool stillTransferring = (mState == STATE_TRANSFER &&
nextState == STATE_TRANSFER);
if (stillTransferring) {
NS_ASSERTION(NS_SUCCEEDED(mStatus),
"Should not have failed status for ongoing transfer");
} else {
NS_ASSERTION(mState != nextState,
"Only OnStateTransfer can be called more than once.");
}
if (mRetargeting) {
NS_ASSERTION(mState != STATE_STOP,
"Retargeting should not happen during OnStateStop.");
}
if (mState == nextState && !mSuspendCount) {
NS_ASSERTION(mState == STATE_TRANSFER, "unexpected state");
NS_ASSERTION(NS_SUCCEEDED(mStatus), "unexpected status");
// Wait asynchronously if there is still data to transfer, or if
// delivery of data has been requested on another thread.
if (!mSuspendCount && (stillTransferring || mRetargeting)) {
mState = nextState;
mWaiting = false;
mStatus = EnsureWaiting();
if (NS_SUCCEEDED(mStatus))
break;
// Failure to start asynchronous wait: stop transfer.
nextState = STATE_STOP;
}
@ -575,7 +551,6 @@ nsInputStreamPump::OnStateStop()
mAsyncStream = 0;
mTargetThread = 0;
mIsPending = false;
mRetargeting = false;
mListener->OnStopRequest(this, mListenerContext, mStatus);
mListener = 0;
@ -586,37 +561,3 @@ nsInputStreamPump::OnStateStop()
return STATE_IDLE;
}
//-----------------------------------------------------------------------------
// nsIThreadRetargetableRequest
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsInputStreamPump::RetargetDeliveryTo(nsIEventTarget* aNewTarget)
{
NS_ENSURE_ARG(aNewTarget);
if (aNewTarget == mTargetThread) {
NS_WARNING("Retargeting delivery to same thread");
return NS_OK;
}
NS_ENSURE_TRUE(mState == STATE_START || mState == STATE_TRANSFER,
NS_ERROR_UNEXPECTED);
// Ensure that |mListener| and any subsequent listeners can be retargeted
// to another thread.
nsresult rv = NS_OK;
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
do_QueryInterface(mListener, &rv);
if (NS_SUCCEEDED(rv) && retargetableListener) {
rv = retargetableListener->CheckListenerChain();
if (NS_SUCCEEDED(rv)) {
mTargetThread = aNewTarget;
mRetargeting = true;
}
}
LOG(("nsInputStreamPump::RetargetDeliveryTo [this=%x aNewTarget=%p] "
"%s listener [%p] rv[%x]",
this, aNewTarget, (mTargetThread == aNewTarget ? "success" : "failure"),
(nsIStreamListener*)mListener, rv));
return rv;
}

View File

@ -15,20 +15,17 @@
#include "nsIProgressEventSink.h"
#include "nsIAsyncInputStream.h"
#include "nsIThread.h"
#include "nsIThreadRetargetableRequest.h"
#include "nsCOMPtr.h"
#include "mozilla/Attributes.h"
class nsInputStreamPump MOZ_FINAL : public nsIInputStreamPump
, public nsIInputStreamCallback
, public nsIThreadRetargetableRequest
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUEST
NS_DECL_NSIINPUTSTREAMPUMP
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_NSITHREADRETARGETABLEREQUEST
nsInputStreamPump();
~nsInputStreamPump();
@ -74,7 +71,7 @@ protected:
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsIStreamListener> mListener;
nsCOMPtr<nsISupports> mListenerContext;
nsCOMPtr<nsIEventTarget> mTargetThread;
nsCOMPtr<nsIThread> mTargetThread;
nsCOMPtr<nsIInputStream> mStream;
nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
uint64_t mStreamOffset;
@ -87,7 +84,6 @@ protected:
bool mIsPending;
bool mWaiting; // true if waiting on async source
bool mCloseWhenDone;
bool mRetargeting;
};
#endif // !nsInputStreamChannel_h__

View File

@ -5,11 +5,10 @@
#include "nsStreamListenerTee.h"
#include "nsProxyRelease.h"
NS_IMPL_THREADSAFE_ISUPPORTS4(nsStreamListenerTee,
nsIStreamListener,
nsIRequestObserver,
nsIStreamListenerTee,
nsIThreadRetargetableStreamListener)
NS_IMPL_ISUPPORTS3(nsStreamListenerTee,
nsIStreamListener,
nsIRequestObserver,
nsIStreamListenerTee)
NS_IMETHODIMP
nsStreamListenerTee::OnStartRequest(nsIRequest *request,
@ -93,29 +92,6 @@ nsStreamListenerTee::OnDataAvailable(nsIRequest *request,
return mListener->OnDataAvailable(request, context, tee, offset, count);
}
NS_IMETHODIMP
nsStreamListenerTee::CheckListenerChain()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!");
nsresult rv = NS_OK;
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
do_QueryInterface(mListener, &rv);
if (retargetableListener) {
rv = retargetableListener->CheckListenerChain();
}
if (NS_FAILED(rv)) {
return rv;
}
if (!mObserver) {
return rv;
}
retargetableListener = do_QueryInterface(mObserver, &rv);
if (retargetableListener) {
rv = retargetableListener->CheckListenerChain();
}
return rv;
}
NS_IMETHODIMP
nsStreamListenerTee::Init(nsIStreamListener *listener,
nsIOutputStream *sink,

View File

@ -6,20 +6,17 @@
#define nsStreamListenerTee_h__
#include "nsIStreamListenerTee.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "nsIInputStreamTee.h"
#include "nsIOutputStream.h"
#include "nsCOMPtr.h"
#include "nsIEventTarget.h"
class nsStreamListenerTee : public nsIStreamListenerTee
, public nsIThreadRetargetableStreamListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
NS_DECL_NSISTREAMLISTENERTEE
nsStreamListenerTee() { }

View File

@ -3,22 +3,8 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsStreamListenerWrapper.h"
#include "nsThreadUtils.h"
NS_IMPL_ISUPPORTS3(nsStreamListenerWrapper,
NS_IMPL_ISUPPORTS2(nsStreamListenerWrapper,
nsIStreamListener,
nsIRequestObserver,
nsIThreadRetargetableStreamListener)
nsIRequestObserver)
NS_IMETHODIMP
nsStreamListenerWrapper::CheckListenerChain()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!");
nsresult rv = NS_OK;
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
do_QueryInterface(mListener, &rv);
if (retargetableListener) {
rv = retargetableListener->CheckListenerChain();
}
return rv;
}

View File

@ -29,7 +29,6 @@
#include "nsIRedirectResultListener.h"
#include "mozilla/TimeStamp.h"
#include "nsError.h"
#include "nsPrintfCString.h"
#include "nsAlgorithm.h"
#include "GeckoProfiler.h"
#include "nsIConsoleService.h"
@ -4253,8 +4252,6 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
NS_INTERFACE_MAP_ENTRY(nsITimedChannel)
NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest)
NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableStreamListener)
NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
//-----------------------------------------------------------------------------
@ -4946,42 +4943,6 @@ nsHttpChannel::ContinueOnStartRequest3(nsresult result)
return CallOnStartRequest();
}
class OnStopRequestCleanupEvent : public nsRunnable
{
public:
OnStopRequestCleanupEvent(nsHttpChannel *aHttpChannel,
nsresult aStatus)
: mHttpChannel(aHttpChannel)
, mStatus(aStatus)
{
MOZ_ASSERT(!NS_IsMainThread(), "Shouldn't be created on main thread");
NS_ASSERTION(aHttpChannel, "aHttpChannel should not be null");
}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread(), "Should run on main thread");
if (mHttpChannel) {
mHttpChannel->OnStopRequestCleanup(mStatus);
}
return NS_OK;
}
private:
nsRefPtr<nsHttpChannel> mHttpChannel;
nsresult mStatus;
};
nsresult
nsHttpChannel::OnStopRequestCleanup(nsresult aStatus)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread");
if (mLoadGroup) {
mLoadGroup->RemoveRequest(this, nullptr, aStatus);
}
ReleaseListeners();
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult status)
{
@ -5111,17 +5072,14 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
if (mOfflineCacheEntry)
CloseOfflineCacheEntry();
if (NS_IsMainThread()) {
OnStopRequestCleanup(status);
} else {
nsresult rv = NS_DispatchToMainThread(
new OnStopRequestCleanupEvent(this, status));
NS_ENSURE_SUCCESS(rv, rv);
}
if (mLoadGroup)
mLoadGroup->RemoveRequest(this, nullptr, status);
// We don't need this info anymore
CleanRedirectCacheChainIfNecessary();
ReleaseListeners();
return NS_OK;
}
@ -5129,37 +5087,6 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
// nsHttpChannel::nsIStreamListener
//-----------------------------------------------------------------------------
class OnTransportStatusAsyncEvent : public nsRunnable
{
public:
OnTransportStatusAsyncEvent(nsITransportEventSink* aEventSink,
nsresult aTransportStatus,
uint64_t aProgress,
uint64_t aProgressMax)
: mEventSink(aEventSink)
, mTransportStatus(aTransportStatus)
, mProgress(aProgress)
, mProgressMax(aProgressMax)
{
MOZ_ASSERT(!NS_IsMainThread(), "Shouldn't be created on main thread");
}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread(), "Should run on main thread");
if (mEventSink) {
mEventSink->OnTransportStatus(nullptr, mTransportStatus,
mProgress, mProgressMax);
}
return NS_OK;
}
private:
nsCOMPtr<nsITransportEventSink> mEventSink;
nsresult mTransportStatus;
uint64_t mProgress;
uint64_t mProgressMax;
};
NS_IMETHODIMP
nsHttpChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
nsIInputStream *input,
@ -5204,14 +5131,7 @@ nsHttpChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
uint64_t progress = mLogicalOffset + uint64_t(count);
MOZ_ASSERT(progress <= progressMax, "unexpected progress values");
if (NS_IsMainThread()) {
OnTransportStatus(nullptr, transportStatus, progress, progressMax);
} else {
nsresult rv = NS_DispatchToMainThread(
new OnTransportStatusAsyncEvent(this, transportStatus,
progress, progressMax));
NS_ENSURE_SUCCESS(rv, rv);
}
OnTransportStatus(nullptr, transportStatus, progress, progressMax);
//
// we have to manually keep the logical offset of the stream up-to-date.
@ -5235,67 +5155,6 @@ nsHttpChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
return NS_ERROR_ABORT;
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsIThreadRetargetableRequest
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsHttpChannel::RetargetDeliveryTo(nsIEventTarget* aNewTarget)
{
MOZ_ASSERT(NS_IsMainThread(), "Should be called on main thread only");
NS_ENSURE_ARG(aNewTarget);
if (aNewTarget == NS_GetCurrentThread()) {
NS_WARNING("Retargeting delivery to same thread");
return NS_OK;
}
NS_ENSURE_TRUE(mTransactionPump || mCachePump, NS_ERROR_NOT_AVAILABLE);
nsresult rv = NS_OK;
// If both cache pump and transaction pump exist, we're probably dealing
// with partially cached content. So, we must be able to retarget both.
nsCOMPtr<nsIThreadRetargetableRequest> retargetableCachePump;
nsCOMPtr<nsIThreadRetargetableRequest> retargetableTransactionPump;
if (mCachePump) {
retargetableCachePump = do_QueryObject(mCachePump);
// nsInputStreamPump should implement this interface.
MOZ_ASSERT(retargetableCachePump);
rv = retargetableCachePump->RetargetDeliveryTo(aNewTarget);
}
if (NS_SUCCEEDED(rv) && mTransactionPump) {
retargetableTransactionPump = do_QueryObject(mTransactionPump);
// nsInputStreamPump should implement this interface.
MOZ_ASSERT(retargetableTransactionPump);
rv = retargetableTransactionPump->RetargetDeliveryTo(aNewTarget);
// If retarget fails for transaction pump, we must restore mCachePump.
if (NS_FAILED(rv) && retargetableCachePump) {
nsCOMPtr<nsIThread> mainThread;
rv = NS_GetMainThread(getter_AddRefs(mainThread));
NS_ENSURE_SUCCESS(rv, rv);
rv = retargetableCachePump->RetargetDeliveryTo(mainThread);
}
}
return rv;
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsThreadRetargetableStreamListener
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsHttpChannel::CheckListenerChain()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!");
nsresult rv = NS_OK;
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
do_QueryInterface(mListener, &rv);
if (retargetableListener) {
rv = retargetableListener->CheckListenerChain();
}
return rv;
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsITransportEventSink
//-----------------------------------------------------------------------------

View File

@ -28,8 +28,6 @@
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsITimedChannel.h"
#include "nsIFile.h"
#include "nsIThreadRetargetableRequest.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "nsDNSPrefetch.h"
#include "TimingStruct.h"
#include "AutoClose.h"
@ -56,14 +54,11 @@ class nsHttpChannel : public HttpBaseChannel
, public nsIApplicationCacheChannel
, public nsIAsyncVerifyRedirectCallback
, public nsITimedChannel
, public nsIThreadRetargetableRequest
, public nsIThreadRetargetableStreamListener
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
NS_DECL_NSICACHEINFOCHANNEL
NS_DECL_NSICACHINGCHANNEL
NS_DECL_NSICACHELISTENER
@ -74,7 +69,6 @@ public:
NS_DECL_NSIAPPLICATIONCACHECHANNEL
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
NS_DECL_NSITIMEDCHANNEL
NS_DECL_NSITHREADRETARGETABLEREQUEST
// nsIHttpAuthenticableChannel. We can't use
// NS_DECL_NSIHTTPAUTHENTICABLECHANNEL because it duplicates cancel() and
@ -156,8 +150,6 @@ public: /* internal necko use only */
OfflineCacheEntryAsForeignMarker* GetOfflineCacheEntryAsForeignMarker();
nsresult OnStopRequestCleanup(nsresult aStatus);
private:
typedef nsresult (nsHttpChannel::*nsContinueRedirectionFunc)(nsresult result);

View File

@ -1,21 +0,0 @@
# -*- Mode: Makefile; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# vim: set ts=8 sts=2 et sw=2 tw=80:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = @relativesrcdir@
FAIL_ON_WARNINGS := 1
include $(DEPTH)/config/autoconf.mk
MOCHITEST_FILES = \
partial_content.sjs \
test_partially_cached_content.html \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -1,7 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'test_necko'

View File

@ -1,154 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Debug and Error wrapper functions for dump().
*/
function ERR(response, responseCode, responseCodeStr, msg)
{
// Reset state var.
setState("expectedRequestType", "");
// Dump to console log and send to client in response.
dump("SERVER ERROR: " + msg + "\n");
response.write("HTTP/1.1" + responseCode + responseCodeStr + "\r\n");
response.write("Content-Type: text/html; charset=UTF-8\r\n");
response.write("Content-Length: " + msg.length + "\r\n");
response.write("\r\n");
response.write(msg);
}
function DBG(msg)
{
// enable when you want to debug
if (0) {
// Dump to console only.
dump("SERVER DEBUG: " + msg + "\n");
}
}
/* Delivers content in parts to test partially cached content: requires two
* requests for the same resource.
*
* First call will respond with partial content, but a 200 header and
* Content-Length equal to the full content length. No Range or If-Range
* headers are allowed in the request.
*
* Second call will require Range and If-Range in the request headers, and
* will respond with the range requested.
*/
function handleRequest(request, response)
{
DBG("Trying to seize power");
response.seizePower();
DBG("About to check state vars");
// Get state var to determine if this is the first or second request.
var expectedRequestType;
var lastModified;
if (getState("expectedRequestType") === "") {
DBG("First call: Should be requesting full content.");
expectedRequestType = "fullRequest";
// Set state var for second request.
setState("expectedRequestType", "partialRequest");
// Create lastModified variable for responses.
lastModified = (new Date()).toUTCString();
setState("lastModified", lastModified);
} else if (getState("expectedRequestType") === "partialRequest") {
DBG("Second call: Should be requesting undelivered content.");
expectedRequestType = "partialRequest";
// Reset state var for first request.
setState("expectedRequestType", "");
// Get last modified date and reset state var.
lastModified = getState("lastModified");
} else {
ERR(response, 500, "Internal Server Error",
"Invalid expectedRequestType \"" + expectedRequestType + "\"in " +
"server state db.");
return;
}
// Look for Range and If-Range
var range = request.hasHeader("Range") ? request.getHeader("Range") : "";
var ifRange = request.hasHeader("If-Range") ? request.getHeader("If-Range") : "";
if (expectedRequestType === "fullRequest") {
// Should not have Range or If-Range in first request.
if (range && range.length > 0) {
ERR(response, 400, "Bad Request",
"Should not receive \"Range: " + range + "\" for first, full request.");
return;
}
if (ifRange && ifRange.length > 0) {
ERR(response, 400, "Bad Request",
"Should not receive \"Range: " + range + "\" for first, full request.");
return;
}
} else if (expectedRequestType === "partialRequest") {
// Range AND If-Range should both be present in second request.
if (!range) {
ERR(response, 400, "Bad Request",
"Should receive \"Range: \" for second, partial request.");
return;
}
if (!ifRange) {
ERR(response, 400, "Bad Request",
"Should receive \"If-Range: \" for second, partial request.");
return;
}
} else {
// Somewhat redundant, but a check for errors in this test code.
ERR(response, 500, "Internal Server Error",
"expectedRequestType not set correctly: \"" + expectedRequestType + "\"");
return;
}
// Prepare content in two parts for responses.
var partialContent = "<html><head></head><body><p id=\"firstResponse\">" +
"First response</p>";
var remainderContent = "<p id=\"secondResponse\">Second response</p>" +
"</body></html>";
var totalLength = partialContent.length + remainderContent.length;
DBG("totalLength: " + totalLength);
// Prepare common headers for the two responses.
date = new Date();
DBG("Date: " + date.toUTCString() + ", Last-Modified: " + lastModified);
var commonHeaders = "Date: " + date.toUTCString() + "\r\n" +
"Last-Modified: " + lastModified + "\r\n" +
"Content-Type: text/html; charset=UTF-8\r\n" +
"ETag: abcd0123\r\n" +
"Accept-Ranges: bytes\r\n";
// Prepare specific headers and content for first and second responses.
if (expectedRequestType === "fullRequest") {
DBG("First response: Sending partial content with a full header");
response.write("HTTP/1.1 200 OK\r\n");
response.write(commonHeaders);
// Set Content-Length to full length of resource.
response.write("Content-Length: " + totalLength + "\r\n");
response.write("\r\n");
response.write(partialContent);
} else if (expectedRequestType === "partialRequest") {
DBG("Second response: Sending remaining content with a range header");
response.write("HTTP/1.1 206 Partial Content\r\n");
response.write(commonHeaders);
// Set Content-Length to length of bytes transmitted.
response.write("Content-Length: " + remainderContent.length + "\r\n");
response.write("Content-Range: bytes " + partialContent.length + "-" +
(totalLength - 1) + "/" + totalLength + "\r\n");
response.write("\r\n");
response.write(remainderContent);
} else {
// Somewhat redundant, but a check for errors in this test code.
ERR(response, 500, "Internal Server Error",
"Something very bad happened here: expectedRequestType is invalid " +
"towards the end of handleRequest! - \"" + expectedRequestType + "\"");
return;
}
response.finish();
}

View File

@ -1,90 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=497003
This test verifies that partially cached content is read from the cache first
and then from the network. It is written in the mochitest framework to take
thread retargeting into consideration of nsIStreamListener callbacks (inc.
nsIRequestObserver). E.g. HTML5 Stream Parser requesting retargeting of
nsIStreamListener callbacks to the parser thread.
-->
<head>
<meta charset="UTF-8">
<title>Test for Bug 497003: support sending OnDataAvailable() to other threads</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p><a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=497003">Mozilla Bug 497003: support sending OnDataAvailable() to other threads</a></p>
<p><iframe id="contentFrame" src="partial_content.sjs"></iframe></p>
<pre id="test">
<script>
/* Check that the iframe has initial content only after the first load.
*/
function expectInitialContent(e) {
info("expectInitialContent",
"First response received: should have partial content");
var frameWindow = document.getElementById('contentFrame').contentWindow;
// Expect "First response" in received HTML.
var firstResponse = frameWindow.document.getElementById('firstResponse');
ok(firstResponse, "First response should exist");
if (firstResponse) {
is(firstResponse.innerHTML, "First response",
"First response should be correct");
}
// Expect NOT to get any second response element.
var secondResponse = frameWindow.document.getElementById('secondResponse');
ok(!secondResponse, "Should not get text for second response in first.");
// Set up listener for second load.
e.target.removeEventListener("load", expectInitialContent, false);
e.target.addEventListener("load", expectFullContent, false);
// Reload.
e.target.src="partial_content.sjs";
}
/* Check that the iframe has all the content after the second load.
*/
function expectFullContent(e)
{
info("expectFullContent",
"Second response received: should complete content from first load");
var frameWindow = document.getElementById('contentFrame').contentWindow;
// Expect "First response" to still be there
var firstResponse = frameWindow.document.getElementById('firstResponse');
ok(firstResponse, "First response should exist");
if (firstResponse) {
is(firstResponse.innerHTML, "First response",
"First response should be correct");
}
// Expect "Second response" to be there also.
var secondResponse = frameWindow.document.getElementById('secondResponse');
ok(secondResponse, "Second response should exist");
if (secondResponse) {
is(secondResponse.innerHTML, "Second response",
"Second response should be correct");
}
SimpleTest.finish();
}
// Set listener for first load to expect partial content.
document.getElementById('contentFrame')
.addEventListener("load", expectInitialContent, false);
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -4,7 +4,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
TEST_DIRS += ['httpserver', 'browser', 'mochitests']
TEST_DIRS += ['httpserver', 'browser']
MODULE = 'test_necko'

View File

@ -26,8 +26,6 @@
#include "nsINestedURI.h"
#include "nsCharsetSource.h"
#include "nsIWyciwygChannel.h"
#include "nsIThreadRetargetableRequest.h"
#include "nsPrintfCString.h"
#include "mozilla/dom/EncodingUtils.h"
@ -75,10 +73,9 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHtml5StreamParser)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHtml5StreamParser)
NS_INTERFACE_TABLE_HEAD(nsHtml5StreamParser)
NS_INTERFACE_TABLE3(nsHtml5StreamParser,
NS_INTERFACE_TABLE2(nsHtml5StreamParser,
nsIStreamListener,
nsICharsetDetectionObserver,
nsIThreadRetargetableStreamListener)
nsICharsetDetectionObserver)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsHtml5StreamParser)
NS_INTERFACE_MAP_END
@ -929,14 +926,6 @@ nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
mReparseForbidden = true;
mFeedChardet = false; // can't restart anyway
}
// Attempt to retarget delivery of data (via OnDataAvailable) to the parser
// thread, rather than through the main thread.
nsCOMPtr<nsIThreadRetargetableRequest> threadRetargetableRequest =
do_QueryInterface(mRequest);
if (threadRetargetableRequest) {
threadRetargetableRequest->RetargetDeliveryTo(mThread);
}
}
if (mCharsetSource == kCharsetFromParentFrame) {
@ -971,22 +960,6 @@ nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
return NS_OK;
}
NS_IMETHODIMP
nsHtml5StreamParser::CheckListenerChain()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread!");
if (!mObserver) {
return NS_OK;
}
nsresult rv;
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetable =
do_QueryInterface(mObserver, &rv);
if (NS_SUCCEEDED(rv) && retargetable) {
rv = retargetable->CheckListenerChain();
}
return rv;
}
void
nsHtml5StreamParser::DoStopRequest()
{
@ -1040,24 +1013,19 @@ nsHtml5StreamParser::OnStopRequest(nsIRequest* aRequest,
nsresult status)
{
NS_ASSERTION(mRequest == aRequest, "Got Stop on wrong stream.");
NS_ASSERTION(NS_IsMainThread() || IsParserThread(), "Wrong thread!");
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mObserver) {
mObserver->OnStopRequest(aRequest, aContext, status);
}
if (NS_IsMainThread()) {
nsCOMPtr<nsIRunnable> stopper = new nsHtml5RequestStopper(this);
if (NS_FAILED(mThread->Dispatch(stopper, nsIThread::DISPATCH_NORMAL))) {
NS_WARNING("Dispatching StopRequest event failed.");
}
} else {
mozilla::MutexAutoLock autoLock(mTokenizerMutex);
DoStopRequest();
nsCOMPtr<nsIRunnable> stopper = new nsHtml5RequestStopper(this);
if (NS_FAILED(mThread->Dispatch(stopper, nsIThread::DISPATCH_NORMAL))) {
NS_WARNING("Dispatching StopRequest event failed.");
}
return NS_OK;
}
void
nsHtml5StreamParser::DoDataAvailable(const uint8_t* aBuffer, uint32_t aLength)
nsHtml5StreamParser::DoDataAvailable(uint8_t* aBuffer, uint32_t aLength)
{
NS_ASSERTION(IsParserThread(), "Wrong thread!");
NS_PRECONDITION(STREAM_BEING_READ == mStreamState,
@ -1142,58 +1110,24 @@ nsHtml5StreamParser::OnDataAvailable(nsIRequest* aRequest,
NS_ASSERTION(mRequest == aRequest, "Got data on wrong stream.");
uint32_t totalRead;
// Main thread to parser thread dispatch requires copying to buffer first.
if (NS_IsMainThread()) {
const mozilla::fallible_t fallible = mozilla::fallible_t();
nsAutoArrayPtr<uint8_t> data(new (fallible) uint8_t[aLength]);
if (!data) {
return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
}
rv = aInStream->Read(reinterpret_cast<char*>(data.get()),
aLength, &totalRead);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(totalRead <= aLength, "Read more bytes than were available?");
nsCOMPtr<nsIRunnable> dataAvailable = new nsHtml5DataAvailable(this,
data.forget(),
totalRead);
if (NS_FAILED(mThread->Dispatch(dataAvailable, nsIThread::DISPATCH_NORMAL))) {
NS_WARNING("Dispatching DataAvailable event failed.");
}
return rv;
} else {
NS_ASSERTION(IsParserThread(), "Wrong thread!");
mozilla::MutexAutoLock autoLock(mTokenizerMutex);
// Read directly from response buffer.
rv = aInStream->ReadSegments(CopySegmentsToParser, this, aLength,
&totalRead);
if (NS_FAILED(rv)) {
NS_WARNING("Failed reading response data to parser");
return rv;
}
return NS_OK;
const mozilla::fallible_t fallible = mozilla::fallible_t();
nsAutoArrayPtr<uint8_t> data(new (fallible) uint8_t[aLength]);
if (!data) {
return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
}
rv = aInStream->Read(reinterpret_cast<char*>(data.get()),
aLength, &totalRead);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(totalRead <= aLength, "Read more bytes than were available?");
nsCOMPtr<nsIRunnable> dataAvailable = new nsHtml5DataAvailable(this,
data.forget(),
totalRead);
if (NS_FAILED(mThread->Dispatch(dataAvailable, nsIThread::DISPATCH_NORMAL))) {
NS_WARNING("Dispatching DataAvailable event failed.");
}
return rv;
}
/* static */
NS_METHOD
nsHtml5StreamParser::CopySegmentsToParser(nsIInputStream *aInStream,
void *aClosure,
const char *aFromSegment,
uint32_t aToOffset,
uint32_t aCount,
uint32_t *aWriteCount)
{
nsHtml5StreamParser* parser = static_cast<nsHtml5StreamParser*>(aClosure);
parser->DoDataAvailable((const uint8_t*)aFromSegment, aCount);
// Assume DoDataAvailable consumed all available bytes.
*aWriteCount = aCount;
return NS_OK;
}
bool
nsHtml5StreamParser::PreferredForInternalEncodingDecl(nsACString& aEncoding)
{

View File

@ -20,7 +20,6 @@
#include "nsHtml5Speculation.h"
#include "nsITimer.h"
#include "nsICharsetDetector.h"
#include "nsIThreadRetargetableStreamListener.h"
class nsHtml5Parser;
@ -102,7 +101,6 @@ enum eHtml5StreamState {
};
class nsHtml5StreamParser : public nsIStreamListener,
public nsIThreadRetargetableStreamListener,
public nsICharsetDetectionObserver {
friend class nsHtml5RequestStopper;
@ -127,8 +125,6 @@ class nsHtml5StreamParser : public nsIStreamListener,
NS_DECL_NSIREQUESTOBSERVER
// nsIStreamListener methods:
NS_DECL_NSISTREAMLISTENER
// nsIThreadRetargetableStreamListener methods:
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
// nsICharsetDetectionObserver
/**
@ -243,14 +239,7 @@ class nsHtml5StreamParser : public nsIStreamListener,
void DoStopRequest();
void DoDataAvailable(const uint8_t* aBuffer, uint32_t aLength);
static NS_METHOD CopySegmentsToParser(nsIInputStream *aInStream,
void *aClosure,
const char *aFromSegment,
uint32_t aToOffset,
uint32_t aCount,
uint32_t *aWriteCount);
void DoDataAvailable(uint8_t* aBuffer, uint32_t aLength);
bool IsTerminatedOrInterrupted() {
mozilla::MutexAutoLock autoLock(mTerminatedMutex);

View File

@ -228,6 +228,7 @@ class nsHtml5TreeOpExecutor : public nsContentSink,
* value if broken.
*/
inline nsresult IsBroken() {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return mBroken;
}

View File

@ -6,7 +6,6 @@
#include "nsURILoader.h"
#include "nsAutoPtr.h"
#include "nsProxyRelease.h"
#include "nsIURIContentListener.h"
#include "nsIContentHandler.h"
#include "nsILoadGroup.h"
@ -31,12 +30,10 @@
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "nsXPIDLString.h"
#include "nsString.h"
#include "nsNetUtil.h"
#include "nsThreadUtils.h"
#include "nsReadableUtils.h"
#include "nsError.h"
@ -66,7 +63,6 @@ PRLogModuleInfo* nsURILoader::mLog = nullptr;
* (or aborted).
*/
class nsDocumentOpenInfo MOZ_FINAL : public nsIStreamListener
, public nsIThreadRetargetableStreamListener
{
public:
// Needed for nsCOMPtr to work right... Don't call this!
@ -114,8 +110,6 @@ public:
// nsIStreamListener methods:
NS_DECL_NSISTREAMLISTENER
// nsIThreadRetargetableStreamListener
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
protected:
~nsDocumentOpenInfo();
@ -130,7 +124,7 @@ protected:
* The stream listener to forward nsIStreamListener notifications
* to. This is set once the load is dispatched.
*/
nsMainThreadPtrHandle<nsIStreamListener> m_targetStreamListener;
nsCOMPtr<nsIStreamListener> m_targetStreamListener;
/**
* A pointer to the entity that originated the load. We depend on getting
@ -165,7 +159,6 @@ NS_INTERFACE_MAP_BEGIN(nsDocumentOpenInfo)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableStreamListener)
NS_INTERFACE_MAP_END_THREADSAFE
nsDocumentOpenInfo::nsDocumentOpenInfo()
@ -273,22 +266,6 @@ NS_IMETHODIMP nsDocumentOpenInfo::OnStartRequest(nsIRequest *request, nsISupport
return rv;
}
NS_IMETHODIMP
nsDocumentOpenInfo::CheckListenerChain()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread!");
nsresult rv = NS_OK;
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
do_QueryInterface(m_targetStreamListener, &rv);
if (retargetableListener) {
rv = retargetableListener->CheckListenerChain();
}
LOG(("[0x%p] nsDocumentOpenInfo::CheckListenerChain %s listener %p rv %x",
this, (NS_SUCCEEDED(rv) ? "success" : "failure"),
(nsIStreamListener*)m_targetStreamListener, rv));
return rv;
}
NS_IMETHODIMP
nsDocumentOpenInfo::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt,
nsIInputStream * inStr,
@ -311,7 +288,7 @@ NS_IMETHODIMP nsDocumentOpenInfo::OnStopRequest(nsIRequest *request, nsISupports
if ( m_targetStreamListener)
{
nsMainThreadPtrHandle<nsIStreamListener> listener = m_targetStreamListener;
nsCOMPtr<nsIStreamListener> listener(m_targetStreamListener);
// If this is a multipart stream, we could get another
// OnStartRequest after this... reset state.
@ -537,15 +514,11 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports *
aChannel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_GUESS_FROM_EXT));
}
nsCOMPtr<nsIStreamListener> listener;
rv = helperAppService->DoContent(mContentType,
request,
m_originalContext,
false,
getter_AddRefs(listener));
// Passing false here to allow off main thread use.
m_targetStreamListener
= new nsMainThreadPtrHolder<nsIStreamListener>(listener, false);
getter_AddRefs(m_targetStreamListener));
if (NS_FAILED(rv)) {
request->SetLoadFlags(loadFlags);
m_targetStreamListener = nullptr;
@ -585,7 +558,7 @@ nsDocumentOpenInfo::ConvertData(nsIRequest *request,
// stream is split up into multiple destination streams. This
// intermediate instance is used to target these "decoded" streams...
//
nsRefPtr<nsDocumentOpenInfo> nextLink =
nsCOMPtr<nsDocumentOpenInfo> nextLink =
new nsDocumentOpenInfo(m_originalContext, mFlags, mURILoader);
if (!nextLink) return NS_ERROR_OUT_OF_MEMORY;
@ -608,16 +581,11 @@ nsDocumentOpenInfo::ConvertData(nsIRequest *request,
// stream converter and sets the output end of the stream converter to
// nextLink. As we pump data into m_targetStreamListener the stream
// converter will convert it and pass the converted data to nextLink.
nsCOMPtr<nsIStreamListener> listener;
rv = StreamConvService->AsyncConvertData(PromiseFlatCString(aSrcContentType).get(),
PromiseFlatCString(aOutContentType).get(),
nextLink,
request,
getter_AddRefs(listener));
// Passing false here to allow off main thread use.
m_targetStreamListener
= new nsMainThreadPtrHolder<nsIStreamListener>(listener, false);
return rv;
return StreamConvService->AsyncConvertData(PromiseFlatCString(aSrcContentType).get(),
PromiseFlatCString(aOutContentType).get(),
nextLink,
request,
getter_AddRefs(m_targetStreamListener));
}
bool
@ -662,7 +630,7 @@ nsDocumentOpenInfo::TryContentListener(nsIURIContentListener* aListener,
// m_targetStreamListener is now the input end of the converter, and we can
// just pump the data in there, if it exists. If it does not, we need to
// try other nsIURIContentListeners.
return m_targetStreamListener.get() != nullptr;
return m_targetStreamListener != nullptr;
}
// At this point, aListener wants data of type mContentType. Let 'em have
@ -684,15 +652,12 @@ nsDocumentOpenInfo::TryContentListener(nsIURIContentListener* aListener,
bool abort = false;
bool isPreferred = (mFlags & nsIURILoader::IS_CONTENT_PREFERRED) != 0;
nsCOMPtr<nsIStreamListener> listener;
nsresult rv = aListener->DoContent(mContentType.get(),
isPreferred,
aChannel,
getter_AddRefs(listener),
getter_AddRefs(m_targetStreamListener),
&abort);
// Passing false here to allow off main thread use.
m_targetStreamListener
= new nsMainThreadPtrHolder<nsIStreamListener>(listener, false);
if (NS_FAILED(rv)) {
LOG_ERROR((" DoContent failed"));
@ -847,7 +812,7 @@ nsresult nsURILoader::OpenChannel(nsIChannel* channel,
// we need to create a DocumentOpenInfo object which will go ahead and open
// the url and discover the content type....
nsRefPtr<nsDocumentOpenInfo> loader =
nsCOMPtr<nsDocumentOpenInfo> loader =
new nsDocumentOpenInfo(aWindowContext, aFlags, this);
if (!loader) return NS_ERROR_OUT_OF_MEMORY;

View File

@ -203,8 +203,6 @@ class nsMainThreadPtrHandle
operator T*() { return get(); }
T* operator->() { return get(); }
operator bool() { return get(); }
// These are safe to call on other threads with appropriate external locking.
bool operator==(const nsMainThreadPtrHandle<T>& aOther) const {
if (!mPtr || !aOther.mPtr)