diff options
| -rw-r--r-- | opentracker.c | 4 | ||||
| -rw-r--r-- | ot_config.c | 22 | ||||
| -rw-r--r-- | ot_http.c | 23 | ||||
| -rw-r--r-- | ot_ip.c | 2 | ||||
| -rw-r--r-- | ot_ip.h | 2 | ||||
| -rw-r--r-- | ot_scan.c | 29 | ||||
| -rw-r--r-- | ot_scan.h | 12 | ||||
| -rw-r--r-- | ot_sync.c | 2 | ||||
| -rw-r--r-- | ot_urlencoded.c | 13 | ||||
| -rw-r--r-- | ot_urlencoded.h | 6 | ||||
| -rw-r--r-- | proxy.c | 4 | ||||
| -rw-r--r-- | tests/t_ip.c | 54 | ||||
| -rw-r--r-- | tests/t_scan.c | 124 | ||||
| -rw-r--r-- | tests/t_urlencoded.c | 29 |
14 files changed, 179 insertions, 147 deletions
diff --git a/opentracker.c b/opentracker.c index f0f6404..7de6c6a 100644 --- a/opentracker.c +++ b/opentracker.c | |||
| @@ -379,10 +379,10 @@ void load_state(const char *const state_filename) { | |||
| 379 | continue; | 379 | continue; |
| 380 | i = 2 * sizeof(ot_hash); | 380 | i = 2 * sizeof(ot_hash); |
| 381 | 381 | ||
| 382 | if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &base, UINT64_MAX))) | 382 | if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &base, UINT64_MAX))) |
| 383 | continue; | 383 | continue; |
| 384 | i += consumed; | 384 | i += consumed; |
| 385 | if (inbuf[i++] != ':' || !(consumed = scan_udec(inbuf + i, &downcount, UINT64_MAX))) | 385 | if (inbuf[i++] != ':' || !(consumed = scan_uint(inbuf + i, &downcount, UINT64_MAX))) |
| 386 | continue; | 386 | continue; |
| 387 | add_torrent_from_saved_state(infohash, base, downcount); | 387 | add_torrent_from_saved_state(infohash, base, downcount); |
| 388 | } | 388 | } |
diff --git a/ot_config.c b/ot_config.c index a5fc06e..32625bd 100644 --- a/ot_config.c +++ b/ot_config.c | |||
| @@ -107,7 +107,7 @@ static int listen_scan_options(char *p, int *shared, int *workers) { | |||
| 107 | *shared = 1; | 107 | *shared = 1; |
| 108 | break; | 108 | break; |
| 109 | case LISTEN_OPTION_WORKERS: { | 109 | case LISTEN_OPTION_WORKERS: { |
| 110 | size_t off = scan_udec(p, &value, UINT_MAX); | 110 | size_t off = scan_uint(p, &value, UINT_MAX); |
| 111 | 111 | ||
| 112 | if (!off) | 112 | if (!off) |
| 113 | return 0; | 113 | return 0; |
| @@ -140,7 +140,7 @@ static int scan_ip6_port(const char *src, ot_ip6 ip, uint16_t *port) { | |||
| 140 | ++s; | 140 | ++s; |
| 141 | if (*s == '[') | 141 | if (*s == '[') |
| 142 | ++s, ++bracket; /* for v6 style notation */ | 142 | ++s, ++bracket; /* for v6 style notation */ |
| 143 | if (!(off = ip_scan(s, ip))) | 143 | if (!(off = ip_parse(s, ip))) |
| 144 | return 0; | 144 | return 0; |
| 145 | s += off; | 145 | s += off; |
| 146 | if (bracket && *s == ']') | 146 | if (bracket && *s == ']') |
| @@ -157,7 +157,7 @@ static int scan_ip6_port(const char *src, ot_ip6 ip, uint16_t *port) { | |||
| 157 | if (*(s++) != ':') | 157 | if (*(s++) != ':') |
| 158 | return 0; | 158 | return 0; |
| 159 | } | 159 | } |
| 160 | if (!(off = scan_udec(s, &value, 65535))) | 160 | if (!(off = scan_uint(s, &value, 65535))) |
| 161 | return 0; | 161 | return 0; |
| 162 | *port = (uint16_t)value; | 162 | *port = (uint16_t)value; |
| 163 | return off + s - src; | 163 | return off + s - src; |
| @@ -169,14 +169,14 @@ static int scan_ip6_net(const char *src, ot_net *net) { | |||
| 169 | int off; | 169 | int off; |
| 170 | while (isspace(*s)) | 170 | while (isspace(*s)) |
| 171 | ++s; | 171 | ++s; |
| 172 | if (!(off = ip_scan(s, net->address))) | 172 | if (!(off = ip_parse(s, net->address))) |
| 173 | return 0; | 173 | return 0; |
| 174 | s += off; | 174 | s += off; |
| 175 | if (*s != '/') | 175 | if (*s != '/') |
| 176 | net->bits = 128; | 176 | net->bits = 128; |
| 177 | else { | 177 | else { |
| 178 | s++; | 178 | s++; |
| 179 | if (!(off = scan_udec(s, &value, 128))) | 179 | if (!(off = scan_uint(s, &value, 128))) |
| 180 | return 0; | 180 | return 0; |
| 181 | net->bits = (int)value; | 181 | net->bits = (int)value; |
| 182 | if (ip_is_v4mapped(net->address)) | 182 | if (ip_is_v4mapped(net->address)) |
| @@ -324,12 +324,12 @@ static int parse_configfile(char *config_filename) { | |||
| 324 | break; | 324 | break; |
| 325 | } | 325 | } |
| 326 | case CONFIG_LISTEN_UDP_WORKERS: | 326 | case CONFIG_LISTEN_UDP_WORKERS: |
| 327 | if (!scan_udec(p, &value, UINT_MAX)) | 327 | if (!scan_uint(p, &value, UINT_MAX)) |
| 328 | goto parse_error; | 328 | goto parse_error; |
| 329 | g_listen_workers = (int)value; | 329 | g_listen_workers = (int)value; |
| 330 | break; | 330 | break; |
| 331 | case CONFIG_LISTEN_SHARED: | 331 | case CONFIG_LISTEN_SHARED: |
| 332 | if (!scan_udec(p, &value, 1)) | 332 | if (!scan_uint(p, &value, 1)) |
| 333 | goto parse_error; | 333 | goto parse_error; |
| 334 | g_listen_shared = (int)value; | 334 | g_listen_shared = (int)value; |
| 335 | break; | 335 | break; |
| @@ -479,7 +479,7 @@ void config_parse(int argc, char **argv) { | |||
| 479 | scanon = 0; | 479 | scanon = 0; |
| 480 | break; | 480 | break; |
| 481 | case 'i': | 481 | case 'i': |
| 482 | if (!ip_scan(optarg, serverip)) { | 482 | if (!ip_parse(optarg, serverip)) { |
| 483 | usage(argv[0]); | 483 | usage(argv[0]); |
| 484 | exit(1); | 484 | exit(1); |
| 485 | } | 485 | } |
| @@ -494,7 +494,7 @@ void config_parse(int argc, char **argv) { | |||
| 494 | break; | 494 | break; |
| 495 | #endif | 495 | #endif |
| 496 | case 'p': | 496 | case 'p': |
| 497 | if (!scan_udec(optarg, &value, 65535)) { | 497 | if (!scan_uint(optarg, &value, 65535)) { |
| 498 | usage(argv[0]); | 498 | usage(argv[0]); |
| 499 | exit(1); | 499 | exit(1); |
| 500 | } | 500 | } |
| @@ -502,7 +502,7 @@ void config_parse(int argc, char **argv) { | |||
| 502 | bound++; | 502 | bound++; |
| 503 | break; | 503 | break; |
| 504 | case 'P': | 504 | case 'P': |
| 505 | if (!scan_udec(optarg, &value, 65535)) { | 505 | if (!scan_uint(optarg, &value, 65535)) { |
| 506 | usage(argv[0]); | 506 | usage(argv[0]); |
| 507 | exit(1); | 507 | exit(1); |
| 508 | } | 508 | } |
| @@ -511,7 +511,7 @@ void config_parse(int argc, char **argv) { | |||
| 511 | break; | 511 | break; |
| 512 | #ifdef WANT_SYNC_LIVE | 512 | #ifdef WANT_SYNC_LIVE |
| 513 | case 's': | 513 | case 's': |
| 514 | if (!scan_udec(optarg, &value, 65535)) { | 514 | if (!scan_uint(optarg, &value, 65535)) { |
| 515 | usage(argv[0]); | 515 | usage(argv[0]); |
| 516 | exit(1); | 516 | exit(1); |
| 517 | } | 517 | } |
| @@ -482,7 +482,8 @@ static ot_keywords keywords_announce[] = {{"port", 1}, {"left", 2}, {"event", | |||
| 482 | static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; | 482 | static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; |
| 483 | static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { | 483 | static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { |
| 484 | size_t numwant; | 484 | size_t numwant; |
| 485 | int tmp, scanon; | 485 | int64_t tmp; |
| 486 | int scanon; | ||
| 486 | unsigned short port = 0; | 487 | unsigned short port = 0; |
| 487 | char *write_ptr; | 488 | char *write_ptr; |
| 488 | ssize_t len; | 489 | ssize_t len; |
| @@ -501,7 +502,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct | |||
| 501 | if (accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_PROXY)) { | 502 | if (accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_PROXY)) { |
| 502 | ot_ip6 proxied_ip; | 503 | ot_ip6 proxied_ip; |
| 503 | char *fwd = http_header(ws->request, ws->header_size, "x-forwarded-for"); | 504 | char *fwd = http_header(ws->request, ws->header_size, "x-forwarded-for"); |
| 504 | if (fwd && ip_scan(fwd, proxied_ip)) { | 505 | if (fwd && ip_parse(fwd, proxied_ip)) { |
| 505 | OT_SETIP(ws->peer, proxied_ip); | 506 | OT_SETIP(ws->peer, proxied_ip); |
| 506 | } else | 507 | } else |
| 507 | OT_SETIP(ws->peer, cookie->ip); | 508 | OT_SETIP(ws->peer, cookie->ip); |
| @@ -529,15 +530,15 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct | |||
| 529 | break; | 530 | break; |
| 530 | case 1: /* matched "port" */ | 531 | case 1: /* matched "port" */ |
| 531 | len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); | 532 | len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); |
| 532 | if ((len <= 0) || scan_fixed_int(write_ptr, len, &tmp) || (tmp > 0xffff)) | 533 | if ((len <= 0) || scan_int(write_ptr, len, &tmp) || (tmp > 0xffff)) |
| 533 | HTTPERROR_400_PARAM; | 534 | HTTPERROR_400_PARAM; |
| 534 | port = htons(tmp); | 535 | port = htons((uint16_t)tmp); |
| 535 | OT_SETPORT(&ws->peer, &port); | 536 | OT_SETPORT(&ws->peer, &port); |
| 536 | break; | 537 | break; |
| 537 | case 2: /* matched "left" */ | 538 | case 2: /* matched "left" */ |
| 538 | if ((len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0) | 539 | if ((len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE)) <= 0) |
| 539 | HTTPERROR_400_PARAM; | 540 | HTTPERROR_400_PARAM; |
| 540 | if (scan_fixed_int(write_ptr, len, &tmp)) | 541 | if (scan_int(write_ptr, len, &tmp)) |
| 541 | tmp = 0; | 542 | tmp = 0; |
| 542 | if (!tmp) | 543 | if (!tmp) |
| 543 | OT_PEERFLAG(&ws->peer) |= PEER_FLAG_SEEDING; | 544 | OT_PEERFLAG(&ws->peer) |= PEER_FLAG_SEEDING; |
| @@ -558,17 +559,17 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct | |||
| 558 | break; | 559 | break; |
| 559 | case 4: /* matched "numwant" */ | 560 | case 4: /* matched "numwant" */ |
| 560 | len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); | 561 | len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); |
| 561 | if ((len <= 0) || scan_fixed_int(write_ptr, len, &tmp)) | 562 | if ((len <= 0) || scan_int(write_ptr, len, &tmp)) |
| 562 | HTTPERROR_400_PARAM; | 563 | HTTPERROR_400_PARAM; |
| 563 | if (tmp < 0) | 564 | if (tmp < 0) |
| 564 | tmp = 50; | 565 | tmp = 50; |
| 565 | if (tmp > 200) | 566 | if (tmp > 200) |
| 566 | tmp = 200; | 567 | tmp = 200; |
| 567 | numwant = tmp; | 568 | numwant = (size_t)tmp; |
| 568 | break; | 569 | break; |
| 569 | case 5: /* matched "compact" */ | 570 | case 5: /* matched "compact" */ |
| 570 | len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); | 571 | len = urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); |
| 571 | if ((len <= 0) || scan_fixed_int(write_ptr, len, &tmp)) | 572 | if ((len <= 0) || scan_int(write_ptr, len, &tmp)) |
| 572 | HTTPERROR_400_PARAM; | 573 | HTTPERROR_400_PARAM; |
| 573 | if (!tmp) | 574 | if (!tmp) |
| 574 | HTTPERROR_400_COMPACT; | 575 | HTTPERROR_400_COMPACT; |
| @@ -587,7 +588,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct | |||
| 587 | char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply + 16; | 588 | char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply + 16; |
| 588 | len = urlencoded_parse(&read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE); | 589 | len = urlencoded_parse(&read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE); |
| 589 | tmp_buf2[len] = 0; | 590 | tmp_buf2[len] = 0; |
| 590 | if ((len <= 0) || !ip_scan(tmp_buf2, tmp_buf1)) | 591 | if ((len <= 0) || !ip_parse(tmp_buf2, tmp_buf1)) |
| 591 | HTTPERROR_400_PARAM; | 592 | HTTPERROR_400_PARAM; |
| 592 | OT_SETIP(&ws->peer, tmp_buf1); | 593 | OT_SETIP(&ws->peer, tmp_buf1); |
| 593 | } break; | 594 | } break; |
| @@ -609,13 +610,13 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct | |||
| 609 | loglist_reset(); | 610 | loglist_reset(); |
| 610 | return ws->reply_size = sprintf(ws->reply, "Successfully removed.\n"); | 611 | return ws->reply_size = sprintf(ws->reply, "Successfully removed.\n"); |
| 611 | } | 612 | } |
| 612 | parsed = ip_scan(tmp_buf, net.address); | 613 | parsed = ip_parse(tmp_buf, net.address); |
| 613 | if (!parsed) | 614 | if (!parsed) |
| 614 | HTTPERROR_400_PARAM; | 615 | HTTPERROR_400_PARAM; |
| 615 | if (tmp_buf[parsed++] != '/') | 616 | if (tmp_buf[parsed++] != '/') |
| 616 | bits = 128; | 617 | bits = 128; |
| 617 | else { | 618 | else { |
| 618 | parsed = scan_udec(tmp_buf + parsed, &value, 128); | 619 | parsed = scan_uint(tmp_buf + parsed, &value, 128); |
| 619 | if (!parsed) | 620 | if (!parsed) |
| 620 | HTTPERROR_400_PARAM; | 621 | HTTPERROR_400_PARAM; |
| 621 | bits = (signed short)value; | 622 | bits = (signed short)value; |
| @@ -120,7 +120,7 @@ size_t ip_format(char *dest, const ot_ip6 ip) { | |||
| 120 | return (size_t)(d - dest); | 120 | return (size_t)(d - dest); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | size_t ip_scan(const char *src, ot_ip6 ip) { | 123 | size_t ip_parse(const char *src, ot_ip6 ip) { |
| 124 | uint8_t prefix[16], suffix[16]; | 124 | uint8_t prefix[16], suffix[16]; |
| 125 | size_t prefixlen = 0, suffixlen = 0; | 125 | size_t prefixlen = 0, suffixlen = 0; |
| 126 | const char *s = src; | 126 | const char *s = src; |
| @@ -23,7 +23,7 @@ static inline int ip_is_v4mapped(const void *ip) { return !memcmp(ip, ip_v4mappe | |||
| 23 | 23 | ||
| 24 | The count lets the caller carry on where the address ended, which is how | 24 | The count lets the caller carry on where the address ended, which is how |
| 25 | "address:port" and "address/bits" are read. */ | 25 | "address:port" and "address/bits" are read. */ |
| 26 | size_t ip_scan(const char *src, ot_ip6 ip); | 26 | size_t ip_parse(const char *src, ot_ip6 ip); |
| 27 | 27 | ||
| 28 | /* Write an address and return how many characters it took. Nothing is | 28 | /* Write an address and return how many characters it took. Nothing is |
| 29 | terminated, so a caller may keep appending. A v4 mapped address is written | 29 | terminated, so a caller may keep appending. A v4 mapped address is written |
| @@ -11,7 +11,7 @@ | |||
| 11 | /* Opentracker */ | 11 | /* Opentracker */ |
| 12 | #include "ot_scan.h" | 12 | #include "ot_scan.h" |
| 13 | 13 | ||
| 14 | size_t scan_udec(const char *src, uint64_t *dest, uint64_t max) { | 14 | size_t scan_uint(const char *src, uint64_t *dest, uint64_t max) { |
| 15 | unsigned long long value; | 15 | unsigned long long value; |
| 16 | char *end; | 16 | char *end; |
| 17 | 17 | ||
| @@ -28,9 +28,9 @@ size_t scan_udec(const char *src, uint64_t *dest, uint64_t max) { | |||
| 28 | return (size_t)(end - src); | 28 | return (size_t)(end - src); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | size_t scan_udec_bencode(const char *src, uint64_t *dest, uint64_t max) { | 31 | size_t scan_uint_bencode(const char *src, uint64_t *dest, uint64_t max) { |
| 32 | uint64_t value; | 32 | uint64_t value; |
| 33 | size_t consumed = scan_udec(src, &value, max); | 33 | size_t consumed = scan_uint(src, &value, max); |
| 34 | 34 | ||
| 35 | /* bencode writes no leading zeros, so anything longer than a single digit | 35 | /* bencode writes no leading zeros, so anything longer than a single digit |
| 36 | must not begin with one. */ | 36 | must not begin with one. */ |
| @@ -42,3 +42,26 @@ size_t scan_udec_bencode(const char *src, uint64_t *dest, uint64_t max) { | |||
| 42 | 42 | ||
| 43 | return consumed; | 43 | return consumed; |
| 44 | } | 44 | } |
| 45 | |||
| 46 | int scan_int(const char *src, size_t len, int64_t *dest) { | ||
| 47 | int64_t value = 0; | ||
| 48 | int negate = 0; | ||
| 49 | |||
| 50 | if (len && *src == '-') | ||
| 51 | --len, ++src, negate = 1; | ||
| 52 | if (!len) | ||
| 53 | return -1; | ||
| 54 | |||
| 55 | while (len--) { | ||
| 56 | if (*src < '0' || *src > '9') | ||
| 57 | return -1; | ||
| 58 | /* A twenty character field of nines does not fit, and silently wrapping | ||
| 59 | would magically heal a nonsense announce */ | ||
| 60 | if (value > (INT64_MAX - (*src - '0')) / 10) | ||
| 61 | return -1; | ||
| 62 | value = 10 * value + (*src++ - '0'); | ||
| 63 | } | ||
| 64 | |||
| 65 | *dest = negate ? -value : value; | ||
| 66 | return 0; | ||
| 67 | } | ||
| @@ -7,15 +7,21 @@ | |||
| 7 | #define OT_SCAN_H__ | 7 | #define OT_SCAN_H__ |
| 8 | 8 | ||
| 9 | #include <stddef.h> | 9 | #include <stddef.h> |
| 10 | #include <stddef.h> | ||
| 10 | #include <stdint.h> | 11 | #include <stdint.h> |
| 11 | 12 | ||
| 12 | /* Read an unsigned decimal number from src into dest and return how many | 13 | /* Read an unsigned decimal number from src into dest and return how many |
| 13 | characters were consumed. Returns zero and leaves dest untouched when src | 14 | characters were consumed. Returns zero and leaves dest untouched when src |
| 14 | does not begin with a digit, or when the value would exceed max. */ | 15 | does not begin with a digit, or when the value would exceed max. */ |
| 15 | size_t scan_udec(const char *src, uint64_t *dest, uint64_t max); | 16 | size_t scan_uint(const char *src, uint64_t *dest, uint64_t max); |
| 16 | 17 | ||
| 17 | /* As scan_udec, but following the bencode integer grammar, which permits a | 18 | /* As scan_uint, but following the bencode integer grammar, which permits a |
| 18 | leading zero on zero alone. */ | 19 | leading zero on zero alone. */ |
| 19 | size_t scan_udec_bencode(const char *src, uint64_t *dest, uint64_t max); | 20 | size_t scan_uint_bencode(const char *src, uint64_t *dest, uint64_t max); |
| 21 | |||
| 22 | /* Read a signed decimal number that has to take up exactly len characters, | ||
| 23 | which is how a value lifted out of a query string arrives. Returns 0, or | ||
| 24 | -1 leaving dest untouched. */ | ||
| 25 | int scan_int(const char *src, size_t len, int64_t *dest); | ||
| 20 | 26 | ||
| 21 | #endif | 27 | #endif |
| @@ -51,7 +51,7 @@ int add_changeset_to_tracker(uint8_t *data, size_t len) { | |||
| 51 | data += sizeof(ot_hash); | 51 | data += sizeof(ot_hash); |
| 52 | 52 | ||
| 53 | /* Scan string length indicator, strictly: bencode writes no leading zeros */ | 53 | /* Scan string length indicator, strictly: bencode writes no leading zeros */ |
| 54 | data += (len = scan_udec_bencode((char *)data, &peer_count, (uint64_t)(end - data))); | 54 | data += (len = scan_uint_bencode((char *)data, &peer_count, (uint64_t)(end - data))); |
| 55 | 55 | ||
| 56 | /* If no long was scanned, it is not divisible by 8, it is not | 56 | /* If no long was scanned, it is not divisible by 8, it is not |
| 57 | followed by a colon or claims to need to much memory, we fail */ | 57 | followed by a colon or claims to need to much memory, we fail */ |
diff --git a/ot_urlencoded.c b/ot_urlencoded.c index 1ca6e81..17f12a4 100644 --- a/ot_urlencoded.c +++ b/ot_urlencoded.c | |||
| @@ -146,19 +146,6 @@ ssize_t urlencoded_parse(char **string, char *deststring, SCAN_SEARCHPATH_FLAG f | |||
| 146 | return d - (unsigned char *)deststring; | 146 | return d - (unsigned char *)deststring; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | ssize_t scan_fixed_int(char *data, size_t len, int *tmp) { | ||
| 150 | int minus = 0; | ||
| 151 | *tmp = 0; | ||
| 152 | if (*data == '-') | ||
| 153 | --len, ++data, ++minus; | ||
| 154 | while ((len > 0) && (*data >= '0') && (*data <= '9')) { | ||
| 155 | --len; | ||
| 156 | *tmp = 10 * *tmp + *data++ - '0'; | ||
| 157 | } | ||
| 158 | if (minus) | ||
| 159 | *tmp = -*tmp; | ||
| 160 | return len; | ||
| 161 | } | ||
| 162 | 149 | ||
| 163 | size_t urlencoded_format(char *dest, const uint8_t *src, size_t len) { | 150 | size_t urlencoded_format(char *dest, const uint8_t *src, size_t len) { |
| 164 | static const char safe[] = "$/.=~-_"; | 151 | static const char safe[] = "$/.=~-_"; |
diff --git a/ot_urlencoded.h b/ot_urlencoded.h index 8147370..b6f1208 100644 --- a/ot_urlencoded.h +++ b/ot_urlencoded.h | |||
| @@ -47,12 +47,6 @@ int urlencoded_match_keyword(const ot_keywords *keywords, char **string, SCA | |||
| 47 | */ | 47 | */ |
| 48 | void urlencoded_skip_value(char **string); | 48 | void urlencoded_skip_value(char **string); |
| 49 | 49 | ||
| 50 | /* data pointer to len chars of string | ||
| 51 | len length of chars in data to parse | ||
| 52 | number number to receive result | ||
| 53 | returns number of bytes not parsed, mostly !=0 means fail | ||
| 54 | */ | ||
| 55 | ssize_t scan_fixed_int(char *data, size_t len, int *number); | ||
| 56 | 50 | ||
| 57 | /* The other direction: percent encode len bytes from src into dest and return | 51 | /* The other direction: percent encode len bytes from src into dest and return |
| 58 | how many characters were written. dest needs room for three times len. */ | 52 | how many characters were written. dest needs room for three times len. */ |
| @@ -507,7 +507,7 @@ static int scan_ip6_port(const char *src, ot_ip6 ip, uint16_t *port) { | |||
| 507 | ++s; | 507 | ++s; |
| 508 | if (*s == '[') | 508 | if (*s == '[') |
| 509 | ++s, ++bracket; /* for v6 style notation */ | 509 | ++s, ++bracket; /* for v6 style notation */ |
| 510 | if (!(off = ip_scan(s, ip))) | 510 | if (!(off = ip_parse(s, ip))) |
| 511 | return 0; | 511 | return 0; |
| 512 | s += off; | 512 | s += off; |
| 513 | if (*s == 0 || isspace(*s)) | 513 | if (*s == 0 || isspace(*s)) |
| @@ -522,7 +522,7 @@ static int scan_ip6_port(const char *src, ot_ip6 ip, uint16_t *port) { | |||
| 522 | if (*(s++) != ':') | 522 | if (*(s++) != ':') |
| 523 | return 0; | 523 | return 0; |
| 524 | } | 524 | } |
| 525 | if (!(off = scan_udec(s, &value, 65535))) | 525 | if (!(off = scan_uint(s, &value, 65535))) |
| 526 | return 0; | 526 | return 0; |
| 527 | *port = (uint16_t)value; | 527 | *port = (uint16_t)value; |
| 528 | return off + s - src; | 528 | return off + s - src; |
diff --git a/tests/t_ip.c b/tests/t_ip.c index 2fe3a72..8d71679 100644 --- a/tests/t_ip.c +++ b/tests/t_ip.c | |||
| @@ -95,27 +95,27 @@ static void case_scan_forms(void) { | |||
| 95 | char ip[16]; | 95 | char ip[16]; |
| 96 | 96 | ||
| 97 | test_case("2.2 form 1, every group spelled out"); | 97 | test_case("2.2 form 1, every group spelled out"); |
| 98 | CHECK_INT(ip_scan("1111:2222:3333:4444:5555:6666:7777:8888", ip), 39); | 98 | CHECK_INT(ip_parse("1111:2222:3333:4444:5555:6666:7777:8888", ip), 39); |
| 99 | CHECK_MEM(ip, "\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x66\x66\x77\x77\x88\x88", 16); | 99 | CHECK_MEM(ip, "\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x66\x66\x77\x77\x88\x88", 16); |
| 100 | 100 | ||
| 101 | test_case("2.2 form 2, zero groups abbreviated"); | 101 | test_case("2.2 form 2, zero groups abbreviated"); |
| 102 | CHECK_INT(ip_scan("2001:db8::1", ip), 11); | 102 | CHECK_INT(ip_parse("2001:db8::1", ip), 11); |
| 103 | CHECK_MEM(ip, "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16); | 103 | CHECK_MEM(ip, "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16); |
| 104 | CHECK_INT(ip_scan("::1", ip), 3); | 104 | CHECK_INT(ip_parse("::1", ip), 3); |
| 105 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16); | 105 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16); |
| 106 | CHECK_INT(ip_scan("::", ip), 2); | 106 | CHECK_INT(ip_parse("::", ip), 2); |
| 107 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); | 107 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); |
| 108 | CHECK_INT(ip_scan("1::", ip), 3); | 108 | CHECK_INT(ip_parse("1::", ip), 3); |
| 109 | CHECK_MEM(ip, "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); | 109 | CHECK_MEM(ip, "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); |
| 110 | 110 | ||
| 111 | test_case("2.2 form 3, a dotted quad in the last two groups"); | 111 | test_case("2.2 form 3, a dotted quad in the last two groups"); |
| 112 | CHECK_INT(ip_scan("::ffff:1.2.3.4", ip), 14); | 112 | CHECK_INT(ip_parse("::ffff:1.2.3.4", ip), 14); |
| 113 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x03\x04", 16); | 113 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x03\x04", 16); |
| 114 | CHECK_INT(ip_scan("1:2:3:4:5:6:1.2.3.4", ip), 19); | 114 | CHECK_INT(ip_parse("1:2:3:4:5:6:1.2.3.4", ip), 19); |
| 115 | CHECK_MEM(ip, "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x01\x02\x03\x04", 16); | 115 | CHECK_MEM(ip, "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x01\x02\x03\x04", 16); |
| 116 | 116 | ||
| 117 | test_case("upper case input is accepted"); | 117 | test_case("upper case input is accepted"); |
| 118 | CHECK_INT(ip_scan("2001:DB8::1", ip), 11); | 118 | CHECK_INT(ip_parse("2001:DB8::1", ip), 11); |
| 119 | CHECK_MEM(ip, "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16); | 119 | CHECK_MEM(ip, "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| @@ -125,7 +125,7 @@ static void case_scan_accepts_bare_ipv4(void) { | |||
| 125 | /* Every address opentracker holds is sixteen bytes, so an operator writing | 125 | /* Every address opentracker holds is sixteen bytes, so an operator writing |
| 126 | a plain IPv4 address in the config has to land as the v4 mapped form */ | 126 | a plain IPv4 address in the config has to land as the v4 mapped form */ |
| 127 | test_case("a bare IPv4 address is stored v4 mapped"); | 127 | test_case("a bare IPv4 address is stored v4 mapped"); |
| 128 | CHECK_INT(ip_scan("10.0.0.1", ip), 8); | 128 | CHECK_INT(ip_parse("10.0.0.1", ip), 8); |
| 129 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x0a\x00\x00\x01", 16); | 129 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x0a\x00\x00\x01", 16); |
| 130 | CHECK(ip_is_v4mapped(ip)); | 130 | CHECK(ip_is_v4mapped(ip)); |
| 131 | } | 131 | } |
| @@ -136,39 +136,39 @@ static void case_scan_reports_length(void) { | |||
| 136 | /* The config parser continues from where the address ended, which is how | 136 | /* The config parser continues from where the address ended, which is how |
| 137 | "address:port" and "address/bits" are read */ | 137 | "address:port" and "address/bits" are read */ |
| 138 | test_case("scanning stops at the character after the address"); | 138 | test_case("scanning stops at the character after the address"); |
| 139 | CHECK_INT(ip_scan("10.0.0.1:6969", ip), 8); | 139 | CHECK_INT(ip_parse("10.0.0.1:6969", ip), 8); |
| 140 | CHECK_INT(ip_scan("2001:db8::1/64", ip), 11); | 140 | CHECK_INT(ip_parse("2001:db8::1/64", ip), 11); |
| 141 | CHECK_INT(ip_scan("::1]", ip), 3); | 141 | CHECK_INT(ip_parse("::1]", ip), 3); |
| 142 | CHECK_INT(ip_scan("1:2:3:4:5:6:7:8 trailing", ip), 15); | 142 | CHECK_INT(ip_parse("1:2:3:4:5:6:7:8 trailing", ip), 15); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | static void case_scan_rejects(void) { | 145 | static void case_scan_rejects(void) { |
| 146 | char ip[16]; | 146 | char ip[16]; |
| 147 | 147 | ||
| 148 | test_case("an empty or junk string is refused"); | 148 | test_case("an empty or junk string is refused"); |
| 149 | CHECK_INT(ip_scan("", ip), 0); | 149 | CHECK_INT(ip_parse("", ip), 0); |
| 150 | CHECK_INT(ip_scan("x", ip), 0); | 150 | CHECK_INT(ip_parse("x", ip), 0); |
| 151 | CHECK_INT(ip_scan(":", ip), 0); | 151 | CHECK_INT(ip_parse(":", ip), 0); |
| 152 | CHECK_INT(ip_scan(":1:2", ip), 0); | 152 | CHECK_INT(ip_parse(":1:2", ip), 0); |
| 153 | 153 | ||
| 154 | test_case("too few groups without :: are refused"); | 154 | test_case("too few groups without :: are refused"); |
| 155 | CHECK_INT(ip_scan("1:2:3:4:5:6:7", ip), 0); | 155 | CHECK_INT(ip_parse("1:2:3:4:5:6:7", ip), 0); |
| 156 | CHECK_INT(ip_scan("2001:db8:1", ip), 0); | 156 | CHECK_INT(ip_parse("2001:db8:1", ip), 0); |
| 157 | 157 | ||
| 158 | /* libowfat accepted a prefix of each of these and carried on. Taking only | 158 | /* libowfat accepted a prefix of each of these and carried on. Taking only |
| 159 | part of a malformed address is worse than refusing it, especially where | 159 | part of a malformed address is worse than refusing it, especially where |
| 160 | the text comes from a config file or an X-Forwarded-For header. */ | 160 | the text comes from a config file or an X-Forwarded-For header. */ |
| 161 | test_case("a second :: is refused rather than truncated"); | 161 | test_case("a second :: is refused rather than truncated"); |
| 162 | CHECK_INT(ip_scan("1::2::3", ip), 0); | 162 | CHECK_INT(ip_parse("1::2::3", ip), 0); |
| 163 | CHECK_INT(ip_scan("::1::", ip), 0); | 163 | CHECK_INT(ip_parse("::1::", ip), 0); |
| 164 | CHECK_INT(ip_scan("::::", ip), 0); | 164 | CHECK_INT(ip_parse("::::", ip), 0); |
| 165 | 165 | ||
| 166 | test_case("more than eight groups is refused"); | 166 | test_case("more than eight groups is refused"); |
| 167 | CHECK_INT(ip_scan("1:2:3:4:5:6:7:8:9", ip), 0); | 167 | CHECK_INT(ip_parse("1:2:3:4:5:6:7:8:9", ip), 0); |
| 168 | 168 | ||
| 169 | test_case("a group of more than four digits is refused, not truncated"); | 169 | test_case("a group of more than four digits is refused, not truncated"); |
| 170 | CHECK_INT(ip_scan("12345::1", ip), 0); | 170 | CHECK_INT(ip_parse("12345::1", ip), 0); |
| 171 | CHECK_INT(ip_scan("fffff::1", ip), 0); | 171 | CHECK_INT(ip_parse("fffff::1", ip), 0); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | static void case_round_trip(void) { | 174 | static void case_round_trip(void) { |
| @@ -187,7 +187,7 @@ static void case_round_trip(void) { | |||
| 187 | 187 | ||
| 188 | test_case("every formatted address scans back to the same bytes"); | 188 | test_case("every formatted address scans back to the same bytes"); |
| 189 | for (i = 0; samples[i]; ++i) { | 189 | for (i = 0; samples[i]; ++i) { |
| 190 | size_t n = ip_scan(samples[i], ip); | 190 | size_t n = ip_parse(samples[i], ip); |
| 191 | if (n != strlen(samples[i])) { | 191 | if (n != strlen(samples[i])) { |
| 192 | test_failf(__FILE__, __LINE__, "\"%s\" consumed %zu of %zu", samples[i], n, strlen(samples[i])); | 192 | test_failf(__FILE__, __LINE__, "\"%s\" consumed %zu of %zu", samples[i], n, strlen(samples[i])); |
| 193 | return; | 193 | return; |
| @@ -197,7 +197,7 @@ static void case_round_trip(void) { | |||
| 197 | test_failf(__FILE__, __LINE__, "\"%s\" formatted back as \"%s\"", samples[i], text); | 197 | test_failf(__FILE__, __LINE__, "\"%s\" formatted back as \"%s\"", samples[i], text); |
| 198 | return; | 198 | return; |
| 199 | } | 199 | } |
| 200 | if (!ip_scan(text, again) || memcmp(ip, again, 16)) { | 200 | if (!ip_parse(text, again) || memcmp(ip, again, 16)) { |
| 201 | test_failf(__FILE__, __LINE__, "\"%s\" did not survive a second pass", samples[i]); | 201 | test_failf(__FILE__, __LINE__, "\"%s\" did not survive a second pass", samples[i]); |
| 202 | return; | 202 | return; |
| 203 | } | 203 | } |
diff --git a/tests/t_scan.c b/tests/t_scan.c index 89f1590..aab4413 100644 --- a/tests/t_scan.c +++ b/tests/t_scan.c | |||
| @@ -15,13 +15,13 @@ static void case_plain_numbers(void) { | |||
| 15 | uint64_t value; | 15 | uint64_t value; |
| 16 | 16 | ||
| 17 | test_case("a decimal number is read and its length reported"); | 17 | test_case("a decimal number is read and its length reported"); |
| 18 | CHECK_INT(scan_udec("0", &value, 65535), 1); | 18 | CHECK_INT(scan_uint("0", &value, 65535), 1); |
| 19 | CHECK_INT(value, 0); | 19 | CHECK_INT(value, 0); |
| 20 | CHECK_INT(scan_udec("7", &value, 65535), 1); | 20 | CHECK_INT(scan_uint("7", &value, 65535), 1); |
| 21 | CHECK_INT(value, 7); | 21 | CHECK_INT(value, 7); |
| 22 | CHECK_INT(scan_udec("6969", &value, 65535), 4); | 22 | CHECK_INT(scan_uint("6969", &value, 65535), 4); |
| 23 | CHECK_INT(value, 6969); | 23 | CHECK_INT(value, 6969); |
| 24 | CHECK_INT(scan_udec("65535", &value, 65535), 5); | 24 | CHECK_INT(scan_uint("65535", &value, 65535), 5); |
| 25 | CHECK_INT(value, 65535); | 25 | CHECK_INT(value, 65535); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| @@ -29,11 +29,11 @@ static void case_stops_at_non_digit(void) { | |||
| 29 | uint64_t value; | 29 | uint64_t value; |
| 30 | 30 | ||
| 31 | test_case("scanning stops at the first character that is not a digit"); | 31 | test_case("scanning stops at the first character that is not a digit"); |
| 32 | CHECK_INT(scan_udec("6969:rest", &value, 65535), 4); | 32 | CHECK_INT(scan_uint("6969:rest", &value, 65535), 4); |
| 33 | CHECK_INT(value, 6969); | 33 | CHECK_INT(value, 6969); |
| 34 | CHECK_INT(scan_udec("128/8", &value, 65535), 3); | 34 | CHECK_INT(scan_uint("128/8", &value, 65535), 3); |
| 35 | CHECK_INT(value, 128); | 35 | CHECK_INT(value, 128); |
| 36 | CHECK_INT(scan_udec("42\n", &value, 65535), 2); | 36 | CHECK_INT(scan_uint("42\n", &value, 65535), 2); |
| 37 | CHECK_INT(value, 42); | 37 | CHECK_INT(value, 42); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| @@ -41,9 +41,9 @@ static void case_rejects_whitespace(void) { | |||
| 41 | uint64_t value = 0xdead; | 41 | uint64_t value = 0xdead; |
| 42 | 42 | ||
| 43 | test_case("leading whitespace is not skipped"); | 43 | test_case("leading whitespace is not skipped"); |
| 44 | CHECK_INT(scan_udec(" 1", &value, 65535), 0); | 44 | CHECK_INT(scan_uint(" 1", &value, 65535), 0); |
| 45 | CHECK_INT(scan_udec("\t1", &value, 65535), 0); | 45 | CHECK_INT(scan_uint("\t1", &value, 65535), 0); |
| 46 | CHECK_INT(scan_udec("\n1", &value, 65535), 0); | 46 | CHECK_INT(scan_uint("\n1", &value, 65535), 0); |
| 47 | CHECK_INT(value, 0xdead); | 47 | CHECK_INT(value, 0xdead); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| @@ -51,9 +51,9 @@ static void case_rejects_sign(void) { | |||
| 51 | uint64_t value = 0xdead; | 51 | uint64_t value = 0xdead; |
| 52 | 52 | ||
| 53 | test_case("a sign is not accepted"); | 53 | test_case("a sign is not accepted"); |
| 54 | CHECK_INT(scan_udec("+1", &value, 65535), 0); | 54 | CHECK_INT(scan_uint("+1", &value, 65535), 0); |
| 55 | CHECK_INT(scan_udec("-1", &value, 65535), 0); | 55 | CHECK_INT(scan_uint("-1", &value, 65535), 0); |
| 56 | CHECK_INT(scan_udec("-0", &value, 65535), 0); | 56 | CHECK_INT(scan_uint("-0", &value, 65535), 0); |
| 57 | CHECK_INT(value, 0xdead); | 57 | CHECK_INT(value, 0xdead); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| @@ -61,9 +61,9 @@ static void case_rejects_empty_and_junk(void) { | |||
| 61 | uint64_t value = 0xdead; | 61 | uint64_t value = 0xdead; |
| 62 | 62 | ||
| 63 | test_case("a string with no leading digit yields nothing"); | 63 | test_case("a string with no leading digit yields nothing"); |
| 64 | CHECK_INT(scan_udec("", &value, 65535), 0); | 64 | CHECK_INT(scan_uint("", &value, 65535), 0); |
| 65 | CHECK_INT(scan_udec("x", &value, 65535), 0); | 65 | CHECK_INT(scan_uint("x", &value, 65535), 0); |
| 66 | CHECK_INT(scan_udec(":80", &value, 65535), 0); | 66 | CHECK_INT(scan_uint(":80", &value, 65535), 0); |
| 67 | CHECK_INT(value, 0xdead); | 67 | CHECK_INT(value, 0xdead); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| @@ -71,9 +71,9 @@ static void case_no_alternative_bases(void) { | |||
| 71 | uint64_t value; | 71 | uint64_t value; |
| 72 | 72 | ||
| 73 | test_case("hexadecimal and octal notations are read as plain decimal"); | 73 | test_case("hexadecimal and octal notations are read as plain decimal"); |
| 74 | CHECK_INT(scan_udec("0x10", &value, 65535), 1); | 74 | CHECK_INT(scan_uint("0x10", &value, 65535), 1); |
| 75 | CHECK_INT(value, 0); | 75 | CHECK_INT(value, 0); |
| 76 | CHECK_INT(scan_udec("010", &value, 65535), 3); | 76 | CHECK_INT(scan_uint("010", &value, 65535), 3); |
| 77 | CHECK_INT(value, 10); | 77 | CHECK_INT(value, 10); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| @@ -81,13 +81,13 @@ static void case_refuses_out_of_range(void) { | |||
| 81 | uint64_t value = 0xdead; | 81 | uint64_t value = 0xdead; |
| 82 | 82 | ||
| 83 | test_case("a value above max is refused, not truncated"); | 83 | test_case("a value above max is refused, not truncated"); |
| 84 | CHECK_INT(scan_udec("65536", &value, 65535), 0); | 84 | CHECK_INT(scan_uint("65536", &value, 65535), 0); |
| 85 | CHECK_INT(scan_udec("99999", &value, 65535), 0); | 85 | CHECK_INT(scan_uint("99999", &value, 65535), 0); |
| 86 | CHECK_INT(scan_udec("129", &value, 128), 0); | 86 | CHECK_INT(scan_uint("129", &value, 128), 0); |
| 87 | CHECK_INT(value, 0xdead); | 87 | CHECK_INT(value, 0xdead); |
| 88 | 88 | ||
| 89 | test_case("the boundary itself is accepted"); | 89 | test_case("the boundary itself is accepted"); |
| 90 | CHECK_INT(scan_udec("128", &value, 128), 3); | 90 | CHECK_INT(scan_uint("128", &value, 128), 3); |
| 91 | CHECK_INT(value, 128); | 91 | CHECK_INT(value, 128); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| @@ -95,21 +95,21 @@ static void case_sixty_four_bit_range(void) { | |||
| 95 | uint64_t value; | 95 | uint64_t value; |
| 96 | 96 | ||
| 97 | test_case("the full unsigned 64 bit range is available"); | 97 | test_case("the full unsigned 64 bit range is available"); |
| 98 | CHECK_INT(scan_udec("18446744073709551615", &value, UINT64_MAX), 20); | 98 | CHECK_INT(scan_uint("18446744073709551615", &value, UINT64_MAX), 20); |
| 99 | CHECK(value == UINT64_MAX); | 99 | CHECK(value == UINT64_MAX); |
| 100 | 100 | ||
| 101 | test_case("a number too large for 64 bits is refused"); | 101 | test_case("a number too large for 64 bits is refused"); |
| 102 | CHECK_INT(scan_udec("18446744073709551616", &value, UINT64_MAX), 0); | 102 | CHECK_INT(scan_uint("18446744073709551616", &value, UINT64_MAX), 0); |
| 103 | CHECK_INT(scan_udec("99999999999999999999999999", &value, UINT64_MAX), 0); | 103 | CHECK_INT(scan_uint("99999999999999999999999999", &value, UINT64_MAX), 0); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | static void case_leading_zeros_allowed(void) { | 106 | static void case_leading_zeros_allowed(void) { |
| 107 | uint64_t value; | 107 | uint64_t value; |
| 108 | 108 | ||
| 109 | test_case("leading zeros are accepted outside bencode"); | 109 | test_case("leading zeros are accepted outside bencode"); |
| 110 | CHECK_INT(scan_udec("007", &value, 65535), 3); | 110 | CHECK_INT(scan_uint("007", &value, 65535), 3); |
| 111 | CHECK_INT(value, 7); | 111 | CHECK_INT(value, 7); |
| 112 | CHECK_INT(scan_udec("0000", &value, 65535), 4); | 112 | CHECK_INT(scan_uint("0000", &value, 65535), 4); |
| 113 | CHECK_INT(value, 0); | 113 | CHECK_INT(value, 0); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| @@ -117,9 +117,9 @@ static void case_bencode_rejects_leading_zeros(void) { | |||
| 117 | uint64_t value = 0xdead; | 117 | uint64_t value = 0xdead; |
| 118 | 118 | ||
| 119 | test_case("bencode refuses a leading zero on anything but zero"); | 119 | test_case("bencode refuses a leading zero on anything but zero"); |
| 120 | CHECK_INT(scan_udec_bencode("007", &value, 65535), 0); | 120 | CHECK_INT(scan_uint_bencode("007", &value, 65535), 0); |
| 121 | CHECK_INT(scan_udec_bencode("0000", &value, 65535), 0); | 121 | CHECK_INT(scan_uint_bencode("0000", &value, 65535), 0); |
| 122 | CHECK_INT(scan_udec_bencode("01", &value, 65535), 0); | 122 | CHECK_INT(scan_uint_bencode("01", &value, 65535), 0); |
| 123 | CHECK_INT(value, 0xdead); | 123 | CHECK_INT(value, 0xdead); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| @@ -127,11 +127,11 @@ static void case_bencode_accepts_canonical(void) { | |||
| 127 | uint64_t value; | 127 | uint64_t value; |
| 128 | 128 | ||
| 129 | test_case("bencode accepts a canonically written number"); | 129 | test_case("bencode accepts a canonically written number"); |
| 130 | CHECK_INT(scan_udec_bencode("0", &value, 65535), 1); | 130 | CHECK_INT(scan_uint_bencode("0", &value, 65535), 1); |
| 131 | CHECK_INT(value, 0); | 131 | CHECK_INT(value, 0); |
| 132 | CHECK_INT(scan_udec_bencode("0:", &value, 65535), 1); | 132 | CHECK_INT(scan_uint_bencode("0:", &value, 65535), 1); |
| 133 | CHECK_INT(value, 0); | 133 | CHECK_INT(value, 0); |
| 134 | CHECK_INT(scan_udec_bencode("160:", &value, 65535), 3); | 134 | CHECK_INT(scan_uint_bencode("160:", &value, 65535), 3); |
| 135 | CHECK_INT(value, 160); | 135 | CHECK_INT(value, 160); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| @@ -139,14 +139,64 @@ static void case_bencode_inherits_the_rest(void) { | |||
| 139 | uint64_t value = 0xdead; | 139 | uint64_t value = 0xdead; |
| 140 | 140 | ||
| 141 | test_case("bencode is no laxer than the plain scanner"); | 141 | test_case("bencode is no laxer than the plain scanner"); |
| 142 | CHECK_INT(scan_udec_bencode(" 1", &value, 65535), 0); | 142 | CHECK_INT(scan_uint_bencode(" 1", &value, 65535), 0); |
| 143 | CHECK_INT(scan_udec_bencode("-1", &value, 65535), 0); | 143 | CHECK_INT(scan_uint_bencode("-1", &value, 65535), 0); |
| 144 | CHECK_INT(scan_udec_bencode("+1", &value, 65535), 0); | 144 | CHECK_INT(scan_uint_bencode("+1", &value, 65535), 0); |
| 145 | CHECK_INT(scan_udec_bencode("65536", &value, 65535), 0); | 145 | CHECK_INT(scan_uint_bencode("65536", &value, 65535), 0); |
| 146 | CHECK_INT(value, 0xdead); | 146 | CHECK_INT(value, 0xdead); |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | /* ------------------------------------------- fixed width signed integers */ | ||
| 150 | |||
| 151 | /* A value lifted out of a query string arrives as a pointer and a length | ||
| 152 | with nothing terminating it, and the whole of it has to be the number. */ | ||
| 153 | |||
| 154 | static void case_int_whole_field(void) { | ||
| 155 | int64_t value = 0; | ||
| 156 | |||
| 157 | test_case("the whole field is read, sign and all"); | ||
| 158 | CHECK_INT(scan_int("123", 3, &value), 0); | ||
| 159 | CHECK_INT(value, 123); | ||
| 160 | CHECK_INT(scan_int("-45", 3, &value), 0); | ||
| 161 | CHECK_INT(value, -45); | ||
| 162 | |||
| 163 | test_case("and only as far as the length given"); | ||
| 164 | CHECK_INT(scan_int("12345", 3, &value), 0); | ||
| 165 | CHECK_INT(value, 123); | ||
| 166 | } | ||
| 167 | |||
| 168 | static void case_int_rejects_the_rest(void) { | ||
| 169 | int64_t value = 4711; | ||
| 170 | |||
| 171 | test_case("anything that is not all digits is refused"); | ||
| 172 | CHECK_INT(scan_int("12a", 3, &value), -1); | ||
| 173 | CHECK_INT(scan_int("", 0, &value), -1); | ||
| 174 | CHECK_INT(scan_int("-", 1, &value), -1); | ||
| 175 | CHECK_INT(scan_int(" 12", 3, &value), -1); | ||
| 176 | CHECK_INT(scan_int("+12", 3, &value), -1); | ||
| 177 | |||
| 178 | test_case("and a refused field leaves the number alone"); | ||
| 179 | CHECK_INT(value, 4711); | ||
| 180 | } | ||
| 181 | |||
| 182 | static void case_int_overflow(void) { | ||
| 183 | int64_t value = 0; | ||
| 184 | |||
| 185 | test_case("a field too long to fit is refused rather than wrapped"); | ||
| 186 | CHECK_INT(scan_int("9223372036854775807", 19, &value), 0); | ||
| 187 | CHECK_INT(value, INT64_MAX); | ||
| 188 | CHECK_INT(scan_int("9223372036854775808", 19, &value), -1); | ||
| 189 | CHECK_INT(scan_int("99999999999999999999", 20, &value), -1); | ||
| 190 | |||
| 191 | test_case("including the negative side"); | ||
| 192 | CHECK_INT(scan_int("-9223372036854775807", 20, &value), 0); | ||
| 193 | CHECK_INT(value, -INT64_MAX); | ||
| 194 | } | ||
| 195 | |||
| 149 | void test_scan(void) { | 196 | void test_scan(void) { |
| 197 | case_int_whole_field(); | ||
| 198 | case_int_rejects_the_rest(); | ||
| 199 | case_int_overflow(); | ||
| 150 | case_plain_numbers(); | 200 | case_plain_numbers(); |
| 151 | case_stops_at_non_digit(); | 201 | case_stops_at_non_digit(); |
| 152 | case_rejects_whitespace(); | 202 | case_rejects_whitespace(); |
diff --git a/tests/t_urlencoded.c b/tests/t_urlencoded.c index 1239e6b..6e0ee31 100644 --- a/tests/t_urlencoded.c +++ b/tests/t_urlencoded.c | |||
| @@ -228,33 +228,6 @@ static void case_find_keywords(void) { | |||
| 228 | CHECK_INT(urlencoded_match_keyword(keywords, &p, SCAN_SEARCHPATH_PARAM), -3); | 228 | CHECK_INT(urlencoded_match_keyword(keywords, &p, SCAN_SEARCHPATH_PARAM), -3); |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | static void case_fixed_int(void) { | ||
| 232 | char positive[] = "123"; | ||
| 233 | char negative[] = "-45"; | ||
| 234 | char trailing[] = "12a"; | ||
| 235 | int value; | ||
| 236 | |||
| 237 | test_case("scan_fixed_int returns the count of unparsed bytes"); | ||
| 238 | CHECK_INT(scan_fixed_int(positive, 3, &value), 0); | ||
| 239 | CHECK_INT(value, 123); | ||
| 240 | |||
| 241 | CHECK_INT(scan_fixed_int(negative, 3, &value), 0); | ||
| 242 | CHECK_INT(value, -45); | ||
| 243 | |||
| 244 | CHECK_INT(scan_fixed_int(trailing, 3, &value), 1); | ||
| 245 | CHECK_INT(value, 12); | ||
| 246 | } | ||
| 247 | |||
| 248 | static void case_fixed_int_bounded(void) { | ||
| 249 | char digits[] = "12345"; | ||
| 250 | int value; | ||
| 251 | |||
| 252 | test_case("scan_fixed_int honours the length it is given"); | ||
| 253 | CHECK_INT(scan_fixed_int(digits, 3, &value), 0); | ||
| 254 | CHECK_INT(value, 123); | ||
| 255 | } | ||
| 256 | |||
| 257 | |||
| 258 | /* The encoding direction. Which bytes survive unescaped is fixed by what | 231 | /* The encoding direction. Which bytes survive unescaped is fixed by what |
| 259 | existing parsers of the urlencoded full scrape expect, so these cases pin | 232 | existing parsers of the urlencoded full scrape expect, so these cases pin |
| 260 | the set rather than describe a preference. */ | 233 | the set rather than describe a preference. */ |
| @@ -361,8 +334,6 @@ void test_urlencoded(void) { | |||
| 361 | case_raw_high_byte(); | 334 | case_raw_high_byte(); |
| 362 | case_skipvalue(); | 335 | case_skipvalue(); |
| 363 | case_find_keywords(); | 336 | case_find_keywords(); |
| 364 | case_fixed_int(); | ||
| 365 | case_fixed_int_bounded(); | ||
| 366 | case_fmt_passes_safe_bytes(); | 337 | case_fmt_passes_safe_bytes(); |
| 367 | case_fmt_escapes_the_rest(); | 338 | case_fmt_escapes_the_rest(); |
| 368 | case_fmt_hex_is_lower_case(); | 339 | case_fmt_hex_is_lower_case(); |
