Changed r3 memory model, made few optimizing

This commit is contained in:
karantin2020 2016-03-22 07:23:37 +05:00
parent ef910789c0
commit 75438ef3d3
21 changed files with 564 additions and 576 deletions

View file

@ -14,12 +14,14 @@
void test1(void) { void test1(void) {
R3Node *n = r3_tree_create(10); 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 // 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", sizeof("/blog") - 1, &route_data1 );
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/{idl:\\d+}/asf/{id}", strlen("/blog/{idl:\\d+}/asf/{id}"), &route_data2 );
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, "/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; char *errstr = NULL;
int err = r3_tree_compile(n, &errstr); int err = r3_tree_compile(n, &errstr);
@ -28,6 +30,7 @@ void test1(void) {
printf("error: %s\n", errstr); printf("error: %s\n", errstr);
free(errstr); // errstr is created from `asprintf`, so you have to free it manually. free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
} }
// r3_tree_dump(n,0);
// in your http server handler // in your http server handler
@ -35,40 +38,54 @@ void test1(void) {
// create the match entry for capturing dynamic variables. // create the match entry for capturing dynamic variables.
match_entry * entry; match_entry * entry;
R3Route *matched_route; R3Route *matched_route;
// for (int k = 0; k < 3000000; k++) { int i;
entry = match_entry_create("/blog"); for (int k = 0; k < 3000000; k++) {
if (entry != NULL) { // printf("round N%d\n",k);
entry->request_method = METHOD_GET; entry = match_entry_create("/blog/432/asf/678");
matched_route = r3_tree_match_route(n, entry); entry->request_method = METHOD_GET;
if (matched_route != NULL) { matched_route = r3_tree_match_route(n, entry);
// printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route // if (matched_route) {
for (int i = 0; i < entry->vars->len; i++) { // printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route
entry->vars->slugs[i]; // if (entry->vars.tokens.size == entry->vars.slugs.size) {
entry->vars->tokens[i]; // for (i = 0; i < entry->vars.tokens.size; i++) {
// printf("Slug name is: %s\n",entry->vars->slugs[i]); // // entry->vars.slugs.entries[i];
// printf("Slug value is: %s\n",entry->vars->tokens[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,
// free the objects at the end // entry->vars.tokens.entries[i].len, entry->vars.tokens.entries[i].base);
match_entry_free(entry); // }
// } // } else {
entry = match_entry_create("/blog/aaa/asd/123/qwe"); // // printf("Slugs and tokens sizes are not equal\n");
if (entry != NULL) { // // for (i = 0; i < entry->vars.slugs.size; i++) {
entry->request_method = METHOD_GET; // // printf("Slug name is: %*.*s\n",entry->vars.slugs.entries[i].len,
matched_route = r3_tree_match_route(n, entry); // // entry->vars.slugs.entries[i].len, entry->vars.slugs.entries[i].base);
if (matched_route != NULL) { // // }
// printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route // // for (i = 0; i < entry->vars.tokens.size; i++) {
for (int i = 0; i < entry->vars->len; i++) { // // printf("Slug value is: %*.*s\n",entry->vars.tokens.entries[i].len,
// entry->vars->slugs[i]; // // entry->vars.tokens.entries[i].len, entry->vars.tokens.entries[i].base);
// 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 // free the objects at the end
match_entry_free(entry); 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); r3_tree_free(n);
} }

View file

@ -32,6 +32,7 @@ typedef unsigned char bool;
#include "str_array.h" #include "str_array.h"
#include "r3_slug.h" #include "r3_slug.h"
#include "memory.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -46,83 +47,61 @@ typedef struct _node R3Node;
typedef struct _R3Route R3Route; typedef struct _R3Route R3Route;
struct _node { struct _node {
R3Edge ** edges; R3_VECTOR(R3Edge) edges;
R3_VECTOR(R3Route) routes;
char * combined_pattern; char * combined_pattern;
pcre * pcre_pattern; pcre * pcre_pattern;
pcre_extra * pcre_extra; pcre_extra * pcre_extra;
// edges are mostly less than 255 // edges are mostly less than 255
unsigned int compare_type; // compare_type: pcre, opcode, string 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 endpoint; // endpoint, should be zero for non-endpoint nodes
unsigned int ov_cnt; // capture vector array size for pcre unsigned int ov_cnt; // capture vector array size for pcre
R3Route ** routes;
// the pointer of R3Route data // the pointer of R3Route data
void * data; void * data;
// almost less than 255 // almost less than 255
unsigned char edge_cap;
unsigned char route_len;
unsigned char route_cap;
} __attribute__((aligned(64))); } __attribute__((aligned(64)));
#define r3_node_edge_pattern(node,i) node->edges[i]->pattern #define r3_node_edge_pattern(node,i) node->edges.entries[i].pattern.base
#define r3_node_edge_pattern_len(node,i) node->edges[i]->pattern_len #define r3_node_edge_pattern_len(node,i) node->edges.entries[i].pattern.len
struct _edge { struct _edge {
char * pattern; // 8 bytes r3_iovec_t pattern; // 8 bytes
R3Node * child; // 8 bytes R3Node * child; // 8 bytes
unsigned int pattern_len; // 4byte // unsigned int pattern_len; // 4byte
unsigned int opcode; // 4byte unsigned int opcode; // 4byte
unsigned int has_slug; // 4byte unsigned int has_slug; // 4byte
} __attribute__((aligned(64))); } __attribute__((aligned(64)));
struct _R3Route { struct _R3Route {
char * path; r3_iovec_t path;
int path_len; R3_VECTOR(r3_iovec_t) slugs;
int request_method; // can be (GET || POST)
char **slugs; r3_iovec_t host; // required host name
int slugs_len;
int slugs_cap;
int request_method; // can be (GET || POST)
char * host; // required host name
int host_len;
void * data; void * data;
char * remote_addr_pattern; r3_iovec_t remote_addr_pattern;
int remote_addr_pattern_len;
} __attribute__((aligned(64))); } __attribute__((aligned(64)));
typedef struct { typedef struct _R3Entry match_entry;
str_array * vars; struct _R3Entry {
const char * path; // current path to dispatch str_array vars;
int path_len; // the length of the current path r3_iovec_t path; // current path to dispatch
int request_method; // current request method int request_method; // current request method
void * data; // R3Route ptr void * data; // R3Route ptr
char * host; // the request host r3_iovec_t host; // the request host
int host_len; r3_iovec_t remote_addr;
} __attribute__((aligned(64)));
char * remote_addr;
int remote_addr_len;
} match_entry;
R3Node * r3_tree_create(int cap); R3Node * r3_tree_create(int cap);
R3Node * r3_node_create(); // R3Node * r3_node_create();
void r3_tree_free(R3Node * tree); 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) #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); 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); 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_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) #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 * 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); 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); 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) #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); // 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); 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); 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_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); 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 }; enum { NODE_COMPARE_STR, NODE_COMPARE_PCRE, NODE_COMPARE_OPCODE };

View file

@ -90,13 +90,13 @@ namespace r3 {
} }
Node insert_path(const char* path, void* data, char** errstr = NULL) { 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); data, errstr);
} }
Node insert_pathl(const char* path, int path_len, void* data, Node insert_pathl(const char* path, int path_len, void* data,
char** errstr = NULL) { 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); errstr);
} }

View file

@ -11,13 +11,13 @@
extern "C" { extern "C" {
#endif #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); int r3_slug_count(const char * needle, int len, char **errstr);

View file

@ -8,25 +8,25 @@
#ifndef STR_ARRAY_H #ifndef STR_ARRAY_H
#define STR_ARRAY_H #define STR_ARRAY_H
#include "r3.h"
#include "memory.h"
typedef struct _str_array { typedef struct _str_array {
char **slugs; R3_VECTOR(r3_iovec_t) slugs;
int slugs_len; R3_VECTOR(r3_iovec_t) tokens;
char **tokens;
int len;
int cap;
} str_array; } 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_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); void str_array_free(str_array *l);

View file

@ -1,7 +1,7 @@
include_directories("${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/3rdparty ${PROJECT_SOURCE_DIR}") 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}) # install(TARGETS swiftnav-static DESTINATION lib${LIB_SUFFIX})
find_package(PCRE REQUIRED) 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) set(LIBS ${LIBS} ${PCRE_LIBRARIES} r3)
add_library(r3 STATIC ${libr3_SRCS}) add_library(r3 STATIC ${libr3_SRCS})

View file

@ -4,7 +4,7 @@ MAYBE_COVERAGE=--coverage
noinst_LTLIBRARIES = libr3core.la noinst_LTLIBRARIES = libr3core.la
# lib_LIBRARIES = libr3.a # 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 if ENABLE_JSON
libr3core_la_SOURCES += json.c libr3core_la_SOURCES += json.c

View file

@ -27,24 +27,24 @@
void r3_edge_initl(R3Edge *e, const char * pattern, int pattern_len, R3Node * child) void r3_edge_initl(R3Edge *e, const char * pattern, int pattern_len, R3Node * child)
{ {
e->pattern = (char*) pattern; e->pattern.base = (char*) pattern;
e->pattern_len = pattern_len; e->pattern.len = (unsigned int)pattern_len;
e->opcode = 0; // e->opcode = 0;
e->child = child; 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 * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child)
{ // {
R3Edge * e = (R3Edge*) zmalloc( sizeof(R3Edge) ); // R3Edge * e = (R3Edge*) zmalloc( sizeof(R3Edge) );
CHECK_PTR(e); // CHECK_PTR(e);
e->pattern = (char*) pattern; // e->pattern = (char*) pattern;
e->pattern_len = pattern_len; // e->pattern_len = pattern_len;
e->opcode = 0; // e->opcode = 0;
e->child = child; // e->child = child;
e->has_slug = r3_path_contains_slug_char(e->pattern); // e->has_slug = r3_path_contains_slug_char(e->pattern);
return e; // return e;
} // }
@ -64,35 +64,28 @@ R3Node * r3_edge_branch(R3Edge *e, int dl) {
R3Edge * new_edge; R3Edge * new_edge;
// the rest string // the rest string
char * s1 = e->pattern + dl; char * s1 = e->pattern.base + dl;
int s1_len = e->pattern_len - dl; int s1_len = e->pattern.len - dl;
// the suffix edge of the leaf // the suffix edge of the leaf
new_child = r3_tree_create(3); 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 = r3_node_append_edge(new_child);
new_edge->child = e->child; r3_edge_initl(new_edge, s1, s1_len, e->child);
e->child = new_child; e->child = new_child;
r3_node_append_edge(new_child, new_edge);
// truncate the original edge pattern // truncate the original edge pattern
char *oldpattern = e->pattern; e->pattern.len = dl;
e->pattern = zstrndup(e->pattern, dl);
e->pattern_len = dl;
zfree(oldpattern);
return new_child; return new_child;
} }
void r3_edge_free(R3Edge * e) { void r3_edge_free(R3Edge * e) {
if (e) { if (e) {
zfree(e->pattern);
if ( e->child ) { if ( e->child ) {
r3_tree_free(e->child); r3_tree_free(e->child);
} }
// free itself // free itself
zfree(e); // zfree(e);
} }
} }

View file

@ -16,8 +16,8 @@ void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node
if (!n) if (!n)
return; return;
for ( int i = 0 ; i < n->edge_len ; i++ ) { for ( int i = 0 ; i < n->edges.size ; i++ ) {
edge * e = n->edges[i]; edge * e = n->edges.entries + i;
(*node_cnt)++; (*node_cnt)++;
Agnode_t *agn_child = NULL; Agnode_t *agn_child = NULL;

View file

@ -13,15 +13,15 @@ json_object * r3_route_to_json_object(const R3Route * r) {
json_object *obj; json_object *obj;
obj = json_object_new_object(); 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)); json_object_object_add(obj, "allowed_methods", json_object_new_int(r->request_method));
if (r->host) { 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) { 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; return obj;
} }
@ -31,7 +31,7 @@ json_object * r3_edge_to_json_object(const R3Edge * e) {
json_object *obj; json_object *obj;
obj = json_object_new_object(); 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, "opcode", json_object_new_int(e->opcode));
json_object_object_add(obj, "slug", json_object_new_boolean(e->has_slug)); 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 *edges_array = json_object_new_array();
json_object_object_add(obj, "edges", edges_array); json_object_object_add(obj, "edges", edges_array);
for (i = 0 ; i < n->edge_len ; i++ ) { 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); 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 *routes_array = json_object_new_array();
json_object_object_add(obj, "routes", routes_array); json_object_object_add(obj, "routes", routes_array);
for (i = 0; i < n->route_len; i++ ) { 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); json_object_array_add(routes_array, route_json_obj);
} }
} }

View file

@ -16,20 +16,16 @@
#include "zmalloc.h" #include "zmalloc.h"
match_entry * match_entry_createl(const char * path, int path_len) { match_entry * match_entry_createl(const char * path, int path_len) {
match_entry * entry = zmalloc(sizeof(match_entry)); match_entry * entry = r3_mem_alloc( sizeof(match_entry) );
if(!entry) memset(entry, 0, sizeof(*entry));
return NULL; r3_vector_reserve(NULL, &entry->vars.tokens, 3);
entry->vars = str_array_create(3); entry->path.base = path;
entry->path = path; entry->path.len = path_len;
entry->path_len = path_len;
entry->data = NULL;
return entry; return entry;
} }
void match_entry_free(match_entry * entry) { void match_entry_free(match_entry * entry) {
assert(entry); assert(entry);
if (entry->vars) { free(entry->vars.tokens.entries);
str_array_free(entry->vars); free(entry);
}
zfree(entry);
} }

View file

@ -53,40 +53,26 @@ static int strdiff(char * d1, char * d2) {
* Create a node object * Create a node object
*/ */
R3Node * r3_tree_create(int cap) { R3Node * r3_tree_create(int cap) {
R3Node * n = (R3Node*) zmalloc( sizeof(R3Node) ); R3Node * n = r3_mem_alloc( sizeof(R3Node) );
CHECK_PTR(n); 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); n->compare_type = NODE_COMPARE_PCRE;
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;
return n; return n;
} }
void r3_tree_free(R3Node * tree) { void r3_tree_free(R3Node * tree) {
if (tree->edges) { for (int j=0;j<tree->edges.size;j++) {
for (int j=0;j<tree->edge_len;j++) { r3_edge_free(tree->edges.entries + j);
r3_edge_free(tree->edges[j]);
}
zfree(tree->edges);
} }
if (tree->routes) { free(tree->edges.entries);
for (int k=0;k<tree->route_len;k++) { for (int k=0;k<tree->routes.size;k++) {
r3_route_free(tree->routes[k]); r3_route_free(tree->routes.entries + k);
}
zfree(tree->routes);
} }
free(tree->routes.entries);
if (tree->pcre_pattern) { if (tree->pcre_pattern) {
pcre_free(tree->pcre_pattern); pcre_free(tree->pcre_pattern);
} }
@ -96,7 +82,7 @@ void r3_tree_free(R3Node * tree) {
} }
#endif #endif
zfree(tree->combined_pattern); zfree(tree->combined_pattern);
zfree(tree); free(tree);
tree = NULL; 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) { 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 // find the same sub-pattern, if it does not exist, create one
R3Edge * e; R3Edge * e;
e = r3_node_find_edge(n, pat, len); e = r3_node_find_edge(n, pat, len);
if (e) { if (e) {
return e; return e;
} }
if (dupl) { if (dupl) {
pat = zstrndup(pat, len); pat = zstrndup(pat, len);
} }
e = r3_edge_createl(pat, len, child); // e = r3_edge_createl(pat, len, child);
CHECK_PTR(e); e = r3_node_append_edge(n);
R3Edge * e2 = r3_node_append_edge(n, e); r3_edge_initl(e, pat, len, child);
return e2; // 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) { r3_vector_reserve(NULL, &n->edges, n->edges.size + 1);
n->edge_cap = 3; R3Edge *new_e = n->edges.entries + n->edges.size++;
n->edges = zmalloc(sizeof(R3Edge) * n->edge_cap); memset(new_e, 0, sizeof(*new_e));
} return new_e;
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++];
} }
@ -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. * 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 * r3_node_find_edge(const R3Node * n, const char * pat, unsigned int pat_len) {
R3Edge * e; R3Edge *edge_entries = n->edges.entries;
int i; R3Edge *e;
for (i = 0 ; i < n->edge_len ; i++ ) { unsigned int i;
e = n->edges[i]; for (i = 0 ; i < n->edges.size ; i++ ) {
e = edge_entries + i;
// there is a case: "{foo}" vs "{foo:xxx}", // there is a case: "{foo}" vs "{foo:xxx}",
// we should return the match result: full-match or partial-match // 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; 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 r3_tree_compile(R3Node *n, char **errstr)
{ {
int i; unsigned int i;
int ret = 0; int ret = 0;
bool use_slug = r3_node_has_slug_edges(n); // bool use_slug = r3_node_has_slug_edges(n);
if ( use_slug ) { if ( r3_node_has_slug_edges(n) ) {
if ( (ret = r3_tree_compile_patterns(n, errstr)) ) { if ( ret = r3_tree_compile_patterns(n, errstr) ) {
return ret; return ret;
} }
} else { } else {
@ -176,8 +152,8 @@ int r3_tree_compile(R3Node *n, char **errstr)
n->combined_pattern = NULL; n->combined_pattern = NULL;
} }
for (i = 0 ; i < n->edge_len ; i++ ) { for (i = 0 ; i < n->edges.size ; i++ ) {
if ((ret = r3_tree_compile(n->edges[i]->child, errstr))) { if ((ret = r3_tree_compile(n->edges.entries[i].child, errstr))) {
return ret; // stop here if error occurs return ret; // stop here if error occurs
} }
} }
@ -192,7 +168,7 @@ int r3_tree_compile(R3Node *n, char **errstr)
* Return 0 if success * Return 0 if success
*/ */
int r3_tree_compile_patterns(R3Node * n, char **errstr) { int r3_tree_compile_patterns(R3Node * n, char **errstr) {
R3Edge *e = NULL; R3Edge *e;
char * p; char * p;
char * cpat = zcalloc(sizeof(char) * 64 * 3); // XXX char * cpat = zcalloc(sizeof(char) * 64 * 3); // XXX
if (!cpat) { if (!cpat) {
@ -202,29 +178,31 @@ int r3_tree_compile_patterns(R3Node * n, char **errstr) {
p = cpat; p = cpat;
int opcode_cnt = 0; int opcode_cnt = 0;
int i = 0; unsigned int i = 0;
for (; i < n->edge_len ; i++) { for (; i < n->edges.size ; i++) {
e = n->edges[i]; e = n->edges.entries + i;
if (e->opcode) { if (e->opcode) {
opcode_cnt++; opcode_cnt++;
} }
if (e->has_slug) { if (e->has_slug) {
// compile "foo/{slug}" to "foo/[^/]+" // 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); strcat(p, slug_pat);
zfree(slug_pat); zfree(slug_pat);
info("temp pattern: %s\n",cpat);
} else { } else {
strncat(p,"^(", 2); strncat(p,"^(", 2);
p += 2; p += 2;
strncat(p, e->pattern, e->pattern_len); strncat(p, e->pattern.base, e->pattern.len);
p += e->pattern_len; p += e->pattern.len;
strncat(p++,")", 1); 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); strncat(p++,"|",1);
} }
} }
@ -232,12 +210,13 @@ int r3_tree_compile_patterns(R3Node * n, char **errstr) {
info("pattern: %s\n",cpat); info("pattern: %s\n",cpat);
// if all edges use opcode, we should skip the combined_pattern. // 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); // zfree(cpat);
n->compare_type = NODE_COMPARE_OPCODE; n->compare_type = NODE_COMPARE_OPCODE;
} else { } else {
n->compare_type = NODE_COMPARE_PCRE; n->compare_type = NODE_COMPARE_PCRE;
} }
info("COMPARE_TYPE: %d\n",n->compare_type);
n->combined_pattern = cpat; n->combined_pattern = cpat;
@ -245,7 +224,7 @@ int r3_tree_compile_patterns(R3Node * n, char **errstr) {
int pcre_erroffset; int pcre_erroffset;
unsigned int option_bits = 0; 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) { if (n->pcre_pattern) {
pcre_free(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); pcre_free_study(n->pcre_extra);
} }
n->pcre_extra = pcre_study(n->pcre_pattern, 0, &pcre_error); n->pcre_extra = pcre_study(n->pcre_pattern, 0, &pcre_error);
if (n->pcre_extra == NULL) { if (!n->pcre_extra) {
if (errstr) { if (errstr) {
asprintf(errstr, "PCRE study failed at offset %s, pattern: %s", pcre_error, n->combined_pattern); 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 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. * @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); info("try matching: %s\n", path);
R3Edge *e; 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;
const char *pp_end; 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) { if (n->compare_type == NODE_COMPARE_OPCODE) {
info("NODE_COMPARE_OPCODE\n");
pp_end = path + path_len; 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; pp = path;
e = n->edges[i];
switch(e->opcode) { switch(e->opcode) {
case OP_EXPECT_NOSLASH: case OP_EXPECT_NOSLASH:
while (*pp != '/' && pp < pp_end) pp++; 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 // check match
if ((pp - path) > 0) { if ((pp - path) > 0) {
if (entry) { if (entry) {
str_array_append(entry->vars , zstrndup(path, pp - path)); str_array_append(&entry->vars , path, pp - path);
} }
restlen = pp_end - pp; restlen = pp_end - pp;
if (restlen == 0) { if (!restlen) {
return e->child && e->child->endpoint > 0 ? e->child : NULL; return e->child && e->child->endpoint ? e->child : NULL;
} }
return r3_tree_matchl(e->child, pp, restlen, entry); 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 // 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 // pcre pattern node, we use pcre_exec to match the nodes
if (n->pcre_pattern) { if (n->pcre_pattern) {
const char *substring_start = NULL; info("COMPARE PCRE_PATTERN\n");
const char *substring_start = 0;
int substring_length = 0; int substring_length = 0;
int ov[ n->ov_cnt ]; int ov[ n->ov_cnt ];
int rc; 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) restlen = path_len - ov[1]; // if it's fully matched to the end (rest string length)
int *inv = ov + 2;
if (restlen == 0 ) { if (!restlen) {
// Check the substring to decide we should go deeper on which edge // Check the substring to decide we should go deeper on which edge
for (i = 1; i < rc; i++) 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 it's not matched for this edge, just skip them quickly
if (substring_length == 0) if ( !substring_length ) {
inv += 2;
continue; continue;
}
substring_start = path + ov[2*i]; substring_start = path + *inv;
e = n->edges[i - 1]; e = n->edges.entries + i - 1;
if (entry && e->has_slug) { if (entry && e->has_slug) {
// append captured token to entry // 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. // 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 // Check the substring to decide we should go deeper on which edge
inv = ov + 2;
for (i = 1; i < rc; i++) 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 it's not matched for this edge, just skip them quickly
if ( substring_length == 0) { if ( !substring_length ) {
inv += 2;
continue; continue;
} }
substring_start = path + ov[2*i]; substring_start = path + *inv;
e = n->edges[i - 1]; e = n->edges.entries + i - 1;
if (entry && e->has_slug) { if (entry && e->has_slug) {
// append captured token to entry // 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 // 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; return NULL;
} }
if ((e = r3_node_find_edge_str(n, path, path_len)) != NULL) { info("COMPARE COMPARE_STR\n");
restlen = path_len - e->pattern_len;
if (restlen == 0) { if (e = r3_node_find_edge_str(n, path, path_len)) {
return e->child && e->child->endpoint > 0 ? e->child : NULL; 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; 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) { R3Route * r3_tree_match_route(const R3Node *tree, match_entry * entry) {
R3Node *n; R3Node *n;
int i; R3Route *r;
n = r3_tree_match_entry(tree, entry); n = r3_tree_match_entry(tree, entry);
if (n && n->routes && n->route_len > 0) { unsigned int i, irs = n->routes.size;
for (i = n->route_len; i--; ) { if (n && irs) {
if ( r3_route_cmp(n->routes[i], entry) == 0 ) { 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 // Add slugs from found route to match_entry
entry->vars->slugs = n->routes[i]->slugs; entry->vars.slugs.entries = r->slugs.entries;
return n->routes[i]; entry->vars.slugs.size = r->slugs.size;
return r;
} }
r++;
} }
} }
return NULL; return NULL;
} }
inline R3Edge * r3_node_find_edge_str(const R3Node * n, const char * str, int str_len) { inline R3Edge * r3_node_find_edge_str(const R3Node * n, const char * str, int str_len) {
R3Edge * e; R3Edge *e;
unsigned int i; unsigned int i, cst = *str;
char firstbyte = *str; e = n->edges.entries;
for (i = n->edge_len; i--; ) { unsigned int ies = n->edges.size;
e = n->edges[i]; for (i = 0; ies - i; i++ ) {
if (firstbyte == e->pattern[0]) { if (cst == *e->pattern.base) {
if (strncmp(e->pattern, str, e->pattern_len) == 0) { if (!strncmp(e->pattern.base, str, e->pattern.len)) {
return n->edges[i]; return e;
} }
return NULL; return NULL;
} }
e++;
} }
return NULL; return NULL;
} }
R3Node * r3_node_create() { // R3Node * r3_node_create() {
R3Node * n = (R3Node*) zmalloc( sizeof(R3Node) ); // R3Node * n = (R3Node*) zmalloc( sizeof(R3Node) );
CHECK_PTR(n); // CHECK_PTR(n);
n->edges = NULL; // n->edges = NULL;
n->edge_len = 0; // n->edge_len = 0;
n->edge_cap = 0; // n->edge_cap = 0;
n->routes = NULL; // n->routes = NULL;
n->route_len = 0; // n->route_len = 0;
n->route_cap = 0; // n->route_cap = 0;
n->endpoint = 0; // n->endpoint = 0;
n->combined_pattern = NULL; // n->combined_pattern = NULL;
n->pcre_pattern = NULL; // n->pcre_pattern = NULL;
n->pcre_extra = NULL; // n->pcre_extra = NULL;
n->data = NULL; // n->data = NULL;
return n; // return n;
} // }
void r3_route_free(R3Route * route) { void r3_route_free(R3Route * route) {
assert(route); assert(route);
for ( int i = 0; i < route->slugs_len ; i++ ) { free(route->slugs.entries);
if (route->slugs[ i ]) {
zfree(route->slugs[i]);
}
}
zfree(route->slugs);
zfree(route);
} }
static bool router_slugs_full(const R3Route * route) { // static bool router_slugs_full(const R3Route * route) {
return route->slugs_len >= route->slugs_cap; // 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) { static void get_slugs(R3Route * route, const char * path, int path_len) {
route->slugs = zrealloc(route->slugs, sizeof(char**) * new_cap); char *plh = (char*)path;
route->slugs_cap = new_cap; unsigned int l, namel;
return route->slugs != NULL; l = 0;
}
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;
char *name; char *name;
while(1) { while (plh < (path + path_len)) {
plh = r3_slug_find_placeholder(plh+l,&l); plh = r3_slug_find_placeholder(plh+l, path_len, &l);
if (plh == NULL) break; if (!plh) break;
namel = 0; namel = 0;
name = r3_slug_find_name(plh,&namel); name = r3_slug_find_name(plh, l, &namel);
router_append_slug(route,zstrndup(name,namel)); if (name) {
router_append_slug(route, name, namel);
}
if ((plh + l) >= (path + path_len)) break; if ((plh + l) >= (path + path_len)) break;
} }
} }
R3Route * r3_route_createl(const char * path, int path_len) { R3Route * r3_node_append_route(R3Node *tree, const char * path, int path_len, int method, void *data) {
R3Route * info = zmalloc(sizeof(R3Route)); r3_vector_reserve(NULL, &tree->routes, tree->routes.size + 1);
CHECK_PTR(info); R3Route *info = tree->routes.entries + tree->routes.size++;
info->slugs_cap = 3; memset(info, 0, sizeof(*info));
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)
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->data = data;
info->host_len = 0;
info->remote_addr_pattern = NULL;
info->remote_addr_pattern_len = 0;
return info; 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 ... * 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 * 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); R3Node * ret = r3_tree_insert_pathl_ex(tree, path, path_len, method, 1, data, errstr);
CHECK_PTR(r); R3Route *router = ret->routes.entries + (ret->routes.size - 1);
r->request_method = method; // ALLOW GET OR POST METHOD get_slugs(router, path, path_len);
R3Node * ret = r3_tree_insert_pathl_ex(tree, path, path_len, r, data, errstr);
if (!ret) { return router;
// failed insert
r3_route_free(r);
return NULL;
}
return r;
} }
@ -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" * 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) { 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; int prefix = 0;
*prefix_len = 0; *prefix_len = 0;
R3Edge *e = NULL; R3Edge *e = NULL;
for(i = 0 ; i < n->edge_len ; i++ ) { for(i = 0 ; i < n->edges.size ; i++ ) {
// ignore all edges with slug // 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 // no common, consider insert a new edge
if ( prefix > 0 ) { if ( prefix > 0 ) {
e = n->edges[i]; e = n->edges.entries + i;
break; 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. * 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; 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. // point on the node and append the route.
if (path_len == 0) { if (path_len == 0) {
tree->endpoint++; tree->endpoint++;
if (route) { if (router) {
route->data = data; r3_node_append_route(tree, path, path_len, method, data);
r3_node_append_route(tree, route); info("tree router path is: %s, with len: %d\n", path, path_len);
} }
return tree; 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; const int subpath_len = path_len - prefix_len;
// common prefix not found, insert a new edge for this pattern // 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 // there are two more slugs, we should break them into several parts
int slug_cnt = r3_slug_count(path, path_len, errstr); int slug_cnt = r3_slug_count(path, path_len, errstr);
if (slug_cnt == -1) { if (slug_cnt == -1) {
return NULL; return NULL;
} }
info("slug_cnt: %d\n",slug_cnt);
if ( slug_cnt > 1 ) { if ( slug_cnt > 1 ) {
int slug_len; unsigned int slug_len;
char *p = r3_slug_find_placeholder(path, &slug_len); char *p = r3_slug_find_placeholder(path, path_len, &slug_len);
#ifdef DEBUG #ifdef DEBUG
assert(p); 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 // find the next one '{', then break there
if(p) { 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 #ifdef DEBUG
assert(p); 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" // insert the first one edge, and break at "p"
R3Node * child = r3_tree_create(3); R3Node * child = r3_tree_create(3);
CHECK_PTR(child); unsigned int paln = p - path;
r3_node_connectl(n, path, p - path, 0, child); // no duplicate
r3_node_connectl(n, path, p - path, 1, child); // duplicate
// and insert the rest part to the child // 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 { } else {
if (slug_cnt == 1) { if (slug_cnt == 1) {
// there is one slug, let's see if it's optimiz-able by opcode // there is one slug, let's see if it's optimiz-able by opcode
int slug_len = 0; unsigned int slug_len = 0;
char *slug_p = r3_slug_find_placeholder(path, &slug_len); char *slug_p = r3_slug_find_placeholder(path, path_len, &slug_len);
int slug_pattern_len = 0; unsigned int slug_pattern_len = 0;
char *slug_pattern = r3_slug_find_pattern(slug_p, &slug_pattern_len); char *slug_pattern = r3_slug_find_pattern(slug_p, slug_len, &slug_pattern_len);
int opcode = 0; int opcode = 0;
// if there is a pattern defined. // if there is a pattern defined.
if (slug_pattern_len) { if (slug_pattern_len) {
char *cpattern = r3_slug_compile(slug_pattern, 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)); opcode = r3_pattern_to_opcode(cpattern, strlen(cpattern));
info("opcode: %d\n", opcode);
zfree(cpattern); zfree(cpattern);
} else { } else {
opcode = OP_EXPECT_NOSLASH; 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; R3Node *c1;
if (slug_p > path) { if (slug_p > path) {
c1 = r3_tree_create(3); c1 = r3_tree_create(3);
CHECK_PTR(c1); r3_node_connectl(n, path, slug_p - path, 0, c1); // no duplicate
r3_node_connectl(n, path, slug_p - path, 1, c1); // duplicate
} else { } else {
c1 = n; c1 = n;
} }
R3Node * c2 = r3_tree_create(3); R3Node * c2 = r3_tree_create(3);
CHECK_PTR(c2);
R3Edge * op_edge = r3_node_connectl(c1, slug_p, slug_len , 0, c2);
R3Edge * op_edge = r3_node_connectl(c1, slug_p, slug_len , 1, c2);
if(opcode) { if(opcode) {
op_edge->opcode = 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); int restlen = path_len - ((slug_p - path) + slug_len);
if (restlen) { 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->data = data;
c2->endpoint++; c2->endpoint++;
if (route) { if (router) {
route->data = data; // route->data = data;
r3_node_append_route(c2, route); 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; return c2;
} }
// only one slug // only one slug
R3Node * child = r3_tree_create(3); R3Node * child = r3_tree_create(3);
CHECK_PTR(child);
child->endpoint++; child->endpoint++;
if (data) if (data)
child->data = data; child->data = data;
r3_node_connectl(n, path, path_len, 1, child); r3_node_connectl(n, path, path_len, 0, child);
if (route) { if (router) {
route->data = data; r3_node_append_route(child, path, path_len, method, data);
r3_node_append_route(child, route); info("child router path is: %s, with len: %d\n", path, path_len);
} }
return child; 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 // there are something more we can insert
if ( subpath_len > 0 ) { 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 { } else {
// there are no more path to insert // there are no more path to insert
// see if there is an endpoint already, we should n't overwrite the data on child. // see if there is an endpoint already, we should n't overwrite the data on child.
// but we still need to append the route. // but we still need to append the route.
if (route) { if (router) {
route->data = data; // route->data = data;
r3_node_append_route(e->child, route); 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 e->child->endpoint++; // make it as an endpoint
return e->child; 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; return e->child;
} }
} else if ( prefix_len < e->pattern_len ) { } else if ( prefix_len < e->pattern.len ) {
/* it's partially matched with the pattern, /* it's partially matched with the pattern,
* we should split the end point and make a branch here... * we should split the end point and make a branch here...
*/ */
r3_edge_branch(e, prefix_len); 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 { } else {
fprintf(stderr, "unexpected route."); fprintf(stderr, "unexpected route.");
return NULL; 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 r3_node_has_slug_edges(const R3Node *n) {
bool found = false; bool found = false;
R3Edge *edge_entries = n->edges.entries;
R3Edge *e; R3Edge *e;
for ( int i = 0 ; i < n->edge_len ; i++ ) { unsigned int i;
e = n->edges[i]; for ( i = 0 ; i < n->edges.size ; i++ ) {
e->has_slug = r3_path_contains_slug_char(e->pattern); e = edge_entries + i;
e->has_slug = r3_path_contains_slug_char(e->pattern.base, e->pattern.len);
if (e->has_slug) if (e->has_slug)
found = true; found = true;
} }
@ -847,6 +831,8 @@ void r3_tree_dump(const R3Node * n, int level) {
printf("(o)"); printf("(o)");
printf(" compare_type:%d", n->compare_type);
if ( n->combined_pattern ) { if ( n->combined_pattern ) {
printf(" regexp:%s", n->combined_pattern); printf(" regexp:%s", n->combined_pattern);
} }
@ -858,14 +844,24 @@ void r3_tree_dump(const R3Node * n, int level) {
} }
printf("\n"); printf("\n");
for ( int i = 0 ; i < n->edge_len ; i++ ) { for ( int i = 0 ; i < n->edges.size ; i++ ) {
R3Edge * e = n->edges[i]; R3Edge * e = n->edges.entries + i;
print_indent(level + 1); print_indent(level + 1);
printf("|-\"%s\"", e->pattern); printf("|-\"%*.*s\"", e->pattern.len, e->pattern.len, e->pattern.base);
if (e->opcode ) { if (e->opcode ) {
printf(" opcode:%d", 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 ) { if ( e->child ) {
printf("\n"); printf("\n");
@ -882,26 +878,26 @@ void r3_tree_dump(const R3Node * n, int level) {
* -1 == different route * -1 == different route
*/ */
inline int r3_route_cmp(const R3Route *r1, const match_entry *r2) { 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) ) { if (0 == (r1->request_method & r2->request_method) ) {
return -1; return -1;
} }
} }
if ( r1->host && r2->host ) { if ( r1->host.len && r2->host.len ) {
if (strcmp(r1->host, r2->host) != 0 ) { if (strncmp(r1->host.base, r2->host.base, r2->host.len)) {
return -1; return -1;
} }
} }
if (r1->remote_addr_pattern) { if (r1->remote_addr_pattern.len && r2->remote_addr.len) {
/* /*
* XXX: consider "netinet/in.h" * XXX: consider "netinet/in.h"
if (r2->remote_addr) { if (r2->remote_addr) {
inet_addr(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; 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) { // void r3_node_append_route(R3Node * n, R3Route * r)
if (n->routes == NULL) { // {
n->route_cap = 3; // r3_vector_reserve(NULL, &n->routes, n->routes.size + 1);
n->routes = zmalloc(sizeof(R3Route) * n->route_cap); // memset(n->routes.entries + 1, 0, sizeof(*n->routes.entries));
}
if (n->route_len >= n->route_cap) { // if (n->routes == NULL) {
n->route_cap *= 2; // n->route_cap = 3;
n->routes = zrealloc(n->routes, sizeof(R3Route) * n->route_cap); // n->routes = zmalloc(sizeof(R3Route) * n->route_cap);
} // }
n->routes[ n->route_len++ ] = r; // 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;
// }

View file

@ -86,7 +86,7 @@ int r3_slug_parse(r3_slug_t *s, const char *needle, int needle_len, const char *
} }
// there is no slug // there is no slug
if (!r3_path_contains_slug_char(offset)) { if (!r3_path_contains_slug_char(offset, needle_len)) {
return 0; return 0;
} }

View file

@ -49,8 +49,11 @@ char * r3_slug_to_str(const r3_slug_t *s);
void r3_slug_free(r3_slug_t * s); void r3_slug_free(r3_slug_t * s);
static inline int r3_path_contains_slug_char(const char * str) { static inline int r3_path_contains_slug_char(const char *str, unsigned int len) {
return strchr(str, '{') != NULL ? 1 : 0; for (unsigned int i = 0; i < len; i++) {
if (str[i] == '{') return 1;
}
return 0;
} }
#endif /* !SLUG_H */ #endif /* !SLUG_H */

View file

@ -15,7 +15,14 @@
#include "slug.h" #include "slug.h"
#include "zmalloc.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 ) { if ( strncmp(pattern, "\\w+",len) == 0 ) {
return OP_EXPECT_MORE_WORDS; return OP_EXPECT_MORE_WORDS;
} }
@ -79,14 +86,15 @@ char * r3_inside_slug(const char * needle, int needle_len, char *offset, char **
return NULL; 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 *c;
char *s2; char *s2;
int cnt = 0; int cnt = 0;
if ( NULL != (c = strchr(s1, '{')) ) { if (c = strnchr(s1, str_len, '{')) {
// find closing '}' // find closing '}'
s2 = c; s2 = c;
while(*s2) { unsigned int j = str_len - (c - s1);
for (unsigned int i = 0; i < j; i++) {
if (*s2 == '{' ) if (*s2 == '{' )
cnt++; cnt++;
else if (*s2 == '}' ) 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 * 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 *c;
char *s2; char *s2;
int cnt = 1; unsigned int cnt = 1;
if ( NULL != (c = strchr(s1, ':')) ) { if ( (c = strnchr(s1, str_len, ':')) ) {
c++; c++;
// find closing '}' // find closing '}'
s2 = c; s2 = c;
while(s2) { unsigned int j = str_len - (c - s1);
for (unsigned int i = 0; i < j; i++) {
if (*s2 == '{' ) if (*s2 == '{' )
cnt++; cnt++;
else if (*s2 == '}' ) else if (*s2 == '}' )
@ -132,6 +141,9 @@ char * r3_slug_find_pattern(const char *s1, int *len) {
} else { } else {
return NULL; return NULL;
} }
if (cnt!=0) {
return NULL;
}
*len = s2 - c; *len = s2 - c;
return 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 * 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 * c;
char * s2; char * s2;
int cnt = 0; int cnt = 0;
c = (char*) s1; unsigned int plholder;
if (c = r3_slug_find_placeholder(s1, str_len, &plholder)) {
while(1) { c++;
if(*c == '{') cnt++; if ( s2 = strnchr(c, plholder, ':') ) {
if(*c == '}') cnt--; *len = s2 - c;
if(*c == ':') break; return c;
if(*c == '\0') return NULL; } else {
if(cnt == 0) break; *len = plholder - 2;
c++; 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 * @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 *s1 = NULL, *o = NULL;
char *pat = NULL; char *pat = NULL;
@ -179,15 +183,15 @@ char * r3_slug_compile(const char * str, int len)
// append prefix // append prefix
int s1_len; unsigned int s1_len;
s1 = r3_slug_find_placeholder(str, &s1_len); s1 = r3_slug_find_placeholder(str, len, &s1_len);
if ( s1 == NULL ) { if ( !s1 ) {
return zstrdup(str); return zstrndup(str,len);
} }
char * out = NULL; char * out = NULL;
if ((out = zcalloc(sizeof(char) * 200)) == NULL) { if (!(out = zcalloc(sizeof(char) * 200))) {
return (NULL); return (NULL);
} }
@ -199,8 +203,8 @@ char * r3_slug_compile(const char * str, int len)
o += (s1 - str); o += (s1 - str);
int pat_len; unsigned int pat_len;
pat = r3_slug_find_pattern(s1, &pat_len); pat = r3_slug_find_pattern(s1, s1_len, &pat_len);
if (pat) { if (pat) {
*o = '('; *o = '(';
@ -214,7 +218,7 @@ char * r3_slug_compile(const char * str, int len)
o+= strlen("([^*]+)"); o+= strlen("([^*]+)");
} }
s1 += s1_len; s1 += s1_len;
strncat(o, s1, strlen(s1)); strncat(o, s1, len - (s1 - str)); // string after slug
return out; return out;
} }

View file

@ -13,83 +13,44 @@
#include "r3_slug.h" #include "r3_slug.h"
#include "str_array.h" #include "str_array.h"
#include "zmalloc.h" #include "zmalloc.h"
#include "memory.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;
}
void str_array_free(str_array *l) { void str_array_free(str_array *l) {
assert(l); assert(l);
for ( int i = 0; i < l->len ; i++ ) { free(l->tokens.entries);
if (l->tokens[ i ]) {
zfree(l->tokens[i]);
}
}
zfree(l->tokens);
zfree(l);
} }
bool str_array_slugs_full(const str_array * l) { bool str_array_append(str_array * l, char * token, unsigned int len) {
return l->slugs_len >= l->cap; R3_VECTOR(r3_iovec_t) *tks = &l->tokens;
} r3_vector_reserve(NULL, tks, tks->size + 1);
r3_iovec_t *temp = tks->entries + tks->size++;
bool str_array_tokens_full(const str_array * l) { memset(temp, 0, sizeof(*temp));
return l->len >= l->cap; temp->base = token;
} temp->len = len;
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;
return true; return true;
} }
void str_array_dump_slugs(const str_array *l) { void str_array_dump_slugs(const str_array *l) {
printf("["); if (l->tokens.size) {
for ( int i = 0; i < l->slugs_len ; i++ ) { printf("[");
printf("\"%s\"", l->slugs[i] ); for ( int i = 0; i < l->tokens.size ; i++ ) {
if ( i + 1 != l->slugs_len ) { printf("\"%*.*s\"", l->slugs.entries[i].len,l->slugs.entries[i].len,l->slugs.entries[i].base );
printf(", "); if ( i + 1 != l->tokens.size ) {
printf(", ");
}
} }
printf("]\n");
} else {
printf("[]\n");
} }
printf("]\n");
} }
void str_array_dump(const str_array *l) { void str_array_dump(const str_array *l) {
printf("["); printf("[");
for ( int i = 0; i < l->len ; i++ ) { for ( int i = 0; i < l->tokens.size ; i++ ) {
printf("\"%s\"", l->tokens[i] ); printf("\"%*.*s\"", l->tokens.entries[i].len,l->tokens.entries[i].len,l->tokens.entries[i].base );
if ( i + 1 != l->len ) { // printf("\"%s\"", l->tokens.entries[i] );
if ( i + 1 != l->tokens.size ) {
printf(", "); printf(", ");
} }
} }

View file

@ -1,6 +1,6 @@
TESTS = 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 AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS) @CHECK_LIBS@ $(top_builddir)/libr3.la
if USE_JEMALLOC if USE_JEMALLOC

View file

@ -464,7 +464,8 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL);
R3Node * tree2 = r3_tree_create(1); R3Node * tree2 = r3_tree_create(1);
r3_tree_insert_path(tree2, "/post/{year}/{month}", NULL); r3_tree_insert_path(tree2, "/post/{year}/{month}", NULL);
r3_tree_compile(tree2, NULL); r3_tree_compile(tree2, NULL);
// r3_tree_dump(tree2,0);
BENCHMARK(pcre_dispatch) BENCHMARK(pcre_dispatch)
r3_tree_matchl(tree2, "/post/2014/12", strlen("/post/2014/12"), NULL); r3_tree_matchl(tree2, "/post/2014/12", strlen("/post/2014/12"), NULL);
END_BENCHMARK(pcre_dispatch) END_BENCHMARK(pcre_dispatch)

View file

@ -46,14 +46,16 @@ END_TEST
START_TEST (test_contains_slug) 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 END_TEST
START_TEST (test_r3_slug_find_pattern) START_TEST (test_r3_slug_find_pattern)
{ {
int len; 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 ); ck_assert( strncmp(namerex, "\\s+", len) == 0 );
} }
END_TEST END_TEST
@ -61,7 +63,8 @@ END_TEST
START_TEST (test_r3_slug_find_name) START_TEST (test_r3_slug_find_name)
{ {
int len; 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 ); ck_assert( strncmp(namerex, "name", len) == 0 );
} }
END_TEST END_TEST
@ -69,7 +72,8 @@ END_TEST
START_TEST (test_r3_slug_find_name_without_pattern) START_TEST (test_r3_slug_find_name_without_pattern)
{ {
int len; 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 ); ck_assert( strncmp(namerex, "name", len) == 0 );
} }
END_TEST END_TEST
@ -77,7 +81,8 @@ END_TEST
START_TEST (test_r3_slug_find_name_with_multiple_slug) START_TEST (test_r3_slug_find_name_with_multiple_slug)
{ {
int len; 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 ); ck_assert( strncmp(namerex, "name", len) == 0 );
} }
END_TEST END_TEST
@ -86,11 +91,12 @@ START_TEST (test_r3_slug_find_placeholder)
{ {
int slug_len = 0; int slug_len = 0;
char * slug; 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 ); ck_assert( strncmp(slug, "{name:\\s+}", slug_len) == 0 );
test_str = "/user/{idx:\\d{3}}/to/{idy:\\d{3}}";
slug = r3_slug_find_placeholder("/user/{idx:\\d{3}}/to/{idy:\\d{3}}", &slug_len); slug = r3_slug_find_placeholder(test_str, strlen(test_str), &slug_len);
ck_assert( slug_len == strlen("{idx:\\d{3}}") ); ck_assert( slug_len == strlen("{idx:\\d{3}}") );
ck_assert( strncmp(slug, "{idx:\\d{3}}", slug_len) == 0 ); 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) START_TEST (test_r3_slug_find_placeholder_with_broken_slug)
{ {
int slug_len = 0; 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); ck_assert(slug == 0);
} }
END_TEST END_TEST

View file

@ -14,23 +14,26 @@
START_TEST (test_str_array) START_TEST (test_str_array)
{ {
str_array * l = str_array_create(3); match_entry * entry = match_entry_create("/foo");
ck_assert(l); ck_assert(entry);
ck_assert(str_array_append(l, zstrdup("abc"))); char *test_str = "abc";
ck_assert( l->len == 1 ); 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") )); char *test_str1 = "foo";
ck_assert( l->len == 2 ); 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") ) ); char *test_str2 = "bar";
ck_assert( l->len == 3 ); 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") ) ); char *test_str3 = "zoo";
ck_assert( l->len == 4 ); 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) ); match_entry_free(entry);
str_array_free(l);
} }
END_TEST END_TEST

View file

@ -15,9 +15,10 @@
START_TEST (test_find_common_prefix) START_TEST (test_find_common_prefix)
{ {
char *test_str = "/foo/{slug}";
R3Node * n = r3_tree_create(10); R3Node * n = r3_tree_create(10);
R3Edge * e = r3_edge_createl(zstrdup("/foo/{slug}"), sizeof("/foo/{slug}")-1, NULL); R3Edge * e = r3_node_append_edge(n);
r3_node_append_edge(n,e); r3_edge_initl(e, test_str, strlen(test_str), NULL);
char *errstr = NULL; char *errstr = NULL;
int prefix_len = 0; int prefix_len = 0;
@ -25,14 +26,16 @@ START_TEST (test_find_common_prefix)
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(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 4); ck_assert_int_eq(prefix_len, 4);
SAFE_FREE(errstr); SAFE_FREE(errstr);
errstr = NULL; 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(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 5); ck_assert_int_eq(prefix_len, 5);
SAFE_FREE(errstr); SAFE_FREE(errstr);
@ -40,35 +43,40 @@ START_TEST (test_find_common_prefix)
errstr = NULL; errstr = NULL;
prefix_len = 0; 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(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 5); ck_assert_int_eq(prefix_len, 5);
SAFE_FREE(errstr); SAFE_FREE(errstr);
errstr = NULL; 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(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 5); ck_assert_int_eq(prefix_len, 5);
SAFE_FREE(errstr); SAFE_FREE(errstr);
errstr = NULL; 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(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 5); ck_assert_int_eq(prefix_len, 5);
SAFE_FREE(errstr); SAFE_FREE(errstr);
errstr = NULL; 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(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 1); ck_assert_int_eq(prefix_len, 1);
SAFE_FREE(errstr); SAFE_FREE(errstr);
errstr = NULL; 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(ret_edge == NULL);
ck_assert_int_eq(prefix_len, 0); ck_assert_int_eq(prefix_len, 0);
SAFE_FREE(errstr); SAFE_FREE(errstr);
@ -84,30 +92,34 @@ END_TEST
START_TEST (test_find_common_prefix_after) START_TEST (test_find_common_prefix_after)
{ {
char *test_str = "{slug}/foo";
R3Node * n = r3_tree_create(10); R3Node * n = r3_tree_create(10);
R3Edge * e = r3_edge_createl(zstrdup("{slug}/foo"), sizeof("{slug}/foo")-1, NULL); R3Edge * e = r3_node_append_edge(n);
r3_node_append_edge(n,e); r3_edge_initl(e, test_str, strlen(test_str), NULL);
int prefix_len = 0; int prefix_len = 0;
R3Edge *ret_edge = NULL; R3Edge *ret_edge = NULL;
char *errstr = NULL; char *errstr = NULL;
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(ret_edge == NULL);
ck_assert_int_eq(prefix_len, 0); ck_assert_int_eq(prefix_len, 0);
SAFE_FREE(errstr); SAFE_FREE(errstr);
errstr = NULL; 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(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 7); ck_assert_int_eq(prefix_len, 7);
SAFE_FREE(errstr); SAFE_FREE(errstr);
errstr = NULL; 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(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 10); ck_assert_int_eq(prefix_len, 10);
SAFE_FREE(errstr); SAFE_FREE(errstr);
@ -121,16 +133,18 @@ END_TEST
START_TEST (test_find_common_prefix_double_middle) START_TEST (test_find_common_prefix_double_middle)
{ {
char *test_str = "{slug}/foo/{name}";
R3Node * n = r3_tree_create(10); R3Node * n = r3_tree_create(10);
R3Edge * e = r3_edge_createl(zstrdup("{slug}/foo/{name}"), sizeof("{slug}/foo/{name}")-1, NULL); R3Edge * e = r3_node_append_edge(n);
r3_node_append_edge(n,e); r3_edge_initl(e, test_str, strlen(test_str), NULL);
int prefix_len; int prefix_len;
R3Edge *ret_edge = NULL; R3Edge *ret_edge = NULL;
char *errstr; char *errstr;
errstr = NULL; 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(ret_edge);
ck_assert_int_eq(prefix_len, 11); ck_assert_int_eq(prefix_len, 11);
SAFE_FREE(errstr); SAFE_FREE(errstr);
@ -144,21 +158,24 @@ END_TEST
START_TEST (test_find_common_prefix_middle) START_TEST (test_find_common_prefix_middle)
{ {
R3Node * n = r3_tree_create(10); R3Node * n = r3_tree_create(10);
R3Edge * e = r3_edge_createl(zstrdup("/foo/{slug}/hate"), sizeof("/foo/{slug}/hate")-1, NULL); char *test_str = "/foo/{slug}/hate";
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; int prefix_len;
R3Edge *ret_edge = NULL; R3Edge *ret_edge = NULL;
char *errstr = NULL; char *errstr = NULL;
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(ret_edge);
ck_assert_int_eq(prefix_len, 12); ck_assert_int_eq(prefix_len, 12);
SAFE_FREE(errstr); SAFE_FREE(errstr);
errstr = NULL; 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(ret_edge);
ck_assert_int_eq(prefix_len, 3); ck_assert_int_eq(prefix_len, 3);
SAFE_FREE(errstr); SAFE_FREE(errstr);
@ -170,8 +187,9 @@ END_TEST
START_TEST (test_find_common_prefix_same_pattern) START_TEST (test_find_common_prefix_same_pattern)
{ {
R3Node * n = r3_tree_create(10); R3Node * n = r3_tree_create(10);
R3Edge * e = r3_edge_createl(zstrdup("/foo/{slug:xxx}/hate"), sizeof("/foo/{slug:xxx}/hate")-1, NULL); char *test_str = "/foo/{slug:xxx}/hate";
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; int prefix_len;
R3Edge *ret_edge = NULL; R3Edge *ret_edge = NULL;
@ -194,8 +212,9 @@ END_TEST
START_TEST (test_find_common_prefix_same_pattern2) START_TEST (test_find_common_prefix_same_pattern2)
{ {
R3Node * n = r3_tree_create(10); R3Node * n = r3_tree_create(10);
R3Edge * e = r3_edge_createl(zstrdup("{slug:xxx}/hate"), sizeof("{slug:xxx}/hate")-1, NULL); char *test_str = "{slug:xxx}/hate";
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; int prefix_len;
R3Edge *ret_edge = NULL; R3Edge *ret_edge = NULL;
@ -443,7 +462,7 @@ START_TEST (test_pcre_patterns_insert_2)
// r3_tree_dump(n, 0); // r3_tree_dump(n, 0);
R3Node *matched; R3Node *matched;
matched = r3_tree_match(n, "/post/11/22", NULL); matched = r3_tree_match(n, "/post/11/22", NULL);
ck_assert((int)matched); ck_assert(matched);
ck_assert(matched->endpoint > 0); ck_assert(matched->endpoint > 0);
} }
END_TEST END_TEST
@ -473,7 +492,7 @@ START_TEST (test_pcre_patterns_insert_3)
matched = r3_tree_match(n, "/post/11/22", NULL); matched = r3_tree_match(n, "/post/11/22", NULL);
ck_assert((int)matched); ck_assert(matched);
matched = r3_tree_match(n, "/post/11", NULL); matched = r3_tree_match(n, "/post/11", NULL);
ck_assert(!matched); ck_assert(!matched);
@ -497,7 +516,7 @@ START_TEST (test_insert_pathl_fail)
R3Node * ret; R3Node * ret;
char *errstr = NULL; 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(ret == NULL);
ck_assert(errstr != NULL); ck_assert(errstr != NULL);
printf("%s\n", errstr); // Returns Incomplete slug pattern. PATTERN (16): '/foo/{name:\d{5}', OFFSET: 16, STATE: 1 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) 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"); match_entry * m = match_entry_create("/blog/post");
fail_if( r3_route_cmp(r1, m) == -1, "should match"); fail_if( r3_route_cmp(r1, m) == -1, "should match");
@ -627,6 +648,7 @@ START_TEST(test_route_cmp)
r3_route_free(r1); r3_route_free(r1);
match_entry_free(m); match_entry_free(m);
r3_tree_free(n);
} }
END_TEST END_TEST
@ -643,8 +665,8 @@ START_TEST(test_pcre_pattern_simple)
R3Node *matched; R3Node *matched;
matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry); matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry);
ck_assert(matched); ck_assert(matched);
ck_assert(entry->vars->len > 0); ck_assert(entry->vars.tokens.size > 0);
ck_assert_str_eq(entry->vars->tokens[0],"123"); ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123");
r3_tree_free(n); r3_tree_free(n);
} }
END_TEST END_TEST
@ -653,7 +675,8 @@ END_TEST
START_TEST(test_pcre_pattern_more) START_TEST(test_pcre_pattern_more)
{ {
match_entry * entry; 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); R3Node * n = r3_tree_create(10);
int var0 = 5; int var0 = 5;
@ -674,25 +697,26 @@ START_TEST(test_pcre_pattern_more)
// r3_tree_dump(n, 0); // r3_tree_dump(n, 0);
R3Node *matched; 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(matched);
ck_assert(entry->vars->len > 0); ck_assert(entry->vars.tokens.size > 0);
ck_assert_str_eq(entry->vars->tokens[0],"123"); ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123");
info("matched %p\n", matched->data);
info("matched %p\n", matched->data); info("matched %p\n", matched->data);
ck_assert_int_eq( *((int*) matched->data), var1); ck_assert_int_eq( *((int*) matched->data), var1);
matched = r3_tree_matchl(n, "/user2/123", strlen("/user2/123"), entry); matched = r3_tree_matchl(n, "/user2/123", strlen("/user2/123"), entry);
ck_assert(matched); ck_assert(matched);
ck_assert(entry->vars->len > 0); ck_assert(entry->vars.tokens.size > 0);
ck_assert_str_eq(entry->vars->tokens[0],"123"); 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); ck_assert_int_eq( *((int*)matched->data), var2);
matched = r3_tree_matchl(n, "/user3/123", strlen("/user3/123"), entry); matched = r3_tree_matchl(n, "/user3/123", strlen("/user3/123"), entry);
ck_assert(matched); ck_assert(matched);
ck_assert(entry->vars->len > 0); ck_assert(entry->vars.tokens.size > 0);
ck_assert_str_eq(entry->vars->tokens[0],"123"); 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); ck_assert_int_eq( *((int*)matched->data), var3);
r3_tree_free(n); r3_tree_free(n);
@ -707,9 +731,9 @@ START_TEST(test_insert_pathl_before_root)
int var2 = 33; int var2 = 33;
int var3 = 44; int var3 = 44;
R3Node * n = r3_tree_create(3); 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/post"), 0, 0, &var1, NULL);
r3_tree_insert_pathl_ex(n, STR("/blog"), NULL, &var2, NULL); r3_tree_insert_pathl_ex(n, STR("/blog"), 0, 0, &var2, NULL);
r3_tree_insert_pathl_ex(n, STR("/"), NULL, &var3, NULL); r3_tree_insert_pathl_ex(n, STR("/"), 0, 0, &var3, NULL);
errstr = NULL; errstr = NULL;
r3_tree_compile(n, &errstr); r3_tree_compile(n, &errstr);