Merge branch 'krn_feature' of https://github.com/karantin2020/r3 into 2.0
This commit is contained in:
commit
341a29387b
25 changed files with 1405 additions and 467 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -51,3 +51,7 @@ autoscan.log
|
||||||
r3.pc
|
r3.pc
|
||||||
stamp-h1
|
stamp-h1
|
||||||
tests/bench_str.csv
|
tests/bench_str.csv
|
||||||
|
|
||||||
|
config.h.in
|
||||||
|
examples/simple
|
||||||
|
examples/simple_cpp
|
95
examples/routing.c
Normal file
95
examples/routing.c
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* check_slug.c
|
||||||
|
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "../include/r3.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void test1(void) {
|
||||||
|
R3Node *n = r3_tree_create(10);
|
||||||
|
|
||||||
|
int route_data1 = 3;
|
||||||
|
int route_data2 = 44;
|
||||||
|
int route_data3 = 555;
|
||||||
|
|
||||||
|
// insert the R3Route path into the router tree
|
||||||
|
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog", sizeof("/blog") - 1, &route_data1 );
|
||||||
|
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/{idl:\\d+}/asf/{id}", strlen("/blog/{idl:\\d+}/asf/{id}"), &route_data2 );
|
||||||
|
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog3/{idl:\\d{3}}/asd/{id:[0-9]+}/qwe", sizeof("/blog3/{idl:\\d{3}}/asd/{id:[0-9]+}/qwe") - 1, &route_data3 );
|
||||||
|
|
||||||
|
char *errstr = NULL;
|
||||||
|
int err = r3_tree_compile(n, &errstr);
|
||||||
|
if (err != 0) {
|
||||||
|
// fail
|
||||||
|
printf("error: %s\n", errstr);
|
||||||
|
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
|
||||||
|
}
|
||||||
|
// r3_tree_dump(n,0);
|
||||||
|
|
||||||
|
|
||||||
|
// in your http server handler
|
||||||
|
|
||||||
|
// create the match entry for capturing dynamic variables.
|
||||||
|
match_entry * entry;
|
||||||
|
R3Route *matched_route;
|
||||||
|
int i;
|
||||||
|
for (int k = 0; k < 3000000; k++) {
|
||||||
|
// printf("round N%d\n",k);
|
||||||
|
entry = match_entry_create("/blog/432/asf/678");
|
||||||
|
entry->request_method = METHOD_GET;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
// if (matched_route) {
|
||||||
|
// printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route
|
||||||
|
// if (entry->vars.tokens.size == entry->vars.slugs.size) {
|
||||||
|
// for (i = 0; i < entry->vars.tokens.size; i++) {
|
||||||
|
// // entry->vars.slugs.entries[i];
|
||||||
|
// // entry->vars.tokens.entries[i];
|
||||||
|
// printf("Slug name is: %*.*s\n",entry->vars.slugs.entries[i].len,
|
||||||
|
// entry->vars.slugs.entries[i].len, entry->vars.slugs.entries[i].base);
|
||||||
|
// printf("Slug value is: %*.*s\n",entry->vars.tokens.entries[i].len,
|
||||||
|
// entry->vars.tokens.entries[i].len, entry->vars.tokens.entries[i].base);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // printf("Slugs and tokens sizes are not equal\n");
|
||||||
|
// // for (i = 0; i < entry->vars.slugs.size; i++) {
|
||||||
|
// // printf("Slug name is: %*.*s\n",entry->vars.slugs.entries[i].len,
|
||||||
|
// // entry->vars.slugs.entries[i].len, entry->vars.slugs.entries[i].base);
|
||||||
|
// // }
|
||||||
|
// // for (i = 0; i < entry->vars.tokens.size; i++) {
|
||||||
|
// // printf("Slug value is: %*.*s\n",entry->vars.tokens.entries[i].len,
|
||||||
|
// // entry->vars.tokens.entries[i].len, entry->vars.tokens.entries[i].base);
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// free the objects at the end
|
||||||
|
match_entry_free(entry);
|
||||||
|
}
|
||||||
|
// entry = match_entry_create("/blog/aaa/asd/123/qwe");
|
||||||
|
// if (entry != NULL) {
|
||||||
|
// entry->request_method = METHOD_GET;
|
||||||
|
// matched_route = r3_tree_match_route(n, entry);
|
||||||
|
// if (matched_route != NULL) {
|
||||||
|
// // printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route
|
||||||
|
// for (int i = 0; i < entry->vars->len; i++) {
|
||||||
|
// // entry->vars->slugs[i];
|
||||||
|
// // entry->vars->tokens[i];
|
||||||
|
// printf("Slug name is: %s\n",entry->vars->slugs[i]);
|
||||||
|
// printf("Slug value is: %s\n",entry->vars->tokens[i]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // free the objects at the end
|
||||||
|
// match_entry_free(entry);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
test1();
|
||||||
|
}
|
|
@ -54,5 +54,6 @@ int main()
|
||||||
printf("Matched! %s\n", e->path);
|
printf("Matched! %s\n", e->path);
|
||||||
}
|
}
|
||||||
match_entry_free(e);
|
match_entry_free(e);
|
||||||
|
r3_tree_free(n);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
389
include/memory.h
Normal file
389
include/memory.h
Normal file
|
@ -0,0 +1,389 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Justin Zhu
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef r3__memory_h
|
||||||
|
#define r3__memory_h
|
||||||
|
|
||||||
|
#ifdef __sun__
|
||||||
|
#include <alloca.h>
|
||||||
|
#endif
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <alloca.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define R3_STRUCT_FROM_MEMBER(s, m, p) ((s *)((char *)(p)-offsetof(s, m)))
|
||||||
|
|
||||||
|
#if __GNUC__ >= 3
|
||||||
|
#define R3_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
|
#define R3_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
|
#else
|
||||||
|
#define R3_LIKELY(x) (x)
|
||||||
|
#define R3_UNLIKELY(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define R3_GNUC_VERSION ((__GNUC__ << 16) | (__GNUC_MINOR__ << 8) | __GNUC_PATCHLEVEL__)
|
||||||
|
#else
|
||||||
|
#define R3_GNUC_VERSION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __STDC_VERSION__ >= 201112L
|
||||||
|
#define R3_NORETURN _Noreturn
|
||||||
|
#elif defined(__clang__) || defined(__GNUC__) && R3_GNUC_VERSION >= 0x20500
|
||||||
|
// noreturn was not defined before gcc 2.5
|
||||||
|
#define R3_NORETURN __attribute__((noreturn))
|
||||||
|
#else
|
||||||
|
#define R3_NORETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__) && R3_GNUC_VERSION >= 0x40900
|
||||||
|
// returns_nonnull was seemingly not defined before gcc 4.9 (exists in 4.9.1 but not in 4.8.2)
|
||||||
|
#define R3_RETURNS_NONNULL __attribute__((returns_nonnull))
|
||||||
|
#else
|
||||||
|
#define R3_RETURNS_NONNULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct st_r3_buffer_prototype_t r3_buffer_prototype_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* buffer structure compatible with iovec
|
||||||
|
*/
|
||||||
|
typedef struct st_r3_iovec_t {
|
||||||
|
char *base;
|
||||||
|
unsigned int len;
|
||||||
|
} r3_iovec_t;
|
||||||
|
|
||||||
|
typedef struct st_r3_mem_recycle_t {
|
||||||
|
unsigned int max;
|
||||||
|
unsigned int cnt;
|
||||||
|
struct st_r3_mem_recycle_chunk_t *_link;
|
||||||
|
} r3_mem_recycle_t;
|
||||||
|
|
||||||
|
struct st_r3_mem_pool_shared_entry_t {
|
||||||
|
unsigned int refcnt;
|
||||||
|
void (*dispose)(void *);
|
||||||
|
char bytes[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the memory pool
|
||||||
|
*/
|
||||||
|
typedef struct st_r3_mem_pool_t {
|
||||||
|
struct st_r3_mem_pool_chunk_t *chunks;
|
||||||
|
unsigned int chunk_offset;
|
||||||
|
struct st_r3_mem_pool_shared_ref_t *shared_refs;
|
||||||
|
struct st_r3_mem_pool_direct_t *directs;
|
||||||
|
} r3_mem_pool_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* buffer used to store incoming / outgoing octets
|
||||||
|
*/
|
||||||
|
typedef struct st_r3_buffer_t {
|
||||||
|
/**
|
||||||
|
* capacity of the buffer (or minimum initial capacity in case of a prototype (i.e. bytes == NULL))
|
||||||
|
*/
|
||||||
|
unsigned int capacity;
|
||||||
|
/**
|
||||||
|
* amount of the data available
|
||||||
|
*/
|
||||||
|
unsigned int size;
|
||||||
|
/**
|
||||||
|
* pointer to the start of the data (or NULL if is pointing to a prototype)
|
||||||
|
*/
|
||||||
|
char *bytes;
|
||||||
|
/**
|
||||||
|
* prototype (or NULL if the instance is part of the prototype (i.e. bytes == NULL))
|
||||||
|
*/
|
||||||
|
r3_buffer_prototype_t *_prototype;
|
||||||
|
/**
|
||||||
|
* file descriptor (if not -1, used to store the buffer)
|
||||||
|
*/
|
||||||
|
int _fd;
|
||||||
|
char _buf[1];
|
||||||
|
} r3_buffer_t;
|
||||||
|
|
||||||
|
typedef struct st_r3_buffer_mmap_settings_t {
|
||||||
|
unsigned int threshold;
|
||||||
|
char fn_template[FILENAME_MAX];
|
||||||
|
} r3_buffer_mmap_settings_t;
|
||||||
|
|
||||||
|
struct st_r3_buffer_prototype_t {
|
||||||
|
r3_mem_recycle_t allocator;
|
||||||
|
r3_buffer_t _initial_buf;
|
||||||
|
r3_buffer_mmap_settings_t *mmap_settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define R3_VECTOR(type) \
|
||||||
|
struct { \
|
||||||
|
type *entries; \
|
||||||
|
unsigned int size; \
|
||||||
|
unsigned int capacity; \
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef R3_VECTOR(void) r3_vector_t;
|
||||||
|
|
||||||
|
extern void *(*r3_mem__set_secure)(void *, int, unsigned int);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prints an error message and aborts
|
||||||
|
*/
|
||||||
|
R3_NORETURN void r3_fatal(const char *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor for r3_iovec_t
|
||||||
|
*/
|
||||||
|
static r3_iovec_t r3_iovec_init(const void *base, unsigned int len);
|
||||||
|
/**
|
||||||
|
* wrapper of malloc; allocates given size of memory or dies if impossible
|
||||||
|
*/
|
||||||
|
R3_RETURNS_NONNULL static void *r3_mem_alloc(unsigned int sz);
|
||||||
|
/**
|
||||||
|
* warpper of realloc; reallocs the given chunk or dies if impossible
|
||||||
|
*/
|
||||||
|
static void *r3_mem_realloc(void *oldp, unsigned int sz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* allocates memory using the reusing allocator
|
||||||
|
*/
|
||||||
|
void *r3_mem_alloc_recycle(r3_mem_recycle_t *allocator, unsigned int sz);
|
||||||
|
/**
|
||||||
|
* returns the memory to the reusing allocator
|
||||||
|
*/
|
||||||
|
void r3_mem_free_recycle(r3_mem_recycle_t *allocator, void *p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initializes the memory pool.
|
||||||
|
*/
|
||||||
|
void r3_mem_init_pool(r3_mem_pool_t *pool);
|
||||||
|
/**
|
||||||
|
* clears the memory pool.
|
||||||
|
* Applications may dispose the pool after calling the function or reuse it without calling r3_mem_init_pool.
|
||||||
|
*/
|
||||||
|
void r3_mem_clear_pool(r3_mem_pool_t *pool);
|
||||||
|
/**
|
||||||
|
* allocates given size of memory from the memory pool, or dies if impossible
|
||||||
|
*/
|
||||||
|
void *r3_mem_alloc_pool(r3_mem_pool_t *pool, unsigned int sz);
|
||||||
|
/**
|
||||||
|
* allocates a ref-counted chunk of given size from the memory pool, or dies if impossible.
|
||||||
|
* The ref-count of the returned chunk is 1 regardless of whether or not the chunk is linked to a pool.
|
||||||
|
* @param pool pool to which the allocated chunk should be linked (or NULL to allocate an orphan chunk)
|
||||||
|
*/
|
||||||
|
void *r3_mem_alloc_shared(r3_mem_pool_t *pool, unsigned int sz, void (*dispose)(void *));
|
||||||
|
/**
|
||||||
|
* links a ref-counted chunk to a memory pool.
|
||||||
|
* The ref-count of the chunk will be decremented when the pool is cleared.
|
||||||
|
* It is permitted to link a chunk more than once to a single pool.
|
||||||
|
*/
|
||||||
|
void r3_mem_link_shared(r3_mem_pool_t *pool, void *p);
|
||||||
|
/**
|
||||||
|
* increments the reference count of a ref-counted chunk.
|
||||||
|
*/
|
||||||
|
static void r3_mem_addref_shared(void *p);
|
||||||
|
/**
|
||||||
|
* decrements the reference count of a ref-counted chunk.
|
||||||
|
* The chunk gets freed when the ref-count reaches zero.
|
||||||
|
*/
|
||||||
|
static int r3_mem_release_shared(void *p);
|
||||||
|
/**
|
||||||
|
* initialize the buffer using given prototype.
|
||||||
|
*/
|
||||||
|
static void r3_buffer_init(r3_buffer_t **buffer, r3_buffer_prototype_t *prototype);
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void r3_buffer__do_free(r3_buffer_t *buffer);
|
||||||
|
/**
|
||||||
|
* disposes of the buffer
|
||||||
|
*/
|
||||||
|
static void r3_buffer_dispose(r3_buffer_t **buffer);
|
||||||
|
/**
|
||||||
|
* allocates a buffer.
|
||||||
|
* @param inbuf - pointer to a pointer pointing to the structure (set *inbuf to NULL to allocate a new buffer)
|
||||||
|
* @param min_guarantee minimum number of bytes to reserve
|
||||||
|
* @return buffer to which the next data should be stored
|
||||||
|
* @note When called against a new buffer, the function returns a buffer twice the size of requested guarantee. The function uses
|
||||||
|
* exponential backoff for already-allocated buffers.
|
||||||
|
*/
|
||||||
|
r3_iovec_t r3_buffer_reserve(r3_buffer_t **inbuf, unsigned int min_guarantee);
|
||||||
|
/**
|
||||||
|
* throws away given size of the data from the buffer.
|
||||||
|
* @param delta number of octets to be drained from the buffer
|
||||||
|
*/
|
||||||
|
void r3_buffer_consume(r3_buffer_t **inbuf, unsigned int delta);
|
||||||
|
/**
|
||||||
|
* resets the buffer prototype
|
||||||
|
*/
|
||||||
|
static void r3_buffer_set_prototype(r3_buffer_t **buffer, r3_buffer_prototype_t *prototype);
|
||||||
|
/**
|
||||||
|
* registers a buffer to memory pool, so that it would be freed when the pool is flushed. Note that the buffer cannot be resized
|
||||||
|
* after it is linked.
|
||||||
|
*/
|
||||||
|
static void r3_buffer_link_to_pool(r3_buffer_t *buffer, r3_mem_pool_t *pool);
|
||||||
|
void r3_buffer__dispose_linked(void *p);
|
||||||
|
/**
|
||||||
|
* grows the vector so that it could store at least new_capacity elements of given size (or dies if impossible).
|
||||||
|
* @param pool memory pool that the vector is using
|
||||||
|
* @param vector the vector
|
||||||
|
* @param element_size size of the elements stored in the vector
|
||||||
|
* @param new_capacity the capacity of the buffer after the function returns
|
||||||
|
*/
|
||||||
|
#define r3_vector_reserve(pool, vector, new_capacity) \
|
||||||
|
r3_vector__reserve((pool), (r3_vector_t *)(void *)(vector), sizeof((vector)->entries[0]), (new_capacity))
|
||||||
|
static void r3_vector__reserve(r3_mem_pool_t *pool, r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity);
|
||||||
|
void r3_vector__expand(r3_mem_pool_t *pool, r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tests if target chunk (target_len bytes long) is equal to test chunk (test_len bytes long)
|
||||||
|
*/
|
||||||
|
static int r3_memis(const void *target, unsigned int target_len, const void *test, unsigned int test_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* secure memset
|
||||||
|
*/
|
||||||
|
static void *r3_mem_set_secure(void *b, int c, unsigned int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* swaps contents of memory
|
||||||
|
*/
|
||||||
|
void r3_mem_swap(void *x, void *y, unsigned int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* emits hexdump of given buffer to fp
|
||||||
|
*/
|
||||||
|
void r3_dump_memory(FILE *fp, const char *buf, unsigned int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appends an element to a NULL-terminated list allocated using malloc
|
||||||
|
*/
|
||||||
|
void r3_append_to_null_terminated_list(void ***list, void *element);
|
||||||
|
|
||||||
|
/* inline defs */
|
||||||
|
|
||||||
|
inline r3_iovec_t r3_iovec_init(const void *base, unsigned int len)
|
||||||
|
{
|
||||||
|
/* intentionally declared to take a "const void*" since it may contain any type of data and since _some_ buffers are constant */
|
||||||
|
r3_iovec_t buf;
|
||||||
|
buf.base = (char *)base;
|
||||||
|
buf.len = len;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void *r3_mem_alloc(unsigned int sz)
|
||||||
|
{
|
||||||
|
void *p = malloc(sz);
|
||||||
|
if (p == NULL)
|
||||||
|
r3_fatal("no memory");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void *r3_mem_realloc(void *oldp, unsigned int sz)
|
||||||
|
{
|
||||||
|
void *newp = realloc(oldp, sz);
|
||||||
|
if (newp == NULL) {
|
||||||
|
r3_fatal("no memory");
|
||||||
|
return oldp;
|
||||||
|
}
|
||||||
|
return newp;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void r3_mem_addref_shared(void *p)
|
||||||
|
{
|
||||||
|
struct st_r3_mem_pool_shared_entry_t *entry = R3_STRUCT_FROM_MEMBER(struct st_r3_mem_pool_shared_entry_t, bytes, p);
|
||||||
|
assert(entry->refcnt != 0);
|
||||||
|
++entry->refcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int r3_mem_release_shared(void *p)
|
||||||
|
{
|
||||||
|
struct st_r3_mem_pool_shared_entry_t *entry = R3_STRUCT_FROM_MEMBER(struct st_r3_mem_pool_shared_entry_t, bytes, p);
|
||||||
|
if (--entry->refcnt == 0) {
|
||||||
|
if (entry->dispose != NULL)
|
||||||
|
entry->dispose(entry->bytes);
|
||||||
|
free(entry);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void r3_buffer_init(r3_buffer_t **buffer, r3_buffer_prototype_t *prototype)
|
||||||
|
{
|
||||||
|
*buffer = &prototype->_initial_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void r3_buffer_dispose(r3_buffer_t **_buffer)
|
||||||
|
{
|
||||||
|
r3_buffer_t *buffer = *_buffer;
|
||||||
|
*_buffer = NULL;
|
||||||
|
if (buffer->bytes != NULL)
|
||||||
|
r3_buffer__do_free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void r3_buffer_set_prototype(r3_buffer_t **buffer, r3_buffer_prototype_t *prototype)
|
||||||
|
{
|
||||||
|
if ((*buffer)->_prototype != NULL)
|
||||||
|
(*buffer)->_prototype = prototype;
|
||||||
|
else
|
||||||
|
*buffer = &prototype->_initial_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void r3_buffer_link_to_pool(r3_buffer_t *buffer, r3_mem_pool_t *pool)
|
||||||
|
{
|
||||||
|
r3_buffer_t **slot = (r3_buffer_t **)r3_mem_alloc_shared(pool, sizeof(*slot), r3_buffer__dispose_linked);
|
||||||
|
*slot = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void r3_vector__reserve(r3_mem_pool_t *pool, r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity)
|
||||||
|
{
|
||||||
|
if (vector->capacity < new_capacity) {
|
||||||
|
r3_vector__expand(pool, vector, element_size, new_capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int r3_memis(const void *_target, unsigned int target_len, const void *_test, unsigned int test_len)
|
||||||
|
{
|
||||||
|
const char *target = (const char *)_target, *test = (const char *)_test;
|
||||||
|
if (target_len != test_len)
|
||||||
|
return 0;
|
||||||
|
if (target_len == 0)
|
||||||
|
return 1;
|
||||||
|
if (target[0] != test[0])
|
||||||
|
return 0;
|
||||||
|
return memcmp(target + 1, test + 1, test_len - 1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void *r3_mem_set_secure(void *b, int c, unsigned int len)
|
||||||
|
{
|
||||||
|
return r3_mem__set_secure(b, c, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
81
include/r3.h
81
include/r3.h
|
@ -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,79 +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)
|
||||||
int request_method; // can be (GET || POST)
|
r3_iovec_t host; // required host name
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
@ -126,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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,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)
|
||||||
|
|
||||||
|
@ -152,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);
|
||||||
|
|
||||||
|
@ -164,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);
|
||||||
|
|
||||||
|
@ -187,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);
|
||||||
|
|
||||||
|
@ -211,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 };
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,30 @@
|
||||||
#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 **tokens;
|
R3_VECTOR(r3_iovec_t) slugs;
|
||||||
int len;
|
R3_VECTOR(r3_iovec_t) tokens;
|
||||||
int cap;
|
|
||||||
} str_array;
|
} 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_resize(str_array *l, int new_cap);
|
// bool str_array_tokens_full(const str_array * l);
|
||||||
|
|
||||||
bool str_array_append(str_array * list, char * token);
|
// 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 * l, char * token, unsigned int len);
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -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})
|
||||||
|
|
|
@ -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
|
||||||
|
|
57
src/edge.c
57
src/edge.c
|
@ -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,33 +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) {
|
||||||
zfree(e->pattern);
|
if (e) {
|
||||||
if ( e->child ) {
|
if ( e->child ) {
|
||||||
r3_tree_free(e->child);
|
r3_tree_free(e->child);
|
||||||
|
}
|
||||||
|
// free itself
|
||||||
|
// zfree(e);
|
||||||
}
|
}
|
||||||
// free itself
|
|
||||||
zfree(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
12
src/json.c
12
src/json.c
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
378
src/memory.c
Normal file
378
src/memory.c
Normal file
|
@ -0,0 +1,378 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 DeNA Co., Ltd.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
struct st_r3_mem_recycle_chunk_t {
|
||||||
|
struct st_r3_mem_recycle_chunk_t *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct st_r3_mem_pool_chunk_t {
|
||||||
|
struct st_r3_mem_pool_chunk_t *next;
|
||||||
|
unsigned int _dummy; /* align to 2*sizeof(void*) */
|
||||||
|
char bytes[4096 - sizeof(void *) * 2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct st_r3_mem_pool_direct_t {
|
||||||
|
struct st_r3_mem_pool_direct_t *next;
|
||||||
|
unsigned int _dummy; /* align to 2*sizeof(void*) */
|
||||||
|
char bytes[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct st_r3_mem_pool_shared_ref_t {
|
||||||
|
struct st_r3_mem_pool_shared_ref_t *next;
|
||||||
|
struct st_r3_mem_pool_shared_entry_t *entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
void *(*r3_mem__set_secure)(void *, int, unsigned int) = memset;
|
||||||
|
|
||||||
|
static __thread r3_mem_recycle_t mempool_allocator = {16};
|
||||||
|
|
||||||
|
void r3_fatal(const char *msg)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "fatal:%s\n", msg);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *r3_mem_alloc_recycle(r3_mem_recycle_t *allocator, unsigned int sz)
|
||||||
|
{
|
||||||
|
struct st_r3_mem_recycle_chunk_t *chunk;
|
||||||
|
if (allocator->cnt == 0)
|
||||||
|
return r3_mem_alloc(sz);
|
||||||
|
/* detach and return the pooled pointer */
|
||||||
|
chunk = allocator->_link;
|
||||||
|
assert(chunk != NULL);
|
||||||
|
allocator->_link = chunk->next;
|
||||||
|
--allocator->cnt;
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_mem_free_recycle(r3_mem_recycle_t *allocator, void *p)
|
||||||
|
{
|
||||||
|
struct st_r3_mem_recycle_chunk_t *chunk;
|
||||||
|
if (allocator->cnt == allocator->max) {
|
||||||
|
free(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* register the pointer to the pool */
|
||||||
|
chunk = p;
|
||||||
|
chunk->next = allocator->_link;
|
||||||
|
allocator->_link = chunk;
|
||||||
|
++allocator->cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_mem_init_pool(r3_mem_pool_t *pool)
|
||||||
|
{
|
||||||
|
pool->chunks = NULL;
|
||||||
|
pool->chunk_offset = sizeof(pool->chunks->bytes);
|
||||||
|
pool->directs = NULL;
|
||||||
|
pool->shared_refs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_mem_clear_pool(r3_mem_pool_t *pool)
|
||||||
|
{
|
||||||
|
/* release the refcounted chunks */
|
||||||
|
if (pool->shared_refs != NULL) {
|
||||||
|
struct st_r3_mem_pool_shared_ref_t *ref = pool->shared_refs;
|
||||||
|
do {
|
||||||
|
r3_mem_release_shared(ref->entry->bytes);
|
||||||
|
} while ((ref = ref->next) != NULL);
|
||||||
|
pool->shared_refs = NULL;
|
||||||
|
}
|
||||||
|
/* release the direct chunks */
|
||||||
|
if (pool->directs != NULL) {
|
||||||
|
struct st_r3_mem_pool_direct_t *direct = pool->directs, *next;
|
||||||
|
do {
|
||||||
|
next = direct->next;
|
||||||
|
free(direct);
|
||||||
|
} while ((direct = next) != NULL);
|
||||||
|
pool->directs = NULL;
|
||||||
|
}
|
||||||
|
/* free chunks, and reset the first chunk */
|
||||||
|
while (pool->chunks != NULL) {
|
||||||
|
struct st_r3_mem_pool_chunk_t *next = pool->chunks->next;
|
||||||
|
r3_mem_free_recycle(&mempool_allocator, pool->chunks);
|
||||||
|
pool->chunks = next;
|
||||||
|
}
|
||||||
|
pool->chunk_offset = sizeof(pool->chunks->bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *r3_mem_alloc_pool(r3_mem_pool_t *pool, unsigned int sz)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
if (sz >= sizeof(pool->chunks->bytes) / 4) {
|
||||||
|
/* allocate large requests directly */
|
||||||
|
struct st_r3_mem_pool_direct_t *newp = r3_mem_alloc(offsetof(struct st_r3_mem_pool_direct_t, bytes) + sz);
|
||||||
|
newp->next = pool->directs;
|
||||||
|
pool->directs = newp;
|
||||||
|
return newp->bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 16-bytes rounding */
|
||||||
|
sz = (sz + 15) & ~15;
|
||||||
|
if (sizeof(pool->chunks->bytes) - pool->chunk_offset < sz) {
|
||||||
|
/* allocate new chunk */
|
||||||
|
struct st_r3_mem_pool_chunk_t *newp = r3_mem_alloc_recycle(&mempool_allocator, sizeof(*newp));
|
||||||
|
newp->next = pool->chunks;
|
||||||
|
pool->chunks = newp;
|
||||||
|
pool->chunk_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pool->chunks->bytes + pool->chunk_offset;
|
||||||
|
pool->chunk_offset += sz;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void link_shared(r3_mem_pool_t *pool, struct st_r3_mem_pool_shared_entry_t *entry)
|
||||||
|
{
|
||||||
|
struct st_r3_mem_pool_shared_ref_t *ref = r3_mem_alloc_pool(pool, sizeof(struct st_r3_mem_pool_shared_ref_t));
|
||||||
|
ref->entry = entry;
|
||||||
|
ref->next = pool->shared_refs;
|
||||||
|
pool->shared_refs = ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *r3_mem_alloc_shared(r3_mem_pool_t *pool, unsigned int sz, void (*dispose)(void *))
|
||||||
|
{
|
||||||
|
struct st_r3_mem_pool_shared_entry_t *entry = r3_mem_alloc(offsetof(struct st_r3_mem_pool_shared_entry_t, bytes) + sz);
|
||||||
|
entry->refcnt = 1;
|
||||||
|
entry->dispose = dispose;
|
||||||
|
if (pool != NULL)
|
||||||
|
link_shared(pool, entry);
|
||||||
|
return entry->bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_mem_link_shared(r3_mem_pool_t *pool, void *p)
|
||||||
|
{
|
||||||
|
r3_mem_addref_shared(p);
|
||||||
|
link_shared(pool, R3_STRUCT_FROM_MEMBER(struct st_r3_mem_pool_shared_entry_t, bytes, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int topagesize(unsigned int capacity)
|
||||||
|
{
|
||||||
|
unsigned int pagesize = getpagesize();
|
||||||
|
return (offsetof(r3_buffer_t, _buf) + capacity + pagesize - 1) / pagesize * pagesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_buffer__do_free(r3_buffer_t *buffer)
|
||||||
|
{
|
||||||
|
/* caller should assert that the buffer is not part of the prototype */
|
||||||
|
if (buffer->capacity == buffer->_prototype->_initial_buf.capacity) {
|
||||||
|
r3_mem_free_recycle(&buffer->_prototype->allocator, buffer);
|
||||||
|
} else if (buffer->_fd != -1) {
|
||||||
|
close(buffer->_fd);
|
||||||
|
munmap((void *)buffer, topagesize(buffer->capacity));
|
||||||
|
} else {
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r3_iovec_t r3_buffer_reserve(r3_buffer_t **_inbuf, unsigned int min_guarantee)
|
||||||
|
{
|
||||||
|
r3_buffer_t *inbuf = *_inbuf;
|
||||||
|
r3_iovec_t ret;
|
||||||
|
|
||||||
|
if (inbuf->bytes == NULL) {
|
||||||
|
r3_buffer_prototype_t *prototype = R3_STRUCT_FROM_MEMBER(r3_buffer_prototype_t, _initial_buf, inbuf);
|
||||||
|
if (min_guarantee <= prototype->_initial_buf.capacity) {
|
||||||
|
min_guarantee = prototype->_initial_buf.capacity;
|
||||||
|
inbuf = r3_mem_alloc_recycle(&prototype->allocator, offsetof(r3_buffer_t, _buf) + min_guarantee);
|
||||||
|
} else {
|
||||||
|
inbuf = r3_mem_alloc(offsetof(r3_buffer_t, _buf) + min_guarantee);
|
||||||
|
}
|
||||||
|
*_inbuf = inbuf;
|
||||||
|
inbuf->size = 0;
|
||||||
|
inbuf->bytes = inbuf->_buf;
|
||||||
|
inbuf->capacity = min_guarantee;
|
||||||
|
inbuf->_prototype = prototype;
|
||||||
|
inbuf->_fd = -1;
|
||||||
|
} else {
|
||||||
|
if (min_guarantee <= inbuf->capacity - inbuf->size - (inbuf->bytes - inbuf->_buf)) {
|
||||||
|
/* ok */
|
||||||
|
} else if ((inbuf->size + min_guarantee) * 2 <= inbuf->capacity) {
|
||||||
|
/* the capacity should be less than or equal to 2 times of: size + guarantee */
|
||||||
|
memmove(inbuf->_buf, inbuf->bytes, inbuf->size);
|
||||||
|
inbuf->bytes = inbuf->_buf;
|
||||||
|
} else {
|
||||||
|
unsigned int new_capacity = inbuf->capacity;
|
||||||
|
do {
|
||||||
|
new_capacity *= 2;
|
||||||
|
} while (new_capacity - inbuf->size < min_guarantee);
|
||||||
|
if (inbuf->_prototype->mmap_settings != NULL && inbuf->_prototype->mmap_settings->threshold <= new_capacity) {
|
||||||
|
unsigned int new_allocsize = topagesize(new_capacity);
|
||||||
|
int fd;
|
||||||
|
r3_buffer_t *newp;
|
||||||
|
if (inbuf->_fd == -1) {
|
||||||
|
char *tmpfn = alloca(strlen(inbuf->_prototype->mmap_settings->fn_template) + 1);
|
||||||
|
strcpy(tmpfn, inbuf->_prototype->mmap_settings->fn_template);
|
||||||
|
if ((fd = mkstemp(tmpfn)) == -1) {
|
||||||
|
fprintf(stderr, "failed to create temporary file:%s:%s\n", tmpfn, strerror(errno));
|
||||||
|
goto MapError;
|
||||||
|
}
|
||||||
|
unlink(tmpfn);
|
||||||
|
} else {
|
||||||
|
fd = inbuf->_fd;
|
||||||
|
}
|
||||||
|
if (ftruncate(fd, new_allocsize) != 0) {
|
||||||
|
perror("failed to resize temporary file");
|
||||||
|
goto MapError;
|
||||||
|
}
|
||||||
|
if ((newp = (void *)mmap(NULL, new_allocsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
|
||||||
|
perror("mmap failed");
|
||||||
|
goto MapError;
|
||||||
|
}
|
||||||
|
if (inbuf->_fd == -1) {
|
||||||
|
/* copy data (moving from malloc to mmap) */
|
||||||
|
newp->size = inbuf->size;
|
||||||
|
newp->bytes = newp->_buf;
|
||||||
|
newp->capacity = new_capacity;
|
||||||
|
newp->_prototype = inbuf->_prototype;
|
||||||
|
newp->_fd = fd;
|
||||||
|
memcpy(newp->_buf, inbuf->bytes, inbuf->size);
|
||||||
|
r3_buffer__do_free(inbuf);
|
||||||
|
*_inbuf = inbuf = newp;
|
||||||
|
} else {
|
||||||
|
/* munmap */
|
||||||
|
unsigned int offset = inbuf->bytes - inbuf->_buf;
|
||||||
|
munmap((void *)inbuf, topagesize(inbuf->capacity));
|
||||||
|
*_inbuf = inbuf = newp;
|
||||||
|
inbuf->capacity = new_capacity;
|
||||||
|
inbuf->bytes = newp->_buf + offset;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r3_buffer_t *newp = r3_mem_alloc(offsetof(r3_buffer_t, _buf) + new_capacity);
|
||||||
|
newp->size = inbuf->size;
|
||||||
|
newp->bytes = newp->_buf;
|
||||||
|
newp->capacity = new_capacity;
|
||||||
|
newp->_prototype = inbuf->_prototype;
|
||||||
|
newp->_fd = -1;
|
||||||
|
memcpy(newp->_buf, inbuf->bytes, inbuf->size);
|
||||||
|
r3_buffer__do_free(inbuf);
|
||||||
|
*_inbuf = inbuf = newp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.base = inbuf->bytes + inbuf->size;
|
||||||
|
ret.len = inbuf->_buf + inbuf->capacity - ret.base;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
MapError:
|
||||||
|
ret.base = NULL;
|
||||||
|
ret.len = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_buffer_consume(r3_buffer_t **_inbuf, unsigned int delta)
|
||||||
|
{
|
||||||
|
r3_buffer_t *inbuf = *_inbuf;
|
||||||
|
|
||||||
|
if (delta != 0) {
|
||||||
|
assert(inbuf->bytes != NULL);
|
||||||
|
if (inbuf->size == delta) {
|
||||||
|
*_inbuf = &inbuf->_prototype->_initial_buf;
|
||||||
|
r3_buffer__do_free(inbuf);
|
||||||
|
} else {
|
||||||
|
inbuf->size -= delta;
|
||||||
|
inbuf->bytes += delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_buffer__dispose_linked(void *p)
|
||||||
|
{
|
||||||
|
r3_buffer_t **buf = p;
|
||||||
|
r3_buffer_dispose(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_vector__expand(r3_mem_pool_t *pool, r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity)
|
||||||
|
{
|
||||||
|
void *new_entries;
|
||||||
|
assert(vector->capacity < new_capacity);
|
||||||
|
if (!vector->capacity)
|
||||||
|
vector->capacity = 4;
|
||||||
|
while (vector->capacity < new_capacity)
|
||||||
|
vector->capacity *= 2;
|
||||||
|
if (pool) {
|
||||||
|
new_entries = r3_mem_alloc_pool(pool, element_size * vector->capacity);
|
||||||
|
memcpy(new_entries, vector->entries, element_size * vector->size);
|
||||||
|
} else {
|
||||||
|
new_entries = r3_mem_realloc(vector->entries, element_size * vector->capacity);
|
||||||
|
}
|
||||||
|
vector->entries = new_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_mem_swap(void *_x, void *_y, unsigned int len)
|
||||||
|
{
|
||||||
|
char *x = _x, *y = _y;
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
while (len != 0) {
|
||||||
|
unsigned int blocksz = len < sizeof(buf) ? len : sizeof(buf);
|
||||||
|
memcpy(buf, x, blocksz);
|
||||||
|
memcpy(x, y, blocksz);
|
||||||
|
memcpy(y, buf, blocksz);
|
||||||
|
len -= blocksz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_dump_memory(FILE *fp, const char *buf, unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i += 16) {
|
||||||
|
fprintf(fp, "%08zx", i);
|
||||||
|
for (j = 0; j != 16; ++j) {
|
||||||
|
if (i + j < len)
|
||||||
|
fprintf(fp, " %02x", (int)(unsigned char)buf[i + j]);
|
||||||
|
else
|
||||||
|
fprintf(fp, " ");
|
||||||
|
}
|
||||||
|
fprintf(fp, " ");
|
||||||
|
for (j = 0; j != 16 && i + j < len; ++j) {
|
||||||
|
int ch = buf[i + j];
|
||||||
|
fputc(' ' <= ch && ch < 0x7f ? ch : '.', fp);
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_append_to_null_terminated_list(void ***list, void *element)
|
||||||
|
{
|
||||||
|
unsigned int cnt;
|
||||||
|
|
||||||
|
for (cnt = 0; (*list)[cnt] != NULL; ++cnt)
|
||||||
|
;
|
||||||
|
*list = r3_mem_realloc(*list, (cnt + 2) * sizeof(void *));
|
||||||
|
(*list)[cnt++] = element;
|
||||||
|
(*list)[cnt] = NULL;
|
||||||
|
}
|
465
src/node.c
465
src/node.c
|
@ -53,31 +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));
|
||||||
|
|
||||||
n->edges = (R3Edge*) zmalloc(sizeof(R3Edge) * cap);
|
r3_vector_reserve(NULL, &n->edges, n->edges.size + cap);
|
||||||
CHECK_PTR(n->edges);
|
|
||||||
n->edge_len = 0;
|
|
||||||
n->edge_cap = cap;
|
|
||||||
|
|
||||||
n->routes = NULL;
|
r3_vector_reserve(NULL, &n->routes, n->routes.size + 1);
|
||||||
n->route_len = 0;
|
|
||||||
n->route_cap = 0;
|
|
||||||
|
|
||||||
n->endpoint = 0;
|
n->compare_type = NODE_COMPARE_PCRE;
|
||||||
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++) {
|
||||||
zfree(tree->edges);
|
r3_edge_free(tree->edges.entries + j);
|
||||||
}
|
}
|
||||||
zfree(tree->routes);
|
free(tree->edges.entries);
|
||||||
|
for (int k=0;k<tree->routes.size;k++) {
|
||||||
|
r3_route_free(tree->routes.entries + k);
|
||||||
|
}
|
||||||
|
free(tree->routes.entries);
|
||||||
if (tree->pcre_pattern) {
|
if (tree->pcre_pattern) {
|
||||||
pcre_free(tree->pcre_pattern);
|
pcre_free(tree->pcre_pattern);
|
||||||
}
|
}
|
||||||
|
@ -87,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,40 +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);
|
||||||
zfree(e);
|
// CHECK_PTR(e);
|
||||||
return e2;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// r3_edge_initl(
|
|
||||||
// copy 'edge' into the edge array
|
|
||||||
n->edges[n->edge_len] = *e;
|
|
||||||
return &n->edges[n->edge_len++];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,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 {
|
||||||
|
@ -169,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,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) {
|
||||||
|
@ -195,28 +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);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,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;
|
||||||
|
|
||||||
|
@ -237,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);
|
||||||
|
@ -259,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);
|
||||||
}
|
}
|
||||||
|
@ -283,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;
|
||||||
|
@ -293,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++;
|
||||||
|
@ -319,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;
|
||||||
|
@ -372,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
|
||||||
|
@ -422,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;
|
||||||
}
|
}
|
||||||
|
@ -436,71 +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;
|
||||||
for (i = n->route_len; i--; ) {
|
if (n && (irs = n->routes.size)) {
|
||||||
if ( r3_route_cmp(n->routes[i], entry) == 0 ) {
|
r = n->routes.entries;
|
||||||
return n->routes[i];
|
for (i = 0; irs - i; i++) {
|
||||||
|
if ( r3_route_cmp(r, entry) == 0 ) {
|
||||||
|
// Add slugs from found route to match_entry
|
||||||
|
entry->vars.slugs.entries = r->slugs.entries;
|
||||||
|
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) {
|
||||||
zfree(route);
|
assert(route);
|
||||||
|
free(route->slugs.entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
R3Route * r3_route_createl(const char * path, int path_len) {
|
// static bool router_slugs_full(const R3Route * route) {
|
||||||
R3Route * info = zmalloc(sizeof(R3Route));
|
// return route->slugs_len >= route->slugs_cap;
|
||||||
CHECK_PTR(info);
|
// }
|
||||||
info->path = (char*) path;
|
|
||||||
info->path_len = path_len;
|
|
||||||
info->request_method = 0; // can be (GET || POST)
|
|
||||||
|
|
||||||
info->data = NULL;
|
// 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;
|
||||||
|
// }
|
||||||
|
|
||||||
info->host = NULL; // required host name
|
static r3_iovec_t* router_append_slug(R3Route * route, char * slug, unsigned int len) {
|
||||||
info->host_len = 0;
|
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 void get_slugs(R3Route * route, const char * path, int path_len) {
|
||||||
|
char *plh = (char*)path;
|
||||||
|
unsigned int l, namel;
|
||||||
|
l = 0;
|
||||||
|
char *name;
|
||||||
|
while (plh < (path + path_len)) {
|
||||||
|
plh = r3_slug_find_placeholder(plh+l, path_len, &l);
|
||||||
|
if (!plh) break;
|
||||||
|
namel = 0;
|
||||||
|
name = r3_slug_find_name(plh, l, &namel);
|
||||||
|
if (name) {
|
||||||
|
router_append_slug(route, name, namel);
|
||||||
|
}
|
||||||
|
if ((plh + l) >= (path + path_len)) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R3Route * r3_node_append_route(R3Node *tree, const char * path, int path_len, int method, void *data) {
|
||||||
|
r3_vector_reserve(NULL, &tree->routes, tree->routes.size + 1);
|
||||||
|
R3Route *info = tree->routes.entries + tree->routes.size++;
|
||||||
|
memset(info, 0, sizeof(*info));
|
||||||
|
|
||||||
|
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->data = data;
|
||||||
|
|
||||||
info->remote_addr_pattern = NULL;
|
|
||||||
info->remote_addr_pattern_len = 0;
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -538,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -601,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;
|
||||||
|
|
||||||
|
@ -612,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;
|
||||||
}
|
}
|
||||||
|
@ -633,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);
|
||||||
|
@ -650,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);
|
||||||
|
@ -658,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_connect(n, zstrndup(path, (int)(p - path)), child);
|
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -688,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 , 1, c2);
|
R3Edge * op_edge = r3_node_connectl(c1, slug_p, slug_len , 0, c2);
|
||||||
if(opcode) {
|
if(opcode) {
|
||||||
op_edge->opcode = opcode;
|
op_edge->opcode = opcode;
|
||||||
}
|
}
|
||||||
|
@ -705,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;
|
||||||
}
|
}
|
||||||
|
@ -758,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;
|
||||||
|
@ -773,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;
|
||||||
}
|
}
|
||||||
|
@ -790,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);
|
||||||
}
|
}
|
||||||
|
@ -801,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");
|
||||||
|
@ -825,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -855,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;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
78
src/str.c
78
src/str.c
|
@ -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) {
|
|
||||||
if(*c == '{') cnt++;
|
|
||||||
if(*c == '}') cnt--;
|
|
||||||
if(*c == ':') break;
|
|
||||||
if(*c == '\0') return NULL;
|
|
||||||
if(cnt == 0) break;
|
|
||||||
c++;
|
c++;
|
||||||
|
if ( s2 = strnchr(c, plholder, ':') ) {
|
||||||
|
*len = s2 - c;
|
||||||
|
return c;
|
||||||
|
} else {
|
||||||
|
*len = plholder - 2;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find starting '{'
|
|
||||||
s2 = c;
|
|
||||||
while(1) {
|
|
||||||
if ( *s2 == '{' )
|
|
||||||
break;
|
|
||||||
s2--;
|
|
||||||
}
|
|
||||||
s2++;
|
|
||||||
*len = c - s2;
|
|
||||||
return s2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param char * sep separator
|
* @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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
66
src/token.c
66
src/token.c
|
@ -13,54 +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->cap = cap;
|
|
||||||
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_is_full(const str_array * l) {
|
bool str_array_append(str_array * l, char * token, unsigned int len) {
|
||||||
return l->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_resize(str_array * l, int new_cap) {
|
memset(temp, 0, sizeof(*temp));
|
||||||
l->tokens = zrealloc(l->tokens, sizeof(char**) * new_cap);
|
temp->base = token;
|
||||||
l->cap = new_cap;
|
temp->len = len;
|
||||||
return l->tokens != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool str_array_append(str_array * l, char * token) {
|
|
||||||
if ( str_array_is_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) {
|
||||||
|
if (l->tokens.size) {
|
||||||
|
printf("[");
|
||||||
|
for ( int i = 0; i < l->tokens.size ; i++ ) {
|
||||||
|
printf("\"%*.*s\"", l->slugs.entries[i].len,l->slugs.entries[i].len,l->slugs.entries[i].base );
|
||||||
|
if ( i + 1 != l->tokens.size ) {
|
||||||
|
printf(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("]\n");
|
||||||
|
} else {
|
||||||
|
printf("[]\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -464,6 +464,7 @@ 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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue