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
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.
......
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
......
......@@ -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
......
......@@ -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"));
......
......@@ -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");
......
......@@ -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);
......
......@@ -30,7 +30,7 @@ static int index_html(struct mg_connection *conn) {
mg_printf_data(conn, "%s", "</body></html>");
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"));
......
......@@ -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, &current_timer);
}
......
......@@ -24,10 +24,13 @@
out('DISCONNECTED');
};
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>');
num_messages++;
if (num_messages > 100) {
}
if (num_messages > 15) {
websocket.send('exit');
}
};
......
......@@ -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)) {
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);
} else {
conn->flags |= CONN_LONG_RUNNING;
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().
......
......@@ -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 {
......
......@@ -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",
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);
return 1;
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) {
int result = MG_REQUEST_NOT_PROCESSED;
if (!strcmp(conn->uri, "/x")) {
mg_send_data(conn, ":-)", 3);
return MG_REPLY_COMPLETED;
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);
......
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