com.qcloud.cos.internal.CosErrorResponseHandler Maven / Gradle / Ivy
/*
* Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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.
* According to cos feature, we modify some class,comment, field name, etc.
*/
package com.qcloud.cos.internal;
import static com.qcloud.cos.utils.StringUtils.UTF8;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.qcloud.cos.Headers;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.exception.CosServiceExceptionBuilder;
import com.qcloud.cos.http.CosHttpResponse;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.http.HttpResponseHandler;
import com.qcloud.cos.utils.IOUtils;
public class CosErrorResponseHandler implements HttpResponseHandler {
private static final Logger log = LoggerFactory.getLogger(CosErrorResponseHandler.class);
/** Shared factory for creating XML event readers */
private static final XMLInputFactory xmlInputFactory = createXMLInputFactory();
private static XMLInputFactory createXMLInputFactory() {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
return inputFactory;
}
private static enum COSErrorTags {
Error, Code, Message, Resource, RequestId, TraceId;
};
private CosServiceException createExceptionFromHeaders(CosHttpResponse errorResponse,
String errorResponseXml) {
final Map headers = errorResponse.getHeaders();
final int statusCode = errorResponse.getStatusCode();
final CosServiceExceptionBuilder exceptionBuilder = new CosServiceExceptionBuilder();
exceptionBuilder.setErrorMessage(errorResponse.getStatusText());
exceptionBuilder.setErrorResponseXml(errorResponseXml);
exceptionBuilder.setStatusCode(statusCode);
exceptionBuilder.setTraceId(headers.get(Headers.TRACE_ID));
String requestId = headers.get(Headers.REQUEST_ID);
exceptionBuilder.setErrorCode(statusCode + " " + errorResponse.getStatusText());
if (requestId == null || requestId.isEmpty()) {
requestId = headers.get(Headers.CI_REQUEST_ID);
}
exceptionBuilder.setRequestId(requestId);
return exceptionBuilder.build();
}
@Override
public CosServiceException handle(CosHttpResponse httpResponse) throws XMLStreamException, IOException {
final InputStream is = httpResponse.getContent();
Map headers = httpResponse.getHeaders();
if ("application/json".equalsIgnoreCase(headers.get(Headers.CONTENT_TYPE))) {
return handleJsonErrorResponse(httpResponse, is);
} else {
return handleXmlErrorResponse(httpResponse, is);
}
}
private CosServiceException handleXmlErrorResponse(CosHttpResponse httpResponse, InputStream is) throws XMLStreamException {
String xmlContent = null;
/*
* We don't always get an error response body back from COS. When we send a HEAD request, we
* don't receive a body, so we'll have to just return what we can.
*/
if (is == null || httpResponse.getRequest().getHttpMethod() == HttpMethodName.HEAD) {
return createExceptionFromHeaders(httpResponse, null);
}
String content = null;
try {
content = IOUtils.toString(is);
} catch (IOException ioe) {
log.debug("Failed in parsing the error response : ", ioe);
return createExceptionFromHeaders(httpResponse, null);
}
XMLStreamReader reader;
synchronized (xmlInputFactory) {
reader = xmlInputFactory
.createXMLStreamReader(new ByteArrayInputStream(content.getBytes(UTF8)));
}
try {
/*
* target depth is to determine if the XML Error response from the server has any
* element inside tag have child tags. Parsing such tags is not supported now.
* target depth is incremented for every start tag and decremented after every end tag
* is encountered.
*/
int targetDepth = 0;
final CosServiceExceptionBuilder exceptionBuilder = new CosServiceExceptionBuilder();
exceptionBuilder.setErrorResponseXml(content);
exceptionBuilder.setStatusCode(httpResponse.getStatusCode());
boolean hasErrorTagVisited = false;
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamConstants.START_ELEMENT:
targetDepth++;
String tagName = reader.getLocalName();
if (targetDepth == 1 && !COSErrorTags.Error.toString().equals(tagName))
return createExceptionFromHeaders(httpResponse,
"Unable to parse error response. Error XML Not in proper format."
+ content);
if (COSErrorTags.Error.toString().equals(tagName)) {
hasErrorTagVisited = true;
}
continue;
case XMLStreamConstants.CHARACTERS:
xmlContent = reader.getText();
if (xmlContent != null)
xmlContent = xmlContent.trim();
continue;
case XMLStreamConstants.END_ELEMENT:
tagName = reader.getLocalName();
targetDepth--;
if (!(hasErrorTagVisited) || targetDepth > 1) {
return createExceptionFromHeaders(httpResponse,
"Unable to parse error response. Error XML Not in proper format."
+ content);
}
if (COSErrorTags.Message.toString().equals(tagName)) {
exceptionBuilder.setErrorMessage(xmlContent);
} else if (COSErrorTags.Code.toString().equals(tagName)) {
exceptionBuilder.setErrorCode(xmlContent);
} else if (COSErrorTags.RequestId.toString().equals(tagName)) {
exceptionBuilder.setRequestId(xmlContent);
} else if (COSErrorTags.TraceId.toString().equals(tagName)) {
exceptionBuilder.setTraceId(xmlContent);
} else {
exceptionBuilder.addAdditionalDetail(tagName, xmlContent);
}
continue;
case XMLStreamConstants.END_DOCUMENT:
return exceptionBuilder.build();
}
}
} catch (Exception e) {
log.debug("Failed in parsing the error response : " + content, e);
}
return createExceptionFromHeaders(httpResponse, content);
}
private CosServiceException handleJsonErrorResponse(CosHttpResponse httpResponse, InputStream is) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(is);
if(jsonNode.has("Message")){
httpResponse.setStatusText(jsonNode.get("Message").asText());
}
return createExceptionFromHeaders(httpResponse,null);
}
@Override
public boolean needsConnectionLeftOpen() {
return false;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy