Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ public static void setenv(String name, String value) {
public static void clearCache() {
localCache.clear();
}

public static void deleteEnv(String name) {
localCache.remove(name);
System.clearProperty(name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.google.firebase.internal.AbstractPlatformErrorHandler;
import com.google.firebase.internal.ApiClientUtils;
import com.google.firebase.internal.ErrorHandlingHttpClient;
import com.google.firebase.internal.FirebaseProcessEnvironment;
import com.google.firebase.internal.HttpRequestInfo;
import com.google.firebase.internal.SdkUtils;
import com.google.firebase.messaging.internal.MessagingServiceErrorResponse;
Expand All @@ -60,14 +61,18 @@
*/
final class FirebaseMessagingClientImpl implements FirebaseMessagingClient {

private static final String FCM_URL = "https://fcm.googleapis.com/v1/projects/%s/messages:send";
private static final String FCM_ROOT_URL = "https://fcm.googleapis.com";
private static final String FCM_SEND_PATH = "v1/projects/%s/messages:send";
private static final String FCM_BATCH_PATH = "batch";
private static final String GOOGLE_FCM_HOST = "GOOGLE_FCM_HOST";

private static final Map<String, String> COMMON_HEADERS =
ImmutableMap.of(
"X-GOOG-API-FORMAT-VERSION", "2",
"X-Firebase-Client", "fire-admin-java/" + SdkUtils.getVersion());

private final String fcmSendUrl;
private final String fcmBatchUrl;
private final HttpRequestFactory requestFactory;
private final HttpRequestFactory childRequestFactory;
private final JsonFactory jsonFactory;
Expand All @@ -78,22 +83,35 @@ final class FirebaseMessagingClientImpl implements FirebaseMessagingClient {

private FirebaseMessagingClientImpl(Builder builder) {
checkArgument(!Strings.isNullOrEmpty(builder.projectId));
this.fcmSendUrl = String.format(FCM_URL, builder.projectId);
String fcmRootUrl = FirebaseProcessEnvironment.getenv(GOOGLE_FCM_HOST);
if (Strings.isNullOrEmpty(fcmRootUrl)) {
fcmRootUrl = FCM_ROOT_URL;
}
this.fcmSendUrl = String.format(String.format(
"%s/%s", fcmRootUrl, FCM_SEND_PATH),
builder.projectId);
this.fcmBatchUrl = String.format("%s/%s", fcmRootUrl, FCM_BATCH_PATH);
this.requestFactory = checkNotNull(builder.requestFactory);
this.childRequestFactory = checkNotNull(builder.childRequestFactory);
this.jsonFactory = checkNotNull(builder.jsonFactory);
this.responseInterceptor = builder.responseInterceptor;
this.errorHandler = new MessagingErrorHandler(this.jsonFactory);
this.httpClient = new ErrorHandlingHttpClient<>(requestFactory, jsonFactory, errorHandler)
.setInterceptor(responseInterceptor);
this.batchClient = new MessagingBatchClient(requestFactory.getTransport(), jsonFactory);
this.batchClient = new MessagingBatchClient(requestFactory.getTransport(),
jsonFactory, fcmRootUrl);
}

@VisibleForTesting
String getFcmSendUrl() {
return fcmSendUrl;
}

@VisibleForTesting
String getFcmBatchUrl() {
return fcmBatchUrl;
}

@VisibleForTesting
HttpRequestFactory getRequestFactory() {
return requestFactory;
Expand Down Expand Up @@ -139,7 +157,7 @@ private BatchResponse sendBatchRequest(
return new BatchResponseImpl(callback.getResponses());
} catch (HttpResponseException e) {
OutgoingHttpRequest req = new OutgoingHttpRequest(
HttpMethods.POST, MessagingBatchClient.FCM_BATCH_URL);
HttpMethods.POST, fcmBatchUrl);
IncomingHttpResponse resp = new IncomingHttpResponse(e, req);
throw errorHandler.handleHttpResponseException(e, resp);
} catch (IOException e) {
Expand Down Expand Up @@ -319,22 +337,17 @@ private MessagingServiceErrorResponse safeParse(String response) {

private static class MessagingBatchClient extends AbstractGoogleJsonClient {

private static final String FCM_ROOT_URL = "https://fcm.googleapis.com";
private static final String FCM_BATCH_PATH = "batch";
private static final String FCM_BATCH_URL = String.format(
"%s/%s", FCM_ROOT_URL, FCM_BATCH_PATH);

MessagingBatchClient(HttpTransport transport, JsonFactory jsonFactory) {
super(new Builder(transport, jsonFactory));
MessagingBatchClient(HttpTransport transport, JsonFactory jsonFactory, String fcmRootUrl) {
super(new Builder(transport, jsonFactory, fcmRootUrl));
}

private MessagingBatchClient(Builder builder) {
super(builder);
}

private static class Builder extends AbstractGoogleJsonClient.Builder {
Builder(HttpTransport transport, JsonFactory jsonFactory) {
super(transport, jsonFactory, FCM_ROOT_URL, "", null, false);
Builder(HttpTransport transport, JsonFactory jsonFactory, String fcmRootUrl) {
super(transport, jsonFactory, fcmRootUrl, "", null, false);
setBatchPath(FCM_BATCH_PATH);
setApplicationName("fire-admin-java");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import com.google.firebase.OutgoingHttpRequest;
import com.google.firebase.auth.MockGoogleCredentials;
import com.google.firebase.internal.ApiClientUtils;
import com.google.firebase.internal.FirebaseProcessEnvironment;
import com.google.firebase.internal.SdkUtils;
import com.google.firebase.messaging.WebpushNotification.Action;
import com.google.firebase.messaging.WebpushNotification.Direction;
Expand Down Expand Up @@ -548,6 +549,36 @@ public void testFromApp() throws IOException {
}
}

@Test
public void testFromAppWithFcmUrlFromEnv() throws IOException {
FirebaseProcessEnvironment.setenv("GOOGLE_FCM_HOST", "https://test-host.com");
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(new MockGoogleCredentials("test-token"))
.setProjectId("test-project")
.build();
FirebaseApp app = FirebaseApp.initializeApp(options);

try {
FirebaseMessagingClientImpl client = FirebaseMessagingClientImpl.fromApp(app);
String expectedFcmSendUrl = "https://test-host.com/v1/projects/test-project/messages:send";
assertEquals(expectedFcmSendUrl, client.getFcmSendUrl());
String expectedFcmBatchUrl = "https://test-host.com/batch";
assertEquals(expectedFcmBatchUrl, client.getFcmBatchUrl());
assertSame(options.getJsonFactory(), client.getJsonFactory());

HttpRequest request = client.getRequestFactory().buildGetRequest(
new GenericUrl("https://example.com"));
assertEquals("Bearer test-token", request.getHeaders().getAuthorization());

request = client.getChildRequestFactory().buildGetRequest(
new GenericUrl("https://example.com"));
assertNull(request.getHeaders().getAuthorization());
} finally {
FirebaseProcessEnvironment.deleteEnv("GOOGLE_FCM_HOST");
app.delete();
}
}

private FirebaseMessagingClientImpl initMessagingClient(
MockLowLevelHttpResponse mockResponse, HttpResponseInterceptor interceptor) {
MockHttpTransport transport = new MockHttpTransport.Builder()
Expand Down