From f08421a796436d14d07894ebd023566e7760a597 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 7 Sep 2022 11:15:09 +0200 Subject: [PATCH] Improve HTTP support (to better handle params) and redirect `/video` params --- cmd/camera-streamer/http.c | 28 +++++++++--------- output/http_h264.c | 2 +- output/http_hls.c | 8 +++--- output/http_jpeg.c | 2 +- util/http/http.c | 58 +++++++++++++++++++++++++++----------- util/http/http.h | 7 ++++- 6 files changed, 68 insertions(+), 37 deletions(-) diff --git a/cmd/camera-streamer/http.c b/cmd/camera-streamer/http.c index 458f51e..83452a0 100644 --- a/cmd/camera-streamer/http.c +++ b/cmd/camera-streamer/http.c @@ -71,19 +71,19 @@ void camera_http_option(http_worker_t *worker, FILE *stream) } http_method_t http_methods[] = { - { "GET /snapshot?", http_snapshot }, - { "GET /snapshot.jpg?", http_snapshot }, - { "GET /stream?", http_stream }, - { "GET /?action=snapshot", http_snapshot }, - { "GET /?action=stream", http_stream }, - { "GET /video?", http_detect_video }, - { "GET /video.html?", http_content, "text/html", html_video_html, 0, &html_video_html_len }, - { "GET /video.m3u8?", http_m3u8_video }, - { "GET /video.h264?", http_h264_video }, - { "GET /video.mkv?", http_mkv_video }, - { "GET /video.mp4?", http_mp4_video }, - { "POST /video?", http_webrtc_offer }, - { "GET /option?", camera_http_option }, - { "GET /?", http_content, "text/html", html_index_html, 0, &html_index_html_len }, + { "GET", "/snapshot", http_snapshot }, + { "GET", "/snapshot.jpg", http_snapshot }, + { "GET", "/stream", http_stream }, + { "GET", "/?action=snapshot", http_snapshot }, + { "GET", "/?action=stream", http_stream }, + { "GET", "/video", http_detect_video }, + { "GET", "/video.html", http_content, "text/html", html_video_html, 0, &html_video_html_len }, + { "GET", "/video.m3u8", http_m3u8_video }, + { "GET", "/video.h264", http_h264_video }, + { "GET", "/video.mkv", http_mkv_video }, + { "GET", "/video.mp4", http_mp4_video }, + { "POST", "/video", http_webrtc_offer }, + { "GET", "/option", camera_http_option }, + { "GET", "/", http_content, "text/html", html_index_html, 0, &html_index_html_len }, { } }; diff --git a/output/http_h264.c b/output/http_h264.c index a91adb4..52d62b4 100644 --- a/output/http_h264.c +++ b/output/http_h264.c @@ -18,7 +18,7 @@ static const char *const VIDEO_HEADER = buffer_lock_t *http_h264_buffer_for_res(http_worker_t *worker) { - if (strstr(worker->client_method, HTTP_LOW_RES_PARAM) && http_jpeg_lowres.buf_list) + if (strstr(worker->request_params, HTTP_LOW_RES_PARAM) && http_h264_lowres.buf_list) return &http_h264_lowres; else return &http_h264; diff --git a/output/http_hls.c b/output/http_hls.c index b61239f..9048fad 100644 --- a/output/http_hls.c +++ b/output/http_hls.c @@ -22,7 +22,7 @@ static const char *const LOCATION_REDIRECT = "HTTP/1.0 307 Temporary Redirect\r\n" "Access-Control-Allow-Origin: *\r\n" "Connection: close\r\n" - "Location: %s\r\n" + "Location: %s?%s\r\n" "\r\n"; void http_m3u8_video(struct http_worker_s *worker, FILE *stream) @@ -35,12 +35,12 @@ void http_detect_video(struct http_worker_s *worker, FILE *stream) { if (strstr(worker->user_agent, "Safari/") && !strstr(worker->user_agent, "Chrome/") && !strstr(worker->user_agent, "Chromium/")) { // Safari only supports m3u8 - fprintf(stream, LOCATION_REDIRECT, "video.m3u8"); + fprintf(stream, LOCATION_REDIRECT, "video.m3u8", worker->request_params); } else if (strstr(worker->user_agent, "Firefox/")) { // Firefox only supports mp4 - fprintf(stream, LOCATION_REDIRECT, "video.mp4"); + fprintf(stream, LOCATION_REDIRECT, "video.mp4", worker->request_params); } else { // Chrome offers best latency with mkv - fprintf(stream, LOCATION_REDIRECT, "video.mkv"); + fprintf(stream, LOCATION_REDIRECT, "video.mkv", worker->request_params); } } diff --git a/output/http_jpeg.c b/output/http_jpeg.c index a16632c..ded1cb3 100644 --- a/output/http_jpeg.c +++ b/output/http_jpeg.c @@ -22,7 +22,7 @@ static const char *const STREAM_BOUNDARY = "\r\n" buffer_lock_t *http_jpeg_buffer_for_res(http_worker_t *worker) { - if (strstr(worker->client_method, HTTP_LOW_RES_PARAM) && http_jpeg_lowres.buf_list) + if (strstr(worker->request_params, HTTP_LOW_RES_PARAM) && http_jpeg_lowres.buf_list) return &http_jpeg_lowres; else return &http_jpeg; diff --git a/util/http/http.c b/util/http/http.c index b84d901..d3a8b1c 100644 --- a/util/http/http.c +++ b/util/http/http.c @@ -56,21 +56,16 @@ error: void *http_enum_params(http_worker_t *worker, FILE *stream, http_param_fn fn, void *opaque) { - const char *params = strstr(worker->client_method, "?"); + const char *params = worker->request_params; if (!params) { return NULL; } void *ret = NULL; - char *start = strdup(params + 1); + char *start = strdup(params); char *string = start; char *option; - // Drop after ` ` - if ((option = strstr(start, " ")) != NULL) { - *option = 0; - } - while ((option = strsep(&string, "&")) != NULL) { char *value = option; char *key = strsep(&value, "="); @@ -99,6 +94,28 @@ static void http_process(http_worker_t *worker, FILE *stream) worker->user_agent[0] = 0; worker->content_length = -1; + + // request_uri + worker->request_method = worker->client_method; + + if ((worker->request_uri = strstr(worker->request_method, " ")) != NULL) { + *worker->request_uri++ = 0; + } else { + worker->request_uri = ""; + } + + if ((worker->request_version = strstr(worker->request_uri, " ")) != NULL) { + *worker->request_version++ = 0; + } else { + worker->request_version = ""; + } + + if ((worker->request_params = strstr(worker->request_uri, "?")) != NULL) { + *worker->request_params++ = 0; + } else { + worker->request_params = ""; + } + // Consume headers for(int i = 0; i < 50; i++) { char line[BUFSIZE]; @@ -118,21 +135,30 @@ static void http_process(http_worker_t *worker, FILE *stream) worker->current_method = NULL; - for (int i = 0; worker->methods[i].name; i++) { - const char *name = worker->methods[i].name; - int nlen = strlen(worker->methods[i].name); + for (int i = 0; worker->methods[i].method; i++) { + http_method_t *method = &worker->methods[i]; - if (strncmp(worker->client_method, name, nlen-1)) + if (strcmp(worker->request_method, method->method)) continue; - // allow last character to match `?` or ` ` - if (worker->client_method[nlen-1] == name[nlen-1] || (name[nlen-1] == '?' && worker->client_method[nlen-1] == ' ')) { - worker->current_method = &worker->methods[i]; - break; + const char *params = strstr(method->uri, "?"); + + if (params) { + // match request_uri and params + if (strncmp(worker->request_uri, method->uri, params - method->uri)) + continue; + if (!strstr(worker->request_params, params+1)) + continue; + } else { + if (strcmp(worker->request_uri, method->uri)) + continue; } + + worker->current_method = &worker->methods[i]; + break; } - LOG_INFO(worker, "Request '%s'", worker->client_method); + LOG_INFO(worker, "Request '%s' '%s' '%s'", worker->request_method, worker->request_uri, worker->request_params); if (worker->current_method) { worker->current_method->func(worker, stream); diff --git a/util/http/http.h b/util/http/http.h index f4cb056..aa465b1 100644 --- a/util/http/http.h +++ b/util/http/http.h @@ -16,7 +16,8 @@ typedef void *(*http_param_fn)(struct http_worker_s *worker, FILE *stream, const #define BUFSIZE 256 typedef struct http_method_s { - const char *name; + const char *method; + const char *uri; http_method_fn func; const char *content_type; const void *content_body; @@ -37,6 +38,10 @@ typedef struct http_worker_s { char client_method[BUFSIZE]; char range_header[BUFSIZE]; char user_agent[BUFSIZE]; + char *request_method; + char *request_uri; + char *request_params; + char *request_version; http_method_t *current_method; } http_worker_t;