Compare commits

...

112 commits

Author SHA1 Message Date
Lily Tsuru ade1527bef Add pcre2 include dir (required for non-system PCRE2 installations) 2023-12-24 23:13:53 -05:00
c9s c1aab00c40
Merge pull request #157 from Nordix/cmake-corrections 2023-11-12 22:51:25 +08:00
Björn Svensson 9887545ab0 Install headers in correct path when using CMake
pkg-config provides users with the include path `../include/r3`
while CMake installs the headers directly under `../include/`.
This corrects the installation path to match the generated r3.pc
and to get the same result as when using autoconf.
2023-11-03 09:49:16 +01:00
Björn Svensson c105117b40
Use PCRE2 instead of PCRE (#153)
PCRE is now at end of life and is no longer actively maintained.
Lift the dependency to the next major version, i.e. PCRE2.

Implementation notes:
- Removed the pcre study option since:
  "The new API ... was simplified by abolishing the separate "study" optimizing
  function; in PCRE2, patterns are automatically optimized where possible."
- If asprintf() fails the content of the 'strp' variable is undefined.
  Lets check the return value and return NULL upon error.
- Pattern and subject can straightforwardly be cast to PCRE2_SPTR since we
  only work with 8-bit code units.
2023-10-23 12:38:24 +02:00
Björn Svensson 9168f7e4d4 Support C23 projects
Don't define true/false/bool when r3 is used by C23 projects
since C23 already has a bool type and predefined constants.
2023-10-23 10:45:18 +02:00
Björn Svensson 58d8b0c028 Use coverity-scan-action in CI
Simplifies the CI job and adds a cache to avoid downloading the 1GB+
tool archive on every run.
See: https://github.com/vapier/coverity-scan-action

Only run this job when a commit is pushed to the default branch 2.0
(like when a PR is merged) since the required Coverity token/secret
is not available when this job is triggered by forks.
2023-10-23 10:35:38 +02:00
Yo-An Lin 91405adda5
Merge pull request #152 from c9s/c9s-patch-1 2023-02-12 10:52:51 +08:00
Yo-An Lin b6639e557f
Update coverity.yml 2022-08-24 16:05:06 +08:00
Yo-An Lin c8123430a9
remove coverity env var since it is not working 2022-07-21 00:41:08 +08:00
Bjorn Svensson 9b69f38527
Fix leak in r3_tree_insert_pathl_ex() (#150)
Includes a testcase triggering the issue when building with
the leak sanitizer.

Resource leak (CID 355063) found by Coverity,
2022-07-20 13:23:45 +02:00
Yo-An Lin 25cc816025
Fix coverity token variable (#151) 2022-07-20 13:08:42 +02:00
Yo-An Lin edbeb0631d
Merge pull request #149 from Nordix/coverity-in-ci
Add Coverity Scan to CI
2022-07-19 17:20:04 +08:00
Björn Svensson 04d52a6dd1 Fix Coverity warning
The return value was checked on all calls to r3_slug_find_placeholder()
except in one place, which triggered a Coverity warning.

This adds a check (assert), and enables the other asserts for non-debug
builds to catch segmentation faults early.
2021-11-10 22:20:46 +01:00
Björn Svensson cfed420cd3 Add Coverity Scan to CI 2021-11-10 22:20:34 +01:00
Yo-An Lin 76e2770304
Merge pull request #148 from Nordix/faulty-slug-in-insert-route
Handle incomplete slug pattern when inserting a route
2021-11-05 09:27:52 +08:00
Yo-An Lin 90450def8b
Merge pull request #147 from Nordix/memory-pool-cleanups
Remove unused memory pool and memory code
2021-11-05 09:26:46 +08:00
Björn Svensson 2f3e0b01ff Handle incomplete slug in insert route 2021-11-04 20:22:10 +01:00
Björn Svensson bf11f8e2e6 Remove unused code in memory.c/.h 2021-11-03 21:58:33 +01:00
Björn Svensson f0dd25bd53 Remove unused memory pool 2021-11-03 21:22:48 +01:00
Yo-An Lin e533bae646
Merge pull request #146 from Nordix/coveralls-action
Use recommended Coveralls GitHub action in CI
2021-10-28 21:14:43 +08:00
Björn Svensson b44f052897 Use recommended Coveralls GitHub action in CI 2021-10-19 11:18:53 +02:00
Yo-An Lin 06c4fc41bf
Merge pull request #140 from Nordix/test-leak-fixes
Correcting leaks in tests
2021-10-19 02:45:18 +08:00
Yo-An Lin 35c5d13df8
Merge pull request #144 from Nordix/migrate-ci-to-github-actions
Add CI via Github Actions
2021-10-19 02:44:40 +08:00
Yo-An Lin 4f3c1cd994
Merge pull request #145 from Nordix/misaligned-address-error
Remove fixed alignment
2021-10-19 02:44:14 +08:00
Björn Svensson 5114d894e5 Remove fixed alignment 2021-10-18 11:36:54 +02:00
Björn Svensson 79a3bc7c50 Add CI via Github Actions
This is an initial setup with similarities to how we test
via TravisCI; build via autotools and build via cmake.
Additional testmatrix for sanitizer testing.
2021-10-18 09:08:42 +02:00
Björn Svensson 9c8feff07f Correcting leaks in tests
A couple of testcases did not free its `match_entry` allocations,
which triggers leak indications.
Visible when build and run using the leak sanitizer, i.e
`CFLAGS="-fno-omit-frame-pointer -fsanitize=leak" cmake ..`
2021-10-14 08:27:19 +02:00
Yo-An Lin b13dc8aa6e
Merge pull request #131 from iresty/feature-ipv6
feature: supported to use ipv6 address match route.
2021-10-14 10:31:23 +08:00
Yo-An Lin eca8d9992e
Merge pull request #143 from Nordix/str_array-fixes
Corrections in `str_array`
2021-10-14 10:29:49 +08:00
Yo-An Lin c9743f3904
Merge pull request #142 from Nordix/invalid-read-corrections
Correcting buffer over-read errors
2021-10-14 10:29:19 +08:00
Björn Svensson 383717a8c7 Update the faulty access macros for str_array
Adds a testcase for the usage of the access macros, and also
updates the testsuite to only include what str_array requires.
This shows that str_array can be used separately by users.
2021-10-13 08:47:20 +02:00
Björn Svensson 673bb2f6d9 Remove declarations for nonexisting functions in str_array.h 2021-10-13 08:47:20 +02:00
Björn Svensson 4babe735e8 Remove cyclic dependency between str_array.h and r3.h
This also makes sure we dont get warnings regarding bool
redefinitions when building with clang.
2021-10-13 08:46:47 +02:00
Björn Svensson 0072b618b6 Check for existence of stdbool.h during CMake builds
The headerfile is searched for during autogen/autoconf builds to
determine when to include stdbool.h.
This let CMake builds have the same behavior.
2021-10-12 10:52:44 +02:00
Björn Svensson 00ec8b7f2b Correct buffer over-read errors
When inserting multiple routes with common slug patterns
there are reads beyond end of strings.

The scenario is added as a testcase and can be triggered by
the address-sanitizer when built using:
`CFLAGS="-fno-omit-frame-pointer -fsanitize=address" cmake ..`

Indicated as a `buffer-overflow`
2021-10-11 10:19:09 +02:00
Yo-An Lin d2fcf2f2d4
Merge pull request #135 from fishgege/patch-1
bugfix: insert path success, but get data failed
2021-10-07 22:08:13 +08:00
Yo-An Lin da0c89b6db
Merge pull request #137 from dthadi3/ppc64le
Travis-ci: added support for ppc64le
2021-10-07 22:07:24 +08:00
Yo-An Lin 3228fb8cb5
Merge pull request #141 from Nordix/multi-edge-corrections
Correcting issue and memory leak when using multiple edges
2021-10-07 22:07:02 +08:00
Björn Svensson ff1ef2c148 Correcting issue with multiple edges
When `r3_node_find_common_prefix()` searches for the common prefix it
selects the first matched edge, which might not be the best match.

This issue gives memoryleaks which can be viewed in legacy
testcase `check_tree::test_insert_pathl()` by building using:
`CFLAGS="-fno-omit-frame-pointer -fsanitize=leak" cmake ..`
See testcase procedures:
    ret = r3_tree_insert_path(n, "/foo/{id}",  NULL);
    ..
    ret = r3_tree_insert_path(n, "/foo/{idx}/{idy}",  NULL);
    ..
    ret = r3_tree_insert_path(n, "/foo/{idx}/{idh}",  NULL); <-- leaks

Also added a testcase that triggers the problem including a leak for
reproduction on baseline.
2021-09-20 16:55:37 +02:00
Devendranath Thadi ac7af9697c Travis-ci: added support for ppc64le 2020-11-18 14:14:29 +00:00
董宇 36198aefba
bugfix: insert path success, but get data failed
background : use  r3_tree_insert_pathl_ex to add path,A : abcdefg   B:abc
When the node A already exists, we set B, then  will split the node and make a branch, suboath_len  is 0 
In this case,  branch a  zero len subpath, which tree's data not set
2019-12-15 13:05:49 +08:00
Yo-An Lin e20e48a5ce
Merge pull request #128 from iresty/bug-end-maybe-0-len
bugfix: the end matching length is 0.
2019-08-06 10:22:30 +08:00
Yuansheng 79fd587615 feature: supported to match ipv6 address. 2019-08-01 21:38:14 -04:00
Yuansheng 1b9e007dfc bugfix: make a try for endpoint. 2019-07-21 08:46:37 -04:00
Yuansheng 81f77ffe5a test: added test cases. 2019-07-21 08:46:37 -04:00
Yuansheng 0d70b8f5de bugfix: the end matching length is 0. 2019-07-21 08:46:37 -04:00
Yo-An Lin 577cfa0ccb
Merge pull request #130 from iresty/typo
change: typo.
2019-07-21 19:30:50 +08:00
Yo-An Lin 3dac164cec
Merge pull request #126 from iresty/optimize-wildcard
optimize: optimized pattern `.*`, which can be used prefix matching.
2019-07-21 19:30:37 +08:00
Yuansheng f8a3741211 change: typo. 2019-07-21 09:14:37 +08:00
Yuansheng 845c47907f test: describe the test case name. 2019-07-21 07:48:11 +08:00
Yuansheng 2ad6b4c4f0 test: skip one test case, will fix it later. 2019-07-20 22:58:17 +08:00
Yuansheng 3364df80ee test: run test case check_routes2. 2019-07-20 22:55:44 +08:00
Yuansheng db91289ab6 change: rename OP_EXPECT_NOLINEBREAKS to OP_GREEDY_ANY. 2019-07-20 10:52:56 -04:00
Yuansheng d516237aab optimize: optimized pattern .*, which can be used prefix matching. 2019-07-20 10:52:56 -04:00
Yo-An Lin 41685d402d
Merge pull request #129 from iresty/make-warning
change: avoided compiling warning.
2019-07-20 18:00:48 +08:00
Yo-An Lin 27d4d3191e
Merge pull request #125 from iresty/feature-scheme
feature: supported to match http scheme.
2019-07-20 17:59:48 +08:00
Yo-An Lin fd34c7244a
Merge branch '2.0' into feature-scheme 2019-07-20 17:56:59 +08:00
Yo-An Lin 2b332bffba
Merge pull request #127 from iresty/check-more
test: run test case `check_remote_addr` in travis.
2019-07-20 17:55:17 +08:00
Yuansheng 91cfc9d282 test: run the test case check_http_scheme. 2019-07-20 07:21:05 +08:00
Yuansheng fdc698f924 change: avoided compiling warning message. 2019-07-20 07:12:37 +08:00
Yuansheng 0485554d44 change(tests/check_slug): avoided compiling warning. 2019-07-20 07:06:56 +08:00
Yuansheng 4b066dd0fc test: run all of the test cases. 2019-07-19 09:15:47 -04:00
Yuansheng 43666a1183 feature: supported to match http scheme. 2019-06-26 23:06:32 +08:00
Yo-An Lin 3f410ef5d4
Merge pull request #124 from iresty/make-WARN
make: avoided the warning message when do make at Ubuntu OS.
2019-06-21 12:55:15 +08:00
Yuansheng 8e18a995d8 make: avoided the warning message when do make.
change: code style, delete some useless spaces(visual code).

eg:

warning: ignoring return value of ‘asprintf’, declared with attribute warn_unused_result
2019-06-21 10:45:54 +08:00
Yo-An Lin 410f66bc1a
Merge pull request #123 from iresty/feature-remote-ip
feature: supported to match remote ip address.
2019-06-20 11:47:46 +08:00
Yuansheng 848b8efdca feature: supported to match remote ip address. 2019-06-19 23:36:37 -04:00
Yo-An Lin 2a08bc62d5
Merge pull request #122 from iresty/feature-wildcard-host
feature: supported wildcard match way for host.
2019-06-20 11:29:52 +08:00
Yuansheng 917fa6e385 change: removed useless comments. 2019-06-20 11:21:04 +08:00
Yuansheng 4ab222a308 feature: supported wildcard match way for host. 2019-06-19 10:07:14 -04:00
Yo-An Lin 9761bdeec3
Merge pull request #119 from GuacheSuede/patch-1
Quick Includes Bug fix
2019-01-23 23:02:41 +08:00
Sakamoto 69e31ce07a
Quick Includes Bug fix 2019-01-23 01:02:04 +08:00
Yo-An Lin 22a6b99b34
Merge pull request #115 from msteinert/remove-zmalloc
Remove zmalloc
2018-07-10 07:36:49 -07:00
Michael Steinert 8abc03ea56 cmake: Add some comments regarding r3.pc.in 2018-07-10 08:24:05 -05:00
Michael Steinert b3dbf75da5 Remove zmalloc dependency
Zmalloc comes from Redis. It's purpose is to track total allocations so
that a maximum can be set. For more information see the following links:

https://groups.google.com/forum/#!topic/redis-db/dPRdpowqJsY
https://stackoverflow.com/questions/22729730/when-would-one-use-malloc-over-zmalloc

This allocator is slower, not needed, and conflicts with Zlib (when
linking statically). This patch removes Zmalloc in favor of the system
allocator. Application developers can still choose to override the
allocator in their applications, e.g. Jemalloc, TCMalloc, etc.

Fixes #104
2018-07-10 08:20:46 -05:00
Yo-An Lin afd2c486c6
Merge pull request #113 from msteinert/cleanup-cmake
Cleanup cmake
2018-07-10 06:11:41 -07:00
Michael Steinert e701bfd596 Add CMake to the CI matrix 2018-07-05 11:52:34 -05:00
Michael Steinert d1c06cd3e9 Cleanup CMake build files 2018-07-05 11:43:22 -05:00
Michael Steinert 2be2a08750 Fix -Wincompatible-pointer-types warning 2018-07-05 11:43:22 -05:00
Michael Steinert e9afe4b6cf Fix -Wdiscarded-qualifiers warnings 2018-07-05 11:43:22 -05:00
Yo-An Lin 3b9bb5745a
Merge pull request #114 from msteinert/check-tree-fixes
Fix issues with check_tree test
2018-07-06 00:42:01 +08:00
Michael Steinert 179ee52801 Attempt to update CI environment 2018-07-05 11:31:27 -05:00
Michael Steinert 081ccb2bde Fix issues with check_tree test
This patch fixes a few issues in the check_tree test:

* Fix various memory leaks in test code
* Fix a double-free in test code
* Fix a memory leak in r3_tree_compile_patterns

One memory leak remains in the library code but it isn't obvious to me
how to fix it at the moment.
2018-07-05 09:58:20 -05:00
Yo-An Lin cf92c9dc96
Merge pull request #108 from martijnotto/2.0
Initial working version of cmake builds
2018-02-25 02:02:25 +08:00
Martijn Otto 6565274ce8 We need 3rdparty for the normal build as well 2018-02-24 17:53:02 +01:00
Martijn Otto 1fceec760f We need to link to 3rdparty to be able to build the tests 2018-02-24 17:50:33 +01:00
Martijn Otto 2f96c59929 Further WIP, got the tests to link against pthread (was broken due to pkg-config not specifying -pthread as -lpthread and cmake thus not recognizing it as a library) 2018-02-24 17:45:15 +01:00
Martijn Otto a2396fe15b WIP on support for CMake builds, fails to build tests (probably error in FindCheck not declaring dependency on pthread) 2018-02-23 09:39:39 +01:00
Yo-An Lin 2b37680087
Merge pull request #107 from martijnotto/2.0
const correctness, branched assignment, unused variables, non-standard feature test, example UB, incorrect memset declaration
2018-02-21 23:01:03 +08:00
Martijn Otto 59d182b1c1 Use the generated config.h instead to enable feature macros 2018-02-21 15:57:25 +01:00
Martijn Otto 1eeff1598a Fix declaration of memset 2018-02-21 10:04:07 +01:00
Martijn Otto f8131b53d6 Fix UB in examples 2018-02-21 09:50:34 +01:00
Martijn Otto 55de164023 Set the feature test macro before including the header to enable non-standard functions used by libr3 2018-02-21 09:49:54 +01:00
Martijn Otto 8d0b90f6e1 Remove unused variables 2018-02-21 09:14:31 +01:00
Martijn Otto 5cab368af2 Add extra parenthesis around branched assignments 2018-02-21 09:11:53 +01:00
Martijn Otto 021c54308a Fix const correctness warnings 2018-02-20 18:18:43 +01:00
Yo-An Lin 0d78599a57 Merge pull request #103 from yohanboniface/fix-configure
Fix syntax error in configure.ac (fix #96)
2017-08-26 16:56:50 +08:00
Yohan Boniface 234e64f584 Fix syntax error in configure.ac (fix #96) 2017-08-26 10:50:30 +02:00
Yo-An Lin 7e4c74d625 Merge pull request #98 from phynalle/2.0
Add include headers
2017-07-02 10:00:11 +08:00
phynalle 267ab34c36 Add include headers 2016-04-27 03:45:11 +09:00
c9s cefefb239a Fix fprintf warning 2016-04-05 16:59:27 +08:00
c9s 341a29387b Merge branch 'krn_feature' of https://github.com/karantin2020/r3 into 2.0 2016-04-05 16:55:54 +08:00
karantin2020 9411039fce Router match logic corrected 2016-03-26 23:32:37 +05:00
karantin2020 ffc9e8571b Added memory files 2016-03-26 21:34:07 +05:00
karantin2020 75438ef3d3 Changed r3 memory model, made few optimizing 2016-03-22 07:23:37 +05:00
Yo-An Lin 0ba956159c Check is not running, fix check
Also update .travis.yml
2016-03-12 12:46:05 +08:00
karantin2020 ef910789c0 Added gitignored files 2016-03-08 22:30:44 +05:00
karantin2020 67fa8929f7 Clean heap after use in simple example 2016-03-08 19:52:47 +05:00
karantin2020 839001afec Changed routing example 2016-03-08 19:24:21 +05:00
karantin2020 40e0e1c2a0 Changed slug parsing 2016-03-08 14:51:42 +05:00
karantin2020 b7c0132fa9 Added routing example 2016-03-08 12:17:33 +05:00
karantin2020 400768394d Added slug parser and repaired few memory leaks 2016-03-08 11:19:54 +05:00
56 changed files with 2119 additions and 1247 deletions

70
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,70 @@
name: ci
on: [push, pull_request]
jobs:
autotools:
runs-on: ubuntu-latest
steps:
- name: Prepare
run: |
sudo apt update -qq
sudo apt install -qq check lcov
- uses: actions/checkout@v2
- name: Build
run: |
./autogen.sh
./configure --enable-check --enable-debug --enable-gcov
make V=1
- name: Install
run: sudo make install
- name: Run tests
run: make check
- name: Collect coverage
run: lcov --capture -d '.' --exclude '/usr*' -o coverage.info
- name: Upload coverage
if: github.repository == 'c9s/r3'
uses: coverallsapp/github-action@1.1.3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: coverage.info
cmake:
runs-on: ubuntu-latest
steps:
- name: Prepare
run: |
sudo apt update -qq
sudo apt install -qq check ninja-build
- uses: actions/checkout@v2
- name: Build and test
run: |
mkdir build && cd build
cmake -GNinja ..
ninja -v
ctest --verbose
sanitizers:
name: ${{ matrix.sanitizer }}-sanitizer [${{ matrix.compiler }}]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
compiler: [gcc, clang]
sanitizer: [thread, undefined, leak, address]
steps:
- name: Prepare
run: |
sudo apt update -qq
sudo apt install -qq check
- uses: actions/checkout@v2
- name: Build
env:
CC: ${{ matrix.compiler }}
run: |
mkdir build && cd build
CFLAGS="-fsanitize=${{ matrix.sanitizer }} -fno-sanitize-recover=all -fno-omit-frame-pointer" cmake ..
VERBOSE=1 make all
- name: Test
run: |
cd build
ctest --verbose

21
.github/workflows/coverity.yml vendored Normal file
View file

@ -0,0 +1,21 @@
name: coverity
on:
push:
branches: [2.0]
jobs:
analyze:
if: github.repository == 'c9s/r3'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
./autogen.sh
./configure --enable-check
- uses: vapier/coverity-scan-action@v1
with:
project: r3
email: yoanlin93+github@gmail.com
token: ${{ secrets.COVERITY_TOKEN }}

5
.gitignore vendored
View file

@ -51,3 +51,8 @@ autoscan.log
r3.pc r3.pc
stamp-h1 stamp-h1
tests/bench_str.csv tests/bench_str.csv
tests/check_host
config.h.in
examples/simple
examples/simple_cpp

5
.travis-ci/after_success.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/sh
if [ x$COVERALLS == xyes ]; then
coveralls --exclude php --exclude 3rdparty
fi

24
.travis-ci/install.sh Executable file
View file

@ -0,0 +1,24 @@
#!/bin/sh
apt-get update -qq
apt-get install -qq \
autoconf \
automake \
build-essential \
check \
clang \
cmake \
graphviz-dev \
libjemalloc-dev \
libpcre2-dev \
libtool \
ninja-build \
pkg-config
if [ x$COVERALLS == xyes ]; then
pip install cpp-coveralls
fi
if [ x$VALGRIND == xyes ]; then
apt-get install valgrind
fi

18
.travis-ci/script-autotools.sh Executable file
View file

@ -0,0 +1,18 @@
#!/bin/sh
set -ev
./autogen.sh
./configure --enable-check $CONFIGURE_OPTION
make V=1
make install
if [ x$VALGRIND == xyes ]; then
make check
else
make check V=1
fi
# XXX: tracing memory leak, disabled for some mystery reason for automake...
#if [ x$VALGRIND == xyes && x$DEBUG == xyes ]; then
# valgrind ./tests/check_* -v --trace-children=yes --show-leak-kinds=full --leak-check=full
#fi

8
.travis-ci/script-cmake.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh
set -ev
mkdir build && cd build
cmake -GNinja ..
ninja -v
ctest

View file

@ -1,4 +1,8 @@
language: c language: c
sudo: required
services:
- docker
git: git:
depth: 1 depth: 1
@ -6,35 +10,102 @@ git:
matrix: matrix:
include: include:
- compiler: gcc - compiler: gcc
env: CONFIGURE_OPTION='--enable-debug --enable-gcov --with-malloc=jemalloc' COVERALLS=yes VALGRIND=no DEBUG=yes env:
- TYPE=autotools
- CONFIGURE_OPTION='--enable-debug --enable-gcov --with-malloc=jemalloc'
- COVERALLS=yes
- VALGRIND=no
- DEBUG=yes
- CC=gcc
- CXX=g++
- compiler: gcc - compiler: gcc
env: CONFIGURE_OPTION='--enable-debug --enable-gcov' COVERALLS=yes VALGRIND=yes DEBUG=yes LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/ env:
- TYPE=autotools
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
- COVERALLS=yes
- VALGRIND=yes
- DEBUG=yes
- CC=gcc
- CXX=g++
- compiler: clang - compiler: clang
env: CONFIGURE_OPTION='--enable-debug --enable-gcov' COVERALLS=yes VALGRIND=yes DEBUG=yes LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/ env:
allow_failures: - TYPE=autotools
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
- COVERALLS=yes
- VALGRIND=yes
- DEBUG=yes
- CC=clang
- CXX=clang++
- compiler: gcc
env:
- TYPE=cmake
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
- COVERALLS=yes
- VALGRIND=yes
- DEBUG=yes
- CC=gcc
- CXX=g++
#power Jobs Added
- compiler: gcc
arch: pc64le
env:
- TYPE=autotools
- CONFIGURE_OPTION='--enable-debug --enable-gcov --with-malloc=jemalloc'
- COVERALLS=yes
- VALGRIND=no
- DEBUG=yes
- CC=gcc
- CXX=g++
- compiler: gcc
arch: ppc64le
env:
- TYPE=autotools
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
- COVERALLS=yes
- VALGRIND=yes
- DEBUG=yes
- CC=gcc
- CXX=g++
- compiler: clang - compiler: clang
env: ASAN_OPTIONS=symbolize=1 ASAN_SYMBOLIZER_PATH=/usr/local/clang-3.4/bin/llvm-symbolizer CFLAGS='-fsanitize=address -g -O1 -D_BSD_SOURCE=1' CXX=clang++ CXXFLAGS='-fsanitize=address -g -O1 -D_BSD_SOURCE=1' arch: ppc64le
install: env:
- sudo apt-get update -qq - TYPE=autotools
- sudo apt-get install -qq automake pkg-config build-essential libtool automake autoconf m4 gnulib - CONFIGURE_OPTION='--enable-debug --enable-gcov'
- sudo apt-get install -qq check libpcre3 libpcre3-dev libjemalloc-dev libjemalloc1 - COVERALLS=yes
- sudo apt-get install -qq graphviz-dev graphviz - VALGRIND=yes
- if [ "x$COVERALLS" == xyes ]; then sudo pip install cpp-coveralls; fi - DEBUG=yes
- if [ "x$VALGRIND" == xyes ]; then sudo apt-get install valgrind; fi - CC=clang
- CXX=clang++
- compiler: gcc
arch: ppc64le
env:
- TYPE=cmake
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
- COVERALLS=yes
- VALGRIND=yes
- DEBUG=yes
- CC=gcc
- CXX=g++
before_install:
- docker run -d
--name build
-v $(pwd):/travis
-e "CONFIGURE_OPTION=$CONFIGURE_OPTION"
-e "COVERALLS=$COVERALLS"
-e "VALGRIND=$VALGRIND"
-e "DEBUG=$DEBUG"
-e "CC=$CC"
-e "CXX=$CXX"
ubuntu:16.04
tail -f /dev/null
- docker ps
install:
- docker exec -t build bash -c "cd /travis && .travis-ci/install.sh"
before_script:
- sudo ldconfig
script: script:
- ./autogen.sh - docker exec -t build bash -c "cd /travis && .travis-ci/script-$TYPE.sh"
- ./configure --enable-check $CONFIGURE_OPTION
- make V=1
- sudo make install
- if [ "x$VALGRIND" == xyes ]; then make check > /dev/null 2>&1; else make check V=1; fi
# XXX: tracing memory leak, disabled for some mystery reason for automake...
# - if [ "x$VALGRIND" == xyes && "x$DEBUG" == xyes ]; then valgrind ./tests/check_* -v --trace-children=yes --show-leak-kinds=full --leak-check=full; fi
after_success: after_success:
- if [ x$COVERALLS == xyes ]; then coveralls --exclude php --exclude 3rdparty; fi - docker exec -t build bash -c "cd /travis && .travis-ci/after_success.sh"
cache:
apt: true

View file

@ -1,6 +0,0 @@
include_directories("${PROJECT_SOURCE_DIR}/3rdparty ${PROJECT_SOURCE_DIR}")
set(lib3rdparty_SRCS zmalloc.c)
add_library(lib3rdparty STATIC ${lib3rdparty_SRCS})
# add_library(r3 SHARED ${libr3_SRCS})
# target_link_libraries(r3 cblas)
# install(FILES ${libswiftnav_HEADERS} DESTINATION include/libswiftnav)

14
3rdparty/Makefile.am vendored
View file

@ -1,14 +0,0 @@
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS)
noinst_LTLIBRARIES = libr3ext.la
libr3ext_la_SOURCES = zmalloc.c
libr3ext_la_LIBADD=$(DEPS_LIBS)
# noinst_LIBRARIES = libr3ext.la
libr3ext_la_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/3rdparty -Wall -std=c99
noinst_HEADERS = \
zmalloc.h \
$(NULL)

368
3rdparty/zmalloc.c vendored
View file

@ -1,368 +0,0 @@
/* zmalloc - total amount of allocated memory aware version of malloc()
*
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
/* This function provide us access to the original libc free(). This is useful
* for instance to free results obtained by backtrace_symbols(). We need
* to define this function before including zmalloc.h that may shadow the
* free implementation if we use jemalloc or another non standard allocator. */
void zlibc_free(void *ptr) {
free(ptr);
}
#include <string.h>
#include <pthread.h>
#include "config.h"
#include "zmalloc.h"
#ifdef HAVE_MALLOC_SIZE
#define PREFIX_SIZE (0)
#else
#if defined(__sun) || defined(__sparc) || defined(__sparc__)
#define PREFIX_SIZE (sizeof(long long))
#else
#define PREFIX_SIZE (sizeof(size_t))
#endif
#endif
/* Explicitly override malloc/free etc when using tcmalloc. */
#if defined(USE_TCMALLOC)
#define malloc(size) tc_malloc(size)
#define calloc(count,size) tc_calloc(count,size)
#define realloc(ptr,size) tc_realloc(ptr,size)
#define free(ptr) tc_free(ptr)
#elif defined(USE_JEMALLOC) && (JEMALLOC_VERSION_MAJOR > 2)
#include <jemalloc/jemalloc.h>
#define malloc(size) je_malloc(size)
#define calloc(count,size) je_calloc(count,size)
#define realloc(ptr,size) je_realloc(ptr,size)
#define free(ptr) je_free(ptr)
#endif
#ifdef HAVE_ATOMIC
#define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))
#define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))
#else
#define update_zmalloc_stat_add(__n) do { \
pthread_mutex_lock(&used_memory_mutex); \
used_memory += (__n); \
pthread_mutex_unlock(&used_memory_mutex); \
} while(0)
#define update_zmalloc_stat_sub(__n) do { \
pthread_mutex_lock(&used_memory_mutex); \
used_memory -= (__n); \
pthread_mutex_unlock(&used_memory_mutex); \
} while(0)
#endif
#define update_zmalloc_stat_alloc(__n) do { \
size_t _n = (__n); \
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
if (zmalloc_thread_safe) { \
update_zmalloc_stat_add(_n); \
} else { \
used_memory += _n; \
} \
} while(0)
#define update_zmalloc_stat_free(__n) do { \
size_t _n = (__n); \
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
if (zmalloc_thread_safe) { \
update_zmalloc_stat_sub(_n); \
} else { \
used_memory -= _n; \
} \
} while(0)
static size_t used_memory = 0;
static int zmalloc_thread_safe = 0;
pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
static void zmalloc_default_oom(size_t size) {
fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
size);
fflush(stderr);
abort();
}
static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
void *zmalloc(size_t size) {
void *ptr = malloc(size+PREFIX_SIZE);
if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc(zmalloc_size(ptr));
return ptr;
#else
*((size_t*)ptr) = size;
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
return (char*)ptr+PREFIX_SIZE;
#endif
}
void *zcalloc(size_t size) {
void *ptr = calloc(1, size+PREFIX_SIZE);
if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc(zmalloc_size(ptr));
return ptr;
#else
*((size_t*)ptr) = size;
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
return (char*)ptr+PREFIX_SIZE;
#endif
}
void *zrealloc(void *ptr, size_t size) {
#ifndef HAVE_MALLOC_SIZE
void *realptr;
#endif
size_t oldsize;
void *newptr;
if (ptr == NULL) return zmalloc(size);
#ifdef HAVE_MALLOC_SIZE
oldsize = zmalloc_size(ptr);
newptr = realloc(ptr,size);
if (!newptr) zmalloc_oom_handler(size);
update_zmalloc_stat_free(oldsize);
update_zmalloc_stat_alloc(zmalloc_size(newptr));
return newptr;
#else
realptr = (char*)ptr-PREFIX_SIZE;
oldsize = *((size_t*)realptr);
newptr = realloc(realptr,size+PREFIX_SIZE);
if (!newptr) zmalloc_oom_handler(size);
*((size_t*)newptr) = size;
update_zmalloc_stat_free(oldsize);
update_zmalloc_stat_alloc(size);
return (char*)newptr+PREFIX_SIZE;
#endif
}
/* Provide zmalloc_size() for systems where this function is not provided by
* malloc itself, given that in that case we store a header with this
* information as the first bytes of every allocation. */
#ifndef HAVE_MALLOC_SIZE
size_t zmalloc_size(void *ptr) {
void *realptr = (char*)ptr-PREFIX_SIZE;
size_t size = *((size_t*)realptr);
/* Assume at least that all the allocations are padded at sizeof(long) by
* the underlying allocator. */
if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
return size+PREFIX_SIZE;
}
#endif
void zfree(void *ptr) {
#ifndef HAVE_MALLOC_SIZE
void *realptr;
size_t oldsize;
#endif
if (ptr == NULL) return;
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_free(zmalloc_size(ptr));
free(ptr);
#else
realptr = (char*)ptr-PREFIX_SIZE;
oldsize = *((size_t*)realptr);
update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
free(realptr);
#endif
}
char *zstrdup(const char *s) {
size_t l = strlen(s)+1;
char *p = zmalloc(l);
memcpy(p,s,l);
return p;
}
char * zstrndup (const char *s, size_t n)
{
char *result;
size_t len = strlen (s);
if (n < len)
len = n;
result = (char *) zmalloc (len + 1);
if (!result)
return 0;
result[len] = '\0';
return (char *) memcpy (result, s, len);
}
size_t zmalloc_used_memory(void) {
size_t um;
if (zmalloc_thread_safe) {
#ifdef HAVE_ATOMIC
um = __sync_add_and_fetch(&used_memory, 0);
#else
pthread_mutex_lock(&used_memory_mutex);
um = used_memory;
pthread_mutex_unlock(&used_memory_mutex);
#endif
}
else {
um = used_memory;
}
return um;
}
void zmalloc_enable_thread_safeness(void) {
zmalloc_thread_safe = 1;
}
void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
zmalloc_oom_handler = oom_handler;
}
/* Get the RSS information in an OS-specific way.
*
* WARNING: the function zmalloc_get_rss() is not designed to be fast
* and may not be called in the busy loops where Redis tries to release
* memory expiring or swapping out objects.
*
* For this kind of "fast RSS reporting" usages use instead the
* function RedisEstimateRSS() that is a much faster (and less precise)
* version of the function. */
#if defined(HAVE_PROC_STAT)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
size_t zmalloc_get_rss(void) {
int page = sysconf(_SC_PAGESIZE);
size_t rss;
char buf[4096];
char filename[256];
int fd, count;
char *p, *x;
snprintf(filename,256,"/proc/%d/stat",getpid());
if ((fd = open(filename,O_RDONLY)) == -1) return 0;
if (read(fd,buf,4096) <= 0) {
close(fd);
return 0;
}
close(fd);
p = buf;
count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
while(p && count--) {
p = strchr(p,' ');
if (p) p++;
}
if (!p) return 0;
x = strchr(p,' ');
if (!x) return 0;
*x = '\0';
rss = strtoll(p,NULL,10);
rss *= page;
return rss;
}
#elif defined(HAVE_TASKINFO)
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach/task.h>
#include <mach/mach_init.h>
size_t zmalloc_get_rss(void) {
task_t task = MACH_PORT_NULL;
struct task_basic_info t_info;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
return 0;
task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
return t_info.resident_size;
}
#else
size_t zmalloc_get_rss(void) {
/* If we can't get the RSS in an OS-specific way for this system just
* return the memory usage we estimated in zmalloc()..
*
* Fragmentation will appear to be always 1 (no fragmentation)
* of course... */
return zmalloc_used_memory();
}
#endif
/* Fragmentation = RSS / allocated-bytes */
float zmalloc_get_fragmentation_ratio(size_t rss) {
return (float)rss/zmalloc_used_memory();
}
#if defined(HAVE_PROC_SMAPS)
size_t zmalloc_get_private_dirty(void) {
char line[1024];
size_t pd = 0;
FILE *fp = fopen("/proc/self/smaps","r");
if (!fp) return 0;
while(fgets(line,sizeof(line),fp) != NULL) {
if (strncmp(line,"Private_Dirty:",14) == 0) {
char *p = strchr(line,'k');
if (p) {
*p = '\0';
pd += strtol(line+14,NULL,10) * 1024;
}
}
}
fclose(fp);
return pd;
}
#else
size_t zmalloc_get_private_dirty(void) {
return 0;
}
#endif

86
3rdparty/zmalloc.h vendored
View file

@ -1,86 +0,0 @@
#ifndef ZMALLOC_H
#define ZMALLOC_H
/* zmalloc - total amount of allocated memory aware version of malloc()
*
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Double expansion needed for stringification of macro values. */
#define __xstr(s) __str(s)
#define __str(s) #s
#if defined(USE_TCMALLOC)
#define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR))
#include <google/tcmalloc.h>
#if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1)
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) tc_malloc_size(p)
#else
#error "Newer version of tcmalloc required"
#endif
#elif defined(USE_JEMALLOC) && (JEMALLOC_VERSION_MAJOR > 2)
#define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))
#include <jemalloc/jemalloc.h>
#if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) je_malloc_usable_size(p)
#else
#error "Newer version of jemalloc required"
#endif
#elif defined(__APPLE__)
#include <malloc/malloc.h>
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) malloc_size(p)
#endif
#ifndef ZMALLOC_LIB
#define ZMALLOC_LIB "libc"
#endif
void *zmalloc(size_t size);
void *zcalloc(size_t size);
void *zrealloc(void *ptr, size_t size);
void zfree(void *ptr);
char *zstrdup(const char *s);
char *zstrndup(const char *s, size_t n);
size_t zmalloc_used_memory(void);
void zmalloc_enable_thread_safeness(void);
void zmalloc_set_oom_handler(void (*oom_handler)(size_t));
float zmalloc_get_fragmentation_ratio(size_t rss);
size_t zmalloc_get_rss(void);
size_t zmalloc_get_private_dirty(void);
void zlibc_free(void *ptr);
#ifndef HAVE_MALLOC_SIZE
size_t zmalloc_size(void *ptr);
#endif
#endif // ZMALLOC_H

View file

@ -1,34 +1,49 @@
# cmake file examples cmake_minimum_required(VERSION 3.0)
# https://code.google.com/p/opencv-feature-tracker/source/browse/CMakeLists.txt?r=f804b03e704147e65183c19a50f57abedb22f45c project(r3 VERSION 2.0.0)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)
set(CMAKE_C_STANDARD 99)
# TODO: find_package(Check)
# cmake clean... orz find_package(PCRE2 REQUIRED)
# http://stackoverflow.com/questions/9680420/looking-for-a-cmake-clean-command-to-clear-up-cmake-output
include(CheckSymbolExists)
include(CheckIncludeFile)
check_symbol_exists(strdup string.h HAVE_STRDUP)
check_symbol_exists(strndup string.h HAVE_STRNDUP)
check_include_file(stdbool.h HAVE_STDBOOL_H)
configure_file(config.h.cmake config.h)
cmake_minimum_required(VERSION 2.8)
project(r3)
SET(CMAKE_MODULE_PATH
${PROJECT_SOURCE_DIR}/cmake
${CMAKE_MODULE_PATH}
)
include_directories(. ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/3rdparty /opt/local/include)
# include_directories(. ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/3rdparty ${PROJECT_SOURCE_DIR})
link_directories(${LINK_DIRECTORIES} /opt/local/lib)
find_package(PCRE REQUIRED)
# find_package(Judy REQUIRED)
# set(LIBS ${LIBS} ${PCRE_LIBRARIES} ${Judy_LIBRARIES} r3)
set(LIBS ${LIBS} ${PCRE_LIBRARIES} r3)
# set (CMAKE_CXX_FLAGS "-std=c++0x -arch x86_64 -stdlib=libc++ -g3 -Wall -O0")
enable_testing()
add_subdirectory(3rdparty)
add_subdirectory(src) add_subdirectory(src)
add_subdirectory(tests)
# add_test(test_tree ${CMAKE_CURRENT_BINARY_DIR}/check_tree) install(
FILES
include/memory.h
include/r3.h
include/r3_list.h
include/r3_slug.h
include/r3_gvc.h
include/r3_json.h
include/str_array.h
include/r3.hpp
DESTINATION include/r3)
# Configure substitutions for r3.pc. The variables set here must match the
# @<values>@ in r3.pc.in.
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix ${prefix})
set(includedir ${prefix}/include)
set(libdir ${prefix}/lib)
set(PACKAGE_VERSION ${PROJECT_VERSION})
configure_file(r3.pc.in r3.pc @ONLY)
install(
FILES
${PROJECT_BINARY_DIR}/r3.pc
DESTINATION lib/pkgconfig)
if(CHECK_FOUND)
enable_testing()
add_subdirectory(tests)
else()
message(STATUS "Skipping unit tests, Check library not found!")
endif()

View file

@ -1,15 +1,15 @@
SUBDIRS=3rdparty src . examples SUBDIRS=src . examples
if HAVE_CHECK if ENABLE_CHECK
SUBDIRS += tests SUBDIRS += tests
endif endif
lib_LTLIBRARIES = libr3.la lib_LTLIBRARIES = libr3.la
libr3_la_SOURCES = libr3_la_SOURCES =
libr3_la_LIBADD = 3rdparty/libr3ext.la src/libr3core.la libr3_la_LIBADD = src/libr3core.la
libr3_la_LDFLAGS = libr3_la_LDFLAGS =
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99 AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS)
@ -27,6 +27,7 @@ endif
r3_includedir = $(includedir)/r3 r3_includedir = $(includedir)/r3
r3_include_HEADERS = \ r3_include_HEADERS = \
include/memory.h \
include/r3.h \ include/r3.h \
include/r3_list.h \ include/r3_list.h \
include/r3_slug.h \ include/r3_slug.h \

View file

@ -25,7 +25,7 @@ Requirement
### Runtime Requirement ### Runtime Requirement
* pcre * pcre2
* (optional) graphviz version 2.38.0 (20140413.2041) * (optional) graphviz version 2.38.0 (20140413.2041)
* (optional) libjson-c-dev * (optional) libjson-c-dev
@ -125,7 +125,7 @@ R3Node * matched_node = r3_tree_match_entry(n, entry);
**Release Memory** **Release Memory**
To release the memory, you may call `r3_tree_free(R3Node *tree)` to release the whole tree structure, To release the memory, you may call `r3_tree_free(R3Node *tree)` to release the whole tree structure,
`node*`, `edge*`, `route*` objects that were inserted into the tree will be freed. `node*`, `edge*`, `route*` objects that were inserted into the tree will be freed.
@ -187,13 +187,13 @@ Optimization
Simple regular expressions are optimized through a regexp pattern to opcode Simple regular expressions are optimized through a regexp pattern to opcode
translator, which translates simple patterns into small & fast scanners. translator, which translates simple patterns into small & fast scanners.
By using this method, r3 reduces the matching overhead of pcre library. By using this method, r3 reduces the matching overhead of pcre2 library.
Optimized patterns are: `[a-z]+`, `[0-9]+`, `\d+`, `\w+`, `[^/]+` or `[^-]+` Optimized patterns are: `[a-z]+`, `[0-9]+`, `\d+`, `\w+`, `[^/]+`, `[^-]+` or `.*`.
Slugs without specified regular expression will be compiled into the `[^/]+` pattern. therefore, it's optimized too. Slugs without specified regular expression will be compiled into the `[^/]+` pattern. therefore, it's optimized too.
Complex regular expressions will still use libpcre to match URL (partially). Complex regular expressions will still use libpcre2 to match URL (partially).
Performance Performance
@ -337,10 +337,10 @@ Use case in PHP
```php ```php
// Here is the paths data structure // Here is the paths data structure
$paths = [ $paths = [
'/blog/post/{id}' => [ 'controller' => 'PostController' , 'action' => 'item' , 'method' => 'GET' ] , '/blog/post/{id}' => [ 'controller' => 'PostController' , 'action' => 'item' , 'method' => 'GET' ] ,
'/blog/post' => [ 'controller' => 'PostController' , 'action' => 'list' , 'method' => 'GET' ] , '/blog/post' => [ 'controller' => 'PostController' , 'action' => 'list' , 'method' => 'GET' ] ,
'/blog/post' => [ 'controller' => 'PostController' , 'action' => 'create' , 'method' => 'POST' ] , '/blog/post' => [ 'controller' => 'PostController' , 'action' => 'create' , 'method' => 'POST' ] ,
'/blog' => [ 'controller' => 'BlogController' , 'action' => 'list' , 'method' => 'GET' ] , '/blog' => [ 'controller' => 'BlogController' , 'action' => 'list' , 'method' => 'GET' ] ,
]; ];
$rs = r3_compile($paths, 'persisten-table-id'); $rs = r3_compile($paths, 'persisten-table-id');
$ret = r3_dispatch($rs, '/blog/post/3' ); $ret = r3_dispatch($rs, '/blog/post/3' );
@ -356,7 +356,7 @@ if ( $error ) {
Install Install
---------------------- ----------------------
sudo apt-get install check libpcre3 libpcre3-dev libjemalloc-dev libjemalloc1 build-essential libtool automake autoconf pkg-config sudo apt-get install check libpcre2 libpcre2-dev libjemalloc-dev libjemalloc1 build-essential libtool automake autoconf pkg-config
sudo apt-get install graphviz-dev graphviz # if you want graphviz sudo apt-get install graphviz-dev graphviz # if you want graphviz
./autogen.sh ./autogen.sh
./configure && make ./configure && make
@ -364,7 +364,7 @@ Install
And we support debian-based distro now! And we support debian-based distro now!
sudo apt-get install build-essential autoconf automake libpcre3-dev pkg-config debhelper libtool check sudo apt-get install build-essential autoconf automake libpcre2-dev pkg-config debhelper libtool check
mv dist-debian debian mv dist-debian debian
dpkg-buildpackage -b -us -uc dpkg-buildpackage -b -us -uc
sudo gdebi ../libr3*.deb sudo gdebi ../libr3*.deb

View file

@ -1,37 +0,0 @@
# Copyright (C) 2007-2009 LuaDist.
# Created by Peter Kapec <kapecp@gmail.com>
# Redistribution and use of this file is allowed according to the terms of the MIT license.
# For details see the COPYRIGHT file distributed with LuaDist.
# Note:
# Searching headers and libraries is very simple and is NOT as powerful as scripts
# distributed with CMake, because LuaDist defines directories to search for.
# Everyone is encouraged to contact the author with improvements. Maybe this file
# becomes part of CMake distribution sometimes.
# - Find pcre
# Find the native PCRE headers and libraries.
#
# PCRE_INCLUDE_DIRS - where to find pcre.h, etc.
# PCRE_LIBRARIES - List of libraries when using pcre.
# PCRE_FOUND - True if pcre found.
# Look for the header file.
FIND_PATH(PCRE_INCLUDE_DIR NAMES pcre.h)
# Look for the library.
FIND_LIBRARY(PCRE_LIBRARY NAMES pcre)
# Handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if all listed variables are TRUE.
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_INCLUDE_DIR)
# Copy the results to the output variables.
IF(PCRE_FOUND)
SET(PCRE_LIBRARIES ${PCRE_LIBRARY})
SET(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR})
ELSE(PCRE_FOUND)
SET(PCRE_LIBRARIES)
SET(PCRE_INCLUDE_DIRS)
ENDIF(PCRE_FOUND)
MARK_AS_ADVANCED(PCRE_INCLUDE_DIRS PCRE_LIBRARIES)

View file

@ -0,0 +1,37 @@
# Copyright (C) 2007-2009 LuaDist.
# Created by Peter Kapec <kapecp@gmail.com>
# Redistribution and use of this file is allowed according to the terms of the MIT license.
# For details see the COPYRIGHT file distributed with LuaDist.
# Note:
# Searching headers and libraries is very simple and is NOT as powerful as scripts
# distributed with CMake, because LuaDist defines directories to search for.
# Everyone is encouraged to contact the author with improvements. Maybe this file
# becomes part of CMake distribution sometimes.
# - Find pcre2
# Find the native PCRE2 headers and libraries.
#
# PCRE2_INCLUDE_DIRS - where to find pcre2.h, etc.
# PCRE2_LIBRARIES - List of libraries when using pcre2.
# PCRE2_FOUND - True if pcre2 found.
# Look for the header file.
FIND_PATH(PCRE2_INCLUDE_DIR NAMES pcre2.h)
# Look for the library.
FIND_LIBRARY(PCRE2_LIBRARY NAMES pcre2-8)
# Handle the QUIETLY and REQUIRED arguments and set PCRE2_FOUND to TRUE if all listed variables are TRUE.
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE2 DEFAULT_MSG PCRE2_LIBRARY PCRE2_INCLUDE_DIR)
# Copy the results to the output variables.
IF(PCRE2_FOUND)
SET(PCRE2_LIBRARIES ${PCRE2_LIBRARY})
SET(PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIR})
ELSE(PCRE2_FOUND)
SET(PCRE2_LIBRARIES)
SET(PCRE2_INCLUDE_DIRS)
ENDIF(PCRE2_FOUND)
MARK_AS_ADVANCED(PCRE2_INCLUDE_DIRS PCRE2_LIBRARIES)

3
config.h.cmake Normal file
View file

@ -0,0 +1,3 @@
#cmakedefine HAVE_STRDUP @HAVE_STRDUP@
#cmakedefine HAVE_STRNDUP @HAVE_STRNDUP@
#cmakedefine HAVE_STDBOOL_H @HAVE_STDBOOL_H@

View file

@ -1,4 +1,4 @@
AC_INIT([r3], 1.3.3) AC_INIT([r3], 2.0.0)
AC_PREREQ([2.64]) AC_PREREQ([2.64])
AC_USE_SYSTEM_EXTENSIONS AC_USE_SYSTEM_EXTENSIONS
AC_CONFIG_HEADERS(config.h) AC_CONFIG_HEADERS(config.h)
@ -23,8 +23,6 @@ AC_C_INLINE
AC_TYPE_SIZE_T AC_TYPE_SIZE_T
# Checks for library functions. # Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([gettimeofday memset strchr strdup strndup strstr]) AC_CHECK_FUNCS([gettimeofday memset strchr strdup strndup strstr])
PKG_PROG_PKG_CONFIG PKG_PROG_PKG_CONFIG
@ -51,7 +49,7 @@ if test "x$found_jemalloc" == "xyes" ; then
AC_MSG_CHECKING([Checking jemalloc version]) AC_MSG_CHECKING([Checking jemalloc version])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <jemalloc/jemalloc.h>]], AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <jemalloc/jemalloc.h>]],
[[ [[
#ifdef JEMALLOC_VERSION_MAJOR > 2 #ifdef JEMALLOC_VERSION_MAJOR > 2
return 0; return 0;
#endif #endif
@ -75,7 +73,7 @@ AM_CONDITIONAL(USE_JEMALLOC, test "x$have_jemalloc" = "xyes")
# AC_DEFINE(USE_JEMALLOC, test "x$found_jemalloc" = "xyes" , "use jemalloc") # AC_DEFINE(USE_JEMALLOC, test "x$found_jemalloc" = "xyes" , "use jemalloc")
PKG_CHECK_MODULES(DEPS, [libpcre]) PKG_CHECK_MODULES(DEPS, [libpcre2-8])
AC_SUBST(DEPS_CFLAGS) AC_SUBST(DEPS_CFLAGS)
AC_SUBST(DEPS_LIBS) AC_SUBST(DEPS_LIBS)
@ -118,20 +116,21 @@ AC_ARG_ENABLE(check,
AS_HELP_STRING([--enable-check], AS_HELP_STRING([--enable-check],
[enable unit testing]), [enable unit testing]),
, enable_check=unset) , enable_check=unset)
if test "x$enable_check" != "xunset" ; then if test "x$enable_check" != "xunset" ; then
PKG_CHECK_MODULES(CHECK,[check >= 0.9.4],:,[ PKG_CHECK_MODULES(CHECK,[check >= 0.9.4],:,[
ifdef([AM_PATH_CHECK], ifdef([AM_PATH_CHECK],
[AM_PATH_CHECK(,[have_check="yes"])], [AM_PATH_CHECK(,[have_check="yes"])],
AC_MSG_WARN([Check not found; cannot run unit tests!]) AC_MSG_WARN([Check not found; cannot run unit tests!])
[have_check="no"])] [have_check="no"]
)]
]) ])
fi fi
AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes") AM_CONDITIONAL(ENABLE_CHECK, test "x$enable_check" = "xyes")
AC_CONFIG_FILES([ AC_CONFIG_FILES([
r3.pc r3.pc
Makefile Makefile
3rdparty/Makefile
src/Makefile src/Makefile
tests/Makefile tests/Makefile
examples/Makefile examples/Makefile

View file

@ -2,7 +2,7 @@ Source: libr3
Priority: optional Priority: optional
Maintainer: Ronmi Ren <ronmi.ren@gmail.com> Maintainer: Ronmi Ren <ronmi.ren@gmail.com>
Build-Depends: debhelper (>= 8.0.0), automake, autotools-dev, autoconf, Build-Depends: debhelper (>= 8.0.0), automake, autotools-dev, autoconf,
libtool, libpcre3-dev, pkg-config, check libtool, libpcre2-dev, pkg-config, check
Standards-Version: 3.9.4 Standards-Version: 3.9.4
Section: libs Section: libs
Homepage: https://github.com/c9s/r3 Homepage: https://github.com/c9s/r3

95
examples/routing.c Normal file
View 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();
}

View file

@ -51,8 +51,9 @@ int main()
match_entry * e = match_entry_createl("/garply/baz/grault", strlen("/garply/baz/grault") ); match_entry * e = match_entry_createl("/garply/baz/grault", strlen("/garply/baz/grault") );
m = r3_tree_match_entry(n , e); m = r3_tree_match_entry(n , e);
if (m) { if (m) {
printf("Matched! %s\n", e->path); printf("Matched! %s\n", e->path.base);
} }
match_entry_free(e); match_entry_free(e);
r3_tree_free(n);
return 0; return 0;
} }

141
include/memory.h Normal file
View file

@ -0,0 +1,141 @@
/*
* 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
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#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
/**
* buffer structure compatible with iovec
*/
typedef struct st_r3_iovec_t {
const char *base;
unsigned int len;
} r3_iovec_t;
#define R3_VECTOR(type) \
struct { \
type *entries; \
unsigned int size; \
unsigned int capacity; \
}
typedef R3_VECTOR(void) r3_vector_t;
/**
* 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);
/**
* wrapper of realloc; reallocs the given chunk or dies if impossible
*/
static void *r3_mem_realloc(void *oldp, unsigned int sz);
/**
* grows the vector so that it could store at least new_capacity elements of given size (or dies if impossible).
* @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(vector, new_capacity) \
r3_vector__reserve((r3_vector_t *)(void *)(vector), sizeof((vector)->entries[0]), (new_capacity))
static void r3_vector__reserve(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity);
void r3_vector__expand(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity);
/* 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_vector__reserve(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity)
{
if (vector->capacity < new_capacity) {
r3_vector__expand(vector, element_size, new_capacity);
}
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -10,28 +10,23 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <pcre.h> #define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#if __STDC_VERSION__ <= 201710L
#ifdef HAVE_STDBOOL_H #ifdef HAVE_STDBOOL_H
# include <stdbool.h>
#include <stdbool.h> #elif !defined(bool) && !defined(__cplusplus)
#else
#if !defined(bool) && !defined(__cplusplus)
typedef unsigned char bool; typedef unsigned char bool;
# define bool bool /* For redefinition guards */
# define false 0
# define true 1
#endif #endif
#ifndef false
# define false 0
#endif
#ifndef true
# define true 1
#endif
#endif #endif
#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 +41,68 @@ 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; pcre2_code * pcre_pattern;
pcre_extra * pcre_extra; pcre2_match_data * match_data;
// 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
R3Route ** routes;
// the pointer of R3Route data // the pointer of R3Route data
void * data; void * data;
};
// almost less than 255 #define r3_node_edge_pattern(node,i) node->edges.entries[i].pattern.base
unsigned char edge_cap; #define r3_node_edge_pattern_len(node,i) node->edges.entries[i].pattern.len
unsigned char route_len;
unsigned char route_cap;
} __attribute__((aligned(64)));
#define r3_node_edge_pattern(node,i) node->edges[i]->pattern
#define r3_node_edge_pattern_len(node,i) node->edges[i]->pattern_len
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 opcode; // 4byte unsigned int opcode; // 4byte
unsigned int has_slug; // 4byte unsigned int has_slug; // 4byte
} __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)));
typedef struct { unsigned int remote_addr_v4;
str_array * vars; int remote_addr_v4_bits;
const char * path; // current path to dispatch
int path_len; // the length of the current path unsigned int remote_addr_v6[4];
int request_method; // current request method int remote_addr_v6_bits[4];
int http_scheme; // can be (SCHEME_HTTP or SCHEME_HTTPS)
};
typedef struct _R3Entry match_entry;
struct _R3Entry {
str_array vars;
r3_iovec_t path; // current path to dispatch
int request_method; // current request method
void * data; // R3Route ptr void * data; // R3Route ptr
char * host; // the request host r3_iovec_t host; // the request host
int host_len; r3_iovec_t remote_addr;
char * remote_addr;
int remote_addr_len;
} match_entry;
int http_scheme;
};
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 +110,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 +128,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 +136,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 +148,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 +171,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);
@ -209,13 +193,16 @@ R3Route * r3_tree_match_route(const R3Node *n, match_entry * entry);
#define METHOD_HEAD 2<<5 #define METHOD_HEAD 2<<5
#define METHOD_OPTIONS 2<<6 #define METHOD_OPTIONS 2<<6
#define SCHEME_HTTP 2
#define SCHEME_HTTPS 2<<1
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 };
enum { OP_EXPECT_MORE_DIGITS = 1, OP_EXPECT_MORE_WORDS, OP_EXPECT_NOSLASH, OP_EXPECT_NODASH, OP_EXPECT_MORE_ALPHA }; enum { OP_EXPECT_MORE_DIGITS = 1, OP_EXPECT_MORE_WORDS, OP_EXPECT_NOSLASH,
OP_EXPECT_NODASH, OP_EXPECT_MORE_ALPHA, OP_GREEDY_ANY};

View file

@ -8,7 +8,7 @@
#define R3_HPP #define R3_HPP
#include <cstring> #include <cstring>
#include <r3.h> #include "r3.h"
namespace r3 { namespace r3 {
template <typename T> template <typename T>
@ -90,13 +90,13 @@ namespace r3 {
} }
Node insert_path(const char* path, void* data, char** errstr = NULL) { Node insert_path(const char* path, void* data, char** errstr = NULL) {
return r3_tree_insert_pathl_ex(get(), path, std::strlen(path), NULL, return r3_tree_insert_pathl_ex(get(), path, std::strlen(path), 0, 0,
data, errstr); data, errstr);
} }
Node insert_pathl(const char* path, int path_len, void* data, Node insert_pathl(const char* path, int path_len, void* data,
char** errstr = NULL) { char** errstr = NULL) {
return r3_tree_insert_pathl_ex(get(), path, path_len, NULL, data, return r3_tree_insert_pathl_ex(get(), path, path_len, 0, 0, data,
errstr); errstr);
} }

View file

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

View file

@ -8,28 +8,34 @@
#ifndef STR_ARRAY_H #ifndef STR_ARRAY_H
#define STR_ARRAY_H #define STR_ARRAY_H
#include "memory.h"
#if __STDC_VERSION__ <= 201710L
#ifdef HAVE_STDBOOL_H
# include <stdbool.h>
#elif !defined(bool) && !defined(__cplusplus)
typedef unsigned char bool;
# define bool bool /* For redefinition guards */
# define false 0
# define true 1
#endif
#endif
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); bool str_array_append(str_array * l, const char * token, unsigned int len);
bool str_array_is_full(const str_array * l);
bool str_array_resize(str_array *l, int new_cap);
bool str_array_append(str_array * list, char * token);
void str_array_free(str_array *l); void str_array_free(str_array *l);
void str_array_dump_slugs(const str_array *l);
void str_array_dump(const str_array *l); void str_array_dump(const str_array *l);
str_array * split_route_pattern(char *pattern, int pattern_len); #define str_array_fetch(t,i) t->tokens.entries[i]
#define str_array_len(t) t->tokens.size
#define str_array_fetch(t,i) t->tokens[i] #define str_array_cap(t) t->tokens.capacity
#define str_array_len(t) t->len
#define str_array_cap(t) t->cap
#endif /* !STR_ARRAY_H */ #endif /* !STR_ARRAY_H */

View file

@ -1,9 +1,9 @@
{ {
"name": "r3", "name": "r3",
"version": "1.3.3", "version": "2.0.0",
"repo": "brendanashworth/r3", "repo": "brendanashworth/r3",
"description": "high-performance path dispatching library", "description": "high-performance path dispatching library",
"keywords": ["path", "dispatch", "performance", "r3", "c9s"], "keywords": ["path", "dispatch", "performance", "r3", "c9s"],
"license": "MIT", "license": "MIT",
"src": ["3rdparty/zmalloc.c", "3rdparty/zmalloc.h", "include/r3.h", "include/r3.hpp", "include/r3_gvc.h", "include/r3_json.h", "include/r3_list.h", "include/r3_slug.h", "include/str_array.h", "src/edge.c", "src/gvc.c", "src/json.c", "src/list.c", "src/match_entry.c", "src/node.c", "src/slug.c", "src/slug.h", "src/str.c", "src/token.c"] "src": ["include/memory.h", "include/r3.h", "include/r3.hpp", "include/r3_gvc.h", "include/r3_json.h", "include/r3_list.h", "include/r3_slug.h", "include/str_array.h", "src/edge.c", "src/gvc.c", "src/json.c", "src/list.c", "src/match_entry.c", "src/node.c", "src/slug.c", "src/slug.h", "src/str.c", "src/token.c"]
} }

View file

@ -6,6 +6,6 @@ libdir=@libdir@
Name: r3 Name: r3
Description: High-performance URL router library Description: High-performance URL router library
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
Requires: libpcre Requires: libpcre2-8
Libs: -L${libdir} -lr3 Libs: -L${libdir} -lr3
CFlags: -I${includedir} CFlags: -I${includedir}

View file

@ -1,9 +1,27 @@
include_directories("${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/3rdparty ${PROJECT_SOURCE_DIR}") add_library(r3 STATIC
# install(TARGETS swiftnav-static DESTINATION lib${LIB_SUFFIX}) edge.c
find_package(PCRE REQUIRED) 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) node.c
slug.c
str.c
token.c)
add_library(r3 STATIC ${libr3_SRCS}) target_compile_definitions(r3
target_link_libraries(r3 lib3rdparty pcre) PRIVATE
# install(FILES ${libswiftnav_HEADERS} DESTINATION include/libswiftnav) _GNU_SOURCE)
target_include_directories(r3
PUBLIC
${PCRE2_INCLUDE_DIR}
${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/3rdparty
${PROJECT_SOURCE_DIR}/include)
target_link_libraries(r3
PUBLIC
${PCRE2_LIBRARIES})
install(
TARGETS r3
DESTINATION lib)

View file

@ -1,10 +1,10 @@
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99 AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS) AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS)
MAYBE_COVERAGE=--coverage 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
@ -23,7 +23,7 @@ MOSTLYCLEANFILES = *.gcov *.gcda *.gcno
# libr3_la_LIBADD=$(DEPS_LIBS) $(LIBOBJS) $(ALLOCA) # libr3_la_LIBADD=$(DEPS_LIBS) $(LIBOBJS) $(ALLOCA)
# libr3core_la_LIBADD=$(DEPS_LIBS) # libr3core_la_LIBADD=$(DEPS_LIBS)
# libr3core_la_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99 # libr3core_la_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
if ENABLE_GRAPHVIZ if ENABLE_GRAPHVIZ
libr3core_la_SOURCES += gvc.c libr3core_la_SOURCES += gvc.c

View file

@ -13,12 +13,9 @@
// Jemalloc memory management // Jemalloc memory management
// #include <jemalloc/jemalloc.h> // #include <jemalloc/jemalloc.h>
// PCRE
#include <pcre.h>
#include "r3.h" #include "r3.h"
#include "r3_slug.h" #include "r3_slug.h"
#include "slug.h" #include "slug.h"
#include "zmalloc.h"
#define CHECK_PTR(ptr) if (ptr == NULL) return NULL; #define CHECK_PTR(ptr) if (ptr == NULL) return NULL;
@ -27,24 +24,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*) malloc( 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 +61,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; const 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
// free(e);
} }
// free itself
zfree(e);
} }

View file

@ -10,14 +10,13 @@
#include <stdlib.h> #include <stdlib.h>
#include "r3.h" #include "r3.h"
#include "r3_gvc.h" #include "r3_gvc.h"
#include "zmalloc.h"
void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node * n, int * node_cnt) { void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node * n, int * node_cnt) {
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;
@ -25,9 +24,11 @@ void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node
char *nodename = NULL; char *nodename = NULL;
if ( e && e->child && e->child->combined_pattern ) { if ( e && e->child && e->child->combined_pattern ) {
asprintf(&nodename,"%s", e->child->combined_pattern); int r = asprintf(&nodename,"%s", e->child->combined_pattern);
if (r) {};
} else { } else {
asprintf(&nodename,"#%d", *node_cnt); int r = asprintf(&nodename,"#%d", *node_cnt);
if (r) {};
} }
agn_child = agnode(g, nodename, 1); agn_child = agnode(g, nodename, 1);

View file

@ -13,15 +13,15 @@ json_object * r3_route_to_json_object(const R3Route * r) {
json_object *obj; json_object *obj;
obj = json_object_new_object(); obj = json_object_new_object();
json_object_object_add(obj, "path", json_object_new_string(r->path)); json_object_object_add(obj, "path", json_object_new_string(r->path.base));
json_object_object_add(obj, "allowed_methods", json_object_new_int(r->request_method)); json_object_object_add(obj, "allowed_methods", json_object_new_int(r->request_method));
if (r->host) { if (r->host) {
json_object_object_add(obj, "host", json_object_new_string(r->host)); json_object_object_add(obj, "host", json_object_new_string(r->host.base));
} }
if (r->remote_addr_pattern) { if (r->remote_addr_pattern) {
json_object_object_add(obj, "remote_addr_pattern", json_object_new_string(r->remote_addr_pattern)); json_object_object_add(obj, "remote_addr_pattern", json_object_new_string(r->remote_addr_pattern.base));
} }
return obj; return obj;
} }
@ -31,7 +31,7 @@ json_object * r3_edge_to_json_object(const R3Edge * e) {
json_object *obj; json_object *obj;
obj = json_object_new_object(); obj = json_object_new_object();
json_object_object_add(obj, "pattern", json_object_new_string(e->pattern)); json_object_object_add(obj, "pattern", json_object_new_string(e->pattern.base));
json_object_object_add(obj, "opcode", json_object_new_int(e->opcode)); json_object_object_add(obj, "opcode", json_object_new_int(e->opcode));
json_object_object_add(obj, "slug", json_object_new_boolean(e->has_slug)); json_object_object_add(obj, "slug", json_object_new_boolean(e->has_slug));
@ -60,7 +60,7 @@ json_object * r3_node_to_json_object(const R3Node * n) {
json_object *edges_array = json_object_new_array(); json_object *edges_array = json_object_new_array();
json_object_object_add(obj, "edges", edges_array); json_object_object_add(obj, "edges", edges_array);
for (i = 0 ; i < n->edge_len ; i++ ) { for (i = 0 ; i < n->edge_len ; i++ ) {
json_object *edge_json_obj = r3_edge_to_json_object(&n->edges[i]); json_object *edge_json_obj = r3_edge_to_json_object(n->edges.entries + i);
json_object_array_add(edges_array, edge_json_obj); json_object_array_add(edges_array, edge_json_obj);
} }
} }
@ -69,7 +69,7 @@ json_object * r3_node_to_json_object(const R3Node * n) {
json_object *routes_array = json_object_new_array(); json_object *routes_array = json_object_new_array();
json_object_object_add(obj, "routes", routes_array); json_object_object_add(obj, "routes", routes_array);
for (i = 0; i < n->route_len; i++ ) { for (i = 0; i < n->route_len; i++ ) {
json_object *route_json_obj = r3_route_to_json_object(n->routes[i]); json_object *route_json_obj = r3_route_to_json_object(n->routes.entries + i);
json_object_array_add(routes_array, route_json_obj); json_object_array_add(routes_array, route_json_obj);
} }
} }

View file

@ -5,14 +5,13 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include "r3_list.h" #include "r3_list.h"
#include "zmalloc.h"
/* Naive linked list implementation */ /* Naive linked list implementation */
list * list *
list_create() list_create()
{ {
list *l = (list *) zmalloc(sizeof(list)); list *l = (list *) malloc(sizeof(list));
l->count = 0; l->count = 0;
l->head = NULL; l->head = NULL;
l->tail = NULL; l->tail = NULL;
@ -38,7 +37,7 @@ list_free(l)
} }
pthread_mutex_unlock(&(l->mutex)); pthread_mutex_unlock(&(l->mutex));
pthread_mutex_destroy(&(l->mutex)); pthread_mutex_destroy(&(l->mutex));
zfree(l); free(l);
} }
} }
@ -48,7 +47,7 @@ list_item * list_add_element(list * l, void * ptr)
pthread_mutex_lock(&(l->mutex)); pthread_mutex_lock(&(l->mutex));
li = (list_item *) zmalloc(sizeof(list_item)); li = (list_item *) malloc(sizeof(list_item));
li->value = ptr; li->value = ptr;
li->next = NULL; li->next = NULL;
li->prev = l->tail; li->prev = l->tail;
@ -89,7 +88,7 @@ list_remove_element(l, ptr)
li->next->prev = li->prev; li->next->prev = li->prev;
} }
l->count--; l->count--;
zfree(li); free(li);
result = 1; result = 1;
break; break;
} }

View file

@ -8,28 +8,21 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <pcre.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h>
#include "r3.h" #include "r3.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(&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);
} }

45
src/memory.c Normal file
View file

@ -0,0 +1,45 @@
/*
* 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 "config.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "memory.h"
void r3_fatal(const char *msg)
{
fprintf(stderr, "fatal:%s\n", msg);
abort();
}
void r3_vector__expand(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;
new_entries = r3_mem_realloc(vector->entries, element_size * vector->capacity);
vector->entries = new_entries;
}

File diff suppressed because it is too large Load diff

View file

@ -12,12 +12,11 @@
#include "r3_slug.h" #include "r3_slug.h"
#include "slug.h" #include "slug.h"
#include "r3_debug.h" #include "r3_debug.h"
#include "zmalloc.h"
r3_slug_t * r3_slug_new(const char * path, int path_len) { r3_slug_t * r3_slug_new(const char * path, int path_len) {
r3_slug_t * s = zmalloc(sizeof(r3_slug_t)); r3_slug_t * s = malloc(sizeof(r3_slug_t));
if (!s) if (!s)
return NULL; return NULL;
s->path = (char*) path; s->path = (char*) path;
@ -33,7 +32,7 @@ r3_slug_t * r3_slug_new(const char * path, int path_len) {
} }
void r3_slug_free(r3_slug_t * s) { void r3_slug_free(r3_slug_t * s) {
zfree(s); free(s);
} }
@ -61,7 +60,8 @@ int r3_slug_check(r3_slug_t *s) {
char * r3_slug_to_str(const r3_slug_t *s) { char * r3_slug_to_str(const r3_slug_t *s) {
char *str = NULL; char *str = NULL;
asprintf(&str, "slug: '%.*s', pattern: '%.*s', path: '%.*s'", s->len, s->begin, s->pattern_len, s->pattern, s->path_len, s->path); int r = asprintf(&str, "slug: '%.*s', pattern: '%.*s', path: '%.*s'", s->len, s->begin, s->pattern_len, s->pattern, s->path_len, s->path);
if (r) {};
return str; return str;
} }
@ -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 - (offset-needle))) {
return 0; return 0;
} }
@ -140,7 +140,8 @@ int r3_slug_parse(r3_slug_t *s, const char *needle, int needle_len, const char *
if (state != 0) { if (state != 0) {
if (errstr) { if (errstr) {
char *err = NULL; char *err = NULL;
asprintf(&err, "Incomplete slug pattern. PATH (%d): '%s', OFFSET: %ld, STATE: %d", needle_len, needle, p - needle, state); int r = asprintf(&err, "Incomplete slug pattern. PATH (%d): '%s', OFFSET: %ld, STATE: %d", needle_len, needle, p - needle, state);
if (r) {};
*errstr = err; *errstr = err;
} }
return -1; return -1;
@ -178,7 +179,8 @@ int r3_slug_count(const char * needle, int len, char **errstr) {
if (state != 0) { if (state != 0) {
if (errstr) { if (errstr) {
char *err = NULL; char *err = NULL;
asprintf(&err, "Incomplete slug pattern. PATTERN (%d): '%s', OFFSET: %ld, STATE: %d", len, needle, p - needle, state); int r = asprintf(&err, "Incomplete slug pattern. PATTERN (%d): '%s', OFFSET: %ld, STATE: %d", len, needle, p - needle, state);
if (r) {};
*errstr = err; *errstr = err;
} }
return -1; return -1;

View file

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

115
src/str.c
View file

@ -13,9 +13,15 @@
#include "r3_slug.h" #include "r3_slug.h"
#include "str.h" #include "str.h"
#include "slug.h" #include "slug.h"
#include "zmalloc.h"
int r3_pattern_to_opcode(const char * pattern, int len) { static const 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;
} }
@ -37,6 +43,9 @@ int r3_pattern_to_opcode(const char * pattern, int len) {
if ( strncmp(pattern, "[^-]+", len) == 0 ) { if ( strncmp(pattern, "[^-]+", len) == 0 ) {
return OP_EXPECT_NODASH; return OP_EXPECT_NODASH;
} }
if ( strncmp(pattern, ".*", len) == 0 ) {
return OP_GREEDY_ANY;
}
return 0; return 0;
} }
@ -72,21 +81,23 @@ char * r3_inside_slug(const char * needle, int needle_len, char *offset, char **
if (found_s1 || found_s2) { if (found_s1 || found_s2) {
// wrong slug pattern // wrong slug pattern
if(errstr) { if(errstr) {
asprintf(errstr, "Incomplete slug pattern"); int r = asprintf(errstr, "Incomplete slug pattern");
if (r) {};
} }
return NULL; return NULL;
} }
return NULL; return NULL;
} }
char * r3_slug_find_placeholder(const char *s1, int *len) { const char * r3_slug_find_placeholder(const char *s1, unsigned int str_len, unsigned int *len) {
char *c; const char *c;
char *s2; const 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 +122,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) { const char * r3_slug_find_pattern(const char *s1, unsigned int str_len, unsigned int *len) {
char *c; const char *c;
char *s2; const 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 +144,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,54 +155,46 @@ 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) { const char * r3_slug_find_name(const char *s1, unsigned int str_len, unsigned int *len) {
char * c; const char * c;
char * s2; const char * s2;
int cnt = 0; unsigned int plholder;
c = (char*) s1; if ((c = r3_slug_find_placeholder(s1, str_len, &plholder))) {
c++;
while(1) { if (( s2 = strnchr(c, plholder, ':') )) {
if(*c == '{') cnt++; *len = s2 - c;
if(*c == '}') cnt--; return c;
if(*c == ':') break; } else {
if(*c == '\0') return NULL; *len = plholder - 2;
if(cnt == 0) break; return c;
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; const char *s1 = NULL;
char *pat = NULL; char *o = NULL;
const char *pat = NULL;
char sep = '/'; char sep = '/';
// 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 strndup(str,len);
} }
char * out = NULL; char * out = NULL;
if ((out = zcalloc(sizeof(char) * 200)) == NULL) { if (!(out = calloc(1, sizeof(char) * 200))) {
return (NULL); return (NULL);
} }
@ -199,8 +206,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 +221,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;
} }
@ -223,7 +230,7 @@ char * ltrim_slash(char* str)
{ {
char * p = str; char * p = str;
while (*p == '/') p++; while (*p == '/') p++;
return zstrdup(p); return strdup(p);
} }
void print_indent(int level) { void print_indent(int level) {
@ -236,13 +243,13 @@ void print_indent(int level) {
#ifndef HAVE_STRDUP #ifndef HAVE_STRDUP
char *zstrdup(const char *s) { char *strdup(const char *s) {
char *out; char *out;
int count = 0; int count = 0;
while( s[count] ) while( s[count] )
++count; ++count;
++count; ++count;
out = zmalloc(sizeof(char) * count); out = malloc(sizeof(char) * count);
out[--count] = 0; out[--count] = 0;
while( --count >= 0 ) while( --count >= 0 )
out[count] = s[count]; out[count] = s[count];
@ -253,13 +260,13 @@ char *zstrdup(const char *s) {
#ifndef HAVE_STRNDUP #ifndef HAVE_STRNDUP
char *zstrndup(const char *s, int n) { char *strndup(const char *s, int n) {
char *out; char *out;
int count = 0; int count = 0;
while( count < n && s[count] ) while( count < n && s[count] )
++count; ++count;
++count; ++count;
out = zmalloc(sizeof(char) * count); out = malloc(sizeof(char) * count);
out[--count] = 0; out[--count] = 0;
while( --count >= 0 ) while( --count >= 0 )
out[count] = s[count]; out[count] = s[count];

View file

@ -12,55 +12,43 @@
#include "r3.h" #include "r3.h"
#include "r3_slug.h" #include "r3_slug.h"
#include "str_array.h" #include "str_array.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, const char * token, unsigned int len) {
return l->len >= l->cap; r3_vector_reserve(&l->tokens, l->tokens.size + 1);
} r3_iovec_t *temp = l->tokens.entries + l->tokens.size++;
memset(temp, 0, sizeof(*temp));
bool str_array_resize(str_array * l, int new_cap) { temp->base = token;
l->tokens = zrealloc(l->tokens, sizeof(char**) * new_cap); temp->len = len;
l->cap = new_cap;
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(", ");
} }
} }

View file

@ -1,24 +1,27 @@
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3) function(add_r3_test NAME)
include_directories("${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}") add_executable(${NAME} ${ARGN})
find_package(Check REQUIRED)
find_package(PCRE REQUIRED)
# find_package(Judy REQUIRED)
if (NOT CHECK_FOUND) target_include_directories(${NAME}
message(STATUS "Skipping unit tests, Check library not found!") PRIVATE
else (NOT CHECK_FOUND) ${CHECK_INCLUDE_DIRS}
set(TEST_LIBS ${LIBS} ${CHECK_LIBRARIES} ${PCRE_LIBRARIES} r3) ${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/src)
include_directories(${CHECK_INCLUDE_DIRS}) target_link_libraries(${NAME}
# include_directories("${PROJECT_SOURCE_DIR}/include/r2") ${CHECK_LDFLAGS}
add_executable(check_tree check_tree.c) r3)
target_link_libraries(check_tree ${TEST_LIBS})
add_custom_command( add_test(NAME ${NAME} COMMAND ${NAME})
TARGET check_tree POST_BUILD endfunction()
COMMENT "Running unit tests"
COMMAND check_tree
)
endif (NOT CHECK_FOUND)
add_r3_test(check_tree check_tree.c)
add_r3_test(check_slug check_slug.c)
add_r3_test(check_routes check_routes.c)
add_r3_test(check_str_array check_str_array.c)
add_r3_test(check_host check_host.c)
add_r3_test(check_http_scheme check_http_scheme.c)
add_r3_test(check_remote_addr check_remote_addr.c)
add_r3_test(check_routes2 check_routes2.c)
add_executable(bench bench.c)
target_link_libraries(bench r3)

View file

@ -1,6 +1,6 @@
TESTS = TESTS =
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) @CHECK_CFLAGS@ -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/src -I$(top_builddir)/3rdparty -Wall -std=c99 -ggdb AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) @CHECK_CFLAGS@ -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/src -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
@ -27,6 +27,18 @@ check_routes_SOURCES = check_routes.c
TESTS += check_str_array TESTS += check_str_array
check_str_array_SOURCES = check_str_array.c check_str_array_SOURCES = check_str_array.c
TESTS += check_host
check_host_SOURCES = check_host.c
TESTS += check_remote_addr
check_remote_addr_SOURCES = check_remote_addr.c
TESTS += check_http_scheme
check_http_scheme_SOURCES = check_http_scheme.c
TESTS += check_routes2
check_routes2_SOURCES = check_routes2.c
if ENABLE_JSON if ENABLE_JSON
TESTS += check_json TESTS += check_json

View file

@ -13,7 +13,6 @@
#include "r3.h" #include "r3.h"
#include "r3_slug.h" #include "r3_slug.h"
#include "zmalloc.h"
#include "bench.h" #include "bench.h"
@ -464,7 +463,8 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL);
R3Node * tree2 = r3_tree_create(1); R3Node * tree2 = r3_tree_create(1);
r3_tree_insert_path(tree2, "/post/{year}/{month}", NULL); r3_tree_insert_path(tree2, "/post/{year}/{month}", NULL);
r3_tree_compile(tree2, NULL); r3_tree_compile(tree2, NULL);
// r3_tree_dump(tree2,0);
BENCHMARK(pcre_dispatch) BENCHMARK(pcre_dispatch)
r3_tree_matchl(tree2, "/post/2014/12", strlen("/post/2014/12"), NULL); r3_tree_matchl(tree2, "/post/2014/12", strlen("/post/2014/12"), NULL);
END_BENCHMARK(pcre_dispatch) END_BENCHMARK(pcre_dispatch)

92
tests/check_host.c Normal file
View file

@ -0,0 +1,92 @@
#include "config.h"
#include <stdio.h>
#include <check.h>
#include <stdlib.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
START_TEST (test_hosts)
{
R3Node * n = r3_tree_create(10);
R3Route * route = NULL;
match_entry * entry;
R3Route *matched_route;
char * uri0 = "/foo";
char * host0 = "foo.com";
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
route->host.base = host0;
route->host.len = strlen(host0);
char * uri1 = "/bar";
char * host1 = "*.bar.com";
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
route->host.base = host1;
route->host.len = strlen(host1);
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo");
entry->host.base = host0;
entry->host.len = strlen(host0);
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->host.base = "www.bar.com";
entry->host.len = strlen("www.bar.com");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->host.base = "bar.com";
entry->host.len = strlen("bar.com");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->host.base = ".bar.com";
entry->host.len = strlen(".bar.com");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->host.base = "a.bar.com";
entry->host.len = strlen("a.bar.com");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
Suite* r3_suite (void) {
Suite *suite = suite_create("r3 host tests");
TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_hosts);
suite_add_tcase(suite, tcase);
return suite;
}
int main (int argc, char *argv[]) {
int number_failed;
Suite *suite = r3_suite();
SRunner *runner = srunner_create(suite);
srunner_run_all(runner, CK_NORMAL);
number_failed = srunner_ntests_failed(runner);
srunner_free(runner);
return number_failed;
}

105
tests/check_http_scheme.c Normal file
View file

@ -0,0 +1,105 @@
#include "config.h"
#include <stdio.h>
#include <check.h>
#include <stdlib.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
START_TEST (test_http_scheme)
{
R3Node * n = r3_tree_create(10);
R3Route * route = NULL;
match_entry * entry;
R3Route *matched_route;
char * uri0 = "/foo";
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
char * uri1 = "/bar";
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
route->http_scheme = SCHEME_HTTPS;
char * uri2 = "/boo";
route = r3_tree_insert_routel(n, 0, uri2, strlen(uri2), &uri2);
route->http_scheme = SCHEME_HTTP | SCHEME_HTTPS;
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo");
entry->http_scheme = SCHEME_HTTP;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/bar");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->http_scheme = SCHEME_HTTP;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->http_scheme = SCHEME_HTTPS;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
entry = match_entry_create("/boo");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->http_scheme = SCHEME_HTTP;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri2);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->http_scheme = SCHEME_HTTPS;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri2);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
Suite* r3_suite (void) {
Suite *suite = suite_create("r3 remote_addr tests");
TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_http_scheme);
suite_add_tcase(suite, tcase);
return suite;
}
int main (int argc, char *argv[]) {
int number_failed;
Suite *suite = r3_suite();
SRunner *runner = srunner_create(suite);
srunner_run_all(runner, CK_NORMAL);
number_failed = srunner_ntests_failed(runner);
srunner_free(runner);
return number_failed;
}

216
tests/check_remote_addr.c Normal file
View file

@ -0,0 +1,216 @@
#include "config.h"
#include <stdio.h>
#include <check.h>
#include <stdlib.h>
#include <assert.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "r3.h"
#include "r3_slug.h"
START_TEST (test_remote_addrs)
{
R3Node * n = r3_tree_create(10);
R3Route * route = NULL;
match_entry * entry;
R3Route *matched_route;
char * uri0 = "/foo";
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
route->remote_addr_v4 = 0;
route->remote_addr_v4_bits = 0;
char * uri1 = "/bar";
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
route->remote_addr_v4 = inet_network("127.0.0.1");
route->remote_addr_v4_bits = 32;
char * uri2 = "/boo";
route = r3_tree_insert_routel(n, 0, uri2, strlen(uri2), &uri2);
route->remote_addr_v4 = inet_network("127.0.0.1");
route->remote_addr_v4_bits = 24;
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo");
entry->remote_addr.base = "127.0.0.1";
entry->remote_addr.len = sizeof("127.0.0.1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->remote_addr.base = "127.0.0.1";
entry->remote_addr.len = sizeof("127.0.0.1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->remote_addr.base = "127.0.0.2";
entry->remote_addr.len = sizeof("127.0.0.2") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->remote_addr.base = "127.0.0.1";
entry->remote_addr.len = sizeof("127.0.0.1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri2);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->remote_addr.base = "127.0.0.2";
entry->remote_addr.len = sizeof("127.0.0.2") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri2);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->remote_addr.base = "127.0.1.2";
entry->remote_addr.len = sizeof("127.0.1.2") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->remote_addr.base = "127.0.1.333"; // invalid ip address
entry->remote_addr.len = sizeof("127.0.1.333") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
void parse_ipv6(const char *ipv6, int nmask, R3Route * route)
{
struct in6_addr addr6;
int ret = inet_pton(AF_INET6, ipv6, (void *)&addr6);
ck_assert(ret == 1);
for (int i = 0; i < 4; i++) {
route->remote_addr_v6[i] = ntohl(addr6.__in6_u.__u6_addr32[i]);
if (nmask >= 32) {
route->remote_addr_v6_bits[i] = 32;
} else if (nmask > 0) {
route->remote_addr_v6_bits[i] = nmask;
} else {
route->remote_addr_v6_bits[i] = 0;
}
nmask -= 32;
}
}
START_TEST (test_remote_addrs_ipv6)
{
R3Node * n = r3_tree_create(10);
R3Route * route = NULL;
match_entry * entry;
R3Route *matched_route;
char * uri0 = "/foo";
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
parse_ipv6("fe80:fe80::1", 128, route); // "fe80:fe80::1"
char * uri1 = "/bar";
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
parse_ipv6("fe80:fe80::", 32, route); // "fe80:fe80::/32"
char * uri2 = "/goo";
route = r3_tree_insert_routel(n, 0, uri2, strlen(uri2), &uri2);
parse_ipv6("::1", 128, route); // "::1"
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo");
entry->remote_addr.base = "fe80:fe80::1";
entry->remote_addr.len = sizeof("fe80:fe80::1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo");
entry->remote_addr.base = "fe80:fe80::2";
entry->remote_addr.len = sizeof("fe80:fe80::2") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/foo");
entry->remote_addr.base = "fe88:fe80::1";
entry->remote_addr.len = sizeof("fe88:fe80::1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->remote_addr.base = "fe80:fe80::1";
entry->remote_addr.len = sizeof("fe80:fe80::1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->remote_addr.base = "fe88:fe80::1";
entry->remote_addr.len = sizeof("fe88:fe80::1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/goo");
entry->remote_addr.base = "::1";
entry->remote_addr.len = sizeof("::1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri2);
match_entry_free(entry);
entry = match_entry_create("/goo");
entry->remote_addr.base = "::2";
entry->remote_addr.len = sizeof("::2") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
Suite* r3_suite (void) {
Suite *suite = suite_create("r3 remote_addr tests");
TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_remote_addrs);
tcase_add_test(tcase, test_remote_addrs_ipv6);
suite_add_tcase(suite, tcase);
return suite;
}
int main (int argc, char *argv[]) {
int number_failed;
Suite *suite = r3_suite();
SRunner *runner = srunner_create(suite);
srunner_run_all(runner, CK_NORMAL);
number_failed = srunner_ntests_failed(runner);
srunner_free(runner);
return number_failed;
}

View file

@ -8,7 +8,6 @@
#include <assert.h> #include <assert.h>
#include "r3.h" #include "r3.h"
#include "r3_slug.h" #include "r3_slug.h"
#include "zmalloc.h"
START_TEST (test_routes) START_TEST (test_routes)
{ {

117
tests/check_routes2.c Normal file
View file

@ -0,0 +1,117 @@
#include "config.h"
#include <stdio.h>
#include <check.h>
#include <stdlib.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
START_TEST (greedy_pattern)
{
R3Node * n = r3_tree_create(10);
match_entry * entry;
R3Route *matched_route;
char * uri0 = "/foo{:.*}";
r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo/bar");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo/");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo/bar/foo/mmasdfasdfasd/f/asdf/as/df");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
START_TEST (common_pattern)
{
R3Node * n = r3_tree_create(10);
match_entry * entry;
R3Route *r, *matched_route;
char * uri0 = "/foo/{slug}";
r = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
ck_assert(r != NULL);
char * uri1 = "/foo/{slug}/bar";
r = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
ck_assert(r != NULL);
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo/bar");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo/bar/bar");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
START_TEST (incomplete_pattern)
{
R3Node * n = r3_tree_create(10);
R3Route * r;
char * uri0 = "{slug";
r = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
ck_assert(r == NULL);
char * uri1 = "/foo/{slug";
r = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
ck_assert(r == NULL);
r3_tree_free(n);
}
END_TEST
Suite* r3_suite (void) {
Suite *suite = suite_create("r3 routes2 tests");
TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, greedy_pattern);
tcase_add_test(tcase, common_pattern);
tcase_add_test(tcase, incomplete_pattern);
suite_add_tcase(suite, tcase);
return suite;
}
int main (int argc, char *argv[]) {
int number_failed;
Suite *suite = r3_suite();
SRunner *runner = srunner_create(suite);
srunner_run_all(runner, CK_NORMAL);
number_failed = srunner_ntests_failed(runner);
srunner_free(runner);
return number_failed;
}

View file

@ -10,7 +10,6 @@
#include <stdlib.h> #include <stdlib.h>
#include "r3.h" #include "r3.h"
#include "r3_slug.h" #include "r3_slug.h"
#include "zmalloc.h"
#include "slug.h" #include "slug.h"
#include "r3_debug.h" #include "r3_debug.h"
@ -28,69 +27,75 @@ START_TEST (test_r3_slug_compile)
char * path = "/user/{id}"; char * path = "/user/{id}";
char * c = NULL; char * c = NULL;
ck_assert_str_eq( c = r3_slug_compile(path, strlen(path) ) , "^/user/([^/]+)" ); ck_assert_str_eq( c = r3_slug_compile(path, strlen(path) ) , "^/user/([^/]+)" );
zfree(c); free(c);
char * path2 = "/what/{id}-foo"; char * path2 = "/what/{id}-foo";
ck_assert_str_eq( c = r3_slug_compile(path2, strlen(path2) ) , "^/what/([^/]+)-foo" ); ck_assert_str_eq( c = r3_slug_compile(path2, strlen(path2) ) , "^/what/([^/]+)-foo" );
zfree(c); free(c);
char * path3 = "-{id}"; char * path3 = "-{id}";
ck_assert_str_eq( c = r3_slug_compile(path3, strlen(path3)), "^-([^/]+)" ); ck_assert_str_eq( c = r3_slug_compile(path3, strlen(path3)), "^-([^/]+)" );
zfree(c); free(c);
char * path4 = "-{idx:\\d{3}}"; char * path4 = "-{idx:\\d{3}}";
ck_assert_str_eq( c = r3_slug_compile(path4, strlen(path4)), "^-(\\d{3})" ); ck_assert_str_eq( c = r3_slug_compile(path4, strlen(path4)), "^-(\\d{3})" );
zfree(c); free(c);
} }
END_TEST 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; unsigned int len;
char * namerex = r3_slug_find_pattern("{name:\\s+}", &len); char *test_str = "{name:\\s+}";
const 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
START_TEST (test_r3_slug_find_name) START_TEST (test_r3_slug_find_name)
{ {
int len; unsigned int len;
char * namerex = r3_slug_find_name("{name:\\s+}", &len); char *test_str = "{name:\\s+}";
const 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
START_TEST (test_r3_slug_find_name_without_pattern) START_TEST (test_r3_slug_find_name_without_pattern)
{ {
int len; unsigned int len;
char * namerex = r3_slug_find_name("{name}", &len); char *test_str = "{name}";
const 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
START_TEST (test_r3_slug_find_name_with_multiple_slug) START_TEST (test_r3_slug_find_name_with_multiple_slug)
{ {
int len; unsigned int len;
char * namerex = r3_slug_find_name("{name}/{name2}", &len); char *test_str = "{name}/{name2}";
const 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
START_TEST (test_r3_slug_find_placeholder) START_TEST (test_r3_slug_find_placeholder)
{ {
int slug_len = 0; unsigned int slug_len = 0;
char * slug; const 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 );
} }
@ -113,7 +118,7 @@ START_TEST (test_incomplete_slug)
char * pattern = "/user/{name:\\d{3}}/to/{id"; char * pattern = "/user/{name:\\d{3}}/to/{id";
cnt = r3_slug_count(pattern, strlen(pattern), &errstr); cnt = r3_slug_count(pattern, strlen(pattern), &errstr);
ck_assert_int_eq(cnt, -1); ck_assert_int_eq(cnt, -1);
ck_assert(errstr); ck_assert(errstr != NULL);
printf("%s\n",errstr); printf("%s\n",errstr);
free(errstr); free(errstr);
} }
@ -185,8 +190,9 @@ 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; unsigned 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";
const 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
@ -208,7 +214,7 @@ Suite* r3_suite (void) {
tcase_add_test(tcase, test_r3_slug_find_name); tcase_add_test(tcase, test_r3_slug_find_name);
tcase_add_test(tcase, test_r3_slug_find_name_without_pattern); tcase_add_test(tcase, test_r3_slug_find_name_without_pattern);
tcase_add_test(tcase, test_r3_slug_find_name_with_multiple_slug); tcase_add_test(tcase, test_r3_slug_find_name_with_multiple_slug);
// tcase_add_test(tcase, test_slug_parse_with_pattern); // tcase_add_test(tcase, test_slug_parse_with_pattern);
// tcase_add_test(tcase, test_slug_parse_without_pattern); // tcase_add_test(tcase, test_slug_parse_without_pattern);

View file

@ -8,29 +8,59 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <check.h> #include <check.h>
#include "r3.h" #include "str_array.h"
#include "r3_slug.h"
#include "zmalloc.h"
START_TEST (test_str_array) START_TEST (test_str_array)
{ {
str_array * l = str_array_create(3); str_array *vars = r3_mem_alloc(sizeof(str_array));
ck_assert(l); memset(vars, 0, sizeof(*vars));
ck_assert(str_array_append(l, zstrdup("abc"))); char *test_str = "abc";
ck_assert( l->len == 1 ); ck_assert( str_array_append(vars, test_str, strlen(test_str)));
ck_assert( 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(vars, test_str1, strlen(test_str1)));
ck_assert( 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(vars, test_str2, strlen(test_str2)));
ck_assert( 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(vars, test_str3, strlen(test_str3)));
ck_assert( vars->tokens.size == 4 );
ck_assert( str_array_resize(l, l->cap * 2) ); str_array_free(vars);
str_array_free(l); free(vars);
}
END_TEST
START_TEST (test_access_macros)
{
str_array *vars = r3_mem_alloc(sizeof(str_array));
memset(vars, 0, sizeof(*vars));
ck_assert( str_array_len(vars) == 0);
ck_assert( str_array_cap(vars) == 0);
r3_vector_reserve(&vars->tokens, 4);
ck_assert( str_array_len(vars) == 0);
ck_assert( str_array_cap(vars) == 4);
char *token1 = "first";
char *token2 = "second";
ck_assert( str_array_append(vars, token1, strlen(token1)));
ck_assert( str_array_append(vars, token2, strlen(token2)));
ck_assert( str_array_len(vars) == 2);
ck_assert( str_array_cap(vars) == 4);
ck_assert( strncmp(str_array_fetch(vars,0).base, "first", 5) == 0);
ck_assert( str_array_fetch(vars,0).len == 5);
ck_assert( strncmp(str_array_fetch(vars,1).base, "second", 6) == 0);
ck_assert( str_array_fetch(vars,1).len == 6);
str_array_free(vars);
free(vars);
} }
END_TEST END_TEST
@ -38,6 +68,7 @@ Suite* r3_suite (void) {
Suite *suite = suite_create("str_array test"); Suite *suite = suite_create("str_array test");
TCase *tcase = tcase_create("testcase"); TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_str_array); tcase_add_test(tcase, test_str_array);
tcase_add_test(tcase, test_access_macros);
suite_add_tcase(suite, tcase); suite_add_tcase(suite, tcase);
return suite; return suite;
} }

View file

@ -5,9 +5,8 @@
#include <assert.h> #include <assert.h>
#include "r3.h" #include "r3.h"
#include "r3_slug.h" #include "r3_slug.h"
#include "zmalloc.h"
#include "bench.h" #include "bench.h"
#include "r3_debug.h" #include "../src/r3_debug.h"
#define SAFE_FREE(ptr) if(ptr) free(ptr); #define SAFE_FREE(ptr) if(ptr) free(ptr);
@ -15,9 +14,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 +25,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 +42,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 +91,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 +132,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 +157,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 +186,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 +211,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;
@ -209,7 +227,59 @@ START_TEST (test_find_common_prefix_same_pattern2)
} }
END_TEST END_TEST
START_TEST (test_find_common_prefix_multi_edge)
{
R3Node * n = r3_tree_create(10);
char *test_str1 = "{id}/foo";
R3Edge * e1 = r3_node_append_edge(n);
r3_edge_initl(e1, test_str1, strlen(test_str1), NULL);
char *test_str2 = "{id2}/bar";
R3Edge * e2 = r3_node_append_edge(n);
r3_edge_initl(e2, test_str2, strlen(test_str2), NULL);
R3Edge *ret_edge = NULL;
int prefix_len = 0;
char *errstr = NULL;
char *test_pref1 = "{id}";
ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 4);
ck_assert(ret_edge == e1);
SAFE_FREE(errstr);
prefix_len = 0;
errstr = NULL;
char *test_pref2 = "{id}/foo";
ret_edge = r3_node_find_common_prefix(n, test_pref2, strlen(test_pref2), &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 8);
ck_assert(ret_edge == e1);
SAFE_FREE(errstr);
prefix_len = 0;
errstr = NULL;
char *test_pref3 = "{id2}";
ret_edge = r3_node_find_common_prefix(n, test_pref3, strlen(test_pref3), &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 5);
ck_assert(ret_edge == e2);
SAFE_FREE(errstr);
prefix_len = 0;
errstr = NULL;
char *test_pref4 = "{id2}/bar";
ret_edge = r3_node_find_common_prefix(n, test_pref4, strlen(test_pref4), &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 9);
ck_assert(ret_edge == e2);
SAFE_FREE(errstr);
r3_tree_free(n);
}
END_TEST
@ -267,26 +337,34 @@ START_TEST (test_compile)
entry = match_entry_createl( "foo" , strlen("/foo") ); entry = match_entry_createl( "foo" , strlen("/foo") );
m = r3_tree_matchl( n , "/foo", strlen("/foo"), entry); m = r3_tree_matchl( n , "/foo", strlen("/foo"), entry);
ck_assert( m ); ck_assert( m );
match_entry_free(entry);
entry = match_entry_createl( "/zoo" , strlen("/zoo") ); entry = match_entry_createl( "/zoo" , strlen("/zoo") );
m = r3_tree_matchl( n , "/zoo", strlen("/zoo"), entry); m = r3_tree_matchl( n , "/zoo", strlen("/zoo"), entry);
ck_assert( m ); ck_assert( m );
match_entry_free(entry);
entry = match_entry_createl( "/bar" , strlen("/bar") ); entry = match_entry_createl( "/bar" , strlen("/bar") );
m = r3_tree_matchl( n , "/bar", strlen("/bar"), entry); m = r3_tree_matchl( n , "/bar", strlen("/bar"), entry);
ck_assert( m ); ck_assert( m );
match_entry_free(entry);
entry = match_entry_createl( "/xxx" , strlen("/xxx") ); entry = match_entry_createl( "/xxx" , strlen("/xxx") );
m = r3_tree_matchl( n , "/xxx", strlen("/xxx"), entry); m = r3_tree_matchl( n , "/xxx", strlen("/xxx"), entry);
ck_assert( m ); ck_assert( m );
match_entry_free(entry);
entry = match_entry_createl( "/foo/xxx" , strlen("/foo/xxx") ); entry = match_entry_createl( "/foo/xxx" , strlen("/foo/xxx") );
m = r3_tree_matchl( n , "/foo/xxx", strlen("/foo/xxx"), entry); m = r3_tree_matchl( n , "/foo/xxx", strlen("/foo/xxx"), entry);
ck_assert( m ); ck_assert( m );
match_entry_free(entry);
entry = match_entry_createl( "/some_id" , strlen("/some_id") ); entry = match_entry_createl( "/some_id" , strlen("/some_id") );
m = r3_tree_matchl( n , "/some_id", strlen("/some_id"), entry); m = r3_tree_matchl( n , "/some_id", strlen("/some_id"), entry);
ck_assert( m ); ck_assert( m );
match_entry_free(entry);
r3_tree_free(n);
} }
END_TEST END_TEST
@ -420,6 +498,8 @@ START_TEST (test_root_match)
ck_assert(matched); ck_assert(matched);
ck_assert(matched->data == &c); ck_assert(matched->data == &c);
ck_assert(matched->endpoint > 0); ck_assert(matched->endpoint > 0);
r3_tree_free(n);
} }
END_TEST END_TEST
@ -443,8 +523,10 @@ 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);
r3_tree_free(n);
} }
END_TEST END_TEST
@ -473,7 +555,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);
@ -485,6 +567,8 @@ START_TEST (test_pcre_patterns_insert_3)
matched = r3_tree_match(n, "/post/113", NULL); matched = r3_tree_match(n, "/post/113", NULL);
ck_assert(!matched); ck_assert(!matched);
*/ */
r3_tree_free(n);
} }
END_TEST END_TEST
@ -497,7 +581,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
@ -511,8 +595,25 @@ START_TEST (test_insert_pathl_fail)
} }
END_TEST END_TEST
START_TEST (test_insert_pathl_fail2)
{
R3Node * n = r3_tree_create(10);
char *errstr = NULL;
R3Node * ret;
ret = r3_tree_insert_pathl_ex(n, "/foo", strlen("/foo"), 0, 0, 0, NULL);
ck_assert(ret);
/* Insert an incomplete pattern without requesting an error string */
ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), 0, 0, 0, NULL);
ck_assert(ret == NULL);
r3_tree_compile(n, &errstr);
ck_assert(errstr == NULL);
r3_tree_free(n);
}
END_TEST
START_TEST (test_insert_pathl) START_TEST (test_insert_pathl)
{ {
@ -608,7 +709,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");
@ -625,8 +728,8 @@ START_TEST(test_route_cmp)
m->request_method = METHOD_POST | METHOD_GET; m->request_method = METHOD_POST | METHOD_GET;
fail_if( r3_route_cmp(r1, m) == -1, "should match"); fail_if( r3_route_cmp(r1, m) == -1, "should match");
r3_route_free(r1);
match_entry_free(m); match_entry_free(m);
r3_tree_free(n);
} }
END_TEST END_TEST
@ -643,8 +746,9 @@ 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");
match_entry_free(entry);
r3_tree_free(n); r3_tree_free(n);
} }
END_TEST END_TEST
@ -653,7 +757,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,27 +779,29 @@ 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);
match_entry_free(entry);
r3_tree_free(n); r3_tree_free(n);
} }
END_TEST END_TEST
@ -707,9 +814,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);
@ -766,11 +873,13 @@ Suite* r3_suite (void) {
tcase_add_test(tcase, test_find_common_prefix_middle); tcase_add_test(tcase, test_find_common_prefix_middle);
tcase_add_test(tcase, test_find_common_prefix_same_pattern); tcase_add_test(tcase, test_find_common_prefix_same_pattern);
tcase_add_test(tcase, test_find_common_prefix_same_pattern2); tcase_add_test(tcase, test_find_common_prefix_same_pattern2);
tcase_add_test(tcase, test_find_common_prefix_multi_edge);
suite_add_tcase(suite, tcase); suite_add_tcase(suite, tcase);
tcase = tcase_create("insert_testcase"); tcase = tcase_create("insert_testcase");
tcase_add_test(tcase, test_insert_pathl); tcase_add_test(tcase, test_insert_pathl);
tcase_add_test(tcase, test_insert_pathl_fail); tcase_add_test(tcase, test_insert_pathl_fail);
tcase_add_test(tcase, test_insert_pathl_fail2);
tcase_add_test(tcase, test_node_construct_and_free); tcase_add_test(tcase, test_node_construct_and_free);
suite_add_tcase(suite, tcase); suite_add_tcase(suite, tcase);