<rdar://problem/6425807> Implement WorkerUtils.importScripts()
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Mar 2009 09:44:30 +0000 (09:44 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Mar 2009 09:44:30 +0000 (09:44 +0000)
<https://bugs.webkit.org/show_bug.cgi?id=22721>

Reviewed by Alexey Proskuryakov

Implement importScripts, currently uses a series of synchronous loads
to fetch the scripts, but this is simpler than a synchronous load of
multiple loads in parallel.  In future we'll want to switch to parallel
loading, but this will do for now.

Test: http/tests/workers/worker-importScripts.html

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@41549 268f45cc-cd09-0410-ab3c-d52691b4dbfc

28 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/workers/resources/worker-importScripts-differentOrigin.js [new file with mode: 0644]
LayoutTests/http/tests/workers/resources/worker-importScripts-source1.js [new file with mode: 0644]
LayoutTests/http/tests/workers/resources/worker-importScripts-source2.js [new file with mode: 0644]
LayoutTests/http/tests/workers/resources/worker-importScripts-syntaxError.js [new file with mode: 0644]
LayoutTests/http/tests/workers/resources/worker-importScripts.js [new file with mode: 0644]
LayoutTests/http/tests/workers/worker-importScripts-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/workers/worker-importScripts.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/GNUmakefile.am
WebCore/WebCore.vcproj/WebCore.vcproj
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/bindings/js/JSWorkerContextCustom.cpp
WebCore/bindings/js/ScriptValue.h
WebCore/bindings/js/WorkerScriptController.cpp
WebCore/bindings/js/WorkerScriptController.h
WebCore/dom/Document.cpp
WebCore/dom/Document.h
WebCore/dom/ScriptExecutionContext.h
WebCore/inspector/InspectorController.cpp
WebCore/inspector/InspectorController.h
WebCore/inspector/InspectorResource.cpp
WebCore/inspector/InspectorResource.h
WebCore/workers/WorkerContext.cpp
WebCore/workers/WorkerContext.h
WebCore/workers/WorkerContext.idl
WebCore/workers/WorkerImportScriptsClient.cpp [new file with mode: 0644]
WebCore/workers/WorkerImportScriptsClient.h [new file with mode: 0644]

index bbb0b87..c0a9ccc 100644 (file)
@@ -1,3 +1,22 @@
+2009-03-10  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Alexey Proskuryakov.
+
+        <rdar://problem/6425807> Implement WorkerUtils.importScripts()
+        <https://bugs.webkit.org/show_bug.cgi?id=22721>
+
+        Tests to cover various usages of importScripts, eg. network load
+        failures, security exceptions, execution ordering, etc
+
+        * http/tests/workers/resources/worker-importScripts-differentOrigin.js: Added.
+        * http/tests/workers/resources/worker-importScripts-source1.js: Added.
+        * http/tests/workers/resources/worker-importScripts-source2.js: Added.
+        * http/tests/workers/resources/worker-importScripts-syntaxError.js: Added.
+        * http/tests/workers/resources/worker-importScripts.js: Added.
+        (try.resetLoadFlags):
+        * http/tests/workers/worker-importScripts-expected.txt: Added.
+        * http/tests/workers/worker-importScripts.html: Added.
+
 2009-03-10  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Darin Adler.
diff --git a/LayoutTests/http/tests/workers/resources/worker-importScripts-differentOrigin.js b/LayoutTests/http/tests/workers/resources/worker-importScripts-differentOrigin.js
new file mode 100644 (file)
index 0000000..358f6d9
--- /dev/null
@@ -0,0 +1,2 @@
+differentOriginLoaded = true;
+postMessage("Loaded message from different origin");
diff --git a/LayoutTests/http/tests/workers/resources/worker-importScripts-source1.js b/LayoutTests/http/tests/workers/resources/worker-importScripts-source1.js
new file mode 100644 (file)
index 0000000..10a8028
--- /dev/null
@@ -0,0 +1,6 @@
+loadedSource1 = true;
+postMessage("Loaded resource 1");
+if (this.firstShouldThrow) {
+    postMessage("First resource throwing an exception");
+    throw "Thrown by first resource"
+}
diff --git a/LayoutTests/http/tests/workers/resources/worker-importScripts-source2.js b/LayoutTests/http/tests/workers/resources/worker-importScripts-source2.js
new file mode 100644 (file)
index 0000000..8640edd
--- /dev/null
@@ -0,0 +1,8 @@
+if (!loadedSource1)
+    postMessage("Resource 2 loaded before resource 1");
+loadedSource2 = true;
+postMessage("Loaded resource 2");
+if (this.secondShouldThrow) {
+    postMessage("Second resource throwing an exception");
+    throw "Thrown by second resource";
+}
diff --git a/LayoutTests/http/tests/workers/resources/worker-importScripts-syntaxError.js b/LayoutTests/http/tests/workers/resources/worker-importScripts-syntaxError.js
new file mode 100644 (file)
index 0000000..de264d4
--- /dev/null
@@ -0,0 +1 @@
+a syntax error
diff --git a/LayoutTests/http/tests/workers/resources/worker-importScripts.js b/LayoutTests/http/tests/workers/resources/worker-importScripts.js
new file mode 100644 (file)
index 0000000..ddf479c
--- /dev/null
@@ -0,0 +1,133 @@
+try {
+postMessage("Test started.");
+
+importScripts();
+postMessage("PASS: importScripts(), exists, is a function, and doesn't throw when not given any arguments");
+
+var source1 = "worker-importScripts-source1.js";
+var source2 = "worker-importScripts-source2.js";
+var differentOrigin = "http://localhost:8000/workers/resources/worker-importScripts-differentOrigin.js";
+var syntaxErrorSource = "worker-importScripts-syntaxError.js";
+var fakeSource = "nonexistant";
+var loadedSource1 = false;
+var loadedSource2 = false;
+var differentOriginLoaded = false;
+
+function resetLoadFlags() {
+    loadedSource1 = false;
+    loadedSource2 = false;
+    differentOriginLoaded = false;
+}
+
+try {
+    importScripts(differentOrigin)
+} catch(e) {
+    postMessage("FAIL: Threw " + e + " when attempting cross origin load");
+}
+if (differentOriginLoaded)
+    postMessage("PASS: executed script from different origin");
+
+resetLoadFlags();
+
+postMessage("Testing single argument:");
+importScripts(source1)
+if (loadedSource1)
+    postMessage("PASS: loaded first source");
+else
+    postMessage("FAIL: did not load first source");
+
+resetLoadFlags();
+
+postMessage("Testing multiple arguments:");
+importScripts(source1, source2);
+if (loadedSource1 && loadedSource2)
+    postMessage("PASS: Both sources loaded and executed.");
+else
+    postMessage("FAIL: not all sources were loaded");
+
+resetLoadFlags();
+
+postMessage("Testing multiple arguments (different order):");
+importScripts(source2, source1);
+if (loadedSource1 && loadedSource2)
+    postMessage("PASS: Both sources loaded and executed.");
+else
+    postMessage("FAIL: not all sources were loaded");
+
+resetLoadFlags();
+firstShouldThrow = false;
+secondShouldThrow = false;
+postMessage("Testing multiple arguments, with different origin for one argument:");
+try {
+    importScripts(source1, differentOrigin, source2);
+} catch(e) {
+    postMessage("FAIL: Threw " + e + " when attempt cross origin load");
+}
+if (loadedSource1 && loadedSource2 && differentOriginLoaded)
+    postMessage("PASS: all resources executed.");
+else
+    postMessage("FAIL: Not  of the origin failure");
+
+resetLoadFlags();
+
+try {
+    importScripts(source1, fakeSource, source2);
+} catch(e) {
+    postMessage("PASS: Threw " + e + " when load failed");
+}
+if (!loadedSource1 && !loadedSource2)
+    postMessage("FAIL: Nothing was executed when network error occurred.");
+else
+    postMessage("PASS: some resources were loaded despite the network error");
+
+resetLoadFlags();
+
+try {
+    importScripts(source1, syntaxErrorSource, source2);
+} catch(e) {
+    postMessage("PASS: Threw " + e + " when encountering a syntax error in imported script");
+}
+if (!loadedSource1 && !loadedSource2)
+    postMessage("FAIL: Nothing was executed when syntax error was present in any source.");
+else
+    postMessage("PASS: some resources were loaded despite the presence of a syntax error");
+
+resetLoadFlags();
+
+postMessage("Testing multiple arguments, with first resource throwing an exception:");
+firstShouldThrow = true;
+try {
+    importScripts(source1, source2);
+} catch(e) {
+    postMessage("PASS: Propagated '" + e + "' from script");
+}
+firstShouldThrow = false;
+if (loadedSource1 && !loadedSource2)
+    postMessage("PASS: First resource was executed, and second resource was not");
+else if (loadedSource2)
+    postMessage("FAIL: Second resource was executed");
+else
+    postMessage("FAIL: first resource did not execute correctly");
+
+resetLoadFlags();
+
+postMessage("Testing multiple arguments, with second resource throwing an exception:");
+secondShouldThrow = true;
+try {
+    importScripts(source1, source2);
+} catch(e) {
+    postMessage("PASS: Propagated '" + e + "' from script");
+}
+secondShouldThrow = false;
+if (loadedSource1 && loadedSource2)
+    postMessage("PASS: Both scripts were executed");
+else
+    postMessage("FAIL: scripts did not execute correctly");
+
+resetLoadFlags();
+
+} catch(e) {
+    postMessage("FAIL: Unexpected exception: " + e);
+} finally {
+    postMessage("DONE");
+}
diff --git a/LayoutTests/http/tests/workers/worker-importScripts-expected.txt b/LayoutTests/http/tests/workers/worker-importScripts-expected.txt
new file mode 100644 (file)
index 0000000..bbd11a7
--- /dev/null
@@ -0,0 +1,42 @@
+Test importScripts.
+
+Test started.
+PASS: importScripts(), exists, is a function, and doesn't throw when not given any arguments
+Loaded message from different origin
+PASS: executed script from different origin
+Testing single argument:
+Loaded resource 1
+PASS: loaded first source
+Testing multiple arguments:
+Loaded resource 1
+Loaded resource 2
+PASS: Both sources loaded and executed.
+Testing multiple arguments (different order):
+Resource 2 loaded before resource 1
+Loaded resource 2
+Loaded resource 1
+PASS: Both sources loaded and executed.
+Testing multiple arguments, with different origin for one argument:
+Loaded resource 1
+Loaded message from different origin
+Loaded resource 2
+PASS: all resources executed.
+Loaded resource 1
+PASS: Threw Error: NETWORK_ERR: XMLHttpRequest Exception 101 when load failed
+PASS: some resources were loaded despite the network error
+Loaded resource 1
+PASS: Threw SyntaxError: Parse error when encountering a syntax error in imported script
+PASS: some resources were loaded despite the presence of a syntax error
+Testing multiple arguments, with first resource throwing an exception:
+Loaded resource 1
+First resource throwing an exception
+PASS: Propagated 'Thrown by first resource' from script
+PASS: First resource was executed, and second resource was not
+Testing multiple arguments, with second resource throwing an exception:
+Loaded resource 1
+Loaded resource 2
+Second resource throwing an exception
+PASS: Propagated 'Thrown by second resource' from script
+PASS: Both scripts were executed
+DONE
+
diff --git a/LayoutTests/http/tests/workers/worker-importScripts.html b/LayoutTests/http/tests/workers/worker-importScripts.html
new file mode 100644 (file)
index 0000000..f70a456
--- /dev/null
@@ -0,0 +1,24 @@
+<body>
+<p>Test importScripts.</p>
+<div id=result></div>
+<script>
+function log(message)
+{
+    document.getElementById("result").innerHTML += message + "<br>";
+}
+
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+var worker = new Worker('resources/worker-importScripts.js');
+
+worker.onmessage = function(evt) {
+    log(evt.data);
+    if (evt.data == "DONE" && window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+</script>
+</body>
+</html>
index 4f16d04..3ba17b8 100644 (file)
@@ -1,3 +1,55 @@
+2009-03-10  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Alexey Proskuryakov.
+
+        <rdar://problem/6425807> Implement WorkerUtils.importScripts()
+        <https://bugs.webkit.org/show_bug.cgi?id=22721>
+
+        Implement importScripts, currently uses a series of synchronous loads
+        to fetch the scripts, but this is simpler than a synchronous load of
+        multiple loads in parallel.  In future we'll want to switch to parallel
+        loading, but this will do for now.
+        
+        Test: http/tests/workers/worker-importScripts.html
+
+        * GNUmakefile.am:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSWorkerContextCustom.cpp:
+        (WebCore::JSWorkerContext::importScripts):
+        * bindings/js/ScriptValue.h:
+        (WebCore::ScriptValue::hasNoValue):
+        * bindings/js/WorkerScriptController.cpp:
+        (WebCore::WorkerScriptController::evaluate):
+        (WebCore::WorkerScriptController::setException):
+        * bindings/js/WorkerScriptController.h:
+        * dom/Document.cpp:
+        (WebCore::Document::scriptImported):
+        * dom/Document.h:
+        * dom/ScriptExecutionContext.h:
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::scriptImported):
+        * inspector/InspectorController.h:
+        * inspector/InspectorResource.cpp:
+        (WebCore::InspectorResource::setScriptProperties):
+        * inspector/InspectorResource.h:
+        * workers/WorkerContext.cpp:
+        (WebCore::WorkerContext::scriptImported):
+        (WebCore::WorkerContext::importScripts):
+        * workers/WorkerContext.h:
+        * workers/WorkerContext.idl:
+        * workers/WorkerImportScriptsClient.cpp: Added.
+        (WebCore::WorkerImportScriptsClient::didReceiveResponse):
+        (WebCore::WorkerImportScriptsClient::didReceiveData):
+        (WebCore::WorkerImportScriptsClient::didFinishLoading):
+        (WebCore::WorkerImportScriptsClient::didFail):
+        (WebCore::WorkerImportScriptsClient::didFailRedirectCheck):
+        (WebCore::WorkerImportScriptsClient::didReceiveAuthenticationCancellation):
+        * workers/WorkerImportScriptsClient.h: Added.
+        (WebCore::WorkerImportScriptsClient::WorkerImportScriptsClient):
+        (WebCore::WorkerImportScriptsClient::script):
+        (WebCore::WorkerImportScriptsClient::failed):
+
 2009-03-10  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Darin Adler.
index 0fb9963..31b3f75 100644 (file)
@@ -2220,7 +2220,9 @@ webcore_sources += \
        WebCore/workers/WorkerRunLoop.cpp \
        WebCore/workers/WorkerRunLoop.h \
        WebCore/workers/WorkerThread.cpp \
-       WebCore/workers/WorkerThread.h
+       WebCore/workers/WorkerThread.h \
+       WebCore/workers/WorkerImportScriptsClient.cpp \
+       WebCore/workers/WorkerImportScriptsClient.h
 endif
 
 # ----
index 994c77f..ba51ad5 100644 (file)
                                RelativePath="..\workers\WorkerThread.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\workers\WorkerImportScriptsClient.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\workers\WorkerImportScriptsClient.h"\r
+                               >\r
+                       </File>\r
                </Filter>\r
                <Filter\r
                        Name="editing"\r
index 0260874..9f2970d 100644 (file)
                A7D0318E0E93540300E24ACD /* JSImageDataCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7D0318D0E93540300E24ACD /* JSImageDataCustom.cpp */; };
                A7D27FC40E0A599F0079AD2B /* SVGFETile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7D27FC30E0A599F0079AD2B /* SVGFETile.cpp */; };
                A7D3C5240B576B4B002CA450 /* PasteboardHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D3C5230B576B4B002CA450 /* PasteboardHelper.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               A7D6B3490F61104500B79FD1 /* WorkerImportScriptsClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D6B3470F61104500B79FD1 /* WorkerImportScriptsClient.h */; };
+               A7D6B34A0F61104500B79FD1 /* WorkerImportScriptsClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7D6B3480F61104500B79FD1 /* WorkerImportScriptsClient.cpp */; };
                A809F1470B73793A002E4D7F /* RenderSVGGradientStop.h in Headers */ = {isa = PBXBuildFile; fileRef = A809F1450B73793A002E4D7F /* RenderSVGGradientStop.h */; };
                A809F1480B73793B002E4D7F /* RenderSVGGradientStop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A809F1460B73793A002E4D7F /* RenderSVGGradientStop.cpp */; };
                A809F1AA0B737FB6002E4D7F /* RenderSVGHiddenContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = A809F1A80B737FB6002E4D7F /* RenderSVGHiddenContainer.h */; };
                A7D0318D0E93540300E24ACD /* JSImageDataCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSImageDataCustom.cpp; sourceTree = "<group>"; };
                A7D27FC30E0A599F0079AD2B /* SVGFETile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGFETile.cpp; sourceTree = "<group>"; };
                A7D3C5230B576B4B002CA450 /* PasteboardHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PasteboardHelper.h; sourceTree = "<group>"; };
+               A7D6B3470F61104500B79FD1 /* WorkerImportScriptsClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WorkerImportScriptsClient.h; path = workers/WorkerImportScriptsClient.h; sourceTree = "<group>"; };
+               A7D6B3480F61104500B79FD1 /* WorkerImportScriptsClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WorkerImportScriptsClient.cpp; path = workers/WorkerImportScriptsClient.cpp; sourceTree = "<group>"; };
                A809F1450B73793A002E4D7F /* RenderSVGGradientStop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGGradientStop.h; sourceTree = "<group>"; };
                A809F1460B73793A002E4D7F /* RenderSVGGradientStop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSVGGradientStop.cpp; sourceTree = "<group>"; };
                A809F1A80B737FB6002E4D7F /* RenderSVGHiddenContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGHiddenContainer.h; sourceTree = "<group>"; };
                                2E4346410F546A8200B0F1BA /* WorkerRunLoop.h */,
                                2E4346420F546A8200B0F1BA /* WorkerThread.cpp */,
                                2E4346430F546A8200B0F1BA /* WorkerThread.h */,
+                               A7D6B3470F61104500B79FD1 /* WorkerImportScriptsClient.h */,
+                               A7D6B3480F61104500B79FD1 /* WorkerImportScriptsClient.cpp */,
                        );
                        name = workers;
                        sourceTree = "<group>";
                                5D925B680F64D4DD00B847F0 /* ScrollBehavior.h in Headers */,
                                E1C415DA0F655D6F0092D2FB /* CrossOriginPreflightResultCache.h in Headers */,
                                E1C416120F6562FD0092D2FB /* CrossOriginAccessControl.h in Headers */,
+                               A7D6B3490F61104500B79FD1 /* WorkerImportScriptsClient.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                5D925B670F64D4DD00B847F0 /* ScrollBehavior.cpp in Sources */,
                                E1C415DE0F655D7C0092D2FB /* CrossOriginPreflightResultCache.cpp in Sources */,
                                E1C416170F6563180092D2FB /* CrossOriginAccessControl.cpp in Sources */,
+                               A7D6B34A0F61104500B79FD1 /* WorkerImportScriptsClient.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index c3ef9c1..5b99435 100644 (file)
@@ -33,6 +33,7 @@
 #include "JSEventListener.h"
 #include "ScheduledAction.h"
 #include "WorkerContext.h"
+#include <interpreter/Interpreter.h>
 
 using namespace JSC;
 
@@ -76,6 +77,29 @@ void JSWorkerContext::setSelf(ExecState* exec, JSValuePtr value)
     putDirect(Identifier(exec, "self"), value);
 }
 
+JSValuePtr JSWorkerContext::importScripts(ExecState* exec, const ArgList& args)
+{
+    if (!args.size())
+        return jsUndefined();
+
+    Vector<String> urls;
+    for (unsigned i = 0; i < args.size(); i++) {
+        urls.append(args.at(exec, i).toString(exec));
+        if (exec->hadException())
+            return jsUndefined();
+    }
+    ExceptionCode ec = 0;
+    int signedLineNumber;
+    intptr_t sourceID;
+    UString sourceURL;
+    JSValuePtr function;
+    exec->interpreter()->retrieveLastCaller(exec, signedLineNumber, sourceID, sourceURL, function);
+
+    impl()->importScripts(urls, sourceURL, signedLineNumber >= 0 ? signedLineNumber : 0, ec);
+    setDOMException(exec, ec);
+    return jsUndefined();
+}
+
 JSValuePtr JSWorkerContext::addEventListener(ExecState* exec, const ArgList& args)
 {
     RefPtr<JSUnprotectedEventListener> listener = findOrCreateJSUnprotectedEventListener(exec, args.at(exec, 1));
index 855509a..3cee09b 100644 (file)
@@ -45,6 +45,7 @@ public:
     bool getString(String& result) const;
     bool isNull() const;
     bool isUndefined() const;
+    bool hasNoValue() const { return m_value == JSC::noValue(); }
 
 private:
     JSC::ProtectedJSValuePtr m_value;
index ab97b52..07eed45 100644 (file)
@@ -80,6 +80,22 @@ ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
         if (m_executionForbidden)
             return noValue();
     }
+    ScriptValue exception;
+    ScriptValue result = evaluate(sourceCode, &exception);
+    if (exception.jsValue()) {
+        JSLock lock(false);
+        reportException(m_workerContextWrapper->globalExec(), exception.jsValue());
+    }
+    return result;
+}
+
+ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, ScriptValue* exception)
+{
+    {
+        MutexLocker lock(m_sharedDataMutex);
+        if (m_executionForbidden)
+            return noValue();
+    }
 
     initScriptIfNeeded();
     JSLock lock(false);
@@ -95,10 +111,15 @@ ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
         return comp.value();
 
     if (comp.complType() == Throw)
-        reportException(exec, comp.value());
+        *exception = comp.value();
     return noValue();
 }
 
+void WorkerScriptController::setException(ScriptValue exception)
+{
+    m_workerContextWrapper->globalExec()->setException(exception.jsValue());
+}
+
 void WorkerScriptController::forbidExecution()
 {
     // This function is called from another thread.
index 1dda5da..0454721 100644 (file)
@@ -57,9 +57,11 @@ namespace WebCore {
         }
 
         ScriptValue evaluate(const ScriptSourceCode&);
+        ScriptValue evaluate(const ScriptSourceCode&, ScriptValue* exception);
 
-        void forbidExecution();
+        void setException(ScriptValue);
 
+        void forbidExecution();
     private:
         void initScriptIfNeeded()
         {
index ea9deb9..da566f6 100644 (file)
@@ -4357,6 +4357,12 @@ void Document::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const
         page()->inspectorController()->resourceRetrievedByXMLHttpRequest(identifier, sourceString);
 }
 
+void Document::scriptImported(unsigned long identifier, const String& sourceString)
+{
+    if (page())
+        page()->inspectorController()->scriptImported(identifier, sourceString);
+}
+
 class ScriptExecutionContextTaskTimer : public TimerBase {
 public:
     ScriptExecutionContextTaskTimer(PassRefPtr<Document> context, PassRefPtr<ScriptExecutionContext::Task> task)
index c9b2184..3770c09 100644 (file)
@@ -792,6 +792,7 @@ public:
     virtual void reportException(const String& errorMessage, int lineNumber, const String& sourceURL);
     virtual void addMessage(MessageDestination, MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL);
     virtual void resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString);
+    virtual void scriptImported(unsigned long, const String&);
     virtual void postTask(PassRefPtr<Task>); // Executes the task on context's thread asynchronously.
 
 protected:
index 867d34f..3859388 100644 (file)
@@ -67,7 +67,8 @@ namespace WebCore {
         virtual void reportException(const String& errorMessage, int lineNumber, const String& sourceURL) = 0;
         virtual void addMessage(MessageDestination, MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL) = 0;
         virtual void resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString) = 0;
-
+        virtual void scriptImported(unsigned long, const String&) = 0;
+        
         // Active objects are not garbage collected even if inaccessible, e.g. because their activity may result in callbacks being invoked.
         bool canSuspendActiveDOMObjects();
         // Active objects can be asked to suspend even if canSuspendActiveDOMObjects() returns 'false' -
index 8119054..2d02e9f 100644 (file)
@@ -1718,6 +1718,21 @@ void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identi
         updateScriptResourceType(resource);
 }
 
+void InspectorController::scriptImported(unsigned long identifier, const JSC::UString& sourceString)
+{
+    if (!enabled())
+        return;
+    
+    InspectorResource* resource = m_resources.get(identifier).get();
+    if (!resource)
+        return;
+    
+    resource->setXMLHttpRequestProperties(sourceString);
+    
+    if (windowVisible() && resource->scriptObject)
+        updateScriptResourceType(resource);
+}
+
 
 #if ENABLE(DATABASE)
 void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version)
index a2f6f44..0fc3bdd 100644 (file)
@@ -215,6 +215,7 @@ public:
     void didFinishLoading(DocumentLoader*, unsigned long identifier);
     void didFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&);
     void resourceRetrievedByXMLHttpRequest(unsigned long identifier, const JSC::UString& sourceString);
+    void scriptImported(unsigned long identifier, const JSC::UString& sourceString);
 
 #if ENABLE(DATABASE)
     void didOpenDatabase(Database*, const String& domain, const String& name, const String& version);
index 925ba6b..7db6cd1 100644 (file)
@@ -133,6 +133,11 @@ void InspectorResource::setXMLHttpRequestProperties(const JSC::UString& data)
     xmlHttpRequestResource.set(new XMLHttpRequestResource(data));
 }
 
+void InspectorResource::setScriptProperties(const JSC::UString& data)
+{
+    xmlHttpRequestResource.set(new XMLHttpRequestResource(data));
+}
+
 String InspectorResource::sourceString() const
 {
     if (xmlHttpRequestResource)
index d330560..46d7fed 100644 (file)
@@ -74,6 +74,7 @@ namespace WebCore {
         Type type() const;
         void setScriptObject(JSContextRef, JSObjectRef);
         void setXMLHttpRequestProperties(const JSC::UString& data);
+        void setScriptProperties(const JSC::UString& data);
 
         String sourceString() const;
 
index fda2e6d..9fc7062 100644 (file)
 #include "EventException.h"
 #include "MessageEvent.h"
 #include "NotImplemented.h"
+#include "ResourceRequest.h"
+#include "ScriptSourceCode.h"
+#include "ScriptValue.h"
 #include "SecurityOrigin.h"
+#include "ThreadableLoader.h"
+#include "WorkerImportScriptsClient.h"
 #include "WorkerLocation.h"
 #include "WorkerNavigator.h"
 #include "WorkerObjectProxy.h"
 #include "WorkerThread.h"
+#include "XMLHttpRequestException.h"
 #include <wtf/RefPtr.h>
 
 namespace WebCore {
@@ -136,6 +142,12 @@ void WorkerContext::resourceRetrievedByXMLHttpRequest(unsigned long, const Scrip
     notImplemented();
 }
 
+void WorkerContext::scriptImported(unsigned long, const String&)
+{
+    // FIXME: The implementation is pending the fixes in https://bugs.webkit.org/show_bug.cgi?id=23175
+    notImplemented();
+}
+
 void WorkerContext::postMessage(const String& message)
 {
     m_thread->workerObjectProxy()->postMessageToWorkerObject(message);
@@ -222,6 +234,44 @@ void WorkerContext::dispatchMessage(const String& message)
     ASSERT(!ec);
 }
 
+void WorkerContext::importScripts(const Vector<String>& urls, const String& callerURL, int callerLine, ExceptionCode& ec)
+{
+    ec = 0;
+    Vector<String>::const_iterator urlsEnd = urls.end();
+    Vector<KURL> completedURLs;
+    for (Vector<String>::const_iterator it = urls.begin(); it != urlsEnd; ++it) {
+        const KURL& url = scriptExecutionContext()->completeURL(*it);
+        if (!url.isValid()) {
+            ec = SYNTAX_ERR;
+            return;
+        }
+        completedURLs.append(url);
+    }
+    String securityOrigin = scriptExecutionContext()->securityOrigin()->toString();
+    Vector<KURL>::const_iterator end = completedURLs.end();
+
+    for (Vector<KURL>::const_iterator it = completedURLs.begin(); it != end; ++it) {
+        ResourceRequest request(*it);
+        request.setHTTPMethod("GET");
+        request.setHTTPOrigin(securityOrigin);
+        WorkerImportScriptsClient client(scriptExecutionContext(), *it, callerURL, callerLine);
+        ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, client);
+        
+        // If the fetching attempt failed, throw a NETWORK_ERR exception and abort all these steps.
+        if (client.failed()) {
+            ec = XMLHttpRequestException::NETWORK_ERR;
+            return;
+        }
+
+        ScriptValue exception;
+        m_script->evaluate(ScriptSourceCode(client.script(), *it), &exception);
+        if (!exception.hasNoValue()) {
+            m_script->setException(exception);
+            return;
+        }
+    }
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WORKERS)
index 2255554..664ded3 100644 (file)
@@ -77,6 +77,7 @@ namespace WebCore {
         virtual void reportException(const String& errorMessage, int lineNumber, const String& sourceURL);
         virtual void addMessage(MessageDestination, MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL);
         virtual void resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString);
+        virtual void scriptImported(unsigned long identifier, const String& sourceString);
 
         virtual WorkerContext* toWorkerContext() { return this; }
 
@@ -99,6 +100,8 @@ namespace WebCore {
         typedef HashMap<AtomicString, ListenerVector> EventListenersMap;
         EventListenersMap& eventListeners() { return m_eventListeners; }
 
+        void importScripts(const Vector<String>& urls, const String& callerURL, int callerLine, ExceptionCode&);
+        
         using RefCounted<WorkerContext>::ref;
         using RefCounted<WorkerContext>::deref;
 
index e1fff51..bbfca63 100644 (file)
@@ -40,6 +40,7 @@ module threads {
 
         attribute EventListener onmessage;
         void postMessage(in DOMString message);
+        [Custom] void importScripts(/* urls */);
 
         attribute [Replaceable] WorkerLocation location;
         attribute [Replaceable] WorkerNavigator navigator;
diff --git a/WebCore/workers/WorkerImportScriptsClient.cpp b/WebCore/workers/WorkerImportScriptsClient.cpp
new file mode 100644 (file)
index 0000000..6335074
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(WORKERS)
+
+#include "WorkerImportScriptsClient.h"
+
+#include "ScriptExecutionContext.h"
+
+namespace WebCore {
+
+void WorkerImportScriptsClient::didReceiveResponse(const ResourceResponse& response)
+{
+    if (response.httpStatusCode() / 100 != 2 && response.httpStatusCode() != 0) {
+        m_failed = true;
+        return;
+    }
+    m_responseEncoding = response.textEncodingName();
+}
+
+void WorkerImportScriptsClient::didReceiveData(const char* data, int len)
+{
+    if (m_failed)
+        return;
+
+    if (!m_decoder) {
+        if (!m_responseEncoding.isEmpty())
+            m_decoder = TextResourceDecoder::create("text/javascript", m_responseEncoding);
+        else
+            m_decoder = TextResourceDecoder::create("text/javascript", m_scriptExecutionContext->encoding());
+    }
+
+    if (!len)
+        return;
+    
+    if (len == -1)
+        len = strlen(data);
+    
+    m_script += m_decoder->decode(data, len);
+}
+
+void WorkerImportScriptsClient::didFinishLoading(unsigned long identifier)
+{
+    if (m_failed)
+        return;
+
+    if (m_decoder)
+        m_script += m_decoder->flush();
+    
+    m_scriptExecutionContext->scriptImported(identifier, m_script);
+    m_scriptExecutionContext->addMessage(InspectorControllerDestination, JSMessageSource, LogMessageLevel, "Worker script imported: \"" + m_url + "\".", m_callerLineNumber, m_callerURL);
+}
+
+void WorkerImportScriptsClient::didFail(const ResourceError&)
+{
+    m_failed = true;
+}
+
+void WorkerImportScriptsClient::didFailRedirectCheck()
+{
+    m_failed = true;
+}
+
+void WorkerImportScriptsClient::didReceiveAuthenticationCancellation(const ResourceResponse&)
+{
+    m_failed = true;
+}
+
+}
+
+#endif // ENABLE(WORKERS)
diff --git a/WebCore/workers/WorkerImportScriptsClient.h b/WebCore/workers/WorkerImportScriptsClient.h
new file mode 100644 (file)
index 0000000..ec27054
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ *
+ */
+
+#ifndef WorkerImportScriptsClient_h
+#define WorkerImportScriptsClient_h
+
+#if ENABLE(WORKERS)
+
+#include "ResourceResponse.h"
+#include "ScriptString.h"
+#include "TextResourceDecoder.h"
+#include "ThreadableLoaderClient.h"
+
+namespace WebCore {
+
+    class ScriptExecutionContext;
+    
+    class WorkerImportScriptsClient : public ThreadableLoaderClient {
+    public:
+        WorkerImportScriptsClient(ScriptExecutionContext* scriptExecutionContext, const String& url, const String& callerURL, int callerLineNumber)
+            : m_scriptExecutionContext(scriptExecutionContext)
+            , m_url(url)
+            , m_callerURL(callerURL)
+            , m_callerLineNumber(callerLineNumber)
+            , m_failed(false)
+        {
+        }
+
+        const String& script() const { return m_script; }
+        bool failed() const { return m_failed; }
+
+        virtual void didReceiveResponse(const ResourceResponse& response);
+        virtual void didReceiveData(const char* data, int lengthReceived);
+        virtual void didFinishLoading(unsigned long identifier);
+        virtual void didFail(const ResourceError&);
+        virtual void didFailRedirectCheck();
+        virtual void didReceiveAuthenticationCancellation(const ResourceResponse&);
+
+    private:
+        ScriptExecutionContext* m_scriptExecutionContext;
+        String m_url;
+        String m_callerURL;
+        int m_callerLineNumber;
+        String m_responseEncoding;        
+        RefPtr<TextResourceDecoder> m_decoder;
+        String m_script;
+        bool m_failed;
+    };
+
+}
+
+#endif // ENABLE(WORKERS)
+#endif
+