mirror of
https://github.com/owntone/owntone-server.git
synced 2025-04-14 08:16:17 -04:00
[httpd] Try doing request handling in worker thread
This commit is contained in:
parent
4736e10d11
commit
50a319df2b
102
src/httpd.c
102
src/httpd.c
@ -291,65 +291,12 @@ modules_search(const char *path)
|
|||||||
|
|
||||||
/* --------------------------- REQUEST HELPERS ------------------------------ */
|
/* --------------------------- REQUEST HELPERS ------------------------------ */
|
||||||
|
|
||||||
static void
|
void
|
||||||
request_unset(struct httpd_request *hreq)
|
httpd_request_handler_set(struct httpd_request *hreq)
|
||||||
{
|
{
|
||||||
if (hreq->out_body)
|
|
||||||
evbuffer_free(hreq->out_body);
|
|
||||||
|
|
||||||
httpd_uri_parsed_free(hreq->uri_parsed);
|
|
||||||
httpd_backend_data_free(hreq->backend_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
request_set(struct httpd_request *hreq, httpd_backend *backend, const char *uri, const char *user_agent)
|
|
||||||
{
|
|
||||||
httpd_backend_data *backend_data;
|
|
||||||
struct httpd_uri_map *map;
|
struct httpd_uri_map *map;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(hreq, 0, sizeof(struct httpd_request));
|
|
||||||
|
|
||||||
// Populate hreq by getting values from the backend (or from the caller)
|
|
||||||
hreq->backend = backend;
|
|
||||||
if (backend)
|
|
||||||
{
|
|
||||||
backend_data = httpd_backend_data_create(backend);
|
|
||||||
hreq->backend_data = backend_data;
|
|
||||||
|
|
||||||
hreq->uri = httpd_backend_uri_get(backend, backend_data);
|
|
||||||
hreq->uri_parsed = httpd_uri_parsed_create(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, backend_data);
|
|
||||||
|
|
||||||
hreq->user_agent = httpd_header_find(hreq->in_headers, "User-Agent");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hreq->uri = uri;
|
|
||||||
hreq->uri_parsed = httpd_uri_parsed_create_fromuri(uri);
|
|
||||||
|
|
||||||
hreq->user_agent = user_agent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hreq->uri_parsed)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_HTTPD, "Unable to parse URI '%s' in request from '%s'\n", hreq->uri, hreq->peer_address);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
|
|
||||||
hreq->path = httpd_uri_path_get(hreq->uri_parsed);
|
|
||||||
hreq->query = httpd_uri_query_get(hreq->uri_parsed);
|
|
||||||
httpd_uri_path_parts_get(&hreq->path_parts, hreq->uri_parsed);
|
|
||||||
|
|
||||||
// Path with e.g. /api -> JSON module
|
// Path with e.g. /api -> JSON module
|
||||||
hreq->module = modules_search(hreq->path);
|
hreq->module = modules_search(hreq->path);
|
||||||
if (!hreq->module)
|
if (!hreq->module)
|
||||||
@ -855,36 +802,28 @@ handle_cors_preflight(struct httpd_request *hreq, const char *allow_origin)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
httpd_gen_cb(httpd_backend *backend, void *arg)
|
request_cb(struct httpd_request *hreq, void *arg)
|
||||||
{
|
{
|
||||||
struct httpd_request hreq_stack;
|
|
||||||
struct httpd_request *hreq = &hreq_stack; // Shorthand
|
|
||||||
|
|
||||||
// This is to make modifications to e.g. evhttps's request object
|
|
||||||
httpd_backend_preprocess(backend);
|
|
||||||
|
|
||||||
// Populates the hreq struct
|
|
||||||
request_set(hreq, backend, NULL, NULL);
|
|
||||||
|
|
||||||
// Did we get a CORS preflight request?
|
// Did we get a CORS preflight request?
|
||||||
if (handle_cors_preflight(hreq, httpd_allow_origin) == 0)
|
if (handle_cors_preflight(hreq, httpd_allow_origin) == 0)
|
||||||
{
|
{
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hreq->uri || !hreq->uri_parsed)
|
if (!hreq->uri || !hreq->uri_parsed)
|
||||||
{
|
{
|
||||||
DPRINTF(E_WARN, L_HTTPD, "Invalid URI in request: '%s'\n", hreq->uri);
|
DPRINTF(E_WARN, L_HTTPD, "Invalid URI in request: '%s'\n", hreq->uri);
|
||||||
httpd_redirect_to(hreq, "/");
|
httpd_redirect_to(hreq, "/");
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
else if (!hreq->path)
|
else if (!hreq->path)
|
||||||
{
|
{
|
||||||
DPRINTF(E_WARN, L_HTTPD, "Invalid path in request: '%s'\n", hreq->uri);
|
DPRINTF(E_WARN, L_HTTPD, "Invalid path in request: '%s'\n", hreq->uri);
|
||||||
httpd_redirect_to(hreq, "/");
|
httpd_redirect_to(hreq, "/");
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpd_request_handler_set(hreq);
|
||||||
if (hreq->module)
|
if (hreq->module)
|
||||||
{
|
{
|
||||||
DPRINTF(E_DBG, hreq->module->logdomain, "%s request: '%s' (thread %ld)\n", hreq->module->name, hreq->uri, syscall(SYS_gettid));
|
DPRINTF(E_DBG, hreq->module->logdomain, "%s request: '%s' (thread %ld)\n", hreq->module->name, hreq->uri, syscall(SYS_gettid));
|
||||||
@ -896,26 +835,11 @@ httpd_gen_cb(httpd_backend *backend, void *arg)
|
|||||||
DPRINTF(E_DBG, L_HTTPD, "HTTP request: '%s'\n", hreq->uri);
|
DPRINTF(E_DBG, L_HTTPD, "HTTP request: '%s'\n", hreq->uri);
|
||||||
serve_file(hreq);
|
serve_file(hreq);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
request_unset(hreq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------- HTTPD API -------------------------------- */
|
/* ------------------------------- HTTPD API -------------------------------- */
|
||||||
|
|
||||||
void
|
|
||||||
httpd_request_unset(struct httpd_request *hreq)
|
|
||||||
{
|
|
||||||
request_unset(hreq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
httpd_request_set(struct httpd_request *hreq, const char *uri, const char *user_agent)
|
|
||||||
{
|
|
||||||
request_set(hreq, NULL, uri, user_agent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Thread: httpd */
|
/* Thread: httpd */
|
||||||
void
|
void
|
||||||
httpd_stream_file(struct httpd_request *hreq, int id)
|
httpd_stream_file(struct httpd_request *hreq, int id)
|
||||||
@ -1484,16 +1408,6 @@ httpd_basic_auth(struct httpd_request *hreq, const char *user, const char *passw
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
httpd_peer_get(const char **address, ev_uint16_t *port, struct evhttp_connection *evcon)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR
|
|
||||||
evhttp_connection_get_peer(evcon, address, port);
|
|
||||||
#else
|
|
||||||
evhttp_connection_get_peer(evcon, (char **)address, port);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Thread: main */
|
/* Thread: main */
|
||||||
int
|
int
|
||||||
httpd_init(const char *webroot)
|
httpd_init(const char *webroot)
|
||||||
@ -1537,7 +1451,7 @@ httpd_init(const char *webroot)
|
|||||||
event_add(exitev, NULL);
|
event_add(exitev, NULL);
|
||||||
|
|
||||||
httpd_port = cfg_getint(cfg_getsec(cfg, "library"), "port");
|
httpd_port = cfg_getint(cfg_getsec(cfg, "library"), "port");
|
||||||
httpd_serv = httpd_server_new(evbase_httpd, httpd_port, httpd_gen_cb, NULL);
|
httpd_serv = httpd_server_new(evbase_httpd, httpd_port, request_cb, NULL);
|
||||||
if (!httpd_serv)
|
if (!httpd_serv)
|
||||||
{
|
{
|
||||||
DPRINTF(E_FATAL, L_HTTPD, "Could not create HTTP server on port %d (server already running?)\n", httpd_port);
|
DPRINTF(E_FATAL, L_HTTPD, "Could not create HTTP server on port %d (server already running?)\n", httpd_port);
|
||||||
|
@ -2306,17 +2306,22 @@ daap_session_is_valid(int id)
|
|||||||
struct evbuffer *
|
struct evbuffer *
|
||||||
daap_reply_build(const char *uri, const char *user_agent, int is_remote)
|
daap_reply_build(const char *uri, const char *user_agent, int is_remote)
|
||||||
{
|
{
|
||||||
struct httpd_request hreq;
|
struct httpd_request *hreq;
|
||||||
struct evbuffer *out_body;
|
struct evbuffer *out_body = NULL;
|
||||||
struct daap_session session;
|
struct daap_session session;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_DAAP, "Building reply for DAAP request: '%s'\n", uri);
|
DPRINTF(E_DBG, L_DAAP, "Building reply for DAAP request: '%s'\n", uri);
|
||||||
|
|
||||||
out_body = NULL;
|
hreq = httpd_request_new(NULL, uri, user_agent);
|
||||||
|
if (!hreq)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_DAAP, "Error building request: '%s'\n", uri);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
httpd_request_set(&hreq, uri, user_agent);
|
httpd_request_handler_set(hreq);
|
||||||
if (!(&hreq)->handler)
|
if (!hreq->handler)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_DAAP, "Cannot build reply, unrecognized path in request: '%s'\n", uri);
|
DPRINTF(E_LOG, L_DAAP, "Cannot build reply, unrecognized path in request: '%s'\n", uri);
|
||||||
goto out;
|
goto out;
|
||||||
@ -2325,20 +2330,20 @@ daap_reply_build(const char *uri, const char *user_agent, int is_remote)
|
|||||||
memset(&session, 0, sizeof(struct daap_session));
|
memset(&session, 0, sizeof(struct daap_session));
|
||||||
session.is_remote = (bool)is_remote;
|
session.is_remote = (bool)is_remote;
|
||||||
|
|
||||||
hreq.extra_data = &session;
|
hreq->extra_data = &session;
|
||||||
|
|
||||||
ret = hreq.handler(&hreq);
|
ret = hreq->handler(hreq);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take ownership of the reply
|
// Take ownership of the reply
|
||||||
out_body = hreq.out_body;
|
out_body = hreq->out_body;
|
||||||
hreq.out_body = NULL;
|
hreq->out_body = NULL;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
httpd_request_unset(&hreq);
|
httpd_request_free(hreq);
|
||||||
|
|
||||||
return out_body;
|
return out_body;
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,13 @@ struct httpd_request;
|
|||||||
|
|
||||||
// Declaring here instead of including event2/http.h makes it easier to support
|
// Declaring here instead of including event2/http.h makes it easier to support
|
||||||
// other backends than evhttp in the future, e.g. libevhtp
|
// other backends than evhttp in the future, e.g. libevhtp
|
||||||
struct evhttp;
|
struct httpd_server;
|
||||||
struct evhttp_connection;
|
struct evhttp_connection;
|
||||||
struct evhttp_request;
|
struct evhttp_request;
|
||||||
struct evkeyvalq;
|
struct evkeyvalq;
|
||||||
struct httpd_uri_parsed;
|
struct httpd_uri_parsed;
|
||||||
|
|
||||||
typedef struct evhttp httpd_server;
|
typedef struct httpd_server httpd_server;
|
||||||
typedef struct evhttp_connection httpd_connection;
|
typedef struct evhttp_connection httpd_connection;
|
||||||
typedef struct evhttp_request httpd_backend;
|
typedef struct evhttp_request httpd_backend;
|
||||||
typedef struct evkeyvalq httpd_headers;
|
typedef struct evkeyvalq httpd_headers;
|
||||||
@ -56,7 +56,7 @@ typedef struct httpd_uri_parsed httpd_uri_parsed;
|
|||||||
typedef void httpd_backend_data; // Not used for evhttp
|
typedef void httpd_backend_data; // Not used for evhttp
|
||||||
|
|
||||||
typedef char *httpd_uri_path_parts[31];
|
typedef char *httpd_uri_path_parts[31];
|
||||||
typedef void (*httpd_general_cb)(httpd_backend *backend, void *arg);
|
typedef void (*httpd_request_cb)(struct httpd_request *hreq, void *arg);
|
||||||
typedef void (*httpd_connection_closecb)(httpd_connection *conn, void *arg);
|
typedef void (*httpd_connection_closecb)(httpd_connection *conn, void *arg);
|
||||||
typedef void (*httpd_connection_chunkcb)(httpd_connection *conn, void *arg);
|
typedef void (*httpd_connection_chunkcb)(httpd_connection *conn, void *arg);
|
||||||
typedef void (*httpd_query_iteratecb)(const char *key, const char *val, void *arg);
|
typedef void (*httpd_query_iteratecb)(const char *key, const char *val, void *arg);
|
||||||
@ -186,10 +186,7 @@ void
|
|||||||
httpd_stream_file(struct httpd_request *hreq, int id);
|
httpd_stream_file(struct httpd_request *hreq, int id);
|
||||||
|
|
||||||
void
|
void
|
||||||
httpd_request_set(struct httpd_request *hreq, const char *uri, const char *user_agent);
|
httpd_request_handler_set(struct httpd_request *hreq);
|
||||||
|
|
||||||
void
|
|
||||||
httpd_request_unset(struct httpd_request *hreq);
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
httpd_request_not_modified_since(struct httpd_request *hreq, time_t mtime);
|
httpd_request_not_modified_since(struct httpd_request *hreq, time_t mtime);
|
||||||
@ -290,11 +287,17 @@ httpd_request_closecb_set(struct httpd_request *hreq, httpd_connection_closecb c
|
|||||||
struct event_base *
|
struct event_base *
|
||||||
httpd_request_evbase_get(struct httpd_request *hreq);
|
httpd_request_evbase_get(struct httpd_request *hreq);
|
||||||
|
|
||||||
|
void
|
||||||
|
httpd_request_free(struct httpd_request *hreq);
|
||||||
|
|
||||||
|
struct httpd_request *
|
||||||
|
httpd_request_new(httpd_backend *backend, const char *uri, const char *user_agent);
|
||||||
|
|
||||||
void
|
void
|
||||||
httpd_server_free(httpd_server *server);
|
httpd_server_free(httpd_server *server);
|
||||||
|
|
||||||
httpd_server *
|
httpd_server *
|
||||||
httpd_server_new(struct event_base *evbase, unsigned short port, httpd_general_cb cb, void *arg);
|
httpd_server_new(struct event_base *evbase, unsigned short port, httpd_request_cb cb, void *arg);
|
||||||
|
|
||||||
void
|
void
|
||||||
httpd_server_allow_origin_set(httpd_server *server, bool allow);
|
httpd_server_allow_origin_set(httpd_server *server, bool allow);
|
||||||
@ -344,9 +347,6 @@ httpd_backend_peer_get(const char **addr, uint16_t *port, httpd_backend *backend
|
|||||||
int
|
int
|
||||||
httpd_backend_method_get(enum httpd_methods *method, httpd_backend *backend);
|
httpd_backend_method_get(enum httpd_methods *method, httpd_backend *backend);
|
||||||
|
|
||||||
void
|
|
||||||
httpd_backend_preprocess(httpd_backend *backend);
|
|
||||||
|
|
||||||
httpd_uri_parsed *
|
httpd_uri_parsed *
|
||||||
httpd_uri_parsed_create(httpd_backend *backend);
|
httpd_uri_parsed_create(httpd_backend *backend);
|
||||||
|
|
||||||
|
@ -1,14 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Espen Jürgensen <espenjurgensen@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|
||||||
#include <event2/http.h>
|
#include <event2/http.h>
|
||||||
#include <event2/http_struct.h>
|
#include <event2/http_struct.h>
|
||||||
|
#include <event2/http_compat.h>
|
||||||
#include <event2/keyvalq_struct.h>
|
#include <event2/keyvalq_struct.h>
|
||||||
|
#include <event2/buffer.h>
|
||||||
|
|
||||||
#include "misc.h" // For net_evhttp_bind
|
#include "misc.h" // For net_evhttp_bind
|
||||||
|
#include "worker.h"
|
||||||
|
#include "logger.h"
|
||||||
#include "httpd_internal.h"
|
#include "httpd_internal.h"
|
||||||
|
|
||||||
|
|
||||||
struct httpd_uri_parsed
|
struct httpd_uri_parsed
|
||||||
{
|
{
|
||||||
struct evhttp_uri *ev_uri;
|
struct evhttp_uri *ev_uri;
|
||||||
@ -17,6 +44,19 @@ struct httpd_uri_parsed
|
|||||||
httpd_uri_path_parts path_parts;
|
httpd_uri_path_parts path_parts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct httpd_server
|
||||||
|
{
|
||||||
|
struct evhttp *evhttp;
|
||||||
|
httpd_request_cb request_cb;
|
||||||
|
void *request_cb_arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cmdargs
|
||||||
|
{
|
||||||
|
httpd_server *server;
|
||||||
|
httpd_backend *backend;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
httpd_query_value_find(httpd_query *query, const char *key)
|
httpd_query_value_find(httpd_query *query, const char *key)
|
||||||
@ -107,29 +147,148 @@ httpd_request_evbase_get(struct httpd_request *hreq)
|
|||||||
return evhttp_connection_get_base(conn);
|
return evhttp_connection_get_base(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
httpd_request_free(struct httpd_request *hreq)
|
||||||
|
{
|
||||||
|
if (!hreq)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (hreq->out_body)
|
||||||
|
evbuffer_free(hreq->out_body);
|
||||||
|
|
||||||
|
httpd_uri_parsed_free(hreq->uri_parsed);
|
||||||
|
httpd_backend_data_free(hreq->backend_data);
|
||||||
|
free(hreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct httpd_request *
|
||||||
|
httpd_request_new(httpd_backend *backend, const char *uri, const char *user_agent)
|
||||||
|
{
|
||||||
|
struct httpd_request *hreq;
|
||||||
|
httpd_backend_data *backend_data;
|
||||||
|
|
||||||
|
CHECK_NULL(L_HTTPD, hreq = calloc(1, sizeof(struct httpd_request)));
|
||||||
|
|
||||||
|
// Populate hreq by getting values from the backend (or from the caller)
|
||||||
|
hreq->backend = backend;
|
||||||
|
if (backend)
|
||||||
|
{
|
||||||
|
backend_data = httpd_backend_data_create(backend);
|
||||||
|
hreq->backend_data = backend_data;
|
||||||
|
|
||||||
|
hreq->uri = httpd_backend_uri_get(backend, backend_data);
|
||||||
|
hreq->uri_parsed = httpd_uri_parsed_create(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, backend_data);
|
||||||
|
|
||||||
|
hreq->user_agent = httpd_header_find(hreq->in_headers, "User-Agent");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hreq->uri = uri;
|
||||||
|
hreq->uri_parsed = httpd_uri_parsed_create_fromuri(uri);
|
||||||
|
|
||||||
|
hreq->user_agent = user_agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hreq->uri_parsed)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_HTTPD, "Unable to parse URI '%s' in request from '%s'\n", hreq->uri, hreq->peer_address);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
|
||||||
|
hreq->path = httpd_uri_path_get(hreq->uri_parsed);
|
||||||
|
hreq->query = httpd_uri_query_get(hreq->uri_parsed);
|
||||||
|
httpd_uri_path_parts_get(&hreq->path_parts, hreq->uri_parsed);
|
||||||
|
|
||||||
|
return hreq;
|
||||||
|
|
||||||
|
error:
|
||||||
|
httpd_request_free(hreq);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
request_free_cb(httpd_backend *backend, void *arg)
|
||||||
|
{
|
||||||
|
struct httpd_request *hreq = arg;
|
||||||
|
|
||||||
|
httpd_request_free(hreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Executed in a worker thread
|
||||||
|
static void
|
||||||
|
gencb_worker_cb(void *arg)
|
||||||
|
{
|
||||||
|
struct cmdargs *cmd = arg;
|
||||||
|
httpd_server *server = cmd->server;
|
||||||
|
httpd_backend *backend = cmd->backend;
|
||||||
|
struct httpd_request *hreq;
|
||||||
|
|
||||||
|
hreq = httpd_request_new(backend, NULL, NULL);
|
||||||
|
if (!hreq)
|
||||||
|
{
|
||||||
|
evhttp_send_error(backend, HTTP_INTERNAL, "Internal error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
evhttp_request_set_on_complete_cb(backend, request_free_cb, hreq);
|
||||||
|
|
||||||
|
server->request_cb(hreq, server->request_cb_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback from evhttp in httpd thread
|
||||||
|
static void
|
||||||
|
gencb_httpd(httpd_backend *backend, void *server)
|
||||||
|
{
|
||||||
|
struct cmdargs cmd;
|
||||||
|
|
||||||
|
cmd.server = server;
|
||||||
|
cmd.backend = backend;
|
||||||
|
|
||||||
|
// Clear the proxy request flag set by evhttp if the request URI was absolute.
|
||||||
|
// It has side-effects on Connection: keep-alive
|
||||||
|
backend->flags &= ~EVHTTP_PROXY_REQUEST;
|
||||||
|
|
||||||
|
// Defer the execution to a worker thread
|
||||||
|
worker_execute(gencb_worker_cb, &cmd, sizeof(cmd), 0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
httpd_server_free(httpd_server *server)
|
httpd_server_free(httpd_server *server)
|
||||||
{
|
{
|
||||||
if (!server)
|
if (!server)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
evhttp_free(server);
|
evhttp_free(server->evhttp);
|
||||||
|
free(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
httpd_server *
|
httpd_server *
|
||||||
httpd_server_new(struct event_base *evbase, unsigned short port, httpd_general_cb cb, void *arg)
|
httpd_server_new(struct event_base *evbase, unsigned short port, httpd_request_cb cb, void *arg)
|
||||||
{
|
{
|
||||||
|
httpd_server *server;
|
||||||
int ret;
|
int ret;
|
||||||
struct evhttp *server = evhttp_new(evbase);
|
|
||||||
|
|
||||||
if (!server)
|
CHECK_NULL(L_HTTPD, server = calloc(1, sizeof(httpd_server)));
|
||||||
goto error;
|
CHECK_NULL(L_HTTPD, server->evhttp = evhttp_new(evbase));
|
||||||
|
|
||||||
ret = net_evhttp_bind(server, port, "httpd");
|
server->request_cb = cb;
|
||||||
|
server->request_cb_arg = arg;
|
||||||
|
|
||||||
|
ret = net_evhttp_bind(server->evhttp, port, "httpd");
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
evhttp_set_gencb(server, cb, arg);
|
evhttp_set_gencb(server->evhttp, gencb_httpd, server);
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
|
|
||||||
@ -141,7 +300,7 @@ httpd_server_new(struct event_base *evbase, unsigned short port, httpd_general_c
|
|||||||
void
|
void
|
||||||
httpd_server_allow_origin_set(httpd_server *server, bool allow)
|
httpd_server_allow_origin_set(httpd_server *server, bool allow)
|
||||||
{
|
{
|
||||||
evhttp_set_allowed_methods(server, EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_PUT | EVHTTP_REQ_DELETE | EVHTTP_REQ_HEAD | EVHTTP_REQ_OPTIONS);
|
evhttp_set_allowed_methods(server->evhttp, EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_PUT | EVHTTP_REQ_DELETE | EVHTTP_REQ_HEAD | EVHTTP_REQ_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -223,7 +382,11 @@ httpd_backend_peer_get(const char **addr, uint16_t *port, httpd_backend *backend
|
|||||||
if (!conn)
|
if (!conn)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
#ifdef HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR
|
||||||
|
evhttp_connection_get_peer(conn, addr, port);
|
||||||
|
#else
|
||||||
evhttp_connection_get_peer(conn, (char **)addr, port);
|
evhttp_connection_get_peer(conn, (char **)addr, port);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,14 +412,6 @@ httpd_backend_method_get(enum httpd_methods *method, httpd_backend *backend)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
httpd_backend_preprocess(httpd_backend *backend)
|
|
||||||
{
|
|
||||||
// Clear the proxy request flag set by evhttp if the request URI was absolute.
|
|
||||||
// It has side-effects on Connection: keep-alive
|
|
||||||
backend->flags &= ~EVHTTP_PROXY_REQUEST;
|
|
||||||
}
|
|
||||||
|
|
||||||
httpd_uri_parsed *
|
httpd_uri_parsed *
|
||||||
httpd_uri_parsed_create(httpd_backend *backend)
|
httpd_uri_parsed_create(httpd_backend *backend)
|
||||||
{
|
{
|
||||||
|
@ -162,35 +162,14 @@ static void
|
|||||||
streaming_end(void)
|
streaming_end(void)
|
||||||
{
|
{
|
||||||
struct streaming_session *session;
|
struct streaming_session *session;
|
||||||
<<<<<<< HEAD
|
|
||||||
struct evhttp_connection *evcon;
|
|
||||||
const char *address;
|
|
||||||
ev_uint16_t port;
|
|
||||||
=======
|
|
||||||
>>>>>>> [httpd] Remove all traces of evhttp from httpd modules
|
|
||||||
|
|
||||||
pthread_mutex_lock(&streaming_sessions_lck);
|
pthread_mutex_lock(&streaming_sessions_lck);
|
||||||
for (session = streaming_sessions; streaming_sessions; session = streaming_sessions)
|
for (session = streaming_sessions; streaming_sessions; session = streaming_sessions)
|
||||||
{
|
{
|
||||||
<<<<<<< HEAD
|
|
||||||
evcon = evhttp_request_get_connection(session->req);
|
|
||||||
if (evcon)
|
|
||||||
{
|
|
||||||
evhttp_connection_set_closecb(evcon, NULL, NULL);
|
|
||||||
httpd_peer_get(&address, &port, evcon);
|
|
||||||
DPRINTF(E_INFO, L_STREAMING, "Force close stream to %s:%d\n", address, (int)port);
|
|
||||||
}
|
|
||||||
evhttp_send_reply_end(session->req);
|
|
||||||
=======
|
|
||||||
DPRINTF(E_INFO, L_STREAMING, "Force close stream to %s:%d\n", session->hreq->peer_address, (int)session->hreq->peer_port);
|
DPRINTF(E_INFO, L_STREAMING, "Force close stream to %s:%d\n", session->hreq->peer_address, (int)session->hreq->peer_port);
|
||||||
|
|
||||||
httpd_request_closecb_set(session->hreq, NULL, NULL);
|
httpd_request_closecb_set(session->hreq, NULL, NULL);
|
||||||
<<<<<<< HEAD
|
|
||||||
httpd_reply_end_send(session->hreq);
|
|
||||||
>>>>>>> [httpd] Remove all traces of evhttp from httpd modules
|
|
||||||
=======
|
|
||||||
httpd_send_reply_end(session->hreq);
|
httpd_send_reply_end(session->hreq);
|
||||||
>>>>>>> [httpd] Changes to httpd_send_reply_chunk et al
|
|
||||||
|
|
||||||
streaming_sessions = session->next;
|
streaming_sessions = session->next;
|
||||||
free(session);
|
free(session);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user