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__ */