diff --git a/examples/routing.c b/examples/routing.c index 6d83c01..8ad7b4b 100644 --- a/examples/routing.c +++ b/examples/routing.c @@ -14,12 +14,14 @@ void test1(void) { R3Node *n = r3_tree_create(10); - int route_data = 3; + int route_data1 = 3; + int route_data2 = 44; + int route_data3 = 555; // insert the R3Route path into the router tree - r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog", sizeof("/blog") - 1, &route_data ); - r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/{post}/asf/{id}", sizeof("/blog/{post}/asf/{id}") - 1, &route_data ); - r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/{post}/asd/{id:[0-9]+}/qwe", sizeof("/blog/{post}/asd/{id:[0-9]+}/qwe") - 1, &route_data ); + r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog", sizeof("/blog") - 1, &route_data1 ); + r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/{idl:\\d+}/asf/{id}", strlen("/blog/{idl:\\d+}/asf/{id}"), &route_data2 ); + r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog3/{idl:\\d{3}}/asd/{id:[0-9]+}/qwe", sizeof("/blog3/{idl:\\d{3}}/asd/{id:[0-9]+}/qwe") - 1, &route_data3 ); char *errstr = NULL; int err = r3_tree_compile(n, &errstr); @@ -28,6 +30,7 @@ void test1(void) { printf("error: %s\n", errstr); free(errstr); // errstr is created from `asprintf`, so you have to free it manually. } + // r3_tree_dump(n,0); // in your http server handler @@ -35,40 +38,54 @@ void test1(void) { // create the match entry for capturing dynamic variables. match_entry * entry; R3Route *matched_route; - // for (int k = 0; k < 3000000; k++) { - entry = match_entry_create("/blog"); - if (entry != NULL) { - entry->request_method = METHOD_GET; - matched_route = r3_tree_match_route(n, entry); - if (matched_route != NULL) { - // printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route - for (int i = 0; i < entry->vars->len; i++) { - entry->vars->slugs[i]; - entry->vars->tokens[i]; - // printf("Slug name is: %s\n",entry->vars->slugs[i]); - // printf("Slug value is: %s\n",entry->vars->tokens[i]); - } - } - } - // free the objects at the end - match_entry_free(entry); - // } - entry = match_entry_create("/blog/aaa/asd/123/qwe"); - if (entry != NULL) { - entry->request_method = METHOD_GET; - matched_route = r3_tree_match_route(n, entry); - if (matched_route != NULL) { - // printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route - for (int i = 0; i < entry->vars->len; i++) { - // entry->vars->slugs[i]; - // entry->vars->tokens[i]; - printf("Slug name is: %s\n",entry->vars->slugs[i]); - printf("Slug value is: %s\n",entry->vars->tokens[i]); - } - } - } + int i; + for (int k = 0; k < 3000000; k++) { + // printf("round N%d\n",k); + entry = match_entry_create("/blog/432/asf/678"); + entry->request_method = METHOD_GET; + matched_route = r3_tree_match_route(n, entry); + // if (matched_route) { + // printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route + // if (entry->vars.tokens.size == entry->vars.slugs.size) { + // for (i = 0; i < entry->vars.tokens.size; i++) { + // // entry->vars.slugs.entries[i]; + // // entry->vars.tokens.entries[i]; + // printf("Slug name is: %*.*s\n",entry->vars.slugs.entries[i].len, + // entry->vars.slugs.entries[i].len, entry->vars.slugs.entries[i].base); + // printf("Slug value is: %*.*s\n",entry->vars.tokens.entries[i].len, + // entry->vars.tokens.entries[i].len, entry->vars.tokens.entries[i].base); + // } + // } else { + // // printf("Slugs and tokens sizes are not equal\n"); + // // for (i = 0; i < entry->vars.slugs.size; i++) { + // // printf("Slug name is: %*.*s\n",entry->vars.slugs.entries[i].len, + // // entry->vars.slugs.entries[i].len, entry->vars.slugs.entries[i].base); + // // } + // // for (i = 0; i < entry->vars.tokens.size; i++) { + // // printf("Slug value is: %*.*s\n",entry->vars.tokens.entries[i].len, + // // entry->vars.tokens.entries[i].len, entry->vars.tokens.entries[i].base); + // // } + // } + // } // free the objects at the end match_entry_free(entry); + } + // entry = match_entry_create("/blog/aaa/asd/123/qwe"); + // if (entry != NULL) { + // entry->request_method = METHOD_GET; + // matched_route = r3_tree_match_route(n, entry); + // if (matched_route != NULL) { + // // printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route + // for (int i = 0; i < entry->vars->len; i++) { + // // entry->vars->slugs[i]; + // // entry->vars->tokens[i]; + // printf("Slug name is: %s\n",entry->vars->slugs[i]); + // printf("Slug value is: %s\n",entry->vars->tokens[i]); + // } + // } + // } + // // free the objects at the end + // match_entry_free(entry); r3_tree_free(n); } diff --git a/include/r3.h b/include/r3.h index d7929c8..993decb 100644 --- a/include/r3.h +++ b/include/r3.h @@ -32,6 +32,7 @@ typedef unsigned char bool; #include "str_array.h" #include "r3_slug.h" +#include "memory.h" #ifdef __cplusplus @@ -46,83 +47,61 @@ typedef struct _node R3Node; typedef struct _R3Route R3Route; struct _node { - R3Edge ** edges; + R3_VECTOR(R3Edge) edges; + R3_VECTOR(R3Route) routes; char * combined_pattern; pcre * pcre_pattern; pcre_extra * pcre_extra; // edges are mostly less than 255 unsigned int compare_type; // compare_type: pcre, opcode, string - unsigned int edge_len; unsigned int endpoint; // endpoint, should be zero for non-endpoint nodes unsigned int ov_cnt; // capture vector array size for pcre - - R3Route ** routes; // the pointer of R3Route data void * data; // almost less than 255 - unsigned char edge_cap; - unsigned char route_len; - unsigned char route_cap; } __attribute__((aligned(64))); -#define r3_node_edge_pattern(node,i) node->edges[i]->pattern -#define r3_node_edge_pattern_len(node,i) node->edges[i]->pattern_len +#define r3_node_edge_pattern(node,i) node->edges.entries[i].pattern.base +#define r3_node_edge_pattern_len(node,i) node->edges.entries[i].pattern.len struct _edge { - char * pattern; // 8 bytes + r3_iovec_t pattern; // 8 bytes R3Node * child; // 8 bytes - unsigned int pattern_len; // 4byte + // unsigned int pattern_len; // 4byte unsigned int opcode; // 4byte unsigned int has_slug; // 4byte } __attribute__((aligned(64))); struct _R3Route { - char * path; - int path_len; - - char **slugs; - int slugs_len; - int slugs_cap; - - int request_method; // can be (GET || POST) - - char * host; // required host name - int host_len; + r3_iovec_t path; + R3_VECTOR(r3_iovec_t) slugs; + int request_method; // can be (GET || POST) + r3_iovec_t host; // required host name void * data; - char * remote_addr_pattern; - int remote_addr_pattern_len; + r3_iovec_t remote_addr_pattern; } __attribute__((aligned(64))); -typedef struct { - str_array * vars; - const char * path; // current path to dispatch - int path_len; // the length of the current path - int request_method; // current request method +typedef struct _R3Entry match_entry; +struct _R3Entry { + str_array vars; + r3_iovec_t path; // current path to dispatch + int request_method; // current request method void * data; // R3Route ptr - char * host; // the request host - int host_len; - - char * remote_addr; - int remote_addr_len; -} match_entry; - - - - - - + r3_iovec_t host; // the request host + r3_iovec_t remote_addr; +} __attribute__((aligned(64))); R3Node * r3_tree_create(int cap); -R3Node * r3_node_create(); +// R3Node * r3_node_create(); void r3_tree_free(R3Node * tree); @@ -130,15 +109,15 @@ R3Edge * r3_node_connectl(R3Node * n, const char * pat, int len, int strdup, R3N #define r3_node_connect(n, pat, child) r3_node_connectl(n, pat, strlen(pat), 0, child) -R3Edge * r3_node_find_edge(const R3Node * n, const char * pat, int pat_len); +R3Edge * r3_node_find_edge(const R3Node * n, const char * pat, unsigned int pat_len); -R3Edge * r3_node_append_edge(R3Node *n, R3Edge *child); +R3Edge * r3_node_append_edge(R3Node *n); R3Edge * r3_node_find_common_prefix(R3Node *n, const char *path, int path_len, int *prefix_len, char **errstr); R3Node * r3_tree_insert_pathl(R3Node *tree, const char *path, int path_len, void * data); -#define r3_tree_insert_pathl(tree, path, path_len, data) r3_tree_insert_pathl_ex(tree, path, path_len, NULL , data, NULL) +#define r3_tree_insert_pathl(tree, path, path_len, data) r3_tree_insert_pathl_ex(tree, path, path_len, 0, 0, data, NULL) @@ -148,7 +127,7 @@ R3Route * r3_tree_insert_routel_ex(R3Node * tree, int method, const char *path, #define r3_tree_insert_routel(n, method, path, path_len, data) r3_tree_insert_routel_ex(n, method, path, path_len, data, NULL) -#define r3_tree_insert_path(n,p,d) r3_tree_insert_pathl_ex(n,p,strlen(p), NULL, d, NULL) +#define r3_tree_insert_path(n,p,d) r3_tree_insert_pathl_ex(n,p,strlen(p), 0, 0, d, NULL) #define r3_tree_insert_route(n,method,path,data) r3_tree_insert_routel(n, method, path, strlen(path), data) @@ -156,7 +135,7 @@ R3Route * r3_tree_insert_routel_ex(R3Node * tree, int method, const char *path, /** * The private API to insert a path */ -R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R3Route * route, void * data, char ** errstr); +R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, unsigned int path_len, int method, unsigned int router, void * data, char **errstr); void r3_tree_dump(const R3Node * n, int level); @@ -168,16 +147,16 @@ int r3_tree_compile(R3Node *n, char** errstr); int r3_tree_compile_patterns(R3Node * n, char** errstr); -R3Node * r3_tree_matchl(const R3Node * n, const char * path, int path_len, match_entry * entry); +R3Node * r3_tree_matchl(const R3Node * n, const char * path, unsigned int path_len, match_entry * entry); #define r3_tree_match(n,p,e) r3_tree_matchl(n,p, strlen(p), e) // R3Node * r3_tree_match_entry(R3Node * n, match_entry * entry); -#define r3_tree_match_entry(n, entry) r3_tree_matchl(n, entry->path, entry->path_len, entry) +#define r3_tree_match_entry(n, entry) r3_tree_matchl(n, entry->path.base, entry->path.len, entry) bool r3_node_has_slug_edges(const R3Node *n); -R3Edge * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child); +// R3Edge * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child); void r3_edge_initl(R3Edge *e, const char * pattern, int pattern_len, R3Node * child); @@ -191,10 +170,10 @@ void r3_edge_free(R3Edge * edge); R3Route * r3_route_create(const char * path); -R3Route * r3_route_createl(const char * path, int path_len); +// R3Route * r3_route_createl(const char * path, int path_len); -void r3_node_append_route(R3Node * n, R3Route * route); +R3Route * r3_node_append_route(R3Node *tree, const char * path, int path_len, int method, void *data); void r3_route_free(R3Route * route); @@ -215,7 +194,7 @@ R3Route * r3_tree_match_route(const R3Node *n, match_entry * entry); -int r3_pattern_to_opcode(const char * pattern, int pattern_len); +int r3_pattern_to_opcode(const char * pattern, unsigned int len); enum { NODE_COMPARE_STR, NODE_COMPARE_PCRE, NODE_COMPARE_OPCODE }; diff --git a/include/r3.hpp b/include/r3.hpp index 38f9011..fcb9297 100644 --- a/include/r3.hpp +++ b/include/r3.hpp @@ -90,13 +90,13 @@ namespace r3 { } Node insert_path(const char* path, void* data, char** errstr = NULL) { - return r3_tree_insert_pathl_ex(get(), path, std::strlen(path), NULL, + return r3_tree_insert_pathl_ex(get(), path, std::strlen(path), 0, 0, data, errstr); } Node insert_pathl(const char* path, int path_len, void* data, char** errstr = NULL) { - return r3_tree_insert_pathl_ex(get(), path, path_len, NULL, data, + return r3_tree_insert_pathl_ex(get(), path, path_len, 0, 0, data, errstr); } diff --git a/include/r3_slug.h b/include/r3_slug.h index 0f1a8eb..76936ae 100644 --- a/include/r3_slug.h +++ b/include/r3_slug.h @@ -11,13 +11,13 @@ extern "C" { #endif -char * r3_slug_compile(const char * str, int len); +char * r3_slug_compile(const char * str, unsigned int len); -char * r3_slug_find_pattern(const char *s1, int *len); +char * r3_slug_find_pattern(const char *s1, unsigned int str_len, unsigned int *len); -char * r3_slug_find_name(const char *s1, int *len); +char * r3_slug_find_name(const char *s1, unsigned int str_len, unsigned int *len); -char * r3_slug_find_placeholder(const char *s1, int *len); +char * r3_slug_find_placeholder(const char *s1, unsigned int str_len, unsigned int *len); int r3_slug_count(const char * needle, int len, char **errstr); diff --git a/include/str_array.h b/include/str_array.h index f4490dd..0663317 100644 --- a/include/str_array.h +++ b/include/str_array.h @@ -8,25 +8,25 @@ #ifndef STR_ARRAY_H #define STR_ARRAY_H +#include "r3.h" +#include "memory.h" + typedef struct _str_array { - char **slugs; - int slugs_len; - char **tokens; - int len; - int cap; + R3_VECTOR(r3_iovec_t) slugs; + R3_VECTOR(r3_iovec_t) tokens; } str_array; -str_array * str_array_create(int cap); +// str_array * str_array_create(int cap); bool str_array_slugs_full(const str_array * l); -bool str_array_tokens_full(const str_array * l); +// bool str_array_tokens_full(const str_array * l); -bool str_array_resize(str_array *l, int new_cap); +// bool str_array_resize(str_array *l, int new_cap); -bool str_array_append_slug(str_array * l, char * slug); +// bool str_array_append_slug(str_array * l, char * slug); -bool str_array_append(str_array * list, char * token); +bool str_array_append(str_array * l, char * token, unsigned int len); void str_array_free(str_array *l); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7aa2935..6ea9dba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ include_directories("${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/3rdparty ${PROJECT_SOURCE_DIR}") # install(TARGETS swiftnav-static DESTINATION lib${LIB_SUFFIX}) find_package(PCRE REQUIRED) -set(libr3_SRCS node.c edge.c list.c slug.c str.c token.c match_entry.c) +set(libr3_SRCS node.c edge.c list.c slug.c str.c token.c match_entry.c memory.c) set(LIBS ${LIBS} ${PCRE_LIBRARIES} r3) add_library(r3 STATIC ${libr3_SRCS}) diff --git a/src/Makefile.am b/src/Makefile.am index 31a3aed..2c71cdb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,7 @@ MAYBE_COVERAGE=--coverage noinst_LTLIBRARIES = libr3core.la # lib_LIBRARIES = libr3.a -libr3core_la_SOURCES = node.c edge.c str.c token.c match_entry.c slug.c +libr3core_la_SOURCES = node.c edge.c str.c token.c match_entry.c slug.c memory.c if ENABLE_JSON libr3core_la_SOURCES += json.c diff --git a/src/edge.c b/src/edge.c index 466c154..666c595 100644 --- a/src/edge.c +++ b/src/edge.c @@ -27,24 +27,24 @@ void r3_edge_initl(R3Edge *e, const char * pattern, int pattern_len, R3Node * child) { - e->pattern = (char*) pattern; - e->pattern_len = pattern_len; - e->opcode = 0; + e->pattern.base = (char*) pattern; + e->pattern.len = (unsigned int)pattern_len; + // e->opcode = 0; e->child = child; - e->has_slug = r3_path_contains_slug_char(e->pattern); + e->has_slug = r3_path_contains_slug_char(e->pattern.base, e->pattern.len); } -R3Edge * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child) -{ - R3Edge * e = (R3Edge*) zmalloc( sizeof(R3Edge) ); - CHECK_PTR(e); - e->pattern = (char*) pattern; - e->pattern_len = pattern_len; - e->opcode = 0; - e->child = child; - e->has_slug = r3_path_contains_slug_char(e->pattern); - return e; -} +// R3Edge * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child) +// { +// R3Edge * e = (R3Edge*) zmalloc( sizeof(R3Edge) ); +// CHECK_PTR(e); +// e->pattern = (char*) pattern; +// e->pattern_len = pattern_len; +// e->opcode = 0; +// e->child = child; +// e->has_slug = r3_path_contains_slug_char(e->pattern); +// return e; +// } @@ -64,35 +64,28 @@ R3Node * r3_edge_branch(R3Edge *e, int dl) { R3Edge * new_edge; // the rest string - char * s1 = e->pattern + dl; - int s1_len = e->pattern_len - dl; + char * s1 = e->pattern.base + dl; + int s1_len = e->pattern.len - dl; // the suffix edge of the leaf new_child = r3_tree_create(3); - new_edge = r3_edge_createl(zstrndup(s1, s1_len), s1_len, new_child); - // Move child node to the new edge - new_edge->child = e->child; + new_edge = r3_node_append_edge(new_child); + r3_edge_initl(new_edge, s1, s1_len, e->child); e->child = new_child; - - r3_node_append_edge(new_child, new_edge); - + // truncate the original edge pattern - char *oldpattern = e->pattern; - e->pattern = zstrndup(e->pattern, dl); - e->pattern_len = dl; - zfree(oldpattern); + e->pattern.len = dl; return new_child; } void r3_edge_free(R3Edge * e) { if (e) { - zfree(e->pattern); if ( e->child ) { r3_tree_free(e->child); } // free itself - zfree(e); + // zfree(e); } } diff --git a/src/gvc.c b/src/gvc.c index 8bd7e21..f8f777b 100644 --- a/src/gvc.c +++ b/src/gvc.c @@ -16,8 +16,8 @@ void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node if (!n) return; - for ( int i = 0 ; i < n->edge_len ; i++ ) { - edge * e = n->edges[i]; + for ( int i = 0 ; i < n->edges.size ; i++ ) { + edge * e = n->edges.entries + i; (*node_cnt)++; Agnode_t *agn_child = NULL; diff --git a/src/json.c b/src/json.c index 18b72a2..046b959 100644 --- a/src/json.c +++ b/src/json.c @@ -13,15 +13,15 @@ json_object * r3_route_to_json_object(const R3Route * r) { json_object *obj; obj = json_object_new_object(); - json_object_object_add(obj, "path", json_object_new_string(r->path)); + json_object_object_add(obj, "path", json_object_new_string(r->path.base)); json_object_object_add(obj, "allowed_methods", json_object_new_int(r->request_method)); if (r->host) { - json_object_object_add(obj, "host", json_object_new_string(r->host)); + json_object_object_add(obj, "host", json_object_new_string(r->host.base)); } if (r->remote_addr_pattern) { - json_object_object_add(obj, "remote_addr_pattern", json_object_new_string(r->remote_addr_pattern)); + json_object_object_add(obj, "remote_addr_pattern", json_object_new_string(r->remote_addr_pattern.base)); } return obj; } @@ -31,7 +31,7 @@ json_object * r3_edge_to_json_object(const R3Edge * e) { json_object *obj; obj = json_object_new_object(); - json_object_object_add(obj, "pattern", json_object_new_string(e->pattern)); + json_object_object_add(obj, "pattern", json_object_new_string(e->pattern.base)); json_object_object_add(obj, "opcode", json_object_new_int(e->opcode)); json_object_object_add(obj, "slug", json_object_new_boolean(e->has_slug)); @@ -60,7 +60,7 @@ json_object * r3_node_to_json_object(const R3Node * n) { json_object *edges_array = json_object_new_array(); json_object_object_add(obj, "edges", edges_array); for (i = 0 ; i < n->edge_len ; i++ ) { - json_object *edge_json_obj = r3_edge_to_json_object(&n->edges[i]); + json_object *edge_json_obj = r3_edge_to_json_object(n->edges.entries + i); json_object_array_add(edges_array, edge_json_obj); } } @@ -69,7 +69,7 @@ json_object * r3_node_to_json_object(const R3Node * n) { json_object *routes_array = json_object_new_array(); json_object_object_add(obj, "routes", routes_array); for (i = 0; i < n->route_len; i++ ) { - json_object *route_json_obj = r3_route_to_json_object(n->routes[i]); + json_object *route_json_obj = r3_route_to_json_object(n->routes.entries + i); json_object_array_add(routes_array, route_json_obj); } } diff --git a/src/match_entry.c b/src/match_entry.c index 16c8f71..2e4cc61 100644 --- a/src/match_entry.c +++ b/src/match_entry.c @@ -16,20 +16,16 @@ #include "zmalloc.h" match_entry * match_entry_createl(const char * path, int path_len) { - match_entry * entry = zmalloc(sizeof(match_entry)); - if(!entry) - return NULL; - entry->vars = str_array_create(3); - entry->path = path; - entry->path_len = path_len; - entry->data = NULL; + match_entry * entry = r3_mem_alloc( sizeof(match_entry) ); + memset(entry, 0, sizeof(*entry)); + r3_vector_reserve(NULL, &entry->vars.tokens, 3); + entry->path.base = path; + entry->path.len = path_len; return entry; } void match_entry_free(match_entry * entry) { assert(entry); - if (entry->vars) { - str_array_free(entry->vars); - } - zfree(entry); + free(entry->vars.tokens.entries); + free(entry); } diff --git a/src/node.c b/src/node.c index 8bbbde7..1883019 100644 --- a/src/node.c +++ b/src/node.c @@ -53,40 +53,26 @@ static int strdiff(char * d1, char * d2) { * Create a node object */ R3Node * r3_tree_create(int cap) { - R3Node * n = (R3Node*) zmalloc( sizeof(R3Node) ); - CHECK_PTR(n); + R3Node * n = r3_mem_alloc( sizeof(R3Node) ); + memset(n, 0, sizeof(*n)); + + r3_vector_reserve(NULL, &n->edges, n->edges.size + cap); + + r3_vector_reserve(NULL, &n->routes, n->routes.size + 1); - n->edges = zmalloc(sizeof(R3Edge) * cap); - CHECK_PTR(n->edges); - n->edge_len = 0; - n->edge_cap = cap; - - n->routes = NULL; - n->route_len = 0; - n->route_cap = 0; - - n->endpoint = 0; - n->compare_type = NODE_COMPARE_STR; - n->combined_pattern = NULL; - n->pcre_pattern = NULL; - n->pcre_extra = NULL; - n->data = NULL; + n->compare_type = NODE_COMPARE_PCRE; return n; } void r3_tree_free(R3Node * tree) { - if (tree->edges) { - for (int j=0;jedge_len;j++) { - r3_edge_free(tree->edges[j]); - } - zfree(tree->edges); + for (int j=0;jedges.size;j++) { + r3_edge_free(tree->edges.entries + j); } - if (tree->routes) { - for (int k=0;kroute_len;k++) { - r3_route_free(tree->routes[k]); - } - zfree(tree->routes); + free(tree->edges.entries); + for (int k=0;kroutes.size;k++) { + r3_route_free(tree->routes.entries + k); } + free(tree->routes.entries); if (tree->pcre_pattern) { pcre_free(tree->pcre_pattern); } @@ -96,7 +82,7 @@ void r3_tree_free(R3Node * tree) { } #endif zfree(tree->combined_pattern); - zfree(tree); + free(tree); tree = NULL; } @@ -108,38 +94,26 @@ void r3_tree_free(R3Node * tree) { R3Edge * r3_node_connectl(R3Node * n, const char * pat, int len, int dupl, R3Node *child) { // find the same sub-pattern, if it does not exist, create one R3Edge * e; - e = r3_node_find_edge(n, pat, len); if (e) { return e; } - if (dupl) { pat = zstrndup(pat, len); } - e = r3_edge_createl(pat, len, child); - CHECK_PTR(e); - R3Edge * e2 = r3_node_append_edge(n, e); - return e2; + // e = r3_edge_createl(pat, len, child); + e = r3_node_append_edge(n); + r3_edge_initl(e, pat, len, child); + // CHECK_PTR(e); + return e; } -R3Edge * r3_node_append_edge(R3Node *n, R3Edge *e) +R3Edge * r3_node_append_edge(R3Node *n) { - if (n->edges == NULL) { - n->edge_cap = 3; - n->edges = zmalloc(sizeof(R3Edge) * n->edge_cap); - } - if (n->edge_len >= n->edge_cap) { - n->edge_cap *= 2; - R3Edge * p = zrealloc(n->edges, sizeof(R3Edge) * n->edge_cap); - if(p) { - n->edges = p; - } - } - - // Insert edge into edge array - n->edges[n->edge_len] = e; - return n->edges[n->edge_len++]; + r3_vector_reserve(NULL, &n->edges, n->edges.size + 1); + R3Edge *new_e = n->edges.entries + n->edges.size++; + memset(new_e, 0, sizeof(*new_e)); + return new_e; } @@ -148,14 +122,16 @@ R3Edge * r3_node_append_edge(R3Node *n, R3Edge *e) * * if "pat" is a slug, we should compare with the specified pattern. */ -R3Edge * r3_node_find_edge(const R3Node * n, const char * pat, int pat_len) { - R3Edge * e; - int i; - for (i = 0 ; i < n->edge_len ; i++ ) { - e = n->edges[i]; +R3Edge * r3_node_find_edge(const R3Node * n, const char * pat, unsigned int pat_len) { + R3Edge *edge_entries = n->edges.entries; + R3Edge *e; + unsigned int i; + for (i = 0 ; i < n->edges.size ; i++ ) { + e = edge_entries + i; // there is a case: "{foo}" vs "{foo:xxx}", // we should return the match result: full-match or partial-match - if (strcmp(e->pattern, pat) == 0) { + if (e->pattern.len == pat_len && + !strncmp(e->pattern.base, pat, e->pattern.len)) { return e; } } @@ -164,11 +140,11 @@ R3Edge * r3_node_find_edge(const R3Node * n, const char * pat, int pat_len) { int r3_tree_compile(R3Node *n, char **errstr) { - int i; + unsigned int i; int ret = 0; - bool use_slug = r3_node_has_slug_edges(n); - if ( use_slug ) { - if ( (ret = r3_tree_compile_patterns(n, errstr)) ) { + // bool use_slug = r3_node_has_slug_edges(n); + if ( r3_node_has_slug_edges(n) ) { + if ( ret = r3_tree_compile_patterns(n, errstr) ) { return ret; } } else { @@ -176,8 +152,8 @@ int r3_tree_compile(R3Node *n, char **errstr) n->combined_pattern = NULL; } - for (i = 0 ; i < n->edge_len ; i++ ) { - if ((ret = r3_tree_compile(n->edges[i]->child, errstr))) { + for (i = 0 ; i < n->edges.size ; i++ ) { + if ((ret = r3_tree_compile(n->edges.entries[i].child, errstr))) { return ret; // stop here if error occurs } } @@ -192,7 +168,7 @@ int r3_tree_compile(R3Node *n, char **errstr) * Return 0 if success */ int r3_tree_compile_patterns(R3Node * n, char **errstr) { - R3Edge *e = NULL; + R3Edge *e; char * p; char * cpat = zcalloc(sizeof(char) * 64 * 3); // XXX if (!cpat) { @@ -202,29 +178,31 @@ int r3_tree_compile_patterns(R3Node * n, char **errstr) { p = cpat; int opcode_cnt = 0; - int i = 0; - for (; i < n->edge_len ; i++) { - e = n->edges[i]; + unsigned int i = 0; + for (; i < n->edges.size ; i++) { + e = n->edges.entries + i; if (e->opcode) { opcode_cnt++; } if (e->has_slug) { // compile "foo/{slug}" to "foo/[^/]+" - char * slug_pat = r3_slug_compile(e->pattern, e->pattern_len); + char * slug_pat = r3_slug_compile(e->pattern.base, e->pattern.len); + info("slug_pat for pattern: %s\n",slug_pat); strcat(p, slug_pat); zfree(slug_pat); + info("temp pattern: %s\n",cpat); } else { strncat(p,"^(", 2); p += 2; - strncat(p, e->pattern, e->pattern_len); - p += e->pattern_len; + strncat(p, e->pattern.base, e->pattern.len); + p += e->pattern.len; strncat(p++,")", 1); } - if ( i + 1 < n->edge_len && n->edge_len > 1 ) { + if ( i + 1 < n->edges.size && n->edges.size > 1 ) { strncat(p++,"|",1); } } @@ -232,12 +210,13 @@ int r3_tree_compile_patterns(R3Node * n, char **errstr) { info("pattern: %s\n",cpat); // if all edges use opcode, we should skip the combined_pattern. - if ( opcode_cnt == n->edge_len ) { + if ( opcode_cnt == n->edges.size ) { // zfree(cpat); n->compare_type = NODE_COMPARE_OPCODE; } else { n->compare_type = NODE_COMPARE_PCRE; } + info("COMPARE_TYPE: %d\n",n->compare_type); n->combined_pattern = cpat; @@ -245,7 +224,7 @@ int r3_tree_compile_patterns(R3Node * n, char **errstr) { int pcre_erroffset; unsigned int option_bits = 0; - n->ov_cnt = (1 + n->edge_len) * 3; + n->ov_cnt = (1 + n->edges.size) * 3; if (n->pcre_pattern) { pcre_free(n->pcre_pattern); @@ -267,7 +246,7 @@ int r3_tree_compile_patterns(R3Node * n, char **errstr) { pcre_free_study(n->pcre_extra); } n->pcre_extra = pcre_study(n->pcre_pattern, 0, &pcre_error); - if (n->pcre_extra == NULL) { + if (!n->pcre_extra) { if (errstr) { asprintf(errstr, "PCRE study failed at offset %s, pattern: %s", pcre_error, n->combined_pattern); } @@ -291,7 +270,7 @@ int r3_tree_compile_patterns(R3Node * n, char **errstr) { * @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. */ -R3Node * r3_tree_matchl(const R3Node * n, const char * path, int path_len, match_entry * entry) { +R3Node * r3_tree_matchl(const R3Node * n, const char * path, unsigned int path_len, match_entry * entry) { info("try matching: %s\n", path); R3Edge *e; @@ -301,12 +280,17 @@ R3Node * r3_tree_matchl(const R3Node * n, const char * path, int path_len, match const char *pp; const char *pp_end; + info("n->compare_type: %d\n",n->compare_type); + info("n->pcre_pattern: %s\n",n->pcre_pattern); + if (n->compare_type == NODE_COMPARE_OPCODE) { + info("NODE_COMPARE_OPCODE\n"); pp_end = path + path_len; - for (i = n->edge_len; i--; ) { + e = n->edges.entries; + unsigned int cies = n->edges.size; + for (i = 0; i < cies; i++) { pp = path; - e = n->edges[i]; switch(e->opcode) { case OP_EXPECT_NOSLASH: while (*pp != '/' && pp < pp_end) pp++; @@ -327,21 +311,23 @@ R3Node * r3_tree_matchl(const R3Node * n, const char * path, int path_len, match // check match if ((pp - path) > 0) { if (entry) { - str_array_append(entry->vars , zstrndup(path, pp - path)); + str_array_append(&entry->vars , path, pp - path); } restlen = pp_end - pp; - if (restlen == 0) { - return e->child && e->child->endpoint > 0 ? e->child : NULL; + if (!restlen) { + return e->child && e->child->endpoint ? e->child : NULL; } return r3_tree_matchl(e->child, pp, restlen, entry); } + e++; } } // if the pcre_pattern is found, and the pointer is not NULL, then it's // pcre pattern node, we use pcre_exec to match the nodes if (n->pcre_pattern) { - const char *substring_start = NULL; + info("COMPARE PCRE_PATTERN\n"); + const char *substring_start = 0; int substring_length = 0; int ov[ n->ov_cnt ]; int rc; @@ -380,47 +366,51 @@ R3Node * r3_tree_matchl(const R3Node * n, const char * path, int path_len, match restlen = path_len - ov[1]; // if it's fully matched to the end (rest string length) - - if (restlen == 0 ) { + int *inv = ov + 2; + if (!restlen) { // Check the substring to decide we should go deeper on which edge for (i = 1; i < rc; i++) { - substring_length = ov[2*i+1] - ov[2*i]; + substring_length = *(inv+1) - *inv; // if it's not matched for this edge, just skip them quickly - if (substring_length == 0) + if ( !substring_length ) { + inv += 2; continue; + } - substring_start = path + ov[2*i]; - e = n->edges[i - 1]; + substring_start = path + *inv; + e = n->edges.entries + i - 1; if (entry && e->has_slug) { // append captured token to entry - str_array_append(entry->vars , zstrndup(substring_start, substring_length)); + str_array_append(&entry->vars, substring_start, substring_length); } // since restlen == 0 return the edge quickly. - return e->child && e->child->endpoint > 0 ? e->child : NULL; + return e->child && e->child->endpoint ? e->child : NULL; } } // Check the substring to decide we should go deeper on which edge + inv = ov + 2; for (i = 1; i < rc; i++) { - substring_length = ov[2*i+1] - ov[2*i]; + substring_length = *(inv+1) - *inv; // if it's not matched for this edge, just skip them quickly - if ( substring_length == 0) { + if ( !substring_length ) { + inv += 2; continue; } - substring_start = path + ov[2*i]; - e = n->edges[i - 1]; + substring_start = path + *inv; + e = n->edges.entries + i - 1; if (entry && e->has_slug) { // append captured token to entry - str_array_append(entry->vars , zstrndup(substring_start, substring_length)); + str_array_append(&entry->vars , substring_start, substring_length); } // get the length of orginal string: $0 @@ -430,12 +420,14 @@ R3Node * r3_tree_matchl(const R3Node * n, const char * path, int path_len, match return NULL; } - if ((e = r3_node_find_edge_str(n, path, path_len)) != NULL) { - restlen = path_len - e->pattern_len; - if (restlen == 0) { - return e->child && e->child->endpoint > 0 ? e->child : NULL; + info("COMPARE COMPARE_STR\n"); + + if (e = r3_node_find_edge_str(n, path, path_len)) { + restlen = path_len - e->pattern.len; + if (!restlen) { + return e->child && e->child->endpoint ? e->child : NULL; } - return r3_tree_matchl(e->child, path + e->pattern_len, restlen, entry); + return r3_tree_matchl(e->child, path + e->pattern.len, restlen, entry); } return NULL; } @@ -444,120 +436,115 @@ R3Node * r3_tree_matchl(const R3Node * n, const char * path, int path_len, match R3Route * r3_tree_match_route(const R3Node *tree, match_entry * entry) { R3Node *n; - int i; + R3Route *r; n = r3_tree_match_entry(tree, entry); - if (n && n->routes && n->route_len > 0) { - for (i = n->route_len; i--; ) { - if ( r3_route_cmp(n->routes[i], entry) == 0 ) { + unsigned int i, irs = n->routes.size; + if (n && irs) { + r = n->routes.entries; + for (i = 0; irs - i; i++) { + if ( r3_route_cmp(r, entry) == 0 ) { // Add slugs from found route to match_entry - entry->vars->slugs = n->routes[i]->slugs; - return n->routes[i]; + entry->vars.slugs.entries = r->slugs.entries; + entry->vars.slugs.size = r->slugs.size; + return r; } + r++; } } return NULL; } inline R3Edge * r3_node_find_edge_str(const R3Node * n, const char * str, int str_len) { - R3Edge * e; - unsigned int i; - char firstbyte = *str; - for (i = n->edge_len; i--; ) { - e = n->edges[i]; - if (firstbyte == e->pattern[0]) { - if (strncmp(e->pattern, str, e->pattern_len) == 0) { - return n->edges[i]; + R3Edge *e; + unsigned int i, cst = *str; + e = n->edges.entries; + unsigned int ies = n->edges.size; + for (i = 0; ies - i; i++ ) { + if (cst == *e->pattern.base) { + if (!strncmp(e->pattern.base, str, e->pattern.len)) { + return e; } return NULL; } + e++; } return NULL; } -R3Node * r3_node_create() { - R3Node * n = (R3Node*) zmalloc( sizeof(R3Node) ); - CHECK_PTR(n); - n->edges = NULL; - n->edge_len = 0; - n->edge_cap = 0; +// R3Node * r3_node_create() { +// R3Node * n = (R3Node*) zmalloc( sizeof(R3Node) ); +// CHECK_PTR(n); +// n->edges = NULL; +// n->edge_len = 0; +// n->edge_cap = 0; - n->routes = NULL; - n->route_len = 0; - n->route_cap = 0; +// n->routes = NULL; +// n->route_len = 0; +// n->route_cap = 0; - n->endpoint = 0; - n->combined_pattern = NULL; - n->pcre_pattern = NULL; - n->pcre_extra = NULL; - n->data = NULL; - return n; -} +// n->endpoint = 0; +// n->combined_pattern = NULL; +// n->pcre_pattern = NULL; +// n->pcre_extra = NULL; +// n->data = NULL; +// return n; +// } void r3_route_free(R3Route * route) { assert(route); - for ( int i = 0; i < route->slugs_len ; i++ ) { - if (route->slugs[ i ]) { - zfree(route->slugs[i]); - } - } - zfree(route->slugs); - zfree(route); + free(route->slugs.entries); } -static bool router_slugs_full(const R3Route * route) { - return route->slugs_len >= route->slugs_cap; +// static bool router_slugs_full(const R3Route * route) { +// return route->slugs_len >= route->slugs_cap; +// } + +// static bool router_slugs_resize(R3Route * route, int new_cap) { +// route->slugs = zrealloc(route->slugs, sizeof(char**) * new_cap); +// route->slugs_cap = new_cap; +// return route->slugs != NULL; +// } + +static r3_iovec_t* router_append_slug(R3Route * route, char * slug, unsigned int len) { + r3_iovec_t *temp; + r3_vector_reserve(NULL, &route->slugs, route->slugs.size + 1); + temp = route->slugs.entries + route->slugs.size++; + temp->base = slug; + temp->len = len; + return temp; } -static bool router_slugs_resize(R3Route * route, int new_cap) { - route->slugs = zrealloc(route->slugs, sizeof(char**) * new_cap); - route->slugs_cap = new_cap; - return route->slugs != NULL; -} - -static bool router_append_slug(R3Route * route, char * slug) { - if ( router_slugs_full(route) ) { - bool ret = router_slugs_resize(route, route->slugs_cap + 20); - if (ret == false ) { - return false; - } - } - route->slugs[ route->slugs_len++ ] = slug; - return true; -} - -static void get_slugs(const char * path, int path_len, R3Route * route) { - char *plh = path; - int l = 0; - int namel; +static void get_slugs(R3Route * route, const char * path, int path_len) { + char *plh = (char*)path; + unsigned int l, namel; + l = 0; char *name; - while(1) { - plh = r3_slug_find_placeholder(plh+l,&l); - if (plh == NULL) break; + while (plh < (path + path_len)) { + plh = r3_slug_find_placeholder(plh+l, path_len, &l); + if (!plh) break; namel = 0; - name = r3_slug_find_name(plh,&namel); - router_append_slug(route,zstrndup(name,namel)); + name = r3_slug_find_name(plh, l, &namel); + if (name) { + router_append_slug(route, name, namel); + } if ((plh + l) >= (path + path_len)) break; } } -R3Route * r3_route_createl(const char * path, int path_len) { - R3Route * info = zmalloc(sizeof(R3Route)); - CHECK_PTR(info); - info->slugs_cap = 3; - info->slugs_len = 0; - info->slugs = (char**) zmalloc( sizeof(char*) * info->slugs_cap); - get_slugs(path, path_len, info); - info->path = (char*) path; - info->path_len = path_len; - info->request_method = 0; // can be (GET || POST) +R3Route * r3_node_append_route(R3Node *tree, const char * path, int path_len, int method, void *data) { + r3_vector_reserve(NULL, &tree->routes, tree->routes.size + 1); + R3Route *info = tree->routes.entries + tree->routes.size++; + memset(info, 0, sizeof(*info)); - info->data = NULL; + r3_vector_reserve(NULL, &info->slugs, info->slugs.size + 3); + info->path.base = (char*) path; + info->path.len = path_len; + info->request_method = method; // ALLOW GET OR POST METHOD + info("\tinfo router path is: %s, with len: %d\n", path, path_len); + info("\troutes size is: %d\n", tree->routes.size); - info->host = NULL; // required host name - info->host_len = 0; + info->data = data; - info->remote_addr_pattern = NULL; - info->remote_addr_pattern_len = 0; return info; } @@ -568,16 +555,11 @@ R3Route * r3_route_createl(const char * path, int path_len) { * method (int): METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE ... */ R3Route * r3_tree_insert_routel_ex(R3Node *tree, int method, const char *path, int path_len, void *data, char **errstr) { - R3Route *r = r3_route_createl(path, path_len); - CHECK_PTR(r); - r->request_method = method; // ALLOW GET OR POST METHOD - R3Node * ret = r3_tree_insert_pathl_ex(tree, path, path_len, r, data, errstr); - if (!ret) { - // failed insert - r3_route_free(r); - return NULL; - } - return r; + R3Node * ret = r3_tree_insert_pathl_ex(tree, path, path_len, method, 1, data, errstr); + R3Route *router = ret->routes.entries + (ret->routes.size - 1); + get_slugs(router, path, path_len); + + return router; } @@ -595,17 +577,17 @@ R3Route * r3_tree_insert_routel_ex(R3Node *tree, int method, const char *path, i * 5. "/foo/{slug}/hate" vs "/fo{slug}/bar" => common prefix = "/fo" */ R3Edge * r3_node_find_common_prefix(R3Node *n, const char *path, int path_len, int *prefix_len, char **errstr) { - int i = 0; + unsigned int i = 0; int prefix = 0; *prefix_len = 0; R3Edge *e = NULL; - for(i = 0 ; i < n->edge_len ; i++ ) { + for(i = 0 ; i < n->edges.size ; i++ ) { // ignore all edges with slug - prefix = strndiff( (char*) path, n->edges[i]->pattern, n->edges[i]->pattern_len); + prefix = strndiff( (char*) path, n->edges.entries[i].pattern.base, n->edges.entries[i].pattern.len); // no common, consider insert a new edge if ( prefix > 0 ) { - e = n->edges[i]; + e = n->edges.entries + i; break; } } @@ -658,7 +640,7 @@ R3Edge * r3_node_find_common_prefix(R3Node *n, const char *path, int path_len, i /** * Return the last inserted node. */ -R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R3Route * route, void * data, char **errstr) +R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, unsigned int path_len, int method, unsigned int router, void * data, char **errstr) { R3Node * n = tree; @@ -669,9 +651,9 @@ R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R // point on the node and append the route. if (path_len == 0) { tree->endpoint++; - if (route) { - route->data = data; - r3_node_append_route(tree, route); + if (router) { + r3_node_append_route(tree, path, path_len, method, data); + info("tree router path is: %s, with len: %d\n", path, path_len); } return tree; } @@ -690,16 +672,16 @@ R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R const int subpath_len = path_len - prefix_len; // common prefix not found, insert a new edge for this pattern - if ( prefix_len == 0 ) { + if ( !prefix_len ) { // there are two more slugs, we should break them into several parts int slug_cnt = r3_slug_count(path, path_len, errstr); if (slug_cnt == -1) { return NULL; } - + info("slug_cnt: %d\n",slug_cnt); if ( slug_cnt > 1 ) { - int slug_len; - char *p = r3_slug_find_placeholder(path, &slug_len); + unsigned int slug_len; + char *p = r3_slug_find_placeholder(path, path_len, &slug_len); #ifdef DEBUG assert(p); @@ -707,7 +689,7 @@ R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R // find the next one '{', then break there if(p) { - p = r3_slug_find_placeholder(p + slug_len + 1, NULL); + p = r3_slug_find_placeholder(p + slug_len + 1, path_len - slug_len - 1, NULL); } #ifdef DEBUG assert(p); @@ -715,26 +697,27 @@ R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R // insert the first one edge, and break at "p" R3Node * child = r3_tree_create(3); - CHECK_PTR(child); - - r3_node_connectl(n, path, p - path, 1, child); // duplicate + unsigned int paln = p - path; + r3_node_connectl(n, path, p - path, 0, child); // no duplicate // and insert the rest part to the child - return r3_tree_insert_pathl_ex(child, p, path_len - (int)(p - path), route, data, errstr); + return r3_tree_insert_pathl_ex(child, p, path_len - (int)(p - path), method, 1, data, errstr); } else { if (slug_cnt == 1) { // there is one slug, let's see if it's optimiz-able by opcode - int slug_len = 0; - char *slug_p = r3_slug_find_placeholder(path, &slug_len); - int slug_pattern_len = 0; - char *slug_pattern = r3_slug_find_pattern(slug_p, &slug_pattern_len); + unsigned int slug_len = 0; + char *slug_p = r3_slug_find_placeholder(path, path_len, &slug_len); + unsigned int slug_pattern_len = 0; + char *slug_pattern = r3_slug_find_pattern(slug_p, slug_len, &slug_pattern_len); int opcode = 0; // if there is a pattern defined. if (slug_pattern_len) { char *cpattern = r3_slug_compile(slug_pattern, slug_pattern_len); + info("cpattern: %s\n", cpattern); opcode = r3_pattern_to_opcode(cpattern, strlen(cpattern)); + info("opcode: %d\n", opcode); zfree(cpattern); } else { opcode = OP_EXPECT_NOSLASH; @@ -745,16 +728,14 @@ R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R R3Node *c1; if (slug_p > path) { c1 = r3_tree_create(3); - CHECK_PTR(c1); - r3_node_connectl(n, path, slug_p - path, 1, c1); // duplicate + r3_node_connectl(n, path, slug_p - path, 0, c1); // no duplicate } else { c1 = n; } R3Node * c2 = r3_tree_create(3); - CHECK_PTR(c2); - - R3Edge * op_edge = r3_node_connectl(c1, slug_p, slug_len , 1, c2); + + R3Edge * op_edge = r3_node_connectl(c1, slug_p, slug_len , 0, c2); if(opcode) { op_edge->opcode = opcode; } @@ -762,45 +743,46 @@ R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R int restlen = path_len - ((slug_p - path) + slug_len); if (restlen) { - return r3_tree_insert_pathl_ex(c2, slug_p + slug_len, restlen, route, data, errstr); + return r3_tree_insert_pathl_ex(c2, slug_p + slug_len, restlen, method, 1, data, errstr); } c2->data = data; c2->endpoint++; - if (route) { - route->data = data; - r3_node_append_route(c2, route); + if (router) { + // route->data = data; + r3_node_append_route(c2, path, path_len, method, data); + info("c2 router path is: %s, with len: %d\n", path, path_len); } return c2; } // only one slug R3Node * child = r3_tree_create(3); - CHECK_PTR(child); child->endpoint++; if (data) child->data = data; - r3_node_connectl(n, path, path_len, 1, child); - if (route) { - route->data = data; - r3_node_append_route(child, route); + r3_node_connectl(n, path, path_len, 0, child); + if (router) { + r3_node_append_route(child, path, path_len, method, data); + info("child router path is: %s, with len: %d\n", path, path_len); } return child; } - } else if ( prefix_len == e->pattern_len ) { // fully-equal to the pattern of the edge + } else if ( prefix_len == e->pattern.len ) { // fully-equal to the pattern of the edge // there are something more we can insert if ( subpath_len > 0 ) { - return r3_tree_insert_pathl_ex(e->child, subpath, subpath_len, route, data, errstr); + return r3_tree_insert_pathl_ex(e->child, subpath, subpath_len, method, 1, data, errstr); } else { // there are no more path to insert // see if there is an endpoint already, we should n't overwrite the data on child. // but we still need to append the route. - if (route) { - route->data = data; - r3_node_append_route(e->child, route); + if (router) { + // route->data = data; + r3_node_append_route(e->child, path, path_len, method, data); + info("e->child router path is: %s, with len: %d\n", path, path_len); e->child->endpoint++; // make it as an endpoint return e->child; } @@ -815,12 +797,12 @@ R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R return e->child; } - } else if ( prefix_len < e->pattern_len ) { + } else if ( prefix_len < e->pattern.len ) { /* it's partially matched with the pattern, * we should split the end point and make a branch here... */ r3_edge_branch(e, prefix_len); - return r3_tree_insert_pathl_ex(e->child, subpath, subpath_len, route , data, errstr); + return r3_tree_insert_pathl_ex(e->child, subpath, subpath_len, method, 1, data, errstr); } else { fprintf(stderr, "unexpected route."); return NULL; @@ -830,10 +812,12 @@ R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R bool r3_node_has_slug_edges(const R3Node *n) { bool found = false; + R3Edge *edge_entries = n->edges.entries; R3Edge *e; - for ( int i = 0 ; i < n->edge_len ; i++ ) { - e = n->edges[i]; - e->has_slug = r3_path_contains_slug_char(e->pattern); + unsigned int i; + for ( i = 0 ; i < n->edges.size ; i++ ) { + e = edge_entries + i; + e->has_slug = r3_path_contains_slug_char(e->pattern.base, e->pattern.len); if (e->has_slug) found = true; } @@ -847,6 +831,8 @@ void r3_tree_dump(const R3Node * n, int level) { printf("(o)"); + printf(" compare_type:%d", n->compare_type); + if ( n->combined_pattern ) { printf(" regexp:%s", n->combined_pattern); } @@ -858,14 +844,24 @@ void r3_tree_dump(const R3Node * n, int level) { } printf("\n"); - for ( int i = 0 ; i < n->edge_len ; i++ ) { - R3Edge * e = n->edges[i]; + for ( int i = 0 ; i < n->edges.size ; i++ ) { + R3Edge * e = n->edges.entries + i; print_indent(level + 1); - printf("|-\"%s\"", e->pattern); + printf("|-\"%*.*s\"", e->pattern.len, e->pattern.len, e->pattern.base); if (e->opcode ) { printf(" opcode:%d", e->opcode); } + printf("\n"); + + print_indent(level + 1); + printf("||-routes num: |%d|", n->routes.size); + + for ( int j = 0 ; j < n->routes.size ; j++ ) { + R3Route * rr = n->routes.entries + j; + printf(" route path: |%*.*s|", rr->path.len,rr->path.len,rr->path.base); + } + printf("\n"); if ( e->child ) { printf("\n"); @@ -882,26 +878,26 @@ void r3_tree_dump(const R3Node * n, int level) { * -1 == different route */ inline int r3_route_cmp(const R3Route *r1, const match_entry *r2) { - if (r1->request_method != 0) { + if (r1->request_method && r2->request_method) { if (0 == (r1->request_method & r2->request_method) ) { return -1; } } - if ( r1->host && r2->host ) { - if (strcmp(r1->host, r2->host) != 0 ) { + if ( r1->host.len && r2->host.len ) { + if (strncmp(r1->host.base, r2->host.base, r2->host.len)) { return -1; } } - if (r1->remote_addr_pattern) { + if (r1->remote_addr_pattern.len && r2->remote_addr.len) { /* * XXX: consider "netinet/in.h" if (r2->remote_addr) { inet_addr(r2->remote_addr); } */ - if ( strcmp(r1->remote_addr_pattern, r2->remote_addr) != 0 ) { + if ( strncmp(r1->remote_addr_pattern.base, r2->remote_addr.base, r2->remote_addr.len) ) { return -1; } } @@ -912,16 +908,20 @@ inline int r3_route_cmp(const R3Route *r1, const match_entry *r2) { /** * */ -void r3_node_append_route(R3Node * n, R3Route * r) { - if (n->routes == NULL) { - n->route_cap = 3; - n->routes = zmalloc(sizeof(R3Route) * n->route_cap); - } - if (n->route_len >= n->route_cap) { - n->route_cap *= 2; - n->routes = zrealloc(n->routes, sizeof(R3Route) * n->route_cap); - } - n->routes[ n->route_len++ ] = r; -} +// void r3_node_append_route(R3Node * n, R3Route * r) +// { +// r3_vector_reserve(NULL, &n->routes, n->routes.size + 1); +// memset(n->routes.entries + 1, 0, sizeof(*n->routes.entries)); + +// if (n->routes == NULL) { +// n->route_cap = 3; +// n->routes = zmalloc(sizeof(R3Route) * n->route_cap); +// } +// if (n->route_len >= n->route_cap) { +// n->route_cap *= 2; +// n->routes = zrealloc(n->routes, sizeof(R3Route) * n->route_cap); +// } +// n->routes[ n->route_len++ ] = r; +// } diff --git a/src/slug.c b/src/slug.c index 19a6401..d7bba28 100644 --- a/src/slug.c +++ b/src/slug.c @@ -86,7 +86,7 @@ int r3_slug_parse(r3_slug_t *s, const char *needle, int needle_len, const char * } // there is no slug - if (!r3_path_contains_slug_char(offset)) { + if (!r3_path_contains_slug_char(offset, needle_len)) { return 0; } diff --git a/src/slug.h b/src/slug.h index fefafe7..4a66682 100644 --- a/src/slug.h +++ b/src/slug.h @@ -49,8 +49,11 @@ char * r3_slug_to_str(const r3_slug_t *s); void r3_slug_free(r3_slug_t * s); -static inline int r3_path_contains_slug_char(const char * str) { - return strchr(str, '{') != NULL ? 1 : 0; +static inline int r3_path_contains_slug_char(const char *str, unsigned int len) { + for (unsigned int i = 0; i < len; i++) { + if (str[i] == '{') return 1; + } + return 0; } #endif /* !SLUG_H */ diff --git a/src/str.c b/src/str.c index 435c376..aca5015 100644 --- a/src/str.c +++ b/src/str.c @@ -15,7 +15,14 @@ #include "slug.h" #include "zmalloc.h" -int r3_pattern_to_opcode(const char * pattern, int len) { +static char * strnchr(const char* str, unsigned int len, int ch) { + for (unsigned int i = 0; i < len; i++) { + if (str[i] == ch) return str + i; + } + return NULL; +} + +int r3_pattern_to_opcode(const char * pattern, unsigned int len) { if ( strncmp(pattern, "\\w+",len) == 0 ) { return OP_EXPECT_MORE_WORDS; } @@ -79,14 +86,15 @@ char * r3_inside_slug(const char * needle, int needle_len, char *offset, char ** return NULL; } -char * r3_slug_find_placeholder(const char *s1, int *len) { +char * r3_slug_find_placeholder(const char *s1, unsigned int str_len, unsigned int *len) { char *c; char *s2; int cnt = 0; - if ( NULL != (c = strchr(s1, '{')) ) { + if (c = strnchr(s1, str_len, '{')) { // find closing '}' s2 = c; - while(*s2) { + unsigned int j = str_len - (c - s1); + for (unsigned int i = 0; i < j; i++) { if (*s2 == '{' ) cnt++; else if (*s2 == '}' ) @@ -111,15 +119,16 @@ char * r3_slug_find_placeholder(const char *s1, int *len) { /** * given a slug string, duplicate the pattern string of the slug */ -char * r3_slug_find_pattern(const char *s1, int *len) { +char * r3_slug_find_pattern(const char *s1, unsigned int str_len, unsigned int *len) { char *c; char *s2; - int cnt = 1; - if ( NULL != (c = strchr(s1, ':')) ) { + unsigned int cnt = 1; + if ( (c = strnchr(s1, str_len, ':')) ) { c++; // find closing '}' s2 = c; - while(s2) { + unsigned int j = str_len - (c - s1); + for (unsigned int i = 0; i < j; i++) { if (*s2 == '{' ) cnt++; else if (*s2 == '}' ) @@ -132,6 +141,9 @@ char * r3_slug_find_pattern(const char *s1, int *len) { } else { return NULL; } + if (cnt!=0) { + return NULL; + } *len = s2 - c; return c; } @@ -140,38 +152,30 @@ char * r3_slug_find_pattern(const char *s1, int *len) { /** * given a slug string, duplicate the parameter name string of the slug */ -char * r3_slug_find_name(const char *s1, int *len) { +char * r3_slug_find_name(const char *s1, unsigned int str_len, unsigned int *len) { char * c; char * s2; int cnt = 0; - c = (char*) s1; - - while(1) { - if(*c == '{') cnt++; - if(*c == '}') cnt--; - if(*c == ':') break; - if(*c == '\0') return NULL; - if(cnt == 0) break; - c++; + unsigned int plholder; + if (c = r3_slug_find_placeholder(s1, str_len, &plholder)) { + c++; + if ( s2 = strnchr(c, plholder, ':') ) { + *len = s2 - c; + return c; + } else { + *len = plholder - 2; + return c; + } + } else { + return NULL; } - - // find starting '{' - s2 = c; - while(1) { - if ( *s2 == '{' ) - break; - s2--; - } - s2++; - *len = c - s2; - return s2; } /** * @param char * sep separator */ -char * r3_slug_compile(const char * str, int len) +char * r3_slug_compile(const char * str, unsigned int len) { char *s1 = NULL, *o = NULL; char *pat = NULL; @@ -179,15 +183,15 @@ char * r3_slug_compile(const char * str, int len) // append prefix - int s1_len; - s1 = r3_slug_find_placeholder(str, &s1_len); + unsigned int s1_len; + s1 = r3_slug_find_placeholder(str, len, &s1_len); - if ( s1 == NULL ) { - return zstrdup(str); + if ( !s1 ) { + return zstrndup(str,len); } char * out = NULL; - if ((out = zcalloc(sizeof(char) * 200)) == NULL) { + if (!(out = zcalloc(sizeof(char) * 200))) { return (NULL); } @@ -199,8 +203,8 @@ char * r3_slug_compile(const char * str, int len) o += (s1 - str); - int pat_len; - pat = r3_slug_find_pattern(s1, &pat_len); + unsigned int pat_len; + pat = r3_slug_find_pattern(s1, s1_len, &pat_len); if (pat) { *o = '('; @@ -214,7 +218,7 @@ char * r3_slug_compile(const char * str, int len) o+= strlen("([^*]+)"); } s1 += s1_len; - strncat(o, s1, strlen(s1)); + strncat(o, s1, len - (s1 - str)); // string after slug return out; } diff --git a/src/token.c b/src/token.c index 0cefd88..6464beb 100644 --- a/src/token.c +++ b/src/token.c @@ -13,83 +13,44 @@ #include "r3_slug.h" #include "str_array.h" #include "zmalloc.h" - -str_array * str_array_create(int cap) { - str_array * list = (str_array*) zmalloc( sizeof(str_array) ); - if (!list) - return NULL; - list->len = 0; - list->slugs_len = 0; - list->cap = cap; - list->slugs = NULL; - list->tokens = (char**) zmalloc( sizeof(char*) * cap); - return list; -} +#include "memory.h" void str_array_free(str_array *l) { assert(l); - for ( int i = 0; i < l->len ; i++ ) { - if (l->tokens[ i ]) { - zfree(l->tokens[i]); - } - } - zfree(l->tokens); - zfree(l); + free(l->tokens.entries); } -bool str_array_slugs_full(const str_array * l) { - return l->slugs_len >= l->cap; -} - -bool str_array_tokens_full(const str_array * l) { - return l->len >= l->cap; -} - -bool str_array_resize(str_array * l, int new_cap) { - l->slugs = zrealloc(l->slugs, sizeof(char**) * new_cap); - l->tokens = zrealloc(l->tokens, sizeof(char**) * new_cap); - l->cap = new_cap; - return l->tokens != NULL && l->slugs != NULL; -} - -bool str_array_append_slug(str_array * l, char * slug) { - if ( str_array_slugs_full(l) ) { - bool ret = str_array_resize(l, l->cap + 20); - if (ret == false ) { - return false; - } - } - l->slugs[ l->slugs_len++ ] = slug; - return true; -} - -bool str_array_append(str_array * l, char * token) { - if ( str_array_tokens_full(l) ) { - bool ret = str_array_resize(l, l->cap + 20); - if (ret == false ) { - return false; - } - } - l->tokens[ l->len++ ] = token; +bool str_array_append(str_array * l, char * token, unsigned int len) { + R3_VECTOR(r3_iovec_t) *tks = &l->tokens; + r3_vector_reserve(NULL, tks, tks->size + 1); + r3_iovec_t *temp = tks->entries + tks->size++; + memset(temp, 0, sizeof(*temp)); + temp->base = token; + temp->len = len; return true; } void str_array_dump_slugs(const str_array *l) { - printf("["); - for ( int i = 0; i < l->slugs_len ; i++ ) { - printf("\"%s\"", l->slugs[i] ); - if ( i + 1 != l->slugs_len ) { - printf(", "); + if (l->tokens.size) { + printf("["); + for ( int i = 0; i < l->tokens.size ; i++ ) { + printf("\"%*.*s\"", l->slugs.entries[i].len,l->slugs.entries[i].len,l->slugs.entries[i].base ); + if ( i + 1 != l->tokens.size ) { + printf(", "); + } } + printf("]\n"); + } else { + printf("[]\n"); } - printf("]\n"); } void str_array_dump(const str_array *l) { printf("["); - for ( int i = 0; i < l->len ; i++ ) { - printf("\"%s\"", l->tokens[i] ); - if ( i + 1 != l->len ) { + for ( int i = 0; i < l->tokens.size ; i++ ) { + printf("\"%*.*s\"", l->tokens.entries[i].len,l->tokens.entries[i].len,l->tokens.entries[i].base ); + // printf("\"%s\"", l->tokens.entries[i] ); + if ( i + 1 != l->tokens.size ) { printf(", "); } } diff --git a/tests/Makefile.am b/tests/Makefile.am index 196c6c8..b150d6c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ TESTS = -AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) @CHECK_CFLAGS@ -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/src -I$(top_builddir)/3rdparty -Wall -std=c99 -ggdb +AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) @CHECK_CFLAGS@ -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/src -I$(top_builddir)/3rdparty -Wall -std=c99 -ggdb `pkg-config --cflags --libs check` AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS) @CHECK_LIBS@ $(top_builddir)/libr3.la if USE_JEMALLOC diff --git a/tests/bench.c b/tests/bench.c index 2416d2a..fbcbd28 100644 --- a/tests/bench.c +++ b/tests/bench.c @@ -464,7 +464,8 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL); R3Node * tree2 = r3_tree_create(1); r3_tree_insert_path(tree2, "/post/{year}/{month}", NULL); r3_tree_compile(tree2, NULL); - + // r3_tree_dump(tree2,0); + BENCHMARK(pcre_dispatch) r3_tree_matchl(tree2, "/post/2014/12", strlen("/post/2014/12"), NULL); END_BENCHMARK(pcre_dispatch) diff --git a/tests/check_slug.c b/tests/check_slug.c index a104912..0e9fe0b 100644 --- a/tests/check_slug.c +++ b/tests/check_slug.c @@ -46,14 +46,16 @@ END_TEST START_TEST (test_contains_slug) { - ck_assert( r3_path_contains_slug_char("/user/{id}/{name}") ); + char *test_str = "/user/{id}/{name}"; + ck_assert( r3_path_contains_slug_char(test_str, strlen(test_str)) ); } END_TEST START_TEST (test_r3_slug_find_pattern) { int len; - char * namerex = r3_slug_find_pattern("{name:\\s+}", &len); + char *test_str = "{name:\\s+}"; + char * namerex = r3_slug_find_pattern(test_str, strlen(test_str), &len); ck_assert( strncmp(namerex, "\\s+", len) == 0 ); } END_TEST @@ -61,7 +63,8 @@ END_TEST START_TEST (test_r3_slug_find_name) { int len; - char * namerex = r3_slug_find_name("{name:\\s+}", &len); + char *test_str = "{name:\\s+}"; + char * namerex = r3_slug_find_name(test_str, strlen(test_str), &len); ck_assert( strncmp(namerex, "name", len) == 0 ); } END_TEST @@ -69,7 +72,8 @@ END_TEST START_TEST (test_r3_slug_find_name_without_pattern) { int len; - char * namerex = r3_slug_find_name("{name}", &len); + char *test_str = "{name}"; + char * namerex = r3_slug_find_name(test_str, strlen(test_str), &len); ck_assert( strncmp(namerex, "name", len) == 0 ); } END_TEST @@ -77,7 +81,8 @@ END_TEST START_TEST (test_r3_slug_find_name_with_multiple_slug) { int len; - char * namerex = r3_slug_find_name("{name}/{name2}", &len); + char *test_str = "{name}/{name2}"; + char * namerex = r3_slug_find_name(test_str, strlen(test_str), &len); ck_assert( strncmp(namerex, "name", len) == 0 ); } END_TEST @@ -86,11 +91,12 @@ START_TEST (test_r3_slug_find_placeholder) { int slug_len = 0; char * slug; - slug = r3_slug_find_placeholder("/user/{name:\\s+}/to/{id}", &slug_len); + char *test_str = "/user/{name:\\s+}/to/{id}"; + slug = r3_slug_find_placeholder(test_str, strlen(test_str), &slug_len); ck_assert( strncmp(slug, "{name:\\s+}", slug_len) == 0 ); - - slug = r3_slug_find_placeholder("/user/{idx:\\d{3}}/to/{idy:\\d{3}}", &slug_len); + test_str = "/user/{idx:\\d{3}}/to/{idy:\\d{3}}"; + slug = r3_slug_find_placeholder(test_str, strlen(test_str), &slug_len); ck_assert( slug_len == strlen("{idx:\\d{3}}") ); ck_assert( strncmp(slug, "{idx:\\d{3}}", slug_len) == 0 ); } @@ -186,7 +192,8 @@ END_TEST START_TEST (test_r3_slug_find_placeholder_with_broken_slug) { int slug_len = 0; - char * slug = r3_slug_find_placeholder("/user/{name:\\s+/to/{id", &slug_len); + char *sl_test = "/user/{name:\\s+/to/{id"; + char * slug = r3_slug_find_placeholder(sl_test, strlen(sl_test), &slug_len); ck_assert(slug == 0); } END_TEST diff --git a/tests/check_str_array.c b/tests/check_str_array.c index 4dbac5b..0eeb895 100644 --- a/tests/check_str_array.c +++ b/tests/check_str_array.c @@ -14,23 +14,26 @@ START_TEST (test_str_array) { - str_array * l = str_array_create(3); - ck_assert(l); + match_entry * entry = match_entry_create("/foo"); + ck_assert(entry); - ck_assert(str_array_append(l, zstrdup("abc"))); - ck_assert( l->len == 1 ); + char *test_str = "abc"; + ck_assert( str_array_append(&entry->vars, test_str, strlen(test_str))); + ck_assert( entry->vars.tokens.size == 1 ); - ck_assert(str_array_append(l, zstrdup("foo") )); - ck_assert( l->len == 2 ); + char *test_str1 = "foo"; + ck_assert( str_array_append(&entry->vars, test_str1, strlen(test_str))); + ck_assert( entry->vars.tokens.size == 2 ); - ck_assert( str_array_append(l, zstrdup("bar") ) ); - ck_assert( l->len == 3 ); + char *test_str2 = "bar"; + ck_assert( str_array_append(&entry->vars, test_str2, strlen(test_str))); + ck_assert( entry->vars.tokens.size == 3 ); - ck_assert( str_array_append(l, zstrdup("zoo") ) ); - ck_assert( l->len == 4 ); + char *test_str3 = "zoo"; + ck_assert( str_array_append(&entry->vars, test_str3, strlen(test_str))); + ck_assert( entry->vars.tokens.size == 4 ); - ck_assert( str_array_resize(l, l->cap * 2) ); - str_array_free(l); + match_entry_free(entry); } END_TEST diff --git a/tests/check_tree.c b/tests/check_tree.c index 1a9870b..bc351a7 100644 --- a/tests/check_tree.c +++ b/tests/check_tree.c @@ -15,9 +15,10 @@ START_TEST (test_find_common_prefix) { + char *test_str = "/foo/{slug}"; R3Node * n = r3_tree_create(10); - R3Edge * e = r3_edge_createl(zstrdup("/foo/{slug}"), sizeof("/foo/{slug}")-1, NULL); - r3_node_append_edge(n,e); + R3Edge * e = r3_node_append_edge(n); + r3_edge_initl(e, test_str, strlen(test_str), NULL); char *errstr = NULL; int prefix_len = 0; @@ -25,14 +26,16 @@ START_TEST (test_find_common_prefix) errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "/foo", sizeof("/foo")-1, &prefix_len, &errstr); + char *test_pref1 = "/foo"; + ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr); ck_assert(ret_edge != NULL); ck_assert_int_eq(prefix_len, 4); SAFE_FREE(errstr); errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "/foo/", sizeof("/foo/")-1, &prefix_len, &errstr); + char *test_pref2 = "/foo/"; + ret_edge = r3_node_find_common_prefix(n, test_pref2, strlen(test_pref2), &prefix_len, &errstr); ck_assert(ret_edge != NULL); ck_assert_int_eq(prefix_len, 5); SAFE_FREE(errstr); @@ -40,35 +43,40 @@ START_TEST (test_find_common_prefix) errstr = NULL; prefix_len = 0; - ret_edge = r3_node_find_common_prefix(n, "/foo/{slog}", sizeof("/foo/{slog}")-1, &prefix_len, &errstr); + char *test_pref3 = "/foo/{slog}"; + ret_edge = r3_node_find_common_prefix(n, test_pref3, strlen(test_pref3), &prefix_len, &errstr); ck_assert(ret_edge != NULL); ck_assert_int_eq(prefix_len, 5); SAFE_FREE(errstr); errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "/foo/{bar}", sizeof("/foo/{bar}")-1, &prefix_len, &errstr); + char *test_pref4 = "/foo/{bar}"; + ret_edge = r3_node_find_common_prefix(n, test_pref4, strlen(test_pref4), &prefix_len, &errstr); ck_assert(ret_edge != NULL); ck_assert_int_eq(prefix_len, 5); SAFE_FREE(errstr); errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "/foo/bar", sizeof("/foo/bar")-1, &prefix_len, &errstr); + char *test_pref5 = "/foo/bar"; + ret_edge = r3_node_find_common_prefix(n, test_pref5, strlen(test_pref5), &prefix_len, &errstr); ck_assert(ret_edge != NULL); ck_assert_int_eq(prefix_len, 5); SAFE_FREE(errstr); errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "/bar/", sizeof("/bar/")-1, &prefix_len, &errstr); + char *test_pref6 = "/bar/"; + ret_edge = r3_node_find_common_prefix(n, test_pref6, strlen(test_pref6), &prefix_len, &errstr); ck_assert(ret_edge != NULL); ck_assert_int_eq(prefix_len, 1); SAFE_FREE(errstr); errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "{bar}", sizeof("{bar}")-1, &prefix_len, &errstr); + char *test_pref7 = "{bar}"; + ret_edge = r3_node_find_common_prefix(n, test_pref7, strlen(test_pref7), &prefix_len, &errstr); ck_assert(ret_edge == NULL); ck_assert_int_eq(prefix_len, 0); SAFE_FREE(errstr); @@ -84,30 +92,34 @@ END_TEST START_TEST (test_find_common_prefix_after) { + char *test_str = "{slug}/foo"; R3Node * n = r3_tree_create(10); - R3Edge * e = r3_edge_createl(zstrdup("{slug}/foo"), sizeof("{slug}/foo")-1, NULL); - r3_node_append_edge(n,e); + R3Edge * e = r3_node_append_edge(n); + r3_edge_initl(e, test_str, strlen(test_str), NULL); int prefix_len = 0; R3Edge *ret_edge = NULL; char *errstr = NULL; errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "/foo", sizeof("/foo")-1, &prefix_len, &errstr); + char *test_pref1 = "/foo"; + ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr); ck_assert(ret_edge == NULL); ck_assert_int_eq(prefix_len, 0); SAFE_FREE(errstr); errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "{slug}/bar", sizeof("{slug}/bar")-1, &prefix_len, &errstr); + char *test_pref2 = "{slug}/bar"; + ret_edge = r3_node_find_common_prefix(n, test_pref2, strlen(test_pref2), &prefix_len, &errstr); ck_assert(ret_edge != NULL); ck_assert_int_eq(prefix_len, 7); SAFE_FREE(errstr); errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "{slug}/foo", sizeof("{slug}/foo")-1, &prefix_len, &errstr); + char *test_pref3 = "{slug}/foo"; + ret_edge = r3_node_find_common_prefix(n, test_pref3, strlen(test_pref3), &prefix_len, &errstr); ck_assert(ret_edge != NULL); ck_assert_int_eq(prefix_len, 10); SAFE_FREE(errstr); @@ -121,16 +133,18 @@ END_TEST START_TEST (test_find_common_prefix_double_middle) { + char *test_str = "{slug}/foo/{name}"; R3Node * n = r3_tree_create(10); - R3Edge * e = r3_edge_createl(zstrdup("{slug}/foo/{name}"), sizeof("{slug}/foo/{name}")-1, NULL); - r3_node_append_edge(n,e); + R3Edge * e = r3_node_append_edge(n); + r3_edge_initl(e, test_str, strlen(test_str), NULL); int prefix_len; R3Edge *ret_edge = NULL; char *errstr; errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "{slug}/foo/{number}", sizeof("{slug}/foo/{number}")-1, &prefix_len, &errstr); + char *test_pref1 = "{slug}/foo/{number}"; + ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr); ck_assert(ret_edge); ck_assert_int_eq(prefix_len, 11); SAFE_FREE(errstr); @@ -144,21 +158,24 @@ END_TEST START_TEST (test_find_common_prefix_middle) { R3Node * n = r3_tree_create(10); - R3Edge * e = r3_edge_createl(zstrdup("/foo/{slug}/hate"), sizeof("/foo/{slug}/hate")-1, NULL); - r3_node_append_edge(n,e); + char *test_str = "/foo/{slug}/hate"; + R3Edge * e = r3_node_append_edge(n); + r3_edge_initl(e, test_str, strlen(test_str), NULL); int prefix_len; R3Edge *ret_edge = NULL; char *errstr = NULL; errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "/foo/{slug}/bar", sizeof("/foo/{slug}/bar")-1, &prefix_len, &errstr); + char *test_str1 = "/foo/{slug}/bar"; + ret_edge = r3_node_find_common_prefix(n, test_str1, strlen(test_str1), &prefix_len, &errstr); ck_assert(ret_edge); ck_assert_int_eq(prefix_len, 12); SAFE_FREE(errstr); errstr = NULL; - ret_edge = r3_node_find_common_prefix(n, "/fo/{slug}/bar", sizeof("/fo/{slug}/bar")-1, &prefix_len, &errstr); + char *test_str2 = "/fo/{slug}/bar"; + ret_edge = r3_node_find_common_prefix(n, test_str2, strlen(test_str2), &prefix_len, &errstr); ck_assert(ret_edge); ck_assert_int_eq(prefix_len, 3); SAFE_FREE(errstr); @@ -170,8 +187,9 @@ END_TEST START_TEST (test_find_common_prefix_same_pattern) { R3Node * n = r3_tree_create(10); - R3Edge * e = r3_edge_createl(zstrdup("/foo/{slug:xxx}/hate"), sizeof("/foo/{slug:xxx}/hate")-1, NULL); - r3_node_append_edge(n,e); + char *test_str = "/foo/{slug:xxx}/hate"; + R3Edge * e = r3_node_append_edge(n); + r3_edge_initl(e, test_str, strlen(test_str), NULL); int prefix_len; R3Edge *ret_edge = NULL; @@ -194,8 +212,9 @@ END_TEST START_TEST (test_find_common_prefix_same_pattern2) { R3Node * n = r3_tree_create(10); - R3Edge * e = r3_edge_createl(zstrdup("{slug:xxx}/hate"), sizeof("{slug:xxx}/hate")-1, NULL); - r3_node_append_edge(n,e); + char *test_str = "{slug:xxx}/hate"; + R3Edge * e = r3_node_append_edge(n); + r3_edge_initl(e, test_str, strlen(test_str), NULL); int prefix_len; R3Edge *ret_edge = NULL; @@ -443,7 +462,7 @@ START_TEST (test_pcre_patterns_insert_2) // r3_tree_dump(n, 0); R3Node *matched; matched = r3_tree_match(n, "/post/11/22", NULL); - ck_assert((int)matched); + ck_assert(matched); ck_assert(matched->endpoint > 0); } END_TEST @@ -473,7 +492,7 @@ START_TEST (test_pcre_patterns_insert_3) matched = r3_tree_match(n, "/post/11/22", NULL); - ck_assert((int)matched); + ck_assert(matched); matched = r3_tree_match(n, "/post/11", NULL); ck_assert(!matched); @@ -497,7 +516,7 @@ START_TEST (test_insert_pathl_fail) R3Node * ret; char *errstr = NULL; - ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), NULL, NULL, &errstr); + ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), 0, 0, 0, &errstr); ck_assert(ret == NULL); ck_assert(errstr != NULL); printf("%s\n", errstr); // Returns Incomplete slug pattern. PATTERN (16): '/foo/{name:\d{5}', OFFSET: 16, STATE: 1 @@ -608,7 +627,9 @@ END_TEST START_TEST(test_route_cmp) { - R3Route *r1 = r3_route_create("/blog/post"); + R3Node * n = r3_tree_create(10); + char *test_str = "/blog/post"; + R3Route *r1 = r3_node_append_route(n,test_str, strlen(test_str),0,0); match_entry * m = match_entry_create("/blog/post"); fail_if( r3_route_cmp(r1, m) == -1, "should match"); @@ -627,6 +648,7 @@ START_TEST(test_route_cmp) r3_route_free(r1); match_entry_free(m); + r3_tree_free(n); } END_TEST @@ -643,8 +665,8 @@ START_TEST(test_pcre_pattern_simple) R3Node *matched; matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry); ck_assert(matched); - ck_assert(entry->vars->len > 0); - ck_assert_str_eq(entry->vars->tokens[0],"123"); + ck_assert(entry->vars.tokens.size > 0); + ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123"); r3_tree_free(n); } END_TEST @@ -653,7 +675,8 @@ END_TEST START_TEST(test_pcre_pattern_more) { match_entry * entry; - entry = match_entry_createl( "/user/123" , strlen("/user/123") ); + entry = match_entry_create( "/user/123" ); + entry->request_method = 0; R3Node * n = r3_tree_create(10); int var0 = 5; @@ -674,25 +697,26 @@ START_TEST(test_pcre_pattern_more) // r3_tree_dump(n, 0); R3Node *matched; - matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry); + matched = r3_tree_match(n, "/user/123", entry); ck_assert(matched); - ck_assert(entry->vars->len > 0); - ck_assert_str_eq(entry->vars->tokens[0],"123"); + ck_assert(entry->vars.tokens.size > 0); + ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123"); - info("matched %p\n", matched->data); info("matched %p\n", matched->data); ck_assert_int_eq( *((int*) matched->data), var1); matched = r3_tree_matchl(n, "/user2/123", strlen("/user2/123"), entry); ck_assert(matched); - ck_assert(entry->vars->len > 0); - ck_assert_str_eq(entry->vars->tokens[0],"123"); + ck_assert(entry->vars.tokens.size > 0); + ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123"); + info("matched %p\n", matched->data); ck_assert_int_eq( *((int*)matched->data), var2); matched = r3_tree_matchl(n, "/user3/123", strlen("/user3/123"), entry); ck_assert(matched); - ck_assert(entry->vars->len > 0); - ck_assert_str_eq(entry->vars->tokens[0],"123"); + ck_assert(entry->vars.tokens.size > 0); + ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123"); + info("matched %p\n", matched->data); ck_assert_int_eq( *((int*)matched->data), var3); r3_tree_free(n); @@ -707,9 +731,9 @@ START_TEST(test_insert_pathl_before_root) int var2 = 33; int var3 = 44; R3Node * n = r3_tree_create(3); - r3_tree_insert_pathl_ex(n, STR("/blog/post"), NULL, &var1, NULL); - r3_tree_insert_pathl_ex(n, STR("/blog"), NULL, &var2, NULL); - r3_tree_insert_pathl_ex(n, STR("/"), NULL, &var3, NULL); + r3_tree_insert_pathl_ex(n, STR("/blog/post"), 0, 0, &var1, NULL); + r3_tree_insert_pathl_ex(n, STR("/blog"), 0, 0, &var2, NULL); + r3_tree_insert_pathl_ex(n, STR("/"), 0, 0, &var3, NULL); errstr = NULL; r3_tree_compile(n, &errstr);