diff --git a/docs/API.md b/docs/API.md index c79473974b..3abad5314c 100644 --- a/docs/API.md +++ b/docs/API.md @@ -60,12 +60,26 @@ that take `struct mg_server *` parameter. Mongoose does not mutex-protect `struct mg_server *`, therefore the best practice is 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); - -Adds an URI handler. If Mongoose gets a request and request's URI starts -with `uri`, then specified handler is called to serve the request. Thus, an -`uri` is a match prefix. For example, if `uri` is "/", then all requests will -be routed to the handler, because all URIs start with `/` character. + void mg_set_auth_handler(struct mg_server *, mg_handler_t handler); + +Sets authorization handler. Called by Mongoose on each request, before +performing any other action. Handler can return either `MG_AUTH_OK` or +`MG_AUTH_FAIL`. If `handler` returns `MG_AUTH_FAIL`, then Mongoose sends +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 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, there is `struct mg_connection::wsbits` field which contains first byte of the websocket frame which URI handler can examine. Note that to reply to the websocket client, `mg_websocket_write()` should be used. -To reply to the plain HTTP client, `mg_write_data()` should be used. - -An URI handler must return a value. If URI handler has sent all data, -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. +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` +value. void mg_set_http_error_handler(struct mg_server *, mg_handler_t); 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 with sending HTTP error to the client. Otherwise, mongoose does nothing. diff --git a/examples/Makefile b/examples/Makefile index a4bcc1f590..54f75ac9d2 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,4 +1,4 @@ -CFLAGS = -W -Wall -I.. -pthread -g -pipe $(COPT) +CFLAGS = -W -Wall -I.. -pthread -g -pipe $(CFLAGS_EXTRA) DLL_FLAGS = -DLUA_COMPAT_ALL -I../build RM = rm -rf diff --git a/examples/auth.c b/examples/auth.c index a5ffca420a..21d13c6426 100644 --- a/examples/auth.c +++ b/examples/auth.c @@ -3,7 +3,7 @@ #include "mongoose.h" static int auth_handler(struct mg_connection *conn) { - int result = 0; // Not authorized + int result = MG_AUTH_FAIL; // Not authorized FILE *fp; // To populate passwords file, do diff --git a/examples/hello.c b/examples/hello.c index 3481af5b7e..4ed9f4356e 100644 --- a/examples/hello.c +++ b/examples/hello.c @@ -5,7 +5,7 @@ // This function will be called by mongoose on every new request static int index_html(struct mg_connection *conn) { mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri); - return 1; + return MG_REQUEST_PROCESSED; } int main(void) { @@ -14,7 +14,7 @@ int main(void) { // Create and configure the server server = mg_create_server(NULL); 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 printf("Starting on port %s\n", mg_get_option(server, "listening_port")); diff --git a/examples/multi_threaded.c b/examples/multi_threaded.c index 509694d3b5..134d88fabc 100644 --- a/examples/multi_threaded.c +++ b/examples/multi_threaded.c @@ -6,7 +6,7 @@ static int request_handler(struct mg_connection *conn) { mg_send_header(conn, "Content-Type", "text/plain"); mg_printf_data(conn, "This is a reply from server instance # %s", (char *) conn->server_param); - return 0; + return MG_REQUEST_PROCESSED; } static void *serve(void *server) { @@ -20,8 +20,8 @@ int main(void) { server1 = mg_create_server((void *) "1"); server2 = mg_create_server((void *) "2"); - mg_add_uri_handler(server1, "/", request_handler); - mg_add_uri_handler(server2, "/", request_handler); + mg_set_request_handler(server1, request_handler); + mg_set_request_handler(server2, request_handler); // Make both server1 and server2 listen on the same socket mg_set_option(server1, "listening_port", "8080"); diff --git a/examples/post.c b/examples/post.c index 127160a405..b958b3858f 100644 --- a/examples/post.c +++ b/examples/post.c @@ -34,13 +34,13 @@ static int handler(struct mg_connection *conn) { mg_send_data(conn, html_form, strlen(html_form)); } - return 1; + return MG_REQUEST_PROCESSED; } int main(void) { struct mg_server *server = mg_create_server(NULL); 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")); for (;;) { mg_poll_server(server, 1000); diff --git a/examples/upload.c b/examples/upload.c index b83693952e..468ccc45bd 100644 --- a/examples/upload.c +++ b/examples/upload.c @@ -30,7 +30,7 @@ static int index_html(struct mg_connection *conn) { mg_printf_data(conn, "%s", ""); - return 1; + return MG_REQUEST_PROCESSED; } int main(void) { @@ -39,7 +39,7 @@ int main(void) { // Create and configure the server server = mg_create_server(NULL); 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 printf("Starting on port %s\n", mg_get_option(server, "listening_port")); diff --git a/examples/websocket.c b/examples/websocket.c index 50039f00f9..5dbe711bda 100644 --- a/examples/websocket.c +++ b/examples/websocket.c @@ -9,7 +9,7 @@ static int iterate_callback(struct mg_connection *c) { int len = snprintf(buf, sizeof(buf), "%d", * (int *) c->connection_param); mg_websocket_write(c, 1, buf, len); } - return 1; + return MG_REQUEST_PROCESSED; } static int index_html(struct mg_connection *conn) { @@ -21,11 +21,12 @@ static int index_html(struct mg_connection *conn) { // times for connection lifetime. // Echo websocket data back to the client. 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 { mg_send_header(conn, "Content-Type", "text/html"); mg_send_data(conn, index_html, index_size); - return 1; + return MG_REQUEST_PROCESSED; } } @@ -34,12 +35,12 @@ int main(void) { unsigned int current_timer = 0, last_timer = 0; 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")); for (;;) { current_timer = mg_poll_server(server, 100); - if (current_timer - last_timer > 1) { + if (current_timer - last_timer > 0) { last_timer = current_timer; mg_iterate_over_connections(server, iterate_callback, ¤t_timer); } diff --git a/examples/websocket.html b/examples/websocket.html index aed62c1695..7f5b7cc46c 100644 --- a/examples/websocket.html +++ b/examples/websocket.html @@ -24,10 +24,13 @@ out('DISCONNECTED'); }; websocket.onmessage = function(ev) { - if (!ev.data) return; // No data, this is a PING message, ignore it - out('RESPONSE: ' + ev.data + ' '); - num_messages++; - if (num_messages > 100) { + if (!ev.data) { + out('PING... '); + } else { + out('RESPONSE: ' + ev.data + ' '); + num_messages++; + } + if (num_messages > 15) { websocket.send('exit'); } }; diff --git a/mongoose.c b/mongoose.c index 1a596f475b..67363dd097 100644 --- a/mongoose.c +++ b/mongoose.c @@ -203,12 +203,6 @@ struct vec { int len; }; -struct uri_handler { - struct ll link; - char *uri; - mg_handler_t handler; -}; - // For directory listing and WevDAV support struct dir_entry { struct connection *conn; @@ -275,7 +269,7 @@ struct mg_server { sock_t listening_sock; union socket_address lsa; // Listening socket address struct ll active_connections; - struct ll uri_handlers; + mg_handler_t request_handler; mg_handler_t error_handler; mg_handler_t auth_handler; char *config_options[NUM_OPTIONS]; @@ -300,7 +294,6 @@ union endpoint { int fd; // Opened regular local file sock_t cgi_sock; // CGI socket 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 }; @@ -338,6 +331,7 @@ struct connection { #endif }; +static void open_local_endpoint(struct connection *conn, int skip_user); static void close_local_endpoint(struct connection *conn); static const struct { @@ -664,7 +658,7 @@ static void send_http_error(struct connection *conn, int code, // Invoke error handler if it is set 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); return; } @@ -1861,7 +1855,7 @@ static int deliver_websocket_frame(struct connection *conn) { } // 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; } discard_leading_iobuf_bytes(&conn->local_iobuf, frame_len); @@ -1934,16 +1928,20 @@ static void write_terminating_chunk(struct connection *conn) { 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; - if (conn->endpoint.uh->handler(&conn->mg_conn)) { - if (conn->flags & CONN_HEADERS_SENT) { - write_terminating_chunk(conn); - } - close_local_endpoint(conn); - } else { - conn->flags |= CONN_LONG_RUNNING; + 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) { + write_terminating_chunk(conn); + } + close_local_endpoint(conn); + break; } + return result; } 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) { 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 // Convert month to the month number. Return -1 on error, or month number static int get_month_index(const char *s) { @@ -2247,7 +2232,7 @@ static void open_file_endpoint(struct connection *conn, const char *path, #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 mg_connection *c = &conn->mg_conn; @@ -2256,8 +2241,9 @@ static void call_uri_handler_if_data_is_buffered(struct connection *conn) { do { } while (deliver_websocket_frame(conn)); } else #endif - if ((size_t) loc->len >= c->content_len) { - call_uri_handler(conn); + if ((size_t) loc->len >= c->content_len && + 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, mg_md5(expected_response, ha1, ":", nonce, ":", nc, ":", 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) { return check_password(c->request_method, ha1, uri, nonce, nc, cnonce, qop, resp); } - return 0; + return MG_AUTH_FAIL; } // Return 1 if request is authorised, 0 otherwise. static int is_authorized(struct connection *conn, const char *path) { FILE *fp; - int authorized = 1; + int authorized = MG_AUTH_OK; if ((fp = open_auth_file(conn, path)) != NULL) { authorized = mg_authorize_digest(&conn->mg_conn, fp); @@ -3034,7 +3021,7 @@ static int is_authorized(struct connection *conn, const char *path) { static int is_authorized_for_dav(struct connection *conn) { const char *auth_file = conn->server->config_options[DAV_AUTH_FILE]; FILE *fp; - int authorized = 0; + int authorized = MG_AUTH_FAIL; if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) { authorized = mg_authorize_digest(&conn->mg_conn, fp); @@ -3359,7 +3346,7 @@ static void handle_lsp_request(struct connection *conn, const char *path, } #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 static const char lua_pat[] = LUA_SCRIPT_PATTERN; file_stat_t st; @@ -3372,17 +3359,15 @@ static void open_local_endpoint(struct connection *conn) { #ifndef MONGOOSE_NO_AUTH // Call auth handler 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); return; } #endif // Call URI handler if one is registered for this URI - conn->endpoint.uh = find_uri_handler(conn->server, conn->mg_conn.uri); - if (conn->endpoint.uh != NULL) { + if (skip_user == 0 && conn->server->request_handler != NULL) { conn->endpoint_type = EP_USER; - conn->mg_conn.content = conn->local_iobuf.buf; #if MONGOOSE_USE_POST_SIZE_LIMIT > 1 { const char *cl = mg_get_header(&conn->mg_conn, "Content-Length"); @@ -3525,7 +3510,7 @@ static void process_request(struct connection *conn) { send_websocket_handshake_if_requested(&conn->mg_conn); #endif send_continue_if_expected(conn); - open_local_endpoint(conn); + open_local_endpoint(conn, 0); } #ifndef MONGOOSE_NO_CGI @@ -3534,7 +3519,7 @@ static void process_request(struct connection *conn) { } #endif 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 if (conn->endpoint_type == EP_PUT && io->len > 0) { @@ -3859,7 +3844,9 @@ unsigned int mg_poll_server(struct mg_server *server, int milliseconds) { } if (conn->flags & CONN_LONG_RUNNING) { 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) { close_conn(conn); @@ -3883,10 +3870,6 @@ void mg_destroy_server(struct mg_server **server) { LINKED_LIST_FOREACH(&s->active_connections, lp, tmp) { 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++) { 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, 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, char *dst, size_t dst_len) { const char *p, *e, *s; @@ -4145,6 +4118,9 @@ const char *mg_set_option(struct mg_server *server, const char *name, 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) { server->error_handler = handler; @@ -4184,7 +4160,6 @@ struct mg_server *mg_create_server(void *server_data) { #endif LINKED_LIST_INIT(&server->active_connections); - LINKED_LIST_INIT(&server->uri_handlers); // Create control socket pair. Do it in a loop to protect from // interrupted syscalls in mg_socketpair(). diff --git a/mongoose.h b/mongoose.h index 9ba5afe9f3..5822b81532 100644 --- a/mongoose.h +++ b/mongoose.h @@ -65,7 +65,7 @@ struct mg_server *mg_create_server(void *server_param); void mg_destroy_server(struct mg_server **); const char *mg_set_option(struct mg_server *, const char *opt, const char *val); 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_auth_handler(struct mg_server *, mg_handler_t); const char **mg_get_valid_option_names(void); @@ -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_printf(struct mg_connection *conn, const char *fmt, ...); - 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, char *buf, size_t buf_len); 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, void *mg_start_thread(void *(*func)(void *), void *param); char *mg_md5(char buf[33], ...); int mg_authorize_digest(struct mg_connection *c, FILE *fp); -void mg_send_digest_auth_request(struct mg_connection *conn); -// Callback return codes -enum { MG_REPLY_TO_BE_CONTINUED, MG_REPLY_COMPLETED }; +// Callback function return codes +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 enum { diff --git a/unit_test.c b/unit_test.c index 03b7b43f29..b9cf34a88c 100644 --- a/unit_test.c +++ b/unit_test.c @@ -364,39 +364,41 @@ static const char *test_next_option(void) { } static int cb1(struct mg_connection *conn) { - // We're not sending HTTP headers here, to make testing easier - //mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\n%s %s %s", - mg_printf(conn, "%s %s %s", - conn->server_param == NULL ? "?" : (char *) conn->server_param, - conn->connection_param == NULL ? "?" : "!", conn->remote_ip); - return 1; + int result = MG_REQUEST_NOT_PROCESSED; + if (!strcmp(conn->uri, "/cb1")) { + mg_printf(conn, "%s %s %s", + conn->server_param == NULL ? "?" : (char *) conn->server_param, + conn->connection_param == NULL ? "?" : "!", conn->remote_ip); + result = MG_REQUEST_PROCESSED; + } + return result; } static int error_handler(struct mg_connection *conn) { 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) { if (conn->status_code == MG_CONNECT_SUCCESS) { 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) { sprintf((char *) conn->connection_param, "%.*s", (int) conn->content_len, conn->content); } - return 1; + return MG_CLIENT_CLOSE; } static int ts2(struct mg_connection *conn) { if (conn->status_code == MG_CONNECT_SUCCESS) { 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) { sprintf((char *) conn->connection_param, "%s %.*s", conn->uri, (int) conn->content_len, conn->content); } - return 1; + return MG_CLIENT_CLOSE; } static const char *test_server(void) { @@ -406,7 +408,7 @@ static const char *test_server(void) { ASSERT(server != NULL); ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == 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); 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) { } static int cb4h(struct mg_connection *conn) { - mg_send_data(conn, ":-)", 3); - return MG_REPLY_COMPLETED; + int result = MG_REQUEST_NOT_PROCESSED; + if (!strcmp(conn->uri, "/x")) { + mg_send_data(conn, ":-)", 3); + result = MG_REQUEST_PROCESSED; + } + return result; } static int cb4(struct mg_connection *conn) { if (conn->status_code == MG_CONNECT_SUCCESS) { 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 { sprintf((char *) conn->connection_param, "%.*s", (int) conn->content_len, conn->content); } - return MG_REPLY_COMPLETED; + return MG_CLIENT_CLOSE; } static int cb3(struct mg_connection *conn) { - fflush(stdout); sprintf((char *) conn->connection_param, "%d", conn->status_code); - return 1; + return MG_CLIENT_CLOSE; } 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, "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, "127.0.0.1", atoi(HTTP_PORT), 0, cb2, buf2) == 1); ASSERT(mg_connect(server, "127.0.0.1", 29, 0, cb3, buf3) == 1);