Skip to content

fix: Allow OPTIONS method on every path #268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

celian-garcia
Copy link

@celian-garcia celian-garcia commented Feb 4, 2025

Hello,
We are making cross origin requests from the browser, and it seems the browser executes some OPTIONS requests on top.

The CORS specification is implemented in the browser and server, allowing web applications to make cross-origin requests. The specification also defines how a browser should handle these requests and how servers should respond.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS#preflighted_requests_in_cors

In CORS, a preflight request is sent with the OPTIONS method so that the server can respond if it is acceptable to send the request. In this example, we will request permission for these parameters:

So I'm proposing this PR to let pass these OPTIONS queries.

@celian-garcia celian-garcia marked this pull request as ready for review February 4, 2025 16:52
@celian-garcia celian-garcia marked this pull request as draft February 5, 2025 09:08
@celian-garcia
Copy link
Author

celian-garcia commented Feb 5, 2025

Converting it back to draft as it seems the OPTIONS proxy query doesn't have the cors response headers while
OPTIONS and GET upstream queries do, and GET proxy queries do as well.

proxy OPTIONS query

curl -iv -X OPTIONS "http://localhost:4444/api/v1/query"
* Host localhost:4444 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:4444...
* Connected to localhost (::1) port 4444
> OPTIONS /api/v1/query HTTP/1.1
> Host: localhost:4444
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Date: Wed, 05 Feb 2025 09:04:35 GMT
Date: Wed, 05 Feb 2025 09:04:35 GMT
< Content-Length: 0
Content-Length: 0
< 

upstream OPTIONS queries

curl -iv -X OPTIONS "http://localhost:19000/api/v1/query"
* Host localhost:19000 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:19000...
* Connected to localhost (::1) port 19000
> OPTIONS /api/v1/query HTTP/1.1
> Host: localhost:19000
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 204 No Content
HTTP/1.1 204 No Content
< Access-Control-Allow-Headers: Accept, Accept-Encoding, Authorization, Content-Type, Origin
Access-Control-Allow-Headers: Accept, Accept-Encoding, Authorization, Content-Type, Origin
< Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Methods: GET, OPTIONS
< Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: Date
Access-Control-Expose-Headers: Date
< Date: Wed, 05 Feb 2025 08:24:17 GMT
Date: Wed, 05 Feb 2025 08:24:17 GMT
< Vary: Accept-Encoding
Vary: Accept-Encoding
< 

* Connection #0 to host localhost left intact

Edit: I found the issue. The browser executes an OPTIONS request on /api/v1/query path, with no query in params. The query handler doesn't like when no query in params... so I updated the enforceMethods to execute the passthrough in case of OPTIONS method, which is far less intrusive.

=> proxy OPTIONS query

curl -iv -X OPTIONS "http://localhost:4444/api/v1/query"
* Host localhost:4444 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:4444...
* Connected to localhost (::1) port 4444
> OPTIONS /api/v1/query HTTP/1.1
> Host: localhost:4444
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 204 No Content
HTTP/1.1 204 No Content
< Access-Control-Allow-Headers: Accept, Accept-Encoding, Authorization, Content-Type, Origin
Access-Control-Allow-Headers: Accept, Accept-Encoding, Authorization, Content-Type, Origin
< Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Methods: GET, OPTIONS
< Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: Date
Access-Control-Expose-Headers: Date
< Date: Wed, 05 Feb 2025 09:11:21 GMT
Date: Wed, 05 Feb 2025 09:11:21 GMT
< Vary: Accept-Encoding
Vary: Accept-Encoding
< 

* Connection #0 to host localhost left intact

@celian-garcia celian-garcia marked this pull request as ready for review February 5, 2025 10:18
@Nexucis
Copy link

Nexucis commented Feb 11, 2025

That sounds reasonable to me. But I don't know much about this code, @simonpasquier are you ok with this change ?

@squat
Copy link
Member

squat commented Feb 11, 2025

@celian-garcia could you please include tests so that we document our intentions here? Otherwise I'm sure that passing CORS requests will regress without anyone noticing since we are not validating.

@celian-garcia
Copy link
Author

@celian-garcia could you please include tests so that we document our intentions here? Otherwise I'm sure that passing CORS requests will regress without anyone noticing since we are not validating.

Thanks @squat, good idea indeed! Adding the tests I realized that it's working only if I'm using the StaticLabelEnforcer, via labelValues argument. It works in my case but if some people want to use the query param enforcer, they will face an issue as the browser don't set query param in their OPTIONS queries.

@squat
Copy link
Member

squat commented Feb 11, 2025

@celian-garcia can you elaborate?

If the solution is just passing through all OPTIONS requests, why does it matter if the query is in the query parameters or not? Why would this be a problem for CORS users not using the StaticLabelEnforcer?

I'm still a little bit paranoid that this might lead to a leak.

@celian-garcia
Copy link
Author

Hi @squat sorry, I checked twice and the query string is actually sent by the OPTIONS request as well. I thought wrongly that the browser was removing query params but that's not true.

So no issue. Enforcers will well reject bad request and accept good requests, being any http method.

@celian-garcia
Copy link
Author

celian-garcia commented Feb 14, 2025

@squat another concern? This is really allowing only the OPTIONS requests to passthrough here. Used only for CORS and supported already by thanos, prometheus and alertmanager.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS

@celian-garcia
Copy link
Author

@squat @simonpasquier ?

@celian-garcia
Copy link
Author

@squat can we have an update? We're running from our fork here and I would like to align

@celian-garcia
Copy link
Author

@simonpasquier you merged a dep last week. Do you have an opinion on that? 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants