schollz / find

High-precision indoor positioning framework for most wifi-enabled devices.
https://www.internalpositioning.com/
GNU Affero General Public License v3.0
5.05k stars 368 forks source link

CORS prevents DELETE calls via XHR #150

Open TilBlechschmidt opened 7 years ago

TilBlechschmidt commented 7 years ago

When sending an HTTP request to the /locations or /location endpoint with the DELETE method using JavaScript the browser sends an HTTP OPTIONS request to ask the server whether or not this type of method is allowed for that specific endpoint. Since the FIND server apparently doesn't know how to handle this type of request it simply returns the dashboard page which (obviously) doesn't contain the appropriate header to tell the client's browser that the DELETE request it is going to make is actually valid.

This all is 'again' part of the Cross-Origin resource sharing specification that made up for some problems a few days ago. The solution would be to integrate a server-side check for requests using the OPTIONS method and returning a list of valid request types (for /locations this would be DELETE and GET if I am not mistaken).

To give an example of such a header:

Access-Control-Allow-Origin *
Access-Control-Allow-Methods GET, DELETE
Access-Control-Allow-Headers accept, content-type

For more detail please consider taking a look at this post over at StackOverflow.

Note that the documentation only contains /locations as a valid DELETE request endpoint but the dashboard actually uses /location with different parameters

schollz commented 7 years ago

Thanks, I forgot to Allow the DELETE method. Added it here: https://github.com/schollz/find/commit/e63c654731550b68b322484ebcf77920d52a46b3.

Let me know if that works.

TilBlechschmidt commented 7 years ago

img-2017-02-21-134957 img-2017-02-21-135006 It does not work. I assume it's because the Access-Control-Allow-Methods header is only set for the actual delete request but the browser is sending an OPTIONS request beforehand and expects the header to be present. Instead, the server returns the index page (I assume that's because this is the fallback and the OPTIONS request method is not implemented).

So you'd have to filter out OPTIONS requests, then send the appropriate header as a response and then the browser runs another request with the actual DELETE method after it verified that the DELETE method is actually allowed (that's how I understood it).

schollz commented 7 years ago

Thanks, I just added OPTIONS as well: https://github.com/schollz/find/commit/75a126ed1a99c8f630ebb2e7465911480f15ea5d

TilBlechschmidt commented 7 years ago

Still doesn't work. I assume that the problem is not that the header you modified doesn't contain the OPTIONS method but instead it's how the FIND HTTP server reacts to an HTTP request with the OPTIONS method since it simply returns the dashboard instead of returning a response with an Access-Control-Allow-Methods header set.

My assumption is (haven't read through the code though since I'm not that much into Go) that you've got a switch statement or if block that filters out the path that the request comes in at and whether or not the method it uses is actually correct for that specific API endpoint. Since the /locations endpoint is of the DELETE type and not of the OPTIONS type that switch/if block just goes through into the default which appears to be the dashboard.

You have to take into consideration that OPTIONS is a totally different request type similar to how POST, DELETE and GET are.

schollz commented 7 years ago

How are you testing it?

TilBlechschmidt commented 7 years ago

I set up the socket by running the following commands in the browser console:

var xmlHttp = new XMLHttpRequest();
xmlHttp.open("DELETE", "http://localhost:18003/location?group=something&location=somethingElse", true);

then initiating the actual request by running the following:

xmlHttp.send();

which then results in

XMLHttpRequest cannot load http://localhost:18003/location?group=something&location=somethingElse. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.

You have to remember that the code above triggers a request of the OPTIONS type first and then (if that went successfully, which in this case it didn't) sends the actual DELETE request that we are attempting to initiate with the above code. That's due to the aforementioned CORS specs...

Note though that this URL endpoint is grabbed directly from the dashboard (since it uses that) but it doesn't matter the /locations?group=something&names=somethingElse one is not working either for me. The one I used in the code example is not documented maybe that's something worth fixing.