title: Chrome v37/38 CORS failing (again) with 401 for OPTIONS pre-flight requests
body: <p>As from Chrome version 37, pre-flighted, cross-domain requests are failing (again) if the server has authentication enabled, even though all CORS headers are set correctly. This is on <code>localhost</code> (my dev PC).</p>
  
  <p>Some of you may be aware of the history of Chrome/CORS/auth bugs, especially when HTTPS was involved. My problem does <em>not</em> involve HTTPS: I have an AngularJS application served from <code>localhost:8383</code> talking to a Java (Jetty) server on <code>localhost:8081</code> that has HTTP BASIC auth activated. GETs work fine, but POSTs fail with a 401:</p>
  
  <pre><code>XMLHttpRequest cannot load http://localhost:8081/cellnostics/rest/patient.
  Invalid HTTP status code 401
  </code></pre>
  
  <p>I have previously written a custom (Java) CORS filter that sets the correct CORS headers, which worked up until v36. It fails in v37 and also the latest v38 (38.0.2125.101 m). It <em>still works as expected</em> with Internet Explorer 11 (11.0.9600) and Opera 12.17 (build 1863).</p>
  
  <p><strong>GET</strong> requests succeed, but <strong>POST</strong>s fail. It looks like Chrome is pre-flighting all my POSTs due to the content-type: "application/json", and that it is the pre-flighted OPTIONS request that is failing.</p>
  
  <p>In the Angular app I explicitly set the following request headers. AFAIK this setting for <code>withCredentials</code> should ensure that credentials are sent even for OPTIONS requests:</p>
  
  <pre><code>//Enable cross domain calls
  $httpProvider.defaults.useXDomain = true;
  
  //Send all requests, even OPTIONS, with credentials
  $httpProvider.defaults.withCredentials = true;
  </code></pre>
  
  <p>Below is the request/response. You can see that the OPTIONS method is enabled in the <code>Access-Control-Allow-Methods</code> header. You can also see that the Javascript app's origin is explicitly enabled: <code>Access-Control-Allow-Origin: http://localhost:8383</code>.</p>
  
  <pre><code>Remote Address:[::1]:8081
  Request URL:http://localhost:8081/cellnostics/rest/medicaltest
  Request Method:OPTIONS
  Status Code:401 Full authentication is required to access this resource
  
  Request headers:
  
  Accept:*/*
  Accept-Encoding:gzip,deflate,sdch
  Accept-Language:en-US,en;q=0.8,af;q=0.6
  Access-Control-Request-Headers:accept, content-type
  Access-Control-Request-Method:POST
  Connection:keep-alive
  Host:localhost:8081
  Origin:http://localhost:8383
  Referer:http://localhost:8383/celln-web/index.html
  User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36
  
  Response headers:
  
  Access-Control-Allow-Credentials:true
  Access-Control-Allow-Headers:Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept
  Access-Control-Allow-Methods:POST, GET, OPTIONS, PUT, DELETE
  Access-Control-Allow-Origin:http://localhost:8383
  Access-Control-Max-Age:3600
  Content-Length:0
  Server:Jetty(8.1.8.v20121106)
  WWW-Authenticate:Basic realm="Cellnostics"
  </code></pre>
  
  <p>Has anyone got any idea what else I should do? I made sure to clear the Chrome cache before testing, restarting and ensuring that there were no background Chrome processes left running before restart, so I'm pretty sure that there were no lingering auth cache issues.</p>
  
  <p>I've had to switch to IE 11 for testing my web development. The fact that the same client and server setup still works for IE and Opera, and the fact that there is a history of Chrome/CORS bugs, makes me suspect Chrome.</p>
  
  <p>EDIT: Here's an extract from the Chrome net-internals event list:</p>
  
  <pre><code>t=108514 [st=0]   +URL_REQUEST_START_JOB  [dt=4]
      --&gt; load_flags = 336011264 (BYPASS_DATA_REDUCTION_PROXY | DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES | MAYBE_USER_GESTURE | VERIFY_EV_CERT)
      --&gt; method = "OPTIONS"
      --&gt; priority = "LOW"
      --&gt; url = "http://localhost:8081/cellnostics/rest/patient"
  ...
  t=108516 [st=2] HTTP_TRANSACTION_SEND_REQUEST_HEADERS
  --&gt; OPTIONS /cellnostics/rest/patient HTTP/1.1
     Host: localhost:8081
     Connection: keep-alive
     Access-Control-Request-Method: POST
     Origin: http://localhost:8383
     User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36
     Access-Control-Request-Headers: accept, content-type
     Accept: */*
     Referer: http://localhost:8383/celln-web/index.html
     Accept-Encoding: gzip,deflate,sdch
     Accept-Language: en-US,en;q=0.8,af;q=0.6
  </code></pre>
  
  <p>So it looks like the Authorization header is not sent with the OPTIONS pre-flight, even though I explicitly set <code>withCredentials = true</code>.</p>
  
  <p>However, why would IE and Opera still work? Is Chrome more standards-compliant in this regard? Why did it work and then start failing from v37?</p>
  
  <p>EDIT: Chrome dev tools does not show the <code>Content-Type</code> of the request in the dumps above, but here it is from the Network log. The first pic shows the POST when the server auth is disabled, with content type correctly sent as 'application/json'. The 2nd pic is when the auth is enabled, showing the OPTIONS request failing (it seems OPTIONS is always sent with content type 'text/plain'?).</p>
  
  <p><img src="https://i.stack.imgur.com/iDiAt.png" alt="CORS POST with NO auth on server">
  <img src="https://i.stack.imgur.com/Jucv6.png" alt="CORS POST with auth enabled on server"></p>