title: AJAX CORS PUT to Azure Blob Storage returning 405 Error
body: <p>I have an MVC application that allows a user to upload a resource to blob storage with a dynamically generated SAS. A user will select a file and click upload. When upload is clicked, an ajax call is sent to a controller action that will generate an SAS for the container and return a string which is the URI for the blob that is going to be uploaded with the signature appended. This works perfectly and returns the correct URI with SAS. I then have another ajax call that will PUT the data from the file to Azure Blob Storage using the URI that was returned. When this executes I get a javascript runtime error in the Jquery.min file that says "0x80070005 Access is Denied".</p>
  
  <p>I wanted to make sure I had coded this correctly and that my SAS was right so I ran it through Runscope (I had the MVC controller action modify the URI to go through my Runscope account). If I copied the URI and manually set the headers that I am setting in the ajax call, it worked. And the permission settings work. With the SAS that I generated I can access the file, without it I cannot. If I let it run through my javascript file with the ajax call it failed and returned a 405 error. Here is my ajax call and then my two different requests sent with Runscope.</p>
  
  <p>I used this article
  <a href="http://gauravmantri.com/2013/02/16/uploading-large-files-in-windows-azure-blob-storage-using-shared-access-signature-html-and-javascript/#comment-1700" rel="nofollow">http://gauravmantri.com/2013/02/16/uploading-large-files-in-windows-azure-blob-storage-using-shared-access-signature-html-and-javascript/#comment-1700</a>
  as a guide for uploading the file in chunks. The following ajax call will execute for each block uploaded, but it fails on the first try.</p>
  
  <pre><code>var uri = submitUri + "&amp;comp=block&amp;blockid=" + blockIds[blockIds.length - 1];
  var requestData = new Uint8Array(evt.target.result);
  $.ajax({
      url: uri,
      type: "PUT",
      data: requestData,
      processData: false,
      beforeSend: function(xhr) {
          xhr.setRequestHeader("x-ms-blob-type", "BlockBlob");
          xhr.setRequestHeader("Content-Length", requestData.length);
      },
      success: function() {
          // successful stuff here
          uploadFileInBlocks();
      }
      error: function (xhr, desc, err) {
          // error stuff here
      }
  });
  </code></pre>
  
  <p>And here are my Runscope results:</p>
  
  <p>Successful manual request: </p>
  
  <pre><code>PUT https://&lt;myaccount&gt;.blob.core.windows.net/trainingcourseresources/1002/georgewashington.jpg?sr=c&amp;sp=rw&amp;sig=GI+HN1hTEiyTG9Kz1OIBIcArAEkeZWyxI4v7OmMuEsA=&amp;sv=2012-02-12&amp;se=2013-09-17T13:19:52Z
  
  HEADERS
  Accept: */*
  Accept-Encoding: gzip, deflate, compress
  Connection: close
  Host: atlastestblob.blob.core.windows.net
  User-Agent: runscope/0.1
  X-Ms-Blob-Type: BlockBlob
  
  QUERYSTRING
  se: 2013-09-17T13:19:52Z
  sig: GI+HN1hTEiyTG9Kz1OIBIcArAEkeZWyxI4v7OmMuEsA=
  sp: rw
  sr: c
  sv: 2012-02-12
  
  Response: 201 Created
  </code></pre>
  
  <p>Failed ajax request:</p>
  
  <pre><code>OPTIONS https://&lt;myaccount&gt;.blob.core.windows.net/trainingcourseresources/1002/cslewis.jpg?sp=rw&amp;sr=c&amp;blockid=YmxvY2stMDAwMDAw&amp;sv=2012-02-12&amp;sig=iIn/AL3eBBFlZdYoT717SMS9iDOY5PEKIdIufOle7NA=&amp;comp=block&amp;se=2013-09-17T13:40:00Z
  
  HEADERS
  Accept: */*
  Accept-Encoding: gzip, deflate
  Access-Control-Request-Headers: content-type, accept, x-ms-blob-type
  Access-Control-Request-Method: PUT
  Cache-Control: no-cache
  Connection: close
  Dnt: 1
  Host: atlastestblob.blob.core.windows.net
  Origin: https://localhost:44308
  User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
  
  QUERYSTRING
  blockid: YmxvY2stMDAwMDAw
  comp: block
  se: 2013-09-17T13:40:00Z
  sig: iIn/AL3eBBFlZdYoT717SMS9iDOY5PEKIdIufOle7NA=
  sp: rw
  sr: c
  sv: 2012-02-12
  
  Response: 405 The resource doesn't support specified Http Verb
  </code></pre>