Skip to content
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

OPTIONS not working in cowboy_rest #1600

Closed
stephb9959 opened this issue Jan 31, 2023 · 4 comments
Closed

OPTIONS not working in cowboy_rest #1600

stephb9959 opened this issue Jan 31, 2023 · 4 comments

Comments

@stephb9959
Copy link

We are seeing a problem with cowboy 2.9, erl 25, running cowboy_rest.

When doing theoptions method, the client complains that the stream was not closed cleanly, and therefore does not complete, which generates pre-flight validation errors in the browser using the app. We are using TLS and these are real certs (not self-signed). The same certs are working on the same host in a C++ version of the code. We have implemented our own options callback, so we can add CORS headers to the response. (we do the same in our C++ implementation).

This code was working about 2,5 years ago with the version of cowboy at that time. We did not keep the exact version of cowboy a that time (just kept master).

We see the same problem if we use curl to generate the options method.

Are we missing some new options in cowboy:start_tls ?

@essen
Copy link
Member

essen commented Jan 31, 2023

Probably not. Please provide some code (options callback and/or how the response is sent) and error messages from curl -vvv.

@stephb9959
Copy link
Author

Here is the options callback:

options(Req, State) ->
	Req1 = utils:add_cors(Req,<<"GET, POST, OPTIONS">>),
	io:format("Doing options (2): ~p~n",[Req1]),
	{ok, Req1, State}.

( the io:format is there to see that the code is being called)

here is the code for add_cors()

add_cors(Req0, Methods) ->
	Req1 = cowboy_req:set_resp_header(<<"Access-Control-Allow-Credentials">>, <<"true">>, Req0),
	Req2 = cowboy_req:set_resp_header(<<"Access-Control-Request-Headers">>, <<"*">>, Req1),
	Req3 = cowboy_req:set_resp_header(<<"Access-Control-Allow-Origin">>, <<"*">>, Req2),
	Req4 = cowboy_req:set_resp_header(<<"Vary">>, <<"Origin, Accept-Encoding">>, Req3),
	Req5 = cowboy_req:set_resp_header(<<"Access-Control-Allow-Methods">>, Methods, Req4),
	cowboy_req:set_resp_header(<<"Access-Control-Max-Age">>, <<"20">>, Req5).

These same CORS values work on C++ using the Poco framework.

This is the result for running curl

$ curl -vvv -X OPTIONS "https://ucentral.dpaas.arilia.com:16063/api/v1/system?info"
*   Trying 2600:1f13:f7c:6501:9312:c5c6:40f:c842:16063...
* connect to 2600:1f13:f7c:6501:9312:c5c6:40f:c842 port 16063 failed: Connection refused
*   Trying 34.222.8.211:16063...
* Connected to ucentral.dpaas.arilia.com (34.222.8.211) port 16063 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=*.dpaas.arilia.com
*  start date: Jan 24 00:00:00 2023 GMT
*  expire date: Feb 11 23:59:59 2024 GMT
*  subjectAltName: host "ucentral.dpaas.arilia.com" matched cert's "*.dpaas.arilia.com"
*  issuer: C=GB; ST=Greater Manchester; L=Salford; O=Sectigo Limited; CN=Sectigo RSA Domain Validation Secure Server CA
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* h2h3 [:method: OPTIONS]
* h2h3 [:path: /api/v1/system?info]
* h2h3 [:scheme: https]
* h2h3 [:authority: ucentral.dpaas.arilia.com:16063]
* h2h3 [user-agent: curl/7.85.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x14280a800)
> OPTIONS /api/v1/system?info HTTP/2
> Host: ucentral.dpaas.arilia.com:16063
> user-agent: curl/7.85.0
> accept: */*
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 4294967295)!
* HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* Connection #0 to host ucentral.dpaas.arilia.com left intact
curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)

Thanks for your help.

@essen
Copy link
Member

essen commented Feb 1, 2023

The header names have to be given as lowercase. Cowboy doesn't lowercase them, it expects you to provide them already lowercase. Since it's using HTTP/2 and uppercase header names are forbidden in HTTP/2 that's probably the issue.

@stephb9959
Copy link
Author

Thanks @essen, changing the casing to lowercase has fixed the pre-flight. We are still seeing CORS issues but we've made progress. I was not aware of this lower-case HTTP/2 spec. I also see why our C++ framework worked: it only does HTTP1.1. So it all fits together neatly now.

I really appreciate your help.

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

No branches or pull requests

2 participants