33import org .apache .commons .io .FileUtils ;
44import org .apache .commons .io .IOUtils ;
55
6+ import org .json .JSONObject ;
7+
68import java .io .IOException ;
79import java .io .InputStream ;
10+ import java .io .OutputStream ;
811import java .io .BufferedReader ;
912import java .io .InputStreamReader ;
1013import java .io .File ;
1518import java .util .zip .GZIPInputStream ;
1619import java .util .zip .ZipException ;
1720
21+ import java .lang .StringBuilder ;
22+
1823class LocalBinary {
1924
2025 private static final String BIN_URL = "https://www.browserstack.com/local-testing/downloads/binaries/" ;
2126
22- private String httpPath ;
27+ private String binaryFileName ;
28+
29+ private String sourceUrl ;
2330
2431 private String binaryPath ;
2532
33+ private Boolean fallbackEnabled = false ;
34+
35+ private Throwable downloadFailureThrowable = null ;
36+
37+ private String key ;
38+
2639 private boolean isOSWindows ;
2740
2841 private final String orderedPaths [] = {
@@ -31,7 +44,8 @@ class LocalBinary {
3144 System .getProperty ("java.io.tmpdir" )
3245 };
3346
34- LocalBinary (String path ) throws LocalException {
47+ LocalBinary (String path , String key ) throws LocalException {
48+ this .key = key ;
3549 initialize ();
3650 if (path != "" ) {
3751 getBinaryOnPath (path );
@@ -65,8 +79,7 @@ private void initialize() throws LocalException {
6579 throw new LocalException ("Failed to detect OS type" );
6680 }
6781
68- String sourceURL = BIN_URL ;
69- httpPath = sourceURL + binFileName ;
82+ this .binaryFileName = binFileName ;
7083 }
7184
7285 private boolean isAlpine () {
@@ -167,8 +180,40 @@ private boolean makePath(String path) {
167180 }
168181 }
169182
183+ private void fetchSourceUrl () {
184+ URL url = new URL ("https://local.browserstack.com/binary/api/v1/endpoint" );
185+ URLConnection connection = url .openConnection ();
186+
187+ connection .setDoOutput (true );
188+ connection .setRequestProperty ("Content-Type" , "application/json" );
189+ connection .setRequestProperty ("User-Agent" , "browserstack-local-java/" + Local .getPackageVersion ());
190+ connection .setRequestProperty ("Accept" , "application/json" );
191+ if (fallbackEnabled ) connection .setRequestProperty ("X-Local-Fallback-Cloudflare" , "true" );
192+
193+ String jsonInput = "{\" auth_token\" : " + key + (fallbackEnabled ? (", \" error_message\" : " + downloadFailureThrowable .getMessage ()) : "" ) + "}" ;
194+
195+ try (OutputStream os = connection .getOutputStream ()) {
196+ byte [] input = jsonInput .getBytes ("utf-8" );
197+ os .write (input , 0 , input .length );
198+ }
199+
200+ try (InputStream is = connection .getInputStream ();
201+ BufferedReader reader = new BufferedReader (new InputStreamReader (is , "utf-8" ))) {
202+ StringBuilder response = new StringBuilder ();
203+ String line ;
204+ while ((line = reader .readLine ()) != null ) {
205+ response .append (line .trim ());
206+ }
207+ String responseBody = response .toString ();
208+ JSONObject json = new JSONObject (responseBody );
209+ this .sourceUrl = json .getJSONObject ("data" ).getString ("endpoint" );
210+ }
211+ }
212+
170213 private void downloadBinary (String destParentDir , Boolean custom ) throws LocalException {
171214 try {
215+ fetchSourceUrl ();
216+
172217 String source = destParentDir ;
173218 if (!custom ) {
174219 if (!new File (destParentDir ).exists ())
@@ -179,13 +224,20 @@ private void downloadBinary(String destParentDir, Boolean custom) throws LocalEx
179224 source += ".exe" ;
180225 }
181226 }
182- URL url = new URL (httpPath );
227+ URL url = new URL (sourceUrl + '/' + binaryFileName );
183228
184229 File f = new File (source );
185- newCopyToFile (url , f );
186-
230+ try {
231+ newCopyToFile (url , f );
232+ } catch (IOException e ) {
233+ if (fallbackEnabled ) throw e ;
234+ /* Binary download failed due to a server error */
235+ fallbackEnabled = true ;
236+ downloadFailureThrowable = e ;
237+ downloadBinary (destParentDir , custom );
238+ }
187239 changePermissions (binaryPath );
188- } catch (Exception e ) {
240+ } catch (Throwable e ) {
189241 throw new LocalException ("Error trying to download BrowserStackLocal binary: " + e .getMessage ());
190242 }
191243 }
0 commit comments