Bug 450452 - "Implement XHR ('minus X') for worker threads". r+sr=jst.

This commit is contained in:
Ben Turner 2008-09-24 19:48:07 -07:00
Родитель a04e2e37a1
Коммит 4f737aafd3
27 изменённых файлов: 3012 добавлений и 158 удалений

Просмотреть файл

@ -101,7 +101,7 @@ interface nsIXMLHttpRequestUpload : nsIXMLHttpRequestEventTarget {
* you're aware of all the security implications. And then think twice about
* it.
*/
[scriptable, uuid(acda85ab-d06c-4176-b834-6d129ca97ca3)]
[scriptable, uuid(ae8f1468-cd7f-4aea-9c40-a3f085db9369)]
interface nsIXMLHttpRequest : nsISupports
{
/**
@ -334,78 +334,11 @@ interface nsIXMLHttpRequest : nsISupports
[noscript] void init(in nsIPrincipal principal,
in nsIScriptContext scriptContext,
in nsPIDOMWindow ownerWindow);
};
[scriptable, uuid(6e127bd2-b4c1-4a82-be0d-012bd24efb37)]
interface nsIXMLHttpRequestUploadGetter : nsISupports {
/**
* Upload process can be tracked by adding event listener to |upload|.
*/
readonly attribute nsIXMLHttpRequestUpload upload;
};
[scriptable, uuid(261676b4-d508-43bf-b099-74635a0ee2e9)]
interface nsIJSXMLHttpRequest : nsISupports {
/**
* Meant to be a script-only mechanism for setting a load event listener.
* The attribute is expected to be JavaScript function object. When
* the load event occurs, the function is invoked.
* This attribute should not be used from native code!!
*
* After the initial response, all event listeners will be cleared.
* // XXXbz what does that mean, exactly?
*
* Call open() before setting an onload listener.
*
* Mozilla only.
*/
attribute nsIDOMEventListener onload;
/**
* Meant to be a script-only mechanism for setting an error event listener.
* The attribute is expected to be JavaScript function object. When
* the error event occurs, the function is invoked.
* This attribute should not be used from native code!!
*
* After the initial response, all event listeners will be cleared.
* // XXXbz what does that mean, exactly?
*
* Call open() before setting an onerror listener.
*
* Mozilla only.
*/
attribute nsIDOMEventListener onerror;
/**
* Meant to be a script-only mechanism for setting a progress event listener.
* The attribute is expected to be JavaScript function object. When
* the error event occurs, the function is invoked.
* This attribute should not be used from native code!!
* This event listener may be called multiple times during the open request.
*
* After the initial response, all event listeners will be cleared.
* // XXXbz what does that mean, exactly?
*
* This event listener must be set BEFORE calling open().
*
* Mozilla only.
*/
attribute nsIDOMEventListener onprogress;
/**
* Meant to be a script-only mechanism for setting an upload progress event
* listener.
* This attribute should not be used from native code!!
* This event listener may be called multiple times during the upload..
*
* After the initial response, all event listeners will be cleared.
* // XXXbz what does that mean, exactly?
*
* This event listener must be set BEFORE calling open().
*
* Mozilla only.
*/
attribute nsIDOMEventListener onuploadprogress;
/**
* Meant to be a script-only mechanism for setting a callback function.
@ -421,6 +354,27 @@ interface nsIJSXMLHttpRequest : nsISupports {
attribute nsIDOMEventListener onreadystatechange;
};
/**
* DEPRECATED.
*/
[scriptable, uuid(261676b4-d508-43bf-b099-74635a0ee2e9)]
interface nsIJSXMLHttpRequest : nsISupports {
/**
* Meant to be a script-only mechanism for setting an upload progress event
* listener.
* This attribute should not be used from native code!!
* This event listener may be called multiple times during the upload..
*
* After the initial response, all event listeners will be cleared.
* // XXXbz what does that mean, exactly?
*
* This event listener must be set BEFORE calling open().
*
* Mozilla only.
*/
attribute nsIDOMEventListener onuploadprogress;
};
%{ C++
#define NS_XMLHTTPREQUEST_CID \
{ /* d164e770-4157-11d4-9a42-000064657374 */ \

Просмотреть файл

@ -611,8 +611,9 @@ nsXMLHttpRequestUpload::GetContextForEventHandlers(nsIScriptContext** aContext)
/////////////////////////////////////////////
nsXMLHttpRequest::nsXMLHttpRequest()
: mState(XML_HTTP_REQUEST_UNINITIALIZED), mUploadTransferred(0),
mUploadTotal(0), mUploadComplete(PR_TRUE), mErrorLoad(PR_FALSE)
: mRequestObserver(nsnull), mState(XML_HTTP_REQUEST_UNINITIALIZED),
mUploadTransferred(0), mUploadTotal(0), mUploadComplete(PR_TRUE),
mErrorLoad(PR_FALSE), mFirstStartRequestSeen(PR_FALSE)
{
nsLayoutStatics::AddRef();
}
@ -727,6 +728,12 @@ nsXMLHttpRequest::Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
return NS_OK;
}
void
nsXMLHttpRequest::SetRequestObserver(nsIRequestObserver* aObserver)
{
mRequestObserver = aObserver;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
@ -776,7 +783,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLHttpRequest)
NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequest)
NS_INTERFACE_MAP_ENTRY(nsIJSXMLHttpRequest)
NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequestUploadGetter)
NS_INTERFACE_MAP_ENTRY(nsIDOMLoadListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
@ -1565,6 +1571,11 @@ IsSameOrBaseChannel(nsIRequest* aPossibleBase, nsIChannel* aChannel)
NS_IMETHODIMP
nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
if (!mFirstStartRequestSeen && mRequestObserver) {
mFirstStartRequestSeen = PR_TRUE;
mRequestObserver->OnStartRequest(request, ctxt);
}
if (!IsSameOrBaseChannel(request, mChannel)) {
return NS_OK;
}
@ -1785,6 +1796,12 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult
mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
if (mRequestObserver && mState & XML_HTTP_REQUEST_GOT_FINAL_STOP) {
NS_ASSERTION(mFirstStartRequestSeen, "Inconsistent state!");
mFirstStartRequestSeen = PR_FALSE;
mRequestObserver->OnStopRequest(request, ctxt, status);
}
return rv;
}

Просмотреть файл

@ -165,8 +165,7 @@ class nsXMLHttpRequest : public nsXHREventTarget,
public nsIProgressEventSink,
public nsIInterfaceRequestor,
public nsSupportsWeakReference,
public nsIJSNativeInitializer,
public nsIXMLHttpRequestUploadGetter
public nsIJSNativeInitializer
{
public:
nsXMLHttpRequest();
@ -180,17 +179,12 @@ public:
// nsIJSXMLHttpRequest
NS_IMETHOD GetOnuploadprogress(nsIDOMEventListener** aOnuploadprogress);
NS_IMETHOD SetOnuploadprogress(nsIDOMEventListener* aOnuploadprogress);
NS_IMETHOD GetOnreadystatechange(nsIDOMEventListener** aOnreadystatechange);
NS_IMETHOD SetOnreadystatechange(nsIDOMEventListener* aOnreadystatechange);
NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
// nsIDOMEventListener
NS_DECL_NSIDOMEVENTLISTENER
// nsIXMLHttpRequestUploadGetter
NS_DECL_NSIXMLHTTPREQUESTUPLOADGETTER
// nsIDOMLoadListener
NS_IMETHOD Load(nsIDOMEvent* aEvent);
NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent);
@ -250,6 +244,8 @@ public:
// This is called by the factory constructor.
nsresult Init();
void SetRequestObserver(nsIRequestObserver* aObserver);
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXMLHttpRequest,
nsXHREventTarget)
@ -345,6 +341,8 @@ protected:
nsCOMPtr<nsIChannelEventSink> mChannelEventSink;
nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
nsIRequestObserver* mRequestObserver;
PRUint32 mState;
// List of potentially dangerous headers explicitly set using
@ -357,6 +355,8 @@ protected:
PRPackedBool mUploadComplete;
PRPackedBool mErrorLoad;
PRPackedBool mFirstStartRequestSeen;
};
// helper class to expose a progress DOM Event

Просмотреть файл

@ -3385,7 +3385,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIXMLHttpRequest)
DOM_CLASSINFO_MAP_ENTRY(nsIJSXMLHttpRequest)
DOM_CLASSINFO_MAP_ENTRY(nsIXMLHttpRequestEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIXMLHttpRequestUploadGetter)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIInterfaceRequestor)
DOM_CLASSINFO_MAP_END

Просмотреть файл

@ -68,6 +68,8 @@
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
nsIExceptionProvider* gExceptionProvider = nsnull;
nsDOMScriptObjectFactory::nsDOMScriptObjectFactory() :
mLoadedAllLanguages(PR_FALSE)
{
@ -78,18 +80,25 @@ nsDOMScriptObjectFactory::nsDOMScriptObjectFactory() :
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
}
nsCOMPtr<nsIExceptionService> xs =
do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID);
nsCOMPtr<nsIExceptionProvider> provider(new nsDOMExceptionProvider());
if (provider) {
nsCOMPtr<nsIExceptionService> xs =
do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID);
if (xs) {
xs->RegisterExceptionProvider(this, NS_ERROR_MODULE_DOM);
xs->RegisterExceptionProvider(this, NS_ERROR_MODULE_DOM_RANGE);
if (xs) {
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM);
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM_RANGE);
#ifdef MOZ_SVG
xs->RegisterExceptionProvider(this, NS_ERROR_MODULE_SVG);
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_SVG);
#endif
xs->RegisterExceptionProvider(this, NS_ERROR_MODULE_DOM_XPATH);
xs->RegisterExceptionProvider(this, NS_ERROR_MODULE_XPCONNECT);
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM_XPATH);
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_XPCONNECT);
}
NS_ASSERTION(!gExceptionProvider, "Registered twice?!");
provider.swap(gExceptionProvider);
}
// And pre-create the javascript language.
NS_CreateJSRuntime(getter_AddRefs(mLanguageArray[NS_STID_INDEX(nsIProgrammingLanguage::JAVASCRIPT)]));
}
@ -97,7 +106,6 @@ nsDOMScriptObjectFactory::nsDOMScriptObjectFactory() :
NS_INTERFACE_MAP_BEGIN(nsDOMScriptObjectFactory)
NS_INTERFACE_MAP_ENTRY(nsIDOMScriptObjectFactory)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsIExceptionProvider)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMScriptObjectFactory)
NS_INTERFACE_MAP_END
@ -287,17 +295,26 @@ nsDOMScriptObjectFactory::Observe(nsISupports *aSubject,
nsGlobalWindow::ShutDown();
nsDOMClassInfo::ShutDown();
nsCOMPtr<nsIExceptionService> xs =
do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID);
if (gExceptionProvider) {
nsCOMPtr<nsIExceptionService> xs =
do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID);
if (xs) {
xs->UnregisterExceptionProvider(this, NS_ERROR_MODULE_DOM);
xs->UnregisterExceptionProvider(this, NS_ERROR_MODULE_DOM_RANGE);
if (xs) {
xs->UnregisterExceptionProvider(gExceptionProvider,
NS_ERROR_MODULE_DOM);
xs->UnregisterExceptionProvider(gExceptionProvider,
NS_ERROR_MODULE_DOM_RANGE);
#ifdef MOZ_SVG
xs->UnregisterExceptionProvider(this, NS_ERROR_MODULE_SVG);
xs->UnregisterExceptionProvider(gExceptionProvider,
NS_ERROR_MODULE_SVG);
#endif
xs->UnregisterExceptionProvider(this, NS_ERROR_MODULE_DOM_XPATH);
xs->UnregisterExceptionProvider(this, NS_ERROR_MODULE_XPCONNECT);
xs->UnregisterExceptionProvider(gExceptionProvider,
NS_ERROR_MODULE_DOM_XPATH);
xs->UnregisterExceptionProvider(gExceptionProvider,
NS_ERROR_MODULE_XPCONNECT);
}
NS_RELEASE(gExceptionProvider);
}
}
@ -325,30 +342,6 @@ CreateXPConnectException(nsresult aResult, nsIException *aDefaultException,
return NS_OK;
}
NS_IMETHODIMP
nsDOMScriptObjectFactory::GetException(nsresult result,
nsIException *aDefaultException,
nsIException **_retval)
{
switch (NS_ERROR_GET_MODULE(result))
{
case NS_ERROR_MODULE_DOM_RANGE:
return NS_NewRangeException(result, aDefaultException, _retval);
#ifdef MOZ_SVG
case NS_ERROR_MODULE_SVG:
return NS_NewSVGException(result, aDefaultException, _retval);
#endif
case NS_ERROR_MODULE_DOM_XPATH:
return NS_NewXPathException(result, aDefaultException, _retval);
case NS_ERROR_MODULE_XPCONNECT:
return CreateXPConnectException(result, aDefaultException, _retval);
case NS_ERROR_MODULE_DOM_FILE:
return NS_NewFileException(result, aDefaultException, _retval);
default:
return NS_NewDOMException(result, aDefaultException, _retval);
}
}
NS_IMETHODIMP
nsDOMScriptObjectFactory::RegisterDOMClassInfo(const char *aName,
nsDOMClassInfoExternalConstructorFnc aConstructorFptr,
@ -394,3 +387,31 @@ nsresult NS_GetScriptRuntimeByID(PRUint32 aScriptTypeID,
return rv;
return factory->GetScriptRuntimeByID(aScriptTypeID, aLanguage);
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMExceptionProvider, nsIExceptionProvider)
NS_IMETHODIMP
nsDOMExceptionProvider::GetException(nsresult result,
nsIException *aDefaultException,
nsIException **_retval)
{
switch (NS_ERROR_GET_MODULE(result))
{
case NS_ERROR_MODULE_DOM_RANGE:
return NS_NewRangeException(result, aDefaultException, _retval);
#ifdef MOZ_SVG
case NS_ERROR_MODULE_SVG:
return NS_NewSVGException(result, aDefaultException, _retval);
#endif
case NS_ERROR_MODULE_DOM_XPATH:
return NS_NewXPathException(result, aDefaultException, _retval);
case NS_ERROR_MODULE_XPCONNECT:
return CreateXPConnectException(result, aDefaultException, _retval);
case NS_ERROR_MODULE_DOM_FILE:
return NS_NewFileException(result, aDefaultException, _retval);
default:
return NS_NewDOMException(result, aDefaultException, _retval);
}
NS_NOTREACHED("Not reached");
return NS_ERROR_UNEXPECTED;
}

Просмотреть файл

@ -57,8 +57,7 @@
#include "nsIScriptGlobalObject.h" // for misplaced NS_STID_ macros.
class nsDOMScriptObjectFactory : public nsIDOMScriptObjectFactory,
public nsIObserver,
public nsIExceptionProvider
public nsIObserver
{
public:
nsDOMScriptObjectFactory();
@ -68,9 +67,6 @@ public:
// nsIObserver
NS_DECL_NSIOBSERVER
// nsIExceptionProvider
NS_DECL_NSIEXCEPTIONPROVIDER
// nsIDOMScriptObjectFactory
NS_IMETHOD GetScriptRuntime(const nsAString &aLanguageName,
nsIScriptRuntime **aLanguage);
@ -100,3 +96,10 @@ protected:
PRBool mLoadedAllLanguages;
nsCOMPtr<nsIScriptRuntime> mLanguageArray[NS_STID_ARRAY_UBOUND];
};
class nsDOMExceptionProvider : public nsIExceptionProvider
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIEXCEPTIONPROVIDER
};

Просмотреть файл

@ -867,6 +867,14 @@ nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
// Kill all of the workers for this window.
nsDOMThreadService* dts = nsDOMThreadService::get();
if (dts) {
nsIScriptContext *scx = GetContextInternal();
JSContext *cx = scx ? (JSContext *)scx->GetNativeContext() : nsnull;
// Have to suspend this request here because CancelWorkersForGlobal will
// lock until the worker has died and that could cause a deadlock.
JSAutoSuspendRequest asr(cx);
dts->CancelWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
}

Просмотреть файл

@ -51,11 +51,14 @@ FORCE_STATIC_LIB = 1
REQUIRES = \
caps \
content \
gfx \
js \
layout \
locale \
necko \
pref \
string \
thebes \
widget \
xpcom \
xpconnect \
@ -69,10 +72,14 @@ CPPSRCS = \
nsDOMWorkerSecurityManager.cpp \
nsDOMWorkerThread.cpp \
nsDOMWorkerTimeout.cpp \
nsDOMWorkerXHR.cpp \
nsDOMWorkerXHRProxy.cpp \
$(NULL)
LOCAL_INCLUDES = \
-I$(topsrcdir)/dom/src/base \
-I$(topsrcdir)/content/base/src \
-I$(topsrcdir)/content/events/src \
$(NULL)
ifdef ENABLE_TESTS
@ -80,3 +87,5 @@ DIRS += test
endif
include $(topsrcdir)/config/rules.mk
#CXXFLAGS += $(WARNINGS_AS_ERRORS)

Просмотреть файл

@ -478,6 +478,13 @@ DOMWorkerErrorReporter(JSContext* aCx,
nsDOMWorkerThread* worker = (nsDOMWorkerThread*)JS_GetContextPrivate(aCx);
if (worker->IsCanceled()) {
// We don't want to report errors from canceled workers. It's very likely
// that we only returned an error in the first place because the worker was
// already canceled.
return;
}
nsresult rv;
nsCOMPtr<nsIScriptError> errorObject =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);

Просмотреть файл

@ -78,6 +78,8 @@ class nsDOMThreadService : public nsIEventTarget,
friend class nsDOMWorkerRunnable;
friend class nsDOMWorkerThread;
friend class nsDOMWorkerTimeout;
friend class nsDOMWorkerXHR;
friend class nsDOMWorkerXHRProxy;
friend class nsLayoutStatics;
public:

Просмотреть файл

@ -92,12 +92,16 @@ public:
getter_AddRefs(targetIsPool));
#endif
LOG(("Posting message '%s' from %s [0x%p] to %s [0x%p]",
utf8Message.get(), sourceIsPool ? poolStr : workerStr,
static_cast<void*>(mSource.get()), targetIsPool ? poolStr : workerStr,
static_cast<void*>(mTarget.get())));
if (!(mTarget->IsCanceled() || mSource->IsCanceled())) {
LOG(("Posting message '%s' from %s [0x%p] to %s [0x%p]",
utf8Message.get(),
sourceIsPool ? poolStr : workerStr,
static_cast<void*>(mSource.get()),
targetIsPool ? poolStr : workerStr,
static_cast<void*>(mTarget.get())));
mTarget->HandleMessage(mMessage, mSource);
mTarget->HandleMessage(mMessage, mSource);
}
return NS_OK;
}

Просмотреть файл

@ -40,6 +40,7 @@
#include "nsDOMWorkerPool.h"
// Interfaces
#include "nsIDocument.h"
#include "nsIDOMClassInfo.h"
#include "nsIJSContextStack.h"
#include "nsIScriptContext.h"
@ -102,15 +103,8 @@ nsDOMWorkerPool::Init()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// GetCurrentJSContext () can return a null context... We shouldn't
// ever see that here.
JSContext* cx = nsContentUtils::GetCurrentJSContext();
NS_ENSURE_TRUE(cx, NS_ERROR_UNEXPECTED);
nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
NS_ENSURE_STATE(scriptContext);
nsIScriptGlobalObject* globalObject = scriptContext->GetGlobalObject();
nsIScriptGlobalObject* globalObject =
mParentDocument->GetScriptGlobalObject();
NS_ENSURE_STATE(globalObject);
nsCOMPtr<nsPIDOMWindow> domWindow(do_QueryInterface(globalObject));
@ -237,13 +231,22 @@ nsDOMWorkerPool::ResumeWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject)
}
nsIDocument*
nsDOMWorkerPool::GetParentDocument()
nsDOMWorkerPool::ParentDocument()
{
NS_ASSERTION(NS_IsMainThread(),
"Don't touch the non-threadsafe document off the main thread!");
return mParentDocument;
}
nsIScriptContext*
nsDOMWorkerPool::ScriptContext()
{
NS_ASSERTION(NS_IsMainThread(),
"Don't touch the non-threadsafe script context off the main "
"thread!");
return mParentDocument->GetScriptGlobalObject()->GetContext();
}
NS_IMETHODIMP
nsDOMWorkerPool::PostMessage(const nsAString& aMessage)
{

Просмотреть файл

@ -53,6 +53,7 @@
class nsDOMWorkerThread;
class nsIDocument;
class nsIScriptContext;
class nsIScriptError;
class nsIScriptGlobalObject;
@ -84,6 +85,9 @@ public:
return this;
}
nsIDocument* ParentDocument();
nsIScriptContext* ScriptContext();
private:
virtual ~nsDOMWorkerPool();
@ -109,8 +113,6 @@ private:
return mMonitor;
}
nsIDocument* GetParentDocument();
// Weak reference to the window that created and owns this pool.
nsISupports* mParentGlobal;

Просмотреть файл

@ -126,7 +126,13 @@ nsDOMWorkerScriptLoader::LoadScripts(nsDOMWorkerThread* aWorker,
{
JSAutoSuspendRequest asr(aCx);
nsAutoLock lock(mWorker->Lock());
if (mWorker->IsCanceled()) {
return NS_ERROR_ABORT;
}
mTrackedByWorker = nsnull != mWorker->mScriptLoaders.AppendElement(this);
NS_ASSERTION(mTrackedByWorker, "Failed to add loader to worker's array!");
}
@ -442,7 +448,7 @@ nsDOMWorkerScriptLoader::RunInternal()
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// Things we need to make all this work...
nsIDocument* parentDoc = mWorker->Pool()->GetParentDocument();
nsIDocument* parentDoc = mWorker->Pool()->ParentDocument();
NS_ASSERTION(parentDoc, "Null parent document?!");
// All of these can potentially be null, but that should be ok. We'll either
@ -578,7 +584,7 @@ nsDOMWorkerScriptLoader::OnStreamCompleteInternal(nsIStreamLoader* aLoader,
return rv = NS_ERROR_UNEXPECTED;
}
nsIDocument* parentDoc = mWorker->Pool()->GetParentDocument();
nsIDocument* parentDoc = mWorker->Pool()->ParentDocument();
NS_ASSERTION(parentDoc, "Null parent document?!");
// Use the regular nsScriptLoader for this grunt work! Should be just fine

Просмотреть файл

@ -62,6 +62,7 @@
#include "nsDOMWorkerSecurityManager.h"
#include "nsDOMThreadService.h"
#include "nsDOMWorkerTimeout.h"
#include "nsDOMWorkerXHR.h"
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
@ -100,6 +101,9 @@ public:
static JSBool LoadScripts(JSContext* aCx, JSObject* aObj, uintN aArgc,
jsval* aArgv, jsval* aRval);
static JSBool NewXMLHttpRequest(JSContext* aCx, JSObject* aObj, uintN aArgc,
jsval* aArgv, jsval* aRval);
private:
// Internal helper for SetTimeout and SetInterval.
static JSBool MakeTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc,
@ -303,6 +307,63 @@ nsDOMWorkerFunctions::LoadScripts(JSContext* aCx,
return JS_TRUE;
}
JSBool
nsDOMWorkerFunctions::NewXMLHttpRequest(JSContext* aCx,
JSObject* aObj,
uintN aArgc,
jsval* /* aArgv */,
jsval* aRval)
{
nsDOMWorkerThread* worker =
static_cast<nsDOMWorkerThread*>(JS_GetContextPrivate(aCx));
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
if (worker->IsCanceled()) {
return JS_FALSE;
}
if (aArgc) {
JS_ReportError(aCx, "Constructor takes no arguments!");
return JS_FALSE;
}
nsRefPtr<nsDOMWorkerXHR> xhr = new nsDOMWorkerXHR(worker);
if (!xhr) {
JS_ReportOutOfMemory(aCx);
return JS_FALSE;
}
nsresult rv = xhr->Init();
if (NS_FAILED(rv)) {
JS_ReportError(aCx, "Failed to construct XHR!");
return JS_FALSE;
}
nsCOMPtr<nsISupports> xhrSupports;
xhr->QueryInterface(NS_GET_IID(nsISupports), getter_AddRefs(xhrSupports));
NS_ASSERTION(xhrSupports, "Impossible!");
nsIXPConnect* xpc = nsContentUtils::XPConnect();
nsCOMPtr<nsIXPConnectJSObjectHolder> xhrWrapped;
rv = xpc->WrapNative(aCx, aObj, xhrSupports, NS_GET_IID(nsIXMLHttpRequest),
getter_AddRefs(xhrWrapped));
if (NS_FAILED(rv)) {
JS_ReportError(aCx, "Failed to wrap XHR!");
return JS_FALSE;
}
JSObject* xhrJSObj;
rv = xhrWrapped->GetJSObject(&xhrJSObj);
if (NS_FAILED(rv)) {
JS_ReportError(aCx, "Failed to get JSObject!");
return JS_FALSE;
}
*aRval = OBJECT_TO_JSVAL(xhrJSObj);
return JS_TRUE;
}
JSFunctionSpec gDOMWorkerFunctions[] = {
{ "dump", nsDOMWorkerFunctions::Dump, 1, 0, 0 },
{ "debug", nsDOMWorkerFunctions::DebugDump, 1, 0, 0 },
@ -312,6 +373,7 @@ JSFunctionSpec gDOMWorkerFunctions[] = {
{ "setInterval", nsDOMWorkerFunctions::SetInterval, 1, 0, 0 },
{ "clearInterval", nsDOMWorkerFunctions::KillTimeout, 1, 0, 0 },
{ "loadScripts", nsDOMWorkerFunctions::LoadScripts, 1, 0, 0 },
{ "XMLHttpRequest", nsDOMWorkerFunctions::NewXMLHttpRequest, 0, 0, 0 },
#ifdef MOZ_SHARK
{ "startShark", js_StartShark, 0, 0, 0 },
{ "stopShark", js_StopShark, 0, 0, 0 },
@ -551,6 +613,7 @@ nsDOMWorkerThread::Cancel()
// Do this before waiting on the thread service below!
CancelScriptLoaders();
CancelXHRs();
// If we're suspended there's a good chance that we're already paused waiting
// on the pool's monitor. Waiting on the thread service's lock will deadlock.
@ -717,7 +780,7 @@ nsDOMWorkerThread::NextTimeout(nsDOMWorkerTimeout* aTimeout)
return next == &mTimeouts ? nsnull : next;
}
void
PRBool
nsDOMWorkerThread::AddTimeout(nsDOMWorkerTimeout* aTimeout)
{
// This should only ever be called on the worker thread... but there's no way
@ -733,6 +796,10 @@ nsDOMWorkerThread::AddTimeout(nsDOMWorkerTimeout* aTimeout)
nsAutoLock lock(mLock);
if (IsCanceled()) {
return PR_FALSE;
}
// XXX Currently stored in the order that they should execute (like the window
// timeouts are) but we don't flush all expired timeouts the same way that
// the window does... Either we should or this is unnecessary.
@ -741,11 +808,12 @@ nsDOMWorkerThread::AddTimeout(nsDOMWorkerTimeout* aTimeout)
timeout = NextTimeout(timeout)) {
if (timeout->GetInterval() > newInterval) {
PR_INSERT_BEFORE(aTimeout, timeout);
return;
return PR_TRUE;
}
}
PR_APPEND_LINK(aTimeout, &mTimeouts);
return PR_TRUE;
}
void
@ -859,6 +927,54 @@ nsDOMWorkerThread::CancelScriptLoaders()
}
}
PRBool
nsDOMWorkerThread::AddXHR(nsDOMWorkerXHR* aXHR)
{
nsAutoLock lock(mLock);
if (IsCanceled()) {
return PR_FALSE;
}
#ifdef DEBUG
PRBool contains = mXHRs.Contains(aXHR);
NS_ASSERTION(!contains, "Adding an XHR twice!");
#endif
nsDOMWorkerXHR** newElement = mXHRs.AppendElement(aXHR);
NS_ENSURE_TRUE(newElement, PR_FALSE);
return PR_TRUE;
}
void
nsDOMWorkerThread::RemoveXHR(nsDOMWorkerXHR* aXHR)
{
nsAutoLock lock(mLock);
#ifdef DEBUG
PRBool removed =
#endif
mXHRs.RemoveElement(aXHR);
NS_WARN_IF_FALSE(removed, "Removed an XHR that was never added?!");
}
void
nsDOMWorkerThread::CancelXHRs()
{
nsAutoTArray<nsDOMWorkerXHR*, 20> xhrs;
// Must call Cancel outside the lock!
{
nsAutoLock lock(mLock);
xhrs.AppendElements(mXHRs);
}
PRUint32 xhrCount = xhrs.Length();
for (PRUint32 index = 0; index < xhrCount; index++) {
xhrs[index]->Cancel();
}
}
NS_IMETHODIMP
nsDOMWorkerThread::PostMessage(const nsAString& aMessage)
{

Просмотреть файл

@ -117,6 +117,7 @@ _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \
class nsDOMWorkerPool;
class nsDOMWorkerScriptLoader;
class nsDOMWorkerTimeout;
class nsDOMWorkerXHR;
class nsDOMWorkerThread : public nsDOMWorkerBase,
public nsIDOMWorkerThread,
@ -128,6 +129,7 @@ class nsDOMWorkerThread : public nsDOMWorkerBase,
friend class nsDOMWorkerRunnable;
friend class nsDOMWorkerScriptLoader;
friend class nsDOMWorkerTimeout;
friend class nsDOMWorkerXHR;
friend JSBool DOMWorkerOperationCallback(JSContext* aCx);
@ -167,7 +169,7 @@ private:
inline nsDOMWorkerTimeout* FirstTimeout();
inline nsDOMWorkerTimeout* NextTimeout(nsDOMWorkerTimeout* aTimeout);
void AddTimeout(nsDOMWorkerTimeout* aTimeout);
PRBool AddTimeout(nsDOMWorkerTimeout* aTimeout);
void RemoveTimeout(nsDOMWorkerTimeout* aTimeout);
void ClearTimeouts();
void CancelTimeout(PRUint32 aId);
@ -176,6 +178,10 @@ private:
void CancelScriptLoaders();
PRBool AddXHR(nsDOMWorkerXHR* aXHR);
void RemoveXHR(nsDOMWorkerXHR* aXHR);
void CancelXHRs();
PRLock* Lock() {
return mLock;
}
@ -195,6 +201,7 @@ private:
PRCList mTimeouts;
nsTArray<nsDOMWorkerScriptLoader*> mScriptLoaders;
nsTArray<nsDOMWorkerXHR*> mXHRs;
};
#endif /* __NSDOMWORKERTHREAD_H__ */

Просмотреть файл

@ -329,19 +329,26 @@ nsDOMWorkerTimeout::Init(JSContext* aCx, PRUint32 aArgc, jsval* aArgv,
}
mIsInterval = aIsInterval;
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsIEventTarget* target =
static_cast<nsIEventTarget*>(nsDOMThreadService::get());
rv = mTimer->SetTarget(target);
rv = timer->SetTarget(target);
NS_ENSURE_SUCCESS(rv, rv);
rv = mTimer->InitWithCallback(this, interval, type);
rv = timer->InitWithCallback(this, interval, type);
NS_ENSURE_SUCCESS(rv, rv);
mWorker->AddTimeout(this);
mTimer.swap(timer);
if (!mWorker->AddTimeout(this)) {
// Must have been canceled.
mTimer->Cancel();
mTimer = nsnull;
return NS_ERROR_ABORT;
}
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,915 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** 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 worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* 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 "nsDOMWorkerXHR.h"
// Interfaces
#include "nsIDocument.h"
#include "nsIDOMEvent.h"
#include "nsIThread.h"
#include "nsIXPConnect.h"
// Other includes
#include "nsAutoLock.h"
#include "nsAXPCNativeCallContext.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsIClassInfoImpl.h"
#include "nsJSUtils.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
// DOMWorker includes
#include "nsDOMThreadService.h"
#include "nsDOMWorkerPool.h"
#include "nsDOMWorkerXHRProxy.h"
// The list of event types that we support. This list and the defines based on
// it determine the sizes of the listener arrays in nsDOMWorkerXHRProxy. Make
// sure that any event types shared by both the XHR and Upload objects are
// together at the beginning of the list. Any changes made to this list may
// affect sMaxUploadEventTypes, so make sure that it is adjusted accordingly or
// things will break!
const char* const nsDOMWorkerXHREventTarget::sListenerTypes[] = {
// nsIXMLHttpRequestEventTarget listeners.
"abort", /* LISTENER_TYPE_ABORT */
"error", /* LISTENER_TYPE_ERROR */
"load", /* LISTENER_TYPE_LOAD */
"loadstart", /* LISTENER_TYPE_LOADSTART */
"progress", /* LISTENER_TYPE_PROGRESS */
// nsIXMLHttpRequest listeners.
"readystatechange" /* LISTENER_TYPE_READYSTATECHANGE */
};
// Convenience defines for event *indexes* in the sListenerTypes array.
#define LISTENER_TYPE_ABORT 0
#define LISTENER_TYPE_ERROR 1
#define LISTENER_TYPE_LOAD 2
#define LISTENER_TYPE_LOADSTART 3
#define LISTENER_TYPE_PROGRESS 4
#define LISTENER_TYPE_READYSTATECHANGE 5
// This should always be set to the length of sListenerTypes.
const PRUint32 nsDOMWorkerXHREventTarget::sMaxXHREventTypes =
NS_ARRAY_LENGTH(nsDOMWorkerXHREventTarget::sListenerTypes);
// This should be set to the index of the first event type that is *not*
// supported by the Upload object.
const PRUint32 nsDOMWorkerXHREventTarget::sMaxUploadEventTypes =
LISTENER_TYPE_READYSTATECHANGE;
// Enforce the invariant that the upload object supports no more event types
// than the xhr object.
PR_STATIC_ASSERT(nsDOMWorkerXHREventTarget::sMaxXHREventTypes >=
nsDOMWorkerXHREventTarget::sMaxUploadEventTypes);
NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerXHREventTarget,
nsIDOMEventTarget,
nsIXMLHttpRequestEventTarget)
PRUint32
nsDOMWorkerXHREventTarget::GetListenerTypeFromString(const nsAString& aString)
{
for (PRUint32 index = 0; index < sMaxXHREventTypes; index++) {
if (aString.EqualsASCII(sListenerTypes[index])) {
return index;
}
}
return PR_UINT32_MAX;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnabort(nsIDOMEventListener** aOnabort)
{
NS_ENSURE_ARG_POINTER(aOnabort);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(LISTENER_TYPE_ABORT);
listener.forget(aOnabort);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnabort(nsIDOMEventListener* aOnabort)
{
return SetEventListener(LISTENER_TYPE_ABORT, aOnabort, PR_TRUE);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnerror(nsIDOMEventListener** aOnerror)
{
NS_ENSURE_ARG_POINTER(aOnerror);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(LISTENER_TYPE_ERROR);
listener.forget(aOnerror);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnerror(nsIDOMEventListener* aOnerror)
{
return SetEventListener(LISTENER_TYPE_ERROR, aOnerror, PR_TRUE);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnload(nsIDOMEventListener** aOnload)
{
NS_ENSURE_ARG_POINTER(aOnload);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(LISTENER_TYPE_LOAD);
listener.forget(aOnload);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnload(nsIDOMEventListener* aOnload)
{
return SetEventListener(LISTENER_TYPE_LOAD, aOnload, PR_TRUE);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnloadstart(nsIDOMEventListener** aOnloadstart)
{
NS_ENSURE_ARG_POINTER(aOnloadstart);
nsCOMPtr<nsIDOMEventListener> listener =
GetOnXListener(LISTENER_TYPE_LOADSTART);
listener.forget(aOnloadstart);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnloadstart(nsIDOMEventListener* aOnloadstart)
{
return SetEventListener(LISTENER_TYPE_LOADSTART, aOnloadstart, PR_TRUE);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnprogress(nsIDOMEventListener** aOnprogress)
{
NS_ENSURE_ARG_POINTER(aOnprogress);
nsCOMPtr<nsIDOMEventListener> listener =
GetOnXListener(LISTENER_TYPE_PROGRESS);
listener.forget(aOnprogress);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnprogress(nsIDOMEventListener* aOnprogress)
{
return SetEventListener(LISTENER_TYPE_PROGRESS, aOnprogress, PR_TRUE);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture)
{
NS_ENSURE_ARG_POINTER(aListener);
PRUint32 type = GetListenerTypeFromString(aType);
if (type > sMaxXHREventTypes) {
// Silently ignore junk events.
return NS_OK;
}
return SetEventListener(type, aListener, PR_FALSE);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture)
{
NS_ENSURE_ARG_POINTER(aListener);
PRUint32 type = GetListenerTypeFromString(aType);
if (type > sMaxXHREventTypes) {
// Silently ignore junk events.
return NS_OK;
}
return UnsetEventListener(type, aListener);
}
/* ec702b78-c30f-439f-9a9b-a5dae17ee0fc */
#define NS_IPRIVATEWORKERXHREVENT_IID \
{ \
0xec702b78, \
0xc30f, \
0x439f, \
{ 0x9a, 0x9b, 0xa5, 0xda, 0xe1, 0x7e, 0xe0, 0xfc } \
}
class nsIPrivateWorkerXHREvent : public nsIDOMEvent
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPRIVATEWORKERXHREVENT_IID)
virtual PRBool PreventDefaultCalled() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIPrivateWorkerXHREvent,
NS_IPRIVATEWORKERXHREVENT_IID)
#define NS_FORWARD_NSIDOMEVENT_SPECIAL \
NS_IMETHOD GetType(nsAString& aType) \
{ return mEvent->GetType(aType); } \
NS_IMETHOD GetTarget(nsIDOMEventTarget** aTarget) \
{ return mEvent->GetTarget(aTarget); } \
NS_IMETHOD GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget) \
{ return mEvent->GetCurrentTarget(aCurrentTarget); } \
NS_IMETHOD GetEventPhase(PRUint16* aEventPhase) \
{ return mEvent->GetEventPhase(aEventPhase); } \
NS_IMETHOD GetBubbles(PRBool* aBubbles) \
{ return mEvent->GetBubbles(aBubbles); } \
NS_IMETHOD GetCancelable(PRBool* aCancelable) \
{ return mEvent->GetCancelable(aCancelable); } \
NS_IMETHOD GetTimeStamp(DOMTimeStamp* aTimeStamp) \
{ return mEvent->GetTimeStamp(aTimeStamp); } \
NS_IMETHOD StopPropagation() \
{ return mEvent->StopPropagation(); }
class nsDOMWorkerXHREventWrapper : public nsIPrivateWorkerXHREvent
{
public:
NS_DECL_ISUPPORTS
NS_FORWARD_NSIDOMEVENT_SPECIAL
nsDOMWorkerXHREventWrapper(nsIDOMEvent* aEvent)
: mEvent(aEvent), mPreventDefaultCalled(PR_FALSE) {
NS_ASSERTION(aEvent, "Null pointer!");
}
NS_IMETHOD PreventDefault() {
mPreventDefaultCalled = PR_TRUE;
return mEvent->PreventDefault();
}
NS_IMETHOD InitEvent(const nsAString& aEventType, PRBool aCanBubble,
PRBool aCancelable) {
mPreventDefaultCalled = PR_FALSE;
return mEvent->InitEvent(aEventType, aCanBubble, aCancelable);
}
// nsIPrivateWorkerXHREvent
virtual PRBool PreventDefaultCalled() {
return mPreventDefaultCalled;
}
private:
nsCOMPtr<nsIDOMEvent> mEvent;
PRBool mPreventDefaultCalled;
};
NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerXHREventWrapper,
nsIDOMEvent,
nsIPrivateWorkerXHREvent)
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval)
{
NS_ENSURE_ARG_POINTER(aEvent);
NS_ENSURE_ARG_POINTER(_retval);
nsCOMPtr<nsIPrivateWorkerXHREvent> wrapper(do_QueryInterface(aEvent));
if (!wrapper) {
wrapper = new nsDOMWorkerXHREventWrapper(aEvent);
NS_ENSURE_TRUE(wrapper, NS_ERROR_OUT_OF_MEMORY);
}
nsresult rv = HandleWorkerEvent(wrapper);
NS_ENSURE_SUCCESS(rv, rv);
*_retval = wrapper->PreventDefaultCalled();
return NS_OK;
}
nsDOMWorkerXHRUpload::nsDOMWorkerXHRUpload(nsDOMWorkerXHR* aWorkerXHR)
: mWorkerXHR(aWorkerXHR)
{
NS_ASSERTION(aWorkerXHR, "Must have a worker XHR!");
}
NS_IMPL_ISUPPORTS_INHERITED2(nsDOMWorkerXHRUpload, nsDOMWorkerXHREventTarget,
nsIXMLHttpRequestUpload,
nsIClassInfo)
NS_IMPL_CI_INTERFACE_GETTER3(nsDOMWorkerXHRUpload, nsIDOMEventTarget,
nsIXMLHttpRequestEventTarget,
nsIXMLHttpRequestUpload)
NS_IMPL_THREADSAFE_CI(nsDOMWorkerXHRUpload)
nsresult
nsDOMWorkerXHRUpload::SetEventListener(PRUint32 aType,
nsIDOMEventListener* aListener,
PRBool aOnXListener)
{
if (mWorkerXHR->mCanceled) {
return NS_ERROR_ABORT;
}
return mWorkerXHR->mXHRProxy->AddEventListener(aType, aListener, aOnXListener,
PR_TRUE);
}
nsresult
nsDOMWorkerXHRUpload::UnsetEventListener(PRUint32 aType,
nsIDOMEventListener* aListener)
{
if (mWorkerXHR->mCanceled) {
return NS_ERROR_ABORT;
}
return mWorkerXHR->mXHRProxy->RemoveEventListener(aType, aListener, PR_TRUE);
}
nsresult
nsDOMWorkerXHRUpload::HandleWorkerEvent(nsIDOMEvent* aEvent)
{
if (mWorkerXHR->mCanceled) {
return NS_ERROR_ABORT;
}
return mWorkerXHR->mXHRProxy->HandleWorkerEvent(aEvent, PR_TRUE);
}
already_AddRefed<nsIDOMEventListener>
nsDOMWorkerXHRUpload::GetOnXListener(PRUint32 aType)
{
if (mWorkerXHR->mCanceled) {
return nsnull;
}
return mWorkerXHR->mXHRProxy->GetOnXListener(aType, PR_TRUE);
}
nsDOMWorkerXHR::nsDOMWorkerXHR(nsDOMWorkerThread* aWorker)
: mWorker(aWorker),
mCanceled(PR_TRUE)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aWorker, "Must have a worker!");
}
nsDOMWorkerXHR::~nsDOMWorkerXHR()
{
if (!mCanceled) {
mWorker->RemoveXHR(this);
}
}
NS_IMPL_ISUPPORTS_INHERITED2(nsDOMWorkerXHR, nsDOMWorkerXHREventTarget,
nsIXMLHttpRequest,
nsIClassInfo)
NS_IMPL_CI_INTERFACE_GETTER3(nsDOMWorkerXHR, nsIDOMEventTarget,
nsIXMLHttpRequestEventTarget,
nsIXMLHttpRequest)
NS_IMPL_THREADSAFE_CI(nsDOMWorkerXHR)
nsresult
nsDOMWorkerXHR::Init()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (!mWorker->AddXHR(this)) {
// Must have been canceled.
return NS_ERROR_ABORT;
}
mCanceled = PR_FALSE;
nsRefPtr<nsDOMWorkerXHRProxy> proxy = new nsDOMWorkerXHRProxy(this);
NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = proxy->Init();
NS_ENSURE_SUCCESS(rv, rv);
proxy.swap(mXHRProxy);
return NS_OK;
}
void
nsDOMWorkerXHR::Cancel()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// Just in case mUpload holds the only ref to this object we make sure to stay
// alive through this call.
nsRefPtr<nsDOMWorkerXHR> kungFuDeathGrip(this);
{
// This lock is here to prevent a race between Cancel and GetUpload, not to
// protect mCanceled.
nsAutoLock lock(mWorker->Lock());
mCanceled = PR_TRUE;
mUpload = nsnull;
}
if (mXHRProxy) {
mXHRProxy->Destroy();
}
mWorker->RemoveXHR(this);
mWorker = nsnull;
}
nsresult
nsDOMWorkerXHR::SetEventListener(PRUint32 aType,
nsIDOMEventListener* aListener,
PRBool aOnXListener)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
return mXHRProxy->AddEventListener(aType, aListener, aOnXListener, PR_FALSE);
}
nsresult
nsDOMWorkerXHR::UnsetEventListener(PRUint32 aType,
nsIDOMEventListener* aListener)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
return mXHRProxy->RemoveEventListener(aType, aListener, PR_FALSE);
}
nsresult
nsDOMWorkerXHR::HandleWorkerEvent(nsIDOMEvent* aEvent)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
return mXHRProxy->HandleWorkerEvent(aEvent, PR_FALSE);
}
already_AddRefed<nsIDOMEventListener>
nsDOMWorkerXHR::GetOnXListener(PRUint32 aType)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return nsnull;
}
return mXHRProxy->GetOnXListener(aType, PR_FALSE);
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetChannel(nsIChannel** aChannel)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseXML(nsIDOMDocument** aResponseXML)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseText(nsAString& aResponseText)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetResponseText(aResponseText);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetStatus(PRUint32* aStatus)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aStatus);
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetStatus(aStatus);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetStatusText(nsACString& aStatusText)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetStatusText(aStatusText);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Abort()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->Abort();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetAllResponseHeaders(char** _retval)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(_retval);
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetAllResponseHeaders(_retval);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseHeader(const nsACString& aHeader,
nsACString& _retval)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetResponseHeader(aHeader, _retval);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::OpenRequest(const nsACString& aMethod,
const nsACString& aUrl,
PRBool aAsync,
const nsAString& aUser,
const nsAString& aPassword)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->OpenRequest(aMethod, aUrl, aAsync, aUser, aPassword);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Open(const nsACString& aMethod,
const nsACString& aUrl)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
PRBool async = PR_TRUE;
nsAutoString user, password;
nsIXPConnect* xpc = nsContentUtils::XPConnect();
NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED);
nsAXPCNativeCallContext* cc;
nsresult rv = xpc->GetCurrentNativeCallContext(&cc);
do {
if (NS_FAILED(rv) || !cc) {
break;
}
PRUint32 argc;
rv = cc->GetArgc(&argc);
NS_ENSURE_SUCCESS(rv, rv);
if (argc < 3) {
break;
}
jsval* argv;
rv = cc->GetArgvPtr(&argv);
NS_ENSURE_SUCCESS(rv, rv);
JSContext* cx;
rv = cc->GetJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
JSAutoRequest ar(cx);
JSBool asyncBool;
JS_ValueToBoolean(cx, argv[2], &asyncBool);
async = (PRBool)asyncBool;
// XXX Remove me once we support sync XHR
NS_ENSURE_TRUE(async, NS_ERROR_INVALID_ARG);
if (argc < 4) {
break;
}
JSString* argStr;
if (!JSVAL_IS_NULL(argv[3]) && !JSVAL_IS_VOID(argv[3])) {
argStr = JS_ValueToString(cx, argv[3]);
if (argStr) {
user.Assign(nsDependentJSString(argStr));
}
}
if (argc < 5) {
break;
}
if (!JSVAL_IS_NULL(argv[4]) && !JSVAL_IS_VOID(argv[4])) {
argStr = JS_ValueToString(cx, argv[4]);
if (argStr) {
password.Assign(nsDependentJSString(argStr));
}
}
} while (PR_FALSE);
return OpenRequest(aMethod, aUrl, async, user, password);
}
NS_IMETHODIMP
nsDOMWorkerXHR::Send(nsIVariant* aBody)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->Send(aBody);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SendAsBinary(const nsAString& aBody)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->SendAsBinary(aBody);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->SetRequestHeader(aHeader, aValue);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetReadyState(PRInt32* aReadyState)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aReadyState);
nsresult rv = mXHRProxy->GetReadyState(aReadyState);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::OverrideMimeType(const nsACString& aMimetype)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->OverrideMimeType(aMimetype);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetMultipart(PRBool* aMultipart)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aMultipart);
nsresult rv = mXHRProxy->GetMultipart(aMultipart);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetMultipart(PRBool aMultipart)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->SetMultipart(aMultipart);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetMozBackgroundRequest(PRBool* aMozBackgroundRequest)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aMozBackgroundRequest);
*aMozBackgroundRequest = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetMozBackgroundRequest(PRBool aMozBackgroundRequest)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (aMozBackgroundRequest) {
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Init(nsIPrincipal* aPrincipal,
nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwnerWindow)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetUpload(nsIXMLHttpRequestUpload** aUpload)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsRefPtr<nsDOMWorkerThread> worker = mWorker;
if (!worker) {
return NS_ERROR_ABORT;
}
nsAutoLock lock(worker->Lock());
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aUpload);
if (!mUpload) {
mUpload = new nsDOMWorkerXHRUpload(this);
NS_ENSURE_TRUE(mUpload, NS_ERROR_OUT_OF_MEMORY);
}
NS_ADDREF(*aUpload = mUpload);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetOnreadystatechange(nsIDOMEventListener** aOnreadystatechange)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aOnreadystatechange);
nsCOMPtr<nsIDOMEventListener> listener =
mXHRProxy->GetOnXListener(LISTENER_TYPE_READYSTATECHANGE, PR_FALSE);
listener.forget(aOnreadystatechange);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetOnreadystatechange(nsIDOMEventListener* aOnreadystatechange)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
return mXHRProxy->AddEventListener(LISTENER_TYPE_READYSTATECHANGE,
aOnreadystatechange, PR_TRUE, PR_FALSE);
}

Просмотреть файл

@ -0,0 +1,167 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** 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 worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* 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 __NSDOMWORKERXHR_H__
#define __NSDOMWORKERXHR_H__
// Bases
#include "nsIXMLHttpRequest.h"
#include "nsIClassInfo.h"
// Interfaces
// Other includes
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "prlock.h"
// DOMWorker includes
#include "nsDOMWorkerThread.h"
class nsDOMWorkerXHRProxy;
class nsDOMWorkerXHREventTarget : public nsIXMLHttpRequestEventTarget
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTTARGET
NS_DECL_NSIXMLHTTPREQUESTEVENTTARGET
static const char* const sListenerTypes[];
static const PRUint32 sMaxXHREventTypes;
static const PRUint32 sMaxUploadEventTypes;
static PRUint32 GetListenerTypeFromString(const nsAString& aString);
virtual nsresult SetEventListener(PRUint32 aType,
nsIDOMEventListener* aListener,
PRBool aOnXListener) = 0;
virtual nsresult UnsetEventListener(PRUint32 aType,
nsIDOMEventListener* aListener) = 0;
virtual nsresult HandleWorkerEvent(nsIDOMEvent* aEvent) = 0;
virtual already_AddRefed<nsIDOMEventListener>
GetOnXListener(PRUint32 aType) = 0;
protected:
virtual ~nsDOMWorkerXHREventTarget() { }
};
class nsDOMWorkerXHR;
class nsDOMWorkerXHRUpload : public nsDOMWorkerXHREventTarget,
public nsIXMLHttpRequestUpload,
public nsIClassInfo
{
friend class nsDOMWorkerXHR;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMWorkerXHREventTarget::)
NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsDOMWorkerXHREventTarget::)
NS_DECL_NSIXMLHTTPREQUESTUPLOAD
NS_DECL_NSICLASSINFO
nsDOMWorkerXHRUpload(nsDOMWorkerXHR* aWorkerXHR);
virtual nsresult SetEventListener(PRUint32 aType,
nsIDOMEventListener* aListener,
PRBool aOnXListener);
virtual nsresult UnsetEventListener(PRUint32 aType,
nsIDOMEventListener* aListener);
virtual nsresult HandleWorkerEvent(nsIDOMEvent* aEvent);
virtual already_AddRefed<nsIDOMEventListener>
GetOnXListener(PRUint32 aType);
protected:
virtual ~nsDOMWorkerXHRUpload() { }
nsRefPtr<nsDOMWorkerXHR> mWorkerXHR;
};
class nsDOMWorkerXHR : public nsDOMWorkerXHREventTarget,
public nsIXMLHttpRequest,
public nsIClassInfo
{
friend class nsDOMWorkerXHRProxy;
friend class nsDOMWorkerXHRUpload;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIXMLHTTPREQUEST
NS_DECL_NSICLASSINFO
nsDOMWorkerXHR(nsDOMWorkerThread* aWorker);
nsresult Init();
void Cancel();
virtual nsresult SetEventListener(PRUint32 aType,
nsIDOMEventListener* aListener,
PRBool aOnXListener);
virtual nsresult UnsetEventListener(PRUint32 aType,
nsIDOMEventListener* aListener);
virtual nsresult HandleWorkerEvent(nsIDOMEvent* aEvent);
virtual already_AddRefed<nsIDOMEventListener>
GetOnXListener(PRUint32 aType);
protected:
virtual ~nsDOMWorkerXHR();
PRLock* Lock() {
return mWorker->Lock();
}
nsRefPtr<nsDOMWorkerThread> mWorker;
nsRefPtr<nsDOMWorkerXHRProxy> mXHRProxy;
nsRefPtr<nsDOMWorkerXHRUpload> mUpload;
volatile PRBool mCanceled;
};
#endif /* __NSDOMWORKERXHR_H__ */

Просмотреть файл

@ -0,0 +1,248 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** 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 worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* 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 __NSDOMWORKERXHRPROXIEDFUNCTIONS_H__
#define __NSDOMWORKERXHRPROXIEDFUNCTIONS_H__
#define MAKE_PROXIED_FUNCTION0(_name) \
class _name : public nsRunnable \
{ \
public: \
_name (nsDOMWorkerXHRProxy* aXHR) \
: mXHR(aXHR) \
{ \
NS_ASSERTION(aXHR, "Null pointer!"); \
} \
\
NS_IMETHOD Run() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (); \
} \
return NS_OK; \
} \
private: \
nsRefPtr<nsDOMWorkerXHRProxy> mXHR; \
}
#define MAKE_PROXIED_FUNCTION1(_name, _arg1) \
class _name : public nsRunnable \
{ \
public: \
_name (nsDOMWorkerXHRProxy* aXHR, _arg1 aArg1) \
: mXHR(aXHR), mArg1(aArg1) \
{ \
NS_ASSERTION(aXHR, "Null pointer!"); \
} \
\
NS_IMETHOD Run() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (mArg1); \
} \
return NS_OK; \
} \
private: \
nsRefPtr<nsDOMWorkerXHRProxy> mXHR; \
_arg1 mArg1; \
}
#define MAKE_PROXIED_FUNCTION2(_name, _arg1, _arg2) \
class _name : public nsRunnable \
{ \
public: \
_name (nsDOMWorkerXHRProxy* aXHR, _arg1 aArg1, _arg2 aArg2) \
: mXHR(aXHR), mArg1(aArg1), mArg2(aArg2) \
{ \
NS_ASSERTION(aXHR, "Null pointer!"); \
} \
\
NS_IMETHOD Run() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (mArg1, mArg2); \
} \
return NS_OK; \
} \
private: \
nsRefPtr<nsDOMWorkerXHRProxy> mXHR; \
_arg1 mArg1; \
_arg2 mArg2; \
}
#define MAKE_PROXIED_FUNCTION3(_name, _arg1, _arg2, _arg3) \
class _name : public nsRunnable \
{ \
public: \
_name (nsDOMWorkerXHRProxy* aXHR, _arg1 aArg1, _arg2 aArg2, _arg3 aArg3) \
: mXHR(aXHR), mArg1(aArg1), mArg2(aArg2), mArg3(aArg3) \
{ \
NS_ASSERTION(aXHR, "Null pointer!"); \
} \
\
NS_IMETHOD Run() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (mArg1, mArg2, mArg3); \
} \
return NS_OK; \
} \
private: \
nsRefPtr<nsDOMWorkerXHRProxy> mXHR; \
_arg1 mArg1; \
_arg2 mArg2; \
_arg3 mArg3; \
}
#define MAKE_PROXIED_FUNCTION4(_name, _arg1, _arg2, _arg3, _arg4) \
class _name : public nsRunnable \
{ \
public: \
_name (nsDOMWorkerXHRProxy* aXHR, _arg1 aArg1, _arg2 aArg2, _arg3 aArg3, \
_arg4 aArg4) \
: mXHR(aXHR), mArg1(aArg1), mArg2(aArg2), mArg3(aArg3), mArg4(aArg4) \
{ \
NS_ASSERTION(aXHR, "Null pointer!"); \
} \
\
NS_IMETHOD Run() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (mArg1, mArg2, mArg3, mArg4); \
} \
return NS_OK; \
} \
private: \
nsRefPtr<nsDOMWorkerXHRProxy> mXHR; \
_arg1 mArg1; \
_arg2 mArg2; \
_arg3 mArg3; \
_arg4 mArg4; \
}
#define MAKE_PROXIED_FUNCTION5(_name, _arg1, _arg2, _arg3, _arg4, _arg5) \
class _name : public nsRunnable \
{ \
public: \
_name (nsDOMWorkerXHRProxy* aXHR, _arg1 aArg1, _arg2 aArg2, _arg3 aArg3, \
_arg4 aArg4, _arg5 aArg5) \
: mXHR(aXHR), mArg1(aArg1), mArg2(aArg2), mArg3(aArg3), mArg4(aArg4), \
mArg5(aArg5) \
{ \
NS_ASSERTION(aXHR, "Null pointer!"); \
} \
\
NS_IMETHOD Run() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (mArg1, mArg2, mArg3, mArg4, mArg5); \
} \
return NS_OK; \
} \
private: \
nsRefPtr<nsDOMWorkerXHRProxy> mXHR; \
_arg1 mArg1; \
_arg2 mArg2; \
_arg3 mArg3; \
_arg4 mArg4; \
_arg5 mArg5; \
}
#define RUN_PROXIED_FUNCTION(_name, _args) \
PR_BEGIN_MACRO \
if (mCanceled) { \
return NS_ERROR_ABORT; \
} \
\
nsCOMPtr<nsIRunnable> method = new :: _name _args; \
NS_ENSURE_TRUE(method, NS_ERROR_OUT_OF_MEMORY); \
\
nsRefPtr<nsResultReturningRunnable> runnable = \
new nsResultReturningRunnable(mMainThread, method, mWorkerXHR->mWorker); \
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY); \
\
nsresult _rv = runnable->Dispatch(); \
if (NS_FAILED(_rv)) { \
return _rv; \
} \
PR_END_MACRO
namespace nsDOMWorkerProxiedXHRFunctions
{
class Abort : public nsRunnable
{
public:
Abort (nsDOMWorkerXHRProxy* aXHR)
: mXHR(aXHR)
{
NS_ASSERTION(aXHR, "Null pointer!");
}
NS_IMETHOD Run() {
return mXHR->Abort();
}
private:
nsRefPtr<nsDOMWorkerXHRProxy> mXHR;
};
MAKE_PROXIED_FUNCTION1(GetAllResponseHeaders, char**);
MAKE_PROXIED_FUNCTION2(GetResponseHeader, const nsACString&, nsACString&);
MAKE_PROXIED_FUNCTION5(OpenRequest, const nsACString&, const nsACString&,
PRBool, const nsAString&, const nsAString&);
MAKE_PROXIED_FUNCTION1(Send, nsIVariant*);
MAKE_PROXIED_FUNCTION1(SendAsBinary, const nsAString&);
MAKE_PROXIED_FUNCTION2(SetRequestHeader, const nsACString&,
const nsACString&);
MAKE_PROXIED_FUNCTION1(OverrideMimeType, const nsACString&);
MAKE_PROXIED_FUNCTION1(SetMultipart, PRBool);
}
#endif /* __NSDOMWORKERXHRPROXIEDFUNCTIONS_H__ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,173 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** 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 worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* 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 __NSDOMWORKERXHRPROXY_H__
#define __NSDOMWORKERXHRPROXY_H__
// Bases
#include "nsThreadUtils.h"
#include "nsIDOMEventListener.h"
#include "nsIRequestObserver.h"
// Other includes
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
// DOMWorker includes
#include "nsDOMWorkerXHR.h"
class nsIJSXMLHttpRequest;
class nsIThread;
class nsIVariant;
class nsIXMLHttpRequest;
class nsDOMWorkerXHREvent;
class nsDOMWorkerXHRWrappedListener;
class nsXMLHttpRequest;
class nsDOMWorkerXHRProxy : public nsRunnable,
public nsIDOMEventListener,
public nsIRequestObserver
{
friend class nsDOMWorkerXHREvent;
friend class nsDOMWorkerXHR;
friend class nsDOMWorkerXHRUpload;
typedef nsCOMPtr<nsIDOMEventListener> Listener;
typedef nsTArray<Listener> ListenerArray;
typedef nsRefPtr<nsDOMWorkerXHRWrappedListener> WrappedListener;
typedef nsresult (NS_STDCALL nsIDOMEventTarget::*AddRemoveFunction)
(const nsAString&, nsIDOMEventListener*, PRBool);
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_NSIRUNNABLE
NS_DECL_NSIREQUESTOBSERVER
nsDOMWorkerXHRProxy(nsDOMWorkerXHR* aWorkerXHR);
virtual ~nsDOMWorkerXHRProxy();
nsresult Init();
nsIXMLHttpRequest* GetXMLHttpRequest();
nsresult Abort();
protected:
nsresult InitInternal();
void DestroyInternal();
nsresult Destroy();
void FlipOwnership();
nsresult AddEventListener(PRUint32 aType,
nsIDOMEventListener* aListener,
PRBool aOnXListener,
PRBool aUploadListener);
nsresult RemoveEventListener(PRUint32 aType,
nsIDOMEventListener* aListener,
PRBool aUploadListener);
already_AddRefed<nsIDOMEventListener> GetOnXListener(PRUint32 aType,
PRBool aUploadListener);
nsresult HandleWorkerEvent(nsDOMWorkerXHREvent* aEvent, PRBool aUploadEvent);
nsresult HandleWorkerEvent(nsIDOMEvent* aEvent, PRBool aUploadEvent);
nsresult HandleEventInternal(PRUint32 aType,
nsIDOMEvent* aEvent,
PRBool aUploadEvent);
void ClearEventListeners();
// Methods of nsIXMLHttpRequest that we implement
nsresult GetAllResponseHeaders(char** _retval);
nsresult GetResponseHeader(const nsACString& aHeader,
nsACString& _retval);
nsresult OpenRequest(const nsACString& aMethod,
const nsACString& aUrl,
PRBool aAsync,
const nsAString& aUser,
const nsAString& aPassword);
nsresult Send(nsIVariant* aBody);
nsresult SendAsBinary(const nsAString& aBody);
nsresult GetResponseText(nsAString& _retval);
nsresult GetStatusText(nsACString& _retval);
nsresult GetStatus(nsresult* _retval);
nsresult GetReadyState(PRInt32* _retval);
nsresult SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue);
nsresult OverrideMimeType(const nsACString& aMimetype);
nsresult GetMultipart(PRBool* aMultipart);
nsresult SetMultipart(PRBool aMultipart);
// May be weak or strong, check mOwnedByXHR.
nsDOMWorkerXHR* mWorkerXHR;
// Always weak!
nsIXMLHttpRequest* mXHR;
nsXMLHttpRequest* mConcreteXHR;
// May be weak or strong, check mOwnedByXHR.
nsIXMLHttpRequestUpload* mUpload;
nsCOMPtr<nsIThread> mMainThread;
nsRefPtr<nsDOMWorkerXHREvent> mLastXHREvent;
nsTArray<ListenerArray> mXHRListeners;
nsTArray<WrappedListener> mXHROnXListeners;
nsTArray<ListenerArray> mUploadListeners;
nsTArray<WrappedListener> mUploadOnXListeners;
// Whether or not this object is owned by the real XHR object.
PRPackedBool mOwnedByXHR;
PRPackedBool mMultipart;
PRPackedBool mCanceled;
};
#endif /* __NSDOMWORKERXHRPROXY_H__ */

Просмотреть файл

@ -57,6 +57,8 @@ _TEST_FILES = \
test_threadErrors.html \
test_threadTimeouts.html \
test_longThread.html \
test_xhr.html \
testXHR.txt \
$(NULL)
libs:: $(_TEST_FILES)

Просмотреть файл

@ -0,0 +1 @@
A noisy noise annoys an oyster.

Просмотреть файл

@ -0,0 +1,114 @@
<!DOCTYPE HTML>
<html>
<!--
Tests of DOM Worker Threads XHR(Bug 450452 )
-->
<head>
<title>Test for DOM Worker Threads XHR (Bug 450452 )</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=450452">DOM Worker Threads XHR (Bug 450452)</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
function workerScript() {
var xhr = new XMLHttpRequest();
function onload(event) {
if (event.target.status == 200) {
var message = { type: "error",
error: event.target.status };
postMessageToPool(message.toSource());
}
var message = { type: "load",
data: xhr.responseText };
postMessageToPool(message.toSource());
}
xhr.onload = onload;
xhr.addEventListener("load", onload, false);
xhr.removeEventListener("load", onload, false);
if (!xhr.onload) {
var message = { type: "error",
error: "Lost message listener!" };
postMessageToPool(message.toSource());
}
xhr.addEventListener("error", function(event) {
var message = { type: "error",
error: event.target.status };
postMessageToPool(message.toSource());
}, false);
function onprogress(event) {
var message = { type: "progress",
current: event.position,
total: event.totalSize };
postMessageToPool(message.toSource());
}
xhr.addEventListener("progress", onprogress, false);
xhr.addEventListener("foopety", function(event) {}, false);
xhr.removeEventListener("doopety", function(event) {}, false);
var upload = xhr.upload;
upload.onprogress = function(event) { };
upload.addEventListener("readystatechange", function(event) { }, false);
upload.removeEventListener("readystatechange", function(event) { }, false);
upload.addEventListener("load", function(event) { }, false);
upload.removeEventListener("readystatechange", function(event) { }, false);
this.messageListener = function(message, source) {
if (xhr.readystate > 0) {
throw "XHR already running!";
}
xhr.open("GET", message);
xhr.send(null);
}
}
var pool = navigator.newWorkerPool();
pool.messageListener = function(message, source) {
var args = eval(message);
switch (args.type) {
case "progress": {
ok(parseInt(args.current) <= parseInt(args.total));
} break;
case "error": {
ok(false, "XHR error: " + args.error);
} break;
case "load": {
is(args.data, "A noisy noise annoys an oyster.");
document.getElementById("content").textContent = args.data;
SimpleTest.finish();
} break;
default: {
ok(false, "Unexpected message");
SimpleTest.finish();
}
}
};
pool.errorListener = function(error, source) {
ok(false, "Worker had an error:" + error);
SimpleTest.finish();
}
var worker = pool.createWorker("(" + workerScript + ")();");
worker.postMessage("testXHR.txt");
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -3647,8 +3647,8 @@ public:
* @param cx The JSContext, this can be null, we don't do anything then
*/
AutoScriptEvaluate(JSContext * cx)
: mJSContext(cx), mState(0), mEvaluated(PR_FALSE),
mContextHasThread(0) {}
: mJSContext(cx), mState(0), mErrorReporterSet(PR_FALSE),
mEvaluated(PR_FALSE), mContextHasThread(0) {}
/**
* Does the pre script evaluation and sets the error reporter if given
@ -3665,7 +3665,7 @@ public:
private:
JSContext* mJSContext;
JSExceptionState* mState;
JSErrorReporter mOldErrorReporter;
PRBool mErrorReporterSet;
PRBool mEvaluated;
jsword mContextHasThread;

Просмотреть файл

@ -55,7 +55,11 @@ void AutoScriptEvaluate::StartEvaluating(JSErrorReporter errorReporter)
if(!mJSContext)
return;
mEvaluated = PR_TRUE;
mOldErrorReporter = JS_SetErrorReporter(mJSContext, errorReporter);
if(!mJSContext->errorReporter)
{
JS_SetErrorReporter(mJSContext, errorReporter);
mErrorReporterSet = PR_TRUE;
}
mContextHasThread = JS_GetContextThread(mJSContext);
if (mContextHasThread)
JS_BeginRequest(mJSContext);
@ -105,7 +109,9 @@ AutoScriptEvaluate::~AutoScriptEvaluate()
if(scriptNotify)
scriptNotify->ScriptExecuted();
}
JS_SetErrorReporter(mJSContext, mOldErrorReporter);
if(mErrorReporterSet)
JS_SetErrorReporter(mJSContext, NULL);
}
// It turns out that some errors may be not worth reporting. So, this
@ -906,6 +912,15 @@ nsXPCWrappedJSClass::CleanupPointerTypeObject(const nsXPTType& type,
}
}
class AutoClearPendingException
{
public:
AutoClearPendingException(JSContext *cx) : mCx(cx) { }
~AutoClearPendingException() { JS_ClearPendingException(mCx); }
private:
JSContext* mCx;
};
nsresult
nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
const char * aPropertyName,
@ -926,8 +941,10 @@ nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
nsresult pending_result = xpcc->GetPendingResult();
jsval js_exception;
JSBool is_js_exception = JS_GetPendingException(cx, &js_exception);
/* JS might throw an expection whether the reporter was called or not */
if(JS_GetPendingException(cx, &js_exception))
if(is_js_exception)
{
if(!xpc_exception)
XPCConvert::JSValToXPCException(ccx, js_exception, anInterfaceName,
@ -939,9 +956,10 @@ nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
{
ccx.GetThreadData()->SetException(nsnull); // XXX necessary?
}
JS_ClearPendingException(cx);
}
AutoClearPendingException acpe(cx);
if(xpc_exception)
{
nsresult e_result;
@ -992,6 +1010,14 @@ nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
}
}
// Try to use the error reporter set on the context to handle this
// error if it came from a JS exception.
if(reportable && is_js_exception &&
cx->errorReporter != xpcWrappedJSErrorReporter)
{
reportable = !JS_ReportPendingException(cx);
}
if(reportable)
{
#ifdef DEBUG