From 358950d0c2c2b16568c50daa66212f1db920bf48 Mon Sep 17 00:00:00 2001 From: Ayrton Sparling Date: Tue, 26 Apr 2022 16:23:52 -0700 Subject: [PATCH 1/2] Better CORS support Current CORS support only adds an Access-Control-Allow-Origin header to some requests. It also does not support the OPTIONS preflight sent by modern browsers. This commit adds support for OPTIONS preflight as well as more CORS headers. The OPTIONS preflight is sent without any credentials attached to it so it mist take place before Authorization header processesing. Firefox 99 requires other access control headers like Access-Control-Allow-Headers be returned for a successful CORS interaction. Signed-off-by: Ayrton Sparling --- src/ustreamer/http/server.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/ustreamer/http/server.c b/src/ustreamer/http/server.c index ae91f0e..bdc1f86 100644 --- a/src/ustreamer/http/server.c +++ b/src/ustreamer/http/server.c @@ -76,7 +76,7 @@ server_s *server_init(stream_s *stream) { assert(!evthread_use_pthreads()); assert((run->base = event_base_new())); assert((run->http = evhttp_new(run->base))); - evhttp_set_allowed_methods(run->http, EVHTTP_REQ_GET|EVHTTP_REQ_HEAD); + evhttp_set_allowed_methods(run->http, EVHTTP_REQ_GET|EVHTTP_REQ_HEAD|EVHTTP_REQ_OPTIONS); return server; } @@ -218,6 +218,24 @@ void server_loop_break(server_s *server) { static int _http_preprocess_request(struct evhttp_request *request, server_s *server) { RUN(last_request_ts) = get_now_monotonic(); + if (server->allow_origin[0] != '\0') { + const char *request_header_cors_headers = evhttp_find_header(evhttp_request_get_input_headers(request), "Access-Control-Request-Headers"); + const char *request_header_cors_method = evhttp_find_header(evhttp_request_get_input_headers(request), "Access-Control-Request-Method"); + + ADD_HEADER("Access-Control-Allow-Origin", server->allow_origin); + ADD_HEADER("Access-Control-Allow-Credentials", "true"); + + if (request_header_cors_headers != NULL) + ADD_HEADER("Access-Control-Allow-Headers", request_header_cors_headers); + if (request_header_cors_method != NULL) + ADD_HEADER("Access-Control-Allow-Methods", request_header_cors_method); + } + + if (evhttp_request_get_command(request) == EVHTTP_REQ_OPTIONS) { + evhttp_send_reply(request, HTTP_OK, "OK", NULL); + return -1; + } + if (RUN(auth_token)) { const char *token = evhttp_find_header(evhttp_request_get_input_headers(request), "Authorization"); @@ -228,8 +246,8 @@ static int _http_preprocess_request(struct evhttp_request *request, server_s *se } } - if (evhttp_request_get_command(request) == EVHTTP_REQ_HEAD) { \ - evhttp_send_reply(request, HTTP_OK, "OK", NULL); \ + if (evhttp_request_get_command(request) == EVHTTP_REQ_HEAD) { + evhttp_send_reply(request, HTTP_OK, "OK", NULL); return -1; } @@ -464,9 +482,6 @@ static void _http_callback_snapshot(struct evhttp_request *request, void *v_serv assert((buf = evbuffer_new())); assert(!evbuffer_add(buf, (const void *)EX(frame->data), EX(frame->used))); - if (server->allow_origin[0] != '\0') { - ADD_HEADER("Access-Control-Allow-Origin", server->allow_origin); - } ADD_HEADER("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate, pre-check=0, post-check=0, max-age=0"); ADD_HEADER("Pragma", "no-cache"); ADD_HEADER("Expires", "Mon, 3 Jan 2000 12:34:56 GMT"); From 1460de95c1c6ce3ae65d729fe8668105fe17cd09 Mon Sep 17 00:00:00 2001 From: Ayrton Sparling Date: Thu, 28 Apr 2022 08:40:15 -0700 Subject: [PATCH 2/2] Add "better cors" to /stream http endpoint Signed-off-by: Ayrton Sparling --- src/ustreamer/http/server.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ustreamer/http/server.c b/src/ustreamer/http/server.c index bdc1f86..f7bd373 100644 --- a/src/ustreamer/http/server.c +++ b/src/ustreamer/http/server.c @@ -635,9 +635,23 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c if (client->need_initial) { assert(evbuffer_add_printf(buf, "HTTP/1.0 200 OK" RN)); + if (client->server->allow_origin[0] != '\0') { - assert(evbuffer_add_printf(buf, "Access-Control-Allow-Origin: %s" RN, client->server->allow_origin)); + const char *request_header_cors_headers = evhttp_find_header(evhttp_request_get_input_headers(client->request), "Access-Control-Request-Headers"); + const char *request_header_cors_method = evhttp_find_header(evhttp_request_get_input_headers(client->request), "Access-Control-Request-Method"); + + assert(evbuffer_add_printf(buf, + "Access-Control-Allow-Origin: %s" RN + "Access-Control-Allow-Credentials: true" RN, + client->server->allow_origin + )); + + if (request_header_cors_headers != NULL) + assert(evbuffer_add_printf(buf, "Access-Control-Allow-Headers: %s" RN, request_header_cors_headers)); + if (request_header_cors_method != NULL) + assert(evbuffer_add_printf(buf, "Access-Control-Allow-Methods: %s" RN, request_header_cors_method)); } + assert(evbuffer_add_printf(buf, "Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate, pre-check=0, post-check=0, max-age=0" RN "Pragma: no-cache" RN