Commit db8df413 authored by Alexander Alashkin's avatar Alexander Alashkin Committed by Sergey Lyubka

Implement mg_register_http_endpoint

    PUBLISHED_FROM=357e722e80a2597aa3959756e69db03dc1057ded
parent bda05d93
...@@ -2112,6 +2112,7 @@ static void mg_destroy_conn(struct mg_connection *conn) { ...@@ -2112,6 +2112,7 @@ static void mg_destroy_conn(struct mg_connection *conn) {
#endif #endif
mbuf_free(&conn->recv_mbuf); mbuf_free(&conn->recv_mbuf);
mbuf_free(&conn->send_mbuf); mbuf_free(&conn->send_mbuf);
mbuf_free(&conn->endpoints);
memset(conn, 0, sizeof(*conn)); memset(conn, 0, sizeof(*conn));
MG_FREE(conn); MG_FREE(conn);
} }
...@@ -4785,6 +4786,45 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, ...@@ -4785,6 +4786,45 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
return body_len; return body_len;
} }
static mg_event_handler_t get_endpoint_handler(struct mg_connection *nc,
struct mg_str *uri_path) {
size_t pos = 0;
mg_event_handler_t ret = NULL;
int matched, matched_max = 0;
if (nc == NULL) {
return NULL;
}
while (pos < nc->endpoints.len) {
size_t name_len;
memcpy(&name_len, nc->endpoints.buf + pos, sizeof(name_len));
if ((matched = mg_match_prefix_n(nc->endpoints.buf + pos + sizeof(size_t),
name_len, uri_path->p, uri_path->len)) !=
-1) {
if (matched > matched_max) {
/* Looking for the longest suitable handler */
memcpy(&ret,
nc->endpoints.buf + pos + sizeof(name_len) + (name_len + 1),
sizeof(ret));
matched_max = matched;
}
}
pos += sizeof(name_len) + (name_len + 1) + sizeof(ret);
}
return ret;
}
static void mg_call_endpoint_handler(struct mg_connection *nc, int ev,
struct http_message *hm) {
mg_event_handler_t uri_handler =
ev == MG_EV_HTTP_REQUEST ? get_endpoint_handler(nc->listener, &hm->uri)
: NULL;
mg_call(nc, uri_handler ? uri_handler : nc->handler, ev, hm);
}
/* /*
* lx106 compiler has a bug (TODO(mkm) report and insert tracking bug here) * lx106 compiler has a bug (TODO(mkm) report and insert tracking bug here)
* If a big structure is declared in a big function, lx106 gcc will make it * If a big structure is declared in a big function, lx106 gcc will make it
...@@ -4821,7 +4861,7 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) { ...@@ -4821,7 +4861,7 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
hm->message.len = io->len; hm->message.len = io->len;
hm->body.len = io->buf + io->len - hm->body.p; hm->body.len = io->buf + io->len - hm->body.p;
mg_call(nc, nc->handler, ev2, hm); mg_call_endpoint_handler(nc, ev2, hm);
} }
free_http_proto_data(nc); free_http_proto_data(nc);
} }
...@@ -4926,10 +4966,10 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) { ...@@ -4926,10 +4966,10 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
if (js_callback_handled_request) { if (js_callback_handled_request) {
nc->flags |= MG_F_SEND_AND_CLOSE; nc->flags |= MG_F_SEND_AND_CLOSE;
} else { } else {
mg_call(nc, nc->handler, trigger_ev, hm); mg_call_endpoint_handler(nc, trigger_ev, hm);
} }
#else #else
mg_call(nc, nc->handler, trigger_ev, hm); mg_call_endpoint_handler(nc, trigger_ev, hm);
#endif #endif
mbuf_remove(io, hm->message.len); mbuf_remove(io, hm->message.len);
} }
...@@ -6127,7 +6167,7 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, ...@@ -6127,7 +6167,7 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
} }
} else { } else {
/* Regular rewrite, URI=directory */ /* Regular rewrite, URI=directory */
int match_len = mg_match_prefix(a.p, a.len, cp); int match_len = mg_match_prefix_n(a.p, a.len, cp, hm->uri.len);
if (match_len > 0) { if (match_len > 0) {
file_uri_start = cp + match_len; file_uri_start = cp + match_len;
if (*file_uri_start == '/' || file_uri_start == cp_end) { if (*file_uri_start == '/' || file_uri_start == cp_end) {
...@@ -7052,6 +7092,14 @@ size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, ...@@ -7052,6 +7092,14 @@ size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
return 0; return 0;
} }
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
mg_event_handler_t handler) {
size_t len = strlen(uri_path);
mbuf_append(&nc->endpoints, &len, sizeof(len));
mbuf_append(&nc->endpoints, uri_path, len + 1);
mbuf_append(&nc->endpoints, &handler, sizeof(handler));
}
#endif /* MG_DISABLE_HTTP */ #endif /* MG_DISABLE_HTTP */
#ifdef MG_MODULE_LINES #ifdef MG_MODULE_LINES
#line 0 "./src/util.c" #line 0 "./src/util.c"
...@@ -7379,35 +7427,41 @@ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, ...@@ -7379,35 +7427,41 @@ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
return list; return list;
} }
int mg_match_prefix(const char *pattern, int pattern_len, const char *str) { int mg_match_prefix_n(const char *pattern, int pattern_len, const char *str,
int str_len) {
const char *or_str; const char *or_str;
int len, res, i = 0, j = 0; int len, res, i = 0, j = 0;
if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) { if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
res = mg_match_prefix(pattern, or_str - pattern, str); res = mg_match_prefix_n(pattern, or_str - pattern, str, str_len);
return res > 0 ? res : mg_match_prefix( return res > 0 ? res
or_str + 1, : mg_match_prefix_n(or_str + 1,
(pattern + pattern_len) - (or_str + 1), str); (pattern + pattern_len) - (or_str + 1),
str, str_len);
} }
for (; i < pattern_len; i++, j++) { for (; i < pattern_len; i++, j++) {
if (pattern[i] == '?' && str[j] != '\0') { if (pattern[i] == '?' && j != str_len) {
continue; continue;
} else if (pattern[i] == '$') { } else if (pattern[i] == '$') {
return str[j] == '\0' ? j : -1; return j == str_len ? j : -1;
} else if (pattern[i] == '*') { } else if (pattern[i] == '*') {
i++; i++;
if (pattern[i] == '*') { if (pattern[i] == '*') {
i++; i++;
len = (int) strlen(str + j); len = str_len - j;
} else { } else {
len = (int) strcspn(str + j, "/"); len = 0;
while (j + len != str_len && str[len] != '/') {
len++;
}
} }
if (i == pattern_len) { if (i == pattern_len) {
return j + len; return j + len;
} }
do { do {
res = mg_match_prefix(pattern + i, pattern_len - i, str + j + len); res = mg_match_prefix_n(pattern + i, pattern_len - i, str + j + len,
str_len - j - len);
} while (res == -1 && len-- > 0); } while (res == -1 && len-- > 0);
return res == -1 ? -1 : j + res + len; return res == -1 ? -1 : j + res + len;
} else if (lowercase(&pattern[i]) != lowercase(&str[j])) { } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
...@@ -7417,6 +7471,10 @@ int mg_match_prefix(const char *pattern, int pattern_len, const char *str) { ...@@ -7417,6 +7471,10 @@ int mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
return j; return j;
} }
int mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
return mg_match_prefix_n(pattern, pattern_len, str, strlen(str));
}
struct mg_str mg_mk_str(const char *s) { struct mg_str mg_mk_str(const char *s) {
struct mg_str ret = {s, strlen(s)}; struct mg_str ret = {s, strlen(s)};
return ret; return ret;
......
...@@ -1061,8 +1061,8 @@ struct mg_connection { ...@@ -1061,8 +1061,8 @@ struct mg_connection {
void *user_data; /* User-specific data */ void *user_data; /* User-specific data */
void *priv_1; /* Used by mg_enable_multithreading() */ void *priv_1; /* Used by mg_enable_multithreading() */
void *priv_2; /* Used by mg_enable_multithreading() */ void *priv_2; /* Used by mg_enable_multithreading() */
struct mbuf endpoints; /* Used by mg_register_http_endpoint */
void *mgr_data; /* Implementation-specific event manager's data. */ void *mgr_data; /* Implementation-specific event manager's data. */
unsigned long flags; unsigned long flags;
/* Flags set by Mongoose */ /* Flags set by Mongoose */
#define MG_F_LISTENING (1 << 0) /* This connection is listening */ #define MG_F_LISTENING (1 << 0) /* This connection is listening */
...@@ -1752,10 +1752,13 @@ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, ...@@ -1752,10 +1752,13 @@ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
struct mg_str *eq_val); struct mg_str *eq_val);
/* /*
* Match 0-terminated string against a glob pattern. * Match 0-terminated string (mg_match_prefix) or string with given length
* mg_match_prefix_n against a glob pattern.
* Match is case-insensitive. Return number of bytes matched, or -1 if no match. * Match is case-insensitive. Return number of bytes matched, or -1 if no match.
*/ */
int mg_match_prefix(const char *pattern, int pattern_len, const char *str); int mg_match_prefix(const char *pattern, int pattern_len, const char *str);
int mg_match_prefix_n(const char *pattern, int pattern_len, const char *str,
int str_len);
/* A helper function for creating mg_str struct from plain C string */ /* A helper function for creating mg_str struct from plain C string */
struct mg_str mg_mk_str(const char *s); struct mg_str mg_mk_str(const char *s);
...@@ -2289,6 +2292,38 @@ struct mg_serve_http_opts { ...@@ -2289,6 +2292,38 @@ struct mg_serve_http_opts {
void mg_serve_http(struct mg_connection *nc, struct http_message *hm, void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
struct mg_serve_http_opts opts); struct mg_serve_http_opts opts);
/*
* Register callback for specified http endpoint
* Note: if callback is registered it is called instead of
* callback provided in mg_bind
*
* Example code snippet:
*
* [source,c]
* .web_server.c
* ----
* static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) {
* (void) ev; (void) ev_data;
* mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello1]");
* nc->flags |= MG_F_SEND_AND_CLOSE;
* }
*
* static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) {
* (void) ev; (void) ev_data;
* mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello2]");
* nc->flags |= MG_F_SEND_AND_CLOSE;
* }
*
* void init() {
* nc = mg_bind(&mgr, local_addr, cb1);
* mg_register_http_endpoint(nc, "/hello1", handle_hello1);
* mg_register_http_endpoint(nc, "/hello1/hello2", handle_hello2);
* }
* ----
*/
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
mg_event_handler_t handler);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
......
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