Added slug parser and repaired few memory leaks
This commit is contained in:
parent
c609003c95
commit
400768394d
5 changed files with 134 additions and 31 deletions
|
@ -46,7 +46,7 @@ typedef struct _node R3Node;
|
||||||
typedef struct _R3Route R3Route;
|
typedef struct _R3Route R3Route;
|
||||||
|
|
||||||
struct _node {
|
struct _node {
|
||||||
R3Edge * edges;
|
R3Edge ** edges;
|
||||||
char * combined_pattern;
|
char * combined_pattern;
|
||||||
pcre * pcre_pattern;
|
pcre * pcre_pattern;
|
||||||
pcre_extra * pcre_extra;
|
pcre_extra * pcre_extra;
|
||||||
|
@ -83,6 +83,10 @@ struct _R3Route {
|
||||||
char * path;
|
char * path;
|
||||||
int path_len;
|
int path_len;
|
||||||
|
|
||||||
|
char **slugs;
|
||||||
|
int slugs_len;
|
||||||
|
int slugs_cap;
|
||||||
|
|
||||||
int request_method; // can be (GET || POST)
|
int request_method; // can be (GET || POST)
|
||||||
|
|
||||||
char * host; // required host name
|
char * host; // required host name
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#define STR_ARRAY_H
|
#define STR_ARRAY_H
|
||||||
|
|
||||||
typedef struct _str_array {
|
typedef struct _str_array {
|
||||||
|
char **slugs;
|
||||||
|
int slugs_len;
|
||||||
char **tokens;
|
char **tokens;
|
||||||
int len;
|
int len;
|
||||||
int cap;
|
int cap;
|
||||||
|
@ -16,14 +18,20 @@ typedef struct _str_array {
|
||||||
|
|
||||||
str_array * str_array_create(int cap);
|
str_array * str_array_create(int cap);
|
||||||
|
|
||||||
bool str_array_is_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_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(str_array * list, char * token);
|
bool str_array_append(str_array * list, char * token);
|
||||||
|
|
||||||
void str_array_free(str_array *l);
|
void str_array_free(str_array *l);
|
||||||
|
|
||||||
|
void str_array_dump_slugs(const str_array *l);
|
||||||
|
|
||||||
void str_array_dump(const str_array *l);
|
void str_array_dump(const str_array *l);
|
||||||
|
|
||||||
str_array * split_route_pattern(char *pattern, int pattern_len);
|
str_array * split_route_pattern(char *pattern, int pattern_len);
|
||||||
|
|
12
src/edge.c
12
src/edge.c
|
@ -86,11 +86,13 @@ R3Node * r3_edge_branch(R3Edge *e, int dl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void r3_edge_free(R3Edge * e) {
|
void r3_edge_free(R3Edge * e) {
|
||||||
zfree(e->pattern);
|
if (e) {
|
||||||
if ( e->child ) {
|
zfree(e->pattern);
|
||||||
r3_tree_free(e->child);
|
if ( e->child ) {
|
||||||
|
r3_tree_free(e->child);
|
||||||
|
}
|
||||||
|
// free itself
|
||||||
|
zfree(e);
|
||||||
}
|
}
|
||||||
// free itself
|
|
||||||
zfree(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
101
src/node.c
101
src/node.c
|
@ -56,7 +56,7 @@ R3Node * r3_tree_create(int cap) {
|
||||||
R3Node * n = (R3Node*) zmalloc( sizeof(R3Node) );
|
R3Node * n = (R3Node*) zmalloc( sizeof(R3Node) );
|
||||||
CHECK_PTR(n);
|
CHECK_PTR(n);
|
||||||
|
|
||||||
n->edges = (R3Edge*) zmalloc(sizeof(R3Edge) * cap);
|
n->edges = zmalloc(sizeof(R3Edge) * cap);
|
||||||
CHECK_PTR(n->edges);
|
CHECK_PTR(n->edges);
|
||||||
n->edge_len = 0;
|
n->edge_len = 0;
|
||||||
n->edge_cap = cap;
|
n->edge_cap = cap;
|
||||||
|
@ -66,6 +66,7 @@ R3Node * r3_tree_create(int cap) {
|
||||||
n->route_cap = 0;
|
n->route_cap = 0;
|
||||||
|
|
||||||
n->endpoint = 0;
|
n->endpoint = 0;
|
||||||
|
n->compare_type = NODE_COMPARE_STR;
|
||||||
n->combined_pattern = NULL;
|
n->combined_pattern = NULL;
|
||||||
n->pcre_pattern = NULL;
|
n->pcre_pattern = NULL;
|
||||||
n->pcre_extra = NULL;
|
n->pcre_extra = NULL;
|
||||||
|
@ -75,9 +76,17 @@ R3Node * r3_tree_create(int cap) {
|
||||||
|
|
||||||
void r3_tree_free(R3Node * tree) {
|
void r3_tree_free(R3Node * tree) {
|
||||||
if (tree->edges) {
|
if (tree->edges) {
|
||||||
|
for (int j=0;j<tree->edge_len;j++) {
|
||||||
|
r3_edge_free(tree->edges[j]);
|
||||||
|
}
|
||||||
zfree(tree->edges);
|
zfree(tree->edges);
|
||||||
}
|
}
|
||||||
zfree(tree->routes);
|
if (tree->routes) {
|
||||||
|
for (int k=0;k<tree->route_len;k++) {
|
||||||
|
r3_route_free(tree->routes[k]);
|
||||||
|
}
|
||||||
|
zfree(tree->routes);
|
||||||
|
}
|
||||||
if (tree->pcre_pattern) {
|
if (tree->pcre_pattern) {
|
||||||
pcre_free(tree->pcre_pattern);
|
pcre_free(tree->pcre_pattern);
|
||||||
}
|
}
|
||||||
|
@ -110,8 +119,7 @@ R3Edge * r3_node_connectl(R3Node * n, const char * pat, int len, int dupl, R3Nod
|
||||||
}
|
}
|
||||||
e = r3_edge_createl(pat, len, child);
|
e = r3_edge_createl(pat, len, child);
|
||||||
CHECK_PTR(e);
|
CHECK_PTR(e);
|
||||||
R3Edge *e2 = r3_node_append_edge(n, e);
|
R3Edge * e2 = r3_node_append_edge(n, e);
|
||||||
zfree(e);
|
|
||||||
return e2;
|
return e2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,10 +137,9 @@ R3Edge * r3_node_append_edge(R3Node *n, R3Edge *e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// r3_edge_initl(
|
// Insert edge into edge array
|
||||||
// copy 'edge' into the edge array
|
n->edges[n->edge_len] = e;
|
||||||
n->edges[n->edge_len] = *e;
|
return n->edges[n->edge_len++];
|
||||||
return &n->edges[n->edge_len++];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -145,7 +152,7 @@ R3Edge * r3_node_find_edge(const R3Node * n, const char * pat, int pat_len) {
|
||||||
R3Edge * e;
|
R3Edge * e;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0 ; i < n->edge_len ; i++ ) {
|
for (i = 0 ; i < n->edge_len ; i++ ) {
|
||||||
e = &n->edges[i];
|
e = n->edges[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 (strcmp(e->pattern, pat) == 0) {
|
||||||
|
@ -170,7 +177,7 @@ int r3_tree_compile(R3Node *n, char **errstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0 ; i < n->edge_len ; i++ ) {
|
for (i = 0 ; i < n->edge_len ; i++ ) {
|
||||||
if ((ret = r3_tree_compile(n->edges[i].child, errstr))) {
|
if ((ret = r3_tree_compile(n->edges[i]->child, errstr))) {
|
||||||
return ret; // stop here if error occurs
|
return ret; // stop here if error occurs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,7 +204,7 @@ int r3_tree_compile_patterns(R3Node * n, char **errstr) {
|
||||||
int opcode_cnt = 0;
|
int opcode_cnt = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < n->edge_len ; i++) {
|
for (; i < n->edge_len ; i++) {
|
||||||
e = &n->edges[i];
|
e = n->edges[i];
|
||||||
if (e->opcode) {
|
if (e->opcode) {
|
||||||
opcode_cnt++;
|
opcode_cnt++;
|
||||||
}
|
}
|
||||||
|
@ -206,6 +213,7 @@ int r3_tree_compile_patterns(R3Node * n, char **errstr) {
|
||||||
// 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, e->pattern_len);
|
||||||
strcat(p, slug_pat);
|
strcat(p, slug_pat);
|
||||||
|
zfree(slug_pat);
|
||||||
} else {
|
} else {
|
||||||
strncat(p,"^(", 2);
|
strncat(p,"^(", 2);
|
||||||
p += 2;
|
p += 2;
|
||||||
|
@ -298,7 +306,7 @@ R3Node * r3_tree_matchl(const R3Node * n, const char * path, int path_len, match
|
||||||
|
|
||||||
for (i = n->edge_len; i--; ) {
|
for (i = n->edge_len; i--; ) {
|
||||||
pp = path;
|
pp = path;
|
||||||
e = &n->edges[i];
|
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++;
|
||||||
|
@ -384,7 +392,7 @@ R3Node * r3_tree_matchl(const R3Node * n, const char * path, int path_len, match
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
substring_start = path + ov[2*i];
|
substring_start = path + ov[2*i];
|
||||||
e = &n->edges[i - 1];
|
e = n->edges[i - 1];
|
||||||
|
|
||||||
if (entry && e->has_slug) {
|
if (entry && e->has_slug) {
|
||||||
// append captured token to entry
|
// append captured token to entry
|
||||||
|
@ -408,7 +416,7 @@ R3Node * r3_tree_matchl(const R3Node * n, const char * path, int path_len, match
|
||||||
}
|
}
|
||||||
|
|
||||||
substring_start = path + ov[2*i];
|
substring_start = path + ov[2*i];
|
||||||
e = &n->edges[i - 1];
|
e = n->edges[i - 1];
|
||||||
|
|
||||||
if (entry && e->has_slug) {
|
if (entry && e->has_slug) {
|
||||||
// append captured token to entry
|
// append captured token to entry
|
||||||
|
@ -441,6 +449,10 @@ R3Route * r3_tree_match_route(const R3Node *tree, match_entry * entry) {
|
||||||
if (n && n->routes && n->route_len > 0) {
|
if (n && n->routes && n->route_len > 0) {
|
||||||
for (i = n->route_len; i--; ) {
|
for (i = n->route_len; i--; ) {
|
||||||
if ( r3_route_cmp(n->routes[i], entry) == 0 ) {
|
if ( r3_route_cmp(n->routes[i], entry) == 0 ) {
|
||||||
|
// Add slugs from found route to match_entry
|
||||||
|
for (int j = 0; j < n->routes[i]->slugs_len; j++) {
|
||||||
|
str_array_append_slug(entry->vars , n->routes[i]->slugs[j]);
|
||||||
|
}
|
||||||
return n->routes[i];
|
return n->routes[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,10 +465,10 @@ inline R3Edge * r3_node_find_edge_str(const R3Node * n, const char * str, int st
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
char firstbyte = *str;
|
char firstbyte = *str;
|
||||||
for (i = n->edge_len; i--; ) {
|
for (i = n->edge_len; i--; ) {
|
||||||
e = &n->edges[i];
|
e = n->edges[i];
|
||||||
if (firstbyte == e->pattern[0]) {
|
if (firstbyte == e->pattern[0]) {
|
||||||
if (strncmp(e->pattern, str, e->pattern_len) == 0) {
|
if (strncmp(e->pattern, str, e->pattern_len) == 0) {
|
||||||
return &n->edges[i];
|
return n->edges[i];
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -484,12 +496,59 @@ R3Node * r3_node_create() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void r3_route_free(R3Route * route) {
|
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);
|
zfree(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 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;
|
||||||
|
while(1) {
|
||||||
|
plh = r3_slug_find_placeholder(plh+l,&l);
|
||||||
|
if (plh == NULL) break;
|
||||||
|
namel = 0;
|
||||||
|
name = r3_slug_find_name(plh,&namel);
|
||||||
|
router_append_slug(route,zstrndup(name,namel));
|
||||||
|
if ((plh + l) >= (path + path_len)) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
R3Route * r3_route_createl(const char * path, int path_len) {
|
R3Route * r3_route_createl(const char * path, int path_len) {
|
||||||
R3Route * info = zmalloc(sizeof(R3Route));
|
R3Route * info = zmalloc(sizeof(R3Route));
|
||||||
CHECK_PTR(info);
|
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 = (char*) path;
|
||||||
info->path_len = path_len;
|
info->path_len = path_len;
|
||||||
info->request_method = 0; // can be (GET || POST)
|
info->request_method = 0; // can be (GET || POST)
|
||||||
|
@ -544,11 +603,11 @@ R3Edge * r3_node_find_common_prefix(R3Node *n, const char *path, int path_len, i
|
||||||
R3Edge *e = NULL;
|
R3Edge *e = NULL;
|
||||||
for(i = 0 ; i < n->edge_len ; i++ ) {
|
for(i = 0 ; i < n->edge_len ; 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[i]->pattern, n->edges[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[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -660,7 +719,7 @@ R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, int path_len, R
|
||||||
R3Node * child = r3_tree_create(3);
|
R3Node * child = r3_tree_create(3);
|
||||||
CHECK_PTR(child);
|
CHECK_PTR(child);
|
||||||
|
|
||||||
r3_node_connect(n, zstrndup(path, (int)(p - path)), child);
|
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), route, data, errstr);
|
||||||
|
@ -775,7 +834,7 @@ bool r3_node_has_slug_edges(const R3Node *n) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
R3Edge *e;
|
R3Edge *e;
|
||||||
for ( int i = 0 ; i < n->edge_len ; i++ ) {
|
for ( int i = 0 ; i < n->edge_len ; i++ ) {
|
||||||
e = &n->edges[i];
|
e = n->edges[i];
|
||||||
e->has_slug = r3_path_contains_slug_char(e->pattern);
|
e->has_slug = r3_path_contains_slug_char(e->pattern);
|
||||||
if (e->has_slug)
|
if (e->has_slug)
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -802,7 +861,7 @@ 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->edge_len ; i++ ) {
|
||||||
R3Edge * e = &n->edges[i];
|
R3Edge * e = n->edges[i];
|
||||||
print_indent(level + 1);
|
print_indent(level + 1);
|
||||||
printf("|-\"%s\"", e->pattern);
|
printf("|-\"%s\"", e->pattern);
|
||||||
|
|
||||||
|
|
36
src/token.c
36
src/token.c
|
@ -19,7 +19,9 @@ str_array * str_array_create(int cap) {
|
||||||
if (!list)
|
if (!list)
|
||||||
return NULL;
|
return NULL;
|
||||||
list->len = 0;
|
list->len = 0;
|
||||||
|
list->slugs_len = 0;
|
||||||
list->cap = cap;
|
list->cap = cap;
|
||||||
|
list->slugs = (char**) zmalloc( sizeof(char*) * cap);
|
||||||
list->tokens = (char**) zmalloc( sizeof(char*) * cap);
|
list->tokens = (char**) zmalloc( sizeof(char*) * cap);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -31,22 +33,39 @@ void str_array_free(str_array *l) {
|
||||||
zfree(l->tokens[i]);
|
zfree(l->tokens[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
zfree(l->slugs);
|
||||||
zfree(l->tokens);
|
zfree(l->tokens);
|
||||||
zfree(l);
|
zfree(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool str_array_is_full(const str_array * l) {
|
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;
|
return l->len >= l->cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool str_array_resize(str_array * l, int new_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->tokens = zrealloc(l->tokens, sizeof(char**) * new_cap);
|
||||||
l->cap = new_cap;
|
l->cap = new_cap;
|
||||||
return l->tokens != NULL;
|
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) {
|
bool str_array_append(str_array * l, char * token) {
|
||||||
if ( str_array_is_full(l) ) {
|
if ( str_array_tokens_full(l) ) {
|
||||||
bool ret = str_array_resize(l, l->cap + 20);
|
bool ret = str_array_resize(l, l->cap + 20);
|
||||||
if (ret == false ) {
|
if (ret == false ) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -56,6 +75,17 @@ bool str_array_append(str_array * l, char * token) {
|
||||||
return true;
|
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(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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->len ; i++ ) {
|
||||||
|
|
Loading…
Reference in a new issue