diff --git a/src/httpd.c b/src/httpd.c index 1489cb17..69b14cc0 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -290,18 +290,121 @@ modules_search(const char *path) /* --------------------------- REQUEST HELPERS ------------------------------ */ +static void +uri_parsed_free(struct httpd_uri_parsed *parsed) +{ + int i; + + if (!parsed) + return; + + free(parsed->uri_decoded); + free(parsed->path); + for (i = 0; i < ARRAY_SIZE(parsed->path_parts); i++) + { + free(parsed->path_parts[i]); + } + + httpd_query_clear(&(parsed->query)); + + if (parsed->ev_uri) + evhttp_uri_free(parsed->ev_uri); + + free(parsed); +} + +static struct httpd_uri_parsed * +uri_parsed_create(const char *uri) +{ + struct httpd_uri_parsed *parsed; + char *path = NULL; + const char *query; + char *path_part; + char *ptr; + int i; + int ret; + + CHECK_NULL(L_HTTPD, parsed = calloc(1, sizeof(struct httpd_uri_parsed))); + + parsed->uri = uri; + + parsed->ev_uri = evhttp_uri_parse_with_flags(parsed->uri, EVHTTP_URI_NONCONFORMANT); + if (!parsed->ev_uri) + { + DPRINTF(E_LOG, L_HTTPD, "Could not parse request: '%s'\n", parsed->uri); + goto error; + } + + parsed->uri_decoded = evhttp_uridecode(parsed->uri, 0, NULL); + if (!parsed->uri_decoded) + { + DPRINTF(E_LOG, L_HTTPD, "Could not URI decode request: '%s'\n", parsed->uri); + goto error; + } + + query = evhttp_uri_get_query(parsed->ev_uri); + if (query && strchr(query, '=')) + { + ret = evhttp_parse_query_str(query, &(parsed->query)); + if (ret < 0) + { + DPRINTF(E_LOG, L_DAAP, "Invalid query '%s' in request: '%s'\n", query, parsed->uri); + goto error; + } + } + + path = strdup(evhttp_uri_get_path(parsed->ev_uri)); + if (!path) + { + DPRINTF(E_WARN, L_HTTPD, "No path in request: '%s'\n", parsed->uri); + return parsed; + } + + parsed->path = evhttp_uridecode(path, 0, NULL); + if (!parsed->path) + { + DPRINTF(E_LOG, L_HTTPD, "Could not URI decode path: '%s'\n", path); + goto error; + } + + path_part = strtok_r(path, "/", &ptr); + for (i = 0; (i < ARRAY_SIZE(parsed->path_parts) && path_part); i++) + { + parsed->path_parts[i] = evhttp_uridecode(path_part, 0, NULL); + path_part = strtok_r(NULL, "/", &ptr); + } + + if (path_part) + { + // If "path_part" is not NULL, we have path tokens that could not be parsed into the "parsed->path_parts" array + DPRINTF(E_LOG, L_HTTPD, "URI path has too many components (%d): '%s'\n", i, parsed->path); + goto error; + } + + free(path); + + return parsed; + + error: + free(path); + uri_parsed_free(parsed); + return NULL; +} + static void request_unset(struct httpd_request *hreq) { - httpd_uri_free(hreq->uri_parsed); + if (hreq->out_body) + evbuffer_free(hreq->out_body); + + uri_parsed_free(hreq->uri_parsed); } static void request_set(struct httpd_request *hreq, httpd_backend *backend, const char *uri, const char *user_agent) { - struct httpd_uri_map *map; struct httpd_uri_parsed *uri_parsed; - struct httpd_module *module; + struct httpd_uri_map *map; int ret; memset(hreq, 0, sizeof(struct httpd_request)); @@ -311,9 +414,9 @@ request_set(struct httpd_request *hreq, httpd_backend *backend, const char *uri, if (backend) { hreq->uri = httpd_backend_uri_get(backend); - hreq->in_body = httpd_backend_input_buffer_get(backend); hreq->in_headers = httpd_backend_input_headers_get(backend); hreq->out_headers = httpd_backend_output_headers_get(backend); + hreq->in_body = httpd_backend_input_buffer_get(backend); httpd_backend_method_get(&hreq->method, backend); httpd_backend_peer_get(&hreq->peer_address, &hreq->peer_port, backend); @@ -325,7 +428,11 @@ request_set(struct httpd_request *hreq, httpd_backend *backend, const char *uri, hreq->user_agent = user_agent; } - uri_parsed = httpd_uri_parse(hreq->uri); + // Don't write directly to backend's buffer. This way we are sure we own the + // buffer even if there is no backend. + CHECK_NULL(L_HTTPD, hreq->out_body = evbuffer_new()); + + uri_parsed = uri_parsed_create(hreq->uri); if (!uri_parsed) { return; @@ -335,13 +442,13 @@ request_set(struct httpd_request *hreq, httpd_backend *backend, const char *uri, hreq->query = &(hreq->uri_parsed->query); // Path with e.g. /api -> JSON module - module = modules_search(uri_parsed->path); - if (!module) + hreq->module = modules_search(uri_parsed->path); + if (!hreq->module) { return; } - for (map = module->handlers; map->handler; map++) + for (map = hreq->module->handlers; map->handler; map++) { // Check if handler supports the current http request method if (map->method && hreq->method && !(map->method & hreq->method)) @@ -868,9 +975,9 @@ httpd_gen_cb(httpd_backend *backend, void *arg) goto out; } - if ((&hreq)->handler) + if ((&hreq)->module) { - (&hreq)->handler(&hreq); + (&hreq)->module->request(&hreq); } else { @@ -886,107 +993,6 @@ httpd_gen_cb(httpd_backend *backend, void *arg) /* ------------------------------- HTTPD API -------------------------------- */ -void -httpd_uri_free(struct httpd_uri_parsed *parsed) -{ - int i; - - if (!parsed) - return; - - free(parsed->uri_decoded); - free(parsed->path); - for (i = 0; i < ARRAY_SIZE(parsed->path_parts); i++) - { - free(parsed->path_parts[i]); - } - - httpd_query_clear(&(parsed->query)); - - if (parsed->ev_uri) - evhttp_uri_free(parsed->ev_uri); - - free(parsed); -} - -struct httpd_uri_parsed * -httpd_uri_parse(const char *uri) -{ - struct httpd_uri_parsed *parsed; - char *path = NULL; - const char *query; - char *path_part; - char *ptr; - int i; - int ret; - - CHECK_NULL(L_HTTPD, parsed = calloc(1, sizeof(struct httpd_uri_parsed))); - - parsed->uri = uri; - - parsed->ev_uri = evhttp_uri_parse_with_flags(parsed->uri, EVHTTP_URI_NONCONFORMANT); - if (!parsed->ev_uri) - { - DPRINTF(E_LOG, L_HTTPD, "Could not parse request: '%s'\n", parsed->uri); - goto error; - } - - parsed->uri_decoded = evhttp_uridecode(parsed->uri, 0, NULL); - if (!parsed->uri_decoded) - { - DPRINTF(E_LOG, L_HTTPD, "Could not URI decode request: '%s'\n", parsed->uri); - goto error; - } - - query = evhttp_uri_get_query(parsed->ev_uri); - if (query && strchr(query, '=')) - { - ret = evhttp_parse_query_str(query, &(parsed->query)); - if (ret < 0) - { - DPRINTF(E_LOG, L_DAAP, "Invalid query '%s' in request: '%s'\n", query, parsed->uri); - goto error; - } - } - - path = strdup(evhttp_uri_get_path(parsed->ev_uri)); - if (!path) - { - DPRINTF(E_WARN, L_HTTPD, "No path in request: '%s'\n", parsed->uri); - return parsed; - } - - parsed->path = evhttp_uridecode(path, 0, NULL); - if (!parsed->path) - { - DPRINTF(E_LOG, L_HTTPD, "Could not URI decode path: '%s'\n", path); - goto error; - } - - path_part = strtok_r(path, "/", &ptr); - for (i = 0; (i < ARRAY_SIZE(parsed->path_parts) && path_part); i++) - { - parsed->path_parts[i] = evhttp_uridecode(path_part, 0, NULL); - path_part = strtok_r(NULL, "/", &ptr); - } - - if (path_part) - { - // If "path_part" is not NULL, we have path tokens that could not be parsed into the "parsed->path_parts" array - DPRINTF(E_LOG, L_HTTPD, "URI path has too many components (%d): '%s'\n", i, parsed->path); - goto error; - } - - free(path); - - return parsed; - - error: - free(path); - httpd_uri_free(parsed); - return NULL; -} - void httpd_request_unset(struct httpd_request *hreq) { diff --git a/src/httpd_artworkapi.c b/src/httpd_artworkapi.c index 91556723..e321c002 100644 --- a/src/httpd_artworkapi.c +++ b/src/httpd_artworkapi.c @@ -88,7 +88,7 @@ artworkapi_reply_nowplaying(struct httpd_request *hreq) if (ret != 0) return HTTP_NOTFOUND; - ret = artwork_get_item(hreq->reply, id, max_w, max_h, 0); + ret = artwork_get_item(hreq->out_body, id, max_w, max_h, 0); return response_process(hreq, ret); } @@ -109,7 +109,7 @@ artworkapi_reply_item(struct httpd_request *hreq) if (ret != 0) return HTTP_BADREQUEST; - ret = artwork_get_item(hreq->reply, id, max_w, max_h, 0); + ret = artwork_get_item(hreq->out_body, id, max_w, max_h, 0); return response_process(hreq, ret); } @@ -130,7 +130,7 @@ artworkapi_reply_group(struct httpd_request *hreq) if (ret != 0) return HTTP_BADREQUEST; - ret = artwork_get_group(hreq->reply, id, max_w, max_h, 0); + ret = artwork_get_group(hreq->out_body, id, max_w, max_h, 0); return response_process(hreq, ret); } @@ -164,17 +164,15 @@ artworkapi_request(struct httpd_request *hreq) return; } - CHECK_NULL(L_WEB, hreq->reply = evbuffer_new()); - status_code = hreq->handler(hreq); switch (status_code) { case HTTP_OK: /* 200 OK */ - httpd_send_reply(hreq, status_code, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, status_code, "OK", hreq->out_body, HTTPD_SEND_NO_GZIP); break; case HTTP_NOCONTENT: /* 204 No Content */ - httpd_send_reply(hreq, status_code, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, status_code, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); break; case HTTP_NOTMODIFIED: /* 304 Not Modified */ httpd_send_reply(hreq, HTTP_NOTMODIFIED, NULL, NULL, HTTPD_SEND_NO_GZIP); @@ -189,8 +187,6 @@ artworkapi_request(struct httpd_request *hreq) default: httpd_send_error(hreq, HTTP_INTERNAL, "Internal Server Error"); } - - evbuffer_free(hreq->reply); } struct httpd_module httpd_artworkapi = diff --git a/src/httpd_daap.c b/src/httpd_daap.c index 9d429e70..43a41a5c 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -670,17 +670,17 @@ daap_reply_send(struct httpd_request *hreq, enum daap_reply_result result) switch (result) { case DAAP_REPLY_LOGOUT: - httpd_send_reply(hreq, 204, "Logout Successful", hreq->reply, 0); + httpd_send_reply(hreq, 204, "Logout Successful", hreq->out_body, 0); break; case DAAP_REPLY_NO_CONTENT: - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); break; case DAAP_REPLY_OK: - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, 0); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, 0); break; case DAAP_REPLY_OK_NO_GZIP: case DAAP_REPLY_ERROR: - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, HTTPD_SEND_NO_GZIP); break; case DAAP_REPLY_FORBIDDEN: httpd_send_error(hreq, 403, "Forbidden"); @@ -857,9 +857,9 @@ daap_reply_server_info(struct httpd_request *hreq) // Create container len = evbuffer_get_length(content); - dmap_add_container(hreq->reply, "msrv", len); + dmap_add_container(hreq->out_body, "msrv", len); - CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, content)); + CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->out_body, content)); evbuffer_free(content); @@ -880,19 +880,19 @@ daap_reply_content_codes(struct httpd_request *hreq) for (i = 0; i < nfields; i++) len += 8 + 12 + 10 + 8 + strlen(dmap_fields[i].desc); - CHECK_ERR(L_DAAP, evbuffer_expand(hreq->reply, len + 8)); + CHECK_ERR(L_DAAP, evbuffer_expand(hreq->out_body, len + 8)); - dmap_add_container(hreq->reply, "mccr", len); - dmap_add_int(hreq->reply, "mstt", 200); + dmap_add_container(hreq->out_body, "mccr", len); + dmap_add_int(hreq->out_body, "mstt", 200); for (i = 0; i < nfields; i++) { len = 12 + 10 + 8 + strlen(dmap_fields[i].desc); - dmap_add_container(hreq->reply, "mdcl", len); - dmap_add_string(hreq->reply, "mcnm", dmap_fields[i].tag); /* 12 */ - dmap_add_string(hreq->reply, "mcna", dmap_fields[i].desc); /* 8 + strlen(desc) */ - dmap_add_short(hreq->reply, "mcty", dmap_fields[i].type); /* 10 */ + dmap_add_container(hreq->out_body, "mdcl", len); + dmap_add_string(hreq->out_body, "mcnm", dmap_fields[i].tag); /* 12 */ + dmap_add_string(hreq->out_body, "mcna", dmap_fields[i].desc); /* 8 + strlen(desc) */ + dmap_add_short(hreq->out_body, "mcty", dmap_fields[i].type); /* 10 */ } return DAAP_REPLY_OK; @@ -908,7 +908,7 @@ daap_reply_login(struct httpd_request *hreq) int request_session_id; int ret; - CHECK_ERR(L_DAAP, evbuffer_expand(hreq->reply, 32)); + CHECK_ERR(L_DAAP, evbuffer_expand(hreq->out_body, 32)); param = httpd_query_value_find(hreq->query, "pairing-guid"); if (param && !net_peer_address_is_trusted(hreq->peer_address)) @@ -957,13 +957,13 @@ daap_reply_login(struct httpd_request *hreq) session = daap_session_add(adhoc->is_remote, request_session_id); if (!session) { - dmap_error_make(hreq->reply, "mlog", "Could not start session"); + dmap_error_make(hreq->out_body, "mlog", "Could not start session"); return DAAP_REPLY_ERROR; } - dmap_add_container(hreq->reply, "mlog", 24); - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ - dmap_add_int(hreq->reply, "mlid", session->id); /* 12 */ + dmap_add_container(hreq->out_body, "mlog", 24); + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ + dmap_add_int(hreq->out_body, "mlid", session->id); /* 12 */ return DAAP_REPLY_OK; } @@ -1009,18 +1009,18 @@ daap_reply_update(struct httpd_request *hreq) { DPRINTF(E_LOG, L_DAAP, "Parameter revision-number not an integer\n"); - dmap_error_make(hreq->reply, "mupd", "Invalid request"); + dmap_error_make(hreq->out_body, "mupd", "Invalid request"); return DAAP_REPLY_ERROR; } if (reqd_rev == 1) /* Or revision is not valid */ { - CHECK_ERR(L_DAAP, evbuffer_expand(hreq->reply, 32)); + CHECK_ERR(L_DAAP, evbuffer_expand(hreq->out_body, 32)); /* Send back current revision */ - dmap_add_container(hreq->reply, "mupd", 24); - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ - dmap_add_int(hreq->reply, "musr", current_rev); /* 12 */ + dmap_add_container(hreq->out_body, "mupd", 24); + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ + dmap_add_int(hreq->out_body, "musr", current_rev); /* 12 */ return DAAP_REPLY_OK; } @@ -1031,7 +1031,7 @@ daap_reply_update(struct httpd_request *hreq) { DPRINTF(E_LOG, L_DAAP, "Out of memory for update request\n"); - dmap_error_make(hreq->reply, "mupd", "Out of memory"); + dmap_error_make(hreq->out_body, "mupd", "Out of memory"); return DAAP_REPLY_ERROR; } @@ -1047,7 +1047,7 @@ daap_reply_update(struct httpd_request *hreq) { DPRINTF(E_LOG, L_DAAP, "Out of memory for update request event\n"); - dmap_error_make(hreq->reply, "mupd", "Could not register timer"); + dmap_error_make(hreq->out_body, "mupd", "Could not register timer"); update_free(ur); return DAAP_REPLY_ERROR; } @@ -1090,7 +1090,7 @@ daap_reply_dblist(struct httpd_request *hreq) CHECK_NULL(L_DAAP, content = evbuffer_new()); CHECK_NULL(L_DAAP, item = evbuffer_new()); CHECK_ERR(L_DAAP, evbuffer_expand(item, 512)); - CHECK_ERR(L_DAAP, evbuffer_expand(hreq->reply, 1024)); + CHECK_ERR(L_DAAP, evbuffer_expand(hreq->out_body, 1024)); // Add db entry for library with dbid = 1 dmap_add_int(item, "miid", 1); @@ -1133,14 +1133,14 @@ daap_reply_dblist(struct httpd_request *hreq) // Create container len = evbuffer_get_length(content); - dmap_add_container(hreq->reply, "avdb", len + 53); - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ - dmap_add_char(hreq->reply, "muty", 0); /* 9 */ - dmap_add_int(hreq->reply, "mtco", 2); /* 12 */ - dmap_add_int(hreq->reply, "mrco", 2); /* 12 */ - dmap_add_container(hreq->reply, "mlcl", len); /* 8 */ + dmap_add_container(hreq->out_body, "avdb", len + 53); + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ + dmap_add_char(hreq->out_body, "muty", 0); /* 9 */ + dmap_add_int(hreq->out_body, "mtco", 2); /* 12 */ + dmap_add_int(hreq->out_body, "mrco", 2); /* 12 */ + dmap_add_container(hreq->out_body, "mlcl", len); /* 8 */ - CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, content)); + CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->out_body, content)); evbuffer_free(item); evbuffer_free(content); @@ -1195,7 +1195,7 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist) CHECK_NULL(L_DAAP, songlist = evbuffer_new()); CHECK_NULL(L_DAAP, song = evbuffer_new()); CHECK_NULL(L_DAAP, sctx = daap_sort_context_new()); - CHECK_ERR(L_DAAP, evbuffer_expand(hreq->reply, 61)); + CHECK_ERR(L_DAAP, evbuffer_expand(hreq->out_body, 61)); CHECK_ERR(L_DAAP, evbuffer_expand(songlist, 4096)); CHECK_ERR(L_DAAP, evbuffer_expand(song, 512)); @@ -1223,7 +1223,7 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist) { DPRINTF(E_LOG, L_DAAP, "Could not start query\n"); - dmap_error_make(hreq->reply, tag, "Could not start query"); + dmap_error_make(hreq->out_body, tag, "Could not start query"); goto error; } @@ -1288,13 +1288,13 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist) if (ret == -100) { - dmap_error_make(hreq->reply, tag, "Out of memory"); + dmap_error_make(hreq->out_body, tag, "Out of memory"); goto error; } else if (ret < 0) { DPRINTF(E_LOG, L_DAAP, "Error fetching results\n"); - dmap_error_make(hreq->reply, tag, "Error fetching query results"); + dmap_error_make(hreq->out_body, tag, "Error fetching query results"); goto error; } @@ -1303,25 +1303,25 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist) if (sort_headers) { daap_sort_finalize(sctx); - dmap_add_container(hreq->reply, tag, len + evbuffer_get_length(sctx->headerlist) + 61); + dmap_add_container(hreq->out_body, tag, len + evbuffer_get_length(sctx->headerlist) + 61); } else - dmap_add_container(hreq->reply, tag, len + 53); + dmap_add_container(hreq->out_body, tag, len + 53); - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ - dmap_add_char(hreq->reply, "muty", 0); /* 9 */ - dmap_add_int(hreq->reply, "mtco", qp.results); /* 12 */ - dmap_add_int(hreq->reply, "mrco", nsongs); /* 12 */ - dmap_add_container(hreq->reply, "mlcl", len); /* 8 */ + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ + dmap_add_char(hreq->out_body, "muty", 0); /* 9 */ + dmap_add_int(hreq->out_body, "mtco", qp.results); /* 12 */ + dmap_add_int(hreq->out_body, "mrco", nsongs); /* 12 */ + dmap_add_container(hreq->out_body, "mlcl", len); /* 8 */ - CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, songlist)); + CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->out_body, songlist)); if (sort_headers) { len = evbuffer_get_length(sctx->headerlist); - dmap_add_container(hreq->reply, "mshl", len); /* 8 */ + dmap_add_container(hreq->out_body, "mshl", len); /* 8 */ - CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, sctx->headerlist)); + CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->out_body, sctx->headerlist)); } free(meta); @@ -1357,7 +1357,7 @@ daap_reply_plsonglist(struct httpd_request *hreq) ret = safe_atoi32(hreq->uri_parsed->path_parts[3], &playlist); if (ret < 0) { - dmap_error_make(hreq->reply, "apso", "Invalid playlist ID"); + dmap_error_make(hreq->out_body, "apso", "Invalid playlist ID"); return DAAP_REPLY_ERROR; } @@ -1403,7 +1403,7 @@ daap_reply_playlists(struct httpd_request *hreq) ret = safe_atoi32(hreq->uri_parsed->path_parts[1], &database); if (ret < 0) { - dmap_error_make(hreq->reply, "aply", "Invalid database ID"); + dmap_error_make(hreq->out_body, "aply", "Invalid database ID"); return DAAP_REPLY_ERROR; } @@ -1412,7 +1412,7 @@ daap_reply_playlists(struct httpd_request *hreq) CHECK_NULL(L_DAAP, playlistlist = evbuffer_new()); CHECK_NULL(L_DAAP, playlist = evbuffer_new()); - CHECK_ERR(L_DAAP, evbuffer_expand(hreq->reply, 61)); + CHECK_ERR(L_DAAP, evbuffer_expand(hreq->out_body, 61)); CHECK_ERR(L_DAAP, evbuffer_expand(playlistlist, 1024)); CHECK_ERR(L_DAAP, evbuffer_expand(playlist, 128)); @@ -1429,7 +1429,7 @@ daap_reply_playlists(struct httpd_request *hreq) { DPRINTF(E_LOG, L_DAAP, "Failed to parse meta parameter in DAAP query\n"); - dmap_error_make(hreq->reply, "aply", "Failed to parse query"); + dmap_error_make(hreq->out_body, "aply", "Failed to parse query"); goto error; } @@ -1438,7 +1438,7 @@ daap_reply_playlists(struct httpd_request *hreq) { DPRINTF(E_LOG, L_DAAP, "Could not start query\n"); - dmap_error_make(hreq->reply, "aply", "Could not start query"); + dmap_error_make(hreq->out_body, "aply", "Could not start query"); goto error; } @@ -1554,26 +1554,26 @@ daap_reply_playlists(struct httpd_request *hreq) if (ret == -100) { - dmap_error_make(hreq->reply, "aply", "Out of memory"); + dmap_error_make(hreq->out_body, "aply", "Out of memory"); goto error; } else if (ret < 0) { DPRINTF(E_LOG, L_DAAP, "Error fetching results\n"); - dmap_error_make(hreq->reply, "aply", "Error fetching query results"); + dmap_error_make(hreq->out_body, "aply", "Error fetching query results"); goto error; } /* Add header to evbuf, add playlistlist to evbuf */ len = evbuffer_get_length(playlistlist); - dmap_add_container(hreq->reply, "aply", len + 53); - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ - dmap_add_char(hreq->reply, "muty", 0); /* 9 */ - dmap_add_int(hreq->reply, "mtco", qp.results); /* 12 */ - dmap_add_int(hreq->reply,"mrco", npls); /* 12 */ - dmap_add_container(hreq->reply, "mlcl", len); + dmap_add_container(hreq->out_body, "aply", len + 53); + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ + dmap_add_char(hreq->out_body, "muty", 0); /* 9 */ + dmap_add_int(hreq->out_body, "mtco", qp.results); /* 12 */ + dmap_add_int(hreq->out_body,"mrco", npls); /* 12 */ + dmap_add_container(hreq->out_body, "mlcl", len); - CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, playlistlist)); + CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->out_body, playlistlist)); free(meta); evbuffer_free(playlist); @@ -1638,7 +1638,7 @@ daap_reply_groups(struct httpd_request *hreq) CHECK_NULL(L_DAAP, grouplist = evbuffer_new()); CHECK_NULL(L_DAAP, group = evbuffer_new()); CHECK_NULL(L_DAAP, sctx = daap_sort_context_new()); - CHECK_ERR(L_DAAP, evbuffer_expand(hreq->reply, 61)); + CHECK_ERR(L_DAAP, evbuffer_expand(hreq->out_body, 61)); CHECK_ERR(L_DAAP, evbuffer_expand(grouplist, 1024)); CHECK_ERR(L_DAAP, evbuffer_expand(group, 128)); @@ -1655,7 +1655,7 @@ daap_reply_groups(struct httpd_request *hreq) { DPRINTF(E_LOG, L_DAAP, "Failed to parse meta parameter in DAAP query\n"); - dmap_error_make(hreq->reply, tag, "Failed to parse query"); + dmap_error_make(hreq->out_body, tag, "Failed to parse query"); goto error; } @@ -1664,7 +1664,7 @@ daap_reply_groups(struct httpd_request *hreq) { DPRINTF(E_LOG, L_DAAP, "Could not start query\n"); - dmap_error_make(hreq->reply, tag, "Could not start query"); + dmap_error_make(hreq->out_body, tag, "Could not start query"); goto error; } @@ -1756,13 +1756,13 @@ daap_reply_groups(struct httpd_request *hreq) if (ret == -100) { - dmap_error_make(hreq->reply, tag, "Out of memory"); + dmap_error_make(hreq->out_body, tag, "Out of memory"); goto error; } else if (ret < 0) { DPRINTF(E_LOG, L_DAAP, "Error fetching results\n"); - dmap_error_make(hreq->reply, tag, "Error fetching query results"); + dmap_error_make(hreq->out_body, tag, "Error fetching query results"); goto error; } @@ -1771,25 +1771,25 @@ daap_reply_groups(struct httpd_request *hreq) if (sort_headers) { daap_sort_finalize(sctx); - dmap_add_container(hreq->reply, tag, len + evbuffer_get_length(sctx->headerlist) + 61); + dmap_add_container(hreq->out_body, tag, len + evbuffer_get_length(sctx->headerlist) + 61); } else - dmap_add_container(hreq->reply, tag, len + 53); + dmap_add_container(hreq->out_body, tag, len + 53); - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ - dmap_add_char(hreq->reply, "muty", 0); /* 9 */ - dmap_add_int(hreq->reply, "mtco", qp.results); /* 12 */ - dmap_add_int(hreq->reply,"mrco", ngrp); /* 12 */ - dmap_add_container(hreq->reply, "mlcl", len); /* 8 */ + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ + dmap_add_char(hreq->out_body, "muty", 0); /* 9 */ + dmap_add_int(hreq->out_body, "mtco", qp.results); /* 12 */ + dmap_add_int(hreq->out_body,"mrco", ngrp); /* 12 */ + dmap_add_container(hreq->out_body, "mlcl", len); /* 8 */ - CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, grouplist)); + CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->out_body, grouplist)); if (sort_headers) { len = evbuffer_get_length(sctx->headerlist); - dmap_add_container(hreq->reply, "mshl", len); /* 8 */ + dmap_add_container(hreq->out_body, "mshl", len); /* 8 */ - CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, sctx->headerlist)); + CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->out_body, sctx->headerlist)); } free(meta); @@ -1847,13 +1847,13 @@ daap_reply_browse(struct httpd_request *hreq) else { DPRINTF(E_LOG, L_DAAP, "Invalid DAAP browse request type '%s'\n", hreq->uri_parsed->path_parts[3]); - dmap_error_make(hreq->reply, "abro", "Invalid browse type"); + dmap_error_make(hreq->out_body, "abro", "Invalid browse type"); return DAAP_REPLY_ERROR; } CHECK_NULL(L_DAAP, itemlist = evbuffer_new()); CHECK_NULL(L_DAAP, sctx = daap_sort_context_new()); - CHECK_ERR(L_DAAP, evbuffer_expand(hreq->reply, 52)); + CHECK_ERR(L_DAAP, evbuffer_expand(hreq->out_body, 52)); CHECK_ERR(L_DAAP, evbuffer_expand(itemlist, 1024)); // Just a starting alloc, it'll expand as needed ret = db_query_start(&qp); @@ -1861,7 +1861,7 @@ daap_reply_browse(struct httpd_request *hreq) { DPRINTF(E_LOG, L_DAAP, "Could not start query\n"); - dmap_error_make(hreq->reply, "abro", "Could not start query"); + dmap_error_make(hreq->out_body, "abro", "Could not start query"); goto error; } @@ -1889,7 +1889,7 @@ daap_reply_browse(struct httpd_request *hreq) { DPRINTF(E_LOG, L_DAAP, "Error fetching/building results\n"); - dmap_error_make(hreq->reply, "abro", "Error fetching/building query results"); + dmap_error_make(hreq->out_body, "abro", "Error fetching/building query results"); goto error; } @@ -1897,24 +1897,24 @@ daap_reply_browse(struct httpd_request *hreq) if (sort_headers) { daap_sort_finalize(sctx); - dmap_add_container(hreq->reply, "abro", len + evbuffer_get_length(sctx->headerlist) + 52); + dmap_add_container(hreq->out_body, "abro", len + evbuffer_get_length(sctx->headerlist) + 52); } else - dmap_add_container(hreq->reply, "abro", len + 44); + dmap_add_container(hreq->out_body, "abro", len + 44); - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ - dmap_add_int(hreq->reply, "mtco", qp.results); /* 12 */ - dmap_add_int(hreq->reply, "mrco", nitems); /* 12 */ - dmap_add_container(hreq->reply, tag, len); /* 8 */ + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ + dmap_add_int(hreq->out_body, "mtco", qp.results); /* 12 */ + dmap_add_int(hreq->out_body, "mrco", nitems); /* 12 */ + dmap_add_container(hreq->out_body, tag, len); /* 8 */ - CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, itemlist)); + CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->out_body, itemlist)); if (sort_headers) { len = evbuffer_get_length(sctx->headerlist); - dmap_add_container(hreq->reply, "mshl", len); /* 8 */ + dmap_add_container(hreq->out_body, "mshl", len); /* 8 */ - CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, sctx->headerlist)); + CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->out_body, sctx->headerlist)); } daap_sort_context_free(sctx); @@ -1984,11 +1984,11 @@ daap_reply_extra_data(struct httpd_request *hreq) } if (strcmp(hreq->uri_parsed->path_parts[2], "groups") == 0) - ret = artwork_get_group(hreq->reply, id, max_w, max_h, 0); + ret = artwork_get_group(hreq->out_body, id, max_w, max_h, 0); else if (strcmp(hreq->uri_parsed->path_parts[2], "items") == 0) - ret = artwork_get_item(hreq->reply, id, max_w, max_h, 0); + ret = artwork_get_item(hreq->out_body, id, max_w, max_h, 0); - len = evbuffer_get_length(hreq->reply); + len = evbuffer_get_length(hreq->out_body); switch (ret) { @@ -2002,7 +2002,7 @@ daap_reply_extra_data(struct httpd_request *hreq) default: if (len > 0) - evbuffer_drain(hreq->reply, len); + evbuffer_drain(hreq->out_body, len); goto no_artwork; } @@ -2112,16 +2112,16 @@ daap_reply_dmap_test(struct httpd_request *hreq) dmap_add_field(test, &dmap_TST8, buf, 0); dmap_add_field(test, &dmap_TST9, buf, 0); - dmap_add_container(hreq->reply, dmap_TEST.tag, evbuffer_get_length(test)); + dmap_add_container(hreq->out_body, dmap_TEST.tag, evbuffer_get_length(test)); - ret = evbuffer_add_buffer(hreq->reply, test); + ret = evbuffer_add_buffer(hreq->out_body, test); evbuffer_free(test); if (ret < 0) { DPRINTF(E_LOG, L_DAAP, "Could not add test results to DMAP test reply\n"); - dmap_error_make(hreq->reply, dmap_TEST.tag, "Out of memory"); + dmap_error_make(hreq->out_body, dmap_TEST.tag, "Out of memory"); return DAAP_REPLY_ERROR; } @@ -2265,18 +2265,13 @@ daap_request(struct httpd_request *hreq) // video/ Content-Type as expected by clients like Front Row. httpd_header_add(hreq->out_headers, "Content-Type", "application/x-dmap-tagged"); - // Now we create the actual reply - CHECK_NULL(L_DAAP, hreq->reply = evbuffer_new()); - // Try the cache - ret = cache_daap_get(hreq->reply, hreq->uri); + ret = cache_daap_get(hreq->out_body, hreq->uri); if (ret == 0) { // The cache will return the data gzipped, so httpd_send_reply won't need to do it httpd_header_add(hreq->out_headers, "Content-Encoding", "gzip"); - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); // TODO not all want this reply - - evbuffer_free(hreq->reply); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, HTTPD_SEND_NO_GZIP); // TODO not all want this reply return; } @@ -2294,8 +2289,6 @@ daap_request(struct httpd_request *hreq) if (ret == DAAP_REPLY_OK && msec > cache_daap_threshold() && hreq->user_agent) cache_daap_add(hreq->uri, hreq->user_agent, ((struct daap_session *)hreq->extra_data)->is_remote, msec); - - evbuffer_free(hreq->reply); } int @@ -2316,13 +2309,13 @@ struct evbuffer * daap_reply_build(const char *uri, const char *user_agent, int is_remote) { struct httpd_request hreq; - struct evbuffer *reply; + struct evbuffer *out_body; struct daap_session session; int ret; DPRINTF(E_DBG, L_DAAP, "Building reply for DAAP request: '%s'\n", uri); - reply = NULL; + out_body = NULL; httpd_request_set(&hreq, uri, user_agent); if (!(&hreq)->handler) @@ -2336,21 +2329,20 @@ daap_reply_build(const char *uri, const char *user_agent, int is_remote) hreq.extra_data = &session; - CHECK_NULL(L_DAAP, hreq.reply = evbuffer_new()); - ret = hreq.handler(&hreq); if (ret < 0) { - evbuffer_free(hreq.reply); goto out; } - reply = hreq.reply; + // Take ownership of the reply + out_body = hreq.out_body; + hreq.out_body = NULL; out: httpd_request_unset(&hreq); - return reply; + return out_body; } static int diff --git a/src/httpd_dacp.c b/src/httpd_dacp.c index 9fdd1dc2..b6cbcfda 100644 --- a/src/httpd_dacp.c +++ b/src/httpd_dacp.c @@ -1183,33 +1183,33 @@ static int dacp_reply_ctrlint(struct httpd_request *hreq) { /* /ctrl-int */ - CHECK_ERR(L_DACP, evbuffer_expand(hreq->reply, 256)); + CHECK_ERR(L_DACP, evbuffer_expand(hreq->out_body, 256)); /* If tags are added or removed container sizes should be adjusted too */ - dmap_add_container(hreq->reply, "caci", 194); /* 8, unknown dacp container - size of content */ - dmap_add_int(hreq->reply, "mstt", 200); /* 12, dmap.status */ - dmap_add_char(hreq->reply, "muty", 0); /* 9, dmap.updatetype */ - dmap_add_int(hreq->reply, "mtco", 1); /* 12, dmap.specifiedtotalcount */ - dmap_add_int(hreq->reply, "mrco", 1); /* 12, dmap.returnedcount */ - dmap_add_container(hreq->reply, "mlcl", 141); /* 8, dmap.listing - size of content */ - dmap_add_container(hreq->reply, "mlit", 133); /* 8, dmap.listingitem - size of content */ - dmap_add_int(hreq->reply, "miid", 1); /* 12, dmap.itemid - database ID */ - dmap_add_char(hreq->reply, "cmik", 1); /* 9, unknown */ + dmap_add_container(hreq->out_body, "caci", 194); /* 8, unknown dacp container - size of content */ + dmap_add_int(hreq->out_body, "mstt", 200); /* 12, dmap.status */ + dmap_add_char(hreq->out_body, "muty", 0); /* 9, dmap.updatetype */ + dmap_add_int(hreq->out_body, "mtco", 1); /* 12, dmap.specifiedtotalcount */ + dmap_add_int(hreq->out_body, "mrco", 1); /* 12, dmap.returnedcount */ + dmap_add_container(hreq->out_body, "mlcl", 141); /* 8, dmap.listing - size of content */ + dmap_add_container(hreq->out_body, "mlit", 133); /* 8, dmap.listingitem - size of content */ + dmap_add_int(hreq->out_body, "miid", 1); /* 12, dmap.itemid - database ID */ + dmap_add_char(hreq->out_body, "cmik", 1); /* 9, unknown */ - dmap_add_int(hreq->reply, "cmpr", (2 << 16 | 2)); /* 12, dmcp.protocolversion */ - dmap_add_int(hreq->reply, "capr", (2 << 16 | 5)); /* 12, dacp.protocolversion */ + dmap_add_int(hreq->out_body, "cmpr", (2 << 16 | 2)); /* 12, dmcp.protocolversion */ + dmap_add_int(hreq->out_body, "capr", (2 << 16 | 5)); /* 12, dacp.protocolversion */ - dmap_add_char(hreq->reply, "cmsp", 1); /* 9, unknown */ - dmap_add_char(hreq->reply, "aeFR", 0x64); /* 9, unknown */ - dmap_add_char(hreq->reply, "cmsv", 1); /* 9, unknown */ - dmap_add_char(hreq->reply, "cass", 1); /* 9, unknown */ - dmap_add_char(hreq->reply, "caov", 1); /* 9, unknown */ - dmap_add_char(hreq->reply, "casu", 1); /* 9, unknown */ - dmap_add_char(hreq->reply, "ceSG", 1); /* 9, unknown */ - dmap_add_char(hreq->reply, "cmrl", 1); /* 9, unknown */ - dmap_add_long(hreq->reply, "ceSX", (1 << 1 | 1)); /* 16, unknown dacp - lowest bit announces support for playqueue-contents/-edit */ + dmap_add_char(hreq->out_body, "cmsp", 1); /* 9, unknown */ + dmap_add_char(hreq->out_body, "aeFR", 0x64); /* 9, unknown */ + dmap_add_char(hreq->out_body, "cmsv", 1); /* 9, unknown */ + dmap_add_char(hreq->out_body, "cass", 1); /* 9, unknown */ + dmap_add_char(hreq->out_body, "caov", 1); /* 9, unknown */ + dmap_add_char(hreq->out_body, "casu", 1); /* 9, unknown */ + dmap_add_char(hreq->out_body, "ceSG", 1); /* 9, unknown */ + dmap_add_char(hreq->out_body, "cmrl", 1); /* 9, unknown */ + dmap_add_long(hreq->out_body, "ceSX", (1 << 1 | 1)); /* 16, unknown dacp - lowest bit announces support for playqueue-contents/-edit */ - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, 0); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, 0); return 0; } @@ -1347,13 +1347,13 @@ dacp_reply_cue_play(struct httpd_request *hreq) player_get_status(&status); - CHECK_ERR(L_DACP, evbuffer_expand(hreq->reply, 64)); + CHECK_ERR(L_DACP, evbuffer_expand(hreq->out_body, 64)); - dmap_add_container(hreq->reply, "cacr", 24); /* 8 + len */ - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ - dmap_add_int(hreq->reply, "miid", status.id);/* 12 */ + dmap_add_container(hreq->out_body, "cacr", 24); /* 8 + len */ + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ + dmap_add_int(hreq->out_body, "miid", status.id);/* 12 */ - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, 0); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, 0); return 0; } @@ -1367,13 +1367,13 @@ dacp_reply_cue_clear(struct httpd_request *hreq) db_queue_clear(0); - CHECK_ERR(L_DACP, evbuffer_expand(hreq->reply, 64)); + CHECK_ERR(L_DACP, evbuffer_expand(hreq->out_body, 64)); - dmap_add_container(hreq->reply, "cacr", 24); /* 8 + len */ - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ - dmap_add_int(hreq->reply, "miid", 0); /* 12 */ + dmap_add_container(hreq->out_body, "cacr", 24); /* 8 + len */ + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ + dmap_add_int(hreq->out_body, "miid", 0); /* 12 */ - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, 0); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, 0); return 0; } @@ -1427,7 +1427,7 @@ dacp_reply_play(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -1559,7 +1559,7 @@ dacp_reply_playspec(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; out_fail: @@ -1580,7 +1580,7 @@ dacp_reply_stop(struct httpd_request *hreq) player_playback_stop(); /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -1597,7 +1597,7 @@ dacp_reply_pause(struct httpd_request *hreq) player_playback_pause(); /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -1630,7 +1630,7 @@ dacp_reply_playpause(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -1663,7 +1663,7 @@ dacp_reply_nextitem(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -1696,7 +1696,7 @@ dacp_reply_previtem(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -1713,7 +1713,7 @@ dacp_reply_beginff(struct httpd_request *hreq) /* TODO */ /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -1730,7 +1730,7 @@ dacp_reply_beginrew(struct httpd_request *hreq) /* TODO */ /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -1747,7 +1747,7 @@ dacp_reply_playresume(struct httpd_request *hreq) /* TODO */ /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -1787,7 +1787,7 @@ dacp_reply_playqueuecontents(struct httpd_request *hreq) } CHECK_NULL(L_DACP, songlist = evbuffer_new()); - CHECK_ERR(L_DACP, evbuffer_expand(hreq->reply, 128)); + CHECK_ERR(L_DACP, evbuffer_expand(hreq->out_body, 128)); player_get_status(&status); @@ -1882,24 +1882,24 @@ dacp_reply_playqueuecontents(struct httpd_request *hreq) /* Final construction of reply */ playlist_length = evbuffer_get_length(playlists); - dmap_add_container(hreq->reply, "ceQR", 79 + playlist_length + songlist_length); /* size of entire container */ - dmap_add_int(hreq->reply, "mstt", 200); /* 12, dmap.status */ - dmap_add_int(hreq->reply, "mtco", abs(span)); /* 12 */ - dmap_add_int(hreq->reply, "mrco", count); /* 12 */ - dmap_add_char(hreq->reply, "ceQu", 0); /* 9 */ - dmap_add_container(hreq->reply, "mlcl", 8 + playlist_length + songlist_length); /* 8 */ - dmap_add_container(hreq->reply, "ceQS", playlist_length); /* 8 */ + dmap_add_container(hreq->out_body, "ceQR", 79 + playlist_length + songlist_length); /* size of entire container */ + dmap_add_int(hreq->out_body, "mstt", 200); /* 12, dmap.status */ + dmap_add_int(hreq->out_body, "mtco", abs(span)); /* 12 */ + dmap_add_int(hreq->out_body, "mrco", count); /* 12 */ + dmap_add_char(hreq->out_body, "ceQu", 0); /* 9 */ + dmap_add_container(hreq->out_body, "mlcl", 8 + playlist_length + songlist_length); /* 8 */ + dmap_add_container(hreq->out_body, "ceQS", playlist_length); /* 8 */ - CHECK_ERR(L_DACP, evbuffer_add_buffer(hreq->reply, playlists)); - CHECK_ERR(L_DACP, evbuffer_add_buffer(hreq->reply, songlist)); + CHECK_ERR(L_DACP, evbuffer_add_buffer(hreq->out_body, playlists)); + CHECK_ERR(L_DACP, evbuffer_add_buffer(hreq->out_body, songlist)); evbuffer_free(playlists); evbuffer_free(songlist); - dmap_add_char(hreq->reply, "apsm", status.shuffle); /* 9, daap.playlistshufflemode - not part of mlcl container */ - dmap_add_char(hreq->reply, "aprm", status.repeat); /* 9, daap.playlistrepeatmode - not part of mlcl container */ + dmap_add_char(hreq->out_body, "apsm", status.shuffle); /* 9, daap.playlistshufflemode - not part of mlcl container */ + dmap_add_char(hreq->out_body, "aprm", status.repeat); /* 9, daap.playlistrepeatmode - not part of mlcl container */ - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, 0); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, 0); return 0; @@ -1933,11 +1933,11 @@ dacp_reply_playqueueedit_clear(struct httpd_request *hreq) db_queue_clear(status.item_id); } - dmap_add_container(hreq->reply, "cacr", 24); /* 8 + len */ - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ - dmap_add_int(hreq->reply, "miid", 0); /* 12 */ + dmap_add_container(hreq->out_body, "cacr", 24); /* 8 + len */ + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ + dmap_add_int(hreq->out_body, "miid", 0); /* 12 */ - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, 0); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, 0); return 0; } @@ -2075,7 +2075,7 @@ dacp_reply_playqueueedit_add(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -2123,7 +2123,7 @@ dacp_reply_playqueueedit_move(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -2159,7 +2159,7 @@ dacp_reply_playqueueedit_remove(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -2280,11 +2280,11 @@ dacp_reply_playstatusupdate(struct httpd_request *hreq) // to use when he calls again. if (reqd_rev != current_rev) { - ret = make_playstatusupdate(hreq->reply); + ret = make_playstatusupdate(hreq->out_body); if (ret < 0) httpd_send_error(hreq, 500, "Internal Server Error"); else - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, 0); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, 0); return ret; } @@ -2360,8 +2360,8 @@ dacp_reply_nowplayingartwork(struct httpd_request *hreq) if (ret < 0) goto no_artwork; - ret = artwork_get_item(hreq->reply, id, max_w, max_h, 0); - len = evbuffer_get_length(hreq->reply); + ret = artwork_get_item(hreq->out_body, id, max_w, max_h, 0); + len = evbuffer_get_length(hreq->out_body); switch (ret) { @@ -2375,7 +2375,7 @@ dacp_reply_nowplayingartwork(struct httpd_request *hreq) default: if (len > 0) - evbuffer_drain(hreq->reply, len); + evbuffer_drain(hreq->out_body, len); goto no_artwork; } @@ -2385,7 +2385,7 @@ dacp_reply_nowplayingartwork(struct httpd_request *hreq) snprintf(clen, sizeof(clen), "%ld", (long)len); httpd_header_add(hreq->out_headers, "Content-Length", clen); - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; no_artwork: @@ -2479,14 +2479,14 @@ dacp_reply_getproperty(struct httpd_request *hreq) free_queue_item(queue_item, 0); len = evbuffer_get_length(proplist); - dmap_add_container(hreq->reply, "cmgt", 12 + len); - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ + dmap_add_container(hreq->out_body, "cmgt", 12 + len); + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ - CHECK_ERR(L_DACP, evbuffer_add_buffer(hreq->reply, proplist)); + CHECK_ERR(L_DACP, evbuffer_add_buffer(hreq->out_body, proplist)); evbuffer_free(proplist); - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, 0); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, 0); return 0; @@ -2541,7 +2541,7 @@ dacp_reply_setproperty(struct httpd_request *hreq) httpd_query_iterate(hreq->query, setproperty_cb, hreq); /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -2562,14 +2562,14 @@ dacp_reply_getspeakers(struct httpd_request *hreq) player_speaker_enumerate(speaker_enum_cb, spklist); len = evbuffer_get_length(spklist); - dmap_add_container(hreq->reply, "casp", 12 + len); - dmap_add_int(hreq->reply, "mstt", 200); /* 12 */ + dmap_add_container(hreq->out_body, "casp", 12 + len); + dmap_add_int(hreq->out_body, "mstt", 200); /* 12 */ - evbuffer_add_buffer(hreq->reply, spklist); + evbuffer_add_buffer(hreq->out_body, spklist); evbuffer_free(spklist); - httpd_send_reply(hreq, HTTP_OK, "OK", hreq->reply, 0); + httpd_send_reply(hreq, HTTP_OK, "OK", hreq->out_body, 0); return 0; } @@ -2659,7 +2659,7 @@ dacp_reply_setspeakers(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -2685,7 +2685,7 @@ dacp_reply_volumeup(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -2711,7 +2711,7 @@ dacp_reply_volumedown(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -2738,7 +2738,7 @@ dacp_reply_mutetoggle(struct httpd_request *hreq) } /* 204 No Content is the canonical reply */ - httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); return 0; } @@ -2867,11 +2867,7 @@ dacp_request(struct httpd_request *hreq) /* Content-Type for all DACP replies; can be overriden as needed */ httpd_header_add(hreq->out_headers, "Content-Type", "application/x-dmap-tagged"); - CHECK_NULL(L_DACP, hreq->reply = evbuffer_new()); - hreq->handler(hreq); - - evbuffer_free(hreq->reply); } // Forward diff --git a/src/httpd_internal.h b/src/httpd_internal.h index 8ca06d1a..d76cdfde 100644 --- a/src/httpd_internal.h +++ b/src/httpd_internal.h @@ -8,6 +8,8 @@ #include #include +struct httpd_request; + typedef struct evhttp httpd_server; typedef struct evhttp_connection httpd_connection; typedef struct evhttp_request httpd_backend; @@ -32,6 +34,53 @@ enum httpd_send_flags HTTPD_SEND_NO_GZIP = (1 << 0), }; + +/*---------------------------------- MODULES ---------------------------------*/ + +// 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); +}; + +/* + * Maps a regex of the request path to a handler of the request + */ +struct httpd_uri_map +{ + enum httpd_methods method; + char *regexp; + int (*handler)(struct httpd_request *hreq); + void *preg; +}; + + +/*------------------------------- HTTPD STRUCTS ------------------------------*/ + /* * Contains a parsed version of the URI httpd got. The URI may have been * complete: @@ -85,69 +134,17 @@ struct httpd_request { struct evbuffer *in_body; // Response headers httpd_headers *out_headers; - // Reply evbuffer - struct evbuffer *reply; + // Response body + struct evbuffer *out_body; + // The module that will process this request + struct httpd_module *module; // A pointer to the handler that will process the request int (*handler)(struct httpd_request *hreq); }; -/*---------------------------------- MODULES ---------------------------------*/ - -// 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); -}; - -/* - * Maps a regex of the request path to a handler of the request - */ -struct httpd_uri_map -{ - enum httpd_methods method; - char *regexp; - int (*handler)(struct httpd_request *hreq); - void *preg; -}; - - -/* - * Helper to free the parsed uri struct - */ -void -httpd_uri_free(struct httpd_uri_parsed *parsed); - -/* - * Parse an URI into the struct - */ -struct httpd_uri_parsed * -httpd_uri_parse(const char *uri); +/*------------------------------ HTTPD FUNCTIONS -----------------------------*/ void httpd_stream_file(struct httpd_request *hreq, int id); diff --git a/src/httpd_jsonapi.c b/src/httpd_jsonapi.c index 9b490a06..9bc26ef1 100644 --- a/src/httpd_jsonapi.c +++ b/src/httpd_jsonapi.c @@ -867,7 +867,7 @@ jsonapi_reply_config(struct httpd_request *hreq) json_object_object_add(jreply, "allow_modifying_stored_playlists", json_object_new_boolean(allow_modifying_stored_playlists)); safe_json_add_string(jreply, "default_playlist_directory", default_playlist_directory); - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); @@ -974,7 +974,7 @@ jsonapi_reply_settings_get(struct httpd_request *hreq) json_object_object_add(jreply, "categories", json_categories); - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); @@ -1006,7 +1006,7 @@ jsonapi_reply_settings_category_get(struct httpd_request *hreq) return HTTP_INTERNAL; } - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); @@ -1048,7 +1048,7 @@ jsonapi_reply_settings_option_get(struct httpd_request *hreq) return HTTP_INTERNAL; } - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); @@ -1236,7 +1236,7 @@ jsonapi_reply_library(struct httpd_request *hreq) } } - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); return HTTP_OK; @@ -1329,7 +1329,7 @@ jsonapi_reply_spotify(struct httpd_request *hreq) json_object_object_add(jreply, "enabled", json_object_new_boolean(false)); #endif - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); @@ -1363,7 +1363,7 @@ jsonapi_reply_lastfm(struct httpd_request *hreq) json_object_object_add(jreply, "enabled", json_object_new_boolean(enabled)); json_object_object_add(jreply, "scrobbling_enabled", json_object_new_boolean(scrobbling_enabled)); - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); @@ -1430,7 +1430,7 @@ jsonapi_reply_lastfm_login(struct httpd_request *hreq) json_object_object_add(jreply, "errors", errors); } - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); @@ -1526,7 +1526,7 @@ jsonapi_reply_pairing_get(struct httpd_request *hreq) json_object_object_add(jreply, "active", json_object_new_boolean(false)); } - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); free(remote_name); @@ -1603,7 +1603,7 @@ jsonapi_reply_outputs_get_byid(struct httpd_request *hreq) } jreply = speaker_to_json(&speaker_info); - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); @@ -1723,7 +1723,7 @@ jsonapi_reply_outputs(struct httpd_request *hreq) jreply = json_object_new_object(); json_object_object_add(jreply, "outputs", outputs); - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); @@ -2132,7 +2132,7 @@ jsonapi_reply_player(struct httpd_request *hreq) } } - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply))); jparse_free(reply); @@ -2520,7 +2520,7 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq) reply = json_object_new_object(); json_object_object_add(reply, "count", json_object_new_int(total_count)); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); jparse_free(reply); } @@ -2741,7 +2741,7 @@ jsonapi_reply_queue(struct httpd_request *hreq) json_object_array_add(items, item); } - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "outputs: Couldn't add outputs to response buffer.\n"); @@ -2980,7 +2980,7 @@ jsonapi_reply_library_artists(struct httpd_request *hreq) json_object_object_add(reply, "offset", json_object_new_int(query_params.offset)); json_object_object_add(reply, "limit", json_object_new_int(query_params.limit)); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add artists to response buffer.\n"); @@ -3014,7 +3014,7 @@ jsonapi_reply_library_artist(struct httpd_request *hreq) goto error; } - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add artists to response buffer.\n"); @@ -3066,7 +3066,7 @@ jsonapi_reply_library_artist_albums(struct httpd_request *hreq) json_object_object_add(reply, "offset", json_object_new_int(query_params.offset)); json_object_object_add(reply, "limit", json_object_new_int(query_params.limit)); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add albums to response buffer.\n"); @@ -3129,7 +3129,7 @@ jsonapi_reply_library_albums(struct httpd_request *hreq) json_object_object_add(reply, "offset", json_object_new_int(query_params.offset)); json_object_object_add(reply, "limit", json_object_new_int(query_params.limit)); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add albums to response buffer.\n"); @@ -3163,7 +3163,7 @@ jsonapi_reply_library_album(struct httpd_request *hreq) goto error; } - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add artists to response buffer.\n"); @@ -3215,7 +3215,7 @@ jsonapi_reply_library_album_tracks(struct httpd_request *hreq) json_object_object_add(reply, "offset", json_object_new_int(query_params.offset)); json_object_object_add(reply, "limit", json_object_new_int(query_params.limit)); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add tracks to response buffer.\n"); @@ -3297,7 +3297,7 @@ jsonapi_reply_library_tracks_get_byid(struct httpd_request *hreq) reply = track_to_json(&dbmfi); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add track to response buffer.\n"); @@ -3505,7 +3505,7 @@ jsonapi_reply_library_track_playlists(struct httpd_request *hreq) json_object_object_add(reply, "offset", json_object_new_int(query_params.offset)); json_object_object_add(reply, "limit", json_object_new_int(query_params.limit)); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "track playlists: Couldn't add playlists to response buffer.\n"); @@ -3556,7 +3556,7 @@ jsonapi_reply_library_playlists(struct httpd_request *hreq) json_object_object_add(reply, "offset", json_object_new_int(query_params.offset)); json_object_object_add(reply, "limit", json_object_new_int(query_params.limit)); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add playlists to response buffer.\n"); @@ -3607,7 +3607,7 @@ jsonapi_reply_library_playlist_get(struct httpd_request *hreq) goto error; } - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add playlist to response buffer.\n"); @@ -3711,7 +3711,7 @@ jsonapi_reply_library_playlist_tracks(struct httpd_request *hreq) json_object_object_add(reply, "offset", json_object_new_int(query_params.offset)); json_object_object_add(reply, "limit", json_object_new_int(query_params.limit)); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "playlist tracks: Couldn't add tracks to response buffer.\n"); @@ -3789,7 +3789,7 @@ jsonapi_reply_library_playlist_playlists(struct httpd_request *hreq) json_object_object_add(reply, "offset", json_object_new_int(query_params.offset)); json_object_object_add(reply, "limit", json_object_new_int(query_params.limit)); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "playlist tracks: Couldn't add tracks to response buffer.\n"); @@ -3950,7 +3950,7 @@ jsonapi_reply_library_browse(struct httpd_request *hreq) json_object_object_add(reply, "offset", json_object_new_int(query_params.offset)); json_object_object_add(reply, "limit", json_object_new_int(query_params.limit)); - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add browse items to response buffer.\n"); @@ -4023,7 +4023,7 @@ jsonapi_reply_library_browseitem(struct httpd_request *hreq) goto error; } - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add browse item to response buffer.\n"); @@ -4088,7 +4088,7 @@ jsonapi_reply_library_count(struct httpd_request *hreq) free(qp.filter); - CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply))); + CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(jreply))); jparse_free(jreply); return HTTP_OK; @@ -4182,7 +4182,7 @@ jsonapi_reply_library_files(struct httpd_request *hreq) json_object_object_add(playlists, "limit", json_object_new_int(query_params.limit)); // Build JSON response - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "browse: Couldn't add directories to response buffer.\n"); @@ -4587,7 +4587,7 @@ jsonapi_reply_search(struct httpd_request *hreq) goto error; } - ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply)); + ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); if (ret < 0) DPRINTF(E_LOG, L_WEB, "playlist tracks: Couldn't add tracks to response buffer.\n"); @@ -4721,8 +4721,6 @@ jsonapi_request(struct httpd_request *hreq) return; } - CHECK_NULL(L_WEB, hreq->reply = evbuffer_new()); - status_code = hreq->handler(hreq); if (status_code >= 400) @@ -4732,10 +4730,10 @@ jsonapi_request(struct httpd_request *hreq) { case HTTP_OK: /* 200 OK */ httpd_header_add(hreq->out_headers, "Content-Type", "application/json"); - httpd_send_reply(hreq, status_code, "OK", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, status_code, "OK", hreq->out_body, HTTPD_SEND_NO_GZIP); break; case HTTP_NOCONTENT: /* 204 No Content */ - httpd_send_reply(hreq, status_code, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP); + httpd_send_reply(hreq, status_code, "No Content", hreq->out_body, HTTPD_SEND_NO_GZIP); break; case HTTP_NOTMODIFIED: /* 304 Not Modified */ httpd_send_reply(hreq, HTTP_NOTMODIFIED, NULL, NULL, HTTPD_SEND_NO_GZIP); @@ -4757,8 +4755,6 @@ jsonapi_request(struct httpd_request *hreq) httpd_send_error(hreq, HTTP_INTERNAL, "Internal Server Error"); break; } - - evbuffer_free(hreq->reply); } static int diff --git a/src/httpd_libevhttp.c b/src/httpd_libevhttp.c index fcaf50a4..5b302c9c 100644 --- a/src/httpd_libevhttp.c +++ b/src/httpd_libevhttp.c @@ -193,6 +193,12 @@ httpd_backend_input_buffer_get(httpd_backend *backend) return evhttp_request_get_input_buffer(backend); } +struct evbuffer * +httpd_backend_output_buffer_get(httpd_backend *backend) +{ + return evhttp_request_get_output_buffer(backend); +} + int httpd_backend_peer_get(char **addr, uint16_t *port, httpd_backend *backend) { diff --git a/src/httpd_oauth.c b/src/httpd_oauth.c index 1c3f8f18..a097f475 100644 --- a/src/httpd_oauth.c +++ b/src/httpd_oauth.c @@ -54,12 +54,12 @@ oauth_reply_spotify(struct httpd_request *hreq) ret = spotifywebapi_oauth_callback(hreq->query, redirect_uri, &errmsg); if (ret < 0) { - DPRINTF(E_LOG, L_WEB, "Could not parse Spotify OAuth callback '%s': %s\n", hreq->uri_parsed->uri, errmsg); + DPRINTF(E_LOG, L_WEB, "Could not parse Spotify OAuth callback '%s': %s\n", hreq->uri, errmsg); httpd_send_error(hreq, HTTP_INTERNAL, errmsg); return -1; } - httpd_redirect_to(hreq->req, "/#/settings/online-services"); + httpd_redirect_to(hreq, "/#/settings/online-services"); return 0; }