Fix r3_tree_match_route
This commit is contained in:
parent
c34ae55da2
commit
2ac6f87422
6 changed files with 95 additions and 65 deletions
19
CHANGES.md
19
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`.
|
||||
|
||||
|
|
53
README.md
53
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
|
||||
```
|
||||
|
||||
|
||||
|
|
15
include/r3.h
15
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
|
||||
|
|
26
src/node.c
26
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue