Fix r3_tree_match_route

This commit is contained in:
c9s 2014-05-19 10:34:48 +08:00
parent c34ae55da2
commit 2ac6f87422
6 changed files with 95 additions and 65 deletions

View file

@ -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`.

View file

@ -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
```

View file

@ -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

View file

@ -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);

View file

@ -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

1 1400242718 5649455.80
316 1400415353 10705889.14
317 1400415397 11505319.20
318 1400465549 13249817.73
319 1400465650 13467612.96
320 1400465723 13269768.49
321 1400465767 13374884.38
322 1400465776 13440016.82
323 1400465836 13386592.12
324 1400465865 13137081.39
325 1400465878 13376710.05
326 1400465928 13251983.44
327 1400466198 13359933.76
328 1400466833 13166545.46
329 1400466875 13515485.94

View file

@ -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);