azure-functions-host: CORS broken for Linux consumption plans

I’m running a node Azure Functions app on a Linux consumption plan and since sometime over the weekend preflight requests have stopped reaching the corresponding HTTP triggers.

Investigative information

  • Function App version (1.0 or 2.0): 2.0
  • Invocation ID: I can’t provide invocation ID since I cannot see the request anywhere in the Azure Portal
  • Region: West Europe

Repro steps

Make a preflight request to any HTTP trigger, presumably on a Linux consumption plan. As an example:

curl -i '<any-azure-function-http-trigger-url>' -X OPTIONS -H 'Connection: keep-alive' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache'  -H 'Origin: <any-origin>' -H 'Access-Control-Request-Method: GET' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36' -H 'Access-Control-Request-Headers: authorization' -H 'Accept: */*' -H 'Sec-Fetch-Site: cross-site' -H 'Sec-Fetch-Mode: cors' -H 'Referer: <any-referrer>' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US,en;q=0.9,sv;q=0.8,la;q=0.7' --compressed

Expected behavior

I expect the request to reach my HTTP trigger where I can process it.

Actual behavior

The request never reaches the HTTP trigger. I can’t see the request in any Azure Portal monitoring tools.

I get a response that looks like this:

HTTP/1.1 204 No Content
Server: Kestrel
Request-Context: appId=<app-id>
Date: Mon, 04 Nov 2019 10:46:27 GMT

Known workarounds

No known workarounds. Tried using proxies.json to override headers, but the preflight request never reaches the proxies.

Related information

Removing any relevant preflight request header, such as Access-Control-Request-Method: GET makes the request successfully reach the corresponding HTTP trigger.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 24 (8 by maintainers)

Most upvoted comments

Definitely a bug in how we configured the CORS middleware. Opened a PR https://github.com/Azure/azure-functions-host/pull/5215 to fix this.

We should be able get this deployed sometime early next week.

@ericdrobinson @jacobgunnarsson Thanks for the patience and all the help investigating this.

thanks for all the details. investigating this more today and will update here soon.

Fix is deployed on all regions. Please give it a try (might need an app restart if the app has been running non-stop).

Our functions are working again. Not sure if this is falling back to our own CORS implementation or being handled properly by the host (likely the host, at this point). One way or the other, browsers are no longer dropping the responses due to incorrect CORS responses.

@balag0 thanks for the update. it seems like I might be having some other issue then. It is letting OPTIONS requests through, yntil i set an Origin header, then I get “empty headers”

Server: Kestrel
Request-Context: appId=cid-v1:xxxx
Date: Tue, 26 Nov 2019 09:55:42 GMT

Do I need to set anything but leaving all fields blank for CORS in the azure portal for it to work?

No CORS settings

@balag0 Our functions still aren’t working properly. We’re about two weeks with broken features now. Is there a useful ETA for a fix deployment that you can share?

Update: The build with the fix is available now, the plan is to include this change with the next scheduled release starting end of the week instead of doing an one off deployment today.

A simple way to get a browser to trigger the Preflight Request is to issue a request (XHR; Fetch) that includes a payload (body). This example (adapted from MDN’s Fetch API documentation) should do the trick:

const url = 'https://[someappname].azurewebsites.net/httptrigger';
const data = { username: 'example' };

try {
  const response = await fetch(url, {
    method: 'POST', // or 'PUT'
    body: JSON.stringify(data), // data can be `string` or {object}!
    headers: {
      'Content-Type': 'application/json'
    }
  });
  const json = await response.json();
  console.log('Success:', JSON.stringify(json));
} catch (error) {
  console.error('Error:', error);
}

Hopefully this is helpful.

@ericdrobinson thanks for looking into this in a bit more detail!

@balag0 thanks for your reply! Yes, the issue still persists. As I wrote before adding allowed origins through Azure CLI (or through the portal) properly adds the Access-Control-Allow-Origin header to the preflight response.

However, the issue is not wether or not the Access-Control-Allow-Origin header is present in the preflight response. The issue is that the rest of the required headers are missing, what about Access-Control-Request-Method or Access-Control-Allow-Headers? (or any of the other Access-Control-* headers, described here)

If the preflight request includes those headers but the response does not, the response is considered unsafe and is rejected by the browser.