summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/t_scan_urlencoded_query.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/tests/t_scan_urlencoded_query.c b/tests/t_scan_urlencoded_query.c
index 4c1ef23..6fa34e0 100644
--- a/tests/t_scan_urlencoded_query.c
+++ b/tests/t_scan_urlencoded_query.c
@@ -254,6 +254,106 @@ static void case_fixed_int_bounded(void) {
254 CHECK_INT(value, 123); 254 CHECK_INT(value, 123);
255} 255}
256 256
257
258/* The encoding direction. Which bytes survive unescaped is fixed by what
259 existing parsers of the urlencoded full scrape expect, so these cases pin
260 the set rather than describe a preference. */
261
262static void case_fmt_passes_safe_bytes(void) {
263 const uint8_t src[] = "aZ09$-./=_~";
264 char dest[64];
265 size_t n;
266
267 test_case("alphanumerics and the safe punctuation pass through");
268 n = fmt_urlencoded(dest, src, 11);
269 dest[n] = 0;
270 CHECK_INT(n, 11);
271 CHECK_STR(dest, "aZ09$-./=_~");
272}
273
274static void case_fmt_escapes_the_rest(void) {
275 const uint8_t src[] = {' ', '%', '&', '+', ':', '?'};
276 char dest[64];
277 size_t n;
278
279 test_case("everything else becomes a percent escape");
280 n = fmt_urlencoded(dest, src, sizeof(src));
281 dest[n] = 0;
282 CHECK_INT(n, 18);
283 CHECK_STR(dest, "%20%25%26%2b%3a%3f");
284}
285
286static void case_fmt_hex_is_lower_case(void) {
287 const uint8_t src[] = {0x00, 0xab, 0xff};
288 char dest[64];
289 size_t n;
290
291 test_case("escapes use lower case hex digits");
292 n = fmt_urlencoded(dest, src, sizeof(src));
293 dest[n] = 0;
294 CHECK_INT(n, 9);
295 CHECK_STR(dest, "%00%ab%ff");
296}
297
298static void case_fmt_length_only(void) {
299 const uint8_t src[] = {'a', 0xff, 'b'};
300
301 test_case("a null destination reports the length without writing");
302 CHECK_INT(fmt_urlencoded(NULL, src, sizeof(src)), 5);
303 CHECK_INT(fmt_urlencoded(NULL, src, 0), 0);
304}
305
306static void case_fmt_zero_length(void) {
307 char dest[4];
308
309 test_case("a zero length input writes nothing");
310 memset(dest, 0x5a, sizeof(dest));
311 CHECK_INT(fmt_urlencoded(dest, (const uint8_t *)"abc", 0), 0);
312 CHECK_MEM(dest, "\x5a\x5a\x5a\x5a", 4);
313}
314
315static void case_fmt_worst_case_fits(void) {
316 uint8_t src[20];
317 char dest[61];
318 size_t i, n;
319
320 test_case("a hash of entirely unsafe bytes needs three times its length");
321 for (i = 0; i < sizeof(src); ++i)
322 src[i] = 0xff;
323 n = fmt_urlencoded(dest, src, sizeof(src));
324 dest[n] = 0;
325 CHECK_INT(n, 60);
326 for (i = 0; i < 20; ++i)
327 if (memcmp(dest + 3 * i, "%ff", 3)) {
328 test_failf(__FILE__, __LINE__, "escape %zu is wrong", i);
329 return;
330 }
331 ++test_checks;
332}
333
334static void case_fmt_decoder_disagrees_on_dollar(void) {
335 /* Documenting a known asymmetry rather than a wish. Of the bytes the
336 encoder passes through unescaped, '$' is the only one the decoder then
337 refuses, and it refuses the whole string rather than stopping short.
338 Output of the urlencoded full scrape therefore does not round trip
339 through scan_urlencoded_query when a hash contains 0x24. Harmless today
340 because only third party tooling reads that output. */
341 const uint8_t src[] = {'a', '$', 'b'};
342 char dest[16];
343 char scanned[16];
344 char *p = dest;
345 size_t n;
346 ssize_t got;
347
348 test_case("the encoder passes '$' but the decoder rejects it");
349 n = fmt_urlencoded(dest, src, sizeof(src));
350 dest[n] = 0;
351 CHECK_STR(dest, "a$b");
352
353 got = scan_urlencoded_query(&p, scanned, SCAN_SEARCHPATH_VALUE);
354 CHECK_INT(got, -1);
355}
356
257void test_scan_urlencoded_query(void) { 357void test_scan_urlencoded_query(void) {
258 case_path(); 358 case_path();
259 case_param_and_value(); 359 case_param_and_value();
@@ -271,4 +371,11 @@ void test_scan_urlencoded_query(void) {
271 case_find_keywords(); 371 case_find_keywords();
272 case_fixed_int(); 372 case_fixed_int();
273 case_fixed_int_bounded(); 373 case_fixed_int_bounded();
374 case_fmt_passes_safe_bytes();
375 case_fmt_escapes_the_rest();
376 case_fmt_hex_is_lower_case();
377 case_fmt_length_only();
378 case_fmt_zero_length();
379 case_fmt_worst_case_fits();
380 case_fmt_decoder_disagrees_on_dollar();
274} 381}