nwjs / nw.js

Call all Node.js modules directly from DOM/WebWorker and enable a new way of writing applications with all Web technologies.
https://nwjs.io
MIT License
40.29k stars 3.88k forks source link

setTimeout not working when called from window message handler if content path is absolute #6421

Open DjulLau opened 6 years ago

DjulLau commented 6 years ago

NWJS Version : 0.27.5 Operating System : Windows 7 Pro

Expected behavior

setTimeout should call the arrow function after the delay

Actual behavior

setTimeout doesn't call the function

How to reproduce

main.js

// Relative path works OK
require("nw.gui").Window.open("blank.html", {}, (wnd) => {
    wnd.on("loaded", () => { console.debug("Loaded!"); });
    wnd.window.addEventListener("message", (e) => {
        console.debug("wnd1 message", e);
        setTimeout(() => {
            console.debug("timeout 1");
        }, 1000);
    });
});
// Absolute path does not
require("nw.gui").Window.open("Z:\\CBi\\tests\\nwjs-loaded\\blank.html", {}, (wnd) => {
    wnd.on("loaded", () => { console.debug("Loaded!"); });
    wnd.window.addEventListener("message", (e) => {
        console.debug("wnd2 message", e);
        setTimeout(() => {
            console.debug("timeout 2");
        }, 1000);
    });
});

blank.html

window.postMessage("test", "*");

console

wnd2 message MessageEvent main.js:11 Loaded! main.js:4 wnd1 message MessageEvent main.js:2 Loaded! main.js:6 timeout 1

I suspect a security issue but I'm not sure...

Of course in this silly example I don't need to use the absolute path but my real app (like common windows app) downloads data in the appData folder which is different from the program folder (where is located NW.exe and the main program files) and needs to communicate with its content. I'm not sure what is the correct way to handle that in NW. Any help would be greatly appreciated (either a workaround or a hint about installing and using html data that are not located near the main NW program) !

Regards,

Christywl commented 6 years ago

I can reproduce this issue on Linux/Windows with nwjs-sdk-v0.27.5.

DjulLau commented 6 years ago

I've been trying to find a workaround the whole day as this is crucial for the application I should be shipping. I somehow manage to find one for the setTimeout problem by sending message to the window.opener instead of the window itself. Strangely it works but I encounter another problem after when calling capturePage. So after this quite long journey I've updated my minimal test case to that :

main.js

let wndsData = {};

function msgHandler(msg) {
    const wndData = wndsData[msg.data];
    console.debug("Message:", wndData.path);
    const t = setTimeout(() => {
        console.debug("Timeout", wndData.path);
        wndData.wnd.capturePage((buffer) => {
            console.debug("CapturePage", wndData.path);
        });
    }, 10);
}
function openWnd(path) {
    require("nw.gui").Window.open(path, {}, (wnd) => {
        wnd.on("loaded", () => {
            console.debug("Loaded:", path);
            wndsData[wnd.window.location.href] = { wnd, path };
            wnd.window.addEventListener("message", msgHandler);
        });
    });
}

console.debug("*** message to child window ***");
setTimeout(() => { console.debug("*** message to opener ***") }, 4000);

window.addEventListener("message", msgHandler);
openWnd("blank.html");
openWnd("Z:\\CBi\\tests\\nwjs-loaded\\blank.html");

blank.html

setTimeout(() => {            
    window.postMessage(window.location.href, "*");
}, 2000);
setTimeout(() => {
    window.opener.postMessage(window.location.href, "*");
}, 4000);

console

message to child window Loaded: Z:\CBi\tests\nwjs-loaded\blank.html Loaded: blank.html Message: Z:\CBi\tests\nwjs-loaded\blank.html Message: blank.html Timeout blank.html CapturePage blank.html message to opener Message: Z:\CBi\tests\nwjs-loaded\blank.html Timeout Z:\CBi\tests\nwjs-loaded\blank.html Message: blank.html Timeout blank.html CapturePage blank.html

As you can see the setTimeout executes OK with the second "to opener" method. However the capturePage fails and output in the corresponding devtools console :

(WEB_PAGE context) extensions::sendRequest:21: Uncaught TypeError: Cannot read property 'chrome' of undefined{TypeError: Cannot read property 'chrome' of undefined at try_hidden (extensions::sendRequest:21:12) at handleResponse (extensions::sendRequest:42:20)}