From 5c05daf75cdc7497096b3fbadfaa4d4a073c893a Mon Sep 17 00:00:00 2001 From: amaanbs Date: Fri, 6 Jun 2025 05:26:51 +0530 Subject: [PATCH 1/4] change binary download distribution --- .../java/com/browserstack/local/Local.java | 4 +- .../com/browserstack/local/LocalBinary.java | 68 ++++++++++++++++--- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/browserstack/local/Local.java b/src/main/java/com/browserstack/local/Local.java index 7669007..6075b02 100644 --- a/src/main/java/com/browserstack/local/Local.java +++ b/src/main/java/com/browserstack/local/Local.java @@ -55,9 +55,9 @@ public void start(Map options) throws Exception { startOptions = options; LocalBinary lb; if (options.get("binarypath") != null) { - lb = new LocalBinary(options.get("binarypath")); + lb = new LocalBinary(options.get("binarypath"), options.get("key")); } else { - lb = new LocalBinary(""); + lb = new LocalBinary("", options.get("key")); } binaryPath = lb.getBinaryPath(); diff --git a/src/main/java/com/browserstack/local/LocalBinary.java b/src/main/java/com/browserstack/local/LocalBinary.java index 6b7a0fb..4dbd303 100644 --- a/src/main/java/com/browserstack/local/LocalBinary.java +++ b/src/main/java/com/browserstack/local/LocalBinary.java @@ -3,8 +3,11 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import org.json.JSONObject; + import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.File; @@ -15,14 +18,24 @@ import java.util.zip.GZIPInputStream; import java.util.zip.ZipException; +import java.lang.StringBuilder; + class LocalBinary { private static final String BIN_URL = "https://www.browserstack.com/local-testing/downloads/binaries/"; - private String httpPath; + private String binaryFileName; + + private String sourceUrl; private String binaryPath; + private Boolean fallbackEnabled = false; + + private Throwable downloadFailureThrowable = null; + + private String key; + private boolean isOSWindows; private final String orderedPaths[] = { @@ -31,7 +44,8 @@ class LocalBinary { System.getProperty("java.io.tmpdir") }; - LocalBinary(String path) throws LocalException { + LocalBinary(String path, String key) throws LocalException { + this.key = key; initialize(); if (path != "") { getBinaryOnPath(path); @@ -65,8 +79,7 @@ private void initialize() throws LocalException { throw new LocalException("Failed to detect OS type"); } - String sourceURL = BIN_URL; - httpPath = sourceURL + binFileName; + this.binaryFileName = binFileName; } private boolean isAlpine() { @@ -167,8 +180,40 @@ private boolean makePath(String path) { } } + private void fetchSourceUrl() { + URL url = new URL("https://local.browserstack.com/binary/api/v1/endpoint"); + URLConnection connection = url.openConnection(); + + connection.setDoOutput(true); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "browserstack-local-java/" + Local.getPackageVersion()); + connection.setRequestProperty("Accept", "application/json"); + if (fallbackEnabled) connection.setRequestProperty("X-Local-Fallback-Cloudflare", "true"); + + String jsonInput = "{\"auth_token\": " + key + (fallbackEnabled ? (", \"error_message\": " + downloadFailureThrowable.getMessage()) : "") + "}"; + + try (OutputStream os = connection.getOutputStream()) { + byte[] input = jsonInput.getBytes("utf-8"); + os.write(input, 0, input.length); + } + + try (InputStream is = connection.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"))) { + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line.trim()); + } + String responseBody = response.toString(); + JSONObject json = new JSONObject(responseBody); + this.sourceUrl = json.getJSONObject("data").getString("endpoint"); + } + } + private void downloadBinary(String destParentDir, Boolean custom) throws LocalException { try { + fetchSourceUrl(); + String source = destParentDir; if (!custom) { if (!new File(destParentDir).exists()) @@ -179,13 +224,20 @@ private void downloadBinary(String destParentDir, Boolean custom) throws LocalEx source += ".exe"; } } - URL url = new URL(httpPath); + URL url = new URL(sourceUrl + '/' + binaryFileName); File f = new File(source); - newCopyToFile(url, f); - + try { + newCopyToFile(url, f); + } catch (IOException e) { + if (fallbackEnabled) throw e; + /* Binary download failed due to a server error */ + fallbackEnabled = true; + downloadFailureThrowable = e; + downloadBinary(destParentDir, custom); + } changePermissions(binaryPath); - } catch (Exception e) { + } catch (Throwable e) { throw new LocalException("Error trying to download BrowserStackLocal binary: " + e.getMessage()); } } From 7094fd61114626fc337336e74fda1494cff0a929 Mon Sep 17 00:00:00 2001 From: amaanbs Date: Fri, 6 Jun 2025 06:21:19 +0530 Subject: [PATCH 2/4] fixes --- .../com/browserstack/local/LocalBinary.java | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/browserstack/local/LocalBinary.java b/src/main/java/com/browserstack/local/LocalBinary.java index 4dbd303..c6d5254 100644 --- a/src/main/java/com/browserstack/local/LocalBinary.java +++ b/src/main/java/com/browserstack/local/LocalBinary.java @@ -47,12 +47,23 @@ class LocalBinary { LocalBinary(String path, String key) throws LocalException { this.key = key; initialize(); - if (path != "") { - getBinaryOnPath(path); - } else { - getBinary(); + downloadAndVerifyBinary(path); + } + + private void downloadAndVerifyBinary(String path) throws LocalException { + try { + if (path != "") { + getBinaryOnPath(path); + } else { + getBinary(); + } + checkBinary(); + } catch (Throwable e) { + if (fallbackEnabled) throw e; + fallbackEnabled = true; + downloadFailureThrowable = e; + downloadAndVerifyBinary(path); } - checkBinary(); } private void initialize() throws LocalException { @@ -181,6 +192,11 @@ private boolean makePath(String path) { } private void fetchSourceUrl() { + if ((!fallbackEnabled && sourceUrl) || (fallbackEnabled && !downloadFailureThrowable)) { + /* Retry because binary (from any of the endpoints) validation failed */ + return; + } + URL url = new URL("https://local.browserstack.com/binary/api/v1/endpoint"); URLConnection connection = url.openConnection(); @@ -207,6 +223,7 @@ private void fetchSourceUrl() { String responseBody = response.toString(); JSONObject json = new JSONObject(responseBody); this.sourceUrl = json.getJSONObject("data").getString("endpoint"); + if(fallbackEnabled) downloadFailureThrowable = null; } } @@ -227,15 +244,8 @@ private void downloadBinary(String destParentDir, Boolean custom) throws LocalEx URL url = new URL(sourceUrl + '/' + binaryFileName); File f = new File(source); - try { - newCopyToFile(url, f); - } catch (IOException e) { - if (fallbackEnabled) throw e; - /* Binary download failed due to a server error */ - fallbackEnabled = true; - downloadFailureThrowable = e; - downloadBinary(destParentDir, custom); - } + newCopyToFile(url, f); + changePermissions(binaryPath); } catch (Throwable e) { throw new LocalException("Error trying to download BrowserStackLocal binary: " + e.getMessage()); From 3ad7fcef497968fd7e64d39641c6e152072f4db9 Mon Sep 17 00:00:00 2001 From: amaanbs Date: Tue, 10 Jun 2025 03:41:44 +0530 Subject: [PATCH 3/4] fixes --- .../java/com/browserstack/local/Local.java | 4 +- .../com/browserstack/local/LocalBinary.java | 69 +++++++++++-------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/browserstack/local/Local.java b/src/main/java/com/browserstack/local/Local.java index 6075b02..85f9827 100644 --- a/src/main/java/com/browserstack/local/Local.java +++ b/src/main/java/com/browserstack/local/Local.java @@ -109,9 +109,9 @@ public void stop() throws Exception { public void stop(Map options) throws Exception { LocalBinary lb; if (options.get("binarypath") != null) { - lb = new LocalBinary(options.get("binarypath")); + lb = new LocalBinary(options.get("binarypath"), options.get("key")); } else { - lb = new LocalBinary(""); + lb = new LocalBinary("", options.get("key")); } binaryPath = lb.getBinaryPath(); makeCommand(options, "stop"); diff --git a/src/main/java/com/browserstack/local/LocalBinary.java b/src/main/java/com/browserstack/local/LocalBinary.java index c6d5254..7b39183 100644 --- a/src/main/java/com/browserstack/local/LocalBinary.java +++ b/src/main/java/com/browserstack/local/LocalBinary.java @@ -60,6 +60,10 @@ private void downloadAndVerifyBinary(String path) throws LocalException { checkBinary(); } catch (Throwable e) { if (fallbackEnabled) throw e; + File binary_file = new File(binaryPath); + if (binary_file.exists()) { + binary_file.delete(); + } fallbackEnabled = true; downloadFailureThrowable = e; downloadAndVerifyBinary(path); @@ -191,39 +195,46 @@ private boolean makePath(String path) { } } - private void fetchSourceUrl() { - if ((!fallbackEnabled && sourceUrl) || (fallbackEnabled && !downloadFailureThrowable)) { + private void fetchSourceUrl() throws LocalException { + if ((!fallbackEnabled && sourceUrl != null) || (fallbackEnabled && downloadFailureThrowable == null)) { /* Retry because binary (from any of the endpoints) validation failed */ return; } - URL url = new URL("https://local.browserstack.com/binary/api/v1/endpoint"); - URLConnection connection = url.openConnection(); - - connection.setDoOutput(true); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("User-Agent", "browserstack-local-java/" + Local.getPackageVersion()); - connection.setRequestProperty("Accept", "application/json"); - if (fallbackEnabled) connection.setRequestProperty("X-Local-Fallback-Cloudflare", "true"); - - String jsonInput = "{\"auth_token\": " + key + (fallbackEnabled ? (", \"error_message\": " + downloadFailureThrowable.getMessage()) : "") + "}"; - - try (OutputStream os = connection.getOutputStream()) { - byte[] input = jsonInput.getBytes("utf-8"); - os.write(input, 0, input.length); - } - - try (InputStream is = connection.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"))) { - StringBuilder response = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - response.append(line.trim()); - } - String responseBody = response.toString(); - JSONObject json = new JSONObject(responseBody); - this.sourceUrl = json.getJSONObject("data").getString("endpoint"); - if(fallbackEnabled) downloadFailureThrowable = null; + try { + URL url = new URL("https://local.browserstack.com/binary/api/v1/endpoint"); + URLConnection connection = url.openConnection(); + + connection.setDoOutput(true); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "browserstack-local-java/" + Local.getPackageVersion()); + connection.setRequestProperty("Accept", "application/json"); + if (fallbackEnabled) connection.setRequestProperty("X-Local-Fallback-Cloudflare", "true"); + + String jsonInput = "{\"auth_token\": \"" + key + (fallbackEnabled ? ("\", \"error_message\": \"" + downloadFailureThrowable.getMessage()) + "\"" : "\"") + "}"; + + try (OutputStream os = connection.getOutputStream()) { + byte[] input = jsonInput.getBytes("utf-8"); + os.write(input, 0, input.length); + } + + try (InputStream is = connection.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"))) { + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line.trim()); + } + String responseBody = response.toString(); + JSONObject json = new JSONObject(responseBody); + if (json.has("error")) { + throw new Exception(json.getString("error")); + } + this.sourceUrl = json.getJSONObject("data").getString("endpoint"); + if(fallbackEnabled) downloadFailureThrowable = null; + } + } catch (Throwable e) { + throw new LocalException("Error trying to fetch the source URL: " + e.getMessage()); } } From 880af8dd85b677215dfe38941a9d70778cfcee31 Mon Sep 17 00:00:00 2001 From: amaanbs Date: Tue, 10 Jun 2025 03:45:43 +0530 Subject: [PATCH 4/4] fixes --- src/main/java/com/browserstack/local/LocalBinary.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/browserstack/local/LocalBinary.java b/src/main/java/com/browserstack/local/LocalBinary.java index 7b39183..e2f3f4b 100644 --- a/src/main/java/com/browserstack/local/LocalBinary.java +++ b/src/main/java/com/browserstack/local/LocalBinary.java @@ -22,8 +22,6 @@ class LocalBinary { - private static final String BIN_URL = "https://www.browserstack.com/local-testing/downloads/binaries/"; - private String binaryFileName; private String sourceUrl;