From 3664b7045229158eba01826b370f579b6f493ffd Mon Sep 17 00:00:00 2001 From: Osiris Team Date: Thu, 30 Sep 2021 22:07:05 +0200 Subject: [PATCH] 0.0.9 - Fixed js exceptions not getting caught properly --- pom.xml | 2 +- .../osiris/headlessbrowser/NodeContext.java | 61 ++++++++++--------- .../osiris/headlessbrowser/NodeWindow.java | 50 ++++++++++++++- .../headlessbrowser/NodeWindowTest.java | 2 + 4 files changed, 82 insertions(+), 33 deletions(-) diff --git a/pom.xml b/pom.xml index 75fe15f..5c95ddf 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.osiris.headlessbrowser Headless-Browser - 0.0.7 + 0.0.9 jitpack diff --git a/src/main/java/com/osiris/headlessbrowser/NodeContext.java b/src/main/java/com/osiris/headlessbrowser/NodeContext.java index 7eb2d93..c2495be 100644 --- a/src/main/java/com/osiris/headlessbrowser/NodeContext.java +++ b/src/main/java/com/osiris/headlessbrowser/NodeContext.java @@ -25,8 +25,8 @@ public class NodeContext implements AutoCloseable { private final OutputStream processOutput; private final PrintStream debugOutput; private final File lastJsCodeExecutionResultFile; - private File executableFile; private final int timeout; + private File executableFile; public NodeContext() { this(null, 30); @@ -133,17 +133,6 @@ public NodeContext(OutputStream debugOutput, int timeout) { "var fs = require('fs');\n" + "var data = fs.writeFileSync('" + resultFilePath + "', result);\n" + "};\n" + - "// Ensures that all errors get catched:\n" + - "// Note that process.exit() must be called explicitly because by adding the below we are in an inconsistent state\n" + - "// Source: https://stackoverflow.com/questions/19909904/how-to-handle-all-exceptions-in-node-js\n" + - "process.on('uncaughtException', function(err) {\n" + - " console.error('Caught exception: ' + err.name);\n" + - " console.error(\"with message: \"+err.message);\n" + - "try {\n" + - " console.error(\"at line: \" + err.lineNumber);\n" + - " console.error(\"with stack: \" + err.stack);\n" + - "} catch (e) {}\n" + - "});\n" + "console.log('Context initialised!');\n"); } catch (Exception e) { @@ -196,10 +185,10 @@ public synchronized NodeContext writeLine(String line) throws IOException { } /** - * See {@link #executeJavaScript(String, int)} for details. + * See {@link #executeJavaScript(String, int, boolean)} for details. */ public NodeContext executeJavaScript(String jsCode) throws NodeJsCodeException { - return executeJavaScript(jsCode, timeout); + return executeJavaScript(jsCode, timeout, true); } /** @@ -208,10 +197,24 @@ public NodeContext executeJavaScript(String jsCode) throws NodeJsCodeException { * Note that everything related to JavaScript gets printed/written to the {@link #debugOutput}, which
* means that you must have provided this {@link NodeContext} a {@link #debugOutput} at initialisation to see your codes output.
*/ - public synchronized NodeContext executeJavaScript(String jsCode, int timeout) throws NodeJsCodeException { + public synchronized NodeContext executeJavaScript(String jsCode, int timeout, boolean wrapInTryCatch) throws NodeJsCodeException { try { - jsCode = jsCode + "\n" + - "console.log('Done!');\n"; + if (wrapInTryCatch) { + jsCode = "try{\n" + // Just to make sure that errors get definitively caught + jsCode + "\n" + + "console.log('Done!');\n" + + "} catch (e){\n" + + " console.error('CAUGHT JS-EXCEPTION: ' + e.name + '\\n'" + + " + 'MESSAGE: ' + e.message + '\\n'" + + " + 'LINE: ' + e.lineNumber + '\\n'" + + " + 'STACK: ' + e.stack+'\\n');\n" + + "}\n" + ; + } else { + jsCode = jsCode + "\n" + + "console.log('Done!');\n"; + } + if (jsCode.contains("\n")) { debugOutput.println("Executing following JS-Code: "); debugOutput.println("JS-CODE START >"); @@ -227,7 +230,7 @@ public synchronized NodeContext executeJavaScript(String jsCode, int timeout) th } AtomicBoolean wasExecuted = new AtomicBoolean(); - List errors = new ArrayList<>(); + List errors = new ArrayList<>(2); Consumer consoleLogListener = line -> wasExecuted.set(true); processInput.listeners.add(consoleLogListener); @@ -245,26 +248,26 @@ public synchronized NodeContext executeJavaScript(String jsCode, int timeout) th // Wait until we receive a response, like undefined for (int i = 0; i < timeout * 10; i++) { // Example timeout = 30s * 10 = 300loops * 100ms = 30000ms = 30s - if (wasExecuted.get()) + if (wasExecuted.get() || !errors.isEmpty()) break; else Thread.sleep(100); // Total of 30 seconds } - if (timeout == 0) { - while (!wasExecuted.get()) { + if (timeout == 0) { // Since the timeout is 0 we wait indefinitely for the script to finish + while (!wasExecuted.get() && errors.isEmpty()) { Thread.sleep(100); } } + if (!errors.isEmpty()) { + throw new NodeJsCodeException("Error during JavaScript code execution! Details: ", errors); + } + if (!wasExecuted.get()) throw new NodeJsCodeException("Script execution timeout of 30 seconds reached! This means that the script didn't finish within the last 30 seconds.", null); - if (!errors.isEmpty()) { - throw new NodeJsCodeException("Error during JavaScript code execution!", errors); - } - processErrorInput.listeners.remove(consoleErrorLogListener); processInput.listeners.remove(consoleLogListener); tmpJs.delete(); @@ -277,10 +280,10 @@ public synchronized NodeContext executeJavaScript(String jsCode, int timeout) th } /** - * See {@link #executeJavaScript(String, int)} for details. + * See {@link #executeJavaScript(String, int, boolean)} for details. */ public synchronized String executeJavaScriptAndGetResult(String jsCode) { - return executeJavaScriptAndGetResult(jsCode, timeout); + return executeJavaScriptAndGetResult(jsCode, timeout, true); } /** @@ -293,10 +296,10 @@ public synchronized String executeJavaScriptAndGetResult(String jsCode) { * * @param timeout 30 seconds is the default, set to 0 to disable. */ - public synchronized String executeJavaScriptAndGetResult(String jsCode, int timeout) { + public synchronized String executeJavaScriptAndGetResult(String jsCode, int timeout, boolean wrapInTryCatch) { try { executeJavaScript(jsCode + "\n" - + "writeToJava(result);\n", timeout); + + "writeToJava(result);\n", timeout, wrapInTryCatch); StringBuilder result = new StringBuilder(); String line = null; diff --git a/src/main/java/com/osiris/headlessbrowser/NodeWindow.java b/src/main/java/com/osiris/headlessbrowser/NodeWindow.java index a8298ca..6939d4e 100644 --- a/src/main/java/com/osiris/headlessbrowser/NodeWindow.java +++ b/src/main/java/com/osiris/headlessbrowser/NodeWindow.java @@ -26,6 +26,7 @@ public class NodeWindow implements AutoCloseable { private final OutputStream debugOutput; private HBrowser parentBrowser; private boolean enableJavaScript; + private String url; public NodeWindow(HBrowser parentBrowser, boolean enableJavaScript, OutputStream debugOutput, int jsTimeout) { this.parentBrowser = parentBrowser; @@ -35,7 +36,19 @@ public NodeWindow(HBrowser parentBrowser, boolean enableJavaScript, OutputStream jsContext.npmInstall("puppeteer"); jsContext.executeJavaScript("const puppeteer = require('puppeteer');\n" + "const browser = await puppeteer.launch();\n" + - "const page = await browser.newPage();\n"); + "const page = await browser.newPage();\n" + + "var downloadFile = null;\n", 30, false); + jsContext.executeJavaScript("" + + "await page.setRequestInterception(true);\n" + + "page.on('request', (request) => {\n" + + "if (downloadFile!=null){" + + " // Override headers\n" + + " var content = await request.frame().content()\n" + + " console.log('FRAME: '+content);\n" + + "} else{" + + "request.continue();" + + "}" + + "});"); setEnableJavaScript(enableJavaScript); } catch (Exception e) { throw new RuntimeException(e); @@ -60,7 +73,9 @@ public NodeWindow load(String url) throws IOException, NodeJsCodeException { if (!url.startsWith("http")) url = "https://" + url; - jsContext.executeJavaScript("var currentPageResponse = await page.goto('" + url + "');"); + jsContext.executeJavaScript("" + + "var response = await page.goto('" + url + "');\n"); + this.url = url; return this; } @@ -84,7 +99,7 @@ public String getTitle() { * Note that the current {@link NodeContext} must have been initialised with a debugOutputStream to see JavaScript console output.
*/ public NodeWindow executeJS(String jsCode) throws NodeJsCodeException { - jsContext.executeJavaScript("page.evaluate(() => {\n" + + jsContext.executeJavaScript("await page.evaluate(() => {\n" + jsCode + "});\n"); return this; @@ -322,6 +337,35 @@ public int getStatusCode() throws NodeJsCodeException { } */ + /** TODO + * Downloads the currently loaded page/resource to the specified file.
+ * Creates the file if not existing.
+ + public NodeWindow download(File downloadedFile) throws NodeJsCodeException, IOException { + + return download(url, downloadedFile); + } + */ + + /** + * TODO + * Note that the url won't get loaded into the current window. + *

+ * public NodeWindow download(String url, File downloadedFile) throws NodeJsCodeException, IOException { + * String filePath = downloadedFile.getAbsolutePath().replace("\\", "/"); + * jsContext.executeJavaScript("downloadFile = '"+filePath+"';"); + * load(url); + * jsContext.executeJavaScript("downloadFile = null;"); + *

+ * jsContext.executeJavaScript("" + + * "" + + * "var buffer = await response.buffer();\n" + + * "fs.writeFileSync(\""+filePath+"\", buffer);"); + *

+ *

+ * return this; + * } + */ public HBrowser getParentBrowser() { return parentBrowser; diff --git a/src/test/java/com/osiris/headlessbrowser/NodeWindowTest.java b/src/test/java/com/osiris/headlessbrowser/NodeWindowTest.java index c8fe581..15796f5 100644 --- a/src/test/java/com/osiris/headlessbrowser/NodeWindowTest.java +++ b/src/test/java/com/osiris/headlessbrowser/NodeWindowTest.java @@ -10,6 +10,8 @@ public static void main(String[] args) throws Exception { window.load("https://github.com/Osiris-Team"); System.out.println(window.getBrowserType()); window.printCookiesAsJsonArray(); + //TODO window.download("https://github.com/Osiris-Team/AutoPlug-Releases/raw/master/stable-builds/AutoPlug-Client.jar", + // new File("AutoPlug-Client.jar")); } }