title: S3 PUT doesn't work with pre-signed URL in javascript
body: <p>I have generated a pre-signed S3 URL in java for HTTP PUT method. </p>
  
  <p>A slightly modified version of the URL:</p>
  
  <p><code>https://s3.amazonaws.com/somebucket/pre-signed-url-key-2?AWSAccessKeyId=BKIAIQ6H5Z7BG6KZ2ZUA&amp;Expires=1425617244&amp;Signature=GWcRM5ZIrAKnMJBsxyfm%2F9fyuBk%3D</code></p>
  
  <p>I know that it is a valid pre-signed url since I can use it with <code>curl</code> to upload a file</p>
  
  <p><code>curl -v --upload-file somefile.txt "https://s3.amazonaws.com/somebucket/pre-signed-url-key-2?AWSAccessKeyId=BKIAIQ6H5Z7BG6KZ2ZUA&amp;Expires=1425617244&amp;Signature=GWcRM5ZIrAKnMJBsxyfm%2F9fyuBk%3D"</code></p>
  
  <p>When I try to upload a file to the same URL using the following Javascript:  </p>
  
  <pre><code>function ajaxUsingPresignedUrlPut() {
              $.ajax({
                  url: presignedURLPUT,
                  type: 'PUT',
                  data: 'blah blah blah',
                  success: function () {
                      console.log('Uploaded data successfully.');
                  }
              }).done(function (data) {
                  console.log("DONE : " + data);
              }).fail(function (e, r) {
                  console.log("FAIL");
              });
          }
  </code></pre>
  
  <p>I get a 403 status and responseText</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;Error&gt;&lt;Code&gt;SignatureDoesNotMatch&lt;/Code&gt;&lt;Message&gt;The request signature we calculated does not match the signature you provided. Check your key and signing method.&lt;/Message&gt;&lt;AWSAccessKeyId&gt;BKIAIQ6H5Z7BG6KZ2ZUA&lt;/AWSAccessKeyId&gt;&lt;StringToSign&gt;PUT
  
  application/x-www-form-urlencoded; charset=UTF-8
  1425617244
  /somebucket/pre-signed-url-key-2&lt;/StringToSign&gt;&lt;SignatureProvided&gt;GWcRM5ZIrAKnMJAsxyfm/9fyuAk=&lt;/SignatureProvided&gt;&lt;StringToSignBytes&gt;50 55 54 0a 0a 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 2d 77 77 77 2d 66 6f 72 6d 2d 75 72 6c 65 6e 63 6f 64 65 64 3b 20 63 68 61 72 73 65 74 3d 55 54 46 2d 38 0a 31 34 32 35 36 31 37 32 34 34 0a 2f 6e 6b 6f 6e 64 72 61 74 5f 62 75 63 6b 65 74 2f 70 72 65 2d 73 69 67 6e 65 64 2d 75 72 6c 2d 6b 65 79 2d 32&lt;/StringToSignBytes&gt;&lt;RequestId&gt;3C8298CAC404C6F5&lt;/RequestId&gt;&lt;HostId&gt;uCkzA//CdCLi4SINifkIe0WH6GOlCJBgFlN8ghx8NnULEe+QVslsdoUsJc4AUdA8&lt;/HostId&gt;&lt;/Error&gt;
  </code></pre>
  
  <p>I have the following CORS policy configured on the S3 bucket:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"&gt;
      &lt;CORSRule&gt;
          &lt;AllowedOrigin&gt;*&lt;/AllowedOrigin&gt;
          &lt;AllowedMethod&gt;HEAD&lt;/AllowedMethod&gt;
          &lt;AllowedMethod&gt;GET&lt;/AllowedMethod&gt;
          &lt;AllowedMethod&gt;PUT&lt;/AllowedMethod&gt;
          &lt;AllowedMethod&gt;POST&lt;/AllowedMethod&gt;
          &lt;AllowedMethod&gt;DELETE&lt;/AllowedMethod&gt;
          &lt;MaxAgeSeconds&gt;3000&lt;/MaxAgeSeconds&gt;
          &lt;ExposeHeader&gt;ETag&lt;/ExposeHeader&gt;
          &lt;ExposeHeader&gt;Content-Length&lt;/ExposeHeader&gt;
          &lt;ExposeHeader&gt;Content-Type&lt;/ExposeHeader&gt;
          &lt;ExposeHeader&gt;Connection&lt;/ExposeHeader&gt;
          &lt;ExposeHeader&gt;Date&lt;/ExposeHeader&gt;
          &lt;ExposeHeader&gt;Server&lt;/ExposeHeader&gt;
          &lt;ExposeHeader&gt;x-amz-delete-marker&lt;/ExposeHeader&gt;
          &lt;ExposeHeader&gt;x-amz-id-2&lt;/ExposeHeader&gt;
          &lt;ExposeHeader&gt;x-amz-request-id&lt;/ExposeHeader&gt;
          &lt;ExposeHeader&gt;x-amz-version-id&lt;/ExposeHeader&gt;
          &lt;AllowedHeader&gt;*&lt;/AllowedHeader&gt;
      &lt;/CORSRule&gt;
  &lt;/CORSConfiguration&gt;
  </code></pre>
  
  <p>And the same javascript code works for a pre-signed GET URL:
  <code>https://s3.amazonaws.com/somebucket/pre-signed-url-key-2?AWSAccessKeyId=BKIBIQ6H5Z7LG6KZ2ZUB&amp;Expires=1425616588&amp;Signature=qMPpuzMwxonYPDQETdLafEQGqMU%3D</code></p>
  
  <pre><code>function ajaxUsingPresignedUrlGET() {
              $.ajax({
                  url: presignedURLGET,
                  type: 'GET',
                  success: function () {
                      console.log('Uploaded data successfully.');
                  }
              }).done(function (data) {
                  console.log("DONE : " + data);
              }).fail(function (e, r) {
                  console.log("FAIL");
              });
          }
  </code></pre>
  
  <p>My only guess right now looking at the URLs is that the PUT url contains <code>%2F</code> and looking at <a href="http://www.w3schools.com/tags/ref_urlencode.asp" rel="noreferrer">http://www.w3schools.com/tags/ref_urlencode.asp</a> that stands for <code>/</code> which might be causing an issue in the browser? Or maybe I am completely off here and there is some other issue that I am missing. </p>
  
  <hr>
  
  <p>Edit #1 Adding java code used to generate pre-signed URL </p>
  
  <pre><code>public S3GeneratePresignedUrlDemo(HttpMethod httpMethod) {
      this.httpMethod = httpMethod;
      System.out.println("HTTP METHOD : " + this.httpMethod);
  }
  
  @Override
  public void goImpl() throws Exception {        
      GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, KEY);
  
      request.setMethod(httpMethod);
  
      request.setExpiration(createDateNHoursFromNow(24));
  
      URL url = s3Client.generatePresignedUrl(request);
  
      System.out.println(url);
  }
  
  private static Date createDateNHoursFromNow(int hours){
      Date date = new Date();
      long millis = date.getTime();
      final int millisInSecond = 1000;
      final int secondsInMinute = 60;
      final int minutesInHour = 60;
      millis += millisInSecond * secondsInMinute * minutesInHour * hours;
  
      date.setTime(millis);
      return date;
  }`
  </code></pre>