All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.qcloud.cos.internal.CosErrorResponseHandler Maven / Gradle / Ivy

There is a newer version: 5.6.238.2
Show newest version
/*
 * 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