com.google.firebase.internal.AbstractHttpErrorHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of firebase-admin Show documentation
Show all versions of firebase-admin Show documentation
This is the official Firebase Admin Java SDK. Build extraordinary native JVM apps in
minutes with Firebase. The Firebase platform can power your app’s backend, user
authentication, static hosting, and more.
/*
* Copyright 2020 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.firebase.internal;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.http.HttpStatusCodes;
import com.google.common.collect.ImmutableMap;
import com.google.firebase.ErrorCode;
import com.google.firebase.FirebaseException;
import com.google.firebase.IncomingHttpResponse;
import java.io.IOException;
import java.net.NoRouteToHostException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* An abstract HttpErrorHandler implementation that maps HTTP status codes to Firebase error codes.
* Also provides reasonable default implementations to other error handler methods in the
* HttpErrorHandler interface.
*/
public abstract class AbstractHttpErrorHandler
implements HttpErrorHandler {
private static final Map HTTP_ERROR_CODES =
ImmutableMap.builder()
.put(HttpStatusCodes.STATUS_CODE_BAD_REQUEST, ErrorCode.INVALID_ARGUMENT)
.put(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED, ErrorCode.UNAUTHENTICATED)
.put(HttpStatusCodes.STATUS_CODE_FORBIDDEN, ErrorCode.PERMISSION_DENIED)
.put(HttpStatusCodes.STATUS_CODE_NOT_FOUND, ErrorCode.NOT_FOUND)
.put(HttpStatusCodes.STATUS_CODE_CONFLICT, ErrorCode.CONFLICT)
.put(429, ErrorCode.RESOURCE_EXHAUSTED)
.put(HttpStatusCodes.STATUS_CODE_SERVER_ERROR, ErrorCode.INTERNAL)
.put(HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE, ErrorCode.UNAVAILABLE)
.build();
@Override
public final T handleHttpResponseException(
HttpResponseException e, IncomingHttpResponse response) {
FirebaseException base = this.httpResponseErrorToBaseException(e, response);
return this.createException(base);
}
@Override
public final T handleIOException(IOException e) {
FirebaseException base = this.ioErrorToBaseException(e);
return this.createException(base);
}
@Override
public final T handleParseException(IOException e, IncomingHttpResponse response) {
FirebaseException base = this.parseErrorToBaseException(e, response);
return this.createException(base);
}
/**
* Creates a FirebaseException from the given HTTP response error. Error code is determined from
* the HTTP status code of the response. Error message includes both the status code and full
* response payload to aid in debugging.
*
* @param e HTTP response exception.
* @param response Incoming HTTP response.
* @return A FirebaseException instance.
*/
protected FirebaseException httpResponseErrorToBaseException(
HttpResponseException e, IncomingHttpResponse response) {
ErrorCode code = HTTP_ERROR_CODES.get(e.getStatusCode());
if (code == null) {
code = ErrorCode.UNKNOWN;
}
String message = String.format("Unexpected HTTP response with status: %d\n%s",
e.getStatusCode(), e.getContent());
return new FirebaseException(code, message, e, response);
}
/**
* Creates a FirebaseException from the given IOException. If IOException resulted from a socket
* timeout, sets the error code DEADLINE_EXCEEDED. If the IOException resulted from a network
* outage or other connectivity issue, sets the error code to UNAVAILABLE. In all other cases sets
* the error code to UNKNOWN.
*
* @param e IOException to create the new exception from.
* @return A FirebaseException instance.
*/
protected FirebaseException ioErrorToBaseException(IOException e) {
ErrorCode code = ErrorCode.UNKNOWN;
String message = "Unknown error while making a remote service call" ;
if (isInstance(e, SocketTimeoutException.class)) {
code = ErrorCode.DEADLINE_EXCEEDED;
message = "Timed out while making an API call";
}
if (isInstance(e, UnknownHostException.class) || isInstance(e, NoRouteToHostException.class)) {
code = ErrorCode.UNAVAILABLE;
message = "Failed to establish a connection";
}
return new FirebaseException(code, message + ": " + e.getMessage(), e);
}
protected FirebaseException parseErrorToBaseException(
IOException e, IncomingHttpResponse response) {
return new FirebaseException(
ErrorCode.UNKNOWN, "Error while parsing HTTP response: " + e.getMessage(), e, response);
}
/**
* Converts the given base FirebaseException to a more specific exception type. The base exception
* is guaranteed to have an error code, a message and a cause. But the HTTP response is only set
* if the exception occurred after receiving a response from a remote server.
*
* @param base A FirebaseException.
* @return A more specific exception created from the base.
*/
protected abstract T createException(FirebaseException base);
/**
* Checks if the given exception stack t contains an instance of type.
*/
private boolean isInstance(IOException t, Class type) {
Throwable current = t;
Set chain = new HashSet<>();
while (current != null) {
if (!chain.add(current)) {
break;
}
if (type.isInstance(current)) {
return true;
}
current = current.getCause();
}
return false;
}
}