From db8df413962c03a02b5d8edd1efcfe3f418755e2 Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Wed, 17 Feb 2016 08:02:17 +0200 Subject: [PATCH] Implement mg_register_http_endpoint PUBLISHED_FROM=357e722e80a2597aa3959756e69db03dc1057ded --- mongoose.c | 86 +++++++++++++++++++++++++++++++++++++++++++++--------- mongoose.h | 39 +++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 16 deletions(-) diff --git a/mongoose.c b/mongoose.c index 2ad27c34..e954e3ff 100644 --- a/mongoose.c +++ b/mongoose.c @@ -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; diff --git a/mongoose.h b/mongoose.h index 4ef90bb7..eeb33397 100644 --- a/mongoose.h +++ b/mongoose.h @@ -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 */