Implement mg_register_http_endpoint

PUBLISHED_FROM=357e722e80a2597aa3959756e69db03dc1057ded
This commit is contained in:
Alexander Alashkin 2016-02-17 08:02:17 +02:00 committed by Sergey Lyubka
parent bda05d9372
commit db8df41396
2 changed files with 109 additions and 16 deletions

View File

@ -2112,6 +2112,7 @@ static void mg_destroy_conn(struct mg_connection *conn) {
#endif
mbuf_free(&conn->recv_mbuf);
mbuf_free(&conn->send_mbuf);
mbuf_free(&conn->endpoints);
memset(conn, 0, sizeof(*conn));
MG_FREE(conn);
}
@ -4785,6 +4786,45 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
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)
* 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) {
int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
hm->message.len = io->len;
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);
}
@ -4926,10 +4966,10 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
if (js_callback_handled_request) {
nc->flags |= MG_F_SEND_AND_CLOSE;
} else {
mg_call(nc, nc->handler, trigger_ev, hm);
mg_call_endpoint_handler(nc, trigger_ev, hm);
}
#else
mg_call(nc, nc->handler, trigger_ev, hm);
mg_call_endpoint_handler(nc, trigger_ev, hm);
#endif
mbuf_remove(io, hm->message.len);
}
@ -6127,7 +6167,7 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
}
} else {
/* 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) {
file_uri_start = cp + match_len;
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,
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 */
#ifdef MG_MODULE_LINES
#line 0 "./src/util.c"
@ -7379,35 +7427,41 @@ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
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;
int len, res, i = 0, j = 0;
if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
res = mg_match_prefix(pattern, or_str - pattern, str);
return res > 0 ? res : mg_match_prefix(
or_str + 1,
(pattern + pattern_len) - (or_str + 1), str);
res = mg_match_prefix_n(pattern, or_str - pattern, str, str_len);
return res > 0 ? res
: mg_match_prefix_n(or_str + 1,
(pattern + pattern_len) - (or_str + 1),
str, str_len);
}
for (; i < pattern_len; i++, j++) {
if (pattern[i] == '?' && str[j] != '\0') {
if (pattern[i] == '?' && j != str_len) {
continue;
} else if (pattern[i] == '$') {
return str[j] == '\0' ? j : -1;
return j == str_len ? j : -1;
} else if (pattern[i] == '*') {
i++;
if (pattern[i] == '*') {
i++;
len = (int) strlen(str + j);
len = str_len - j;
} else {
len = (int) strcspn(str + j, "/");
len = 0;
while (j + len != str_len && str[len] != '/') {
len++;
}
}
if (i == pattern_len) {
return j + len;
}
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);
return res == -1 ? -1 : j + res + len;
} 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) {
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 ret = {s, strlen(s)};
return ret;

View File

@ -1061,8 +1061,8 @@ struct mg_connection {
void *user_data; /* User-specific data */
void *priv_1; /* 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. */
unsigned long flags;
/* Flags set by Mongoose */
#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,
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.
*/
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 */
struct mg_str mg_mk_str(const char *s);
@ -2289,6 +2292,38 @@ struct mg_serve_http_opts {
void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
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
}
#endif /* __cplusplus */