private String urlEncodeTags(ObjectTagging tagging) { if (tagging == null || tagging.getTagSet() == null) return null; StringBuilder sb = new StringBuilder(); Iterator<Tag> tagIter = tagging.getTagSet().iterator(); while (tagIter.hasNext()) { Tag tag = tagIter.next(); sb.append(SdkHttpUtils.urlEncode(tag.getKey(), false)).append('=').append(SdkHttpUtils.urlEncode(tag.getValue(), false)); if (tagIter.hasNext()) { sb.append("&"); } } return sb.toString(); }
/** * Set the request's endpoint and resource path with the new region provided * * @param request Request to set endpoint for * @param regionString New region to determine endpoint to hit */ public void resolveRequestEndpoint(Request<?> request, String regionString) { if (regionString != null) { final Region r = RegionUtils.getRegion(regionString); if (r == null) { throw new SdkClientException("Not able to determine region" + " for " + regionString + ".Please upgrade to a newer " + "version of the SDK"); } endpointBuilder.withRegion(r); } final URI endpoint = endpointBuilder.getServiceEndpoint(); if (shouldUseVirtualAddressing(endpoint)) { request.setEndpoint(convertToVirtualHostEndpoint(endpoint, bucketName)); request.setResourcePath(SdkHttpUtils.urlEncode(getHostStyleResourcePath(), true)); } else { request.setEndpoint(endpoint); if (bucketName != null) { request.setResourcePath(SdkHttpUtils.urlEncode(getPathStyleResourcePath(), true)); } } }
public Request apply(SignableRequest<?> signableRequest) { Multimap<String, String> headers = ArrayListMultimap.create(Multimaps.forMap(signableRequest.getHeaders())); headers.put(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); return new RequestBuilder() .setMethod(signableRequest.getHttpMethod().name()) .setUrl(signableRequest.getEndpoint().resolve(signableRequest.getResourcePath()).toString()) .setHeaders(headers.asMap()) .setBody(SdkHttpUtils.encodeParameters(signableRequest)) .build(); }
@Override public String marshall(String resourcePath, String paramName, String pathValue) { if (pathValue != null && pathValue.isEmpty()) { throw new IllegalArgumentException(paramName + " must not be empty. If not set a value will be auto generated"); } return resourcePath.replace(String.format("{%s}", paramName), SdkHttpUtils.urlEncode(IdempotentUtils.resolveString(pathValue), false)); }
@Override public HttpRequestBase create(final Request<?> request, final HttpClientSettings settings) throws FakeIOException { URI endpoint = request.getEndpoint(); /* * HttpClient cannot handle url in pattern of "http://host//path", so we * have to escape the double-slash between endpoint and resource-path * into "/%2F" */ String uri = SdkHttpUtils.appendUri(endpoint.toString(), request .getResourcePath(), true); String encodedParams = SdkHttpUtils.encodeParameters(request); /* * For all non-POST requests, and any POST requests that already have a * payload, we put the encoded params directly in the URI, otherwise, * we'll put them in the POST request's payload. */ boolean requestHasNoPayload = request.getContent() != null; boolean requestIsPost = request.getHttpMethod() == HttpMethodName.POST; boolean putParamsInUri = !requestIsPost || requestHasNoPayload; if (encodedParams != null && putParamsInUri) { uri += "?" + encodedParams; } final HttpRequestBase base = createApacheRequest(request, uri, encodedParams); addHeadersToRequest(base, request); addRequestConfig(base, request, settings); return base; }
private String getHostHeaderValue(final URI endpoint) { /* * Apache HttpClient omits the port number in the Host header (even if * we explicitly specify it) if it's the default port for the protocol * in use. To ensure that we use the same Host header in the request and * in the calculated string to sign (even if Apache HttpClient changed * and started honoring our explicit host with endpoint), we follow this * same behavior here and in the QueryString signer. */ return SdkHttpUtils.isUsingNonDefaultPort(endpoint) ? endpoint.getHost() + ":" + endpoint.getPort() : endpoint.getHost(); }
/** * Step 1 of the AWS Signature version 4 calculation. Refer to * http://docs.aws * .amazon.com/general/latest/gr/sigv4-create-canonical-request.html to * generate the canonical request. */ protected String createCanonicalRequest(SignableRequest<?> request, String contentSha256) { /* This would url-encode the resource path for the first time. */ final String path = SdkHttpUtils.appendUri( request.getEndpoint().getPath(), request.getResourcePath()); final StringBuilder canonicalRequestBuilder = new StringBuilder(request .getHttpMethod().toString()); canonicalRequestBuilder.append(LINE_SEPARATOR) // This would optionally double url-encode the resource path .append(getCanonicalizedResourcePath(path, doubleUrlEncode)) .append(LINE_SEPARATOR) .append(getCanonicalizedQueryString(request)) .append(LINE_SEPARATOR) .append(getCanonicalizedHeaderString(request)) .append(LINE_SEPARATOR) .append(getSignedHeadersString(request)).append(LINE_SEPARATOR) .append(contentSha256); final String canonicalRequest = canonicalRequestBuilder.toString(); if (log.isDebugEnabled()) log.debug("AWS4 Canonical Requests: '\"" + canonicalRequest + "\""); return canonicalRequest; }
protected void addHostHeader(SignableRequest<?> request) { // AWS4 requires that we sign the Host header so we // have to have it in the request by the time we sign. final URI endpoint = request.getEndpoint(); final StringBuilder hostHeaderBuilder = new StringBuilder( endpoint.getHost()); if (SdkHttpUtils.isUsingNonDefaultPort(endpoint)) { hostHeaderBuilder.append(":").append(endpoint.getPort()); } request.addHeader(HOST, hostHeaderBuilder.toString()); }
protected String getCanonicalizedQueryString(SignableRequest<?> request) { /* * If we're using POST and we don't have any request payload content, * then any request query parameters will be sent as the payload, and * not in the actual query string. */ if (SdkHttpUtils.usePayloadForQueryParameters(request)) return ""; return this.getCanonicalizedQueryString(request.getParameters()); }
/** * Returns the request's payload as binary data. * * @param request * The request * @return The data from the request's payload, as binary data. */ protected byte[] getBinaryRequestPayload(SignableRequest<?> request) { if (SdkHttpUtils.usePayloadForQueryParameters(request)) { String encodedParameters = SdkHttpUtils.encodeParameters(request); if (encodedParameters == null) return new byte[0]; return encodedParameters.getBytes(UTF8); } return getBinaryRequestPayloadWithoutQueryParams(request); }
protected InputStream getBinaryRequestPayloadStream(SignableRequest<?> request) { if (SdkHttpUtils.usePayloadForQueryParameters(request)) { String encodedParameters = SdkHttpUtils.encodeParameters(request); if (encodedParameters == null) return new ByteArrayInputStream(new byte[0]); return new ByteArrayInputStream( encodedParameters.getBytes(UTF8)); } return getBinaryRequestPayloadStreamWithoutQueryParams(request); }
protected String getCanonicalizedResourcePath(String resourcePath, boolean urlEncode) { if (resourcePath == null || resourcePath.isEmpty()) { return "/"; } else { String value = urlEncode ? SdkHttpUtils.urlEncode(resourcePath, true) : resourcePath; if (value.startsWith("/")) { return value; } else { return "/".concat(value); } } }
protected String getCanonicalizedEndpoint(URI endpoint) { String endpointForStringToSign = StringUtils.lowerCase(endpoint.getHost()); /* * Apache HttpClient will omit the port in the Host header for default * port values (i.e. 80 for HTTP and 443 for HTTPS) even if we * explicitly specify it, so we need to be careful that we use the same * value here when we calculate the string to sign and in the Host * header we send in the HTTP request. */ if (SdkHttpUtils.isUsingNonDefaultPort(endpoint)) { endpointForStringToSign += ":" + endpoint.getPort(); } return endpointForStringToSign; }
/** * Pre-signs the specified request, using a signature query-string * parameter. * * @param request * The request to sign. * @param methodName * The HTTP method (GET, PUT, DELETE, HEAD) for the specified * request. * @param bucketName * The name of the bucket involved in the request. If the request * is not an operation on a bucket this parameter should be null. * @param key * The object key involved in the request. If the request is not * an operation on an object, this parameter should be null. * @param expiration * The time at which the signed request is no longer valid, and * will stop working. * @param subResource * The optional sub-resource being requested as part of the * request (e.g. "location", "acl", "logging", or "torrent"). */ protected <T> void presignRequest(Request<T> request, HttpMethod methodName, String bucketName, String key, Date expiration, String subResource) { // Run any additional request handlers if present beforeRequest(request); String resourcePath = "/" + ((bucketName != null) ? bucketName + "/" : "") + ((key != null) ? SdkHttpUtils.urlEncode(key, true) : "") + ((subResource != null) ? "?" + subResource : ""); // Make sure the resource-path for signing does not contain // any consecutive "/"s. // Note that we should also follow the same rule to escape // consecutive "/"s when generating the presigned URL. // See ServiceUtils#convertRequestToUrl(...) resourcePath = resourcePath.replaceAll("(?<=/)/", "%2F"); new S3QueryStringSigner(methodName.toString(), resourcePath, expiration) .sign(request, CredentialUtils.getCredentialsProvider(request.getOriginalRequest(), awsCredentialsProvider).getCredentials()); // The Amazon S3 DevPay token header is a special exception and can be safely moved // from the request's headers into the query string to ensure that it travels along // with the pre-signed URL when it's sent back to Amazon S3. if (request.getHeaders().containsKey(Headers.SECURITY_TOKEN)) { String value = request.getHeaders().get(Headers.SECURITY_TOKEN); request.addParameter(Headers.SECURITY_TOKEN, value); request.getHeaders().remove(Headers.SECURITY_TOKEN); } }
/** * <p> * Populates the specified request with the numerous options available in * <code>CopyObjectRequest</code>. * </p> * * @param request * The request to populate with headers to represent all the * options expressed in the <code>CopyPartRequest</code> object. * @param copyPartRequest * The object containing all the options for copying an object in * Amazon S3. */ private static void populateRequestWithCopyPartParameters(Request<?> request, CopyPartRequest copyPartRequest) { String copySourceHeader = "/" + SdkHttpUtils.urlEncode(copyPartRequest.getSourceBucketName(), true) + "/" + SdkHttpUtils.urlEncode(copyPartRequest.getSourceKey(), true); if (copyPartRequest.getSourceVersionId() != null) { copySourceHeader += "?versionId=" + copyPartRequest.getSourceVersionId(); } request.addHeader("x-amz-copy-source", copySourceHeader); addDateHeader(request, Headers.COPY_SOURCE_IF_MODIFIED_SINCE, copyPartRequest.getModifiedSinceConstraint()); addDateHeader(request, Headers.COPY_SOURCE_IF_UNMODIFIED_SINCE, copyPartRequest.getUnmodifiedSinceConstraint()); addStringListHeader(request, Headers.COPY_SOURCE_IF_MATCH, copyPartRequest.getMatchingETagConstraints()); addStringListHeader(request, Headers.COPY_SOURCE_IF_NO_MATCH, copyPartRequest.getNonmatchingETagConstraints()); if ( copyPartRequest.getFirstByte() != null && copyPartRequest.getLastByte() != null ) { String range = "bytes=" + copyPartRequest.getFirstByte() + "-" + copyPartRequest.getLastByte(); request.addHeader(Headers.COPY_PART_RANGE, range); } // Populate the SSE-C parameters for the destination object populateSourceSSE_C(request, copyPartRequest.getSourceSSECustomerKey()); populateSSE_C(request, copyPartRequest.getDestinationSSECustomerKey()); }
private String queryParamsString(Multimap<String, String> queryParams) { final ImmutableList.Builder<String> result = ImmutableList.builder(); for (Map.Entry<String, Collection<String>> param : new TreeMap<>(queryParams.asMap()).entrySet()) { for (String value : param.getValue()) { result.add(SdkHttpUtils.urlEncode(param.getKey(), false) + '=' + SdkHttpUtils.urlEncode(value, false)); } } return AMPERSAND_JOINER.join(result.build()); }
private Request<?> buildAWSRequest(String httpMethod, String endpoint, String resourcePath, Map<String, String> headers, Map<String, String> params, InputStream entity) { Request<AmazonWebServiceRequest> r = new DefaultRequest<>(Config.PARA); if (!StringUtils.isBlank(httpMethod)) { r.setHttpMethod(HttpMethodName.valueOf(httpMethod)); } if (!StringUtils.isBlank(endpoint)) { if (!endpoint.startsWith("http")) { endpoint = "https://" + endpoint; } r.setEndpoint(URI.create(endpoint)); } if (!StringUtils.isBlank(resourcePath)) { r.setResourcePath(SdkHttpUtils.urlEncode(resourcePath, true)); } if (headers != null) { if (headers.containsKey("x-amz-date")) { overriddenDate = parseAWSDate(headers.get("x-amz-date")); } // we don't need these here, added by default headers.remove("host"); headers.remove("x-amz-date"); r.setHeaders(headers); } if (params != null) { for (Map.Entry<String, String> param : params.entrySet()) { r.addParameter(param.getKey(), param.getValue()); } } if (entity != null) { r.setContent(entity); } return r; }
@Override public String marshall(String resourcePath, String paramName, String pathValue) { assertStringNotEmpty(pathValue, paramName); return resourcePath.replace(String.format("{%s}", paramName), SdkHttpUtils.urlEncode(pathValue, false)); }
/** * Signs the specified request with the AWS3 signing protocol by using the * AWS account credentials specified when this object was constructed and * adding the required AWS3 headers to the request. * * @param request * The request to sign. */ @Override public void sign(SignableRequest<?> request, AWSCredentials credentials) throws SdkClientException { // annonymous credentials, don't sign if ( credentials instanceof AnonymousAWSCredentials ) { return; } AWSCredentials sanitizedCredentials = sanitizeCredentials(credentials); SigningAlgorithm algorithm = SigningAlgorithm.HmacSHA256; String nonce = UUID.randomUUID().toString(); int timeOffset = request.getTimeOffset(); Date dateValue = getSignatureDate(timeOffset); String date = DateUtils.formatRFC822Date(dateValue); boolean isHttps = false; if (overriddenDate != null) date = overriddenDate; request.addHeader("Date", date); request.addHeader("X-Amz-Date", date); // AWS3 HTTP requires that we sign the Host header // so we have to have it in the request by the time we sign. String hostHeader = request.getEndpoint().getHost(); if (SdkHttpUtils.isUsingNonDefaultPort(request.getEndpoint())) { hostHeader += ":" + request.getEndpoint().getPort(); } request.addHeader("Host", hostHeader); if ( sanitizedCredentials instanceof AWSSessionCredentials ) { addSessionCredentials(request, (AWSSessionCredentials) sanitizedCredentials); } byte[] bytesToSign; String stringToSign; if (isHttps) { request.addHeader(NONCE_HEADER, nonce); stringToSign = date + nonce; bytesToSign = stringToSign.getBytes(UTF8); } else { String path = SdkHttpUtils.appendUri(request.getEndpoint().getPath(), request.getResourcePath()); /* * AWS3 requires all query params to be listed on the third line of * the string to sign, even if those query params will be sent in * the request body and not as a query string. POST formatted query * params should *NOT* be included in the request payload. */ stringToSign = request.getHttpMethod().toString() + "\n" + getCanonicalizedResourcePath(path) + "\n" + getCanonicalizedQueryString(request.getParameters()) + "\n" + getCanonicalizedHeadersForStringToSign(request) + "\n" + getRequestPayloadWithoutQueryParams(request); bytesToSign = hash(stringToSign); } if (log.isDebugEnabled()) log.debug("Calculated StringToSign: " + stringToSign); String signature = signAndBase64Encode(bytesToSign, sanitizedCredentials.getAWSSecretKey(), algorithm); StringBuilder builder = new StringBuilder(); builder.append(isHttps ? HTTPS_SCHEME : HTTP_SCHEME).append(" "); builder.append("AWSAccessKeyId=" + sanitizedCredentials.getAWSAccessKeyId() + ","); builder.append("Algorithm=" + algorithm.toString() + ","); if (!isHttps) { builder.append(getSignedHeadersComponent(request) + ","); } builder.append("Signature=" + signature); request.addHeader(AUTHORIZATION_HEADER, builder.toString()); }
/** * <p> * Populates the specified request with the numerous options available in * <code>CopyObjectRequest</code>. * </p> * * @param request * The request to populate with headers to represent all the * options expressed in the <code>CopyObjectRequest</code> object. * @param copyObjectRequest * The object containing all the options for copying an object in * Amazon S3. */ private void populateRequestWithCopyObjectParameters(Request<? extends AmazonWebServiceRequest> request, CopyObjectRequest copyObjectRequest) { String copySourceHeader = "/" + SdkHttpUtils.urlEncode(copyObjectRequest.getSourceBucketName(), true) + "/" + SdkHttpUtils.urlEncode(copyObjectRequest.getSourceKey(), true); if (copyObjectRequest.getSourceVersionId() != null) { copySourceHeader += "?versionId=" + copyObjectRequest.getSourceVersionId(); } request.addHeader("x-amz-copy-source", copySourceHeader); addDateHeader(request, Headers.COPY_SOURCE_IF_MODIFIED_SINCE, copyObjectRequest.getModifiedSinceConstraint()); addDateHeader(request, Headers.COPY_SOURCE_IF_UNMODIFIED_SINCE, copyObjectRequest.getUnmodifiedSinceConstraint()); addStringListHeader(request, Headers.COPY_SOURCE_IF_MATCH, copyObjectRequest.getMatchingETagConstraints()); addStringListHeader(request, Headers.COPY_SOURCE_IF_NO_MATCH, copyObjectRequest.getNonmatchingETagConstraints()); if (copyObjectRequest.getAccessControlList() != null) { addAclHeaders(request, copyObjectRequest.getAccessControlList()); } else if (copyObjectRequest.getCannedAccessControlList() != null) { request.addHeader(Headers.S3_CANNED_ACL, copyObjectRequest.getCannedAccessControlList().toString()); } if (copyObjectRequest.getStorageClass() != null) { request.addHeader(Headers.STORAGE_CLASS, copyObjectRequest.getStorageClass()); } if (copyObjectRequest.getRedirectLocation() != null) { request.addHeader(Headers.REDIRECT_LOCATION, copyObjectRequest.getRedirectLocation()); } populateRequesterPaysHeader(request, copyObjectRequest.isRequesterPays()); ObjectMetadata newObjectMetadata = copyObjectRequest.getNewObjectMetadata(); if (newObjectMetadata != null) { request.addHeader(Headers.METADATA_DIRECTIVE, "REPLACE"); populateRequestMetadata(request, newObjectMetadata); } ObjectTagging newObjectTagging = copyObjectRequest.getNewObjectTagging(); if (newObjectTagging != null) { request.addHeader(Headers.TAGGING_DIRECTIVE, "REPLACE"); request.addHeader(Headers.S3_TAGGING, urlEncodeTags(newObjectTagging)); } // Populate the SSE-C parameters for the destination object populateSourceSSE_C(request, copyObjectRequest.getSourceSSECustomerKey()); populateSSE_C(request, copyObjectRequest.getDestinationSSECustomerKey()); }
/** * Converts the specified request object into a URL, containing all the * specified parameters, the specified request endpoint, etc. * * @param request * The request to convert into a URL. * @param removeLeadingSlashInResourcePath * Whether the leading slash in resource-path should be removed * before appending to the endpoint. * @param urlEncode True if request resource path should be URL encoded * @return A new URL representing the specified request. * * @throws SdkClientException * If the request cannot be converted to a well formed URL. */ public static URL convertRequestToUrl(Request<?> request, boolean removeLeadingSlashInResourcePath, boolean urlEncode) { String resourcePath = urlEncode ? SdkHttpUtils.urlEncode(request.getResourcePath(), true) : request.getResourcePath(); // Removed the padding "/" that was already added into the request's resource path. if (removeLeadingSlashInResourcePath && resourcePath.startsWith("/")) { resourcePath = resourcePath.substring(1); } // Some http client libraries (e.g. Apache HttpClient) cannot handle // consecutive "/"s between URL authority and path components. // So we escape "////..." into "/%2F%2F%2F...", in the same way as how // we treat consecutive "/"s in AmazonS3Client#presignRequest(...) String urlPath = "/" + resourcePath; urlPath = urlPath.replaceAll("(?<=/)/", "%2F"); StringBuilder url = new StringBuilder(request.getEndpoint().toString()); url.append(urlPath); StringBuilder queryParams = new StringBuilder(); Map<String, List<String>> requestParams = request.getParameters(); for (Map.Entry<String, List<String>> entry : requestParams.entrySet()) { for (String value : entry.getValue()) { queryParams = queryParams.length() > 0 ? queryParams .append("&") : queryParams.append("?"); queryParams.append(entry.getKey()) .append("=") .append(SdkHttpUtils.urlEncode(value, false)); } } url.append(queryParams.toString()); try { return new URL(url.toString()); } catch (MalformedURLException e) { throw new SdkClientException( "Unable to convert request to well formed URL: " + e.getMessage(), e); } }
@Override public void sign(SignableRequest<?> request, AWSCredentials credentials) { if (resourcePath == null) { throw new UnsupportedOperationException( "Cannot sign a request using a dummy S3Signer instance with " + "no resource path"); } if (credentials == null || credentials.getAWSSecretKey() == null) { log.debug("Canonical string will not be signed, as no AWS Secret Key was provided"); return; } AWSCredentials sanitizedCredentials = sanitizeCredentials(credentials); if (sanitizedCredentials instanceof AWSSessionCredentials) { addSessionCredentials(request, (AWSSessionCredentials) sanitizedCredentials); } /* * In s3 sigv2, the way slash characters are encoded should be * consistent in both the request url and the encoded resource path. * Since we have to encode "//" to "/%2F" in the request url to make * httpclient works, we need to do the same encoding here for the * resource path. */ String encodedResourcePath = SdkHttpUtils.appendUri( request.getEndpoint().getPath(), SdkHttpUtils.urlEncode(resourcePath, true), true); int timeOffset = request.getTimeOffset(); Date date = getSignatureDate(timeOffset); request.addHeader(Headers.DATE, ServiceUtils.formatRfc822Date(date)); String canonicalString = RestUtils.makeS3CanonicalString(httpVerb, encodedResourcePath, request, null, additionalQueryParamsToSign); log.debug("Calculated string to sign:\n\"" + canonicalString + "\""); String signature = super.signAndBase64Encode(canonicalString, sanitizedCredentials.getAWSSecretKey(), SigningAlgorithm.HmacSHA1); request.addHeader("Authorization", "AWS " + sanitizedCredentials.getAWSAccessKeyId() + ":" + signature); }
public Map<String, Object> getSignedHeaders(String uri, String method, Multimap<String, String> queryParams, Map<String, Object> headers, Optional<byte[]> payload) { final LocalDateTime now = clock.get(); final AWSCredentials credentials = credentialsProvider.getCredentials(); final Map<String, Object> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); result.putAll(headers); final Optional<String> possibleHost = Optional.fromNullable(result.get(HOST)) .transform(Object::toString); final int indexOfPortSymbol = possibleHost.transform(host -> host.indexOf(':')).or(-1); if (indexOfPortSymbol > -1) { result.put(HOST, possibleHost.get().substring(0, indexOfPortSymbol)); } if (!result.containsKey(DATE)) { result.put(X_AMZ_DATE, now.format(BASIC_TIME_FORMAT)); } if (AWSSessionCredentials.class.isAssignableFrom(credentials.getClass())) { result.put(SESSION_TOKEN, ((AWSSessionCredentials) credentials).getSessionToken()); } final StringBuilder headersString = new StringBuilder(); final ImmutableList.Builder<String> signedHeaders = ImmutableList.builder(); for (Map.Entry<String, Object> entry : result.entrySet()) { final Optional<String> headerAsString = headerAsString(entry, method); if (headerAsString.isPresent()) { headersString.append(headerAsString.get()).append(RETURN); signedHeaders.add(entry.getKey().toLowerCase()); } } final String signedHeaderKeys = JOINER.join(signedHeaders.build()); final String canonicalRequest = method + RETURN + SdkHttpUtils.urlEncode(uri, true) + RETURN + queryParamsString(queryParams) + RETURN + headersString.toString() + RETURN + signedHeaderKeys + RETURN + toBase16(hash(payload.or(EMPTY.getBytes(Charsets.UTF_8)))); final String stringToSign = createStringToSign(canonicalRequest, now); final String signature = sign(stringToSign, now, credentials); final String autorizationHeader = AWS4_HMAC_SHA256_CREDENTIAL + credentials.getAWSAccessKeyId() + SLASH + getCredentialScope(now) + SIGNED_HEADERS + signedHeaderKeys + SIGNATURE + signature; result.put(AUTHORIZATION, autorizationHeader); return ImmutableMap.copyOf(result); }
/** * Perform a url decode on the given value if specified. * Return value by default; */ private static String decodeIfSpecified(String value, boolean decode) { return decode ? SdkHttpUtils.urlDecode(value) : value; }
/** * S3 URL encodes the key of the object involved in the event. This is * a convenience method to automatically URL decode the key. * @return The URL decoded object key. */ public String getUrlDecodedKey() { return SdkHttpUtils.urlDecode(getKey()); }