├── .busted
├── .github
└── workflows
│ └── unit-tests.yaml
├── .gitignore
├── .luacheckrc
├── .luacov
├── CHANGES.md
├── CMakeLists.txt
├── LICENSE
├── Makefile
├── README.md
├── config.ld
├── dev
└── Dockerfile
├── dist.ini
├── docs
├── classes
│ ├── search.html
│ └── url.html
├── data
│ └── icon.png
├── index.html
├── ldoc_new.css
└── modules
│ ├── resty.ada.html
│ └── resty.ada.search.html
├── lib
└── resty
│ ├── ada.lua
│ └── ada
│ ├── lib.lua
│ ├── search.lua
│ └── utils.lua
├── lua-resty-ada-1.1.0-1.rockspec
└── spec
└── 01-ada-url_spec.lua
/.busted:
--------------------------------------------------------------------------------
1 | return {
2 | default = {
3 | lua = "resty",
4 | verbose = true,
5 | coverage = true,
6 | output = "gtest",
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.github/workflows/unit-tests.yaml:
--------------------------------------------------------------------------------
1 | name: unit-tests
2 | on: [pull_request]
3 |
4 | jobs:
5 | test:
6 | strategy:
7 | fail-fast: false
8 | matrix:
9 | luaVersion: ["luajit-openresty"]
10 |
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 |
15 | - name: Setup environment
16 | run: docker build dev/ -t resty-ada
17 |
18 | - name: Run tests
19 | run: docker run --network=host -v $PWD:/test -w /test resty-ada bash -c "make test"
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.project
2 |
--------------------------------------------------------------------------------
/.luacheckrc:
--------------------------------------------------------------------------------
1 | std = "ngx_lua"
2 | redefined = false
3 | max_line_length = false
4 |
--------------------------------------------------------------------------------
/.luacov:
--------------------------------------------------------------------------------
1 | return {
2 | -- filename to store stats collected
3 | ["statsfile"] = "luacov.stats.out",
4 |
5 | -- filename to store report
6 | ["reportfile"] = "luacov.report.out",
7 |
8 | -- Patterns for files to include when reporting
9 | -- all will be included if nothing is listed
10 | -- (exclude overrules include, do not include
11 | -- the .lua extension, path separator is always '/')
12 | ["include"] = { 'resty/ada' },
13 |
14 | -- Patterns for files to exclude when reporting
15 | -- all will be included if nothing is listed
16 | -- (exclude overrules include, do not include
17 | -- the .lua extension, path separator is always '/')
18 | ["exclude"] = {
19 | "luacov$",
20 | "luacov/reporter$",
21 | "luacov/defaults$",
22 | "luacov/runner$",
23 | "luacov/stats$",
24 | "luacov/tick$",
25 | },
26 | }
27 |
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to `lua-resty-ada` will be documented in this file.
4 |
5 | ## [1.2.0] - Unreleased
6 | ### Changed
7 | - Bumped Ada to `3.2.1`
8 |
9 | ## [1.1.0] - 2024-09-03
10 | ### Added
11 | - `url:decode` method
12 | - `ada.decode` function
13 | - `ada.search_encode` function
14 | - `ada.search.encode` function
15 | - `search:decode` method
16 | - `search:decode_all` method
17 | - `ada.search_decode` function
18 | - `ada.search.decode` function
19 | - `ada.search_decode_all` function
20 | - `ada.search.decode_all` function
21 | ### Changed
22 | - The `set_port` to not allow negative or positive inf or NaN
23 | ### Updated
24 | - The CI is now executed against Ada 2.9.2
25 |
26 | ## [1.0.1] - 2024-08-20
27 | ### Removed
28 | - The unnecessary `:is_valid` was removed (the URL is validated when parsed)
29 | ### Added
30 | - Explicitly free Ada URL object on invalid URLs
31 |
32 | ## [1.0.0] - 2024-08-08
33 | ### Added
34 | - Initial, but complete, implementation of LuaJIT FFI bindings to Ada
35 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16)
2 |
3 | project(
4 | ada
5 | DESCRIPTION "Fast spec-compliant URL parser"
6 | LANGUAGES C CXX
7 | VERSION 3.2.1
8 | )
9 |
10 | set(CMAKE_CXX_STANDARD 20)
11 |
12 | # Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24:
13 | if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
14 | cmake_policy(SET CMP0135 NEW)
15 | endif()
16 |
17 | include(FetchContent)
18 |
19 | FetchContent_Declare(
20 | ada
21 | URL https://github.com/ada-url/ada/releases/download/v3.2.1/singleheader.zip
22 | URL_HASH SHA256=2954ff2208aa016de4213af7371273e1c41c71571e373eadf550ada808c79f42
23 | )
24 |
25 | FetchContent_MakeAvailable(ada)
26 |
27 | add_library(ada SHARED _deps/ada-src/ada.cpp)
28 |
29 | install(TARGETS ada DESTINATION lib)
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2024–2025 Aapo Talvensaari, 2024 Guilherme Salazar
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build copy-library luarocks-install lint unit coverage test docs clean install-rock install-lib install
2 |
3 | LIBRARY := libada.so
4 | ifeq ($(shell uname), Darwin)
5 | LIBRARY := libada.dylib
6 | endif
7 |
8 | build:
9 | @cmake -B build
10 | @cmake --build build
11 |
12 | copy-library: build
13 | @cp build/$(LIBRARY) .
14 |
15 | luarocks-install:
16 | @luarocks make
17 |
18 | lint:
19 | @luacheck ./lib
20 |
21 | unit:
22 | @busted
23 |
24 | coverage: unit
25 | @luacov
26 | @echo
27 | @awk '/File/,0' luacov.report.out
28 | @echo
29 |
30 | test: copy-library luarocks-install coverage lint
31 |
32 | docs:
33 | @ldoc .
34 |
35 | install-rock:
36 | @luarocks make
37 |
38 | install-lib: build
39 | @cmake --install build
40 |
41 | install: install-rock install-lib
42 |
43 | clean:
44 | @rm -Rf build luacov.stats.out luacov.report.out $(LIBRARY)
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # lua-resty-ada
2 |
3 | **lua-resty-ada** implements a LuaJIT FFI bindings to
4 | [Ada — WHATWG-compliant and fast URL parser](https://github.com/ada-url/ada/).
5 |
6 | ## Status
7 |
8 | This library is considered production ready.
9 |
10 |
11 | ## Synopsis
12 |
13 | ```lua
14 | local ada = require("resty.ada")
15 |
16 | local url = assert(ada.parse("https://www.7‑Eleven.com:1234/Home/../Privacy/Montréal"))
17 |
18 | print(tostring(url))
19 | -- prints: https://www.xn--7eleven-506c.com:1234/Privacy/Montr%C3%A9al
20 |
21 | print(tostring(url:clear_port())) -- there are many more methods
22 | -- prints: https://www.xn--7eleven-506c.com/Privacy/Montr%C3%A9al
23 |
24 | url:free()
25 | -- explicitly frees the memory without waiting for the garbage collector
26 |
27 | -- There is also a static API
28 |
29 | print(ada.get_href("https://www.7‑Eleven.com:1234/Home/../Privacy/Montréal"))
30 | -- prints: https://www.xn--7eleven-506c.com:1234/Privacy/Montr%C3%A9al
31 |
32 | print(ada.clear_port("https://www.7‑Eleven.com:1234/Home/../Privacy/Montréal"))
33 | -- prints: https://www.xn--7eleven-506c.com/Privacy/Montr%C3%A9al
34 | ```
35 |
36 |
37 | ## API
38 |
39 | LDoc generated API docs can be viewed at [bungle.github.io/lua-resty-ada](https://bungle.github.io/lua-resty-ada/).
40 |
41 |
42 | ## Installation
43 |
44 | ### Using OpenResty Package Manager
45 |
46 | ```bash
47 | ❯ opm get bungle/lua-resty-ada
48 | ```
49 |
50 | OPM repository for `lua-resty-ada` is located at
51 | [opm.openresty.org/package/bungle/lua-resty-ada](https://opm.openresty.org/package/bungle/lua-resty-ada/).
52 |
53 | ### Using LuaRocks
54 |
55 | ```bash
56 | ❯ luarocks install lua-resty-ada
57 | ```
58 |
59 | LuaRocks repository for `lua-resty-ada` is located at
60 | [luarocks.org/modules/bungle/lua-resty-ada](https://luarocks.org/modules/bungle/lua-resty-session).
61 |
62 | ### Building Ada
63 |
64 | Please consult [Ada](https://github.com/ada-url/ada/) on how to build or install
65 | the ada library. The Ada library needs to installed in in the system library path or
66 | one of the paths in Lua's `package.cpath`.
67 |
68 | This project can also build it by executing (requires [cmake](https://cmake.org/)):
69 |
70 | ```bash
71 | ❯ make build
72 | ```
73 |
74 | Or run the test suite with [act](https://github.com/nektos/act):
75 |
76 | ```bash
77 | ❯ act
78 | ```
79 |
80 |
81 | # License
82 |
83 | `lua-resty-ada` uses two clause BSD license.
84 |
85 | ```
86 | Copyright (c) 2024–2025 Aapo Talvensaari, 2024 Guilherme Salazar
87 | All rights reserved.
88 |
89 | Redistribution and use in source and binary forms, with or without modification,
90 | are permitted provided that the following conditions are met:
91 |
92 | * Redistributions of source code must retain the above copyright notice, this
93 | list of conditions and the following disclaimer.
94 |
95 | * Redistributions in binary form must reproduce the above copyright notice, this
96 | list of conditions and the following disclaimer in the documentation and/or
97 | other materials provided with the distribution.
98 |
99 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
100 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
101 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
102 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
103 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
104 | ```
105 |
--------------------------------------------------------------------------------
/config.ld:
--------------------------------------------------------------------------------
1 | project = "resty.ada"
2 | description = "WHATWG-compliant and fast URL parser"
3 | full_description = "`lua-resty-ada` implements a LuaJIT FFI bindings to Ada — WHATWG-compliant and fast URL parser"
4 | title = "LuaJIT FFI bindings to Ada — WHATWG-compliant and fast URL parser"
5 | dir = "docs"
6 | use_markdown_titles = true
7 | package = "ada"
8 | format = "discount"
9 | file = "./lib/resty"
10 | style = "!new"
11 | multimodule = true
12 | icon = "icon.png"
13 |
--------------------------------------------------------------------------------
/dev/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openresty/openresty:1.27.1.1-0-noble
2 |
3 | ENV DEBIAN_FRONTEND noninteractive
4 | ENV TEST_NGINX_BINARY openresty
5 |
6 | USER root
7 |
8 | RUN apt update
9 | RUN apt install -y gcc git cmake
10 | RUN luarocks install luacheck
11 | RUN luarocks install busted
12 | RUN luarocks install LuaCov
13 |
--------------------------------------------------------------------------------
/dist.ini:
--------------------------------------------------------------------------------
1 | name = lua-resty-ada
2 | abstract = LuaJIT FFI bindings to Ada — WHATWG-compliant and fast URL parser
3 | author = Aapo Talvensaari (@bungle)
4 | is_original = yes
5 | license = 2bsd
6 | repo_link = https://github.com/bungle/lua-resty-ada
7 | requires = luajit
8 |
--------------------------------------------------------------------------------
/docs/classes/search.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | LuaJIT FFI bindings to Ada — WHATWG-compliant and fast URL parser
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
resty.ada
28 |
29 |
30 |
31 |
34 |
35 |
Contents
36 |
47 |
48 |
49 |
Classes
50 |
51 | url
52 | search
53 |
54 |
Modules
55 |
59 |
60 |
61 |
62 |
63 |
64 |
Class search
65 |
Ada URL search parameters
66 |
See: https://url.spec.whatwg.org/#interface-urlsearchparams
67 |
68 |
69 |
70 |
71 |
72 | search:decode ()
73 | Decodes search parameters and returns a Lua table of them.
74 |
75 |
76 | search:decode ()
77 | Decodes all search parameters and returns a Lua table of them.
78 |
79 |
80 |
81 |
91 |
92 |
102 |
103 |
117 |
118 |
132 |
133 |
151 |
152 |
153 |
154 | search:free ()
155 | Explicitly destroys the Ada URL Search instance and frees the memory.
156 |
157 |
158 |
159 |
169 |
170 |
171 |
172 | search:each ()
173 | Iterate over search parameters.
174 |
175 |
176 | search:each_key ()
177 | Iterate over each key in search parameters.
178 |
179 |
180 | search:each_value ()
181 | Iterate over each value in search parameters.
182 |
183 |
184 | search:pairs ()
185 | Iterate over each key and value in search parameters.
186 |
187 |
188 | search:ipairs ()
189 | Iterate over each parameter in search parameters.
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 | search:decode ()
203 |
204 |
205 | Decodes search parameters and returns a Lua table of them.
206 |
207 | If same parameter appears multiple times, only the value of the
208 | first is returned.
209 |
210 | An example return value:
211 | {
212 | key1 = “value”,
213 | key2 = “value2”,
214 | }
215 |
216 |
217 |
218 |
Returns:
219 |
220 |
221 | table
222 | a table of all search parameters (a string:string map).
223 |
224 |
225 |
226 |
227 | Usage:
228 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f&a=g" )
230 | local result = search:decode ()
231 |
232 |
233 |
234 |
235 |
236 | search:decode ()
237 |
238 |
239 | Decodes all search parameters and returns a Lua table of them.
240 |
241 | An example return value:
242 | {
243 | key1 = { “first”, “second”, },
244 | key2 = { “value” },
245 | }
246 |
247 |
248 |
249 |
Returns:
250 |
251 |
252 | table
253 | a table of all search parameters (a string:table [array] map).
254 |
255 |
256 |
257 |
258 | Usage:
259 | local search = require ("resty.ada.search" ).parse ("a=b&a=c&d=e" )
261 | local result = search:decode_all ()
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 | search:has (key)
272 |
273 |
274 | Checks whether the search has a key.
275 |
276 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-has
277 |
278 |
279 |
Parameters:
280 |
281 | key
282 | string
283 | search parameter name to check
284 |
285 |
286 |
287 | Returns:
288 |
289 |
290 | boolean
291 | true
if search has the key, otherwise false
292 |
293 |
294 | Raises:
295 | error when key is not a string
296 |
297 |
298 | Usage:
299 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
301 | local result = search:has ("a" )
302 |
303 |
304 |
305 |
306 |
307 | search:has_value (key, value)
308 |
309 |
310 | Checks whether the search has a key with a specific value.
311 |
312 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-has
313 |
314 |
315 |
Parameters:
316 |
317 | key
318 | string
319 | search parameter name to check
320 |
321 | value
322 | string
323 | search parameter value to check
324 |
325 |
326 |
327 | Returns:
328 |
329 |
330 | boolean
331 | true
if search has the key with the value, otherwise false
332 |
333 |
334 | Raises:
335 | error when key or value is not a string
336 |
337 |
338 | Usage:
339 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
341 | local result = search:has_value ("a" , "b" )
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 | search:get (key)
352 |
353 |
354 | Get search parameter’s value.
355 |
356 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-get
357 |
358 |
359 |
Parameters:
360 |
361 | key
362 | string
363 | search parameter name
364 |
365 |
366 |
367 | Returns:
368 |
369 |
370 | string or nil
371 | parameter value or nil
372 |
373 |
374 | Raises:
375 | error when key is not a string
376 |
377 |
378 | Usage:
379 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
381 | local result = search:get ("a" )
382 |
383 |
384 |
385 |
386 |
387 | search:get_all (key)
388 |
389 |
390 | Get all the search parameter’s values.
391 |
392 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-getall
393 |
394 |
395 |
Parameters:
396 |
397 | key
398 | string
399 | search parameter name
400 |
401 |
402 |
403 | Returns:
404 |
405 |
406 | table
407 | array of all the values (or an empty array)
408 |
409 |
410 | Raises:
411 | error when key is not a string
412 |
413 |
414 | Usage:
415 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
417 | local result = search:get_all ("a" )
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 | search:reset (search)
428 |
429 |
430 | Sets (or resets) the search parameters.
431 |
432 |
433 | Parameters:
434 |
435 | search
436 | string
437 | search to parse
438 |
439 |
440 |
441 | Returns:
442 |
443 |
444 | search
445 | self
446 |
447 |
448 | Raises:
449 | error when search is not a string
450 |
451 |
452 | Usage:
453 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
455 | print (search:reset ("g=h" ):tostring ())
456 |
457 |
458 |
459 |
460 |
461 | search:set (key, value)
462 |
463 |
464 | Set the search parameter’s value.
465 |
466 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-set
467 |
468 |
469 |
Parameters:
470 |
471 | key
472 | string
473 | search parameter name
474 |
475 | value
476 | string
477 | search parameter value
478 |
479 |
480 |
481 | Returns:
482 |
483 |
484 | search
485 | self
486 |
487 |
488 | Raises:
489 | error when key or value is not a string
490 |
491 |
492 | Usage:
493 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
495 | local result = search:set ("a" , "g" ):tostring ()
496 |
497 |
498 |
499 |
500 |
501 | search:append (key, value)
502 |
503 |
504 | Append value to the the search parameter.
505 |
506 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-append
507 |
508 |
509 |
Parameters:
510 |
511 | key
512 | string
513 | search parameter name
514 |
515 | value
516 | string
517 | search parameter value
518 |
519 |
520 |
521 | Returns:
522 |
523 |
524 | search
525 | self
526 |
527 |
528 | Raises:
529 | error when key or value is not a string
530 |
531 |
532 | Usage:
533 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
535 | local result = search:append ("a" , "g" ):tostring ()
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 | search:tostring ()
546 |
547 |
548 | Return search parameters as a string.
549 |
550 | See: https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
551 |
552 |
553 |
554 |
Returns:
555 |
556 |
557 | string
558 | string presentation of the search parameters
559 |
560 |
561 |
562 |
563 | Usage:
564 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
566 | local result = search:tostring ()
567 |
568 |
569 |
570 |
571 |
572 | search:sort ()
573 |
574 |
575 | Sort search parameters.
576 |
577 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-sort
578 |
579 |
580 |
581 |
Returns:
582 |
583 |
584 | search
585 | self
586 |
587 |
588 |
589 |
590 | Usage:
591 | local search = require ("resty.ada.search" ).parse ("e=f&c=d&a=b" )
593 | local result = search:sort ():tostring ()
594 |
595 |
596 |
597 |
598 |
599 | search:size ()
600 |
601 |
602 | Count search parameters.
603 |
604 |
605 |
606 | Returns:
607 |
608 |
609 | number
610 | search parameters count
611 |
612 |
613 |
614 |
615 | Usage:
616 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
618 | local result = search:size ()
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 | search:__pairs ()
629 |
630 |
631 | Iterate over each key and value in search parameters.
632 |
633 |
634 |
635 | Returns:
636 |
637 |
638 | function
639 | iterator function
640 |
641 | cdata
642 | state
643 |
644 |
645 |
646 |
647 | Usage:
648 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
650 | for key, value in pairs (search) do
651 | print (key, " = " , value)
652 | end
653 |
654 |
655 |
656 |
657 |
658 | search:__pairs ()
659 |
660 |
661 | Iterate over each parameter in search parameters.
662 |
663 |
664 |
665 | Returns:
666 |
667 |
668 | function
669 | iterator function
670 |
671 | cdata
672 | state
673 |
674 |
675 |
676 |
677 | Usage:
678 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
680 | for i, param in ipairs (search) do
681 | print (i, ". " , param.key, " = " , param.value)
682 | end
683 |
684 |
685 |
686 |
687 |
688 | search:__tostring ()
689 |
690 |
691 | Return search parameters as a string.
692 |
693 | See: https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
694 |
695 |
696 |
697 |
Returns:
698 |
699 |
700 | string
701 | string presentation of the search parameters
702 |
703 |
704 |
705 |
706 | Usage:
707 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
709 | local result = tostring (search)
710 |
711 |
712 |
713 |
714 |
715 | search:__len ()
716 |
717 |
718 | Count search parameters.
719 |
720 |
721 |
722 | Returns:
723 |
724 |
725 | number
726 | search parameters count
727 |
728 |
729 |
730 |
731 | Usage:
732 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
734 | local result = #search
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 | search:free ()
745 |
746 |
747 | Explicitly destroys the Ada URL Search instance and frees the memory.
748 |
749 | After calling this function, further calls will result runtime error.
750 | If this is not explicitly called, the memory is freed with garbage
751 | collector.
752 |
753 |
754 |
755 |
756 |
757 |
758 |
Usage:
759 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
761 | search:free ()
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 | search:remove (key)
772 |
773 |
774 | Remove search parameter.
775 |
776 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-delete
777 |
778 |
779 |
Parameters:
780 |
781 | key
782 | string
783 | search parameter name
784 |
785 |
786 |
787 | Returns:
788 |
789 |
790 | search
791 | self
792 |
793 |
794 | Raises:
795 | error when key is not a string
796 |
797 |
798 | Usage:
799 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
801 | local result = search:remove ("a" ):tostring ()
802 |
803 |
804 |
805 |
806 |
807 | search:remove_value (key, value)
808 |
809 |
810 | Remove search parameter’s value.
811 |
812 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-delete
813 |
814 |
815 |
Parameters:
816 |
817 | key
818 | string
819 | search parameter name
820 |
821 | value
822 | string
823 | search parameter’s value
824 |
825 |
826 |
827 | Returns:
828 |
829 |
830 | search
831 | self
832 |
833 |
834 | Raises:
835 | error when key or value is not a string
836 |
837 |
838 | Usage:
839 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
841 | local result = search:remove_value ("a" , "b" ):tostring ()
842 |
843 |
844 |
845 |
846 |
847 |
848 |
849 |
850 |
851 | search:each ()
852 |
853 |
854 | Iterate over search parameters.
855 |
856 |
857 |
858 | Returns:
859 |
860 |
861 | function
862 | iterator function
863 |
864 | cdata
865 | state
866 |
867 |
868 |
869 |
870 | Usage:
871 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
873 | for param in search:each () do
874 | print (param.key, " = " , param.value)
875 | end
876 |
877 |
878 |
879 |
880 |
881 | search:each_key ()
882 |
883 |
884 | Iterate over each key in search parameters.
885 |
886 |
887 |
888 | Returns:
889 |
890 |
891 | function
892 | iterator function
893 |
894 | cdata
895 | state
896 |
897 |
898 |
899 |
900 | Usage:
901 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
903 | for key in search:each_key () do
904 | print ("key: " , key)
905 | end
906 |
907 |
908 |
909 |
910 |
911 | search:each_value ()
912 |
913 |
914 | Iterate over each value in search parameters.
915 |
916 |
917 |
918 | Returns:
919 |
920 |
921 | function
922 | iterator function
923 |
924 | cdata
925 | state
926 |
927 |
928 |
929 |
930 | Usage:
931 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
933 | for value in search:each_value () do
934 | print ("value: " , value)
935 | end
936 |
937 |
938 |
939 |
940 |
941 | search:pairs ()
942 |
943 |
944 | Iterate over each key and value in search parameters.
945 |
946 |
947 |
948 | Returns:
949 |
950 |
951 | function
952 | iterator function
953 |
954 | cdata
955 | state
956 |
957 |
958 |
959 |
960 | Usage:
961 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
963 | for key, value in search:pairs () do
964 | print (key, " = " , value)
965 | end
966 |
967 |
968 |
969 |
970 |
971 | search:ipairs ()
972 |
973 |
974 | Iterate over each parameter in search parameters.
975 |
976 |
977 |
978 | Returns:
979 |
980 |
981 | function
982 | iterator function
983 |
984 | cdata
985 | state
986 |
987 |
988 |
989 |
990 | Usage:
991 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
993 | for i, param in search:ipairs () do
994 | print (param.key, " = " , param.value)
995 | end
996 |
997 |
998 |
999 |
1000 |
1001 |
1002 |
1003 |
1004 |
1005 |
generated by LDoc 1.5.0
1006 |
Last updated 2024-09-03 15:49:45
1007 |
1008 |
1009 |
1010 |
1011 |
--------------------------------------------------------------------------------
/docs/data/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bungle/lua-resty-ada/ea95c91af82c4c2ed4e0e4e5a4253429ad346437/docs/data/icon.png
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | LuaJIT FFI bindings to Ada — WHATWG-compliant and fast URL parser
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
resty.ada
28 |
29 |
30 |
31 |
32 |
33 |
34 |
Modules
35 |
39 |
Classes
40 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
WHATWG-compliant and fast URL parser
51 |
lua-resty-ada
implements a LuaJIT FFI bindings to Ada — WHATWG-compliant and fast URL parser
52 |
53 |
Modules
54 |
55 |
56 | resty.ada
57 | Provides URL parsing and manipulation functionality.
58 |
59 |
60 | resty.ada.search
61 | Provides URL search parameter parsing and manipulation functionality.
62 |
63 |
64 |
Classes
65 |
66 |
67 | url
68 | Ada URL
69 |
70 |
71 | search
72 | Ada URL search parameters
73 |
74 |
75 |
76 |
77 |
78 |
79 |
generated by LDoc 1.5.0
80 |
Last updated 2024-09-03 15:49:45
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/docs/ldoc_new.css:
--------------------------------------------------------------------------------
1 | body {
2 | color: #47555c;
3 | font-size: 16px;
4 | font-family: "Open Sans", sans-serif;
5 | margin: 0;
6 | background: #eff4ff;
7 | }
8 |
9 | a:link { color: #008fee; }
10 | a:visited { color: #008fee; }
11 | a:hover { color: #22a7ff; }
12 |
13 | h1 { font-size:26px; font-weight: normal; }
14 | h2 { font-size:22px; font-weight: normal; }
15 | h3 { font-size:18px; font-weight: normal; }
16 | h4 { font-size:16px; font-weight: bold; }
17 |
18 | hr {
19 | height: 1px;
20 | background: #c1cce4;
21 | border: 0px;
22 | margin: 15px 0;
23 | }
24 |
25 | code, tt {
26 | font-family: monospace;
27 | }
28 | span.parameter {
29 | font-family: monospace;
30 | font-weight: bold;
31 | color: rgb(99, 115, 131);
32 | }
33 | span.parameter:after {
34 | content:":";
35 | }
36 | span.types:before {
37 | content:"(";
38 | }
39 | span.types:after {
40 | content:")";
41 | }
42 | .type {
43 | font-weight: bold; font-style:italic
44 | }
45 |
46 | p.name {
47 | font-family: "Andale Mono", monospace;
48 | }
49 |
50 | #navigation {
51 | float: left;
52 | background-color: white;
53 | border-right: 1px solid #d3dbec;
54 | border-bottom: 1px solid #d3dbec;
55 |
56 | width: 14em;
57 | vertical-align: top;
58 | overflow: visible;
59 | }
60 |
61 | #navigation br {
62 | display: none;
63 | }
64 |
65 | #navigation h1 {
66 | background-color: white;
67 | border-bottom: 1px solid #d3dbec;
68 | padding: 15px;
69 | margin-top: 0px;
70 | margin-bottom: 0px;
71 | }
72 |
73 | #navigation h2 {
74 | font-size: 18px;
75 | background-color: white;
76 | border-bottom: 1px solid #d3dbec;
77 | padding-left: 15px;
78 | padding-right: 15px;
79 | padding-top: 10px;
80 | padding-bottom: 10px;
81 | margin-top: 30px;
82 | margin-bottom: 0px;
83 | }
84 |
85 | #content h1 {
86 | background-color: #2c3e67;
87 | color: white;
88 | padding: 15px;
89 | margin: 0px;
90 | }
91 |
92 | #content h2 {
93 | background-color: #6c7ea7;
94 | color: white;
95 | padding: 15px;
96 | padding-top: 15px;
97 | padding-bottom: 15px;
98 | margin-top: 0px;
99 | }
100 |
101 | #content h2 a {
102 | background-color: #6c7ea7;
103 | color: white;
104 | text-decoration: none;
105 | }
106 |
107 | #content h2 a:hover {
108 | text-decoration: underline;
109 | }
110 |
111 | #content h3 {
112 | font-style: italic;
113 | padding-top: 15px;
114 | padding-bottom: 4px;
115 | margin-right: 15px;
116 | margin-left: 15px;
117 | margin-bottom: 5px;
118 | border-bottom: solid 1px #bcd;
119 | }
120 |
121 | #content h4 {
122 | margin-right: 15px;
123 | margin-left: 15px;
124 | border-bottom: solid 1px #bcd;
125 | }
126 |
127 | #content pre {
128 | margin: 15px;
129 | }
130 |
131 | pre {
132 | background-color: rgb(50, 55, 68);
133 | color: white;
134 | border-radius: 3px;
135 | /* border: 1px solid #C0C0C0; /* silver */
136 | padding: 15px;
137 | overflow: auto;
138 | font-family: "Andale Mono", monospace;
139 | }
140 |
141 | #content ul pre.example {
142 | margin-left: 0px;
143 | }
144 |
145 | table.index {
146 | /* border: 1px #00007f; */
147 | }
148 | table.index td { text-align: left; vertical-align: top; }
149 |
150 | #navigation ul
151 | {
152 | font-size:1em;
153 | list-style-type: none;
154 | margin: 1px 1px 10px 1px;
155 | }
156 |
157 | #navigation li {
158 | text-indent: -1em;
159 | display: block;
160 | margin: 3px 0px 0px 22px;
161 | }
162 |
163 | #navigation li li a {
164 | margin: 0px 3px 0px -1em;
165 | }
166 |
167 | #content {
168 | margin-left: 14em;
169 | }
170 |
171 | #content p {
172 | padding-left: 15px;
173 | padding-right: 15px;
174 | }
175 |
176 | #content table {
177 | padding-left: 15px;
178 | padding-right: 15px;
179 | background-color: white;
180 | }
181 |
182 | #content p, #content table, #content ol, #content ul, #content dl {
183 | max-width: 900px;
184 | }
185 |
186 | #about {
187 | padding: 15px;
188 | padding-left: 16em;
189 | background-color: white;
190 | border-top: 1px solid #d3dbec;
191 | border-bottom: 1px solid #d3dbec;
192 | }
193 |
194 | table.module_list, table.function_list {
195 | border-width: 1px;
196 | border-style: solid;
197 | border-color: #cccccc;
198 | border-collapse: collapse;
199 | margin: 15px;
200 | }
201 | table.module_list td, table.function_list td {
202 | border-width: 1px;
203 | padding-left: 10px;
204 | padding-right: 10px;
205 | padding-top: 5px;
206 | padding-bottom: 5px;
207 | border: solid 1px rgb(193, 204, 228);
208 | }
209 | table.module_list td.name, table.function_list td.name {
210 | background-color: white; min-width: 200px; border-right-width: 0px;
211 | }
212 | table.module_list td.summary, table.function_list td.summary {
213 | background-color: white; width: 100%; border-left-width: 0px;
214 | }
215 |
216 | dl.function {
217 | margin-right: 15px;
218 | margin-left: 15px;
219 | border-bottom: solid 1px rgb(193, 204, 228);
220 | border-left: solid 1px rgb(193, 204, 228);
221 | border-right: solid 1px rgb(193, 204, 228);
222 | background-color: white;
223 | }
224 |
225 | dl.function dt {
226 | color: rgb(99, 123, 188);
227 | font-family: monospace;
228 | border-top: solid 1px rgb(193, 204, 228);
229 | padding: 15px;
230 | }
231 |
232 | dl.function dd {
233 | margin-left: 15px;
234 | margin-right: 15px;
235 | margin-top: 5px;
236 | margin-bottom: 15px;
237 | }
238 |
239 | #content dl.function dd h3 {
240 | margin-top: 0px;
241 | margin-left: 0px;
242 | padding-left: 0px;
243 | font-size: 16px;
244 | color: rgb(128, 128, 128);
245 | border-bottom: solid 1px #def;
246 | }
247 |
248 | #content dl.function dd ul, #content dl.function dd ol {
249 | padding: 0px;
250 | padding-left: 15px;
251 | list-style-type: none;
252 | }
253 |
254 | ul.nowrap {
255 | overflow:auto;
256 | white-space:nowrap;
257 | }
258 |
259 | .section-description {
260 | padding-left: 15px;
261 | padding-right: 15px;
262 | }
263 |
264 | /* stop sublists from having initial vertical space */
265 | ul ul { margin-top: 0px; }
266 | ol ul { margin-top: 0px; }
267 | ol ol { margin-top: 0px; }
268 | ul ol { margin-top: 0px; }
269 |
270 | /* make the target distinct; helps when we're navigating to a function */
271 | a:target + * {
272 | background-color: #FF9;
273 | }
274 |
275 |
276 | /* styles for prettification of source */
277 | pre .comment { color: #bbccaa; }
278 | pre .constant { color: #a8660d; }
279 | pre .escape { color: #844631; }
280 | pre .keyword { color: #ffc090; font-weight: bold; }
281 | pre .library { color: #0e7c6b; }
282 | pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; }
283 | pre .string { color: #8080ff; }
284 | pre .number { color: #f8660d; }
285 | pre .operator { color: #2239a8; font-weight: bold; }
286 | pre .preprocessor, pre .prepro { color: #a33243; }
287 | pre .global { color: #c040c0; }
288 | pre .user-keyword { color: #800080; }
289 | pre .prompt { color: #558817; }
290 | pre .url { color: #272fc2; text-decoration: underline; }
291 |
--------------------------------------------------------------------------------
/docs/modules/resty.ada.search.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | LuaJIT FFI bindings to Ada — WHATWG-compliant and fast URL parser
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
resty.ada
28 |
29 |
30 |
31 |
34 |
35 |
Contents
36 |
46 |
47 |
48 |
Modules
49 |
53 |
Classes
54 |
58 |
59 |
60 |
61 |
62 |
63 |
Module resty.ada.search
64 |
Provides URL search parameter parsing and manipulation functionality.
65 |
See: https://url.spec.whatwg.org/#interface-urlsearchparams
66 |
67 |
68 |
69 |
70 |
71 | parse (search)
72 | Parses search and returns an instance of Ada URL Search.
73 |
74 |
75 |
76 |
86 |
87 |
97 |
98 |
108 |
109 |
110 |
111 | encode (params)
112 | Encodes search parameters and returns an query string.
113 |
114 |
115 | decode (search)
116 | Decodes search parameters and returns a Lua table of them.
117 |
118 |
119 | decode_all (search)
120 | Decodes all search parameters and returns a Lua table of them.
121 |
122 |
123 |
124 |
134 |
135 |
136 |
137 | each (search)
138 | Iterate over search parameters.
139 |
140 |
141 | each_key (search)
142 | Iterate over each key in search parameters.
143 |
144 |
145 | each_value (search)
146 | Iterate over each value in search parameters.
147 |
148 |
149 | pairs (search)
150 | Iterate over each key and value in search parameters.
151 |
152 |
153 | ipairs (search)
154 | Iterate over each parameter in search parameters.
155 |
156 |
157 |
158 |
159 |
160 | sort (search)
161 | Sort search parameters.
162 |
163 |
164 | size (search)
165 | Count search parameters.
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 | parse (search)
179 |
180 |
181 | Parses search and returns an instance of Ada URL Search.
182 |
183 | See: https://url.spec.whatwg.org/#interface-urlsearchparams
184 |
185 |
186 |
Parameters:
187 |
188 | search
189 | string
190 | search to parse
191 |
192 |
193 |
194 | Returns:
195 |
196 |
197 | search
198 | Ada URL Search instance
199 |
200 |
201 | Raises:
202 | error when search is not a string
203 |
204 |
205 | Usage:
206 | local search = require ("resty.ada.search" ).parse ("a=b&c=d&e=f" )
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 | has (search, key)
218 |
219 |
220 | Checks whether the search has a key.
221 |
222 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-has
223 |
224 |
225 |
Parameters:
226 |
227 | search
228 | string
229 | search to parse
230 |
231 | key
232 | string
233 | search parameter name to check
234 |
235 |
236 |
237 | Returns:
238 |
239 |
240 | boolean
241 | true
if search has the key, otherwise false
242 |
243 |
244 | Raises:
245 | error when search or key is not a string
246 |
247 |
248 | Usage:
249 | local search = require ("resty.ada.search" )
251 | local result = search.has ("a=b&c=d&e=f" , "a" )
252 |
253 |
254 |
255 |
256 |
257 | has_value (search, key, value)
258 |
259 |
260 | Checks whether the search has a key with a specific value.
261 |
262 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-has
263 |
264 |
265 |
Parameters:
266 |
267 | search
268 | string
269 | search to parse
270 |
271 | key
272 | string
273 | search parameter name to check
274 |
275 | value
276 | string
277 | search parameter value to check
278 |
279 |
280 |
281 | Returns:
282 |
283 |
284 | boolean
285 | true
if search has the key with the value, otherwise false
286 |
287 |
288 | Raises:
289 | error when search, key or value is not a string
290 |
291 |
292 | Usage:
293 | local search = require ("resty.ada.search" )
295 | local result = search.has_value ("a=b&c=d&e=f" , "a" , "b" )
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 | get (search, key)
306 |
307 |
308 | Get search parameter’s value.
309 |
310 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-get
311 |
312 |
313 |
Parameters:
314 |
315 | search
316 | string
317 | search to parse
318 |
319 | key
320 | string
321 | search parameter name
322 |
323 |
324 |
325 | Returns:
326 |
327 |
328 | string or nil
329 | parameter value or nil
330 |
331 |
332 | Raises:
333 | error when search or key is not a string
334 |
335 |
336 | Usage:
337 | local search = require ("resty.ada.search" )
339 | local result = search.get ("a=b&c=d&e=f" , "a" )
340 |
341 |
342 |
343 |
344 |
345 | get_all (search, key)
346 |
347 |
348 | Get all the search parameter’s values.
349 |
350 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-getall
351 |
352 |
353 |
Parameters:
354 |
355 | search
356 | string
357 | search to parse
358 |
359 | key
360 | string
361 | search parameter name
362 |
363 |
364 |
365 | Returns:
366 |
367 |
368 | table
369 | array of all the values (or an empty array)
370 |
371 |
372 | Raises:
373 | error when search or key is not a string
374 |
375 |
376 | Usage:
377 | local search = require ("resty.ada.search" )
379 | local result = search.get_all ("a=b&c=d&e=f" , "a" )
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 | set (search, key, value)
390 |
391 |
392 | Set the search parameter’s value.
393 |
394 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-set
395 |
396 |
397 |
Parameters:
398 |
399 | search
400 | string
401 | search to parse
402 |
403 | key
404 | string
405 | search parameter name
406 |
407 | value
408 | string
409 | search parameter value
410 |
411 |
412 |
413 | Returns:
414 |
415 |
416 | string
417 | string presentation of the search parameters
418 |
419 |
420 | Raises:
421 | error when search, key or value is not a string
422 |
423 |
424 | Usage:
425 | local search = require ("resty.ada.search" )
427 | local result = search.set ("a=b&c=d&e=f" , "a" , "g" )
428 |
429 |
430 |
431 |
432 |
433 | append (search, key, value)
434 |
435 |
436 | Append value to the the search parameter.
437 |
438 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-append
439 |
440 |
441 |
Parameters:
442 |
443 | search
444 | string
445 | search to parse
446 |
447 | key
448 | string
449 | search parameter name
450 |
451 | value
452 | string
453 | search parameter value
454 |
455 |
456 |
457 | Returns:
458 |
459 |
460 | string
461 | string presentation of the search parameters
462 |
463 |
464 | Raises:
465 | error when search, key or value is not a string
466 |
467 |
468 | Usage:
469 | local search = require ("resty.ada.search" )
471 | local result = search.append ("a=b&c=d&e=f" , "a" , "g" )
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 | encode (params)
482 |
483 |
484 | Encodes search parameters and returns an query string.
485 |
486 |
487 | only string keys are allowed.
488 | only string , boolean
and number
values are allowed or an array of them
489 | false
value is treated as missing (same as nil
)
490 | true
returns ""
(empty string)
491 | negative and positive inf
and NaN
are not allowed as numbers in values
492 |
493 |
494 |
495 | When passing a table the keys will be sorted and with string the given order
496 | is preserved.
497 |
498 |
499 |
Parameters:
500 |
506 |
507 | Returns:
508 |
509 |
510 | string
511 | encoded query string
512 |
513 |
514 | Raises:
515 | error when search or key is not a table or string, or when the rules above are not followed
516 |
517 |
518 | Usage:
519 | local search = require ("resty.ada.search" )
521 | local result = search.encode ({
522 | g = "h" ,
523 | a = { "f" , "b" , },
524 | c = "d" ,
525 | })
526 |
527 |
528 |
529 |
530 |
531 | decode (search)
532 |
533 |
534 | Decodes search parameters and returns a Lua table of them.
535 |
536 | If same parameter appears multiple times, only the value of the
537 | first is returned.
538 |
539 | Given the following query string:
540 | “a=b&c=d&e=f&a=g”
541 |
542 | The following table is returned:
543 | {
544 | a = “b”,
545 | c = “d”,
546 | e = “f”,
547 | }
548 |
549 |
550 |
Parameters:
551 |
552 | search
553 | string
554 | search to parse
555 |
556 |
557 |
558 | Returns:
559 |
560 |
561 | table
562 | a table of all search parameters (a string:string map).
563 |
564 |
565 | Raises:
566 | error when search or key is not a string
567 |
568 |
569 | Usage:
570 | local search = require ("resty.ada.search" )
572 | local result = search.decode ("a=b&c=d&e=f&a=g" )
573 |
574 |
575 |
576 |
577 |
578 | decode_all (search)
579 |
580 |
581 | Decodes all search parameters and returns a Lua table of them.
582 |
583 | Given the following query string:
584 | “a=b&a=c&d=e”"
585 |
586 | The following table is returned:
587 | {
588 | a = { “b”, “c” },
589 | d = { “e” },
590 | }
591 |
592 |
593 |
Parameters:
594 |
595 | search
596 | string
597 | search to parse
598 |
599 |
600 |
601 | Returns:
602 |
603 |
604 | table
605 | a table of all search parameters (a string:table [array] map).
606 |
607 |
608 | Raises:
609 | error when search or key is not a string
610 |
611 |
612 | Usage:
613 | local search = require ("resty.ada.search" )
615 | local result = search.decode_all ("a=b&a=c&d=e" )
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 | remove (search, key)
626 |
627 |
628 | Remove search parameter.
629 |
630 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-delete
631 |
632 |
633 |
Parameters:
634 |
635 | search
636 | string
637 | search to parse
638 |
639 | key
640 | string
641 | search parameter name
642 |
643 |
644 |
645 | Returns:
646 |
647 |
648 | string
649 | string presentation of the search parameters
650 |
651 |
652 | Raises:
653 | error when search or key is not a string
654 |
655 |
656 | Usage:
657 | local search = require ("resty.ada.search" )
659 | local result = search.remove ("a=b&c=d&e=f" , "a" )
660 |
661 |
662 |
663 |
664 |
665 | remove_value (search, key, value)
666 |
667 |
668 | Remove search parameter’s value.
669 |
670 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-delete
671 |
672 |
673 |
Parameters:
674 |
675 | search
676 | string
677 | search to parse
678 |
679 | key
680 | string
681 | search parameter name
682 |
683 | value
684 | string
685 | search parameter’s value
686 |
687 |
688 |
689 | Returns:
690 |
691 |
692 | string
693 | string presentation of the search parameters
694 |
695 |
696 | Raises:
697 | error when search, key or value is not a string
698 |
699 |
700 | Usage:
701 | local search = require ("resty.ada.search" )
703 | local result = search.remove_value ("a=b&c=d&e=f" , "a" , "b" )
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 | each (search)
714 |
715 |
716 | Iterate over search parameters.
717 |
718 |
719 | Parameters:
720 |
721 | search
722 | string
723 | search to parse
724 |
725 |
726 |
727 | Returns:
728 |
729 |
730 | function
731 | iterator function
732 |
733 | cdata
734 | state
735 |
736 |
737 | Raises:
738 | error when search is not a string
739 |
740 |
741 | Usage:
742 | local search = require ("resty.ada.search" )
744 | for param in search.each ("a=b&c=d&e=f" ) do
745 | print (param.key, " = " , param.value)
746 | end
747 |
748 |
749 |
750 |
751 |
752 | each_key (search)
753 |
754 |
755 | Iterate over each key in search parameters.
756 |
757 |
758 | Parameters:
759 |
760 | search
761 | string
762 | search to parse
763 |
764 |
765 |
766 | Returns:
767 |
768 |
769 | function
770 | iterator function
771 |
772 | cdata
773 | state
774 |
775 |
776 | Raises:
777 | error when search is not a string
778 |
779 |
780 | Usage:
781 | local search = require ("resty.ada.search" )
783 | for key in search.each_key ("a=b&c=d&e=f" ) do
784 | print ("key: " , key)
785 | end
786 |
787 |
788 |
789 |
790 |
791 | each_value (search)
792 |
793 |
794 | Iterate over each value in search parameters.
795 |
796 |
797 | Parameters:
798 |
799 | search
800 | string
801 | search to parse
802 |
803 |
804 |
805 | Returns:
806 |
807 |
808 | function
809 | iterator function
810 |
811 | cdata
812 | state
813 |
814 |
815 | Raises:
816 | error when search is not a string
817 |
818 |
819 | Usage:
820 | local search = require ("resty.ada.search" )
822 | for value in search.each_value ("a=b&c=d&e=f" ) do
823 | print ("value: " , value)
824 | end
825 |
826 |
827 |
828 |
829 |
830 | pairs (search)
831 |
832 |
833 | Iterate over each key and value in search parameters.
834 |
835 |
836 | Parameters:
837 |
838 | search
839 | string
840 | search to parse
841 |
842 |
843 |
844 | Returns:
845 |
846 |
847 | function
848 | iterator function
849 |
850 | cdata
851 | state
852 |
853 |
854 | Raises:
855 | error when search is not a string
856 |
857 |
858 | Usage:
859 | local search = require ("resty.ada.search" )
861 | for key, value in search.pairs ("a=b&c=d&e=f" ) do
862 | print (key, " = " , value)
863 | end
864 |
865 |
866 |
867 |
868 |
869 | ipairs (search)
870 |
871 |
872 | Iterate over each parameter in search parameters.
873 |
874 |
875 | Parameters:
876 |
877 | search
878 | string
879 | search to parse
880 |
881 |
882 |
883 | Returns:
884 |
885 |
886 | function
887 | iterator function
888 |
889 | cdata
890 | state
891 |
892 |
893 | Raises:
894 | error when search is not a string
895 |
896 |
897 | Usage:
898 | for i, param in search.ipairs ("a=b&c=d&e=f" ) do
900 | print (i, ". " , param.key, " = " , param.value)
901 | end
902 |
903 |
904 |
905 |
906 |
907 |
908 |
909 |
910 |
911 | sort (search)
912 |
913 |
914 | Sort search parameters.
915 |
916 | See: https://url.spec.whatwg.org/#dom-urlsearchparams-sort
917 |
918 |
919 |
Parameters:
920 |
921 | search
922 | string
923 | search to parse
924 |
925 |
926 |
927 | Returns:
928 |
929 |
930 | string
931 | string presentation of the search parameters
932 |
933 |
934 | Raises:
935 | error when search is not a string
936 |
937 |
938 | Usage:
939 | local search = require ("resty.ada.search" )
941 | local result = search.sort ("e=f&c=d&a=b" )
942 |
943 |
944 |
945 |
946 |
947 | size (search)
948 |
949 |
950 | Count search parameters.
951 |
952 |
953 | Parameters:
954 |
955 | search
956 | string
957 | search to parse
958 |
959 |
960 |
961 | Returns:
962 |
963 |
964 | number
965 | search parameters count
966 |
967 |
968 | Raises:
969 | error when search is not a string
970 |
971 |
972 | Usage:
973 | local search = require ("resty.ada.search" )
975 | local result = search.size ("a=b&c=d&e=f" )
976 |
977 |
978 |
979 |
980 |
981 |
982 |
983 |
984 |
985 |
generated by LDoc 1.5.0
986 |
Last updated 2024-09-03 15:49:45
987 |
988 |
989 |
990 |
991 |
--------------------------------------------------------------------------------
/lib/resty/ada/lib.lua:
--------------------------------------------------------------------------------
1 | ---
2 | -- Provides Ada FFI definitions and library loading functionality.
3 | --
4 | -- @local
5 | -- @module resty.ada.lib
6 |
7 |
8 | local ffi = require("ffi")
9 |
10 |
11 | local error = error
12 | local pcall = pcall
13 | local ipairs = ipairs
14 | local ffi_load = ffi.load
15 |
16 |
17 | ffi.cdef([[
18 | typedef struct {
19 | const char* data;
20 | size_t length;
21 | } ada_string;
22 |
23 | typedef struct {
24 | const char* data;
25 | size_t length;
26 | } ada_owned_string;
27 |
28 | typedef struct {
29 | uint32_t protocol_end;
30 | uint32_t username_end;
31 | uint32_t host_start;
32 | uint32_t host_end;
33 | uint32_t port;
34 | uint32_t pathname_start;
35 | uint32_t search_start;
36 | uint32_t hash_start;
37 | } ada_url_components;
38 |
39 | typedef struct {
40 | ada_string key;
41 | ada_string value;
42 | } ada_string_pair;
43 |
44 | typedef void* ada_url;
45 | typedef void* ada_strings;
46 | typedef void* ada_url_search_params;
47 | typedef void* ada_url_search_params_keys_iter;
48 | typedef void* ada_url_search_params_values_iter;
49 | typedef void* ada_url_search_params_entries_iter;
50 |
51 | const ada_url_components* ada_get_components(ada_url result);
52 |
53 | ada_url ada_parse(const char* input, size_t length);
54 | ada_url ada_parse_with_base(const char* input, size_t input_length, const char* base, size_t base_length);
55 | ada_url_search_params ada_parse_search_params(const char* input, size_t length);
56 |
57 | bool ada_can_parse(const char* input, size_t length);
58 | bool ada_can_parse_with_base(const char* input, size_t input_length, const char* base, size_t base_length);
59 |
60 | void ada_free(ada_url result);
61 | void ada_free_owned_string(ada_owned_string owned);
62 | void ada_free_search_params(ada_url_search_params result);
63 | void ada_free_strings(ada_strings result);
64 | void ada_free_search_params_keys_iter(ada_url_search_params_keys_iter result);
65 | void ada_free_search_params_values_iter(ada_url_search_params_values_iter result);
66 | void ada_free_search_params_entries_iter(ada_url_search_params_entries_iter result);
67 |
68 | ada_url ada_copy(ada_url input);
69 |
70 | bool ada_is_valid(ada_url result);
71 |
72 | ada_owned_string ada_get_origin(ada_url result);
73 | ada_string ada_get_href(ada_url result);
74 | ada_string ada_get_username(ada_url result);
75 | ada_string ada_get_password(ada_url result);
76 | ada_string ada_get_port(ada_url result);
77 | ada_string ada_get_hash(ada_url result);
78 | ada_string ada_get_host(ada_url result);
79 | ada_string ada_get_hostname(ada_url result);
80 | ada_string ada_get_pathname(ada_url result);
81 | ada_string ada_get_search(ada_url result);
82 | ada_string ada_get_protocol(ada_url result);
83 | uint8_t ada_get_host_type(ada_url result);
84 | uint8_t ada_get_scheme_type(ada_url result);
85 |
86 | bool ada_set_href(ada_url result, const char* input, size_t length);
87 | bool ada_set_host(ada_url result, const char* input, size_t length);
88 | bool ada_set_hostname(ada_url result, const char* input, size_t length);
89 | bool ada_set_protocol(ada_url result, const char* input, size_t length);
90 | bool ada_set_username(ada_url result, const char* input, size_t length);
91 | bool ada_set_password(ada_url result, const char* input, size_t length);
92 | bool ada_set_port(ada_url result, const char* input, size_t length);
93 | bool ada_set_pathname(ada_url result, const char* input, size_t length);
94 | void ada_set_search(ada_url result, const char* input, size_t length);
95 | void ada_set_hash(ada_url result, const char* input, size_t length);
96 |
97 | void ada_clear_port(ada_url result);
98 | void ada_clear_hash(ada_url result);
99 | void ada_clear_search(ada_url result);
100 |
101 | bool ada_has_credentials(ada_url result);
102 | bool ada_has_empty_hostname(ada_url result);
103 | bool ada_has_hostname(ada_url result);
104 | bool ada_has_non_empty_username(ada_url result);
105 | bool ada_has_non_empty_password(ada_url result);
106 | bool ada_has_port(ada_url result);
107 | bool ada_has_password(ada_url result);
108 | bool ada_has_hash(ada_url result);
109 | bool ada_has_search(ada_url result);
110 |
111 | ada_owned_string ada_idna_to_unicode(const char* input, size_t length);
112 | ada_owned_string ada_idna_to_ascii(const char* input, size_t length);
113 |
114 | ada_owned_string ada_search_params_to_string(ada_url_search_params result);
115 | size_t ada_search_params_size(ada_url_search_params result);
116 | void ada_search_params_reset(ada_url_search_params result, const char* input, size_t length);
117 | void ada_search_params_sort(ada_url_search_params result);
118 | void ada_search_params_append(ada_url_search_params result, const char* key, size_t key_length, const char* value, size_t value_length);
119 | void ada_search_params_set(ada_url_search_params result, const char* key, size_t key_length, const char* value, size_t value_length);
120 | bool ada_search_params_has(ada_url_search_params result, const char* key, size_t key_length);
121 | bool ada_search_params_has_value(ada_url_search_params result, const char* key, size_t key_length, const char* value, size_t value_length);
122 | ada_string ada_search_params_get(ada_url_search_params result, const char* key, size_t key_length);
123 | ada_strings ada_search_params_get_all(ada_url_search_params result, const char* key, size_t key_length);
124 |
125 | ada_url_search_params_keys_iter ada_search_params_get_keys(ada_url_search_params result);
126 | ada_url_search_params_values_iter ada_search_params_get_values(ada_url_search_params result);
127 | ada_url_search_params_entries_iter ada_search_params_get_entries(ada_url_search_params result);
128 |
129 | bool ada_search_params_keys_iter_has_next(ada_url_search_params_keys_iter result);
130 | bool ada_search_params_values_iter_has_next(ada_url_search_params_values_iter result);
131 | bool ada_search_params_entries_iter_has_next(ada_url_search_params_entries_iter result);
132 |
133 | ada_string ada_search_params_keys_iter_next(ada_url_search_params_keys_iter result);
134 | ada_string ada_search_params_values_iter_next(ada_url_search_params_values_iter result);
135 | ada_string_pair ada_search_params_entries_iter_next(ada_url_search_params_entries_iter result);
136 |
137 | size_t ada_strings_size(ada_strings result);
138 | ada_string ada_strings_get(ada_strings result, size_t index);
139 |
140 | void ada_search_params_remove(ada_url_search_params result, const char* key, size_t key_length);
141 | void ada_search_params_remove_value(ada_url_search_params result, const char* key, size_t key_length, const char* value, size_t value_length);
142 | ]])
143 |
144 |
145 | local function load_lib(name)
146 | local pok, lib = pcall(ffi_load, name)
147 | if pok then
148 | return lib
149 | end
150 | end
151 |
152 |
153 | local load_lib_from_cpath do
154 | local gmatch = string.gmatch
155 | local match = string.match
156 | local open = io.open
157 | local close = io.close
158 | local cpath = package.cpath
159 | function load_lib_from_cpath(name)
160 | for path, _ in gmatch(cpath, "[^;]+") do
161 | if path == "?.so" or path == "?.dylib" then
162 | path = "./"
163 | end
164 | local file_path = match(path, "(.*/)")
165 | file_path = file_path .. name
166 | local file = open(file_path)
167 | if file ~= nil then
168 | close(file)
169 | local lib = load_lib(file_path)
170 | return lib
171 | end
172 | end
173 | end
174 | end
175 |
176 |
177 | do
178 | local library_names = {
179 | "libada",
180 | "ada",
181 | }
182 |
183 | local library_versions = {
184 | "",
185 | ".3",
186 | ".2",
187 | }
188 |
189 | local library_extensions = ffi.os == "OSX" and { ".dylib", ".so", }
190 | or { ".so", ".dylib", }
191 |
192 | -- try to load ada library from package.cpath
193 | for _, library_name in ipairs(library_names) do
194 | for _, library_version in ipairs(library_versions) do
195 | for _, library_extension in ipairs(library_extensions) do
196 | local lib = load_lib_from_cpath(library_name .. library_version .. library_extension)
197 | if lib then
198 | return lib
199 | end
200 | end
201 | end
202 | end
203 |
204 | -- try to load ada library from normal system path
205 | for _, library_name in ipairs(library_names) do
206 | for _, library_version in ipairs(library_versions) do
207 | local lib = load_lib(library_name .. library_version)
208 | if lib then
209 | return lib
210 | end
211 | end
212 | end
213 |
214 | -- a final check before we give up
215 | local pok, lib = pcall(function()
216 | if ffi.C.ada_parse then
217 | return ffi.C
218 | end
219 | end)
220 | if pok then
221 | return lib
222 | end
223 | end
224 |
225 |
226 | error("unable to load ada library - please make sure that it can be found in package.cpath or system library path")
227 |
--------------------------------------------------------------------------------
/lib/resty/ada/search.lua:
--------------------------------------------------------------------------------
1 | ---
2 | -- Ada URL search parameters
3 | --
4 | -- See:
5 | --
6 | -- @classmod search
7 |
8 |
9 | local lib = require("resty.ada.lib")
10 | local utils = require("resty.ada.utils")
11 |
12 |
13 | local ada_string_to_lua = utils.ada_string_to_lua
14 | local ada_strings_to_lua = utils.ada_strings_to_lua
15 | local ada_owned_string_to_lua = utils.ada_owned_string_to_lua
16 | local number_to_string = utils.number_to_string
17 |
18 |
19 | local ffi_gc = require("ffi").gc
20 |
21 |
22 | local type = type
23 | local next = next
24 | local pairs = pairs
25 | local assert = assert
26 | local tonumber = tonumber
27 | local setmetatable = setmetatable
28 |
29 |
30 | local function each_iter(entries_iterator)
31 | if lib.ada_search_params_entries_iter_has_next(entries_iterator) then
32 | local pair = lib.ada_search_params_entries_iter_next(entries_iterator)
33 | return {
34 | key = ada_string_to_lua(pair.key),
35 | value = ada_string_to_lua(pair.value),
36 | }
37 | end
38 |
39 | ffi_gc(entries_iterator, nil)
40 | lib.ada_free_search_params_entries_iter(entries_iterator)
41 | end
42 |
43 |
44 | local function each_key_iter(keys_iterator)
45 | if lib.ada_search_params_keys_iter_has_next(keys_iterator) then
46 | local key = ada_string_to_lua(lib.ada_search_params_keys_iter_next(keys_iterator))
47 | return key
48 | end
49 |
50 | ffi_gc(keys_iterator, nil)
51 | lib.ada_free_search_params_keys_iter(keys_iterator)
52 | end
53 |
54 |
55 | local function each_value_iter(values_iterator)
56 | if lib.ada_search_params_values_iter_has_next(values_iterator) then
57 | local value = ada_string_to_lua(lib.ada_search_params_values_iter_next(values_iterator))
58 | return value
59 | end
60 |
61 | ffi_gc(values_iterator, nil)
62 | lib.ada_free_search_params_values_iter(values_iterator)
63 | end
64 |
65 |
66 | local function pairs_iter(entries_iterator)
67 | if lib.ada_search_params_entries_iter_has_next(entries_iterator) then
68 | local pair = lib.ada_search_params_entries_iter_next(entries_iterator)
69 | local key = ada_string_to_lua(pair.key)
70 | local value = ada_string_to_lua(pair.value)
71 | return key, value
72 | end
73 |
74 | ffi_gc(entries_iterator, nil)
75 | lib.ada_free_search_params_entries_iter(entries_iterator)
76 | end
77 |
78 |
79 | local function ipairs_iter(entries_iterator, invariant_state)
80 | if lib.ada_search_params_entries_iter_has_next(entries_iterator) then
81 | local pair = lib.ada_search_params_entries_iter_next(entries_iterator)
82 | local entry = {
83 | key = ada_string_to_lua(pair.key),
84 | value = ada_string_to_lua(pair.value),
85 | }
86 | return invariant_state + 1, entry
87 | end
88 |
89 | ffi_gc(entries_iterator, nil)
90 | lib.ada_free_search_params_entries_iter(entries_iterator)
91 | end
92 |
93 |
94 | local mt = {}
95 |
96 |
97 | mt.__index = mt
98 |
99 |
100 | ---
101 | -- Decode Methods
102 | -- @section decode-methods
103 |
104 |
105 | ---
106 | -- Decodes search parameters and returns a Lua table of them.
107 | --
108 | -- If same parameter appears multiple times, only the value of the
109 | -- first is returned.
110 | --
111 | -- An example return value:
112 | -- {
113 | -- key1 = "value",
114 | -- key2 = "value2",
115 | -- }
116 | --
117 | -- @function decode
118 | -- @treturn table a table of all search parameters (a string:string map).
119 | --
120 | -- @usage
121 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f&a=g")
122 | -- local result = search:decode()
123 | function mt:decode()
124 | if self:size() == 0 then
125 | return {}
126 | end
127 | local r = {}
128 | for k in self:each_key() do
129 | if not r[k] then
130 | r[k] = self:get(k)
131 | end
132 | end
133 | return r
134 | end
135 |
136 |
137 | ---
138 | -- Decodes all search parameters and returns a Lua table of them.
139 | --
140 | -- An example return value:
141 | -- {
142 | -- key1 = { "first", "second", },
143 | -- key2 = { "value" },
144 | -- }
145 | --
146 | -- @function decode
147 | -- @treturn table a table of all search parameters (a string:table [array] map).
148 | --
149 | -- @usage
150 | -- local search = require("resty.ada.search").parse("a=b&a=c&d=e")
151 | -- local result = search:decode_all()
152 | function mt:decode_all()
153 | if self:size() == 0 then
154 | return {}
155 | end
156 | local r = {}
157 | for k in self:each_key() do
158 | if not r[k] then
159 | r[k] = self:get_all(k)
160 | end
161 | end
162 | return r
163 | end
164 |
165 |
166 | ---
167 | -- Has Methods
168 | -- @section has-methods
169 |
170 |
171 | ---
172 | -- Checks whether the search has a key.
173 | --
174 | -- See:
175 | --
176 | -- @function has
177 | -- @tparam string key search parameter name to check
178 | -- @treturn boolean `true` if search has the key, otherwise `false`
179 | -- @raise error when key is not a string
180 | --
181 | -- @usage
182 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
183 | -- local result = search:has("a")
184 | function mt:has(key)
185 | assert(type(key) == "string", "invalid key")
186 | local r = lib.ada_search_params_has(self[1], key, #key)
187 | return r
188 | end
189 |
190 |
191 | ---
192 | -- Checks whether the search has a key with a specific value.
193 | --
194 | -- See:
195 | --
196 | -- @function has_value
197 | -- @tparam string key search parameter name to check
198 | -- @tparam string value search parameter value to check
199 | -- @treturn boolean `true` if search has the key with the value, otherwise `false`
200 | -- @raise error when key or value is not a string
201 | --
202 | -- @usage
203 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
204 | -- local result = search:has_value("a", "b")
205 | function mt:has_value(key, value)
206 | assert(type(key) == "string", "invalid key")
207 | assert(type(value) == "string", "invalid value")
208 | local r = lib.ada_search_params_has_value(self[1], key, #key, value, #value)
209 | return r
210 | end
211 |
212 |
213 | ---
214 | -- Get Methods
215 | -- @section get-methods
216 |
217 |
218 | ---
219 | -- Get search parameter's value.
220 | --
221 | -- See:
222 | --
223 | -- @function get
224 | -- @tparam string key search parameter name
225 | -- @treturn string|nil parameter value or `nil`
226 | -- @raise error when key is not a string
227 | --
228 | -- @usage
229 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
230 | -- local result = search:get("a")
231 | function mt:get(key)
232 | assert(type(key) == "string", "invalid key")
233 | local r = ada_string_to_lua(lib.ada_search_params_get(self[1], key, #key))
234 | return r
235 | end
236 |
237 |
238 | ---
239 | -- Get all the search parameter's values.
240 | --
241 | -- See:
242 | --
243 | -- @function get_all
244 | -- @tparam string key search parameter name
245 | -- @treturn table array of all the values (or an empty array)
246 | -- @raise error when key is not a string
247 | --
248 | -- @usage
249 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
250 | -- local result = search:get_all("a")
251 | function mt:get_all(key)
252 | assert(type(key) == "string", "invalid key")
253 | local r = ada_strings_to_lua(lib.ada_search_params_get_all(self[1], key, #key))
254 | return r
255 | end
256 |
257 |
258 | ---
259 | -- Set Methods
260 | -- @section set-methods
261 |
262 |
263 | ---
264 | -- Sets (or resets) the search parameters.
265 | --
266 | -- @function reset
267 | -- @tparam string search search to parse
268 | -- @treturn search self
269 | -- @raise error when search is not a string
270 | --
271 | -- @usage
272 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
273 | -- print(search:reset("g=h"):tostring())
274 | function mt:reset(search)
275 | assert(type(search) == "string", "invalid search")
276 | lib.ada_search_params_reset(self[1], search, #search)
277 | return self
278 | end
279 |
280 |
281 | ---
282 | -- Set the search parameter's value.
283 | --
284 | -- See:
285 | --
286 | -- @function set
287 | -- @tparam string key search parameter name
288 | -- @tparam string value search parameter value
289 | -- @treturn search self
290 | -- @raise error when key or value is not a string
291 | --
292 | -- @usage
293 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
294 | -- local result = search:set("a", "g"):tostring()
295 | function mt:set(key, value)
296 | assert(type(key) == "string", "invalid key")
297 | assert(type(value) == "string", "invalid value")
298 | lib.ada_search_params_set(self[1], key, #key, value, #value)
299 | return self
300 | end
301 |
302 |
303 | ---
304 | -- Append value to the the search parameter.
305 | --
306 | -- See:
307 | --
308 | -- @function append
309 | -- @tparam string key search parameter name
310 | -- @tparam string value search parameter value
311 | -- @treturn search self
312 | -- @raise error when key or value is not a string
313 | --
314 | -- @usage
315 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
316 | -- local result = search:append("a", "g"):tostring()
317 | function mt:append(key, value)
318 | assert(type(key) == "string", "invalid key")
319 | assert(type(value) == "string", "invalid value")
320 | lib.ada_search_params_append(self[1], key, #key, value, #value)
321 | return self
322 | end
323 |
324 |
325 | ---
326 | -- Remove Methods
327 | -- @section remove-methods
328 |
329 |
330 | ---
331 | -- Remove search parameter.
332 | --
333 | -- See:
334 | --
335 | -- @function remove
336 | -- @tparam string key search parameter name
337 | -- @treturn search self
338 | -- @raise error when key is not a string
339 | --
340 | -- @usage
341 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
342 | -- local result = search:remove("a"):tostring()
343 | function mt:remove(key)
344 | assert(type(key) == "string", "invalid key")
345 | lib.ada_search_params_remove(self[1], key, #key)
346 | return self
347 | end
348 |
349 |
350 | ---
351 | -- Remove search parameter's value.
352 | --
353 | -- See:
354 | --
355 | -- @function remove_value
356 | -- @tparam string key search parameter name
357 | -- @tparam string value search parameter's value
358 | -- @treturn search self
359 | -- @raise error when key or value is not a string
360 | --
361 | -- @usage
362 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
363 | -- local result = search:remove_value("a", "b"):tostring()
364 | function mt:remove_value(key, value)
365 | assert(type(key) == "string", "invalid key")
366 | assert(type(value) == "string", "invalid value")
367 | lib.ada_search_params_remove_value(self[1], key, #key, value, #value)
368 | return self
369 | end
370 |
371 |
372 | ---
373 | -- Iterate Methods
374 | -- @section iterate-methods
375 |
376 |
377 | ---
378 | -- Iterate over search parameters.
379 | --
380 | -- @function each
381 | -- @treturn function iterator function
382 | -- @treturn cdata state
383 | --
384 | -- @usage
385 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
386 | -- for param in search:each() do
387 | -- print(param.key, " = ", param.value)
388 | -- end
389 | function mt:each()
390 | local entries_iter = ffi_gc(lib.ada_search_params_get_entries(self[1]), lib.ada_free_search_params_entries_iter)
391 | return each_iter, entries_iter
392 | end
393 |
394 |
395 | ---
396 | -- Iterate over each key in search parameters.
397 | --
398 | -- @function each_key
399 | -- @treturn function iterator function
400 | -- @treturn cdata state
401 | --
402 | -- @usage
403 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
404 | -- for key in search:each_key() do
405 | -- print("key: ", key)
406 | -- end
407 | function mt:each_key()
408 | local keys_iter = ffi_gc(lib.ada_search_params_get_keys(self[1]), lib.ada_free_search_params_keys_iter)
409 | return each_key_iter, keys_iter
410 | end
411 |
412 |
413 | ---
414 | -- Iterate over each value in search parameters.
415 | --
416 | -- @function each_value
417 | -- @treturn function iterator function
418 | -- @treturn cdata state
419 | --
420 | -- @usage
421 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
422 | -- for value in search:each_value() do
423 | -- print("value: ", value)
424 | -- end
425 | function mt:each_value()
426 | local values_iter = ffi_gc(lib.ada_search_params_get_values(self[1]), lib.ada_free_search_params_values_iter)
427 | return each_value_iter, values_iter
428 | end
429 |
430 |
431 | ---
432 | -- Iterate over each key and value in search parameters.
433 | --
434 | -- @function pairs
435 | -- @treturn function iterator function
436 | -- @treturn cdata state
437 | --
438 | -- @usage
439 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
440 | -- for key, value in search:pairs() do
441 | -- print(key, " = ", value)
442 | -- end
443 | function mt:pairs()
444 | local entries_iter = ffi_gc(lib.ada_search_params_get_entries(self[1]), lib.ada_free_search_params_entries_iter)
445 | return pairs_iter, entries_iter
446 | end
447 |
448 |
449 | ---
450 | -- Iterate over each parameter in search parameters.
451 | --
452 | -- @function ipairs
453 | -- @treturn function iterator function
454 | -- @treturn cdata state
455 | --
456 | -- @usage
457 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
458 | -- for i, param in search:ipairs() do
459 | -- print(param.key, " = ", param.value)
460 | -- end
461 | function mt:ipairs()
462 | local entries_iter = ffi_gc(lib.ada_search_params_get_entries(self[1]), lib.ada_free_search_params_entries_iter)
463 | return ipairs_iter, entries_iter, 0
464 | end
465 |
466 |
467 | ---
468 | -- Other Methods
469 | -- @section other-methods
470 |
471 |
472 | ---
473 | -- Return search parameters as a string.
474 | --
475 | -- See:
476 | --
477 | -- @function tostring
478 | -- @treturn string string presentation of the search parameters
479 | --
480 | -- @usage
481 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
482 | -- local result = search:tostring()
483 | function mt:tostring()
484 | local r = ada_owned_string_to_lua(lib.ada_search_params_to_string(self[1]))
485 | return r
486 | end
487 |
488 |
489 | ---
490 | -- Sort search parameters.
491 | --
492 | -- See:
493 | --
494 | -- @function sort
495 | -- @treturn search self
496 | --
497 | -- @usage
498 | -- local search = require("resty.ada.search").parse("e=f&c=d&a=b")
499 | -- local result = search:sort():tostring()
500 | function mt:sort()
501 | lib.ada_search_params_sort(self[1])
502 | return self
503 | end
504 |
505 |
506 | ---
507 | -- Count search parameters.
508 | --
509 | -- @function size
510 | -- @treturn number search parameters count
511 | --
512 | -- @usage
513 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
514 | -- local result = search:size()
515 | function mt:size()
516 | local r = tonumber(lib.ada_search_params_size(self[1]), 10)
517 | return r
518 | end
519 |
520 |
521 | ---
522 | -- Meta Methods
523 | -- @section meta-methods
524 |
525 |
526 | ---
527 | -- Iterate over each key and value in search parameters.
528 | --
529 | -- @function __pairs
530 | -- @treturn function iterator function
531 | -- @treturn cdata state
532 | --
533 | -- @usage
534 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
535 | -- for key, value in pairs(search) do
536 | -- print(key, " = ", value)
537 | -- end
538 | mt.__pairs = mt.pairs
539 |
540 |
541 | ---
542 | -- Iterate over each parameter in search parameters.
543 | --
544 | -- @function __pairs
545 | -- @treturn function iterator function
546 | -- @treturn cdata state
547 | --
548 | -- @usage
549 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
550 | -- for i, param in ipairs(search) do
551 | -- print(i, ". ", param.key, " = ", param.value)
552 | -- end
553 | mt.__ipairs = mt.ipairs
554 |
555 |
556 | ---
557 | -- Return search parameters as a string.
558 | --
559 | -- See:
560 | --
561 | -- @function __tostring
562 | -- @treturn string string presentation of the search parameters
563 | --
564 | -- @usage
565 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
566 | -- local result = tostring(search)
567 | mt.__tostring = mt.tostring
568 |
569 |
570 | ---
571 | -- Count search parameters.
572 | --
573 | -- @function __len
574 | -- @treturn number search parameters count
575 | --
576 | -- @usage
577 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
578 | -- local result = #search
579 | mt.__len = mt.size
580 |
581 |
582 | ---
583 | -- Destructor Method
584 | -- @section destructor-method
585 |
586 |
587 | ---
588 | -- Explicitly destroys the Ada URL Search instance and frees the memory.
589 | --
590 | -- After calling this function, further calls will result runtime error.
591 | -- If this is not explicitly called, the memory is freed with garbage
592 | -- collector.
593 | --
594 | -- @function free
595 | --
596 | -- @usage
597 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
598 | -- search:free()
599 | function mt:free()
600 | ffi_gc(self[1], nil)
601 | lib.ada_free_search_params(self[1])
602 | self[1] = nil
603 | setmetatable(self, nil)
604 | end
605 |
606 |
607 | ---
608 | -- Provides URL search parameter parsing and manipulation functionality.
609 | --
610 | -- See:
611 | --
612 | -- @module resty.ada.search
613 |
614 |
615 | ---
616 | -- Constructors
617 | -- @section constructors
618 |
619 |
620 | ---
621 | -- Parses search and returns an instance of Ada URL Search.
622 | --
623 | -- See:
624 | --
625 | -- @function parse
626 | -- @tparam string search search to parse
627 | -- @treturn search Ada URL Search instance
628 | -- @raise error when search is not a string
629 | --
630 | -- @usage
631 | -- local search = require("resty.ada.search").parse("a=b&c=d&e=f")
632 | local function parse(search)
633 | assert(type(search) == "string", "invalid search")
634 | return setmetatable({
635 | ffi_gc(lib.ada_parse_search_params(search, #search), lib.ada_free_search_params)
636 | }, mt)
637 | end
638 |
639 |
640 | local S = parse("") -- just a dummy init value for this singleton
641 |
642 |
643 | ---
644 | -- Encode and Decode Functions
645 | -- @section encode-and-decode-function
646 |
647 |
648 | local function encode_value(v)
649 | if v == true or v == "" then
650 | return ""
651 | end
652 |
653 | if type(v) == "number" then
654 | v = number_to_string(v)
655 | end
656 |
657 | return v
658 | end
659 |
660 |
661 | ---
662 | -- Encodes search parameters and returns an query string.
663 | --
664 | -- * only `string` keys are allowed.
665 | -- * only `string`, `boolean` and `number` values are allowed or an array of them
666 | -- * `false` value is treated as missing (same as `nil`)
667 | -- * `true` returns `""` (empty string)
668 | -- * negative and positive `inf` and `NaN` are not allowed as numbers in values
669 | --
670 | -- When passing a table the keys will be sorted and with string the given order
671 | -- is preserved.
672 | --
673 | -- @function encode
674 | -- @tparam table|string params search parameters to encode (either a `table` or `string`)
675 | -- @treturn string encoded query string
676 | -- @raise error when search or key is not a table or string, or when the rules above are not followed
677 | --
678 | -- @usage
679 | -- local search = require("resty.ada.search")
680 | -- local result = search.encode({
681 | -- g = "h",
682 | -- a = { "f", "b", },
683 | -- c = "d",
684 | -- })
685 | local function encode(params)
686 | if type(params) == "table" then
687 | if not next(params) then
688 | return ""
689 | end
690 |
691 | S:reset("")
692 |
693 | for k, v in pairs(params) do
694 | if v ~= false then
695 | if type(v) == "table" then
696 | for i = 1, #v do
697 | if v[i] then
698 | S:append(k, encode_value(v[i]))
699 | end
700 | end
701 |
702 | else
703 | S:append(k, encode_value(v))
704 | end
705 | end
706 | end
707 |
708 | S:sort()
709 |
710 | else
711 | if params == "" or params == "?" then
712 | return ""
713 | end
714 |
715 | S:reset(params)
716 | end
717 |
718 | local r = S:tostring()
719 | return r
720 | end
721 |
722 |
723 | ---
724 | -- Decodes search parameters and returns a Lua table of them.
725 | --
726 | -- If same parameter appears multiple times, only the value of the
727 | -- first is returned.
728 | --
729 | -- Given the following query string:
730 | -- "a=b&c=d&e=f&a=g"
731 | --
732 | -- The following table is returned:
733 | -- {
734 | -- a = "b",
735 | -- c = "d",
736 | -- e = "f",
737 | -- }
738 | --
739 | -- @function decode
740 | -- @tparam string search search to parse
741 | -- @treturn table a table of all search parameters (a string:string map).
742 | -- @raise error when search or key is not a string
743 | --
744 | -- @usage
745 | -- local search = require("resty.ada.search")
746 | -- local result = search.decode("a=b&c=d&e=f&a=g")
747 | local function decode(search)
748 | local r = S:reset(search):decode()
749 | return r
750 | end
751 |
752 |
753 | ---
754 | -- Decodes all search parameters and returns a Lua table of them.
755 | --
756 | -- Given the following query string:
757 | -- "a=b&a=c&d=e""
758 | --
759 | -- The following table is returned:
760 | -- {
761 | -- a = { "b", "c" },
762 | -- d = { "e" },
763 | -- }
764 | --
765 | -- @function decode_all
766 | -- @tparam string search search to parse
767 | -- @treturn table a table of all search parameters (a string:table [array] map).
768 | -- @raise error when search or key is not a string
769 | --
770 | -- @usage
771 | -- local search = require("resty.ada.search")
772 | -- local result = search.decode_all("a=b&a=c&d=e")
773 | local function decode_all(search)
774 | local r = S:reset(search):decode_all()
775 | return r
776 | end
777 |
778 |
779 | ---
780 | -- Has Functions
781 | -- @section has-functions
782 |
783 |
784 | ---
785 | -- Checks whether the search has a key.
786 | --
787 | -- See:
788 | --
789 | -- @function has
790 | -- @tparam string search search to parse
791 | -- @tparam string key search parameter name to check
792 | -- @treturn boolean `true` if search has the key, otherwise `false`
793 | -- @raise error when search or key is not a string
794 | --
795 | -- @usage
796 | -- local search = require("resty.ada.search")
797 | -- local result = search.has("a=b&c=d&e=f", "a")
798 | local function has(search, key)
799 | local r = S:reset(search):has(key)
800 | return r
801 | end
802 |
803 |
804 | ---
805 | -- Checks whether the search has a key with a specific value.
806 | --
807 | -- See:
808 | --
809 | -- @function has_value
810 | -- @tparam string search search to parse
811 | -- @tparam string key search parameter name to check
812 | -- @tparam string value search parameter value to check
813 | -- @treturn boolean `true` if search has the key with the value, otherwise `false`
814 | -- @raise error when search, key or value is not a string
815 | --
816 | -- @usage
817 | -- local search = require("resty.ada.search")
818 | -- local result = search.has_value("a=b&c=d&e=f", "a", "b")
819 | local function has_value(search, key, value)
820 | local r = S:reset(search):has_value(key, value)
821 | return r
822 | end
823 |
824 |
825 | ---
826 | -- Get Functions
827 | -- @section get-functions
828 |
829 |
830 | ---
831 | -- Get search parameter's value.
832 | --
833 | -- See:
834 | --
835 | -- @function get
836 | -- @tparam string search search to parse
837 | -- @tparam string key search parameter name
838 | -- @treturn string|nil parameter value or `nil`
839 | -- @raise error when search or key is not a string
840 | --
841 | -- @usage
842 | -- local search = require("resty.ada.search")
843 | -- local result = search.get("a=b&c=d&e=f", "a")
844 | local function get(search, key)
845 | local r = S:reset(search):get(key)
846 | return r
847 | end
848 |
849 |
850 | ---
851 | -- Get all the search parameter's values.
852 | --
853 | -- See:
854 | --
855 | -- @function get_all
856 | -- @tparam string search search to parse
857 | -- @tparam string key search parameter name
858 | -- @treturn table array of all the values (or an empty array)
859 | -- @raise error when search or key is not a string
860 | --
861 | -- @usage
862 | -- local search = require("resty.ada.search")
863 | -- local result = search.get_all("a=b&c=d&e=f", "a")
864 | local function get_all(search, key)
865 | local r = S:reset(search):get_all(key)
866 | return r
867 | end
868 |
869 |
870 | ---
871 | -- Set Functions
872 | -- @section set-functions
873 |
874 |
875 | ---
876 | -- Set the search parameter's value.
877 | --
878 | -- See:
879 | --
880 | -- @function set
881 | -- @tparam string search search to parse
882 | -- @tparam string key search parameter name
883 | -- @tparam string value search parameter value
884 | -- @treturn string string presentation of the search parameters
885 | -- @raise error when search, key or value is not a string
886 | --
887 | -- @usage
888 | -- local search = require("resty.ada.search")
889 | -- local result = search.set("a=b&c=d&e=f", "a", "g")
890 | local function set(search, key, value)
891 | local r = S:reset(search):set(key, value):tostring()
892 | return r
893 | end
894 |
895 |
896 | ---
897 | -- Append value to the the search parameter.
898 | --
899 | -- See:
900 | --
901 | -- @function append
902 | -- @tparam string search search to parse
903 | -- @tparam string key search parameter name
904 | -- @tparam string value search parameter value
905 | -- @treturn string string presentation of the search parameters
906 | -- @raise error when search, key or value is not a string
907 | --
908 | -- @usage
909 | -- local search = require("resty.ada.search")
910 | -- local result = search.append("a=b&c=d&e=f", "a", "g")
911 | local function append(search, key, value)
912 | local r = S:reset(search):append(key, value):tostring()
913 | return r
914 | end
915 |
916 |
917 | ---
918 | -- Remove Functions
919 | -- @section remove-functions
920 |
921 |
922 | ---
923 | -- Remove search parameter.
924 | --
925 | -- See:
926 | --
927 | -- @function remove
928 | -- @tparam string search search to parse
929 | -- @tparam string key search parameter name
930 | -- @treturn string string presentation of the search parameters
931 | -- @raise error when search or key is not a string
932 | --
933 | -- @usage
934 | -- local search = require("resty.ada.search")
935 | -- local result = search.remove("a=b&c=d&e=f", "a")
936 | local function remove(search, key)
937 | local r = S:reset(search):remove(key):tostring()
938 | return r
939 | end
940 |
941 |
942 | ---
943 | -- Remove search parameter's value.
944 | --
945 | -- See:
946 | --
947 | -- @function remove_value
948 | -- @tparam string search search to parse
949 | -- @tparam string key search parameter name
950 | -- @tparam string value search parameter's value
951 | -- @treturn string string presentation of the search parameters
952 | -- @raise error when search, key or value is not a string
953 | --
954 | -- @usage
955 | -- local search = require("resty.ada.search")
956 | -- local result = search.remove_value("a=b&c=d&e=f", "a", "b")
957 | local function remove_value(search, key, value)
958 | local r = S:reset(search):remove_value(key, value):tostring()
959 | return r
960 | end
961 |
962 |
963 | ---
964 | -- Iterate Functions
965 | -- @section iterate-functions
966 |
967 |
968 | ---
969 | -- Iterate over search parameters.
970 | --
971 | -- @function each
972 | -- @tparam string search search to parse
973 | -- @treturn function iterator function
974 | -- @treturn cdata state
975 | -- @raise error when search is not a string
976 | --
977 | -- @usage
978 | -- local search = require("resty.ada.search")
979 | -- for param in search.each("a=b&c=d&e=f") do
980 | -- print(param.key, " = ", param.value)
981 | -- end
982 | local function each(search)
983 | local iterator, invariant_state = S:reset(search):each()
984 | return iterator, invariant_state
985 | end
986 |
987 |
988 | ---
989 | -- Iterate over each key in search parameters.
990 | --
991 | -- @function each_key
992 | -- @tparam string search search to parse
993 | -- @treturn function iterator function
994 | -- @treturn cdata state
995 | -- @raise error when search is not a string
996 | --
997 | -- @usage
998 | -- local search = require("resty.ada.search")
999 | -- for key in search.each_key("a=b&c=d&e=f") do
1000 | -- print("key: ", key)
1001 | -- end
1002 | local function each_key(search)
1003 | local iterator, invariant_state = S:reset(search):each_key()
1004 | return iterator, invariant_state
1005 | end
1006 |
1007 |
1008 | ---
1009 | -- Iterate over each value in search parameters.
1010 | --
1011 | -- @function each_value
1012 | -- @tparam string search search to parse
1013 | -- @treturn function iterator function
1014 | -- @treturn cdata state
1015 | -- @raise error when search is not a string
1016 | --
1017 | -- @usage
1018 | -- local search = require("resty.ada.search")
1019 | -- for value in search.each_value("a=b&c=d&e=f") do
1020 | -- print("value: ", value)
1021 | -- end
1022 | local function each_value(search)
1023 | local iterator, invariant_state = S:reset(search):each_value()
1024 | return iterator, invariant_state
1025 | end
1026 |
1027 |
1028 | ---
1029 | -- Iterate over each key and value in search parameters.
1030 | --
1031 | -- @function pairs
1032 | -- @tparam string search search to parse
1033 | -- @treturn function iterator function
1034 | -- @treturn cdata state
1035 | -- @raise error when search is not a string
1036 | --
1037 | -- @usage
1038 | -- local search = require("resty.ada.search")
1039 | -- for key, value in search.pairs("a=b&c=d&e=f") do
1040 | -- print(key, " = ", value)
1041 | -- end
1042 | local function search_pairs(search)
1043 | local iterator, invariant_state = S:reset(search):pairs()
1044 | return iterator, invariant_state
1045 | end
1046 |
1047 |
1048 | ---
1049 | -- Iterate over each parameter in search parameters.
1050 | --
1051 | -- @function ipairs
1052 | -- @tparam string search search to parse
1053 | -- @treturn function iterator function
1054 | -- @treturn cdata state
1055 | -- @raise error when search is not a string
1056 | --
1057 | -- @usage
1058 | -- for i, param in search.ipairs("a=b&c=d&e=f") do
1059 | -- print(i, ". ", param.key, " = ", param.value)
1060 | -- end
1061 | local function search_ipairs(search)
1062 | local iterator, invariant_state, initial_value = S:reset(search):ipairs()
1063 | return iterator, invariant_state, initial_value
1064 | end
1065 |
1066 |
1067 | ---
1068 | -- Other Functions
1069 | -- @section other-functions
1070 |
1071 |
1072 | ---
1073 | -- Sort search parameters.
1074 | --
1075 | -- See:
1076 | --
1077 | -- @function sort
1078 | -- @tparam string search search to parse
1079 | -- @treturn string string presentation of the search parameters
1080 | -- @raise error when search is not a string
1081 | --
1082 | -- @usage
1083 | -- local search = require("resty.ada.search")
1084 | -- local result = search.sort("e=f&c=d&a=b")
1085 | local function sort(search)
1086 | local r = S:reset(search):sort():tostring()
1087 | return r
1088 | end
1089 |
1090 |
1091 | ---
1092 | -- Count search parameters.
1093 | --
1094 | -- @function size
1095 | -- @tparam string search search to parse
1096 | -- @treturn number search parameters count
1097 | -- @raise error when search is not a string
1098 | --
1099 | -- @usage
1100 | -- local search = require("resty.ada.search")
1101 | -- local result = search.size("a=b&c=d&e=f")
1102 | local function size(search)
1103 | local r = S:reset(search):size()
1104 | return r
1105 | end
1106 |
1107 |
1108 | return {
1109 | parse = parse,
1110 | encode = encode,
1111 | decode = decode,
1112 | decode_all = decode_all,
1113 | has = has,
1114 | has_value = has_value,
1115 | get = get,
1116 | get_all = get_all,
1117 | set = set,
1118 | append = append,
1119 | remove = remove,
1120 | remove_value = remove_value,
1121 | each = each,
1122 | each_key = each_key,
1123 | each_value = each_value,
1124 | pairs = search_pairs,
1125 | ipairs = search_ipairs,
1126 | sort = sort,
1127 | size = size,
1128 | }
1129 |
--------------------------------------------------------------------------------
/lib/resty/ada/utils.lua:
--------------------------------------------------------------------------------
1 | ---
2 | -- Provides reusable utilities for `resty.ada`.
3 | --
4 | -- @local
5 | -- @module resty.ada.utils
6 |
7 |
8 | local lib = require("resty.ada.lib")
9 | local new_tab = require("table.new")
10 |
11 |
12 | local ffi_str = require("ffi").string
13 |
14 |
15 | local tonumber = tonumber
16 | local tostring = tostring
17 |
18 |
19 | local POS_INF = 1/0
20 | local NEG_INF = -1/0
21 |
22 |
23 | local function ada_string_to_lua(result)
24 | if result.data == nil then -- nullptr equals to nil but is not falsy
25 | return nil
26 | end
27 | if result.length == 0 then
28 | return ""
29 | end
30 | local r = ffi_str(result.data, result.length)
31 | return r
32 | end
33 |
34 |
35 | local function ada_strings_to_lua(result)
36 | local size = tonumber(lib.ada_strings_size(result), 10)
37 | if size == 0 then
38 | lib.ada_free_strings(result)
39 | return {}
40 | end
41 | local r = new_tab(size, 0)
42 | for i = 1, size do
43 | r[i] = ada_string_to_lua(lib.ada_strings_get(result, i - 1))
44 | end
45 | lib.ada_free_strings(result)
46 | return r
47 | end
48 |
49 |
50 | local function ada_owned_string_to_lua(ada_owned_string)
51 | local r = ada_string_to_lua(ada_owned_string)
52 | lib.ada_free_owned_string(ada_owned_string)
53 | return r
54 | end
55 |
56 |
57 | local function number_to_string(v)
58 | if v == POS_INF or v == NEG_INF or v ~= v then
59 | return nil
60 | end
61 | local r = tostring(v)
62 | return r
63 | end
64 |
65 |
66 | return {
67 | ada_string_to_lua = ada_string_to_lua,
68 | ada_strings_to_lua = ada_strings_to_lua,
69 | ada_owned_string_to_lua = ada_owned_string_to_lua,
70 | number_to_string = number_to_string,
71 | }
72 |
--------------------------------------------------------------------------------
/lua-resty-ada-1.1.0-1.rockspec:
--------------------------------------------------------------------------------
1 | package = "lua-resty-ada"
2 | version = "1.1.0-1"
3 | source = {
4 | url = "git+https://github.com/bungle/lua-resty-ada.git",
5 | tag = "v1.1.0",
6 | }
7 | description = {
8 | summary = "LuaJIT FFI bindings to Ada — WHATWG-compliant and fast URL parser",
9 | detailed = "lua-resty-ada implements a LuaJIT FFI bindings to Ada — WHATWG-compliant and fast URL parser.",
10 | homepage = "https://github.com/bungle/lua-resty-ada",
11 | maintainer = "Aapo Talvensaari ",
12 | license = "BSD",
13 | }
14 | dependencies = {
15 | "lua >= 5.1",
16 | }
17 | build = {
18 | type = "builtin",
19 | modules = {
20 | ["resty.ada"] = "lib/resty/ada.lua",
21 | ["resty.ada.lib"] = "lib/resty/ada/lib.lua",
22 | ["resty.ada.search"] = "lib/resty/ada/search.lua",
23 | ["resty.ada.utils"] = "lib/resty/ada/utils.lua",
24 | },
25 | }
26 |
--------------------------------------------------------------------------------
/spec/01-ada-url_spec.lua:
--------------------------------------------------------------------------------
1 | local ada = require("resty.ada")
2 |
3 |
4 | local assert = assert
5 | local describe = describe
6 | local it = it
7 | local tostring = tostring
8 |
9 |
10 | local null = ngx.null
11 | local same = assert.same
12 | local equal = assert.equal
13 | local is_nil = assert.is_nil
14 | local is_true = assert.is_true
15 | local is_false = assert.is_false
16 | local is_table = assert.is_table
17 | local errors = assert.errors
18 |
19 |
20 | local function is_err(msg, ok, err)
21 | is_nil(ok)
22 | equal(msg, err)
23 | return ok, err
24 | end
25 |
26 |
27 | describe("Ada", function()
28 | describe("URL", function()
29 | describe(".parse", function()
30 | it("rejects invalid url", function()
31 | is_err("invalid url", ada.parse(""))
32 | end)
33 | it("accepts valid url", function()
34 | is_table(ada.parse("http://www.google.com/"))
35 | end)
36 | end)
37 | describe(".parse_with_base", function()
38 | it("rejects invalid url", function()
39 | is_err("invalid url or base", ada.parse_with_base("", ""))
40 | end)
41 | it("accepts valid url", function()
42 | is_table(ada.parse_with_base("/path?search#hash", "http://www.google.com"))
43 | end)
44 | end)
45 | describe(".idna_to_ascii", function()
46 | it("translates unicode domain to ascii", function()
47 | equal("www.xn--7eleven-506c.com", ada.idna_to_ascii("www.7‑Eleven.com"))
48 | end)
49 | end)
50 | describe(".idna_to_unicode", function()
51 | it("translates ascii encoded domain to unicode", function()
52 | equal("www.7‐eleven.com", ada.idna_to_unicode("www.xn--7eleven-506c.com"))
53 | end)
54 | end)
55 | describe(".can_parse", function()
56 | it("rejects invalid url", function()
57 | is_false(ada.can_parse(".com:443/Home/Privacy/Montréal"))
58 | is_false(ada.can_parse(""))
59 | end)
60 | it("accepts valid url", function()
61 | is_true(ada.can_parse("https://www.7‑Eleven.com:443/Home/Privacy/Montréal"))
62 | end)
63 | end)
64 | describe(".can_parse_with_base", function()
65 | it("rejects invalid url", function()
66 | is_false(ada.can_parse_with_base("/path?search#hash", ".com:443/Home/Privacy/Montréal"))
67 | is_false(ada.can_parse_with_base("/path?search#hash", ""))
68 | is_false(ada.can_parse_with_base("", "http://"))
69 | end)
70 | it("accepts valid url", function()
71 | is_true(ada.can_parse_with_base("/path?search#hash", "http://www.google.com"))
72 | end)
73 | end)
74 | describe(".decode", function()
75 | it("works", function()
76 | same({
77 | scheme_type = 2,
78 | protocol = "https:",
79 | username = "user",
80 | password = "pass",
81 | origin = "https://example.com:1234",
82 | host_type = 0,
83 | host = "example.com:1234",
84 | hostname = "example.com",
85 | port = 1234,
86 | pathname = "/foo/bar",
87 | search = "?baz",
88 | hash = "#quux",
89 | }, ada.decode("https://user:pass@example.com:1234/foo/bar?baz#quux"))
90 | is_err("invalid url", ada.decode(""))
91 | end)
92 | end)
93 | describe(".has_credentials", function()
94 | it("works", function()
95 | is_false(ada.has_credentials("https://www.7‑Eleven.com:443/Home/Privacy/Montréal"))
96 | is_true(ada.has_credentials("https://foo:bar@www.7‑Eleven.com:443/Home/Privacy/Montréal"))
97 | is_err("invalid url", ada.has_credentials(""))
98 | end)
99 | end)
100 | describe(".has_non_empty_username", function()
101 | it("works", function()
102 | is_false(ada.has_non_empty_username("https://www.7‑Eleven.com:443/Home/Privacy/Montréal"))
103 | is_true(ada.has_non_empty_username("https://foo@www.7‑Eleven.com:443/Home/Privacy/Montréal"))
104 | is_err("invalid url", ada.has_non_empty_username(""))
105 | end)
106 | end)
107 | describe(".has_password", function()
108 | it("works", function()
109 | is_false(ada.has_password("https://www.7‑Eleven.com:443/Home/Privacy/Montréal"))
110 | is_false(ada.has_password("https://foo@www.7‑Eleven.com:443/Home/Privacy/Montréal"))
111 | is_false(ada.has_password("https://foo:@www.7‑Eleven.com:443/Home/Privacy/Montréal"))
112 | is_true(ada.has_password("https://foo:bar@www.7‑Eleven.com:443/Home/Privacy/Montréal"))
113 | is_err("invalid url", ada.has_password(""))
114 | end)
115 | end)
116 | describe(".has_non_empty_password", function()
117 | it("works", function()
118 | is_false(ada.has_non_empty_password("https://www.7‑Eleven.com:443/Home/Privacy/Montréal"))
119 | is_false(ada.has_non_empty_password("https://foo@www.7‑Eleven.com:443/Home/Privacy/Montréal"))
120 | is_false(ada.has_non_empty_password("https://foo:@www.7‑Eleven.com:443/Home/Privacy/Montréal"))
121 | is_true(ada.has_non_empty_password("https://foo:bar@www.7‑Eleven.com:443/Home/Privacy/Montréal"))
122 | is_err("invalid url", ada.has_non_empty_password(""))
123 | end)
124 | end)
125 | describe(".has_hostname", function()
126 | it("works", function()
127 | is_true(ada.has_hostname("https://www.7‑Eleven.com"))
128 | is_true(ada.has_hostname("file:///tmp/mock/path"))
129 | is_false(ada.has_hostname("non-spec:/.//p"))
130 | is_err("invalid url", ada.has_hostname(""))
131 | end)
132 | end)
133 | describe(".has_empty_hostname", function()
134 | it("works", function()
135 | is_false(ada.has_empty_hostname("https://www.7‑Eleven.com"))
136 | is_true(ada.has_empty_hostname("file:///tmp/mock/path"))
137 | is_false(ada.has_empty_hostname("non-spec:/.//p"))
138 | is_err("invalid url", ada.has_empty_hostname(""))
139 | end)
140 | end)
141 | describe(".has_port", function()
142 | it("works", function()
143 | is_false(ada.has_port("https://www.foo.com:443")) -- this is expected to return false on standard port
144 | is_false(ada.has_port("https://www.foo.com"))
145 | is_true(ada.has_port("https://www.foo.com:8888"))
146 | is_err("invalid url", ada.has_port(""))
147 | end)
148 | end)
149 | describe(".has_search", function()
150 | it("works", function()
151 | is_true(ada.has_search("https://www.foo.com?foo=bar"))
152 | is_false(ada.has_search("https://www.foo.com"))
153 | is_err("invalid url", ada.has_search(""))
154 | end)
155 | end)
156 | describe(".has_hash", function()
157 | it("works", function()
158 | is_true(ada.has_hash("https://www.foo.com?foo=bar#abc"))
159 | is_true(ada.has_hash("https://www.foo.com#abc"))
160 | is_false(ada.has_hash("https://www.foo.com"))
161 | is_err("invalid url", ada.has_hash(""))
162 | end)
163 | end)
164 | describe(".get_components", function()
165 | it("works", function()
166 | local c = ada.get_components("https://www.7‑Eleven.com:443/Home/Privacy/Montréal")
167 | equal(32, c.host_end)
168 | equal(9, c.host_start)
169 | equal(33, c.pathname_start)
170 | equal(7, c.protocol_end)
171 | equal(9, c.username_end)
172 | is_err("invalid url", ada.get_components(""))
173 | end)
174 | end)
175 | describe(".get_href", function()
176 | it("works", function()
177 | local u, err = ada.get_href("https://user:pass@host:1234/path?search#hash")
178 | equal("https://user:pass@host:1234/path?search#hash", u)
179 | is_nil(err)
180 | is_err("invalid url", ada.get_href(""))
181 | end)
182 | end)
183 | describe(".get_protocol", function()
184 | it("works", function()
185 | equal("https:", ada.get_protocol("https://www.foo.com"))
186 | is_nil(ada.get_protocol("www.foo.com?foo=bar"))
187 | is_err("invalid url", ada.get_protocol(""))
188 | end)
189 | end)
190 | describe(".get_scheme_type", function()
191 | it("works", function()
192 | equal(2, ada.get_scheme_type("https://www.foo.com"))
193 | equal(1, ada.get_scheme_type("grpc://www.foo.com"))
194 | equal(0, ada.get_scheme_type("http://www.foo.com"))
195 | is_nil(ada.get_scheme_type("www.foo.com"))
196 | is_err("invalid url", ada.get_scheme_type(""))
197 | end)
198 | end)
199 | describe(".get_origin", function()
200 | it("works", function()
201 | equal("https://www.foo.com", ada.get_origin("https://www.foo.com/foo/bar"))
202 | is_nil(ada.get_origin("www.foo.com/foo/bar"))
203 | is_err("invalid url", ada.get_origin(""))
204 | end)
205 | end)
206 | describe(".get_username", function()
207 | it("works", function()
208 | equal("foo", ada.get_username("https://foo:bar@www.foo.com?foo=bar"))
209 | equal("", ada.get_username("https://:bar@www.foo.com?foo=bar"))
210 | equal("", ada.get_username("https://:@www.foo.com?foo=bar"))
211 | equal("", ada.get_username("https://www.foo.com?foo=bar"))
212 | is_err("invalid url", ada.get_username(""))
213 | end)
214 | end)
215 | describe(".get_password", function()
216 | it("works", function()
217 | equal("bar", ada.get_password("https://foo:bar@www.foo.com?foo=bar"))
218 | equal("bar", ada.get_password("https://:bar@www.foo.com?foo=bar"))
219 | equal("", ada.get_password("https://:@www.foo.com?foo=bar"))
220 | equal("", ada.get_password("https://www.foo.com?foo=bar"))
221 | is_err("invalid url", ada.get_password(""))
222 | end)
223 | end)
224 | describe(".get_host", function()
225 | it("works", function()
226 | equal("www.foo.com", ada.get_host("https://foo:bar@www.foo.com?foo=bar"))
227 | equal("127.0.0.1", ada.get_host("https://127.0.0.1/foo/bar"))
228 | is_err("invalid url", ada.get_host(""))
229 | end)
230 | end)
231 | describe(".get_hostname", function()
232 | it("works", function()
233 | equal("www.foo.com", ada.get_hostname("https://foo:bar@www.foo.com?foo=bar"))
234 | equal("127.0.0.1", ada.get_hostname("https://127.0.0.1/foo/bar"))
235 | is_err("invalid url", ada.get_hostname(""))
236 | end)
237 | end)
238 | describe(".get_host_type", function()
239 | it("works", function()
240 | equal(0, ada.get_host_type("https://foo:bar@www.foo.com?foo=bar"))
241 | equal(1, ada.get_host_type("https://127.0.0.1/foo/bar"))
242 | is_err("invalid url", ada.get_host_type(""))
243 | end)
244 | end)
245 | describe(".get_port", function()
246 | it("works", function()
247 | equal("", ada.get_port("https://www.foo.com:443"))
248 | equal("", ada.get_port("https://www.foo.com"))
249 | equal(8888, ada.get_port("https://www.foo.com:8888"))
250 | is_err("invalid url", ada.get_port(""))
251 | end)
252 | end)
253 | describe(".get_pathname", function()
254 | it("works", function()
255 | equal("/", ada.get_pathname("https://foo:bar@www.foo.com?foo=bar"))
256 | equal("/foo/bar", ada.get_pathname("https://127.0.0.1/foo/bar"))
257 | is_err("invalid url", ada.get_pathname(""))
258 | end)
259 | end)
260 | describe(".get_search", function()
261 | it("works", function()
262 | equal("?foo=bar", ada.get_search("https://www.foo.com?foo=bar"))
263 | equal("?foo=bar&a=b&b=c", ada.get_search("https://www.foo.com?foo=bar&a=b&b=c"))
264 | equal("", ada.get_search("https://www.foo.com/"))
265 | equal("", ada.get_search("https://www.foo.com?"))
266 | is_err("invalid url", ada.get_search(""))
267 | end)
268 | end)
269 | describe(".get_hash", function()
270 | it("works", function()
271 | equal("#foo-bar", ada.get_hash("https://www.foo.com?foo=bar#foo-bar"))
272 | equal("", ada.get_hash("https://www.foo.com#"))
273 | equal("", ada.get_hash("https://www.foo.com"))
274 | is_err("invalid url", ada.get_hash(""))
275 | end)
276 | end)
277 | describe(".set_protocol", function()
278 | it("works", function()
279 | equal("http://www.xn--7eleven-506c.com/Home/Privacy/Montr%C3%A9al", ada.set_protocol("https://www.7‑Eleven.com:443/Home/Privacy/Montréal", "http"))
280 | equal("https:", ada.get_protocol("https://www.7‑Eleven.com:443/Home/Privacy/Montréal"))
281 | equal("http:", ada.get_protocol("http://www.7‑Eleven.com:443/Home/Privacy/Montréal"))
282 | local u = ada.parse("https://www.7‑Eleven.com:443/Home/Privacy/Montréal")
283 | is_table(u:set_protocol("http"))
284 | equal("http:", u:get_protocol())
285 | is_table(u:set_protocol("https"))
286 | equal("https:", u:get_protocol())
287 | is_err("invalid url", ada.set_protocol("", "http"))
288 | is_err("unable to set protocol", ada.set_protocol("http://www.7‑Eleven.com:443/Home/Privacy/Montréal", "1234"))
289 | end)
290 | end)
291 | describe(".set_username", function()
292 | it("works", function()
293 | equal("https://user@www.xn--7eleven-506c.com/Home/Privacy/Montr%C3%A9al", ada.set_username("https://www.7‑Eleven.com:443/Home/Privacy/Montréal", "user"))
294 | local u = ada.parse("https://www.7‑Eleven.com:443/Home/Privacy/Montréal")
295 | is_table(u:set_username("user"))
296 | equal("user", u:get_username())
297 | is_err("invalid url", ada.set_username("", "user"))
298 | is_err("unable to set username", ada.set_username("file:///doge", "user"))
299 | end)
300 | end)
301 | describe(".set_password", function()
302 | it("works", function()
303 | equal("https://:pass@www.xn--7eleven-506c.com/Home/Privacy/Montr%C3%A9al", ada.set_password("https://www.7‑Eleven.com:443/Home/Privacy/Montréal", "pass"))
304 | local u = ada.parse("https://www.7‑Eleven.com:443/Home/Privacy/Montréal")
305 | is_table(u:set_password("pass"))
306 | equal("pass", u:get_password())
307 | is_err("invalid url", ada.set_password("", "pass"))
308 | is_err("unable to set password", ada.set_password("file:///doge", "pass"))
309 | end)
310 | end)
311 | describe(".set_host", function()
312 | it("works", function()
313 | equal("https://example.com/Home/Privacy/Montr%C3%A9al", ada.set_host("https://www.7‑Eleven.com:443/Home/Privacy/Montréal", "example.com"))
314 | local u = ada.parse("https://www.7‑Eleven.com:443/Home/Privacy/Montréal")
315 | is_table(u:set_host("example.com"))
316 | equal("example.com", u:get_host())
317 | is_err("invalid url", ada.set_host("", "example.com"))
318 | is_err("unable to set host", ada.set_host("foo://example.com", "exa[mple.org"))
319 | end)
320 | end)
321 | describe(".set_hostname", function()
322 | it("works", function()
323 | equal("https://example.com/Home/Privacy/Montr%C3%A9al", ada.set_hostname("https://www.7‑Eleven.com:443/Home/Privacy/Montréal", "example.com"))
324 | local u = ada.parse("https://www.7‑Eleven.com:443/Home/Privacy/Montréal")
325 | is_table(u:set_hostname("example.com"))
326 | equal("example.com", u:get_host())
327 | is_err("invalid url", ada.set_hostname("", "example.com"))
328 | is_err("unable to set hostname", ada.set_hostname("foo://example.com", "exa[mple.org"))
329 | end)
330 | end)
331 | describe(".set_port", function()
332 | it("works", function()
333 | errors(function() ada.set_port("https://host/", 0/0) end, "invalid port")
334 | errors(function() ada.set_port("https://host/", 1/0) end, "invalid port")
335 | errors(function() ada.set_port("https://host/", -1/0) end, "invalid port")
336 | equal("https://www.xn--7eleven-506c.com:1234/Home/Privacy/Montr%C3%A9al", ada.set_port("https://www.7‑Eleven.com:443/Home/Privacy/Montréal", 1234))
337 | local u = ada.parse("https://www.7‑Eleven.com:443/Home/Privacy/Montréal")
338 | is_table(u:set_port(1234))
339 | equal(1234, u:get_port())
340 | is_err("invalid url", ada.set_port("", 1234))
341 | is_err("unable to set port", ada.set_port("https://www.7‑Eleven.com:443/Home/Privacy/Montréal", ""))
342 | end)
343 | end)
344 | describe(".set_pathname", function()
345 | it("works", function()
346 | equal("https://www.xn--7eleven-506c.com/Doge", ada.set_pathname("https://www.7‑Eleven.com:443/Home/Privacy/Montréal", "/Doge"))
347 | local u = ada.parse("https://www.7‑Eleven.com:443/Home/Privacy")
348 | equal("/Home/Privacy", u:get_pathname())
349 | is_table(u:set_pathname("/foo/bar"))
350 | equal("/foo/bar", u:get_pathname())
351 | is_err("invalid url", ada.set_pathname("", "/Doge"))
352 | is_err("unable to set pathname", ada.set_pathname("mailto:user@example.org", "/doge"))
353 | end)
354 | end)
355 | describe(".set_search", function()
356 | it("works", function()
357 | equal("https://www.xn--7eleven-506c.com/Home/Privacy/Montr%C3%A9al?foo=bar", ada.set_search("https://www.7‑Eleven.com:443/Home/Privacy/Montréal", "foo=bar"))
358 | local u = ada.parse("https://www.7‑Eleven.com:443/Home/Privacy?foo=bar")
359 | equal("?foo=bar", u:get_search())
360 | is_table(u:set_search("bar=baz"))
361 | equal("?bar=baz", u:get_search())
362 | is_err("invalid url", ada.set_search("", "foo"))
363 | end)
364 | end)
365 | describe(".set_hash", function()
366 | it("works", function()
367 | equal("https://www.xn--7eleven-506c.com/Home/Privacy?foo=bar#bar", ada.set_hash("https://www.7‑Eleven.com:443/Home/Privacy?foo=bar#foo", "#bar"))
368 | local u = ada.parse("https://www.7‑Eleven.com:443/Home/Privacy?foo=bar#foo")
369 | equal("#foo", u:get_hash())
370 | is_table(u:set_hash("#bar"))
371 | equal("#bar", u:get_hash())
372 | is_err("invalid url", ada.set_hash("", "foo"))
373 | end)
374 | end)
375 | describe(".clear_port", function()
376 | it("works", function()
377 | equal("https://www.google.com/", ada.clear_port("https://www.google.com:8888/"))
378 | local u = ada.parse("https://www.google.com:8888/")
379 | equal("https://www.google.com/", tostring(u:clear_port()))
380 | is_err("invalid url", ada.clear_port(""))
381 | end)
382 | end)
383 | describe(".clear_search", function()
384 | it("works", function()
385 | equal("https://www.google.com:8888/", ada.clear_search("https://www.google.com:8888?foo=bar"))
386 | local u = ada.parse("https://www.google.com:8888?foo=bar")
387 | equal("https://www.google.com:8888/", tostring(u:clear_search()))
388 | is_err("invalid url", ada.clear_search(""))
389 | end)
390 | end)
391 | describe(".clear_hash", function()
392 | it("works", function()
393 | equal("https://www.google.com:8888/?foo=bar", ada.clear_hash("https://www.google.com:8888?foo=bar#bar"))
394 | local u = ada.parse("https://www.google.com:8888?foo=bar#bar")
395 | equal("https://www.google.com:8888/?foo=bar", tostring(u:clear_hash()))
396 | is_err("invalid url", ada.clear_hash(""))
397 | end)
398 | end)
399 | describe(".search_parse", function()
400 | it("works", function()
401 | local s = ada.search_parse("https://www.google.com?doge=z&jack=2")
402 | is_table(s)
403 | equal("doge=z&jack=2", s:tostring())
404 |
405 | local url = ada.parse("https://www.google.com?doge=z&jack=2")
406 | s = url:search_parse()
407 | is_table(s)
408 | equal("doge=z&jack=2", s:tostring())
409 |
410 | is_err("invalid url", ada.search_parse(""))
411 | end)
412 | end)
413 | describe(".search_encode", function()
414 | it("works", function()
415 | equal("doge=z&jack=2", ada.search_encode("https://www.google.com?doge=z&jack=2"))
416 | equal("", ada.search_encode("https://www.google.com"))
417 | equal("", ada.search_encode("https://www.google.com?"))
418 | equal("c=&e=&e=v&f=v", ada.search.encode({ a = false, b = nil, c = "", d = {}, e = { false, "", "v" }, f = "v" }))
419 | errors(function() ada.search.encode({ k = null }) end, "invalid value")
420 | errors(function() ada.search.encode({ k = 0/0 }) end, "invalid value")
421 | errors(function() ada.search.encode({ k = 1/0 }) end, "invalid value")
422 | errors(function() ada.search.encode({ k = -1/0 }) end, "invalid value")
423 | equal("", ada.search.encode({}))
424 | is_err("invalid url", ada.search_encode(""))
425 | end)
426 | end)
427 | describe(".search_decode", function()
428 | it("works", function()
429 | same({ doge = "z", jack = "2" }, ada.search_decode("https://www.google.com?doge=z&jack=2&doge=x"))
430 | same({}, ada.search_decode("https://www.google.com"))
431 | same({ doge = "z", jack = "2" }, ada.parse("https://www.google.com?doge=z&jack=2&doge=x"):search_decode())
432 | same({}, ada.parse("https://www.google.com"):search_decode())
433 | is_err("invalid url", ada.search_decode(""))
434 | end)
435 | end)
436 | describe(".search_decode_all", function()
437 | it("works", function()
438 | same({ doge = { "z", "x" }, jack = { "2" } }, ada.search_decode_all("https://www.google.com?doge=z&jack=2&doge=x"))
439 | same({}, ada.search_decode_all("https://www.google.com"))
440 | same({ doge = { "z", "x" }, jack = { "2" } }, ada.parse("https://www.google.com?doge=z&jack=2&doge=x"):search_decode_all())
441 | same({}, ada.parse("https://www.google.com"):search_decode_all())
442 | is_err("invalid url", ada.search_decode_all(""))
443 | end)
444 | end)
445 | describe(".search_has", function()
446 | it("works", function()
447 | is_true(ada.search_has("https://www.google.com?doge=z&jack=2", "jack"))
448 | local u = ada.parse("https://www.google.com?doge=z&jack=2")
449 | is_true(u:search_has("jack"))
450 | is_err("invalid url", ada.search_has("", "jack"))
451 | end)
452 | end)
453 | describe(".search_has_value", function()
454 | it("works", function()
455 | is_false(ada.search_has_value("https://www.google.com?doge=z&jack=2", "jack", "4"))
456 | is_true(ada.search_has_value("https://www.google.com?doge=z&jack=2", "jack", "2"))
457 | local u = ada.parse("https://www.google.com?doge=z&jack=2")
458 | is_false(u:search_has_value("jack", "4"))
459 | is_true(u:search_has_value("jack", "2"))
460 | is_err("invalid url", ada.search_has_value("", "jack", "2"))
461 | end)
462 | end)
463 | describe(".search_get", function()
464 | it("works", function()
465 | equal("2", ada.search_get("https://www.google.com?doge=z&jack=2", "jack"))
466 | is_nil(ada.search_get("https://www.google.com?doge=z&jack=2", "foo"))
467 | local u = ada.parse("https://www.google.com?doge=z&jack=2")
468 | equal("2", u:search_get("jack"))
469 | is_nil(u:search_get("foo"))
470 | is_err("invalid url", ada.search_get("", "jack"))
471 | end)
472 | end)
473 | describe(".search_get_all", function()
474 | it("works", function()
475 | same({}, ada.search_get_all("https://www.google.com?doge=z&jack=2&doge=s", "missing"))
476 | same({"z", "s"}, ada.search_get_all("https://www.google.com?doge=z&jack=2&doge=s", "doge"))
477 | local u = ada.parse("https://www.google.com?doge=z&jack=2&doge=s")
478 | same({"z", "s"}, u:search_get_all("doge"))
479 | is_err("invalid url", ada.search_get_all("", "doge"))
480 | end)
481 | end)
482 | describe(".search_set", function()
483 | it("works", function()
484 | equal("https://www.google.com/?doge=z&jack=4", ada.search_set("https://www.google.com?doge=z&jack=2", "jack", "4"))
485 | local u = ada.parse("https://www.google.com?doge=z&jack=2")
486 | equal("https://www.google.com/?doge=z&jack=4", tostring(u:search_set("jack", "4")))
487 | is_err("invalid url", ada.search_set("", "jack", "4"))
488 | end)
489 | end)
490 | describe(".search_append", function()
491 | it("works", function()
492 | equal("https://www.google.com/?doge=z&jack=2&doge=z", ada.search_append("https://www.google.com?doge=z&jack=2", "doge", "z"))
493 | local u = ada.parse("https://www.google.com?doge=z&jack=2")
494 | equal("https://www.google.com/?doge=z&jack=2&doge=z", tostring(u:search_append("doge", "z")))
495 | is_err("invalid url", ada.search_append("", "jack", "4"))
496 | end)
497 | end)
498 | describe(".search_remove", function()
499 | it("works", function()
500 | equal("https://www.google.com/?jack=2&bug=&aa=3", ada.search_remove("https://www.google.com?doge=z&jack=2&doge=s&bug&aa=3", "doge"))
501 | local u = ada.parse("https://www.google.com?doge=z&jack=2&doge=s&bug&aa=3")
502 | equal("https://www.google.com/?jack=2&bug=&aa=3", tostring(u:search_remove("doge")))
503 | is_err("invalid url", ada.search_remove("", "doge"))
504 | end)
505 | end)
506 | describe(".search_remove_value", function()
507 | it("works", function()
508 | equal("https://www.google.com/?doge=z&jack=2&doge=s&bug=&aa=3", ada.search_remove_value("https://www.google.com?doge=z&jack=2&doge=s&bug&aa=3", "doge", "t"))
509 | equal("https://www.google.com/?jack=2&doge=s&bug=&aa=3", ada.search_remove_value("https://www.google.com?doge=z&jack=2&doge=s&bug&aa=3", "doge", "z"))
510 | local u = ada.parse("https://www.google.com?doge=z&jack=2&doge=s&bug&aa=3")
511 | equal("https://www.google.com/?doge=z&jack=2&doge=s&bug=&aa=3", tostring(u:search_remove_value("doge", "t")))
512 | u = ada.parse("https://www.google.com?doge=z&jack=2&doge=s&bug&aa=3")
513 | equal("https://www.google.com/?jack=2&doge=s&bug=&aa=3", tostring(u:search_remove_value("doge", "z")))
514 | is_err("invalid url", ada.search_remove_value("", "doge", "z"))
515 | end)
516 | end)
517 | describe(".search_each", function()
518 | it("works", function()
519 | local args = {
520 | doge = true,
521 | jack = true,
522 | bug = true,
523 | aa = true,
524 | bb = true,
525 | }
526 |
527 | for t in ada.search_each("https://www.google.com?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10") do
528 | is_true(args[t.key])
529 | end
530 |
531 | for t in ada.search.each("?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10") do
532 | is_true(args[t.key])
533 | end
534 |
535 | local url = ada.parse("https://www.google.com?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10")
536 | for t in url:search_each() do
537 | is_true(args[t.key])
538 | end
539 |
540 | is_err("invalid url", ada.search_each(""))
541 | end)
542 | end)
543 | describe(".search_each_key", function()
544 | it("works", function()
545 | local args = {
546 | doge = true,
547 | jack = true,
548 | bug = true,
549 | aa = true,
550 | bb = true,
551 | }
552 |
553 | for k in ada.search_each_key("https://www.google.com?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10") do
554 | is_true(args[k])
555 | end
556 |
557 | for k in ada.search.each_key("?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10") do
558 | is_true(args[k])
559 | end
560 |
561 | local url = ada.parse("https://www.google.com?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10")
562 | for k in url:search_each_key() do
563 | is_true(args[k])
564 | end
565 |
566 | is_err("invalid url", ada.search_each_key(""))
567 | end)
568 | end)
569 | describe(".search_each_value", function()
570 | it("works", function()
571 | local args = {
572 | z = true,
573 | ["2"] = true,
574 | s = true,
575 | [""] = true,
576 | ["3"] = true,
577 | ["4"] = true,
578 | ["10"] = true,
579 | }
580 |
581 | for v in ada.search_each_value("https://www.google.com?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10") do
582 | is_true(args[v])
583 | end
584 |
585 | for v in ada.search.each_value("?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10") do
586 | is_true(args[v])
587 | end
588 |
589 | local url = ada.parse("https://www.google.com?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10")
590 | for v in url:search_each_value() do
591 | is_true(args[v])
592 | end
593 |
594 | is_err("invalid url", ada.search_each_value(""))
595 | end)
596 | end)
597 | describe(".search_pairs", function()
598 | it("works", function()
599 | local args = {
600 | doge = true,
601 | jack = true,
602 | bug = true,
603 | aa = true,
604 | bb = true,
605 | }
606 |
607 | for k in ada.search_pairs("https://www.google.com?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10") do
608 | is_true(args[k])
609 | end
610 |
611 | for k in ada.search.pairs("?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10") do
612 | is_true(args[k])
613 | end
614 |
615 | local url = ada.parse("https://www.google.com?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10")
616 | for k in url:search_pairs() do
617 | is_true(args[k])
618 | end
619 |
620 | is_err("invalid url", ada.search_pairs(""))
621 | end)
622 | end)
623 | describe(".search_ipairs", function()
624 | it("works", function()
625 | local args = {
626 | doge = true,
627 | jack = true,
628 | bug = true,
629 | aa = true,
630 | bb = true,
631 | }
632 |
633 | for _, v in ada.search_ipairs("https://www.google.com?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10") do
634 | is_true(args[v.key])
635 | end
636 |
637 | for _, v in ada.search.ipairs("?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10") do
638 | is_true(args[v.key])
639 | end
640 |
641 | local url = ada.parse("https://www.google.com?doge=z&jack=2&doge=s&bug=&aa=3&bb=4&bb=10")
642 | for _, v in url:search_ipairs() do
643 | is_true(args[v.key])
644 | end
645 |
646 | is_err("invalid url", ada.search_ipairs(""))
647 | end)
648 | end)
649 | describe(".search_sort", function()
650 | it("works", function()
651 | equal("https://www.google.com/?doge=z&doge=s&jack=2", ada.search_sort("https://www.google.com?doge=z&jack=2&doge=s"))
652 | local u = ada.parse("https://www.google.com?doge=z&jack=2&doge=s")
653 | equal("https://www.google.com/?doge=z&doge=s&jack=2", tostring(u:search_sort()))
654 | is_err("invalid url", ada.search_sort(""))
655 | end)
656 | end)
657 | describe(".search_size", function()
658 | it("works", function()
659 | equal(3, ada.search_size("https://www.google.com?doge=z&jack=2&doge=s"))
660 | local u = ada.parse("https://www.google.com?doge=z&jack=2&doge=s")
661 | equal(3, u:search_size())
662 | is_err("invalid url", ada.search_size(""))
663 | end)
664 | end)
665 | describe(":set_href", function()
666 | it("works", function()
667 | local u = ada.parse("https://localhost")
668 | is_table(u:set_href("https://www.google.com?doge=z&jack=2&doge=s"))
669 | equal("www.google.com", u:get_hostname())
670 | is_err("unable to set href", u:set_href(""))
671 | equal("www.google.com", u:get_hostname())
672 | end)
673 | end)
674 | describe(":free", function()
675 | it("works", function()
676 | local u = ada.parse("https://www.google.com?doge=z&jack=2&doge=s")
677 | equal("www.google.com", u:get_hostname())
678 | u:free()
679 | errors(function() u:get_hostname() end, "attempt to call method 'get_hostname' (a nil value)")
680 | end)
681 | end)
682 | describe("__len metamethod", function()
683 | it("works", function()
684 | local u = ada.parse("https://www.google.com/?doge=z&jack=2&doge=s")
685 | equal(44, #u)
686 | end)
687 | end)
688 | end)
689 | describe("Search", function()
690 | describe(":free", function()
691 | it("works", function()
692 | local s = ada.search.parse("doge=z&jack=2&doge=s")
693 | equal("2", s:get("jack"))
694 | s:free()
695 | errors(function() s:get("jack") end, "attempt to call method 'get' (a nil value)")
696 | end)
697 | end)
698 | end)
699 | end)
700 |
--------------------------------------------------------------------------------