Commit 14526a21 authored by Sergey Lyubka's avatar Sergey Lyubka

mg_add_uri_handler -> mg_set_request_handler()

parent a6cfbd25
...@@ -60,12 +60,26 @@ that take `struct mg_server *` parameter. Mongoose does not ...@@ -60,12 +60,26 @@ that take `struct mg_server *` parameter. Mongoose does not
mutex-protect `struct mg_server *`, therefore the best practice is mutex-protect `struct mg_server *`, therefore the best practice is
to call server management functions from the same thread (an IO thread). to call server management functions from the same thread (an IO thread).
void mg_add_uri_handler(struct mg_server *, const char *uri, mg_handler_t); void mg_set_auth_handler(struct mg_server *, mg_handler_t handler);
Adds an URI handler. If Mongoose gets a request and request's URI starts Sets authorization handler. Called by Mongoose on each request, before
with `uri`, then specified handler is called to serve the request. Thus, an performing any other action. Handler can return either `MG_AUTH_OK` or
`uri` is a match prefix. For example, if `uri` is "/", then all requests will `MG_AUTH_FAIL`. If `handler` returns `MG_AUTH_FAIL`, then Mongoose sends
be routed to the handler, because all URIs start with `/` character. digest authorization request to the client. If `handler returns `MG_AUTH_OK`,
then mongoose proceeds with handling the request. Handler function can use
`mg_authorize_digest()` function to verify authorization, or implement any other
custom authorization mechanism.
void mg_set_request_handler(struct mg_server *, mg_handler_t handler);
Sets a request handler. When set, `handler` will be called for each request.
Possible return values from a handler function are `MG_REQUEST_NOT_PROCESSED`,
`MG_REQUEST_PROCESSED` and `MG_REQUEST_CALL_AGAIN`. If handler returns
`MG_REQUEST_NOT_PROCESSED`, mongoose will proceed with handling the request.
If handler returns `MG_REQUEST_PROCESSED`, that signals mongoose that handler
has already processed the connection, and mongoose will skip to the next
request. `MG_REQUEST_CALL_AGAIN` tells mongoose to call request handler
again and again on each `mg_poll_server()` iteration.
When mongoose buffers in HTTP request and successfully parses it, it calls When mongoose buffers in HTTP request and successfully parses it, it calls
appropriate URI handler immediately for GET requests. For POST requests, appropriate URI handler immediately for GET requests. For POST requests,
...@@ -82,19 +96,16 @@ whether the request is websocket or not. Also, for websocket requests, ...@@ -82,19 +96,16 @@ whether the request is websocket or not. Also, for websocket requests,
there is `struct mg_connection::wsbits` field which contains first byte there is `struct mg_connection::wsbits` field which contains first byte
of the websocket frame which URI handler can examine. Note that to of the websocket frame which URI handler can examine. Note that to
reply to the websocket client, `mg_websocket_write()` should be used. reply to the websocket client, `mg_websocket_write()` should be used.
To reply to the plain HTTP client, `mg_write_data()` should be used. To reply to the plain HTTP client, `mg_write_data()` should be used. Note that
websocket handler must return either `MG_CLIENT_CLOSE` or `MG_CLIENT_CONTINUE`
An URI handler must return a value. If URI handler has sent all data, value.
it should return `1`. If URI handler returns `0`, that signals Mongoose
that URI handler hasn't finished sending data to the client. In this case,
Mongoose will call URI handler after each successful socket write.
`struct mg_connection::wsbits` flag will indicate the status of the write,
`1` means that write has failed and connection will be closed.
void mg_set_http_error_handler(struct mg_server *, mg_handler_t); void mg_set_http_error_handler(struct mg_server *, mg_handler_t);
Adds HTTP error handler. An actual HTTP error is passed as Adds HTTP error handler. An actual HTTP error is passed as
`struct mg_connection::status_code` parameter. If handler returns 0, it `struct mg_connection::status_code` parameter.
Hanlder should return either `MG_ERROR_PROCESSED` or `MG_ERROR_NOT_PROCESSED`.
If handler returns `MG_ERROR_NOT_PROCESSED`, it
means a handler has not processed the connection, and mongoose proceeds means a handler has not processed the connection, and mongoose proceeds
with sending HTTP error to the client. Otherwise, mongoose does nothing. with sending HTTP error to the client. Otherwise, mongoose does nothing.
......
CFLAGS = -W -Wall -I.. -pthread -g -pipe $(COPT) CFLAGS = -W -Wall -I.. -pthread -g -pipe $(CFLAGS_EXTRA)
DLL_FLAGS = -DLUA_COMPAT_ALL -I../build DLL_FLAGS = -DLUA_COMPAT_ALL -I../build
RM = rm -rf RM = rm -rf
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#include "mongoose.h" #include "mongoose.h"
static int auth_handler(struct mg_connection *conn) { static int auth_handler(struct mg_connection *conn) {
int result = 0; // Not authorized int result = MG_AUTH_FAIL; // Not authorized
FILE *fp; FILE *fp;
// To populate passwords file, do // To populate passwords file, do
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
// This function will be called by mongoose on every new request // This function will be called by mongoose on every new request
static int index_html(struct mg_connection *conn) { static int index_html(struct mg_connection *conn) {
mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri); mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri);
return 1; return MG_REQUEST_PROCESSED;
} }
int main(void) { int main(void) {
...@@ -14,7 +14,7 @@ int main(void) { ...@@ -14,7 +14,7 @@ int main(void) {
// Create and configure the server // Create and configure the server
server = mg_create_server(NULL); server = mg_create_server(NULL);
mg_set_option(server, "listening_port", "8080"); mg_set_option(server, "listening_port", "8080");
mg_add_uri_handler(server, "/", index_html); mg_set_request_handler(server, index_html);
// Serve request. Hit Ctrl-C to terminate the program // Serve request. Hit Ctrl-C to terminate the program
printf("Starting on port %s\n", mg_get_option(server, "listening_port")); printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
......
...@@ -6,7 +6,7 @@ static int request_handler(struct mg_connection *conn) { ...@@ -6,7 +6,7 @@ static int request_handler(struct mg_connection *conn) {
mg_send_header(conn, "Content-Type", "text/plain"); mg_send_header(conn, "Content-Type", "text/plain");
mg_printf_data(conn, "This is a reply from server instance # %s", mg_printf_data(conn, "This is a reply from server instance # %s",
(char *) conn->server_param); (char *) conn->server_param);
return 0; return MG_REQUEST_PROCESSED;
} }
static void *serve(void *server) { static void *serve(void *server) {
...@@ -20,8 +20,8 @@ int main(void) { ...@@ -20,8 +20,8 @@ int main(void) {
server1 = mg_create_server((void *) "1"); server1 = mg_create_server((void *) "1");
server2 = mg_create_server((void *) "2"); server2 = mg_create_server((void *) "2");
mg_add_uri_handler(server1, "/", request_handler); mg_set_request_handler(server1, request_handler);
mg_add_uri_handler(server2, "/", request_handler); mg_set_request_handler(server2, request_handler);
// Make both server1 and server2 listen on the same socket // Make both server1 and server2 listen on the same socket
mg_set_option(server1, "listening_port", "8080"); mg_set_option(server1, "listening_port", "8080");
......
...@@ -34,13 +34,13 @@ static int handler(struct mg_connection *conn) { ...@@ -34,13 +34,13 @@ static int handler(struct mg_connection *conn) {
mg_send_data(conn, html_form, strlen(html_form)); mg_send_data(conn, html_form, strlen(html_form));
} }
return 1; return MG_REQUEST_PROCESSED;
} }
int main(void) { int main(void) {
struct mg_server *server = mg_create_server(NULL); struct mg_server *server = mg_create_server(NULL);
mg_set_option(server, "listening_port", "8080"); mg_set_option(server, "listening_port", "8080");
mg_add_uri_handler(server, "/", handler); mg_set_request_handler(server, handler);
printf("Starting on port %s\n", mg_get_option(server, "listening_port")); printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) { for (;;) {
mg_poll_server(server, 1000); mg_poll_server(server, 1000);
......
...@@ -30,7 +30,7 @@ static int index_html(struct mg_connection *conn) { ...@@ -30,7 +30,7 @@ static int index_html(struct mg_connection *conn) {
mg_printf_data(conn, "%s", "</body></html>"); mg_printf_data(conn, "%s", "</body></html>");
return 1; return MG_REQUEST_PROCESSED;
} }
int main(void) { int main(void) {
...@@ -39,7 +39,7 @@ int main(void) { ...@@ -39,7 +39,7 @@ int main(void) {
// Create and configure the server // Create and configure the server
server = mg_create_server(NULL); server = mg_create_server(NULL);
mg_set_option(server, "listening_port", "8080"); mg_set_option(server, "listening_port", "8080");
mg_add_uri_handler(server, "/", index_html); mg_set_request_handler(server, index_html);
// Serve request. Hit Ctrl-C to terminate the program // Serve request. Hit Ctrl-C to terminate the program
printf("Starting on port %s\n", mg_get_option(server, "listening_port")); printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
......
...@@ -9,7 +9,7 @@ static int iterate_callback(struct mg_connection *c) { ...@@ -9,7 +9,7 @@ static int iterate_callback(struct mg_connection *c) {
int len = snprintf(buf, sizeof(buf), "%d", * (int *) c->connection_param); int len = snprintf(buf, sizeof(buf), "%d", * (int *) c->connection_param);
mg_websocket_write(c, 1, buf, len); mg_websocket_write(c, 1, buf, len);
} }
return 1; return MG_REQUEST_PROCESSED;
} }
static int index_html(struct mg_connection *conn) { static int index_html(struct mg_connection *conn) {
...@@ -21,11 +21,12 @@ static int index_html(struct mg_connection *conn) { ...@@ -21,11 +21,12 @@ static int index_html(struct mg_connection *conn) {
// times for connection lifetime. // times for connection lifetime.
// Echo websocket data back to the client. // Echo websocket data back to the client.
mg_websocket_write(conn, 1, conn->content, conn->content_len); mg_websocket_write(conn, 1, conn->content, conn->content_len);
return conn->content_len == 4 && !memcmp(conn->content, "exit", 4); return conn->content_len == 4 && !memcmp(conn->content, "exit", 4) ?
MG_CLIENT_CLOSE : MG_CLIENT_CONTINUE;
} else { } else {
mg_send_header(conn, "Content-Type", "text/html"); mg_send_header(conn, "Content-Type", "text/html");
mg_send_data(conn, index_html, index_size); mg_send_data(conn, index_html, index_size);
return 1; return MG_REQUEST_PROCESSED;
} }
} }
...@@ -34,12 +35,12 @@ int main(void) { ...@@ -34,12 +35,12 @@ int main(void) {
unsigned int current_timer = 0, last_timer = 0; unsigned int current_timer = 0, last_timer = 0;
mg_set_option(server, "listening_port", "8080"); mg_set_option(server, "listening_port", "8080");
mg_add_uri_handler(server, "/", index_html); mg_set_request_handler(server, index_html);
printf("Started on port %s\n", mg_get_option(server, "listening_port")); printf("Started on port %s\n", mg_get_option(server, "listening_port"));
for (;;) { for (;;) {
current_timer = mg_poll_server(server, 100); current_timer = mg_poll_server(server, 100);
if (current_timer - last_timer > 1) { if (current_timer - last_timer > 0) {
last_timer = current_timer; last_timer = current_timer;
mg_iterate_over_connections(server, iterate_callback, &current_timer); mg_iterate_over_connections(server, iterate_callback, &current_timer);
} }
......
...@@ -24,10 +24,13 @@ ...@@ -24,10 +24,13 @@
out('DISCONNECTED'); out('DISCONNECTED');
}; };
websocket.onmessage = function(ev) { websocket.onmessage = function(ev) {
if (!ev.data) return; // No data, this is a PING message, ignore it if (!ev.data) {
out('<span style="color: blue;">PING... </span>');
} else {
out('<span style="color: blue;">RESPONSE: ' + ev.data + ' </span>'); out('<span style="color: blue;">RESPONSE: ' + ev.data + ' </span>');
num_messages++; num_messages++;
if (num_messages > 100) { }
if (num_messages > 15) {
websocket.send('exit'); websocket.send('exit');
} }
}; };
......
...@@ -203,12 +203,6 @@ struct vec { ...@@ -203,12 +203,6 @@ struct vec {
int len; int len;
}; };
struct uri_handler {
struct ll link;
char *uri;
mg_handler_t handler;
};
// For directory listing and WevDAV support // For directory listing and WevDAV support
struct dir_entry { struct dir_entry {
struct connection *conn; struct connection *conn;
...@@ -275,7 +269,7 @@ struct mg_server { ...@@ -275,7 +269,7 @@ struct mg_server {
sock_t listening_sock; sock_t listening_sock;
union socket_address lsa; // Listening socket address union socket_address lsa; // Listening socket address
struct ll active_connections; struct ll active_connections;
struct ll uri_handlers; mg_handler_t request_handler;
mg_handler_t error_handler; mg_handler_t error_handler;
mg_handler_t auth_handler; mg_handler_t auth_handler;
char *config_options[NUM_OPTIONS]; char *config_options[NUM_OPTIONS];
...@@ -300,7 +294,6 @@ union endpoint { ...@@ -300,7 +294,6 @@ union endpoint {
int fd; // Opened regular local file int fd; // Opened regular local file
sock_t cgi_sock; // CGI socket sock_t cgi_sock; // CGI socket
void *ssl; // SSL descriptor void *ssl; // SSL descriptor
struct uri_handler *uh; // URI handler user function
}; };
enum endpoint_type { EP_NONE, EP_FILE, EP_CGI, EP_USER, EP_PUT, EP_CLIENT }; enum endpoint_type { EP_NONE, EP_FILE, EP_CGI, EP_USER, EP_PUT, EP_CLIENT };
...@@ -338,6 +331,7 @@ struct connection { ...@@ -338,6 +331,7 @@ struct connection {
#endif #endif
}; };
static void open_local_endpoint(struct connection *conn, int skip_user);
static void close_local_endpoint(struct connection *conn); static void close_local_endpoint(struct connection *conn);
static const struct { static const struct {
...@@ -664,7 +658,7 @@ static void send_http_error(struct connection *conn, int code, ...@@ -664,7 +658,7 @@ static void send_http_error(struct connection *conn, int code,
// Invoke error handler if it is set // Invoke error handler if it is set
if (conn->server->error_handler != NULL && if (conn->server->error_handler != NULL &&
conn->server->error_handler(&conn->mg_conn)) { conn->server->error_handler(&conn->mg_conn) == MG_ERROR_PROCESSED) {
close_local_endpoint(conn); close_local_endpoint(conn);
return; return;
} }
...@@ -1861,7 +1855,7 @@ static int deliver_websocket_frame(struct connection *conn) { ...@@ -1861,7 +1855,7 @@ static int deliver_websocket_frame(struct connection *conn) {
} }
// Call the handler and remove frame from the iobuf // Call the handler and remove frame from the iobuf
if (conn->endpoint.uh->handler(&conn->mg_conn)) { if (conn->server->request_handler(&conn->mg_conn) == MG_CLIENT_CLOSE) {
conn->flags |= CONN_SPOOL_DONE; conn->flags |= CONN_SPOOL_DONE;
} }
discard_leading_iobuf_bytes(&conn->local_iobuf, frame_len); discard_leading_iobuf_bytes(&conn->local_iobuf, frame_len);
...@@ -1934,16 +1928,20 @@ static void write_terminating_chunk(struct connection *conn) { ...@@ -1934,16 +1928,20 @@ static void write_terminating_chunk(struct connection *conn) {
mg_write(&conn->mg_conn, "0\r\n\r\n", 5); mg_write(&conn->mg_conn, "0\r\n\r\n", 5);
} }
static void call_uri_handler(struct connection *conn) { static int call_request_handler(struct connection *conn) {
int result;
conn->mg_conn.content = conn->local_iobuf.buf; conn->mg_conn.content = conn->local_iobuf.buf;
if (conn->endpoint.uh->handler(&conn->mg_conn)) { switch ((result = conn->server->request_handler(&conn->mg_conn))) {
case MG_REQUEST_CALL_AGAIN: conn->flags |= CONN_LONG_RUNNING; break;
case MG_REQUEST_NOT_PROCESSED: break;
default:
if (conn->flags & CONN_HEADERS_SENT) { if (conn->flags & CONN_HEADERS_SENT) {
write_terminating_chunk(conn); write_terminating_chunk(conn);
} }
close_local_endpoint(conn); close_local_endpoint(conn);
} else { break;
conn->flags |= CONN_LONG_RUNNING;
} }
return result;
} }
static void callback_http_client_on_connect(struct connection *conn) { static void callback_http_client_on_connect(struct connection *conn) {
...@@ -2021,19 +2019,6 @@ const char *mg_get_mime_type(const char *path, const char *default_mime_type) { ...@@ -2021,19 +2019,6 @@ const char *mg_get_mime_type(const char *path, const char *default_mime_type) {
return default_mime_type; return default_mime_type;
} }
static struct uri_handler *find_uri_handler(struct mg_server *server,
const char *uri) {
struct ll *lp, *tmp;
struct uri_handler *uh;
LINKED_LIST_FOREACH(&server->uri_handlers, lp, tmp) {
uh = LINKED_LIST_ENTRY(lp, struct uri_handler, link);
if (!strncmp(uh->uri, uri, strlen(uh->uri))) return uh;
}
return NULL;
}
#ifndef MONGOOSE_NO_FILESYSTEM #ifndef MONGOOSE_NO_FILESYSTEM
// Convert month to the month number. Return -1 on error, or month number // Convert month to the month number. Return -1 on error, or month number
static int get_month_index(const char *s) { static int get_month_index(const char *s) {
...@@ -2247,7 +2232,7 @@ static void open_file_endpoint(struct connection *conn, const char *path, ...@@ -2247,7 +2232,7 @@ static void open_file_endpoint(struct connection *conn, const char *path,
#endif // MONGOOSE_NO_FILESYSTEM #endif // MONGOOSE_NO_FILESYSTEM
static void call_uri_handler_if_data_is_buffered(struct connection *conn) { static void call_request_handler_if_data_is_buffered(struct connection *conn) {
struct iobuf *loc = &conn->local_iobuf; struct iobuf *loc = &conn->local_iobuf;
struct mg_connection *c = &conn->mg_conn; struct mg_connection *c = &conn->mg_conn;
...@@ -2256,8 +2241,9 @@ static void call_uri_handler_if_data_is_buffered(struct connection *conn) { ...@@ -2256,8 +2241,9 @@ static void call_uri_handler_if_data_is_buffered(struct connection *conn) {
do { } while (deliver_websocket_frame(conn)); do { } while (deliver_websocket_frame(conn));
} else } else
#endif #endif
if ((size_t) loc->len >= c->content_len) { if ((size_t) loc->len >= c->content_len &&
call_uri_handler(conn); call_request_handler(conn) == MG_REQUEST_NOT_PROCESSED) {
open_local_endpoint(conn, 1);
} }
} }
...@@ -2984,7 +2970,8 @@ static int check_password(const char *method, const char *ha1, const char *uri, ...@@ -2984,7 +2970,8 @@ static int check_password(const char *method, const char *ha1, const char *uri,
mg_md5(expected_response, ha1, ":", nonce, ":", nc, mg_md5(expected_response, ha1, ":", nonce, ":", nc,
":", cnonce, ":", qop, ":", ha2, NULL); ":", cnonce, ":", qop, ":", ha2, NULL);
return mg_strcasecmp(response, expected_response) == 0; return mg_strcasecmp(response, expected_response) == 0 ?
MG_AUTH_OK : MG_AUTH_FAIL;
} }
...@@ -3014,14 +3001,14 @@ int mg_authorize_digest(struct mg_connection *c, FILE *fp) { ...@@ -3014,14 +3001,14 @@ int mg_authorize_digest(struct mg_connection *c, FILE *fp) {
return check_password(c->request_method, ha1, uri, return check_password(c->request_method, ha1, uri,
nonce, nc, cnonce, qop, resp); nonce, nc, cnonce, qop, resp);
} }
return 0; return MG_AUTH_FAIL;
} }
// Return 1 if request is authorised, 0 otherwise. // Return 1 if request is authorised, 0 otherwise.
static int is_authorized(struct connection *conn, const char *path) { static int is_authorized(struct connection *conn, const char *path) {
FILE *fp; FILE *fp;
int authorized = 1; int authorized = MG_AUTH_OK;
if ((fp = open_auth_file(conn, path)) != NULL) { if ((fp = open_auth_file(conn, path)) != NULL) {
authorized = mg_authorize_digest(&conn->mg_conn, fp); authorized = mg_authorize_digest(&conn->mg_conn, fp);
...@@ -3034,7 +3021,7 @@ static int is_authorized(struct connection *conn, const char *path) { ...@@ -3034,7 +3021,7 @@ static int is_authorized(struct connection *conn, const char *path) {
static int is_authorized_for_dav(struct connection *conn) { static int is_authorized_for_dav(struct connection *conn) {
const char *auth_file = conn->server->config_options[DAV_AUTH_FILE]; const char *auth_file = conn->server->config_options[DAV_AUTH_FILE];
FILE *fp; FILE *fp;
int authorized = 0; int authorized = MG_AUTH_FAIL;
if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) { if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) {
authorized = mg_authorize_digest(&conn->mg_conn, fp); authorized = mg_authorize_digest(&conn->mg_conn, fp);
...@@ -3359,7 +3346,7 @@ static void handle_lsp_request(struct connection *conn, const char *path, ...@@ -3359,7 +3346,7 @@ static void handle_lsp_request(struct connection *conn, const char *path,
} }
#endif // MONGOOSE_USE_LUA #endif // MONGOOSE_USE_LUA
static void open_local_endpoint(struct connection *conn) { static void open_local_endpoint(struct connection *conn, int skip_user) {
#ifndef MONGOOSE_NO_FILESYSTEM #ifndef MONGOOSE_NO_FILESYSTEM
static const char lua_pat[] = LUA_SCRIPT_PATTERN; static const char lua_pat[] = LUA_SCRIPT_PATTERN;
file_stat_t st; file_stat_t st;
...@@ -3372,17 +3359,15 @@ static void open_local_endpoint(struct connection *conn) { ...@@ -3372,17 +3359,15 @@ static void open_local_endpoint(struct connection *conn) {
#ifndef MONGOOSE_NO_AUTH #ifndef MONGOOSE_NO_AUTH
// Call auth handler // Call auth handler
if (conn->server->auth_handler != NULL && if (conn->server->auth_handler != NULL &&
conn->server->auth_handler(&conn->mg_conn) == 0) { conn->server->auth_handler(&conn->mg_conn) == MG_AUTH_FAIL) {
mg_send_digest_auth_request(&conn->mg_conn); mg_send_digest_auth_request(&conn->mg_conn);
return; return;
} }
#endif #endif
// Call URI handler if one is registered for this URI // Call URI handler if one is registered for this URI
conn->endpoint.uh = find_uri_handler(conn->server, conn->mg_conn.uri); if (skip_user == 0 && conn->server->request_handler != NULL) {
if (conn->endpoint.uh != NULL) {
conn->endpoint_type = EP_USER; conn->endpoint_type = EP_USER;
conn->mg_conn.content = conn->local_iobuf.buf;
#if MONGOOSE_USE_POST_SIZE_LIMIT > 1 #if MONGOOSE_USE_POST_SIZE_LIMIT > 1
{ {
const char *cl = mg_get_header(&conn->mg_conn, "Content-Length"); const char *cl = mg_get_header(&conn->mg_conn, "Content-Length");
...@@ -3525,7 +3510,7 @@ static void process_request(struct connection *conn) { ...@@ -3525,7 +3510,7 @@ static void process_request(struct connection *conn) {
send_websocket_handshake_if_requested(&conn->mg_conn); send_websocket_handshake_if_requested(&conn->mg_conn);
#endif #endif
send_continue_if_expected(conn); send_continue_if_expected(conn);
open_local_endpoint(conn); open_local_endpoint(conn, 0);
} }
#ifndef MONGOOSE_NO_CGI #ifndef MONGOOSE_NO_CGI
...@@ -3534,7 +3519,7 @@ static void process_request(struct connection *conn) { ...@@ -3534,7 +3519,7 @@ static void process_request(struct connection *conn) {
} }
#endif #endif
if (conn->endpoint_type == EP_USER) { if (conn->endpoint_type == EP_USER) {
call_uri_handler_if_data_is_buffered(conn); call_request_handler_if_data_is_buffered(conn);
} }
#ifndef MONGOOSE_NO_DAV #ifndef MONGOOSE_NO_DAV
if (conn->endpoint_type == EP_PUT && io->len > 0) { if (conn->endpoint_type == EP_PUT && io->len > 0) {
...@@ -3859,7 +3844,9 @@ unsigned int mg_poll_server(struct mg_server *server, int milliseconds) { ...@@ -3859,7 +3844,9 @@ unsigned int mg_poll_server(struct mg_server *server, int milliseconds) {
} }
if (conn->flags & CONN_LONG_RUNNING) { if (conn->flags & CONN_LONG_RUNNING) {
conn->mg_conn.wsbits = conn->flags & CONN_CLOSE ? 1 : 0; conn->mg_conn.wsbits = conn->flags & CONN_CLOSE ? 1 : 0;
call_uri_handler(conn); if (call_request_handler(conn) == MG_REQUEST_PROCESSED) {
conn->flags |= CONN_CLOSE;
}
} }
if (conn->flags & CONN_CLOSE || conn->last_activity_time < expire_time) { if (conn->flags & CONN_CLOSE || conn->last_activity_time < expire_time) {
close_conn(conn); close_conn(conn);
...@@ -3883,10 +3870,6 @@ void mg_destroy_server(struct mg_server **server) { ...@@ -3883,10 +3870,6 @@ void mg_destroy_server(struct mg_server **server) {
LINKED_LIST_FOREACH(&s->active_connections, lp, tmp) { LINKED_LIST_FOREACH(&s->active_connections, lp, tmp) {
close_conn(LINKED_LIST_ENTRY(lp, struct connection, link)); close_conn(LINKED_LIST_ENTRY(lp, struct connection, link));
} }
LINKED_LIST_FOREACH(&s->uri_handlers, lp, tmp) {
free(LINKED_LIST_ENTRY(lp, struct uri_handler, link)->uri);
free(LINKED_LIST_ENTRY(lp, struct uri_handler, link));
}
for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) { for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) {
free(s->config_options[i]); // It is OK to free(NULL) free(s->config_options[i]); // It is OK to free(NULL)
} }
...@@ -3909,16 +3892,6 @@ void mg_iterate_over_connections(struct mg_server *server, mg_handler_t handler, ...@@ -3909,16 +3892,6 @@ void mg_iterate_over_connections(struct mg_server *server, mg_handler_t handler,
send(server->ctl[0], (void *) msg, sizeof(msg), 0); send(server->ctl[0], (void *) msg, sizeof(msg), 0);
} }
void mg_add_uri_handler(struct mg_server *server, const char *uri,
mg_handler_t handler) {
struct uri_handler *p = (struct uri_handler *) malloc(sizeof(*p));
if (p != NULL) {
LINKED_LIST_ADD_TO_TAIL(&server->uri_handlers, &p->link);
p->uri = mg_strdup(uri);
p->handler = handler;
}
}
static int get_var(const char *data, size_t data_len, const char *name, static int get_var(const char *data, size_t data_len, const char *name,
char *dst, size_t dst_len) { char *dst, size_t dst_len) {
const char *p, *e, *s; const char *p, *e, *s;
...@@ -4145,6 +4118,9 @@ const char *mg_set_option(struct mg_server *server, const char *name, ...@@ -4145,6 +4118,9 @@ const char *mg_set_option(struct mg_server *server, const char *name,
return error_msg; return error_msg;
} }
void mg_set_request_handler(struct mg_server *server, mg_handler_t handler) {
server->request_handler = handler;
}
void mg_set_http_error_handler(struct mg_server *server, mg_handler_t handler) { void mg_set_http_error_handler(struct mg_server *server, mg_handler_t handler) {
server->error_handler = handler; server->error_handler = handler;
...@@ -4184,7 +4160,6 @@ struct mg_server *mg_create_server(void *server_data) { ...@@ -4184,7 +4160,6 @@ struct mg_server *mg_create_server(void *server_data) {
#endif #endif
LINKED_LIST_INIT(&server->active_connections); LINKED_LIST_INIT(&server->active_connections);
LINKED_LIST_INIT(&server->uri_handlers);
// Create control socket pair. Do it in a loop to protect from // Create control socket pair. Do it in a loop to protect from
// interrupted syscalls in mg_socketpair(). // interrupted syscalls in mg_socketpair().
......
...@@ -65,7 +65,7 @@ struct mg_server *mg_create_server(void *server_param); ...@@ -65,7 +65,7 @@ struct mg_server *mg_create_server(void *server_param);
void mg_destroy_server(struct mg_server **); void mg_destroy_server(struct mg_server **);
const char *mg_set_option(struct mg_server *, const char *opt, const char *val); const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
unsigned int mg_poll_server(struct mg_server *, int milliseconds); unsigned int mg_poll_server(struct mg_server *, int milliseconds);
void mg_add_uri_handler(struct mg_server *, const char *uri, mg_handler_t); void mg_set_request_handler(struct mg_server *, mg_handler_t);
void mg_set_http_error_handler(struct mg_server *, mg_handler_t); void mg_set_http_error_handler(struct mg_server *, mg_handler_t);
void mg_set_auth_handler(struct mg_server *, mg_handler_t); void mg_set_auth_handler(struct mg_server *, mg_handler_t);
const char **mg_get_valid_option_names(void); const char **mg_get_valid_option_names(void);
...@@ -87,9 +87,8 @@ int mg_websocket_write(struct mg_connection *, int opcode, ...@@ -87,9 +87,8 @@ int mg_websocket_write(struct mg_connection *, int opcode,
int mg_write(struct mg_connection *, const void *buf, int len); int mg_write(struct mg_connection *, const void *buf, int len);
int mg_printf(struct mg_connection *conn, const char *fmt, ...); int mg_printf(struct mg_connection *conn, const char *fmt, ...);
const char *mg_get_header(const struct mg_connection *, const char *name); const char *mg_get_header(const struct mg_connection *, const char *name);
const char *mg_get_mime_type(const char *file_name, const char *default_mime_type); const char *mg_get_mime_type(const char *name, const char *default_mime_type);
int mg_get_var(const struct mg_connection *conn, const char *var_name, int mg_get_var(const struct mg_connection *conn, const char *var_name,
char *buf, size_t buf_len); char *buf, size_t buf_len);
int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t); int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t);
...@@ -102,10 +101,12 @@ int mg_parse_multipart(const char *buf, int buf_len, ...@@ -102,10 +101,12 @@ int mg_parse_multipart(const char *buf, int buf_len,
void *mg_start_thread(void *(*func)(void *), void *param); void *mg_start_thread(void *(*func)(void *), void *param);
char *mg_md5(char buf[33], ...); char *mg_md5(char buf[33], ...);
int mg_authorize_digest(struct mg_connection *c, FILE *fp); int mg_authorize_digest(struct mg_connection *c, FILE *fp);
void mg_send_digest_auth_request(struct mg_connection *conn);
// Callback return codes // Callback function return codes
enum { MG_REPLY_TO_BE_CONTINUED, MG_REPLY_COMPLETED }; enum { MG_REQUEST_NOT_PROCESSED, MG_REQUEST_PROCESSED, MG_REQUEST_CALL_AGAIN };
enum { MG_AUTH_FAIL, MG_AUTH_OK };
enum { MG_ERROR_NOT_PROCESSED, MG_ERROR_PROCESSED };
enum { MG_CLIENT_CONTINUE, MG_CLIENT_CLOSE };
// HTTP client events // HTTP client events
enum { enum {
......
...@@ -364,39 +364,41 @@ static const char *test_next_option(void) { ...@@ -364,39 +364,41 @@ static const char *test_next_option(void) {
} }
static int cb1(struct mg_connection *conn) { static int cb1(struct mg_connection *conn) {
// We're not sending HTTP headers here, to make testing easier int result = MG_REQUEST_NOT_PROCESSED;
//mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\n%s %s %s", if (!strcmp(conn->uri, "/cb1")) {
mg_printf(conn, "%s %s %s", mg_printf(conn, "%s %s %s",
conn->server_param == NULL ? "?" : (char *) conn->server_param, conn->server_param == NULL ? "?" : (char *) conn->server_param,
conn->connection_param == NULL ? "?" : "!", conn->remote_ip); conn->connection_param == NULL ? "?" : "!", conn->remote_ip);
return 1; result = MG_REQUEST_PROCESSED;
}
return result;
} }
static int error_handler(struct mg_connection *conn) { static int error_handler(struct mg_connection *conn) {
mg_printf(conn, "HTTP/1.0 404 NF\r\n\r\nERR: %d", conn->status_code); mg_printf(conn, "HTTP/1.0 404 NF\r\n\r\nERR: %d", conn->status_code);
return 1; return MG_ERROR_PROCESSED;
} }
static int ts1(struct mg_connection *conn) { static int ts1(struct mg_connection *conn) {
if (conn->status_code == MG_CONNECT_SUCCESS) { if (conn->status_code == MG_CONNECT_SUCCESS) {
mg_printf(conn, "%s", "GET /cb1 HTTP/1.0\r\n\r\n"); mg_printf(conn, "%s", "GET /cb1 HTTP/1.0\r\n\r\n");
return 0; return MG_CLIENT_CONTINUE;
} else if (conn->status_code == MG_DOWNLOAD_SUCCESS) { } else if (conn->status_code == MG_DOWNLOAD_SUCCESS) {
sprintf((char *) conn->connection_param, "%.*s", sprintf((char *) conn->connection_param, "%.*s",
(int) conn->content_len, conn->content); (int) conn->content_len, conn->content);
} }
return 1; return MG_CLIENT_CLOSE;
} }
static int ts2(struct mg_connection *conn) { static int ts2(struct mg_connection *conn) {
if (conn->status_code == MG_CONNECT_SUCCESS) { if (conn->status_code == MG_CONNECT_SUCCESS) {
mg_printf(conn, "%s", "GET /non_exist HTTP/1.0\r\n\r\n"); mg_printf(conn, "%s", "GET /non_exist HTTP/1.0\r\n\r\n");
return 0; return MG_CLIENT_CONTINUE;
} else if (conn->status_code == MG_DOWNLOAD_SUCCESS) { } else if (conn->status_code == MG_DOWNLOAD_SUCCESS) {
sprintf((char *) conn->connection_param, "%s %.*s", sprintf((char *) conn->connection_param, "%s %.*s",
conn->uri, (int) conn->content_len, conn->content); conn->uri, (int) conn->content_len, conn->content);
} }
return 1; return MG_CLIENT_CLOSE;
} }
static const char *test_server(void) { static const char *test_server(void) {
...@@ -406,7 +408,7 @@ static const char *test_server(void) { ...@@ -406,7 +408,7 @@ static const char *test_server(void) {
ASSERT(server != NULL); ASSERT(server != NULL);
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL); ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
ASSERT(mg_set_option(server, "document_root", ".") == NULL); ASSERT(mg_set_option(server, "document_root", ".") == NULL);
mg_add_uri_handler(server, "/cb1", cb1); mg_set_request_handler(server, cb1);
mg_set_http_error_handler(server, error_handler); mg_set_http_error_handler(server, error_handler);
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, ts1, buf1) == 1); ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, ts1, buf1) == 1);
...@@ -460,25 +462,28 @@ static int cb2(struct mg_connection *conn) { ...@@ -460,25 +462,28 @@ static int cb2(struct mg_connection *conn) {
} }
static int cb4h(struct mg_connection *conn) { static int cb4h(struct mg_connection *conn) {
int result = MG_REQUEST_NOT_PROCESSED;
if (!strcmp(conn->uri, "/x")) {
mg_send_data(conn, ":-)", 3); mg_send_data(conn, ":-)", 3);
return MG_REPLY_COMPLETED; result = MG_REQUEST_PROCESSED;
}
return result;
} }
static int cb4(struct mg_connection *conn) { static int cb4(struct mg_connection *conn) {
if (conn->status_code == MG_CONNECT_SUCCESS) { if (conn->status_code == MG_CONNECT_SUCCESS) {
mg_printf(conn, "%s", "POST /x HTTP/1.0\r\nContent-Length: 999999\r\n\r\n"); mg_printf(conn, "%s", "POST /x HTTP/1.0\r\nContent-Length: 999999\r\n\r\n");
return MG_REPLY_TO_BE_CONTINUED; return MG_CLIENT_CONTINUE;
} else { } else {
sprintf((char *) conn->connection_param, "%.*s", sprintf((char *) conn->connection_param, "%.*s",
(int) conn->content_len, conn->content); (int) conn->content_len, conn->content);
} }
return MG_REPLY_COMPLETED; return MG_CLIENT_CLOSE;
} }
static int cb3(struct mg_connection *conn) { static int cb3(struct mg_connection *conn) {
fflush(stdout);
sprintf((char *) conn->connection_param, "%d", conn->status_code); sprintf((char *) conn->connection_param, "%d", conn->status_code);
return 1; return MG_CLIENT_CLOSE;
} }
static const char *test_mg_connect(void) { static const char *test_mg_connect(void) {
...@@ -487,7 +492,7 @@ static const char *test_mg_connect(void) { ...@@ -487,7 +492,7 @@ static const char *test_mg_connect(void) {
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL); ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
ASSERT(mg_set_option(server, "document_root", ".") == NULL); ASSERT(mg_set_option(server, "document_root", ".") == NULL);
mg_add_uri_handler(server, "/x", cb4h); mg_set_request_handler(server, cb4h);
ASSERT(mg_connect(server, "", 0, 0, NULL, NULL) == 0); ASSERT(mg_connect(server, "", 0, 0, NULL, NULL) == 0);
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, cb2, buf2) == 1); ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, cb2, buf2) == 1);
ASSERT(mg_connect(server, "127.0.0.1", 29, 0, cb3, buf3) == 1); ASSERT(mg_connect(server, "127.0.0.1", 29, 0, cb3, buf3) == 1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment