diff --git a/src/Makefile.am b/src/Makefile.am index fa01a0a9..00c0f83a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -92,14 +92,14 @@ owntone_SOURCES = main.c \ library.c library.h \ $(MDNS_SRC) mdns.h \ remote_pairing.c remote_pairing.h \ - httpd.c httpd.h \ - httpd_rsp.c httpd_rsp.h \ + httpd.c httpd.h httpd_internal.h \ + httpd_rsp.c \ httpd_daap.c httpd_daap.h \ - httpd_dacp.c httpd_dacp.h \ - httpd_jsonapi.c httpd_jsonapi.h \ + httpd_dacp.c \ + httpd_jsonapi.c \ httpd_streaming.c httpd_streaming.h \ - httpd_oauth.c httpd_oauth.h \ - httpd_artworkapi.c httpd_artworkapi.h \ + httpd_oauth.c \ + httpd_artworkapi.c \ http.c http.h \ dmap_common.c dmap_common.h \ transcode.c transcode.h \ diff --git a/src/httpd.c b/src/httpd.c index 79e149b2..4d2b102b 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -52,13 +52,7 @@ #include "misc.h" #include "worker.h" #include "httpd.h" -#include "httpd_rsp.h" -#include "httpd_daap.h" -#include "httpd_dacp.h" -#include "httpd_jsonapi.h" -#include "httpd_streaming.h" -#include "httpd_oauth.h" -#include "httpd_artworkapi.h" +#include "httpd_internal.h" #include "transcode.h" #ifdef LASTFM # include "lastfm.h" @@ -67,7 +61,6 @@ # include "websocket.h" #endif - #define STREAM_CHUNK_SIZE (64 * 1024) #define ERR_PAGE "\n\n" \ "%d %s\n" \ @@ -79,6 +72,26 @@ #define HTTPD_STREAM_BPS 16 #define HTTPD_STREAM_CHANNELS 2 +extern struct httpd_module httpd_dacp; +extern struct httpd_module httpd_daap; +extern struct httpd_module httpd_jsonapi; +extern struct httpd_module httpd_artworkapi; +extern struct httpd_module httpd_streaming; +extern struct httpd_module httpd_oauth; +extern struct httpd_module httpd_rsp; + +// Must be in sync with enum httpd_modules +static struct httpd_module *httpd_modules[] = { + &httpd_dacp, + &httpd_daap, + &httpd_jsonapi, + &httpd_artworkapi, + &httpd_streaming, + &httpd_oauth, + &httpd_rsp, + NULL +}; + struct content_type_map { char *ext; @@ -114,8 +127,6 @@ static const struct content_type_map ext2ctype[] = { NULL, NULL } }; -static const char *http_reply_401 = "401 UnauthorizedAuthorization required"; - static char webroot_directory[PATH_MAX]; struct event_base *evbase_httpd; @@ -161,98 +172,125 @@ scrobble_cb(void *arg) } #endif -/* - * This disabled in the commit after d8cdc89 because my tests work fine without - * it, and it seems that nowadays iTunes and Remote encodes the query just fine. - * However, I'm keeping it around for a while in case problems show up. If you - * are from the future, you can probably safely remove it for good. - * -static char * -httpd_fixup_uri(struct evhttp_request *req) + +/* --------------------------- MODULES INTERFACE ---------------------------- */ + +static void +modules_handlers_unset(struct httpd_uri_map *uri_map) { - struct evkeyvalq *headers; - const char *ua; - const char *uri; - const char *u; - const char *q; - char *fixed; - char *f; - int len; + struct httpd_uri_map *uri; - uri = evhttp_request_get_uri(req); - if (!uri) - return NULL; - - // No query string, nothing to do - q = strchr(uri, '?'); - if (!q) - return strdup(uri); - - headers = evhttp_request_get_input_headers(req); - ua = evhttp_find_header(headers, "User-Agent"); - if (!ua) - return strdup(uri); - - if ((strncmp(ua, "iTunes", strlen("iTunes")) != 0) - && (strncmp(ua, "Remote", strlen("Remote")) != 0) - && (strncmp(ua, "Roku", strlen("Roku")) != 0)) - return strdup(uri); - - // Reencode + as %2B and space as + in the query, - // which iTunes and Roku devices don't do - len = strlen(uri); - - u = q; - while (*u) + for (uri = uri_map; uri->preg; uri++) { - if (*u == '+') - len += 2; - - u++; + regfree(uri->preg); // Frees allocation by regcomp + free(uri->preg); // Frees our own calloc } +} - fixed = (char *)malloc(len + 1); - if (!fixed) - return NULL; +static int +modules_handlers_set(struct httpd_uri_map *uri_map) +{ + struct httpd_uri_map *uri; + char buf[64]; + int ret; - strncpy(fixed, uri, q - uri); - - f = fixed + (q - uri); - while (*q) + for (uri = uri_map; uri->handler; uri++) { - switch (*q) + uri->preg = calloc(1, sizeof(regex_t)); + if (!uri->preg) { - case '+': - *f = '%'; - f++; - *f = '2'; - f++; - *f = 'B'; - break; - - case ' ': - *f = '+'; - break; - - default: - *f = *q; - break; + DPRINTF(E_LOG, L_HTTPD, "Error setting URI handler, out of memory"); + goto error; } - q++; - f++; + ret = regcomp(uri->preg, uri->regexp, REG_EXTENDED | REG_NOSUB); + if (ret != 0) + { + regerror(ret, uri->preg, buf, sizeof(buf)); + DPRINTF(E_LOG, L_HTTPD, "Error setting URI handler, regexp error: %s\n", buf); + goto error; + } } - *f = '\0'; + return 0; - return fixed; + error: + modules_handlers_unset(uri_map); + return -1; +} + +static int +modules_init(void) +{ + struct httpd_module **ptr; + struct httpd_module *m; + + for (ptr = httpd_modules; *ptr; ptr++) + { + m = *ptr; + m->initialized = (!m->init || m->init() == 0); + if (!m->initialized) + { + DPRINTF(E_FATAL, L_HTTPD, "%s init failed\n", m->name); + return -1; + } + + if (modules_handlers_set(m->handlers) != 0) + { + DPRINTF(E_FATAL, L_HTTPD, "%s handler configuration failed\n", m->name); + return -1; + } + } + + return 0; +} + +static void +modules_deinit(void) +{ + struct httpd_module **ptr; + struct httpd_module *m; + + for (ptr = httpd_modules; *ptr; ptr++) + { + m = *ptr; + if (m->initialized && m->deinit) + m->deinit(); + + modules_handlers_unset(m->handlers); + } +} + +static struct httpd_module * +modules_search(const char *path) +{ + struct httpd_module **ptr; + struct httpd_module *m; + const char **test; + bool is_found = false; + + for (ptr = httpd_modules; *ptr; ptr++) + { + m = *ptr; + if (!m->subpaths || !m->request) + continue; + + for (test = m->subpaths; *test && !is_found; test++) + is_found = (strncmp(path, *test, strlen(*test)) == 0); + + for (test = m->fullpaths; *test && !is_found; test++) + is_found = (strcmp(path, *test) == 0); + + if (is_found) + return m; + } + + return NULL; } -*/ /* --------------------------- REQUEST HELPERS ------------------------------ */ - void httpd_redirect_to(struct evhttp_request *req, const char *path) { @@ -745,7 +783,9 @@ httpd_gen_cb(struct evhttp_request *req, void *arg) { struct evkeyvalq *input_headers; struct evkeyvalq *output_headers; + struct httpd_request hreq; struct httpd_uri_parsed *parsed; + struct httpd_module *m; const char *uri; // Clear the proxy request flag set by evhttp if the request URI was absolute. @@ -790,40 +830,11 @@ httpd_gen_cb(struct evhttp_request *req, void *arg) goto serve_file; } - /* Dispatch protocol-specific handlers */ - if (dacp_is_request(parsed->path)) + m = modules_search(parsed->path); + if (m) { - dacp_request(req, parsed); - goto out; - } - else if (daap_is_request(parsed->path)) - { - daap_request(req, parsed); - goto out; - } - else if (jsonapi_is_request(parsed->path)) - { - jsonapi_request(req, parsed); - goto out; - } - else if (artworkapi_is_request(parsed->path)) - { - artworkapi_request(req, parsed); - goto out; - } - else if (streaming_is_request(parsed->path)) - { - streaming_request(req, parsed); - goto out; - } - else if (oauth_is_request(parsed->path)) - { - oauth_request(req, parsed); - goto out; - } - else if (rsp_is_request(parsed->path)) - { - rsp_request(req, parsed); + httpd_request_parse(&hreq, req, parsed, NULL, m->handlers); + m->request(&hreq); goto out; } @@ -941,20 +952,21 @@ httpd_uri_parse(const char *uri) return NULL; } -struct httpd_request * -httpd_request_parse(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed, const char *user_agent, struct httpd_uri_map *uri_map) +int +httpd_request_parse(struct httpd_request *hreq, struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed, const char *user_agent, struct httpd_uri_map *uri_map) { - struct httpd_request *hreq; + ; struct evhttp_connection *evcon; struct evkeyvalq *headers; struct httpd_uri_map *uri; int req_method; int ret; - CHECK_NULL(L_HTTPD, hreq = calloc(1, sizeof(struct httpd_request))); + memset(hreq, 0, sizeof(struct httpd_request)); // Note req is allowed to be NULL hreq->req = req; + hreq->uri = uri_parsed->uri; hreq->uri_parsed = uri_parsed; hreq->query = &(uri_parsed->ev_query); req_method = 0; @@ -988,58 +1000,13 @@ httpd_request_parse(struct evhttp_request *req, struct httpd_uri_parsed *uri_par continue; hreq->handler = uri->handler; - return hreq; // Success + return 0; // Success } // Handler not found, that's an error - free(hreq); - return NULL; -} - -int -httpd_handlers_set(struct httpd_uri_map *uri_map) -{ - struct httpd_uri_map *uri; - char buf[64]; - int ret; - - for (uri = uri_map; uri->handler; uri++) - { - uri->preg = calloc(1, sizeof(regex_t)); - if (!uri->preg) - { - DPRINTF(E_LOG, L_HTTPD, "Error setting URI handler, out of memory"); - goto error; - } - - ret = regcomp(uri->preg, uri->regexp, REG_EXTENDED | REG_NOSUB); - if (ret != 0) - { - regerror(ret, uri->preg, buf, sizeof(buf)); - DPRINTF(E_LOG, L_HTTPD, "Error setting URI handler, regexp error: %s\n", buf); - goto error; - } - } - - return 0; - - error: - httpd_handlers_unset(uri_map); return -1; } -void -httpd_handlers_unset(struct httpd_uri_map *uri_map) -{ - struct httpd_uri_map *uri; - - for (uri = uri_map; uri->preg; uri++) - { - regfree(uri->preg); // Frees allocation by regcomp - free(uri->preg); // Frees our own calloc - } -} - /* Thread: httpd */ void httpd_stream_file(struct evhttp_request *req, int id) @@ -1631,7 +1598,7 @@ httpd_basic_auth(struct evhttp_request *req, const char *user, const char *passw headers = evhttp_request_get_output_headers(req); evhttp_add_header(headers, "WWW-Authenticate", header); - evbuffer_add(evbuf, http_reply_401, strlen(http_reply_401)); + evbuffer_add_printf(evbuf, ERR_PAGE, 401, "Unauthorized", "Authorization required"); httpd_send_reply(req, 401, "Unauthorized", evbuf, HTTPD_SEND_NO_GZIP); @@ -1678,54 +1645,6 @@ httpd_init(const char *webroot) return -1; } - ret = rsp_init(); - if (ret < 0) - { - DPRINTF(E_FATAL, L_HTTPD, "RSP protocol init failed\n"); - - goto rsp_fail; - } - - ret = daap_init(); - if (ret < 0) - { - DPRINTF(E_FATAL, L_HTTPD, "DAAP protocol init failed\n"); - - goto daap_fail; - } - - ret = dacp_init(); - if (ret < 0) - { - DPRINTF(E_FATAL, L_HTTPD, "DACP protocol init failed\n"); - - goto dacp_fail; - } - - ret = jsonapi_init(); - if (ret < 0) - { - DPRINTF(E_FATAL, L_HTTPD, "JSON api init failed\n"); - - goto jsonapi_fail; - } - - ret = artworkapi_init(); - if (ret < 0) - { - DPRINTF(E_FATAL, L_HTTPD, "Artwork init failed\n"); - - goto artworkapi_fail; - } - - ret = oauth_init(); - if (ret < 0) - { - DPRINTF(E_FATAL, L_HTTPD, "OAuth init failed\n"); - - goto oauth_fail; - } - #ifdef HAVE_LIBWEBSOCKETS ret = websocket_init(); if (ret < 0) @@ -1736,7 +1655,13 @@ httpd_init(const char *webroot) } #endif - streaming_init(); + ret = modules_init(); + if (ret < 0) + { + DPRINTF(E_FATAL, L_HTTPD, "Modules init failed\n"); + + goto modules_fail; + } #ifdef HAVE_EVENTFD exit_efd = eventfd(0, EFD_CLOEXEC); @@ -1825,23 +1750,12 @@ httpd_init(const char *webroot) close(exit_pipe[1]); #endif pipe_fail: - streaming_deinit(); + modules_fail: + modules_deinit(); #ifdef HAVE_LIBWEBSOCKETS websocket_deinit(); websocket_fail: #endif - oauth_deinit(); - oauth_fail: - artworkapi_deinit(); - artworkapi_fail: - jsonapi_deinit(); - jsonapi_fail: - dacp_deinit(); - dacp_fail: - daap_deinit(); - daap_fail: - rsp_deinit(); - rsp_fail: event_base_free(evbase_httpd); return -1; @@ -1881,15 +1795,11 @@ httpd_deinit(void) return; } - streaming_deinit(); + modules_deinit(); + #ifdef HAVE_LIBWEBSOCKETS websocket_deinit(); #endif - oauth_deinit(); - jsonapi_deinit(); - rsp_deinit(); - dacp_deinit(); - daap_deinit(); #ifdef HAVE_EVENTFD close(exit_efd); diff --git a/src/httpd.h b/src/httpd.h index 9339aae8..49e336b7 100644 --- a/src/httpd.h +++ b/src/httpd.h @@ -44,6 +44,8 @@ struct httpd_uri_parsed struct httpd_request { // User-agent (if available) const char *user_agent; + // TODO + const char *uri; // The parsed request URI given to us by httpd_uri_parse struct httpd_uri_parsed *uri_parsed; // Shortcut to &uri_parsed->ev_query @@ -87,20 +89,13 @@ struct httpd_uri_parsed * httpd_uri_parse(const char *uri); /* - * Parse a request into the httpd_request struct. It can later be freed with - * free(), unless the module has allocated something to *extra_data. Note that - * the pointers in the returned struct are only valid as long as the inputs are + * Parse a request into the httpd_request struct. Nothing is copied, so the + * pointers in the returned struct are only valid as long as the inputs are * still valid. If req is not null, then we will find the user-agent from the * request headers, except if provided as an argument to this function. */ -struct httpd_request * -httpd_request_parse(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed, const char *user_agent, struct httpd_uri_map *uri_map); - int -httpd_handlers_set(struct httpd_uri_map *uri_map); - -void -httpd_handlers_unset(struct httpd_uri_map *uri_map); +httpd_request_parse(struct httpd_request *hreq, struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed, const char *user_agent, struct httpd_uri_map *uri_map); void httpd_stream_file(struct evhttp_request *req, int id); diff --git a/src/httpd_artworkapi.c b/src/httpd_artworkapi.c index f52de8c0..61cca7a9 100644 --- a/src/httpd_artworkapi.c +++ b/src/httpd_artworkapi.c @@ -25,7 +25,7 @@ #include #include -#include "httpd_artworkapi.h" +#include "httpd_internal.h" #include "logger.h" #include "misc.h" #include "player.h" @@ -149,23 +149,22 @@ static struct httpd_uri_map artworkapi_handlers[] = /* ------------------------------- API --------------------------------- */ -void -artworkapi_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) + +static void +artworkapi_request(struct httpd_request *hreq) { - struct httpd_request *hreq; int status_code; - DPRINTF(E_DBG, L_WEB, "Artwork api request: '%s'\n", uri_parsed->uri); + DPRINTF(E_DBG, L_WEB, "Artwork api request: '%s'\n", hreq->uri); - if (!httpd_admin_check_auth(req)) + if (!httpd_admin_check_auth(hreq->req)) return; - hreq = httpd_request_parse(req, uri_parsed, NULL, artworkapi_handlers); - if (!hreq) + if (!hreq->handler) { - DPRINTF(E_LOG, L_WEB, "Unrecognized path '%s' in artwork api request: '%s'\n", uri_parsed->path, uri_parsed->uri); + DPRINTF(E_LOG, L_WEB, "Unrecognized path in artwork api request: '%s'\n", hreq->uri); - httpd_send_error(req, HTTP_BADREQUEST, "Bad Request"); + httpd_send_error(hreq->req, HTTP_BADREQUEST, "Bad Request"); return; } @@ -176,48 +175,33 @@ artworkapi_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_pars switch (status_code) { case HTTP_OK: /* 200 OK */ - httpd_send_reply(req, status_code, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq->req, status_code, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); break; case HTTP_NOCONTENT: /* 204 No Content */ - httpd_send_reply(req, status_code, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq->req, status_code, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); break; case HTTP_NOTMODIFIED: /* 304 Not Modified */ - httpd_send_reply(req, HTTP_NOTMODIFIED, NULL, NULL, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq->req, HTTP_NOTMODIFIED, NULL, NULL, HTTPD_SEND_NO_GZIP); break; case HTTP_BADREQUEST: /* 400 Bad Request */ - httpd_send_error(req, status_code, "Bad Request"); + httpd_send_error(hreq->req, status_code, "Bad Request"); break; case HTTP_NOTFOUND: /* 404 Not Found */ - httpd_send_error(req, status_code, "Not Found"); + httpd_send_error(hreq->req, status_code, "Not Found"); break; case HTTP_INTERNAL: /* 500 Internal Server Error */ default: - httpd_send_error(req, HTTP_INTERNAL, "Internal Server Error"); + httpd_send_error(hreq->req, HTTP_INTERNAL, "Internal Server Error"); } evbuffer_free(hreq->reply); - free(hreq); } -int -artworkapi_is_request(const char *path) +struct httpd_module httpd_artworkapi = { - if (strncmp(path, "/artwork/", strlen("/artwork/")) == 0) - return 1; - - return 0; -} - -int -artworkapi_init(void) -{ - CHECK_ERR(L_WEB, httpd_handlers_set(artworkapi_handlers)); - - return 0; -} - -void -artworkapi_deinit(void) -{ - httpd_handlers_unset(artworkapi_handlers); -} + .name = "Artwork API", + .type = MODULE_ARTWORKAPI, + .subpaths = { "/artwork/", NULL }, + .handlers = artworkapi_handlers, + .request = artworkapi_request, +}; diff --git a/src/httpd_artworkapi.h b/src/httpd_artworkapi.h deleted file mode 100644 index 7c7163c5..00000000 --- a/src/httpd_artworkapi.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __HTTPD_ARTWORK_H__ -#define __HTTPD_ARTWORK_H__ - -#include "httpd.h" - -int -artworkapi_init(void); - -void -artworkapi_deinit(void); - -void -artworkapi_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed); - -int -artworkapi_is_request(const char *path); - -#endif diff --git a/src/httpd_daap.c b/src/httpd_daap.c index 49b16e89..e6663802 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -43,6 +43,7 @@ #include +#include "httpd_internal.h" #include "httpd_daap.h" #include "logger.h" #include "db.h" @@ -2224,10 +2225,9 @@ static struct httpd_uri_map daap_handlers[] = * iTunes 12.1 gives us an absolute request-uri for streaming like * http://10.1.1.20:3689/databases/1/items/1.mp3 */ -void -daap_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) +static void +daap_request(struct httpd_request *hreq) { - struct httpd_request *hreq; struct evkeyvalq *headers; struct timespec start; struct timespec end; @@ -2237,14 +2237,13 @@ daap_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) int ret; int msec; - DPRINTF(E_DBG, L_DAAP, "DAAP request: '%s'\n", uri_parsed->uri); + DPRINTF(E_DBG, L_DAAP, "DAAP request: '%s'\n", hreq->uri); - hreq = httpd_request_parse(req, uri_parsed, NULL, daap_handlers); - if (!hreq) + if (!hreq->handler) { - DPRINTF(E_LOG, L_DAAP, "Unrecognized path '%s' in DAAP request: '%s'\n", uri_parsed->path, uri_parsed->uri); + DPRINTF(E_LOG, L_DAAP, "Unrecognized path in DAAP request: '%s'\n", hreq->uri); - httpd_send_error(req, HTTP_BADREQUEST, "Bad Request"); + httpd_send_error(hreq->req, HTTP_BADREQUEST, "Bad Request"); return; } @@ -2254,7 +2253,7 @@ daap_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) { ret = safe_atoi32(param, &id); if (ret < 0) - DPRINTF(E_LOG, L_DAAP, "Ignoring non-numeric session id in DAAP request: '%s'\n", uri_parsed->uri); + DPRINTF(E_LOG, L_DAAP, "Ignoring non-numeric session id in DAAP request: '%s'\n", hreq->uri); else hreq->extra_data = daap_session_get(id); } @@ -2270,12 +2269,11 @@ daap_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) ret = daap_request_authorize(hreq); if (ret < 0) { - free(hreq); return; } // Set reply headers - headers = evhttp_request_get_output_headers(req); + headers = evhttp_request_get_output_headers(hreq->req); evhttp_add_header(headers, "Accept-Ranges", "bytes"); evhttp_add_header(headers, "DAAP-Server", PACKAGE_NAME "/" VERSION); // Content-Type for all replies, even the actual audio streaming. Note that @@ -2287,15 +2285,14 @@ daap_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) CHECK_NULL(L_DAAP, hreq->reply = evbuffer_new()); // Try the cache - ret = cache_daap_get(hreq->reply, uri_parsed->uri); + ret = cache_daap_get(hreq->reply, hreq->uri); if (ret == 0) { // The cache will return the data gzipped, so httpd_send_reply won't need to do it evhttp_add_header(headers, "Content-Encoding", "gzip"); - httpd_send_reply(req, HTTP_OK, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); // TODO not all want this reply + httpd_send_reply(hreq->req, HTTP_OK, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); // TODO not all want this reply evbuffer_free(hreq->reply); - free(hreq); return; } @@ -2312,38 +2309,9 @@ daap_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) DPRINTF(E_DBG, L_DAAP, "DAAP request handled in %d milliseconds\n", msec); if (ret == DAAP_REPLY_OK && msec > cache_daap_threshold() && hreq->user_agent) - cache_daap_add(uri_parsed->uri, hreq->user_agent, ((struct daap_session *)hreq->extra_data)->is_remote, msec); + cache_daap_add(hreq->uri, hreq->user_agent, ((struct daap_session *)hreq->extra_data)->is_remote, msec); evbuffer_free(hreq->reply); - free(hreq); -} - -int -daap_is_request(const char *path) -{ - if (strncmp(path, "/databases/", strlen("/databases/")) == 0) - return 1; - if (strcmp(path, "/databases") == 0) - return 1; - if (strcmp(path, "/server-info") == 0) - return 1; - if (strcmp(path, "/content-codes") == 0) - return 1; - if (strcmp(path, "/login") == 0) - return 1; - if (strcmp(path, "/update") == 0) - return 1; - if (strcmp(path, "/activity") == 0) - return 1; - if (strcmp(path, "/logout") == 0) - return 1; - -#ifdef DMAP_TEST - if (strcmp(path, "/dmap-test") == 0) - return 1; -#endif - - return 0; } int @@ -2363,7 +2331,7 @@ daap_session_is_valid(int id) struct evbuffer * daap_reply_build(const char *uri, const char *user_agent, int is_remote) { - struct httpd_request *hreq; + struct httpd_request hreq; struct httpd_uri_parsed *uri_parsed; struct evbuffer *reply; struct daap_session session; @@ -2377,50 +2345,46 @@ daap_reply_build(const char *uri, const char *user_agent, int is_remote) if (!uri_parsed) return NULL; - hreq = httpd_request_parse(NULL, uri_parsed, user_agent, daap_handlers); - if (!hreq) + ret = httpd_request_parse(&hreq, NULL, uri_parsed, user_agent, daap_handlers); + if (ret < 0) { DPRINTF(E_LOG, L_DAAP, "Cannot build reply, unrecognized path '%s' in request: '%s'\n", uri_parsed->path, uri_parsed->uri); - goto out_free_uri; + goto out; } memset(&session, 0, sizeof(struct daap_session)); session.is_remote = (bool)is_remote; - hreq->extra_data = &session; + hreq.extra_data = &session; - CHECK_NULL(L_DAAP, hreq->reply = evbuffer_new()); + CHECK_NULL(L_DAAP, hreq.reply = evbuffer_new()); - ret = hreq->handler(hreq); + ret = hreq.handler(&hreq); if (ret < 0) { - evbuffer_free(hreq->reply); - goto out_free_hreq; + evbuffer_free(hreq.reply); + goto out; } - reply = hreq->reply; + reply = hreq.reply; - out_free_hreq: - free(hreq); - out_free_uri: + out: httpd_uri_free(uri_parsed); return reply; } -int +static int daap_init(void) { srand((unsigned)time(NULL)); current_rev = 2; update_requests = NULL; - CHECK_ERR(L_DAAP, httpd_handlers_set(daap_handlers)); - return 0; } -void +static void daap_deinit(void) { struct daap_session *s; @@ -2446,6 +2410,20 @@ daap_deinit(void) update_free(ur); } - - httpd_handlers_unset(daap_handlers); } + +struct httpd_module httpd_daap = +{ + .name = "DAAP", + .type = MODULE_DAAP, + .subpaths = { "/databases/", NULL }, +#ifdef DMAP_TEST + .fullpaths = { "/databases", "/server-info", "/content-codes", "/login", "/update", "/activity", "/logout", "/dmap-test", NULL }, +#else + .fullpaths = { "/databases", "/server-info", "/content-codes", "/login", "/update", "/activity", "/logout", NULL }, +#endif + .handlers = daap_handlers, + .init = daap_init, + .deinit = daap_deinit, + .request = daap_request, +}; diff --git a/src/httpd_daap.h b/src/httpd_daap.h index 53fb6e55..2efd4b42 100644 --- a/src/httpd_daap.h +++ b/src/httpd_daap.h @@ -2,20 +2,6 @@ #ifndef __HTTPD_DAAP_H__ #define __HTTPD_DAAP_H__ -#include "httpd.h" - -int -daap_init(void); - -void -daap_deinit(void); - -void -daap_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed); - -int -daap_is_request(const char *path); - int daap_session_is_valid(int id); diff --git a/src/httpd_dacp.c b/src/httpd_dacp.c index aa8f3c2d..09d97c30 100644 --- a/src/httpd_dacp.c +++ b/src/httpd_dacp.c @@ -37,7 +37,7 @@ #include -#include "httpd_dacp.h" +#include "httpd_internal.h" #include "httpd_daap.h" #include "logger.h" #include "misc.h" @@ -2862,24 +2862,22 @@ static struct httpd_uri_map dacp_handlers[] = /* ------------------------------- DACP API --------------------------------- */ -void -dacp_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) +static void +dacp_request(struct httpd_request *hreq) { - struct httpd_request *hreq; struct evkeyvalq *headers; - DPRINTF(E_DBG, L_DACP, "DACP request: '%s'\n", uri_parsed->uri); + DPRINTF(E_DBG, L_DACP, "DACP request: '%s'\n", hreq->uri); - hreq = httpd_request_parse(req, uri_parsed, NULL, dacp_handlers); - if (!hreq) + if (!hreq->handler) { - DPRINTF(E_LOG, L_DACP, "Unrecognized path '%s' in DACP request: '%s'\n", uri_parsed->path, uri_parsed->uri); + DPRINTF(E_LOG, L_DACP, "Unrecognized path in DACP request: '%s'\n", hreq->uri); - httpd_send_error(req, HTTP_BADREQUEST, "Bad Request"); + httpd_send_error(hreq->req, HTTP_BADREQUEST, "Bad Request"); return; } - headers = evhttp_request_get_output_headers(req); + headers = evhttp_request_get_output_headers(hreq->req); evhttp_add_header(headers, "DAAP-Server", PACKAGE_NAME "/" VERSION); /* Content-Type for all DACP replies; can be overriden as needed */ evhttp_add_header(headers, "Content-Type", "application/x-dmap-tagged"); @@ -2889,21 +2887,13 @@ dacp_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) hreq->handler(hreq); evbuffer_free(hreq->reply); - free(hreq); } -int -dacp_is_request(const char *path) -{ - if (strncmp(path, "/ctrl-int/", strlen("/ctrl-int/")) == 0) - return 1; - if (strcmp(path, "/ctrl-int") == 0) - return 1; +// Forward +static void +dacp_deinit(void); - return 0; -} - -int +static int dacp_init(void) { current_rev = 2; @@ -2920,8 +2910,6 @@ dacp_init(void) dummy_queue_item.album = CFG_NAME_UNKNOWN_ALBUM; dummy_queue_item.genre = CFG_NAME_UNKNOWN_GENRE; - CHECK_ERR(L_DACP, httpd_handlers_set(dacp_handlers)); - #ifdef HAVE_EVENTFD update_efd = eventfd(0, EFD_CLOEXEC); if (update_efd < 0) @@ -2959,7 +2947,7 @@ dacp_init(void) return -1; } -void +static void dacp_deinit(void) { struct dacp_update_request *ur; @@ -2993,6 +2981,16 @@ dacp_deinit(void) close(update_pipe[0]); close(update_pipe[1]); #endif - - httpd_handlers_unset(dacp_handlers); } + +struct httpd_module httpd_dacp = +{ + .name = "DACP", + .type = MODULE_DACP, + .subpaths = { "/ctrl-int/", NULL }, + .fullpaths = { "/ctrl-int", NULL }, + .handlers = dacp_handlers, + .init = dacp_init, + .deinit = dacp_deinit, + .request = dacp_request, +}; diff --git a/src/httpd_dacp.h b/src/httpd_dacp.h deleted file mode 100644 index 307543dc..00000000 --- a/src/httpd_dacp.h +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef __HTTPD_DACP_H__ -#define __HTTPD_DACP_H__ - -#include "httpd.h" - -int -dacp_init(void); - -void -dacp_deinit(void); - -void -dacp_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed); - -int -dacp_is_request(const char *path); - -#endif /* !__HTTPD_DACP_H__ */ diff --git a/src/httpd_internal.h b/src/httpd_internal.h new file mode 100644 index 00000000..f6939509 --- /dev/null +++ b/src/httpd_internal.h @@ -0,0 +1,37 @@ + +#ifndef __HTTPD_INTERNAL_H__ +#define __HTTPD_INTERNAL_H__ + +#include "httpd.h" // TODO remove and transfer + +// Must be in sync with modules[] in httpd.c +enum httpd_modules +{ + MODULE_DACP, + MODULE_DAAP, + MODULE_JSONAPI, + MODULE_ARTWORKAPI, + MODULE_STREAMING, + MODULE_OAUTH, + MODULE_RSP, +}; + +struct httpd_module +{ + const char *name; + enum httpd_modules type; + char initialized; + + // Null-terminated list of URL subpath that the module accepts e.g., /subpath/morepath/file.mp3 + const char *subpaths[16]; + // Null-terminated list of URL fullparhs that the module accepts e.g., /fullpath + const char *fullpaths[16]; + // Pointer to the module's handler definitions + struct httpd_uri_map *handlers; + + int (*init)(void); + void (*deinit)(void); + void (*request)(struct httpd_request *hreq); +}; + +#endif /* !__HTTPD_INTERNAL_H__ */ diff --git a/src/httpd_jsonapi.c b/src/httpd_jsonapi.c index 966fe257..4ff4456e 100644 --- a/src/httpd_jsonapi.c +++ b/src/httpd_jsonapi.c @@ -41,7 +41,7 @@ #include #include -#include "httpd_jsonapi.h" +#include "httpd_internal.h" #include "conffile.h" #include "db.h" #ifdef LASTFM @@ -4716,24 +4716,24 @@ static struct httpd_uri_map adm_handlers[] = /* ------------------------------- JSON API --------------------------------- */ -void -jsonapi_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) +static void +jsonapi_request(struct httpd_request *hreq) { - struct httpd_request *hreq; + ; struct evkeyvalq *headers; int status_code; - DPRINTF(E_DBG, L_WEB, "JSON api request: '%s'\n", uri_parsed->uri); + DPRINTF(E_DBG, L_WEB, "JSON api request: '%s'\n", hreq->uri); - if (!httpd_admin_check_auth(req)) - return; - - hreq = httpd_request_parse(req, uri_parsed, NULL, adm_handlers); - if (!hreq) + if (!httpd_admin_check_auth(hreq->req)) { - DPRINTF(E_LOG, L_WEB, "Unrecognized path '%s' in JSON api request: '%s'\n", uri_parsed->path, uri_parsed->uri); + return; + } - httpd_send_error(req, HTTP_BADREQUEST, "Bad Request"); + if (!hreq->handler) + { + DPRINTF(E_LOG, L_WEB, "Unrecognized JSON API request: '%s'\n", hreq->uri); + httpd_send_error(hreq->req, HTTP_BADREQUEST, "Bad Request"); return; } @@ -4742,62 +4742,47 @@ jsonapi_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) status_code = hreq->handler(hreq); if (status_code >= 400) - DPRINTF(E_LOG, L_WEB, "JSON api request failed with error code %d (%s)\n", status_code, uri_parsed->uri); + DPRINTF(E_LOG, L_WEB, "JSON api request failed with error code %d (%s)\n", status_code, hreq->uri); switch (status_code) { case HTTP_OK: /* 200 OK */ - headers = evhttp_request_get_output_headers(req); + headers = evhttp_request_get_output_headers(hreq->req); evhttp_add_header(headers, "Content-Type", "application/json"); - httpd_send_reply(req, status_code, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq->req, status_code, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); break; case HTTP_NOCONTENT: /* 204 No Content */ - httpd_send_reply(req, status_code, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq->req, status_code, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); break; case HTTP_NOTMODIFIED: /* 304 Not Modified */ - httpd_send_reply(req, HTTP_NOTMODIFIED, NULL, NULL, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq->req, HTTP_NOTMODIFIED, NULL, NULL, HTTPD_SEND_NO_GZIP); break; - case HTTP_BADREQUEST: /* 400 Bad Request */ - httpd_send_error(req, status_code, "Bad Request"); + httpd_send_error(hreq->req, status_code, "Bad Request"); break; case 403: - httpd_send_error(req, status_code, "Forbidden"); + httpd_send_error(hreq->req, status_code, "Forbidden"); break; case HTTP_NOTFOUND: /* 404 Not Found */ - httpd_send_error(req, status_code, "Not Found"); + httpd_send_error(hreq->req, status_code, "Not Found"); break; case HTTP_SERVUNAVAIL: /* 503 */ - httpd_send_error(req, status_code, "Service Unavailable"); + httpd_send_error(hreq->req, status_code, "Service Unavailable"); break; case HTTP_INTERNAL: /* 500 Internal Server Error */ default: - httpd_send_error(req, HTTP_INTERNAL, "Internal Server Error"); + httpd_send_error(hreq->req, HTTP_INTERNAL, "Internal Server Error"); break; } evbuffer_free(hreq->reply); - free(hreq); } -int -jsonapi_is_request(const char *path) -{ - if (strncmp(path, "/api/", strlen("/api/")) == 0) - return 1; - if (strcmp(path, "/api") == 0) - return 1; - - return 0; -} - -int +static int jsonapi_init(void) { char *temp_path; - CHECK_ERR(L_WEB, httpd_handlers_set(adm_handlers)); - default_playlist_directory = NULL; allow_modifying_stored_playlists = cfg_getbool(cfg_getsec(cfg, "library"), "allow_modifying_stored_playlists"); if (allow_modifying_stored_playlists) @@ -4824,10 +4809,19 @@ jsonapi_init(void) return 0; } -void +static void jsonapi_deinit(void) { free(default_playlist_directory); - - httpd_handlers_unset(adm_handlers); } + +struct httpd_module httpd_jsonapi = +{ + .name = "JSON API", + .type = MODULE_JSONAPI, + .subpaths = { "/api/", NULL }, + .handlers = adm_handlers, + .init = jsonapi_init, + .deinit = jsonapi_deinit, + .request = jsonapi_request, +}; diff --git a/src/httpd_jsonapi.h b/src/httpd_jsonapi.h deleted file mode 100644 index e6113ea6..00000000 --- a/src/httpd_jsonapi.h +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef __HTTPD_JSONAPI_H__ -#define __HTTPD_JSONAPI_H__ - -#include "httpd.h" - -int -jsonapi_init(void); - -void -jsonapi_deinit(void); - -void -jsonapi_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed); - -int -jsonapi_is_request(const char *path); - -#endif /* !__HTTPD_JSONAPI_H__ */ diff --git a/src/httpd_oauth.c b/src/httpd_oauth.c index 29bd5cda..ff41bf76 100644 --- a/src/httpd_oauth.c +++ b/src/httpd_oauth.c @@ -28,7 +28,7 @@ #include #include -#include "httpd_oauth.h" +#include "httpd_internal.h" #include "logger.h" #include "misc.h" #include "conffile.h" @@ -90,48 +90,28 @@ static struct httpd_uri_map oauth_handlers[] = /* ------------------------------- OAUTH API -------------------------------- */ -void -oauth_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) +static void +oauth_request(struct httpd_request *hreq) { - struct httpd_request *hreq; + DPRINTF(E_LOG, L_WEB, "OAuth request: '%s'\n", hreq->uri); - DPRINTF(E_LOG, L_WEB, "OAuth request: '%s'\n", uri_parsed->uri); - - hreq = httpd_request_parse(req, uri_parsed, NULL, oauth_handlers); - if (!hreq) + if (!hreq->handler) { - DPRINTF(E_LOG, L_WEB, "Unrecognized path '%s' in OAuth request: '%s'\n", uri_parsed->path, uri_parsed->uri); + DPRINTF(E_LOG, L_WEB, "Unrecognized path in OAuth request: '%s'\n", hreq->uri); - httpd_send_error(req, HTTP_NOTFOUND, NULL); + httpd_send_error(hreq->req, HTTP_NOTFOUND, NULL); return; } hreq->handler(hreq); - - free(hreq); } -int -oauth_is_request(const char *path) +struct httpd_module httpd_oauth = { - if (strncmp(path, "/oauth/", strlen("/oauth/")) == 0) - return 1; - if (strcmp(path, "/oauth") == 0) - return 1; - - return 0; -} - -int -oauth_init(void) -{ - CHECK_ERR(L_WEB, httpd_handlers_set(oauth_handlers)); - - return 0; -} - -void -oauth_deinit(void) -{ - httpd_handlers_unset(oauth_handlers); -} + .name = "OAuth", + .type = MODULE_OAUTH, + .subpaths = { "/oauth/", NULL }, + .fullpaths = { "/oauth", NULL }, + .handlers = oauth_handlers, + .request = oauth_request, +}; diff --git a/src/httpd_oauth.h b/src/httpd_oauth.h deleted file mode 100644 index 71ff1495..00000000 --- a/src/httpd_oauth.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __HTTPD_OAUTH_H__ -#define __HTTPD_OAUTH_H__ - -#include "httpd.h" - -void -oauth_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed); - -int -oauth_is_request(const char *path); - -int -oauth_init(void); - -void -oauth_deinit(void); - -#endif /* !__HTTPD_OAUTH_H__ */ diff --git a/src/httpd_rsp.c b/src/httpd_rsp.c index da67a781..af10f445 100644 --- a/src/httpd_rsp.c +++ b/src/httpd_rsp.c @@ -32,12 +32,11 @@ #include "mxml-compat.h" -#include "httpd_rsp.h" +#include "httpd_internal.h" #include "logger.h" #include "db.h" #include "conffile.h" #include "misc.h" -#include "httpd.h" #include "transcode.h" #include "parsers/rsp_parser.h" @@ -863,57 +862,46 @@ static struct httpd_uri_map rsp_handlers[] = /* -------------------------------- RSP API --------------------------------- */ -void -rsp_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) +static void +rsp_request(struct httpd_request *hreq) { - struct httpd_request *hreq; int ret; - DPRINTF(E_DBG, L_RSP, "RSP request: '%s'\n", uri_parsed->uri); + DPRINTF(E_DBG, L_RSP, "RSP request: '%s'\n", hreq->uri); - hreq = httpd_request_parse(req, uri_parsed, NULL, rsp_handlers); - if (!hreq) + if (!hreq->handler) { - DPRINTF(E_LOG, L_RSP, "Unrecognized path '%s' in RSP request: '%s'\n", uri_parsed->path, uri_parsed->uri); + DPRINTF(E_LOG, L_RSP, "Unrecognized path in RSP request: '%s'\n", hreq->uri); - rsp_send_error(req, "Server error"); + rsp_send_error(hreq->req, "Server error"); return; } ret = rsp_request_authorize(hreq); if (ret < 0) { - rsp_send_error(req, "Access denied"); + rsp_send_error(hreq->req, "Access denied"); free(hreq); return; } hreq->handler(hreq); - - free(hreq); } -int -rsp_is_request(const char *path) -{ - if (strncmp(path, "/rsp/", strlen("/rsp/")) == 0) - return 1; - - return 0; -} - -int +static int rsp_init(void) { snprintf(rsp_filter_files, sizeof(rsp_filter_files), "f.data_kind = %d", DATA_KIND_FILE); - CHECK_ERR(L_RSP, httpd_handlers_set(rsp_handlers)); - return 0; } -void -rsp_deinit(void) +struct httpd_module httpd_rsp = { - httpd_handlers_unset(rsp_handlers); -} + .name = "RSP", + .type = MODULE_RSP, + .subpaths = { "/rsp/", NULL }, + .handlers = rsp_handlers, + .init = rsp_init, + .request = rsp_request, +}; diff --git a/src/httpd_rsp.h b/src/httpd_rsp.h deleted file mode 100644 index 637afcfe..00000000 --- a/src/httpd_rsp.h +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef __HTTPD_RSP_H__ -#define __HTTPD_RSP_H__ - -#include "httpd.h" - -int -rsp_init(void); - -void -rsp_deinit(void); - -void -rsp_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed); - -int -rsp_is_request(const char *path); - -#endif /* !__HTTPD_RSP_H__ */ diff --git a/src/httpd_streaming.c b/src/httpd_streaming.c index a4b5b1a9..4e8b9485 100644 --- a/src/httpd_streaming.c +++ b/src/httpd_streaming.c @@ -32,6 +32,7 @@ #include +#include "httpd_internal.h" #include "httpd_streaming.h" #include "logger.h" #include "conffile.h" @@ -523,8 +524,27 @@ streaming_write(struct output_buffer *obuf) } } -int -streaming_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed) +// Since streaming is a one-trick pony it doesn't need handlers +static int +streaming_dummy_handler(struct httpd_request *hreq) +{ + return 0; +} + +static struct httpd_uri_map streaming_handlers[] = + { + { + .regexp = "^/stream.mp3$", + .handler = streaming_dummy_handler + }, + { + .regexp = NULL, + .handler = NULL + } + }; + +static void +streaming_request(struct httpd_request *hreq) { struct streaming_session *session; struct evhttp_connection *evcon; @@ -541,13 +561,13 @@ streaming_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parse { DPRINTF(E_LOG, L_STREAMING, "Got MP3 streaming request, but cannot encode to MP3\n"); - evhttp_send_error(req, HTTP_NOTFOUND, "Not Found"); - return -1; + evhttp_send_error(hreq->req, HTTP_NOTFOUND, "Not Found"); + return; } - evcon = evhttp_request_get_connection(req); + evcon = evhttp_request_get_connection(hreq->req); evhttp_connection_get_peer(evcon, &address, &port); - param = evhttp_find_header( evhttp_request_get_input_headers(req), "Icy-MetaData"); + param = evhttp_find_header( evhttp_request_get_input_headers(hreq->req), "Icy-MetaData"); if (param && strcmp(param, "1") == 0) require_icy = true; @@ -556,7 +576,7 @@ streaming_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parse lib = cfg_getsec(cfg, "library"); name = cfg_getstr(lib, "name"); - output_headers = evhttp_request_get_output_headers(req); + output_headers = evhttp_request_get_output_headers(hreq->req); evhttp_add_header(output_headers, "Content-Type", "audio/mpeg"); evhttp_add_header(output_headers, "Server", PACKAGE_NAME "/" VERSION); evhttp_add_header(output_headers, "Cache-Control", "no-cache"); @@ -572,15 +592,15 @@ streaming_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parse evhttp_add_header(output_headers, "Access-Control-Allow-Origin", "*"); evhttp_add_header(output_headers, "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); - evhttp_send_reply_start(req, HTTP_OK, "OK"); + evhttp_send_reply_start(hreq->req, HTTP_OK, "OK"); session = calloc(1, sizeof(struct streaming_session)); if (!session) { DPRINTF(E_LOG, L_STREAMING, "Out of memory for streaming request\n"); - evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error"); - return -1; + evhttp_send_error(hreq->req, HTTP_SERVUNAVAIL, "Internal Server Error"); + return; } pthread_mutex_lock(&streaming_sessions_lck); @@ -591,7 +611,7 @@ streaming_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parse event_add(metaev, NULL); } - session->req = req; + session->req = hreq->req; session->next = streaming_sessions; session->require_icy = require_icy; session->bytes_sent = 0; @@ -600,23 +620,9 @@ streaming_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parse pthread_mutex_unlock(&streaming_sessions_lck); evhttp_connection_set_closecb(evcon, streaming_close_cb, session); - - return 0; } -int -streaming_is_request(const char *path) -{ - char *ptr; - - ptr = strrchr(path, '/'); - if (ptr && (strcasecmp(ptr, "/stream.mp3") == 0)) - return 1; - - return 0; -} - -int +static int streaming_init(void) { int ret; @@ -723,7 +729,7 @@ streaming_init(void) return -1; } -void +static void streaming_deinit(void) { streaming_end(); @@ -744,3 +750,14 @@ streaming_deinit(void) pthread_mutex_destroy(&streaming_sessions_lck); } + +struct httpd_module httpd_streaming = +{ + .name = "Streaming", + .type = MODULE_STREAMING, + .fullpaths = { "/stream.mp3", NULL }, + .handlers = streaming_handlers, + .init = streaming_init, + .deinit = streaming_deinit, + .request = streaming_request, +}; diff --git a/src/httpd_streaming.h b/src/httpd_streaming.h index 3df82023..e32d6094 100644 --- a/src/httpd_streaming.h +++ b/src/httpd_streaming.h @@ -2,7 +2,6 @@ #ifndef __HTTPD_STREAMING_H__ #define __HTTPD_STREAMING_H__ -#include "httpd.h" #include "outputs.h" /* httpd_streaming takes care of incoming requests to /stream.mp3 @@ -14,16 +13,4 @@ void streaming_write(struct output_buffer *obuf); -int -streaming_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed); - -int -streaming_is_request(const char *path); - -int -streaming_init(void); - -void -streaming_deinit(void); - #endif /* !__HTTPD_STREAMING_H__ */