@@ -97,13 +97,15 @@ public class FirebaseInstallationServiceClient {
97
97
private static final String SDK_VERSION_PREFIX = "a:" ;
98
98
99
99
private static final String FIS_TAG = "Firebase-Installations" ;
100
+ private boolean shouldServerErrorRetry ;
100
101
101
102
@ VisibleForTesting
102
103
static final String PARSING_EXPIRATION_TIME_ERROR_MESSAGE = "Invalid Expiration Timestamp." ;
103
104
104
105
private final Context context ;
105
106
private final Provider <UserAgentPublisher > userAgentPublisher ;
106
107
private final Provider <HeartBeatInfo > heartbeatInfo ;
108
+ private final RequestLimiter requestLimiter ;
107
109
108
110
public FirebaseInstallationServiceClient (
109
111
@ NonNull Context context ,
@@ -112,6 +114,7 @@ public FirebaseInstallationServiceClient(
112
114
this .context = context ;
113
115
this .userAgentPublisher = publisher ;
114
116
this .heartbeatInfo = heartbeatInfo ;
117
+ this .requestLimiter = new RequestLimiter ();
115
118
}
116
119
117
120
/**
@@ -140,10 +143,16 @@ public InstallationResponse createFirebaseInstallation(
140
143
@ NonNull String appId ,
141
144
@ Nullable String iidToken )
142
145
throws FirebaseInstallationsException {
146
+ if (!requestLimiter .isRequestAllowed ()) {
147
+ throw new FirebaseInstallationsException (
148
+ "Firebase Installations Service is unavailable. Please try again later." ,
149
+ Status .UNAVAILABLE );
150
+ }
151
+
143
152
String resourceName = String .format (CREATE_REQUEST_RESOURCE_NAME_FORMAT , projectID );
144
- int retryCount = 0 ;
145
153
URL url = getFullyQualifiedRequestUri (resourceName );
146
- while (retryCount <= MAX_RETRIES ) {
154
+ for (int retryCount = 0 ; retryCount <= MAX_RETRIES ; retryCount ++) {
155
+
147
156
HttpURLConnection httpURLConnection = openHttpURLConnection (url , apiKey );
148
157
149
158
try {
@@ -158,15 +167,22 @@ public InstallationResponse createFirebaseInstallation(
158
167
writeFIDCreateRequestBodyToOutputStream (httpURLConnection , fid , appId );
159
168
160
169
int httpResponseCode = httpURLConnection .getResponseCode ();
170
+ requestLimiter .setNextRequestTime (httpResponseCode );
161
171
162
- if (httpResponseCode == 200 ) {
172
+ if (isSuccessfulResponseCode ( httpResponseCode ) ) {
163
173
return readCreateResponse (httpURLConnection );
164
174
}
165
175
166
176
logFisCommunicationError (httpURLConnection , appId , apiKey , projectID );
167
177
168
- if (httpResponseCode == 429 || (httpResponseCode >= 500 && httpResponseCode < 600 )) {
169
- retryCount ++;
178
+ if (httpResponseCode == 429 ) {
179
+ throw new FirebaseInstallationsException (
180
+ "Firebase servers have received too many requests from this client in a short "
181
+ + "period of time. Please try again later." ,
182
+ Status .TOO_MANY_REQUESTS );
183
+ }
184
+
185
+ if (httpResponseCode >= 500 && httpResponseCode < 600 ) {
170
186
continue ;
171
187
}
172
188
@@ -175,7 +191,7 @@ public InstallationResponse createFirebaseInstallation(
175
191
// Return empty installation response with BAD_CONFIG response code after max retries
176
192
return InstallationResponse .builder ().setResponseCode (ResponseCode .BAD_CONFIG ).build ();
177
193
} catch (AssertionError | IOException ignored ) {
178
- retryCount ++ ;
194
+ continue ;
179
195
} finally {
180
196
httpURLConnection .disconnect ();
181
197
}
@@ -363,11 +379,17 @@ public TokenResult generateAuthToken(
363
379
@ NonNull String projectID ,
364
380
@ NonNull String refreshToken )
365
381
throws FirebaseInstallationsException {
382
+ if (!requestLimiter .isRequestAllowed ()) {
383
+ throw new FirebaseInstallationsException (
384
+ "Firebase Installations Service is unavailable. Please try again later." ,
385
+ Status .UNAVAILABLE );
386
+ }
387
+
366
388
String resourceName =
367
389
String .format (GENERATE_AUTH_TOKEN_REQUEST_RESOURCE_NAME_FORMAT , projectID , fid );
368
- int retryCount = 0 ;
369
390
URL url = getFullyQualifiedRequestUri (resourceName );
370
- while (retryCount <= MAX_RETRIES ) {
391
+ for (int retryCount = 0 ; retryCount <= MAX_RETRIES ; retryCount ++) {
392
+
371
393
HttpURLConnection httpURLConnection = openHttpURLConnection (url , apiKey );
372
394
try {
373
395
httpURLConnection .setRequestMethod ("POST" );
@@ -377,8 +399,9 @@ public TokenResult generateAuthToken(
377
399
writeGenerateAuthTokenRequestBodyToOutputStream (httpURLConnection );
378
400
379
401
int httpResponseCode = httpURLConnection .getResponseCode ();
402
+ requestLimiter .setNextRequestTime (httpResponseCode );
380
403
381
- if (httpResponseCode == 200 ) {
404
+ if (isSuccessfulResponseCode ( httpResponseCode ) ) {
382
405
return readGenerateAuthTokenResponse (httpURLConnection );
383
406
}
384
407
@@ -388,8 +411,14 @@ public TokenResult generateAuthToken(
388
411
return TokenResult .builder ().setResponseCode (TokenResult .ResponseCode .AUTH_ERROR ).build ();
389
412
}
390
413
391
- if (httpResponseCode == 429 || (httpResponseCode >= 500 && httpResponseCode < 600 )) {
392
- retryCount ++;
414
+ if (httpResponseCode == 429 ) {
415
+ throw new FirebaseInstallationsException (
416
+ "Firebase servers have received too many requests from this client in a short "
417
+ + "period of time. Please try again later." ,
418
+ Status .TOO_MANY_REQUESTS );
419
+ }
420
+
421
+ if (httpResponseCode >= 500 && httpResponseCode < 600 ) {
393
422
continue ;
394
423
}
395
424
@@ -398,7 +427,7 @@ public TokenResult generateAuthToken(
398
427
return TokenResult .builder ().setResponseCode (TokenResult .ResponseCode .BAD_CONFIG ).build ();
399
428
// TODO(b/166168291): Remove code duplication and clean up this class.
400
429
} catch (AssertionError | IOException ignored ) {
401
- retryCount ++ ;
430
+ continue ;
402
431
} finally {
403
432
httpURLConnection .disconnect ();
404
433
}
@@ -408,6 +437,10 @@ public TokenResult generateAuthToken(
408
437
Status .UNAVAILABLE );
409
438
}
410
439
440
+ private static boolean isSuccessfulResponseCode (int responseCode ) {
441
+ return responseCode >= 200 && responseCode < 300 ;
442
+ }
443
+
411
444
private static void logBadConfigError () {
412
445
Log .e (
413
446
FIS_TAG ,
0 commit comments