/src/ada-url/fuzz/url_pattern.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include <fuzzer/FuzzedDataProvider.h> |
2 | | |
3 | | #include <memory> |
4 | | #include <string> |
5 | | |
6 | | #include "ada.cpp" |
7 | | #include "ada.h" |
8 | | |
9 | | using regex_provider = ada::url_pattern_regex::std_regex_provider; |
10 | | |
11 | 780 | std::string bytesToAlphanumeric(const std::string& source) { |
12 | 780 | static const char alphanumeric[] = |
13 | 780 | "abcdefghijklmnopqrstuvwxyz" |
14 | 780 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
15 | 780 | "0123456789"; |
16 | | |
17 | 780 | std::string result; |
18 | 780 | result.reserve(source.size()); |
19 | | |
20 | 5.00k | for (char byte : source) { |
21 | 5.00k | int index = static_cast<unsigned char>(byte) % (sizeof(alphanumeric) - 1); |
22 | 5.00k | result.push_back(alphanumeric[index]); |
23 | 5.00k | } |
24 | | |
25 | 780 | return result; |
26 | 780 | } |
27 | | |
28 | 585 | void exercise_result(auto result) { |
29 | 585 | (void)result.get_protocol(); |
30 | 585 | (void)result.get_username(); |
31 | 585 | (void)result.get_password(); |
32 | 585 | (void)result.get_hostname(); |
33 | 585 | (void)result.get_port(); |
34 | 585 | (void)result.get_pathname(); |
35 | 585 | (void)result.get_search(); |
36 | 585 | (void)result.get_hash(); |
37 | 585 | (void)result.ignore_case(); |
38 | 585 | (void)result.has_regexp_groups(); |
39 | 585 | } |
40 | | |
41 | 195 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
42 | 195 | FuzzedDataProvider fdp(data, size); |
43 | | // We do not want to trigger arbitrary regex matching. |
44 | 195 | std::string source_1 = |
45 | 195 | "/" + bytesToAlphanumeric(fdp.ConsumeRandomLengthString(50)) + "/" + |
46 | 195 | bytesToAlphanumeric(fdp.ConsumeRandomLengthString(50)); |
47 | 195 | std::string base_source_1 = |
48 | 195 | "/" + bytesToAlphanumeric(fdp.ConsumeRandomLengthString(50)) + "/" + |
49 | 195 | bytesToAlphanumeric(fdp.ConsumeRandomLengthString(50)); |
50 | | |
51 | 195 | std::string source_2 = "https://ada-url.com/*"; |
52 | 195 | std::string base_source_2 = "https://ada-url.com"; |
53 | | |
54 | 195 | std::array<std::pair<std::string, std::string>, 2> sources = {{ |
55 | 195 | {source_1, base_source_1}, |
56 | 195 | {source_2, base_source_2}, |
57 | 195 | }}; |
58 | | |
59 | 390 | for (const auto& [source, base_source] : sources) { |
60 | | // Without base or options |
61 | 390 | auto result = |
62 | 390 | ada::parse_url_pattern<regex_provider>(source, nullptr, nullptr); |
63 | 390 | if (result) exercise_result(*result); |
64 | | |
65 | | // Testing with base_url |
66 | 390 | std::string_view base_source_view(base_source.data(), base_source.length()); |
67 | 390 | auto result_with_base = ada::parse_url_pattern<regex_provider>( |
68 | 390 | source, &base_source_view, nullptr); |
69 | 390 | if (result_with_base) exercise_result(*result_with_base); |
70 | | |
71 | | // Testing with base_url and options |
72 | 390 | ada::url_pattern_options options{.ignore_case = fdp.ConsumeBool()}; |
73 | 390 | auto result_with_base_and_options = ada::parse_url_pattern<regex_provider>( |
74 | 390 | source, &base_source_view, &options); |
75 | 390 | if (result_with_base_and_options) |
76 | 195 | exercise_result(*result_with_base_and_options); |
77 | | |
78 | | // Testing with url_pattern_init and base url. |
79 | 390 | ada::url_pattern_init init{.protocol = source, |
80 | 390 | .username = source, |
81 | 390 | .password = source, |
82 | 390 | .hostname = source, |
83 | 390 | .port = source, |
84 | 390 | .pathname = source, |
85 | 390 | .search = source, |
86 | 390 | .hash = source}; |
87 | 390 | auto result_with_init = ada::parse_url_pattern<regex_provider>( |
88 | 390 | init, &base_source_view, nullptr); |
89 | 390 | if (result_with_init) exercise_result(*result_with_init); |
90 | 390 | } |
91 | | |
92 | 195 | return 0; |
93 | 195 | } |