16
16
17
17
import static com .google .firebase .remoteconfig .FirebaseRemoteConfig .TAG ;
18
18
import static com .google .firebase .remoteconfig .RemoteConfigConstants .REALTIME_REGEX_URL ;
19
+ import static com .google .firebase .remoteconfig .internal .ConfigFetchHandler .HTTP_TOO_MANY_REQUESTS ;
19
20
20
21
import android .annotation .SuppressLint ;
21
22
import android .content .Context ;
@@ -236,7 +237,9 @@ private URL getUrl() {
236
237
return realtimeURL ;
237
238
}
238
239
239
- private HttpURLConnection createRealtimeConnection () throws IOException {
240
+ /** Create HTTP connection and set headers. */
241
+ @ SuppressLint ("VisibleForTests" )
242
+ public HttpURLConnection createRealtimeConnection () throws IOException {
240
243
URL realtimeUrl = getUrl ();
241
244
HttpURLConnection httpURLConnection = (HttpURLConnection ) realtimeUrl .openConnection ();
242
245
setCommonRequestHeaders (httpURLConnection );
@@ -245,8 +248,9 @@ private HttpURLConnection createRealtimeConnection() throws IOException {
245
248
return httpURLConnection ;
246
249
}
247
250
248
- // Try to reopen HTTP connection after a random amount of time
249
- private synchronized void retryHTTPConnection () {
251
+ /** Retries HTTP stream connection asyncly in random time intervals. */
252
+ @ SuppressLint ("VisibleForTests" )
253
+ public synchronized void retryHTTPConnection () {
250
254
if (canMakeHttpStreamConnection () && httpRetriesRemaining > 0 ) {
251
255
if (httpRetriesRemaining < ORIGINAL_RETRIES ) {
252
256
httpRetrySeconds *= getRetryMultiplier ();
@@ -273,7 +277,12 @@ synchronized void stopRealtime() {
273
277
scheduledExecutorService .shutdownNow ();
274
278
}
275
279
276
- private synchronized ConfigAutoFetch startAutoFetch (HttpURLConnection httpURLConnection ) {
280
+ /**
281
+ * Create Autofetch class that listens on HTTP stream for ConfigUpdate messages and calls Fetch
282
+ * accordingly.
283
+ */
284
+ @ SuppressLint ("VisibleForTests" )
285
+ public synchronized ConfigAutoFetch startAutoFetch (HttpURLConnection httpURLConnection ) {
277
286
ConfigUpdateListener retryCallback =
278
287
new ConfigUpdateListener () {
279
288
@ Override
@@ -298,6 +307,16 @@ public void onError(Exception error) {
298
307
return new ConfigAutoFetch (httpURLConnection , configFetchHandler , listeners , retryCallback );
299
308
}
300
309
310
+ // HTTP status code that the Realtime client should retry on.
311
+ private boolean isStatusCodeRetryable (int statusCode ) {
312
+ return statusCode == HttpURLConnection .HTTP_CLIENT_TIMEOUT
313
+ || statusCode == HTTP_TOO_MANY_REQUESTS
314
+ || statusCode == HttpURLConnection .HTTP_BAD_GATEWAY
315
+ || statusCode == HttpURLConnection .HTTP_UNAVAILABLE
316
+ || statusCode == HttpURLConnection .HTTP_GATEWAY_TIMEOUT
317
+ || statusCode == HttpURLConnection .HTTP_OK ;
318
+ }
319
+
301
320
/**
302
321
* Open the realtime connection, begin listening for updates, and auto-fetch when an update is
303
322
* received.
@@ -306,32 +325,42 @@ public void onError(Exception error) {
306
325
* chunk-encoded HTTP body. When the connection closes, it attempts to reestablish the stream.
307
326
*/
308
327
@ SuppressLint ("VisibleForTests" )
309
- synchronized void beginRealtimeHttpStream () {
328
+ public synchronized void beginRealtimeHttpStream () {
310
329
if (!canMakeHttpStreamConnection ()) {
311
330
return ;
312
331
}
313
332
333
+ int responseCode = 200 ;
314
334
try {
315
335
// Create the open the connection.
316
336
httpURLConnection = createRealtimeConnection ();
317
- httpURLConnection .connect ();
337
+ responseCode = httpURLConnection .getResponseCode ();
318
338
319
- // Reset the retries remaining if we opened the connection without an exception.
320
- resetRetryParameters ();
339
+ // If the connection returned a 200 response code, start listening for messages.
340
+ if (responseCode == HttpURLConnection .HTTP_OK ) {
341
+ // Reset the retries remaining if we opened the connection without an exception.
342
+ resetRetryParameters ();
321
343
322
- // Start listening for realtime notifications.
323
- ConfigAutoFetch configAutoFetch = startAutoFetch (httpURLConnection );
324
- configAutoFetch .listenForNotifications ();
344
+ // Start listening for realtime notifications.
345
+ ConfigAutoFetch configAutoFetch = startAutoFetch (httpURLConnection );
346
+ configAutoFetch .listenForNotifications ();
347
+ }
325
348
} catch (IOException e ) {
326
349
Log .d (TAG , "Exception connecting to realtime stream. Retrying the connection..." );
327
350
} finally {
328
351
closeRealtimeHttpStream ();
329
- retryHTTPConnection ();
352
+ if (isStatusCodeRetryable (responseCode )) {
353
+ retryHTTPConnection ();
354
+ } else {
355
+ propagateErrors (
356
+ new FirebaseRemoteConfigRealtimeUpdateStreamException (
357
+ "The server returned a status code that is not retryable. Realtime is shutting down." ));
358
+ }
330
359
}
331
360
}
332
361
333
362
// Pauses Http stream listening
334
- synchronized void closeRealtimeHttpStream () {
363
+ public synchronized void closeRealtimeHttpStream () {
335
364
if (httpURLConnection != null ) {
336
365
this .httpURLConnection .disconnect ();
337
366
0 commit comments