Logo Search packages:      
Sourcecode: jets3t version File versions  Download package

void org::jets3t::service::impl::rest::httpclient::RestS3Service::performRequest ( HttpMethodBase  httpMethod,
int[]  expectedResponseCodes 
) throws S3ServiceException [inline, protected]

Performs an HTTP/S request by invoking the provided HttpMethod object. If the HTTP response code doesn't match the expected value, an exception is thrown.

Parameters:
httpMethod the object containing a request target and all other information necessary to perform the request
expectedResponseCodes the HTTP response code(s) that indicates a successful request. If the response code received does not match this value an error must have occurred, so an exception is thrown.
Exceptions:
S3ServiceException all exceptions are wrapped in an S3ServiceException. Depending on the kind of error that occurred, this exception may contain additional error information available from an XML error response document.

Definition at line 341 of file RestS3Service.java.

References authorizeHttpRequest(), org::jets3t::service::Jets3tProperties::getIntProperty(), org::jets3t::service::S3ServiceException::getS3ErrorCode(), org::jets3t::service::S3ServiceException::isParsedFromXmlMessage(), isXmlContentType(), org::jets3t::service::S3ServiceException::setRequestHost(), org::jets3t::service::S3ServiceException::setRequestPath(), org::jets3t::service::S3ServiceException::setRequestVerb(), org::jets3t::service::S3ServiceException::setResponseCode(), org::jets3t::service::S3ServiceException::setResponseDate(), org::jets3t::service::S3ServiceException::setResponseHeaders(), org::jets3t::service::S3ServiceException::setResponseStatus(), org::jets3t::service::S3ServiceException::setS3RequestAndHostIds(), org::jets3t::service::S3Service::sleepOnInternalError(), and org::jets3t::service::S3Service::timeOffset.

Referenced by deleteObjectWithSignedUrl(), getObjectAclWithSignedUrl(), performRestDelete(), performRestGet(), performRestHead(), performRestPut(), putObjectAclWithSignedUrl(), and putObjectWithSignedUrl().

    {
        try {
            if (log.isDebugEnabled()) {
                log.debug("Performing " + httpMethod.getName()
                    + " request for '" + httpMethod.getURI().toString()
                    + "', expecting response codes: " +
                    "[" + ServiceUtils.join(expectedResponseCodes, ",") + "]");
            }

            // Variables to manage S3 Internal Server 500 or 503 Service Unavailable errors.
            boolean completedWithoutRecoverableError = true;
            int internalErrorCount = 0;
            int requestTimeoutErrorCount = 0;
            int redirectCount = 0;
            boolean wasRecentlyRedirected = false;

            // Perform the request, sleeping and retrying when S3 Internal Errors are encountered.
            int responseCode = -1;
            do {
                // Build the authorization string for the method (Unless we have just been redirected).
                if (!wasRecentlyRedirected) {
                    authorizeHttpRequest(httpMethod);
                } else {
                    // Reset redirection flag
                    wasRecentlyRedirected = false;
                }

                responseCode = httpClient.executeMethod(httpMethod);

                if (responseCode == 307) {
                    // Retry on Temporary Redirects, using new URI from location header
                    Header locationHeader = httpMethod.getResponseHeader("location");
                    httpMethod.setURI(new URI(locationHeader.getValue(), true));

                    completedWithoutRecoverableError = false;
                    redirectCount++;
                    wasRecentlyRedirected = true;

                    if (redirectCount > 5) {
                        throw new S3ServiceException("Exceeded 307 redirect limit (5).");
                    }
                } else if (responseCode == 500 || responseCode == 503) {
                    // Retry on S3 Internal Server 500 or 503 Service Unavailable errors.
                    completedWithoutRecoverableError = false;
                    sleepOnInternalError(++internalErrorCount);
                } else {
                    completedWithoutRecoverableError = true;
                }

                String contentType = "";
                if (httpMethod.getResponseHeader("Content-Type") != null) {
                    contentType = httpMethod.getResponseHeader("Content-Type").getValue();
                }

                if (log.isDebugEnabled()) {
                    log.debug("Response for '" + httpMethod.getPath()
                        + "'. Content-Type: " + contentType
                        + ", Headers: " + Arrays.asList(httpMethod.getResponseHeaders()));
                }

                // Check we received the expected result code.
                boolean didReceiveExpectedResponseCode = false;
                for (int i = 0; i < expectedResponseCodes.length && !didReceiveExpectedResponseCode; i++) {
                    if (responseCode == expectedResponseCodes[i]) {
                        didReceiveExpectedResponseCode = true;
                    }
                }

                if (!didReceiveExpectedResponseCode) {
                    if (log.isWarnEnabled()) {
                        String requestDescription =
                              httpMethod.getName()
                              + " '" + httpMethod.getPath() + "'"
                              + " -- ResponseCode: " + httpMethod.getStatusCode()
                              + ", ResponseStatus: " + httpMethod.getStatusText()
                              + ", Request Headers: [" + ServiceUtils.join(httpMethod.getRequestHeaders(), ", ") + "]"
                              + ", Response Headers: [" + ServiceUtils.join(httpMethod.getResponseHeaders(), ", ") + "]";
                        requestDescription = requestDescription.replaceAll("[\\n\\r\\f]", "");  // Remove any newlines.

                        log.warn("Error Response: " + requestDescription);
                    }

                    if (isXmlContentType(contentType)
                        && httpMethod.getResponseBodyAsStream() != null
                        && httpMethod.getResponseContentLength() != 0)
                    {
                        if (log.isDebugEnabled()) {
                            log.debug("Response '" + httpMethod.getPath()
                                + "' - Received error response with XML message");
                        }

                        StringBuffer sb = new StringBuffer();
                        BufferedReader reader = null;
                        try {
                            reader = new BufferedReader(new InputStreamReader(
                                new HttpMethodReleaseInputStream(httpMethod)));
                            String line = null;
                            while ((line = reader.readLine()) != null) {
                                sb.append(line + "\n");
                            }
                        } finally {
                            if (reader != null) {
                                reader.close();
                            }
                        }

                        httpMethod.releaseConnection();

                        // Throw exception containing the XML message document.
                        S3ServiceException exception =
                            new S3ServiceException("S3 Error Message.", sb.toString());

                        exception.setResponseHeaders(RestUtils.convertHeadersToMap(
                              httpMethod.getResponseHeaders()));

                        if ("RequestTimeout".equals(exception.getS3ErrorCode())) {
                            int retryMaxCount = jets3tProperties.getIntProperty("httpclient.retry-max", 5);

                            if (requestTimeoutErrorCount < retryMaxCount) {
                                requestTimeoutErrorCount++;
                                if (log.isWarnEnabled()) {
                                    log.warn("Retrying connection that failed with RequestTimeout error"
                                        + ", attempt number " + requestTimeoutErrorCount + " of "
                                        + retryMaxCount);
                                }
                                completedWithoutRecoverableError = false;
                            } else {
                                if (log.isErrorEnabled()) {
                                    log.error("Exceeded maximum number of retries for RequestTimeout errors: "
                                        + retryMaxCount);
                                }
                                throw exception;
                            }
                        } else if ("RequestTimeTooSkewed".equals(exception.getS3ErrorCode())) {
                            this.timeOffset = RestUtils.getAWSTimeAdjustment();
                            if (log.isWarnEnabled()) {
                                log.warn("Adjusted time offset in response to RequestTimeTooSkewed error. "
                                    + "Local machine and S3 server disagree on the time by approximately "
                                    + (this.timeOffset / 1000) + " seconds. Retrying connection.");
                            }
                            completedWithoutRecoverableError = false;
                        } else if (responseCode == 500 || responseCode == 503) {
                            // Retrying after 500 or 503 error, don't throw exception.
                        } else if (responseCode == 307) {
                            // Retrying after Temporary Redirect 307, don't throw exception.
                            if (log.isDebugEnabled()) {
                                log.debug("Following Temporary Redirect to: " + httpMethod.getURI().toString());
                            }
                        } else {
                            throw exception;
                        }
                    } else {
                        // Consume response content and release connection.
                        String responseText = null;
                        byte[] responseBody = httpMethod.getResponseBody();
                        if (responseBody != null && responseBody.length > 0) {
                            responseText = new String(responseBody);
                        }

                        if (log.isDebugEnabled()) {
                            log.debug("Releasing error response without XML content");
                        }
                        httpMethod.releaseConnection();

                        if (responseCode == 500 || responseCode == 503) {
                            // Retrying after InternalError 500, don't throw exception.
                        } else {
                            // Throw exception containing the HTTP error fields.
                            HttpException httpException = new HttpException(
                                    httpMethod.getStatusCode(), httpMethod.getStatusText());
                            S3ServiceException exception =
                                new S3ServiceException("Request Error"
                                    + (responseText != null ? " [" + responseText + "]." : "."),
                                    httpException);
                            exception.setResponseHeaders(RestUtils.convertHeadersToMap(
                                    httpMethod.getResponseHeaders()));
                            throw exception;
                        }
                    }
                }
            } while (!completedWithoutRecoverableError);

            // Release immediately any connections without response bodies.
            if ((httpMethod.getResponseBodyAsStream() == null
                || httpMethod.getResponseBodyAsStream().available() == 0)
                && httpMethod.getResponseContentLength() == 0)
            {
                if (log.isDebugEnabled()) {
                    log.debug("Releasing response without content");
                }
                byte[] responseBody = httpMethod.getResponseBody();

                if (responseBody != null && responseBody.length > 0)
                    throw new S3ServiceException("Oops, too keen to release connection with a non-empty response body");
                httpMethod.releaseConnection();
            }

        } catch (Throwable t) {
            if (log.isDebugEnabled()) {
                log.debug("Releasing HttpClient connection after error: " + t.getMessage());
            }
            httpMethod.releaseConnection();

            S3ServiceException s3ServiceException = null;
            if (t instanceof S3ServiceException) {
                s3ServiceException = (S3ServiceException) t;
            } else {
                MxDelegate.getInstance().registerS3ServiceExceptionEvent();
                s3ServiceException = new S3ServiceException("Request Error.", t);
            }

            // Add S3 request and host IDs from HTTP headers to exception, if they are available
            // and have not already been populated by parsing an XML error response.
            if (!s3ServiceException.isParsedFromXmlMessage()
                  && httpMethod.getResponseHeader(Constants.AMZ_REQUEST_ID_1) != null
                  && httpMethod.getResponseHeader(Constants.AMZ_REQUEST_ID_2) != null)
            {
                s3ServiceException.setS3RequestAndHostIds(
                  httpMethod.getResponseHeader(Constants.AMZ_REQUEST_ID_1).getValue(),
                  httpMethod.getResponseHeader(Constants.AMZ_REQUEST_ID_2).getValue());
            }
            s3ServiceException.setRequestVerb(httpMethod.getName());
            s3ServiceException.setRequestPath(httpMethod.getPath());
            try {
                s3ServiceException.setResponseCode(httpMethod.getStatusCode());
                s3ServiceException.setResponseStatus(httpMethod.getStatusText());
            } catch (NullPointerException e) {
                // If no network connection is available, status info is not available
            }
            if (httpMethod.getRequestHeader("Host") != null) {
                s3ServiceException.setRequestHost(
                        httpMethod.getRequestHeader("Host").getValue());
            }
            if (httpMethod.getResponseHeader("Date") != null) {
                s3ServiceException.setResponseDate(
                        httpMethod.getResponseHeader("Date").getValue());
            }
            throw s3ServiceException;
        }
    }


Generated by  Doxygen 1.6.0   Back to index