| /* | |
| * Copyright 2011-2018 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. | |
| * You may obtain a copy of the License at: | |
| * | |
| * http://aws.amazon.com/apache2.0 | |
| * | |
| * 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. | |
| */ | |
| package com.amazonaws.internal; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.io.InputStreamReader; | |
| import java.io.Reader; | |
| import java.net.HttpURLConnection; | |
| import java.net.URI; | |
| import java.util.HashMap; | |
| import java.util.Map; | |
| import com.google.common.base.Charsets; | |
| import com.google.common.io.CharStreams; | |
| import com.google.common.io.Closeables; | |
| import com.google.gson.JsonElement; | |
| import com.google.gson.JsonObject; | |
| import com.google.gson.JsonParser; | |
| import org.apache.commons.logging.Log; | |
| import org.apache.commons.logging.LogFactory; | |
| import com.amazonaws.SdkClientException; | |
| import com.amazonaws.AmazonServiceException; | |
| import com.amazonaws.annotation.SdkInternalApi; | |
| import com.amazonaws.retry.internal.CredentialsEndpointRetryParameters; | |
| import com.amazonaws.retry.internal.CredentialsEndpointRetryPolicy; | |
| @SdkInternalApi | |
| public final class EC2CredentialsUtils { | |
| private static final Log LOG = LogFactory.getLog(EC2CredentialsUtils.class); | |
| private static EC2CredentialsUtils instance; | |
| private final ConnectionUtils connectionUtils; | |
| private EC2CredentialsUtils() { | |
| this(ConnectionUtils.getInstance()); | |
| } | |
| EC2CredentialsUtils(ConnectionUtils connectionUtils) { | |
| this.connectionUtils = connectionUtils; | |
| } | |
| public static EC2CredentialsUtils getInstance() { | |
| if (instance == null) { | |
| instance = new EC2CredentialsUtils(); | |
| } | |
| return instance; | |
| } | |
| /** | |
| * Connects to the given endpoint to read the resource | |
| * and returns the text contents. | |
| * | |
| * If the connection fails, the request will not be retried. | |
| * | |
| * @param endpoint | |
| * The service endpoint to connect to. | |
| * | |
| * @return The text payload returned from the Amazon EC2 endpoint | |
| * service for the specified resource path. | |
| * | |
| * @throws IOException | |
| * If any problems were encountered while connecting to the | |
| * service for the requested resource path. | |
| * @throws SdkClientException | |
| * If the requested service is not found. | |
| */ | |
| public String readResource(URI endpoint) throws IOException { | |
| return readResource(endpoint, CredentialsEndpointRetryPolicy.NO_RETRY, new HashMap<String, String>()); | |
| } | |
| /** | |
| * Connects to the given endpoint to read the resource | |
| * and returns the text contents. | |
| * | |
| * @param endpoint | |
| * The service endpoint to connect to. | |
| * | |
| * @param retryPolicy | |
| * The custom retry policy that determines whether a | |
| * failed request should be retried or not. | |
| * | |
| * @return The text payload returned from the Amazon EC2 endpoint | |
| * service for the specified resource path. | |
| * | |
| * @throws IOException | |
| * If any problems were encountered while connecting to the | |
| * service for the requested resource path. | |
| * @throws SdkClientException | |
| * If the requested service is not found. | |
| */ | |
| public String readResource(URI endpoint, CredentialsEndpointRetryPolicy retryPolicy, Map<String, String> headers) throws IOException { | |
| int retriesAttempted = 0; | |
| InputStream inputStream = null; | |
| while (true) { | |
| try { | |
| HttpURLConnection connection = connectionUtils.connectToEndpoint(endpoint, headers); | |
| int statusCode = connection.getResponseCode(); | |
| if (statusCode == HttpURLConnection.HTTP_OK) { | |
| inputStream = connection.getInputStream(); | |
| try (Reader successReader = new InputStreamReader(inputStream, Charsets.UTF_8)) { | |
| return CharStreams.toString(successReader); | |
| } | |
| } else if (statusCode == HttpURLConnection.HTTP_NOT_FOUND) { | |
| // This is to preserve existing behavior of EC2 Instance metadata service. | |
| throw new SdkClientException("The requested metadata is not found at " + connection.getURL()); | |
| } else { | |
| if (!retryPolicy.shouldRetry(retriesAttempted++, CredentialsEndpointRetryParameters.builder().withStatusCode(statusCode).build())) { | |
| inputStream = connection.getErrorStream(); | |
| handleErrorResponse(inputStream, statusCode, connection.getResponseMessage()); | |
| } | |
| } | |
| } catch (IOException ioException) { | |
| if (!retryPolicy.shouldRetry(retriesAttempted++, CredentialsEndpointRetryParameters.builder().withException(ioException).build())) { | |
| throw ioException; | |
| } | |
| LOG.debug("An IOException occured when connecting to service endpoint: " + endpoint + "\n Retrying to connect again."); | |
| } finally { | |
| Closeables.closeQuietly(inputStream); | |
| } | |
| } | |
| } | |
| private void handleErrorResponse(InputStream errorStream, int statusCode, String responseMessage) throws IOException { | |
| String errorCode = null; | |
| // Parse the error stream returned from the service. | |
| if(errorStream != null) { | |
| try (Reader errorReader = new InputStreamReader(errorStream, Charsets.UTF_8)) { | |
| String errorResponse = CharStreams.toString(errorReader); | |
| JsonParser parser = new JsonParser(); | |
| JsonObject node = parser.parse(errorResponse).getAsJsonObject(); | |
| JsonElement code = node.get("code"); | |
| JsonElement message = node.get("message"); | |
| if (code != null && message != null) { | |
| errorCode = code.getAsString(); | |
| responseMessage = message.getAsString(); | |
| } | |
| } catch (Exception exception) { | |
| LOG.debug("Unable to parse error stream"); | |
| } | |
| } | |
| AmazonServiceException ase = new AmazonServiceException(responseMessage); | |
| ase.setStatusCode(statusCode); | |
| ase.setErrorCode(errorCode); | |
| throw ase; | |
| } | |
| } |