Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/main/java/com/browserstack/local/Local.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ public void start(Map<String, String> 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();

Expand Down Expand Up @@ -109,9 +109,9 @@ public void stop() throws Exception {
public void stop(Map<String, String> 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");
Expand Down
95 changes: 83 additions & 12 deletions src/main/java/com/browserstack/local/LocalBinary.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -15,14 +18,22 @@
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 binaryFileName;

private String httpPath;
private String sourceUrl;

private String binaryPath;

private Boolean fallbackEnabled = false;

private Throwable downloadFailureThrowable = null;

private String key;

private boolean isOSWindows;

private final String orderedPaths[] = {
Expand All @@ -31,14 +42,30 @@ 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);
} 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;
File binary_file = new File(binaryPath);
if (binary_file.exists()) {
binary_file.delete();
}
fallbackEnabled = true;
downloadFailureThrowable = e;
downloadAndVerifyBinary(path);
}
checkBinary();
}

private void initialize() throws LocalException {
Expand All @@ -65,8 +92,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() {
Expand Down Expand Up @@ -167,8 +193,53 @@ private boolean makePath(String path) {
}
}

private void fetchSourceUrl() throws LocalException {
if ((!fallbackEnabled && sourceUrl != null) || (fallbackEnabled && downloadFailureThrowable == null)) {
/* Retry because binary (from any of the endpoints) validation failed */
return;
}

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());
}
}

private void downloadBinary(String destParentDir, Boolean custom) throws LocalException {
try {
fetchSourceUrl();

String source = destParentDir;
if (!custom) {
if (!new File(destParentDir).exists())
Expand All @@ -179,13 +250,13 @@ 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);

changePermissions(binaryPath);
} catch (Exception e) {
} catch (Throwable e) {
throw new LocalException("Error trying to download BrowserStackLocal binary: " + e.getMessage());
}
}
Expand Down