wrouter 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. wrouter-0.1.0/.clang-format +39 -0
  2. wrouter-0.1.0/.gitignore +64 -0
  3. wrouter-0.1.0/LICENSE +28 -0
  4. wrouter-0.1.0/Makefile +41 -0
  5. wrouter-0.1.0/NOTES +3 -0
  6. wrouter-0.1.0/PKG-INFO +266 -0
  7. wrouter-0.1.0/README.md +218 -0
  8. wrouter-0.1.0/TODO +6 -0
  9. wrouter-0.1.0/bindings/cpp/meson.build +30 -0
  10. wrouter-0.1.0/bindings/cpp/tests/test_cpp.cpp +183 -0
  11. wrouter-0.1.0/bindings/cpp/wrouter.cpp +233 -0
  12. wrouter-0.1.0/bindings/cpp/wrouter.hpp +350 -0
  13. wrouter-0.1.0/bindings/python/TODO +18 -0
  14. wrouter-0.1.0/bindings/python/builder.c +157 -0
  15. wrouter-0.1.0/bindings/python/builder.h +22 -0
  16. wrouter-0.1.0/bindings/python/dispatcher.c +131 -0
  17. wrouter-0.1.0/bindings/python/dispatcher.h +17 -0
  18. wrouter-0.1.0/bindings/python/meson.build +18 -0
  19. wrouter-0.1.0/bindings/python/router.c +38 -0
  20. wrouter-0.1.0/bindings/python/router.h +16 -0
  21. wrouter-0.1.0/bindings/python/tests/test_build_router.py +30 -0
  22. wrouter-0.1.0/bindings/python/tests/test_builder.py +61 -0
  23. wrouter-0.1.0/bindings/python/tests/test_builder_threading.py +41 -0
  24. wrouter-0.1.0/bindings/python/tests/test_dispatcher.py +349 -0
  25. wrouter-0.1.0/bindings/python/tests/test_dispatcher_threading.py +23 -0
  26. wrouter-0.1.0/bindings/python/tests/test_dispatcher_types.py +27 -0
  27. wrouter-0.1.0/bindings/python/tests/test_router.py +5 -0
  28. wrouter-0.1.0/bindings/python/wroutermodule.c +164 -0
  29. wrouter-0.1.0/bindings/python/wroutermodule.h +4 -0
  30. wrouter-0.1.0/examples/cpp/callback.cpp +25 -0
  31. wrouter-0.1.0/examples/cpp/hello.cpp +26 -0
  32. wrouter-0.1.0/examples/cpp/http_resolve.cpp +53 -0
  33. wrouter-0.1.0/examples/cpp/meson.build +34 -0
  34. wrouter-0.1.0/examples/cpp/no_context.cpp +22 -0
  35. wrouter-0.1.0/examples/cpp/resolve_lambda.cpp +41 -0
  36. wrouter-0.1.0/examples/libmicrohttpd/README.md +13 -0
  37. wrouter-0.1.0/examples/libmicrohttpd/main.c +158 -0
  38. wrouter-0.1.0/examples/libmicrohttpd/meson.build +10 -0
  39. wrouter-0.1.0/include/wrouter.h +138 -0
  40. wrouter-0.1.0/meson.build +139 -0
  41. wrouter-0.1.0/meson_options.txt +6 -0
  42. wrouter-0.1.0/pyproject.toml +36 -0
  43. wrouter-0.1.0/requirements.txt +2 -0
  44. wrouter-0.1.0/src/arena.c +91 -0
  45. wrouter-0.1.0/src/arena.h +21 -0
  46. wrouter-0.1.0/src/builder.c +307 -0
  47. wrouter-0.1.0/src/builder.h +32 -0
  48. wrouter-0.1.0/src/common.h +6 -0
  49. wrouter-0.1.0/src/compiler.c +122 -0
  50. wrouter-0.1.0/src/dispatcher.c +126 -0
  51. wrouter-0.1.0/src/dispatcher.h +9 -0
  52. wrouter-0.1.0/src/errors.c +49 -0
  53. wrouter-0.1.0/src/graph.c +290 -0
  54. wrouter-0.1.0/src/graph.h +63 -0
  55. wrouter-0.1.0/src/lexer.c +72 -0
  56. wrouter-0.1.0/src/lexer.h +16 -0
  57. wrouter-0.1.0/src/params.c +161 -0
  58. wrouter-0.1.0/src/params.h +9 -0
  59. wrouter-0.1.0/src/prelexer.c +134 -0
  60. wrouter-0.1.0/src/prelexer.h +16 -0
  61. wrouter-0.1.0/src/router.c +205 -0
  62. wrouter-0.1.0/src/router.h +23 -0
  63. wrouter-0.1.0/src/segment.c +127 -0
  64. wrouter-0.1.0/src/segment.h +41 -0
  65. wrouter-0.1.0/src/symbol.c +216 -0
  66. wrouter-0.1.0/src/symbol.h +41 -0
  67. wrouter-0.1.0/src/terminal.c +50 -0
  68. wrouter-0.1.0/src/terminal.h +26 -0
  69. wrouter-0.1.0/src/token.c +14 -0
  70. wrouter-0.1.0/src/token.h +20 -0
  71. wrouter-0.1.0/tests/exp/README +1 -0
  72. wrouter-0.1.0/tests/exp/align.c +62 -0
  73. wrouter-0.1.0/tests/helpers/error_helpers.h +12 -0
  74. wrouter-0.1.0/tests/helpers/token_helpers.c +22 -0
  75. wrouter-0.1.0/tests/helpers/token_helpers.h +14 -0
  76. wrouter-0.1.0/tests/test_arena.c +136 -0
  77. wrouter-0.1.0/tests/test_builder.c +483 -0
  78. wrouter-0.1.0/tests/test_dispatcher.c +16 -0
  79. wrouter-0.1.0/tests/test_errors.c +43 -0
  80. wrouter-0.1.0/tests/test_graph.c +17 -0
  81. wrouter-0.1.0/tests/test_lexer.c +223 -0
  82. wrouter-0.1.0/tests/test_params.c +105 -0
  83. wrouter-0.1.0/tests/test_prelexer.c +386 -0
  84. wrouter-0.1.0/tests/test_router.c +674 -0
  85. wrouter-0.1.0/tests/test_symbol.c +244 -0
  86. wrouter-0.1.0/tests/test_terminal.c +82 -0
@@ -0,0 +1,39 @@
1
+ BasedOnStyle: LLVM
2
+ IndentWidth: 4
3
+ TabWidth: 4
4
+ UseTab: Never
5
+
6
+ BreakBeforeBraces: Custom
7
+ BraceWrapping:
8
+ AfterFunction: true
9
+ AfterControlStatement: false
10
+ AfterStruct: false
11
+ AfterEnum: false
12
+ AfterUnion: false
13
+ BeforeElse: false
14
+ BeforeCatch: false
15
+
16
+ AllowShortIfStatementsOnASingleLine: false
17
+ AllowShortLoopsOnASingleLine: false
18
+ AllowShortFunctionsOnASingleLine: Empty
19
+
20
+ PointerAlignment: Right
21
+ ReferenceAlignment: Right
22
+
23
+ ColumnLimit: 100
24
+
25
+ IndentCaseLabels: true
26
+ SpaceBeforeParens: ControlStatements
27
+
28
+ SortIncludes: false
29
+
30
+ AlignConsecutiveAssignments: false
31
+ AlignConsecutiveDeclarations: false
32
+
33
+ Cpp11BracedListStyle: false
34
+ Standard: Latest
35
+
36
+ # Copied from: https://github.com/pytorch/pytorch/blob/main/.clang-format
37
+ StatementMacros:
38
+ - PyObject_HEAD
39
+ - PyVarObject_HEAD_INIT
@@ -0,0 +1,64 @@
1
+ # Vim.
2
+ .*.swp
3
+ .*.swo
4
+
5
+ # Test coverage.
6
+ coverage*
7
+
8
+ # Ctags.
9
+ tags
10
+
11
+ # Prerequisites
12
+ *.d
13
+
14
+ # Object files
15
+ *.o
16
+ *.ko
17
+ *.obj
18
+ *.elf
19
+
20
+ # Linker output
21
+ *.ilk
22
+ *.map
23
+ *.exp
24
+
25
+ # Precompiled Headers
26
+ *.gch
27
+ *.pch
28
+
29
+ # Libraries
30
+ *.lib
31
+ *.a
32
+ *.la
33
+ *.lo
34
+
35
+ # Shared objects (inc. Windows DLLs)
36
+ *.dll
37
+ *.so
38
+ *.so.*
39
+ *.dylib
40
+
41
+ # Executables
42
+ *.out
43
+ *.app
44
+ *.i*86
45
+ *.x86_64
46
+ *.hex
47
+
48
+ # Debug files
49
+ *.dSYM/
50
+ *.su
51
+ *.idb
52
+ *.pdb
53
+
54
+ # Kernel Module Compile Results
55
+ *.mod*
56
+ *.cmd
57
+ .tmp_versions/
58
+ modules.order
59
+ Module.symvers
60
+ Mkfile.old
61
+ dkms.conf
62
+
63
+ # debug information files
64
+ *.dwo
wrouter-0.1.0/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Damien Bezborodov
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
wrouter-0.1.0/Makefile ADDED
@@ -0,0 +1,41 @@
1
+ .PHONY: build test cpptests ctags format install clean pytest clang-tidy
2
+
3
+ build:
4
+ meson setup build
5
+ meson compile -C build
6
+
7
+ test: build
8
+ meson test -C build --print-errorlogs -v
9
+
10
+ cpptests: build
11
+ meson test -C build cpp --print-errorlogs -v
12
+
13
+ pytest: test
14
+ PYTHONPATH=build/bindings/python pytest -s bindings/python/tests/
15
+
16
+ ctags:
17
+ ctags -R --kinds-C=+stu --extras=+q -f tags .
18
+
19
+ format:
20
+ clang-format -i include/* src/* tests/*.c tests/helpers/* examples/libmicrohttpd/*.c bindings/python/*.c bindings/python/*.h
21
+
22
+ alltest: test cpptests pytest
23
+
24
+ coverage:
25
+ meson setup build-coverage -Db_coverage=true -Db_sanitize=none
26
+ meson compile -C build-coverage
27
+ meson test -C build-coverage --print-errorlogs -v
28
+ lcov --capture --directory build-coverage --output-file coverage.info
29
+ lcov --extract coverage.info "$$(pwd)/src/*" --output-file coverage.filtered.info
30
+ genhtml coverage.filtered.info --output-directory coverage_html
31
+
32
+ clang-tidy:
33
+ clang-tidy src/params.c -p build --fix --checks=misc-include-cleaner
34
+
35
+ clean:
36
+ meson setup --wipe build
37
+
38
+ install:
39
+ meson setup build
40
+ meson compile -C build
41
+ meson install -C build
wrouter-0.1.0/NOTES ADDED
@@ -0,0 +1,3 @@
1
+ For context:
2
+
3
+ void * --(is always a)-> PyObject *
wrouter-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,266 @@
1
+ Metadata-Version: 2.1
2
+ Name: wrouter
3
+ Version: 0.1.0
4
+ Summary: Fast and deterministric symbolic Web URL route resolver.
5
+ Author-Email: Damien Bezborodov <dbezborodov@gmail.com>
6
+ License: BSD 3-Clause License
7
+
8
+ Copyright (c) 2026, Damien Bezborodov
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions are met:
12
+
13
+ 1. Redistributions of source code must retain the above copyright notice, this
14
+ list of conditions and the following disclaimer.
15
+
16
+ 2. Redistributions in binary form must reproduce the above copyright notice,
17
+ this list of conditions and the following disclaimer in the documentation
18
+ and/or other materials provided with the distribution.
19
+
20
+ 3. Neither the name of the copyright holder nor the names of its
21
+ contributors may be used to endorse or promote products derived from
22
+ this software without specific prior written permission.
23
+
24
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
28
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ Classifier: Development Status :: 2 - Pre-Alpha
36
+ Classifier: Intended Audience :: Developers
37
+ Classifier: License :: OSI Approved :: MIT License
38
+ Classifier: Programming Language :: C
39
+ Classifier: Programming Language :: Python :: 3
40
+ Classifier: Programming Language :: Python :: 3 :: Only
41
+ Classifier: Programming Language :: Python :: Implementation :: CPython
42
+ Classifier: Topic :: Internet :: WWW/HTTP
43
+ Classifier: Topic :: Software Development :: Libraries
44
+ Project-URL: Homepage, https://github.com/bezborodow/libwrouter
45
+ Project-URL: Bug Tracker, https://github.com/bezborodow/libwrouter/issues
46
+ Requires-Python: >=3.8
47
+ Description-Content-Type: text/markdown
48
+
49
+ # Wrouter: Symbolic Web Router
50
+
51
+ Project status: This is in pre-release. PyPI package coming soon. There are
52
+ unit tests for both the C API and the CPython module.
53
+
54
+ ## Usage
55
+
56
+ ### Python
57
+
58
+ ```python
59
+ from wrouter import build_router, Dispatcher
60
+
61
+
62
+ routes = [
63
+ ("/account", "account.list"),
64
+ ("/account/create", "account.create"),
65
+ ("/account/a/:account_id", "account.view")
66
+ ]
67
+
68
+ dispatcher = Dispatcher(build_router(routes))
69
+
70
+ endpoint, params = dispatcher.resolve("/account/a/1234")
71
+
72
+ print(f"{endpoint} {params['account_id']}")
73
+ ```
74
+
75
+ Will print: `account.view 1234`.
76
+
77
+ ### C++
78
+
79
+ ```
80
+ #include "wrouter.hpp"
81
+
82
+ #include <iostream>
83
+ #include <string>
84
+
85
+ struct Response {
86
+ std::string body;
87
+ };
88
+
89
+ int main()
90
+ {
91
+ wrouter::Builder<Response> builder;
92
+
93
+ builder.add("/hello/:name", [](Response& response, wrouter::Params params) {
94
+ response.body = "Hello, " + params["name"] + "!";
95
+ });
96
+
97
+ auto router = builder.consume();
98
+ wrouter::Dispatcher dispatcher(router);
99
+
100
+ Response response;
101
+ dispatcher.dispatch("/hello/world", response);
102
+
103
+ std::cout << response.body << "\n";
104
+ }
105
+ ```
106
+
107
+ ### C
108
+
109
+ ```c
110
+ #include <stdio.h>
111
+ #include <wrouter.h>
112
+
113
+ static void route_hello(void *dispatch_ctx, const void *route_ctx, const wrouter_params_t *params)
114
+ {
115
+ const wrouter_param_t *addressee = wrouter_param(params, "addressee");
116
+
117
+ if (addressee)
118
+ printf("Hello, %.*s!\n", addressee->length, addressee->value);
119
+ }
120
+
121
+ int main(void)
122
+ {
123
+ wrouter_error_t err;
124
+ wrouter_options_t options = { 0 };
125
+ wrouter_builder_t *builder = NULL;
126
+ wrouter_t *router = NULL;
127
+ wrouter_dispatcher_t *dispatcher = NULL;
128
+
129
+ builder = wrouter_builder_create(options);
130
+ if (builder == NULL)
131
+ goto failure;
132
+
133
+ err = wrouter_add_handler(builder, "/hello/:addressee", route_hello);
134
+ if (err)
135
+ goto failure;
136
+
137
+ router = wrouter_consume(&builder, &err);
138
+ if (err)
139
+ goto failure;
140
+
141
+ dispatcher = wrouter_dispatcher_create(router);
142
+ if (dispatcher == NULL)
143
+ goto failure;
144
+
145
+ wrouter_dispatch(dispatcher, "/hello/world", NULL);
146
+
147
+ wrouter_dispatcher_destroy(&dispatcher);
148
+ wrouter_destroy(&router);
149
+
150
+ return 0;
151
+
152
+ failure:
153
+ fprintf(stderr, "%s\n", wrouter_strerror(err));
154
+ wrouter_builder_destroy(&builder);
155
+ wrouter_dispatcher_destroy(&dispatcher);
156
+ wrouter_destroy(&router);
157
+ return 1;
158
+ }
159
+ ```
160
+
161
+ Compile with:
162
+
163
+ ```bash
164
+ gcc -o hello hello.c -lwrouter
165
+ ```
166
+
167
+ Will print: `Hello, world!`
168
+
169
+ ## Concepts
170
+
171
+ This project is designed as a router for use in a Web application server that
172
+ is assumed to be behind an HTTP proxy. As such, it makes no attempt to handle
173
+ hostnames, subdomains, or aliases. The router does not handle HTTP parsing or
174
+ request handling, and as such should be used in conjunction with other
175
+ libraries.
176
+
177
+ The router is intended to be fast, cache-efficient, and deterministic. It is
178
+ therefore deliberately restrictive in what forms of routes can be accepted into
179
+ the routing graph (see constraints below). This results in a graph that is
180
+ simple and easy to traverse efficiently. The strict routing graph prevents
181
+ ambiguity in route resolution, avoiding the need for prioritisation or
182
+ resolving the specificity of conflicting routes.
183
+
184
+ The router has no concept of HTTP methods such as GET and POST. Therefore, a
185
+ router must be instantiated for each method supported by the application,
186
+ including a separate router for WebSockets, if desired.
187
+
188
+ The router is immutable, and is therefore thread-safe, and may be shared
189
+ between threads. The dispatcher is mutable and must not be shared between
190
+ threads.
191
+
192
+ ## Constraints
193
+
194
+ A URL is divided into segments by the `/` character. A segment maybe either be
195
+ a literal string, parameter, or wildcard. Parameters are denoted by a colon
196
+ (default), angle, or brace; e.g., `:param`, `<param>`, or `{param}`,
197
+ respectively.
198
+
199
+ Wildcards (`*`) may only appear at the end of a route. Wildcards are evaluated
200
+ as a fallback. The most specific wildcard will match. A wildcard will consume
201
+ all segments following it.
202
+
203
+ - `/accounts/user/*/view` (invalid!)
204
+ - `/accounts/downloads/*`
205
+ - `/*`
206
+
207
+ A segment may only be a parameter or a literal.
208
+
209
+ - `/board/:board_id/ticket:ticket_id` (valid, but `ticket:ticket_id` will be parsed as a literal!)
210
+ - `/board/:board_id/ticket/:ticket_id`
211
+
212
+ Routes must not conflict with parameters and literals at the same level.
213
+
214
+ - `/project/list` and - `/project/:project_id` (incompatible!)
215
+
216
+ Wildcards are acceptable within at the same level at the end if they are
217
+ opposing a literal, not a parameter.
218
+
219
+ - `/project/list` and `/project/*`
220
+ - `/project/:project_id` and `/project/*` (incompatible!)
221
+
222
+ Parameters at the same level must share the same name.
223
+
224
+ - `/repos/:user/:repo` and `/repos/:user/:repo/tree/:branch/*`
225
+ - `/project/:id` and `/project/:project_id/accounts/:account_id` (incompatible!)
226
+
227
+ Routes with trailing slashes are distinct. The following are not equivalent:
228
+
229
+ - `/test`
230
+ - `/test/`
231
+
232
+ If it is desired to redirect from `/test` to `/test/`, this must be performed
233
+ explicitly by adding both routes, of which the former will redirect to the
234
+ latter.
235
+
236
+ Flexibility is not a goal of this project.
237
+
238
+ Where these constraints are severely limiting, the HTTP proxy should rewrite
239
+ URLs for the application server to consume. For example, `/new` could be
240
+ rewritten as `/repo/new`, while `/:user/:repo` could be rewritten as
241
+ `/repos/:user/:repo`. A small rewrite engine might be included in the future.
242
+
243
+ ## Limitations
244
+
245
+ This is not an HTTP parser; as such, request paths containing query parameters
246
+ such as `/foo/bar?query=hi` will fail to match.
247
+
248
+ ## Building
249
+
250
+ Compile:
251
+
252
+ ```bash
253
+ make
254
+ ```
255
+
256
+ Run tests:
257
+
258
+ ```bash
259
+ make test
260
+ ```
261
+
262
+ Install:
263
+
264
+ ```bash
265
+ sudo make install
266
+ ```
@@ -0,0 +1,218 @@
1
+ # Wrouter: Symbolic Web Router
2
+
3
+ Project status: This is in pre-release. PyPI package coming soon. There are
4
+ unit tests for both the C API and the CPython module.
5
+
6
+ ## Usage
7
+
8
+ ### Python
9
+
10
+ ```python
11
+ from wrouter import build_router, Dispatcher
12
+
13
+
14
+ routes = [
15
+ ("/account", "account.list"),
16
+ ("/account/create", "account.create"),
17
+ ("/account/a/:account_id", "account.view")
18
+ ]
19
+
20
+ dispatcher = Dispatcher(build_router(routes))
21
+
22
+ endpoint, params = dispatcher.resolve("/account/a/1234")
23
+
24
+ print(f"{endpoint} {params['account_id']}")
25
+ ```
26
+
27
+ Will print: `account.view 1234`.
28
+
29
+ ### C++
30
+
31
+ ```
32
+ #include "wrouter.hpp"
33
+
34
+ #include <iostream>
35
+ #include <string>
36
+
37
+ struct Response {
38
+ std::string body;
39
+ };
40
+
41
+ int main()
42
+ {
43
+ wrouter::Builder<Response> builder;
44
+
45
+ builder.add("/hello/:name", [](Response& response, wrouter::Params params) {
46
+ response.body = "Hello, " + params["name"] + "!";
47
+ });
48
+
49
+ auto router = builder.consume();
50
+ wrouter::Dispatcher dispatcher(router);
51
+
52
+ Response response;
53
+ dispatcher.dispatch("/hello/world", response);
54
+
55
+ std::cout << response.body << "\n";
56
+ }
57
+ ```
58
+
59
+ ### C
60
+
61
+ ```c
62
+ #include <stdio.h>
63
+ #include <wrouter.h>
64
+
65
+ static void route_hello(void *dispatch_ctx, const void *route_ctx, const wrouter_params_t *params)
66
+ {
67
+ const wrouter_param_t *addressee = wrouter_param(params, "addressee");
68
+
69
+ if (addressee)
70
+ printf("Hello, %.*s!\n", addressee->length, addressee->value);
71
+ }
72
+
73
+ int main(void)
74
+ {
75
+ wrouter_error_t err;
76
+ wrouter_options_t options = { 0 };
77
+ wrouter_builder_t *builder = NULL;
78
+ wrouter_t *router = NULL;
79
+ wrouter_dispatcher_t *dispatcher = NULL;
80
+
81
+ builder = wrouter_builder_create(options);
82
+ if (builder == NULL)
83
+ goto failure;
84
+
85
+ err = wrouter_add_handler(builder, "/hello/:addressee", route_hello);
86
+ if (err)
87
+ goto failure;
88
+
89
+ router = wrouter_consume(&builder, &err);
90
+ if (err)
91
+ goto failure;
92
+
93
+ dispatcher = wrouter_dispatcher_create(router);
94
+ if (dispatcher == NULL)
95
+ goto failure;
96
+
97
+ wrouter_dispatch(dispatcher, "/hello/world", NULL);
98
+
99
+ wrouter_dispatcher_destroy(&dispatcher);
100
+ wrouter_destroy(&router);
101
+
102
+ return 0;
103
+
104
+ failure:
105
+ fprintf(stderr, "%s\n", wrouter_strerror(err));
106
+ wrouter_builder_destroy(&builder);
107
+ wrouter_dispatcher_destroy(&dispatcher);
108
+ wrouter_destroy(&router);
109
+ return 1;
110
+ }
111
+ ```
112
+
113
+ Compile with:
114
+
115
+ ```bash
116
+ gcc -o hello hello.c -lwrouter
117
+ ```
118
+
119
+ Will print: `Hello, world!`
120
+
121
+ ## Concepts
122
+
123
+ This project is designed as a router for use in a Web application server that
124
+ is assumed to be behind an HTTP proxy. As such, it makes no attempt to handle
125
+ hostnames, subdomains, or aliases. The router does not handle HTTP parsing or
126
+ request handling, and as such should be used in conjunction with other
127
+ libraries.
128
+
129
+ The router is intended to be fast, cache-efficient, and deterministic. It is
130
+ therefore deliberately restrictive in what forms of routes can be accepted into
131
+ the routing graph (see constraints below). This results in a graph that is
132
+ simple and easy to traverse efficiently. The strict routing graph prevents
133
+ ambiguity in route resolution, avoiding the need for prioritisation or
134
+ resolving the specificity of conflicting routes.
135
+
136
+ The router has no concept of HTTP methods such as GET and POST. Therefore, a
137
+ router must be instantiated for each method supported by the application,
138
+ including a separate router for WebSockets, if desired.
139
+
140
+ The router is immutable, and is therefore thread-safe, and may be shared
141
+ between threads. The dispatcher is mutable and must not be shared between
142
+ threads.
143
+
144
+ ## Constraints
145
+
146
+ A URL is divided into segments by the `/` character. A segment maybe either be
147
+ a literal string, parameter, or wildcard. Parameters are denoted by a colon
148
+ (default), angle, or brace; e.g., `:param`, `<param>`, or `{param}`,
149
+ respectively.
150
+
151
+ Wildcards (`*`) may only appear at the end of a route. Wildcards are evaluated
152
+ as a fallback. The most specific wildcard will match. A wildcard will consume
153
+ all segments following it.
154
+
155
+ - `/accounts/user/*/view` (invalid!)
156
+ - `/accounts/downloads/*`
157
+ - `/*`
158
+
159
+ A segment may only be a parameter or a literal.
160
+
161
+ - `/board/:board_id/ticket:ticket_id` (valid, but `ticket:ticket_id` will be parsed as a literal!)
162
+ - `/board/:board_id/ticket/:ticket_id`
163
+
164
+ Routes must not conflict with parameters and literals at the same level.
165
+
166
+ - `/project/list` and - `/project/:project_id` (incompatible!)
167
+
168
+ Wildcards are acceptable within at the same level at the end if they are
169
+ opposing a literal, not a parameter.
170
+
171
+ - `/project/list` and `/project/*`
172
+ - `/project/:project_id` and `/project/*` (incompatible!)
173
+
174
+ Parameters at the same level must share the same name.
175
+
176
+ - `/repos/:user/:repo` and `/repos/:user/:repo/tree/:branch/*`
177
+ - `/project/:id` and `/project/:project_id/accounts/:account_id` (incompatible!)
178
+
179
+ Routes with trailing slashes are distinct. The following are not equivalent:
180
+
181
+ - `/test`
182
+ - `/test/`
183
+
184
+ If it is desired to redirect from `/test` to `/test/`, this must be performed
185
+ explicitly by adding both routes, of which the former will redirect to the
186
+ latter.
187
+
188
+ Flexibility is not a goal of this project.
189
+
190
+ Where these constraints are severely limiting, the HTTP proxy should rewrite
191
+ URLs for the application server to consume. For example, `/new` could be
192
+ rewritten as `/repo/new`, while `/:user/:repo` could be rewritten as
193
+ `/repos/:user/:repo`. A small rewrite engine might be included in the future.
194
+
195
+ ## Limitations
196
+
197
+ This is not an HTTP parser; as such, request paths containing query parameters
198
+ such as `/foo/bar?query=hi` will fail to match.
199
+
200
+ ## Building
201
+
202
+ Compile:
203
+
204
+ ```bash
205
+ make
206
+ ```
207
+
208
+ Run tests:
209
+
210
+ ```bash
211
+ make test
212
+ ```
213
+
214
+ Install:
215
+
216
+ ```bash
217
+ sudo make install
218
+ ```
wrouter-0.1.0/TODO ADDED
@@ -0,0 +1,6 @@
1
+ TODO
2
+
3
+ Improve linear to binary search.
4
+ Extend literal count in unused flags bits.
5
+ Double address offset.
6
+ Better documentation.
@@ -0,0 +1,30 @@
1
+ cpp_sources = files('wrouter.cpp')
2
+
3
+ cpp_include_dirs = include_directories('.')
4
+ c_include_dirs = include_directories('../../include')
5
+
6
+ # 1. First define the library
7
+ wrouter_cpp = library(
8
+ 'wrouter_cpp',
9
+ cpp_sources,
10
+ include_directories : [cpp_include_dirs, c_include_dirs],
11
+ dependencies : [libwrouter_dep],
12
+ install : true,
13
+ )
14
+
15
+ install_headers('wrouter.hpp')
16
+
17
+ # 2. Then expose dependency
18
+ wrouter_cpp_dep = declare_dependency(
19
+ link_with : wrouter_cpp,
20
+ include_directories : [cpp_include_dirs, c_include_dirs],
21
+ dependencies : [libwrouter_dep],
22
+ )
23
+
24
+ cpp_test = executable(
25
+ 'test_cpp',
26
+ 'tests/test_cpp.cpp',
27
+ dependencies : wrouter_cpp_dep,
28
+ )
29
+
30
+ test('cpp', cpp_test)