public void testWithIpAllocationModeNONE() throws IOException {

    HttpRequest request =
        HttpRequest.builder().endpoint(URI.create("http://localhost/key")).method("GET").build();

    BindNetworkConnectionSectionToXmlPayload binder =
        injector.getInstance(BindNetworkConnectionSectionToXmlPayload.class);

    binder.bindToRequest(
        request,
        NetworkConnectionSection.builder()
            .type("application/vnd.vmware.vcloud.networkConnectionSection+xml")
            .info("Specifies the available VM network connections")
            .href(URI.create("https://1.1.1.1/api/v1.0/vApp/vm-1/networkConnectionSection/"))
            .connections(
                ImmutableSet.<NetworkConnection>of(
                    NetworkConnection.builder()
                        .network("none")
                        .ipAddressAllocationMode(IpAddressAllocationMode.NONE)
                        .build()))
            .build());
    assertEquals(
        request.getPayload().getContentMetadata().getContentType(),
        "application/vnd.vmware.vcloud.networkConnectionSection+xml");

    assertEquals(
        request.getPayload().getRawContent(),
        "<NetworkConnectionSection xmlns=\"http://www.vmware.com/vcloud/v1\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" href=\"https://1.1.1.1/api/v1.0/vApp/vm-1/networkConnectionSection/\" ovf:required=\"false\" type=\"application/vnd.vmware.vcloud.networkConnectionSection+xml\"><ovf:Info>Specifies the available VM network connections</ovf:Info><NetworkConnection network=\"none\"><NetworkConnectionIndex>0</NetworkConnectionIndex><IsConnected>false</IsConnected><IpAddressAllocationMode>NONE</IpAddressAllocationMode></NetworkConnection></NetworkConnectionSection>");
  }
Beispiel #2
0
 private void appendPayloadMetadata(HttpRequest request, StringBuilder buffer) {
   buffer
       .append(
           utils.valueOrEmpty(
               request.getPayload() == null
                   ? null
                   : request.getPayload().getContentMetadata().getContentType()))
       .append("\n");
 }
 public void testBindEmptyArray() throws IOException {
   BindVolumeRefsToPayload binder = new BindVolumeRefsToPayload(new JAXBParser("false"));
   HttpRequest request =
       HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
   request = binder.bindToRequest(request, new VolumeManagementDto[] {});
   assertPayloadEquals(request.getPayload(), withHeader("<links/>"), LinksDto.class);
 }
  public void testSetInstanceInitiatedShutdownBehaviorForInstanceInRegion()
      throws SecurityException, NoSuchMethodException, IOException {
    Invokable<?, ?> method =
        method(
            InstanceApi.class,
            "setInstanceInitiatedShutdownBehaviorForInstanceInRegion",
            String.class,
            String.class,
            InstanceInitiatedShutdownBehavior.class);
    GeneratedHttpRequest request =
        processor.createRequest(
            method,
            Lists.<Object>newArrayList(null, "1", InstanceInitiatedShutdownBehavior.TERMINATE));

    request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);

    assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
    assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
    assertPayloadEquals(
        request,
        setInstanceInitiatedShutdownBehavior.getPayload().getRawContent().toString(),
        "application/x-www-form-urlencoded",
        false);

    assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
    assertSaxResponseParserClassEquals(method, null);
    assertFallbackClassEquals(method, null);

    checkFilters(request);
  }
 private static HashCode buildHashedPayload(HttpRequest request) {
   HashingInputStream his = null;
   try {
     his =
         new HashingInputStream(
             Hashing.sha256(),
             request.getPayload() == null
                 ? ByteSource.empty().openStream()
                 : request.getPayload().openStream());
     ByteStreams.copy(his, ByteStreams.nullOutputStream());
     return his.hash();
   } catch (IOException e) {
     throw new HttpException("Error signing request", e);
   } finally {
     closeQuietly(his);
   }
 }
 protected void populateHeaders(HttpRequest request, Request.Builder builder) {
   // OkHttp does not set the Accept header if not present in the request.
   // Make sure we send a flexible one.
   if (request.getFirstHeaderOrNull(ACCEPT) == null) {
     builder.addHeader(ACCEPT, "*/*");
   }
   if (request.getFirstHeaderOrNull(USER_AGENT) == null) {
     builder.addHeader(USER_AGENT, DEFAULT_USER_AGENT);
   }
   for (Map.Entry<String, String> entry : request.getHeaders().entries()) {
     builder.addHeader(entry.getKey(), entry.getValue());
   }
   if (request.getPayload() != null) {
     MutableContentMetadata md = request.getPayload().getContentMetadata();
     for (Map.Entry<String, String> entry : contentMetadataCodec.toHeaders(md).entries()) {
       builder.addHeader(entry.getKey(), entry.getValue());
     }
   }
 }
 public static <T> HttpRequest cleanRequest(HttpRequest returnVal) {
   checkNotNull(returnVal, "http request");
   for (HttpRequestFilter filter : returnVal.getFilters()) returnVal = filter.filter(returnVal);
   return HttpRequest.builder()
       .method(returnVal.getMethod())
       .endpoint(returnVal.getEndpoint())
       .headers(returnVal.getHeaders())
       .payload(returnVal.getPayload())
       .build();
 }
  public void testApplyInputStream() throws IOException {

    HttpRequest request = HttpRequest.builder().method("GET").endpoint("http://test").build();
    BindNoBucketLoggingToXmlPayload binder =
        injector.getInstance(BindNoBucketLoggingToXmlPayload.class);

    request = binder.bindToRequest(request, "bucket");
    assertEquals(
        request.getPayload().getRawContent(),
        "<BucketLoggingStatus xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"/>");
  }
  @Test
  public void testMap() throws SecurityException, NoSuchMethodException {
    DiskCreationOptions diskCreationOptions =
        new DiskCreationOptions()
            .sourceSnapshot(URI.create(FAKE_SOURCE_SNAPSHOT))
            .sizeGb(15)
            .description(null);

    HttpRequest request = HttpRequest.builder().method("GET").endpoint("http://momma").build();
    Map<String, Object> postParams =
        ImmutableMap.of("name", "testName", "options", diskCreationOptions);

    request = binder.bindToRequest(request, postParams);

    assertEquals(
        request.getPayload().getRawContent(),
        "{\"name\":\"testName\",\"sizeGb\":15,\"sourceSnapshot\":\""
            + FAKE_SOURCE_SNAPSHOT
            + "\"}");
    assertEquals(request.getPayload().getContentMetadata().getContentType(), "application/json");
  }
  public void testComplete() throws IOException {
    CreateDriveRequest input =
        new CreateDriveRequest.Builder()
            .name("Ubuntu 10.10 Server Edition Linux 64bit Preinstalled System")
            //
            .size(8589934592l) //
            .claimType(ClaimType.SHARED) //
            .readers(ImmutableSet.of("ffffffff-ffff-ffff-ffff-ffffffffffff")) //
            .tags(ImmutableSet.of("tag1", "tag2"))
            .userMetadata(ImmutableMap.of("foo", "bar", "baz", "raz")) //
            .encryptionCipher("aes-xts-plain")
            .avoid(ImmutableSet.of("avoid1"))
            .build();

    HttpRequest request = new HttpRequest("POST", URI.create("https://host/drives/create"));
    FN.bindToRequest(request, input);
    assertEquals(request.getPayload().getContentMetadata().getContentType(), MediaType.TEXT_PLAIN);
    assertEquals(
        request.getPayload().getRawContent(),
        Strings2.toStringAndClose(
            BindDriveToPlainTextStringTest.class.getResourceAsStream("/create_drive.txt")));
  }
 public void testBindMultipleVolumes() throws IOException {
   VolumeManagementDto volume = CloudResources.volumePut();
   BindVolumeRefsToPayload binder = new BindVolumeRefsToPayload(new JAXBParser("false"));
   HttpRequest request =
       HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
   request = binder.bindToRequest(request, new VolumeManagementDto[] {volume, volume});
   assertPayloadEquals(
       request.getPayload(),
       withHeader(
           "<links><link href=\""
               + volume.getEditLink().getHref()
               + "\" rel=\""
               + binder.getRelToUse(volume)
               + "\"/></links>"),
       LinksDto.class);
 }
  public void testMappingOrdersLexicographically() {
    Map<String, BlockDevice> mapping = Maps.newLinkedHashMap();
    mapping.put("apple", new BlockDevice("appleId", true));
    Date date = new Date(999999l);
    mapping.put("cranberry", new BlockDevice("cranberry", Status.ATTACHED, date, false));

    HttpRequest request =
        HttpRequest.builder()
            .method("POST")
            .endpoint("http://localhost")
            .addFormParam("InstanceId", "i-foo")
            .build();
    request = binder.bindToRequest(request, mapping);
    assertEquals(
        request.getPayload().getRawContent(),
        "Action=ModifyInstanceAttribute&BlockDeviceMapping.1.DeviceName=apple&BlockDeviceMapping.1.Ebs.DeleteOnTermination=true&BlockDeviceMapping.1.Ebs.VolumeId=appleId&BlockDeviceMapping.2.DeviceName=cranberry&BlockDeviceMapping.2.Ebs.DeleteOnTermination=false&BlockDeviceMapping.2.Ebs.VolumeId=cranberry&InstanceId=i-foo");
  }
  public HttpRequest filter(HttpRequest input) throws HttpException {
    HttpRequest request =
        input.toBuilder().endpoint(input.getEndpoint().toString().replace("%3F", "?")).build();
    String contentHash = hashBody(request.getPayload());
    Multimap<String, String> headers = ArrayListMultimap.create();
    headers.put("X-Ops-Content-Hash", contentHash);
    String timestamp = timeStampProvider.get();
    String toSign =
        createStringToSign(
            request.getMethod(), hashPath(request.getEndpoint().getPath()), contentHash, timestamp);
    headers.put("X-Ops-Userid", creds.get().identity);
    headers.put("X-Ops-Sign", SIGNING_DESCRIPTION);
    request = calculateAndReplaceAuthorizationHeaders(request, toSign);
    headers.put("X-Ops-Timestamp", timestamp);
    utils.logRequest(signatureLog, request, "<<");

    return request.toBuilder().replaceHeaders(headers).build();
  }
Beispiel #14
0
 public void checkRequestHasRequiredProperties(HttpRequest message) {
   checkArgument(
       message.getPayload() == null || message.getFirstHeaderOrNull(CONTENT_TYPE) == null,
       "configuration error please use request.getPayload().getContentMetadata().setContentType(value) as opposed to adding a content type header: "
           + message);
   checkArgument(
       message.getPayload() == null || message.getFirstHeaderOrNull(CONTENT_LENGTH) == null,
       "configuration error please use request.getPayload().getContentMetadata().setContentLength(value) as opposed to adding a content length header: "
           + message);
   checkArgument(
       message.getPayload() == null
           || message.getPayload().getContentMetadata().getContentLength() != null
           || "chunked".equalsIgnoreCase(message.getFirstHeaderOrNull("Transfer-Encoding")),
       "either chunked encoding must be set on the http request or contentlength set on the payload: "
           + message);
   checkArgument(
       message.getPayload() == null || message.getFirstHeaderOrNull("Content-MD5") == null,
       "configuration error please use request.getPayload().getContentMetadata().setContentMD5(value) as opposed to adding a content md5 header: "
           + message);
   checkArgument(
       message.getPayload() == null || message.getFirstHeaderOrNull("Content-Disposition") == null,
       "configuration error please use request.getPayload().getContentMetadata().setContentDisposition(value) as opposed to adding a content disposition header: "
           + message);
   checkArgument(
       message.getPayload() == null || message.getFirstHeaderOrNull(CONTENT_ENCODING) == null,
       "configuration error please use request.getPayload().getContentMetadata().setContentEncoding(value) as opposed to adding a content encoding header: "
           + message);
   checkArgument(
       message.getPayload() == null || message.getFirstHeaderOrNull(CONTENT_LANGUAGE) == null,
       "configuration error please use request.getPayload().getContentMetadata().setContentLanguage(value) as opposed to adding a content language header: "
           + message);
   checkArgument(
       message.getPayload() == null || message.getFirstHeaderOrNull(EXPIRES) == null,
       "configuration error please use request.getPayload().getContentMetadata().setExpires(value) as opposed to adding an expires header: "
           + message);
 }
    public Request apply(HttpRequest request) {

      for (HttpRequestFilter filter : request.getFilters()) {
        filter.filter(request);
      }

      AsyncHttpClient client = new AsyncHttpClient();
      AsyncHttpClient.BoundRequestBuilder nativeRequestBuilder;
      String endpoint = request.getEndpoint().toASCIIString();
      if (request.getMethod().equals(HttpMethod.HEAD)) {
        nativeRequestBuilder = client.prepareHead(endpoint);
      } else if (request.getMethod().equals(HttpMethod.GET)) {
        nativeRequestBuilder = client.prepareGet(endpoint);
      } else if (request.getMethod().equals(HttpMethod.DELETE)) {
        nativeRequestBuilder = client.prepareDelete(endpoint);
      } else if (request.getMethod().equals(HttpMethod.PUT)) {
        nativeRequestBuilder = client.preparePut(endpoint);
      } else if (request.getMethod().equals(HttpMethod.POST)) {
        nativeRequestBuilder = client.preparePost(endpoint);
      } else {
        throw new UnsupportedOperationException(request.getMethod());
      }
      Payload payload = request.getPayload();
      if (payload != null) {
        boolean chunked = "chunked".equals(request.getFirstHeaderOrNull("Transfer-Encoding"));

        if (request.getPayload().getContentMD5() != null)
          nativeRequestBuilder.addHeader(
              "Content-MD5", CryptoStreams.base64(request.getPayload().getContentMD5()));
        if (request.getPayload().getContentType() != null)
          nativeRequestBuilder.addHeader(
              HttpHeaders.CONTENT_TYPE, request.getPayload().getContentType());
        if (!chunked) {
          Long length =
              checkNotNull(request.getPayload().getContentLength(), "payload.getContentLength");
          nativeRequestBuilder.addHeader(HttpHeaders.CONTENT_LENGTH, length.toString());
        }
        setPayload(nativeRequestBuilder, payload);
      } else {
        nativeRequestBuilder.addHeader(HttpHeaders.CONTENT_LENGTH, "0");
      }

      nativeRequestBuilder.addHeader(HttpHeaders.USER_AGENT, USER_AGENT);
      for (String header : request.getHeaders().keySet()) {
        for (String value : request.getHeaders().get(header)) {
          nativeRequestBuilder.addHeader(header, value);
        }
      }

      return nativeRequestBuilder.build();
    }
 static String requestPayloadIfStringOrFormIfNotReturnEmptyString(HttpRequest request) {
   if (request.getPayload() != null
       && ("application/x-www-form-urlencoded"
               .equals(request.getPayload().getContentMetadata().getContentType())
           || request.getPayload() instanceof StringPayload)
       && request.getPayload().getContentMetadata().getContentLength() != null
       && request.getPayload().getContentMetadata().getContentLength() < 1024) {
     try {
       return String.format(
           " [%s] ",
           request.getPayload() instanceof StringPayload
               ? request.getPayload().getRawContent()
               : Strings2.toString(request.getPayload()));
     } catch (IOException e) {
     }
   }
   return "";
 }
Beispiel #17
0
  static String createStringToSign(
      HttpRequest request, Map<String, String> signedHeaders, String credentialScope) {
    StringBuilder canonicalRequest = new StringBuilder();
    // HTTPRequestMethod + '\n' +
    canonicalRequest.append(request.getMethod()).append("\n");
    // CanonicalURI + '\n' +
    canonicalRequest.append(request.getEndpoint().getPath()).append("\n");
    // CanonicalQueryString + '\n' +
    checkArgument(
        request.getEndpoint().getQuery() == null, "Query parameters not yet supported %s", request);
    canonicalRequest.append("\n");
    // CanonicalHeaders + '\n' +
    for (Map.Entry<String, String> entry : signedHeaders.entrySet()) {
      canonicalRequest.append(entry.getKey()).append(':').append(entry.getValue()).append('\n');
    }
    canonicalRequest.append("\n");

    // SignedHeaders + '\n' +
    canonicalRequest.append(Joiner.on(';').join(signedHeaders.keySet())).append('\n');

    // HexEncode(Hash(Payload))
    String payload = request.getPayload().getRawContent().toString();
    canonicalRequest.append(
        base16().lowerCase().encode(sha256().hashString(payload, UTF_8).asBytes()));

    StringBuilder toSign = new StringBuilder();
    // Algorithm + '\n' +
    toSign.append("AWS4-HMAC-SHA256").append('\n');
    // RequestDate + '\n' +
    toSign.append(signedHeaders.get("x-amz-date")).append('\n');
    // CredentialScope + '\n' +
    toSign.append(credentialScope).append('\n');
    // HexEncode(Hash(CanonicalRequest))
    toSign.append(
        base16()
            .lowerCase()
            .encode(sha256().hashString(canonicalRequest.toString(), UTF_8).asBytes()));

    return toSign.toString();
  }
  @Override
  protected Request convert(HttpRequest request) throws IOException, InterruptedException {
    Request.Builder builder = new Request.Builder();

    builder.url(request.getEndpoint().toString());
    populateHeaders(request, builder);

    RequestBody body = null;
    Payload payload = request.getPayload();

    if (payload != null) {
      Long length =
          checkNotNull(payload.getContentMetadata().getContentLength(), "payload.getContentLength");
      if (length > 0) {
        body = generateRequestBody(request, payload);
      }
    }

    builder.method(request.getMethod(), body);

    return builder.build();
  }
 public void testSimple() {
   HttpRequest request = new HttpRequest("POST", URI.create("https://host/drives/create"));
   FN.bindToRequest(request, new CreateDriveRequest.Builder().name("foo").size(100l).build());
   assertEquals(request.getPayload().getContentMetadata().getContentType(), MediaType.TEXT_PLAIN);
   assertEquals(request.getPayload().getRawContent(), "name foo\nsize 100");
 }
    public Request apply(HttpRequest request) {

      for (HttpRequestFilter filter : request.getFilters()) {
        filter.filter(request);
      }

      RequestBuilder builder = new RequestBuilder(request.getMethod());
      builder.setUrl(request.getEndpoint().toASCIIString());
      Payload payload = request.getPayload();
      if (payload != null) {
        boolean chunked = "chunked".equals(request.getFirstHeaderOrNull("Transfer-Encoding"));

        if (request.getPayload().getContentMetadata().getContentMD5() != null)
          builder.addHeader(
              "Content-MD5",
              CryptoStreams.base64(request.getPayload().getContentMetadata().getContentMD5()));
        if (request.getPayload().getContentMetadata().getContentType() != null)
          builder.addHeader(
              HttpHeaders.CONTENT_TYPE, request.getPayload().getContentMetadata().getContentType());
        if (request.getPayload().getContentMetadata().getContentLanguage() != null)
          builder.addHeader(
              HttpHeaders.CONTENT_LANGUAGE,
              request.getPayload().getContentMetadata().getContentLanguage());
        if (request.getPayload().getContentMetadata().getContentEncoding() != null)
          builder.addHeader(
              HttpHeaders.CONTENT_ENCODING,
              request.getPayload().getContentMetadata().getContentEncoding());
        if (request.getPayload().getContentMetadata().getContentDisposition() != null)
          builder.addHeader(
              "Content-Disposition",
              request.getPayload().getContentMetadata().getContentDisposition());
        if (!chunked) {
          Long length =
              checkNotNull(
                  request.getPayload().getContentMetadata().getContentLength(),
                  "payload.getContentLength");
          builder.addHeader(HttpHeaders.CONTENT_LENGTH, length.toString());
        }
        setPayload(builder, payload);
      } else {
        builder.addHeader(HttpHeaders.CONTENT_LENGTH, "0");
      }

      builder.addHeader(HttpHeaders.USER_AGENT, USER_AGENT);
      for (String header : request.getHeaders().keySet()) {
        for (String value : request.getHeaders().get(header)) {
          builder.addHeader(header, value);
        }
      }

      return builder.build();
    }
  @Override
  protected HttpURLConnection convert(HttpRequest request)
      throws IOException, InterruptedException {
    boolean chunked = "chunked".equals(request.getFirstHeaderOrNull("Transfer-Encoding"));
    URL url = request.getEndpoint().toURL();

    HttpURLConnection connection =
        (HttpURLConnection) url.openConnection(proxyForURI.apply(request.getEndpoint()));
    if (connection instanceof HttpsURLConnection) {
      HttpsURLConnection sslCon = (HttpsURLConnection) connection;
      if (utils.relaxHostname()) sslCon.setHostnameVerifier(verifier);
      if (sslContextSupplier != null) {
        // used for providers which e.g. use certs for authentication (like FGCP)
        // Provider provides SSLContext impl (which inits context with key manager)
        sslCon.setSSLSocketFactory(sslContextSupplier.get().getSocketFactory());
      } else if (utils.trustAllCerts()) {
        sslCon.setSSLSocketFactory(untrustedSSLContextProvider.get().getSocketFactory());
      }
    }
    connection.setConnectTimeout(utils.getConnectionTimeout());
    connection.setReadTimeout(utils.getSocketOpenTimeout());
    connection.setAllowUserInteraction(false);
    // do not follow redirects since https redirects don't work properly
    // ex. Caused by: java.io.IOException: HTTPS hostname wrong: should be
    // <adriancole.s3int0.s3-external-3.amazonaws.com>
    connection.setInstanceFollowRedirects(false);
    try {
      connection.setRequestMethod(request.getMethod());
    } catch (ProtocolException e) {
      try {
        methodField.set(connection, request.getMethod());
      } catch (IllegalAccessException e1) {
        logger.error(e, "could not set request method: ", request.getMethod());
        propagate(e1);
      }
    }

    for (Map.Entry<String, String> entry : request.getHeaders().entries()) {
      connection.setRequestProperty(entry.getKey(), entry.getValue());
    }

    String host = request.getEndpoint().getHost();
    if (request.getEndpoint().getPort() != -1) {
      host += ":" + request.getEndpoint().getPort();
    }
    connection.setRequestProperty(HOST, host);
    if (connection.getRequestProperty(USER_AGENT) == null) {
      connection.setRequestProperty(USER_AGENT, DEFAULT_USER_AGENT);
    }
    Payload payload = request.getPayload();
    if (payload != null) {
      MutableContentMetadata md = payload.getContentMetadata();
      for (Map.Entry<String, String> entry : contentMetadataCodec.toHeaders(md).entries()) {
        connection.setRequestProperty(entry.getKey(), entry.getValue());
      }
      if (chunked) {
        connection.setChunkedStreamingMode(8196);
        writePayloadToConnection(payload, "streaming", connection);
      } else {
        Long length = checkNotNull(md.getContentLength(), "payload.getContentLength");
        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6755625
        checkArgument(
            length < Integer.MAX_VALUE,
            "JDK 1.6 does not support >2GB chunks. Use chunked encoding, if possible.");
        if (length > 0) {
          connection.setRequestProperty(CONTENT_LENGTH, length.toString());
          connection.setFixedLengthStreamingMode(length.intValue());
          writePayloadToConnection(payload, length, connection);
        } else {
          writeNothing(connection);
        }
      }
    } else {
      writeNothing(connection);
    }
    return connection;
  }
Beispiel #22
0
  @Override
  public HttpRequest filter(HttpRequest request) throws HttpException {
    checkArgument(
        request.getHeaders().containsKey(HOST), "request is not ready to sign; host not present");
    String host = request.getFirstHeaderOrNull(HOST);
    String form = request.getPayload().getRawContent().toString();
    checkArgument(
        form.indexOf(ACTION) != -1, "request is not ready to sign; Action not present %s", form);

    String timestamp = iso8601Timestamp.get();
    String datestamp = timestamp.substring(0, 8);

    String service = serviceAndRegion.service();
    String region = serviceAndRegion.region(host);
    String credentialScope = Joiner.on('/').join(datestamp, region, service, "aws4_request");

    // content-type is not a required signing param. However, examples use this, so we include it to
    // ease testing.
    ImmutableMap.Builder<String, String> signedHeadersBuilder =
        ImmutableMap.<String, String>builder() //
            .put("content-type", request.getPayload().getContentMetadata().getContentType()) //
            .put("host", host) //
            .put("x-amz-date", timestamp);

    HttpRequest.Builder<?> requestBuilder =
        request
            .toBuilder() //
            .removeHeader(AUTHORIZATION) //
            .replaceHeader("X-Amz-Date", timestamp);

    if (form.indexOf(VERSION) == -1) {
      requestBuilder.addFormParam("Version", apiVersion);
    }

    Credentials credentials = creds.get();

    if (credentials instanceof SessionCredentials) {
      String token = SessionCredentials.class.cast(credentials).getSessionToken();
      requestBuilder.replaceHeader("X-Amz-Security-Token", token);
      signedHeadersBuilder.put("x-amz-security-token", token);
    }

    ImmutableMap<String, String> signedHeaders = signedHeadersBuilder.build();

    String stringToSign =
        createStringToSign(requestBuilder.build(), signedHeaders, credentialScope);
    byte[] signatureKey = signatureKey(credentials.credential, datestamp, region, service);
    String signature = base16().lowerCase().encode(hmacSHA256(stringToSign, signatureKey));

    StringBuilder authorization = new StringBuilder("AWS4-HMAC-SHA256 ");
    authorization
        .append("Credential=")
        .append(credentials.identity)
        .append('/')
        .append(credentialScope)
        .append(", ");
    authorization
        .append("SignedHeaders=")
        .append(Joiner.on(';').join(signedHeaders.keySet()))
        .append(", ");
    authorization.append("Signature=").append(signature);

    return requestBuilder.addHeader(AUTHORIZATION, authorization.toString()).build();
  }