From 2ac6f874223cbbd0f70ecb8291949caab9829337 Mon Sep 17 00:00:00 2001 From: c9s Date: Mon, 19 May 2014 10:34:48 +0800 Subject: [PATCH] Fix r3_tree_match_route --- CHANGES.md | 19 +++++++++++++--- README.md | 53 ++++++++++++++++++++++++++++++--------------- include/r3.h | 15 ++++++++----- src/node.c | 26 ++++++---------------- tests/bench_str.csv | 11 ++++++++++ tests/check_tree.c | 36 +++++++++++++----------------- 6 files changed, 95 insertions(+), 65 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 94b0eed..59f0173 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ API changes: -1. Remove the `route` argument from `r3_tree_insert_pathl`: +1. Removed the `route` argument from `r3_tree_insert_pathl`: node * r3_tree_insert_pathl(node *tree, char *path, int path_len, void * data); @@ -10,6 +10,19 @@ This reduce the interface complexity, e.g., r3_tree_insert_path(n, "/user2/{id:\\d+}", &var2); -2. The original `r3_tree_insert_pathl` has been renamed to `_r3_tree_insert_path` as a private API. - +2. The original `r3_tree_insert_pathl` has been moved to `_r3_tree_insert_pathl` as a private API. + +3. Moved `r3_tree_matchl` to `r3_tree_matchl` since it require the length of the path string. + + m = r3_tree_matchl( n , "/foo", strlen("/foo"), entry); + +4. Added `r3_tree_match` for users to match a path without the length of the path string. + + m = r3_tree_match( n , "/foo", entry); + +5. Added `r3_tree_match_entry` for users want to match a `match_entry`, which is just a macro to simplify the use: + + #define r3_tree_match_entry(n, entry) r3_tree_matchl(n, entry->path, entry->path_len, entry) + +6. A path that is inserted by `r3_tree_insert_route` can only be matched by `r3_tree_match_route`. diff --git a/README.md b/README.md index 854e8bc..dca5977 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,13 @@ n = r3_tree_create(10); int route_data = 3; // insert the route path into the router tree -r3_tree_insert_pathl(n , "/zoo" , strlen("/zoo") , NULL, &route_data ); -r3_tree_insert_pathl(n , "/foo/bar" , strlen("/foo/bar") , NULL, &route_data ); -r3_tree_insert_pathl(n , "/bar" , strlen("/bar") , NULL, &route_data ); -r3_tree_insert_pathl(n , "/post/{id}" , strlen("/post/{id}") , NULL, &route_data ); +r3_tree_insert_path(n, "/bar", &route_data ); // ignore the length of path + +r3_tree_insert_pathl(n, "/zoo" , strlen("/zoo") , &route_data ); +r3_tree_insert_pathl(n, "/foo/bar" , strlen("/foo/bar") , &route_data ); + +r3_tree_insert_pathl(n , "/post/{id}" , strlen("/post/{id}") , &route_data ); + r3_tree_insert_pathl(n , "/user/{id:\\d+}" , strlen("/user/{id:\\d+}") , NULL, &route_data ); // let's compile the tree! @@ -53,8 +56,31 @@ r3_tree_dump(n, 0); // match a route node *matched_node = r3_tree_match(n, "/foo/bar", strlen("/foo/bar"), NULL); -matched_node->endpoint; // make sure there is a route end at here. -int ret = *( (*int) matched_node->route_ptr ); +if (matched_node) { + matched_node->endpoint; // make sure there is a route end at here. + int ret = *( (*int) matched_node->route_ptr ); +} +``` + +If you want to capture the variables from regular expression, you will need to create a match entry, +the catched variables will be pushed into the match entry structure: + +```c +match_entry * entry = match_entry_create("/foo/bar"); +``` + +And you can even specify the request method restriction: + +```c +entry->request_method = METHOD_GET; +entry->request_method = METHOD_POST; +entry->request_method = METHOD_GET | METHOD_POST; +``` + +When using `match_entry`, you may match the route with `r3_tree_match_entry` function: + +```c +node *matched_node = r3_tree_match_entry(n, entry); ``` ### Routing with conditions @@ -71,21 +97,14 @@ int route_data = 3; // define the route with conditions route *r1 = route_create("/blog/post"); -r1->request_method = METHOD_GET | METHOD_POST; // ALLOW GET OR POST +r1->request_method = METHOD_GET | METHOD_POST; // ALLOW GET OR POST METHOD // insert the route path into the router tree -r3_tree_insert_route(n, r1, NULL, &route_data ); - +r3_tree_insert_route(n, r1, &route_data ); r3_tree_compile(n); -node *matched_node = r3_tree_match(n, "/foo/bar", strlen("/foo/bar"), entry); -matched_node->endpoint; // make sure there is a route end at here. - -if (matched_node->routes) { - // find the route with matched condition - route *c = r3_node_match_route(m, entry); - c->data; // get the data from matched route -} +route *matched_route = r3_tree_match_route(n, entry); +matched_route->data; // get the data from matched route ``` diff --git a/include/r3.h b/include/r3.h index a465fdb..8f7d119 100644 --- a/include/r3.h +++ b/include/r3.h @@ -105,11 +105,13 @@ edge * r3_node_find_edge(node * n, char * pat); void r3_node_append_edge(node *n, edge *child); -node * r3_tree_insert_path(node *tree, char *path, void * data); node * r3_tree_insert_pathl(node *tree, char *path, int path_len, void * data); -node * r3_tree_insert_route(node *tree, route * route, void * data); +#define r3_tree_insert_path(n,p,d) _r3_tree_insert_pathl(n,p,strlen(p), NULL, d) + +// node * r3_tree_insert_route(node *tree, route * route, void * data); +#define r3_tree_insert_route(n,r,d) _r3_tree_insert_pathl(n, r->path, r->path_len, r, d) /** * The private API to insert a path @@ -129,9 +131,12 @@ void r3_tree_compile(node *n); void r3_tree_compile_patterns(node * n); -node * r3_tree_match(node * n, char * path, int path_len, match_entry * entry); +node * r3_tree_matchl(node * n, char * path, int path_len, match_entry * entry); -node * r3_tree_match_with_entry(node * n, match_entry * entry); +#define r3_tree_match(n,p,e) r3_tree_matchl(n,p, strlen(p), e) + +// node * r3_tree_match_entry(node * n, match_entry * entry); +#define r3_tree_match_entry(n, entry) r3_tree_matchl(n, entry->path, entry->path_len, entry) bool r3_node_has_slug_edges(node *n); @@ -160,7 +165,7 @@ void r3_node_append_route(node * n, route * route); void route_free(route * route); -route * r3_node_match_route(node *n, match_entry * entry); +route * r3_tree_match_route(node *n, match_entry * entry); #define METHOD_GET 2 #define METHOD_POST 2<<1 diff --git a/src/node.c b/src/node.c index 5255cf2..a8aa9ab 100644 --- a/src/node.c +++ b/src/node.c @@ -213,22 +213,18 @@ void match_entry_free(match_entry * entry) { } -node * r3_tree_match_with_entry(node * n, match_entry * entry) { - return r3_tree_match(n, entry->path, entry->path_len, entry); -} - /** * This function matches the URL path and return the left node * - * r3_tree_match returns NULL when the path does not match. returns *node when the path matches. + * r3_tree_matchl returns NULL when the path does not match. returns *node when the path matches. * * @param node n the root of the tree * @param char* path the URL path to dispatch * @param int path_len the length of the URL path. * @param match_entry* entry match_entry is used for saving the captured dynamic strings from pcre result. */ -node * r3_tree_match(node * n, char * path, int path_len, match_entry * entry) { +node * r3_tree_matchl(node * n, char * path, int path_len, match_entry * entry) { info("try matching: %s\n", path); edge *e; @@ -287,7 +283,7 @@ node * r3_tree_match(node * n, char * path, int path_len, match_entry * entry) { return e->child; } // get the length of orginal string: $0 - return r3_tree_match( e->child, path + (n->ov[1] - n->ov[0]), restlen, entry); + return r3_tree_matchl( e->child, path + (n->ov[1] - n->ov[0]), restlen, entry); } } // does not match @@ -297,14 +293,16 @@ node * r3_tree_match(node * n, char * path, int path_len, match_entry * entry) { if ( (e = r3_node_find_edge_str(n, path, path_len)) != NULL ) { int restlen = path_len - e->pattern_len; if(restlen > 0) { - return r3_tree_match(e->child, path + e->pattern_len, restlen, entry); + return r3_tree_matchl(e->child, path + e->pattern_len, restlen, entry); } return e->child; } return NULL; } -route * r3_node_match_route(node *n, match_entry * entry) { +route * r3_tree_match_route(node *tree, match_entry * entry) { + node *n; + n = r3_tree_match_entry(tree, entry); if (n->routes && n->route_len > 0) { int i; for (i = 0; i < n->route_len ; i++ ) { @@ -377,16 +375,6 @@ route * route_createl(char * path, int path_len) { return info; } - -node * r3_tree_insert_route(node *tree, route * route, void * data) { - return _r3_tree_insert_pathl(tree, route->path, route->path_len, route, data); -} - -node * r3_tree_insert_path(node *tree, char *path, void * data) -{ - return _r3_tree_insert_pathl(tree, path, strlen(path) , NULL , data); -} - node * r3_tree_insert_pathl(node *tree, char *path, int path_len, void * data) { return _r3_tree_insert_pathl(tree, path, path_len, NULL , data); diff --git a/tests/bench_str.csv b/tests/bench_str.csv index 339d527..0ed01bc 100644 --- a/tests/bench_str.csv +++ b/tests/bench_str.csv @@ -316,3 +316,14 @@ 1400415353,10705889.14 1400415397,11505319.20 1400465549,13249817.73 +1400465650,13467612.96 +1400465723,13269768.49 +1400465767,13374884.38 +1400465776,13440016.82 +1400465836,13386592.12 +1400465865,13137081.39 +1400465878,13376710.05 +1400465928,13251983.44 +1400466198,13359933.76 +1400466833,13166545.46 +1400466875,13515485.94 diff --git a/tests/check_tree.c b/tests/check_tree.c index 9c5bda0..dbf9520 100644 --- a/tests/check_tree.c +++ b/tests/check_tree.c @@ -90,27 +90,27 @@ START_TEST (test_compile) match_entry * entry; entry = match_entry_createl( "foo" , strlen("/foo") ); - m = r3_tree_match( n , "/foo", strlen("/foo"), entry); + m = r3_tree_matchl( n , "/foo", strlen("/foo"), entry); fail_if( NULL == m ); entry = match_entry_createl( "/zoo" , strlen("/zoo") ); - m = r3_tree_match( n , "/zoo", strlen("/zoo"), entry); + m = r3_tree_matchl( n , "/zoo", strlen("/zoo"), entry); fail_if( NULL == m ); entry = match_entry_createl( "/bar" , strlen("/bar") ); - m = r3_tree_match( n , "/bar", strlen("/bar"), entry); + m = r3_tree_matchl( n , "/bar", strlen("/bar"), entry); fail_if( NULL == m ); entry = match_entry_createl( "/xxx" , strlen("/xxx") ); - m = r3_tree_match( n , "/xxx", strlen("/xxx"), entry); + m = r3_tree_matchl( n , "/xxx", strlen("/xxx"), entry); fail_if( NULL == m ); entry = match_entry_createl( "/foo/xxx" , strlen("/foo/xxx") ); - m = r3_tree_match( n , "/foo/xxx", strlen("/foo/xxx"), entry); + m = r3_tree_matchl( n , "/foo/xxx", strlen("/foo/xxx"), entry); fail_if( NULL == m ); entry = match_entry_createl( "/some_id" , strlen("/some_id") ); - m = r3_tree_match( n , "/some_id", strlen("/some_id"), entry); + m = r3_tree_matchl( n , "/some_id", strlen("/some_id"), entry); fail_if( NULL == m ); ck_assert_int_gt( m->endpoint , 0 ); // should not be an endpoint } @@ -172,12 +172,12 @@ START_TEST (test_pcre_patterns_insert) r3_tree_dump(n, 0); node *matched; - matched = r3_tree_match(n, "/post/111-222", strlen("/post/111-222"), NULL); + matched = r3_tree_matchl(n, "/post/111-222", strlen("/post/111-222"), NULL); ck_assert(matched); ck_assert_int_gt(matched->endpoint, 0); // incomplete string shouldn't match - matched = r3_tree_match(n, "/post/111-", strlen("/post/111-"), NULL); + matched = r3_tree_matchl(n, "/post/111-", strlen("/post/111-"), NULL); ck_assert(matched); ck_assert_int_eq(matched->endpoint, 0); @@ -278,7 +278,7 @@ START_TEST(test_pcre_pattern_simple) r3_tree_compile(n); // r3_tree_dump(n, 0); node *matched; - matched = r3_tree_match(n, "/user/123", strlen("/user/123"), entry); + matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry); fail_if(matched == NULL); ck_assert_int_gt(entry->vars->len, 0); ck_assert_str_eq(entry->vars->tokens[0],"123"); @@ -310,7 +310,7 @@ START_TEST(test_pcre_pattern_more) // r3_tree_dump(n, 0); node *matched; - matched = r3_tree_match(n, "/user/123", strlen("/user/123"), entry); + matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry); fail_if(matched == NULL); ck_assert_int_gt(entry->vars->len, 0); ck_assert_str_eq(entry->vars->tokens[0],"123"); @@ -319,13 +319,13 @@ START_TEST(test_pcre_pattern_more) info("matched %p\n", matched->data); ck_assert_int_eq( *((int*) matched->data), var1); - matched = r3_tree_match(n, "/user2/123", strlen("/user2/123"), entry); + matched = r3_tree_matchl(n, "/user2/123", strlen("/user2/123"), entry); fail_if(matched == NULL); ck_assert_int_gt(entry->vars->len, 0); ck_assert_str_eq(entry->vars->tokens[0],"123"); ck_assert_int_eq( *((int*)matched->data), var2); - matched = r3_tree_match(n, "/user3/123", strlen("/user3/123"), entry); + matched = r3_tree_matchl(n, "/user3/123", strlen("/user3/123"), entry); fail_if(matched == NULL); ck_assert_int_gt(entry->vars->len, 0); ck_assert_str_eq(entry->vars->tokens[0],"123"); @@ -352,15 +352,9 @@ START_TEST(test_insert_route) r3_tree_insert_route(n, r1, &var1); r3_tree_insert_route(n, r2, &var2); - node *m; - m = r3_tree_match(n , "/blog/post", strlen("/blog/post"), entry); - - fail_if(m == NULL); - fail_if(m->endpoint == 0); - route *c = r3_node_match_route(m, entry); + route *c = r3_tree_match_route(n, entry); fail_if(c == NULL); - match_entry_free(entry); route_free(r1); route_free(r2); @@ -720,7 +714,7 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL); // match_entry *entry = calloc( sizeof(entry) , 1 ); node *m; - m = r3_tree_match(n , "/qux/bar/corge", strlen("/qux/bar/corge"), NULL); + m = r3_tree_match(n , "/qux/bar/corge", NULL); fail_if( m == NULL ); // r3_tree_dump( m, 0 ); ck_assert_int_eq( *((int*) m->data), 999 ); @@ -728,7 +722,7 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL); printf("Benchmarking...\n"); BENCHMARK(string_dispatch) - r3_tree_match(n , "/qux/bar/corge", strlen("/qux/bar/corge"), NULL); + r3_tree_match(n , "/qux/bar/corge", NULL); END_BENCHMARK() bench_print_summary(&B);