diff --git a/include/NativeJSRenderer.h b/include/NativeJSRenderer.h index ee9f629..11f81c6 100644 --- a/include/NativeJSRenderer.h +++ b/include/NativeJSRenderer.h @@ -137,6 +137,7 @@ namespace JsRuntime { std::list getApplications(); void setExternalApplicationHandler(std::shared_ptr handler); std::string getBaseUserAgent(); + void setLocation(std::stringstream& window, const std::string& url); private: bool downloadFile(std::string& url, MemoryStruct& chunk); void processDevConsoleRequests(); diff --git a/src/NativeJSRenderer.cpp b/src/NativeJSRenderer.cpp index 7649032..a6f9809 100644 --- a/src/NativeJSRenderer.cpp +++ b/src/NativeJSRenderer.cpp @@ -362,8 +362,8 @@ void NativeJSRenderer::runApplicationInternal(ApplicationRequest& appRequest) if(context->getModuleSettings().enableMiniJSDOM || context->getModuleSettings().enableJSDOM) { std::stringstream window; - window<<"window.location = {\"href\":\"" << url << "\"};"; - NativeJSLogger::log(INFO, "Adding the window location: %s to js file\n", window.str().c_str()); + setLocation(window, url); + NativeJSLogger::log(INFO, "Adding the window location: %s to js file\n", window.str().c_str()); context->runScript(window.str().c_str(),true, url, nullptr, true); } NativeJSLogger::log(INFO, "nativeJS application thunder execution url: %s\n", url.c_str()); @@ -377,12 +377,13 @@ void NativeJSRenderer::runApplicationInternal(ApplicationRequest& appRequest) { NativeJSLogger::log(INFO, "About to launch local app\n"); JavaScriptContext* context = (JavaScriptContext*)mContextMap[id].context; - context->setUrl(mContextMap[id].url); + context->setUrl(mContextMap[id].url); if(context->getModuleSettings().enableMiniJSDOM || context->getModuleSettings().enableJSDOM) { std::stringstream window; - window<<"window.location = {\"href\":\"file:/" << url << "\"};"; - NativeJSLogger::log(INFO, "Adding the window location: %s to js file\n", window.str().c_str()); + std::string localUrl = "file://" + url; + setLocation(window, localUrl); + NativeJSLogger::log(INFO, "Adding the window location: %s to js file\n", window.str().c_str()); context->runScript(window.str().c_str(),true, url, nullptr, true); } NativeJSLogger::log(INFO, "Running test application: %s\n", url.c_str()); @@ -689,4 +690,66 @@ std::string NativeJSRenderer::getBaseUserAgent() { return mBaseUserAgent; } +void NativeJSRenderer::setLocation(std::stringstream& window, const std::string& url) +{ + auto schemePos = url.find("://"); + + std::string protocol, host, hostname, port, pathname, search, hash, origin = "null"; + + if (schemePos != std::string::npos) + { + protocol = url.substr(0, schemePos) + ":"; + + auto authorityStart = schemePos + 3; + auto pathStart = url.find_first_of("/?#", authorityStart); + host = (pathStart == std::string::npos) + ? url.substr(authorityStart) + : url.substr(authorityStart, pathStart - authorityStart); + + auto portPos = host.find(':'); + if (portPos != std::string::npos) + { + hostname = host.substr(0, portPos); + port = host.substr(portPos + 1); + } + else + { + hostname = host; + } + + if (pathStart != std::string::npos) + { + auto queryPos = url.find('?', pathStart); + auto hashPos = url.find('#', pathStart); + + auto pathEnd = std::min( + queryPos == std::string::npos ? url.size() : queryPos, + hashPos == std::string::npos ? url.size() : hashPos); + + pathname = url.substr(pathStart, pathEnd - pathStart); + + if (queryPos != std::string::npos) + search = url.substr(queryPos, + (hashPos == std::string::npos ? url.size() : hashPos) - queryPos); + + if (hashPos != std::string::npos) + hash = url.substr(hashPos); + } + + if (protocol != "file:") + origin = protocol + "//" + host; + } + + window << "window.location={" + << "\"href\":\"" << url << "\"," + << "\"protocol\":\"" << protocol << "\"," + << "\"host\":\"" << host << "\"," + << "\"hostname\":\"" << hostname << "\"," + << "\"port\":\"" << port << "\"," + << "\"pathname\":\"" << pathname << "\"," + << "\"search\":\"" << search << "\"," + << "\"hash\":\"" << hash << "\"," + << "\"origin\":\"" << origin << "\"" + << "};"; +} diff --git a/src/jsc/modules/linkedjsdomwrapper.js b/src/jsc/modules/linkedjsdomwrapper.js index e6d70e5..a895b69 100755 --- a/src/jsc/modules/linkedjsdomwrapper.js +++ b/src/jsc/modules/linkedjsdomwrapper.js @@ -27,9 +27,11 @@ var jsdom = new JSDOM(''); document = jsdom.document; global.document = document; window = jsdom.window; +global.window = window; Event = window.Event; DOMParser = window.DOMParser; navigator = window.navigator; +global.navigator = navigator; tv = window.tv = {} //fetch = FetchLib; try @@ -84,3 +86,80 @@ crypto.getRandomValues = getRandom; setInterval(checkUrlChange, 500); })(); + +(function() { + + function run(code, url) { + try { + (0, eval)(code + "\n//# sourceURL=" + url); + return null; + } catch (e) { + return e; + } + } + + function load(url, ok, fail) { + var x = new XMLHttpRequest(); + x.open("GET", url, true); + + x.onreadystatechange = function() { + if (x.readyState !== 4) return; + + if (x.status >= 200 && x.status < 300) + ok(x.responseText || ""); + else + fail(new Error("HTTP " + x.status)); + }; + + x.onerror = fail; + x.send(); + } + + var orig = HTMLElement.prototype.appendChild; + + HTMLElement.prototype.appendChild = function(node) { + + var ret = orig.call(this, node); + + if ( + node && + node.tagName && + node.tagName.toLowerCase() === "script" && + node.src + ) { + load( + node.src, + function(code) { + + var err = run(code, node.src); + + if (err) + return node.onerror && node.onerror(err); + + node.readyState = "complete"; + + if (typeof node.onreadystatechange === "function") + node.onreadystatechange.call(node); + + if (typeof node.dispatchEvent === "function" && typeof Event === "function") { + node.dispatchEvent(new Event("load")); + } else if ( + typeof node.onload === "function" && + node.onload !== node.onreadystatechange + ) { + node.onload.call(node); + } + }, + function(err) { + if (typeof node.dispatchEvent === "function" && typeof Event === "function") { + node.dispatchEvent(new Event("error")); + } else if (typeof node.onerror === "function") { + node.onerror(err); + } + } + ); + } + + return ret; + }; +})();