in sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/HttpTransportClient.java [760:1043]
private Mono<StoreResponse> createErrorResponseFromHttpResponse(String resourceAddress, String activityId,
HttpRequest request,
HttpResponse response) {
int statusCode = response.statusCode();
Mono<String> errorMessageObs = ErrorUtils.getErrorResponseAsync(response, request);
return errorMessageObs.flatMap(
errorMessage -> {
long responseLSN = -1;
List<String> lsnValues = null;
String[] headerValues = response.headers().values(WFConstants.BackendHeaders.LSN);
if (headerValues != null) {
lsnValues = com.azure.cosmos.implementation.guava25.collect.Lists.newArrayList(headerValues);
}
if (lsnValues != null) {
String temp = lsnValues.isEmpty() ? null : lsnValues.get(0);
responseLSN = Longs.tryParse(temp, responseLSN);
}
String responsePartitionKeyRangeId = null;
List<String> partitionKeyRangeIdValues = null;
headerValues = response.headers().values(WFConstants.BackendHeaders.PARTITION_KEY_RANGE_ID);
if (headerValues != null) {
partitionKeyRangeIdValues
= com.azure.cosmos.implementation.guava25.collect.Lists.newArrayList(headerValues);
}
if (partitionKeyRangeIdValues != null) {
responsePartitionKeyRangeId = Lists.firstOrDefault(partitionKeyRangeIdValues, null);
}
CosmosException exception;
switch (statusCode) {
case HttpConstants.StatusCodes.UNAUTHORIZED:
exception = new UnauthorizedException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.Unauthorized : errorMessage),
response.headers(),
request.uri());
break;
case HttpConstants.StatusCodes.FORBIDDEN:
exception = new ForbiddenException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.Forbidden : errorMessage),
response.headers(),
request.uri());
break;
case HttpConstants.StatusCodes.NOTFOUND:
// HTTP.SYS returns NotFound (404) if the URI
// is not registered. This is really an indication that
// the replica which registered the URI is not
// available at the server. We detect this case by
// the presence of Content-Type header in the response
// and map it to HTTP Gone (410), which is the more
// appropriate response for this case.
if (response.body() != null && response.headers() != null && response.headers().value(HttpConstants.HttpHeaders.CONTENT_TYPE) != null &&
!Strings.isNullOrEmpty(response.headers().value(HttpConstants.HttpHeaders.CONTENT_TYPE)) &&
Strings.containsIgnoreCase(response.headers().value(HttpConstants.HttpHeaders.CONTENT_TYPE), RuntimeConstants.MediaTypes.TEXT_HTML)) {
// Have the request URL in the exception message for debugging purposes.
exception = new GoneException(
String.format(
RMResources.ExceptionMessage,
RMResources.Gone),
request.uri().toString(),
HttpConstants.SubStatusCodes.UNKNOWN);
exception.getResponseHeaders().put(HttpConstants.HttpHeaders.ACTIVITY_ID,
activityId);
break;
} else {
exception = new NotFoundException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.NotFound : errorMessage),
response.headers(),
request.uri());
break;
}
case HttpConstants.StatusCodes.BADREQUEST:
exception = new BadRequestException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.BadRequest : errorMessage),
response.headers(),
request.uri());
break;
case HttpConstants.StatusCodes.METHOD_NOT_ALLOWED:
exception = new MethodNotAllowedException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.MethodNotAllowed : errorMessage),
null,
response.headers(),
request.uri().toString());
break;
case HttpConstants.StatusCodes.GONE: {
// TODO: update perf counter
// https://msdata.visualstudio.com/CosmosDB/_workitems/edit/258624
ErrorUtils.logGoneException(request.uri(), activityId);
Integer nSubStatus = getSubStatusCodeFromHeader(response);
if (nSubStatus == HttpConstants.SubStatusCodes.NAME_CACHE_IS_STALE) {
exception = new InvalidPartitionException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.Gone : errorMessage),
response.headers(),
request.uri().toString());
break;
} else if (nSubStatus == HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE) {
exception = new PartitionKeyRangeGoneException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.Gone : errorMessage),
response.headers(),
request.uri().toString());
break;
} else if (nSubStatus == HttpConstants.SubStatusCodes.COMPLETING_SPLIT_OR_MERGE) {
exception = new PartitionKeyRangeIsSplittingException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.Gone : errorMessage),
response.headers(),
request.uri().toString());
break;
} else if (nSubStatus == HttpConstants.SubStatusCodes.COMPLETING_PARTITION_MIGRATION) {
exception = new PartitionIsMigratingException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.Gone : errorMessage),
response.headers(),
request.uri().toString());
break;
} else {
// Have the request URL in the exception message for debugging purposes.
GoneException goneExceptionFromService = new GoneException(
String.format(
RMResources.ExceptionMessage,
RMResources.Gone),
response.headers(),
request.uri(),
(nSubStatus == 0) ? HttpConstants.SubStatusCodes.TRANSPORT_GENERATED_410
: HttpConstants.SubStatusCodes.UNKNOWN);
goneExceptionFromService.setIsBasedOn410ResponseFromService();
goneExceptionFromService.getResponseHeaders().put(
HttpConstants.HttpHeaders.ACTIVITY_ID,
activityId);
exception = goneExceptionFromService;
break;
}
}
case HttpConstants.StatusCodes.CONFLICT:
exception = new ConflictException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.EntityAlreadyExists : errorMessage),
response.headers(),
request.uri().toString());
break;
case HttpConstants.StatusCodes.PRECONDITION_FAILED:
exception = new PreconditionFailedException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.PreconditionFailed : errorMessage),
response.headers(),
request.uri().toString());
break;
case HttpConstants.StatusCodes.REQUEST_ENTITY_TOO_LARGE:
exception = new RequestEntityTooLargeException(
String.format(
RMResources.ExceptionMessage,
String.format(
RMResources.RequestEntityTooLarge,
HttpConstants.HttpHeaders.PAGE_SIZE)),
response.headers(),
request.uri().toString());
break;
case HttpConstants.StatusCodes.LOCKED:
exception = new LockedException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.Locked : errorMessage),
response.headers(),
request.uri().toString());
break;
case HttpConstants.StatusCodes.SERVICE_UNAVAILABLE:
int subStatusCode = getSubStatusCodeFromHeader(response);
exception = new ServiceUnavailableException(errorMessage, response.headers(), request.uri(),
(subStatusCode == 0) ? HttpConstants.SubStatusCodes.SERVER_GENERATED_503
: HttpConstants.SubStatusCodes.UNKNOWN);
break;
case HttpConstants.StatusCodes.REQUEST_TIMEOUT:
exception = new RequestTimeoutException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.RequestTimeout : errorMessage),
response.headers(),
request.uri());
break;
case HttpConstants.StatusCodes.RETRY_WITH:
exception = new RetryWithException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.RetryWith : errorMessage),
response.headers(),
request.uri());
break;
case HttpConstants.StatusCodes.TOO_MANY_REQUESTS:
exception =
new RequestRateTooLargeException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.TooManyRequests : errorMessage),
response.headers(),
request.uri());
List<String> values = null;
headerValues = response.headers().values(HttpConstants.HttpHeaders.RETRY_AFTER_IN_MILLISECONDS);
if (headerValues != null) {
values
= com.azure.cosmos.implementation.guava25.collect.Lists.newArrayList(headerValues);
}
if (values == null || values.isEmpty()) {
logger.warn("RequestRateTooLargeException being thrown without RetryAfter.");
} else {
exception.getResponseHeaders().put(HttpConstants.HttpHeaders.RETRY_AFTER_IN_MILLISECONDS, values.get(0));
}
break;
case HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR:
exception = new InternalServerErrorException(
String.format(
RMResources.ExceptionMessage,
Strings.isNullOrEmpty(errorMessage) ? RMResources.InternalServerError : errorMessage),
response.headers(),
request.uri(),
HttpConstants.SubStatusCodes.UNKNOWN);
break;
default:
logger.error("Unrecognized status code {} returned by backend. ActivityId {}", statusCode, activityId);
ErrorUtils.logException(request.uri(), activityId);
exception = new InternalServerErrorException(
Exceptions.getInternalServerErrorMessage(
String.format(
RMResources.ExceptionMessage,
RMResources.InvalidBackendResponse)),
response.headers(),
request.uri(),
HttpConstants.SubStatusCodes.INVALID_BACKEND_RESPONSE);
break;
}
BridgeInternal.setLSN(exception, responseLSN);
BridgeInternal.setPartitionKeyRangeId(exception, responsePartitionKeyRangeId);
BridgeInternal.setResourceAddress(exception, resourceAddress);
BridgeInternal.setRequestHeaders(exception, HttpUtils.asMap(request.headers()));
return Mono.error(exception);
}
);
}