strparse: switch to curl_off_t as base data type

- add hex and octal parsers to the Curl_str_* family
- make curlx_strtoofft use these parsers
- remove all use of strtol() and strtoul() in library code
- generally use Curl_str_* more than strtoofft, for stricter parsing
- supports 64-bit universally, instead of 'long' which differs in size
  between platforms

Extended the unit test 1664 to verify hex and octal parsing.

Closes #16336
This commit is contained in:
Daniel Stenberg 2025-02-14 11:29:08 +01:00
parent 876db1070b
commit b4538ec522
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
46 changed files with 538 additions and 497 deletions

View File

@ -3,3 +3,5 @@ banfunc strncpy
banfunc sscanf
banfunc snprintf
banfunc vsnprint
banfunc strtoul
banfunc strtol

View File

@ -226,6 +226,7 @@ LIB_CFILES = \
splay.c \
strcase.c \
strdup.c \
strequal.c \
strerror.c \
strparse.c \
strtok.c \

View File

@ -159,10 +159,10 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line)
struct Curl_str srcalpn;
struct Curl_str dstalpn;
struct Curl_str date;
size_t srcport;
size_t dstport;
size_t persist;
size_t prio;
curl_off_t srcport;
curl_off_t dstport;
curl_off_t persist;
curl_off_t prio;
if(Curl_str_word(&line, &srcalpn, MAX_ALTSVC_ALPNLEN) ||
Curl_str_singlespace(&line) ||
@ -193,8 +193,8 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line)
memcpy(dbuf, date.str, date.len);
dbuf[date.len] = 0;
expires = Curl_getdate_capped(dbuf);
as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn, srcport,
dstport);
as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn,
(size_t)srcport, (size_t)dstport);
if(as) {
as->expires = expires;
as->prio = 0; /* not supported to just set zero */
@ -465,10 +465,11 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
return */
static time_t altsvc_debugtime(void *unused)
{
char *timestr = getenv("CURL_TIME");
const char *timestr = getenv("CURL_TIME");
(void)unused;
if(timestr) {
long val = strtol(timestr, NULL, 10);
curl_off_t val;
Curl_str_number(&timestr, &val, TIME_T_MAX);
return (time_t)val;
}
return time(NULL);
@ -528,7 +529,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
size_t dstlen = 0; /* destination hostname length */
const char *value_ptr;
char option[32];
size_t num;
curl_off_t num;
bool quoted = FALSE;
time_t maxage = 24 * 3600; /* default is 24 hours */
bool persist = FALSE;
@ -566,7 +567,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
dstlen = strlen(srchost);
}
if(*p == ':') {
size_t port = 0;
curl_off_t port = 0;
p++;
if(Curl_str_number(&p, &port, 0xffff) || (*p != '\"')) {
infof(data, "Unknown alt-svc port number, ignoring.");
@ -617,7 +618,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
p++;
}
if(!Curl_str_number(&value_ptr, &num, SIZE_T_MAX)) {
if(!Curl_str_number(&value_ptr, &num, TIME_T_MAX)) {
if(strcasecompare("ma", option))
maxage = (time_t)num;
else if(strcasecompare("persist", option) && (num == 1))

View File

@ -742,7 +742,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
Curl_printable_address. The latter returns only numeric scope
IDs and the former returns none at all. So the scope ID, if
present, is known to be numeric */
size_t scope_id;
curl_off_t scope_id;
if(Curl_str_number((const char **)&scope_ptr, &scope_id, UINT_MAX))
return CURLE_UNSUPPORTED_PROTOCOL;
si6->sin6_scope_id = (unsigned int)scope_id;
@ -974,28 +974,28 @@ static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
#ifdef DEBUGBUILD
{
char *p = getenv("CURL_DBG_SOCK_WBLOCK");
const char *p = getenv("CURL_DBG_SOCK_WBLOCK");
if(p) {
long l = strtol(p, NULL, 10);
if(l >= 0 && l <= 100)
curl_off_t l;
if(!Curl_str_number(&p, &l, 100))
ctx->wblock_percent = (int)l;
}
p = getenv("CURL_DBG_SOCK_WPARTIAL");
if(p) {
long l = strtol(p, NULL, 10);
if(l >= 0 && l <= 100)
curl_off_t l;
if(!Curl_str_number(&p, &l, 100))
ctx->wpartial_percent = (int)l;
}
p = getenv("CURL_DBG_SOCK_RBLOCK");
if(p) {
long l = strtol(p, NULL, 10);
if(l >= 0 && l <= 100)
curl_off_t l;
if(!Curl_str_number(&p, &l, 100))
ctx->rblock_percent = (int)l;
}
p = getenv("CURL_DBG_SOCK_RMAX");
if(p) {
long l = strtol(p, NULL, 10);
if(l >= 0)
curl_off_t l;
if(!Curl_str_number(&p, &l, SIZE_T_MAX))
ctx->recv_max = (size_t)l;
}
}

View File

@ -35,6 +35,7 @@
#include "progress.h"
#include "select.h"
#include "warnless.h"
#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -883,11 +884,11 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
{
/* Allow debug builds to override this logic to force short sends
*/
char *p = getenv("CURL_SMALLSENDS");
const char *p = getenv("CURL_SMALLSENDS");
if(p) {
size_t altsize = (size_t)strtoul(p, NULL, 10);
if(altsize)
write_len = CURLMIN(write_len, altsize);
curl_off_t altsize;
if(!Curl_str_number(&p, &altsize, SIZE_T_MAX))
write_len = CURLMIN(write_len, (size_t)altsize);
}
}
#endif

View File

@ -41,6 +41,7 @@
#include "connect.h"
#include "select.h"
#include "strcase.h"
#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -682,10 +683,10 @@ static void cpool_close_and_destroy_all(struct cpool *cpool)
/* Just for testing, run graceful shutdown */
#ifdef DEBUGBUILD
{
char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
const char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
if(p) {
long l = strtol(p, NULL, 10);
if(l > 0 && l < INT_MAX)
curl_off_t l;
if(!Curl_str_number(&p, &l, INT_MAX))
timeout_ms = (int)l;
}
}

View File

@ -80,7 +80,6 @@ Example set of cookies:
#include "sendf.h"
#include "slist.h"
#include "share.h"
#include "strtoofft.h"
#include "strcase.h"
#include "curl_get_line.h"
#include "curl_memrchr.h"
@ -89,6 +88,7 @@ Example set of cookies:
#include "fopen.h"
#include "strdup.h"
#include "llist.h"
#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -708,21 +708,22 @@ parse_cookie_header(struct Curl_easy *data,
* client should discard the cookie. A value of zero means the
* cookie should be discarded immediately.
*/
CURLofft offt;
int rc;
const char *maxage = valuep;
offt = curlx_strtoofft((*maxage == '\"') ?
&maxage[1] : &maxage[0], NULL, 10,
&co->expires);
switch(offt) {
case CURL_OFFT_FLOW:
if(*maxage == '\"')
maxage++;
rc = Curl_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);
switch(rc) {
case STRE_OVERFLOW:
/* overflow, used max value */
co->expires = CURL_OFF_T_MAX;
break;
case CURL_OFFT_INVAL:
default:
/* negative or otherwise bad, expire */
co->expires = 1;
break;
case CURL_OFFT_OK:
case STRE_OK:
if(!co->expires)
/* already expired */
co->expires = 1;
@ -915,16 +916,8 @@ parse_netscape(struct Cookie *co,
}
break;
case 4:
{
char *endp;
const char *p;
/* make sure curlx_strtoofft won't read past the current field */
for(p = ptr; p < &ptr[len] && ISDIGIT(*p); ++p)
;
if(p == ptr || p != &ptr[len] ||
curlx_strtoofft(ptr, &endp, 10, &co->expires) || endp != &ptr[len])
return CERR_RANGE;
}
if(Curl_str_number(&ptr, &co->expires, CURL_OFF_T_MAX))
return CERR_RANGE;
break;
case 5:
co->name = Curl_memdup0(ptr, len);

View File

@ -37,6 +37,7 @@
#define ISCNTRL(x) (ISLOWCNTRL(x) || IS7F(x))
#define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
#define ISXDIGIT(x) (ISDIGIT(x) || ISLOWHEXALHA(x) || ISUPHEXALHA(x))
#define ISODIGIT(x) (((x) >= '0') && ((x) <= '7'))
#define ISALNUM(x) (ISDIGIT(x) || ISLOWER(x) || ISUPPER(x))
#define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z'))
#define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z'))

View File

@ -26,7 +26,7 @@
#include <curl/curl.h>
#include "curl_range.h"
#include "sendf.h"
#include "strtoofft.h"
#include "strparse.h"
/* Only include this function if one or more of FTP, FILE are enabled. */
#if !defined(CURL_DISABLE_FTP) || !defined(CURL_DISABLE_FILE)
@ -37,28 +37,29 @@
*/
CURLcode Curl_range(struct Curl_easy *data)
{
curl_off_t from, to;
char *ptr;
char *ptr2;
if(data->state.use_range && data->state.range) {
CURLofft from_t;
CURLofft to_t;
from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
if(from_t == CURL_OFFT_FLOW)
curl_off_t from, to;
bool first_num = TRUE;
const char *p = data->state.range;
if(Curl_str_number(&p, &from, CURL_OFF_T_MAX))
first_num = FALSE;
if(Curl_str_single(&p, '-'))
/* no leading dash or after the first number is an error */
return CURLE_RANGE_ERROR;
while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
ptr++;
to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
if(to_t == CURL_OFFT_FLOW)
return CURLE_RANGE_ERROR;
if((to_t == CURL_OFFT_INVAL) && !from_t) {
if(Curl_str_number(&p, &to, CURL_OFF_T_MAX)) {
/* no second number */
/* X - */
data->state.resume_from = from;
DEBUGF(infof(data, "RANGE %" FMT_OFF_T " to end of file", from));
}
else if((from_t == CURL_OFFT_INVAL) && !to_t) {
else if(!first_num) {
/* -Y */
if(!to)
/* "-0" is just wrong */
return CURLE_RANGE_ERROR;
data->req.maxdownload = to;
data->state.resume_from = -to;
DEBUGF(infof(data, "RANGE the last %" FMT_OFF_T " bytes", to));

View File

@ -54,7 +54,6 @@
#include "ftplistparser.h"
#include "curl_range.h"
#include "curl_krb5.h"
#include "strtoofft.h"
#include "strcase.h"
#include "vtls/vtls.h"
#include "cfilters.h"
@ -473,7 +472,7 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data)
r += pp->nfinal;
if(LASTLINE(r)) {
size_t status;
curl_off_t status;
if(!Curl_str_number(&r, &status, 999) && (status == 226)) {
/* funny timing situation where we get the final message on the
control connection before traffic on the data connection has been
@ -544,7 +543,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
const char *line, size_t len, int *code)
{
size_t status;
curl_off_t status;
(void)data;
(void)conn;
@ -929,8 +928,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(ip_end) {
const char *portp = strchr(ip_end, ':');
if(portp) {
size_t start;
size_t end;
curl_off_t start;
curl_off_t end;
portp++;
if(!Curl_str_number(&portp, &start, 0xffff)) {
/* got the first number */
@ -1767,7 +1766,7 @@ static bool match_pasv_6nums(const char *p,
{
int i;
for(i = 0; i < 6; i++) {
size_t num;
curl_off_t num;
if(i) {
if(*p != ',')
return FALSE;
@ -1805,11 +1804,9 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
ptr++;
/* |||12345| */
sep = ptr[0];
/* the ISDIGIT() check here is because strtoul() accepts leading minus
etc */
if((ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) {
const char *p = &ptr[3];
size_t num;
curl_off_t num;
if(Curl_str_number(&p, &num, 0xffff) || (*p != sep)) {
failf(data, "Illegal port number in EPSV reply");
return CURLE_FTP_WEIRD_PASV_REPLY;
@ -2297,7 +2294,7 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
for all the digits at the end of the response and parse only those as a
number. */
char *start = &buf[4];
char *fdigit = memchr(start, '\r', len);
const char *fdigit = memchr(start, '\r', len);
if(fdigit) {
fdigit--;
if(*fdigit == '\n')
@ -2307,9 +2304,8 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
}
else
fdigit = start;
/* ignores parsing errors, which will make the size remain unknown */
(void)curlx_strtoofft(fdigit, NULL, 10, &filesize);
if(Curl_str_number(&fdigit, &filesize, CURL_OFF_T_MAX))
filesize = -1; /* size remain unknown */
}
else if(ftpcode == 550) { /* "No such file or directory" */
/* allow a SIZE failure for (resumed) uploads, when probing what command
@ -2471,7 +2467,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
* those cases only confuses us.
*
* Example D above makes this parsing a little tricky */
char *bytes;
const char *bytes;
char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf);
bytes = strstr(buf, " bytes");
if(bytes) {
@ -2493,7 +2489,8 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
if(bytes) {
++bytes;
/* get the number! */
(void)curlx_strtoofft(bytes, NULL, 10, &size);
if(Curl_str_number(&bytes, &size, CURL_OFF_T_MAX))
size = 1;
}
}
}

View File

@ -547,7 +547,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->item_length ++;
if(c == ' ') {
const char *p = &mem[parser->item_offset];
size_t hlinks;
curl_off_t hlinks;
mem[parser->item_offset + parser->item_length - 1] = 0;
if(!Curl_str_number(&p, &hlinks, LONG_MAX)) {

View File

@ -28,10 +28,10 @@
#include "urldata.h"
#include "getinfo.h"
#include "vtls/vtls.h"
#include "connect.h" /* Curl_getconnectinfo() */
#include "progress.h"
#include "strparse.h"
/* The last #include files should be: */
#include "curl_memory.h"
@ -204,9 +204,10 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
} lptr;
#ifdef DEBUGBUILD
char *timestr = getenv("CURL_TIME");
const char *timestr = getenv("CURL_TIME");
if(timestr) {
unsigned long val = strtoul(timestr, NULL, 10);
curl_off_t val;
Curl_str_number(&timestr, &val, TIME_T_MAX);
switch(info) {
case CURLINFO_LOCAL_PORT:
*param_longp = (long)val;
@ -218,7 +219,8 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
/* use another variable for this to allow different values */
timestr = getenv("CURL_DEBUG_SIZE");
if(timestr) {
unsigned long val = strtoul(timestr, NULL, 10);
curl_off_t val;
Curl_str_number(&timestr, &val, LONG_MAX);
switch(info) {
case CURLINFO_HEADER_SIZE:
case CURLINFO_REQUEST_SIZE:
@ -379,9 +381,11 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
curl_off_t *param_offt)
{
#ifdef DEBUGBUILD
char *timestr = getenv("CURL_TIME");
const char *timestr = getenv("CURL_TIME");
if(timestr) {
unsigned long val = strtoul(timestr, NULL, 10);
curl_off_t val;
Curl_str_number(&timestr, &val, CURL_OFF_T_MAX);
switch(info) {
case CURLINFO_TOTAL_TIME_T:
case CURLINFO_NAMELOOKUP_TIME_T:
@ -476,9 +480,11 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
double *param_doublep)
{
#ifdef DEBUGBUILD
char *timestr = getenv("CURL_TIME");
const char *timestr = getenv("CURL_TIME");
if(timestr) {
unsigned long val = strtoul(timestr, NULL, 10);
curl_off_t val;
Curl_str_number(&timestr, &val, CURL_OFF_T_MAX);
switch(info) {
case CURLINFO_TOTAL_TIME:
case CURLINFO_NAMELOOKUP_TIME:

View File

@ -1134,7 +1134,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
if(!hostp->data)
continue;
if(hostp->data[0] == '-') {
size_t num = 0;
curl_off_t num = 0;
size_t entry_len;
size_t hlen = 0;
host_end = strchr(&hostp->data[1], ':');
@ -1173,7 +1173,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
const char *addr_begin;
const char *addr_end;
const char *port_ptr;
size_t port = 0;
curl_off_t port = 0;
const char *end_ptr;
bool permanent = TRUE;
bool error = TRUE;
@ -1273,8 +1273,8 @@ err:
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
if(dns) {
infof(data, "RESOLVE %.*s:%zd - old addresses discarded",
(int)hlen, host_begin, port);
infof(data, "RESOLVE %.*s:%" CURL_FORMAT_CURL_OFF_T
" - old addresses discarded", (int)hlen, host_begin, port);
/* delete old entry, there are two reasons for this
1. old entry may have different addresses.
2. even if entry with correct addresses is already in the cache,
@ -1306,14 +1306,15 @@ err:
return CURLE_OUT_OF_MEMORY;
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
infof(data, "Added %.*s:%zd:%s to DNS cache%s",
infof(data, "Added %.*s:%" CURL_FORMAT_CURL_OFF_T ":%s to DNS cache%s",
(int)hlen, host_begin, port, addresses,
permanent ? "" : " (non-permanent)");
#endif
/* Wildcard hostname */
if((hlen == 1) && (host_begin[0] == '*')) {
infof(data, "RESOLVE *:%zd using wildcard", port);
infof(data, "RESOLVE *:%" CURL_FORMAT_CURL_OFF_T " using wildcard",
port);
data->state.wildcard_resolve = TRUE;
}
}

View File

@ -35,7 +35,6 @@
#include "curl_get_line.h"
#include "strcase.h"
#include "sendf.h"
#include "strtoofft.h"
#include "parsedate.h"
#include "fopen.h"
#include "rename.h"
@ -59,13 +58,12 @@
time_t deltatime; /* allow for "adjustments" for unit test purposes */
static time_t hsts_debugtime(void *unused)
{
char *timestr = getenv("CURL_TIME");
const char *timestr = getenv("CURL_TIME");
(void)unused;
if(timestr) {
curl_off_t val;
(void)curlx_strtoofft(timestr, NULL, 10, &val);
val += (curl_off_t)deltatime;
if(!Curl_str_number(&timestr, &val, TIME_T_MAX))
val += (curl_off_t)deltatime;
return (time_t)val;
}
return time(NULL);
@ -160,8 +158,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
p++;
if(strncasecompare("max-age", p, 7)) {
bool quoted = FALSE;
CURLofft offt;
char *endp;
int rc;
if(gotma)
return CURLE_BAD_FUNCTION_ARGUMENT;
@ -178,13 +175,13 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
p++;
quoted = TRUE;
}
offt = curlx_strtoofft(p, &endp, 10, &expires);
if(offt == CURL_OFFT_FLOW)
rc = Curl_str_number(&p, &expires, TIME_T_MAX);
if(rc == STRE_OVERFLOW)
expires = CURL_OFF_T_MAX;
else if(offt)
else if(rc)
/* invalid max-age */
return CURLE_BAD_FUNCTION_ARGUMENT;
p = endp;
if(quoted) {
if(*p != '\"')
return CURLE_BAD_FUNCTION_ARGUMENT;

View File

@ -86,6 +86,7 @@
#include "hsts.h"
#include "ws.h"
#include "curl_ctype.h"
#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -3072,11 +3073,10 @@ static CURLcode http_header(struct Curl_easy *data,
/* if it truly stopped on a digit */
if(ISDIGIT(*ptr)) {
if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
if(data->state.resume_from == k->offset)
/* we asked for a resume and we got it */
k->content_range = TRUE;
}
if(!Curl_str_number(&ptr, &k->offset, CURL_OFF_T_MAX) &&
(data->state.resume_from == k->offset))
/* we asked for a resume and we got it */
k->content_range = TRUE;
}
else if(k->httpcode < 300)
data->state.resume_from = 0; /* get everything */

View File

@ -64,7 +64,7 @@
#include "socks.h"
#include "imap.h"
#include "mime.h"
#include "strtoofft.h"
#include "strparse.h"
#include "strcase.h"
#include "vtls/vtls.h"
#include "cfilters.h"
@ -1156,9 +1156,9 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
the continuation data contained within the curly brackets */
ptr = memchr(ptr, '{', len);
if(ptr) {
char *endptr;
if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) &&
(endptr - ptr > 1 && *endptr == '}'))
ptr++;
if(!Curl_str_number(&ptr, &size, CURL_OFF_T_MAX) &&
!Curl_str_single(&ptr, '}'))
parsed = TRUE;
}

View File

@ -728,7 +728,9 @@ static void _ldap_trace(const char *fmt, ...)
if(do_trace == -1) {
const char *env = getenv("CURL_TRACE");
do_trace = (env && strtol(env, NULL, 10) > 0);
curl_off_t e = 0;
if(!Curl_str_number(&env, &e, INT_MAX))
do_trace = e > 0;
}
if(!do_trace)
return;

View File

@ -560,7 +560,9 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
#ifdef CURL_OPENLDAP_DEBUG
if(do_trace < 0) {
const char *env = getenv("CURL_OPENLDAP_TRACE");
do_trace = (env && strtol(env, NULL, 10) > 0);
curl_off_t e = 0;
if(!Curl_str_number(&env, &e, INT_MAX))
do_trace = e > 0;
}
if(do_trace)
ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);

View File

@ -420,7 +420,7 @@ static int parsedate(const char *date, time_t *output)
date = end;
}
else {
size_t lval;
curl_off_t lval;
int num_digits = 0;
const char *p = date;
if(Curl_str_number(&p, &lval, 99999999))

View File

@ -34,6 +34,7 @@
#include "sendf.h"
#include "transfer.h"
#include "url.h"
#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -194,11 +195,11 @@ static CURLcode xfer_send(struct Curl_easy *data,
/* Allow debug builds to override this logic to force short initial
sends */
size_t body_len = blen - hds_len;
char *p = getenv("CURL_SMALLREQSEND");
const char *p = getenv("CURL_SMALLREQSEND");
if(p) {
size_t body_small = (size_t)strtoul(p, NULL, 10);
if(body_small && body_small < body_len)
blen = hds_len + body_small;
curl_off_t body_small;
if(!Curl_str_number(&p, &body_small, body_len))
blen = hds_len + (size_t)body_small;
}
}
#endif

View File

@ -926,7 +926,7 @@ CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len)
CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
{
if(checkprefix("CSeq:", header)) {
size_t CSeq = 0;
curl_off_t CSeq = 0;
struct RTSP *rtsp = data->req.p.rtsp;
const char *p = &header[5];
while(ISBLANK(*p))
@ -1007,7 +1007,7 @@ CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport)
start++;
end = strchr(start, ';');
if(checkprefix("interleaved=", start)) {
size_t chan1, chan2, chan;
curl_off_t chan1, chan2, chan;
const char *p = start + 12;
if(!Curl_str_number(&p, &chan1, 255)) {
unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;

View File

@ -215,7 +215,7 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
only send the response code instead as per Section 4.2. */
if(line[3] == ' ' || len == 5) {
char tmpline[6];
size_t code;
curl_off_t code;
const char *p = tmpline;
result = TRUE;
memcpy(tmpline, line, (len == 5 ? 5 : 3));

View File

@ -82,65 +82,6 @@ char Curl_raw_tolower(char in)
return (char)tolowermap[(unsigned char) in];
}
/*
* curl_strequal() is for doing "raw" case insensitive strings. This is meant
* to be locale independent and only compare strings we know are safe for
* this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
* further explanations as to why this function is necessary.
*/
static int casecompare(const char *first, const char *second)
{
while(*first) {
if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
/* get out of the loop as soon as they do not match */
return 0;
first++;
second++;
}
/* If we are here either the strings are the same or the length is different.
We can just test if the "current" character is non-zero for one and zero
for the other. Note that the characters may not be exactly the same even
if they match, we only want to compare zero-ness. */
return !*first == !*second;
}
/* --- public function --- */
int curl_strequal(const char *first, const char *second)
{
if(first && second)
/* both pointers point to something then compare them */
return casecompare(first, second);
/* if both pointers are NULL then treat them as equal */
return NULL == first && NULL == second;
}
static int ncasecompare(const char *first, const char *second, size_t max)
{
while(*first && max) {
if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
return 0;
max--;
first++;
second++;
}
if(0 == max)
return 1; /* they are equal this far */
return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
}
/* --- public function --- */
int curl_strnequal(const char *first, const char *second, size_t max)
{
if(first && second)
/* both pointers point to something then compare them */
return ncasecompare(first, second, max);
/* if both pointers are NULL then treat them as equal if max is non-zero */
return NULL == first && NULL == second && max;
}
/* Copy an upper case version of the string from src to dest. The
* strings may overlap. No more than n characters of the string are copied
* (including any NUL) and the destination string will NOT be

88
lib/strequal.c Normal file
View File

@ -0,0 +1,88 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#include <curl/curl.h>
#include "strcase.h"
/*
* curl_strequal() is for doing "raw" case insensitive strings. This is meant
* to be locale independent and only compare strings we know are safe for
* this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
* further explanations as to why this function is necessary.
*/
static int casecompare(const char *first, const char *second)
{
while(*first) {
if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
/* get out of the loop as soon as they do not match */
return 0;
first++;
second++;
}
/* If we are here either the strings are the same or the length is different.
We can just test if the "current" character is non-zero for one and zero
for the other. Note that the characters may not be exactly the same even
if they match, we only want to compare zero-ness. */
return !*first == !*second;
}
static int ncasecompare(const char *first, const char *second, size_t max)
{
while(*first && max) {
if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
return 0;
max--;
first++;
second++;
}
if(0 == max)
return 1; /* they are equal this far */
return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
}
/* --- public function --- */
int curl_strequal(const char *first, const char *second)
{
if(first && second)
/* both pointers point to something then compare them */
return casecompare(first, second);
/* if both pointers are NULL then treat them as equal */
return NULL == first && NULL == second;
}
/* --- public function --- */
int curl_strnequal(const char *first, const char *second, size_t max)
{
if(first && second)
/* both pointers point to something then compare them */
return ncasecompare(first, second, max);
/* if both pointers are NULL then treat them as equal if max is non-zero */
return NULL == first && NULL == second && max;
}

View File

@ -23,6 +23,7 @@
***************************************************************************/
#include "strparse.h"
#include "strcase.h"
/* Get a word until the first DELIM or end of string. At least one byte long.
return non-zero on error */
@ -103,28 +104,64 @@ int Curl_str_singlespace(const char **linep)
return Curl_str_single(linep, ' ');
}
/* Get an unsigned number. Leading zeroes are accepted.
return non-zero on error */
int Curl_str_number(const char **linep, size_t *nump, size_t max)
/* given an ASCII hexadecimal character, return the value */
#define HEXDIGIT2NUM(x) \
(((x) > '9') ? Curl_raw_tolower(x) - 'a' + 10 : x - '0')
/* given an ASCII character and a given base, return TRUE if valid */
#define valid_digit(digit, base) \
(((base == 10) && ISDIGIT(digit)) || \
((base == 16) && ISXDIGIT(digit)) || \
((base == 8) && ISODIGIT(digit)))
/* given an ASCII character and a given base, return the value */
#define num_digit(digit, base) \
((base != 16) ? digit - '0' : HEXDIGIT2NUM(digit))
/* no support for 0x prefix nor leading spaces */
static int str_num_base(const char **linep, curl_off_t *nump, curl_off_t max,
int base) /* 8, 10 or 16, nothing else */
{
size_t num = 0;
curl_off_t num = 0;
DEBUGASSERT(linep && *linep && nump);
DEBUGASSERT((base == 8) || (base == 10) || (base == 16));
*nump = 0;
if(!ISDIGIT(**linep))
if(!valid_digit(**linep, base))
return STRE_NO_NUM;
do {
int n = **linep - '0';
if(num > ((SIZE_T_MAX - n) / 10))
int n = num_digit(**linep, base);
if(num > ((CURL_OFF_T_MAX - n) / base))
return STRE_OVERFLOW;
num = num * 10 + n;
num = num * base + n;
if(num > max)
return STRE_BIG; /** too big */
(*linep)++;
} while(ISDIGIT(**linep));
} while(valid_digit(**linep, base));
*nump = num;
return STRE_OK;
}
/* Get an unsigned decimal number with no leading space or minus. Leading
zeroes are accepted. return non-zero on error */
int Curl_str_number(const char **linep, curl_off_t *nump, curl_off_t max)
{
return str_num_base(linep, nump, max, 10);
}
/* Get an unsigned hexadecimal number with no leading space or minus and no
"0x" support. Leading zeroes are accepted. return non-zero on error */
int Curl_str_hex(const char **linep, curl_off_t *nump, curl_off_t max)
{
return str_num_base(linep, nump, max, 16);
}
/* Get an unsigned octal number with no leading space or minus and no "0"
prefix support. Leading zeroes are accepted. return non-zero on error */
int Curl_str_octal(const char **linep, curl_off_t *nump, curl_off_t max)
{
return str_num_base(linep, nump, max, 8);
}
/* CR or LF
return non-zero on error */
int Curl_str_newline(const char **linep)

View File

@ -62,9 +62,14 @@ int Curl_str_single(const char **linep, char byte);
return non-zero on error */
int Curl_str_singlespace(const char **linep);
/* Get an unsigned number
return non-zero on error */
int Curl_str_number(const char **linep, size_t *nump, size_t max);
/* Get an unsigned decimal number. Return non-zero on error */
int Curl_str_number(const char **linep, curl_off_t *nump, curl_off_t max);
/* Get an unsigned hexadecimal number. Return non-zero on error */
int Curl_str_hex(const char **linep, curl_off_t *nump, curl_off_t max);
/* Get an unsigned octal number. Return non-zero on error */
int Curl_str_octal(const char **linep, curl_off_t *nump, curl_off_t max);
/* Check for CR or LF
return non-zero on error */

View File

@ -22,216 +22,36 @@
*
***************************************************************************/
#include <errno.h>
#include "curl_setup.h"
#include "strtoofft.h"
#include "strparse.h"
/*
* NOTE:
*
* In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
* could use in case strtoll() does not exist... See
* https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
*/
#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
# ifdef HAVE_STRTOLL
# define strtooff strtoll
# else
# if defined(_MSC_VER) && (_MSC_VER >= 1300)
# if defined(_SAL_VERSION)
_Check_return_ _CRTIMP __int64 __cdecl _strtoi64(
_In_z_ const char *_String,
_Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix);
# else
_CRTIMP __int64 __cdecl _strtoi64(const char *_String,
char **_EndPtr, int _Radix);
# endif
# define strtooff _strtoi64
# else
# define PRIVATE_STRTOOFF 1
# endif
# endif
#else
# define strtooff strtol
#endif
#ifdef PRIVATE_STRTOOFF
/* Range tests can be used for alphanum decoding if characters are consecutive,
like in ASCII. Else an array is scanned. Determine this condition now. */
#if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25
#define NO_RANGE_TEST
static const char valchars[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
#endif
static int get_char(char c, int base);
/**
* Custom version of the strtooff function. This extracts a curl_off_t
* value from the given input string and returns it.
*/
static curl_off_t strtooff(const char *nptr, char **endptr, int base)
{
char *end;
bool is_negative = FALSE;
bool overflow = FALSE;
int i;
curl_off_t value = 0;
/* Skip leading whitespace. */
end = (char *)nptr;
while(ISBLANK(end[0])) {
end++;
}
/* Handle the sign, if any. */
if(end[0] == '-') {
is_negative = TRUE;
end++;
}
else if(end[0] == '+') {
end++;
}
else if(end[0] == '\0') {
/* We had nothing but perhaps some whitespace -- there was no number. */
if(endptr) {
*endptr = end;
}
return 0;
}
/* Handle special beginnings, if present and allowed. */
if(end[0] == '0' && end[1] == 'x') {
if(base == 16 || base == 0) {
end += 2;
base = 16;
}
}
else if(end[0] == '0') {
if(base == 8 || base == 0) {
end++;
base = 8;
}
}
/* Matching strtol, if the base is 0 and it does not look like
* the number is octal or hex, we assume it is base 10.
*/
if(base == 0) {
base = 10;
}
/* Loop handling digits. */
for(i = get_char(end[0], base);
i != -1;
end++, i = get_char(end[0], base)) {
if(value > (CURL_OFF_T_MAX - i) / base) {
overflow = TRUE;
break;
}
value = base * value + i;
}
if(!overflow) {
if(is_negative) {
/* Fix the sign. */
value *= -1;
}
}
else {
if(is_negative)
value = CURL_OFF_T_MIN;
else
value = CURL_OFF_T_MAX;
errno = ERANGE;
}
if(endptr)
*endptr = end;
return value;
}
/**
* Returns the value of c in the given base, or -1 if c cannot
* be interpreted properly in that base (i.e., is out of range,
* is a null, etc.).
*
* @param c the character to interpret according to base
* @param base the base in which to interpret c
*
* @return the value of c in base, or -1 if c is not in range
*/
static int get_char(char c, int base)
{
#ifndef NO_RANGE_TEST
int value = -1;
if(c <= '9' && c >= '0') {
value = c - '0';
}
else if(c <= 'Z' && c >= 'A') {
value = c - 'A' + 10;
}
else if(c <= 'z' && c >= 'a') {
value = c - 'a' + 10;
}
#else
const char *cp;
int value;
cp = memchr(valchars, c, 10 + 26 + 26);
if(!cp)
return -1;
value = cp - valchars;
if(value >= 10 + 26)
value -= 26; /* Lowercase. */
#endif
if(value >= base) {
value = -1;
}
return value;
}
#endif /* Only present if we need strtoll, but do not have it. */
/*
* Parse a *positive* up to 64-bit number written in ASCII.
* Parse a positive number up to 63-bit number written in ASCII. Skip leading
* blanks. No support for prefixes.
*/
CURLofft curlx_strtoofft(const char *str, char **endp, int base,
curl_off_t *num)
{
char *end = NULL;
curl_off_t number;
errno = 0;
int rc;
*num = 0; /* clear by default */
DEBUGASSERT(base); /* starting now, avoid base zero */
DEBUGASSERT((base == 10) || (base == 16));
while(*str && ISBLANK(*str))
str++;
if(('-' == *str) || (ISSPACE(*str))) {
if(endp)
*endp = (char *)str; /* did not actually move */
return CURL_OFFT_INVAL; /* nothing parsed */
}
number = strtooff(str, &end, base);
rc = base == 10 ?
Curl_str_number(&str, &number, CURL_OFF_T_MAX) :
Curl_str_hex(&str, &number, CURL_OFF_T_MAX);
if(endp)
*endp = end;
if(errno == ERANGE)
/* overflow/underflow */
*endp = (char *)str;
if(rc == STRE_OVERFLOW)
/* overflow */
return CURL_OFFT_FLOW;
else if(str == end)
else if(rc)
/* nothing parsed */
return CURL_OFFT_INVAL;

View File

@ -26,22 +26,6 @@
#include "curl_setup.h"
/*
* Determine which string to integral data type conversion function we use
* to implement string conversion to our curl_off_t integral data type.
*
* Notice that curl_off_t might be 64 or 32 bits wide, and that it might use
* an underlying data type which might be 'long', 'int64_t', 'long long' or
* '__int64' and more remotely other data types.
*
* On systems where the size of curl_off_t is greater than the size of 'long'
* the conversion function to use is strtoll() if it is available, otherwise,
* we emulate its functionality with our own clone.
*
* On systems where the size of curl_off_t is smaller or equal than the size
* of 'long' the conversion function to use is strtol().
*/
typedef enum {
CURL_OFFT_OK, /* parsed fine */
CURL_OFFT_FLOW, /* over or underflow */

View File

@ -864,8 +864,8 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
/* Window Size */
if(strncasecompare(option, "WS", 2)) {
const char *p = arg;
size_t x = 0;
size_t y = 0;
curl_off_t x = 0;
curl_off_t y = 0;
if(Curl_str_number(&p, &x, 0xffff) ||
Curl_str_single(&p, 'x') ||
Curl_str_number(&p, &y, 0xffff)) {

View File

@ -331,7 +331,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
infof(data, "got option=(%s) value=(%s)", option, value);
if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
size_t blksize;
curl_off_t blksize;
if(Curl_str_number(&value, &blksize, TFTP_BLKSIZE_MAX)) {
failf(data, "%s (%d)", "blksize is larger than max supported",
TFTP_BLKSIZE_MAX);
@ -350,8 +350,8 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
/* could realloc pkt buffers here, but the spec does not call out
* support for the server requesting a bigger blksize than the client
* requests */
failf(data, "server requested blksize larger than allocated (%zd)",
blksize);
failf(data, "server requested blksize larger than allocated (%"
CURL_FORMAT_CURL_OFF_T ")", blksize);
return CURLE_TFTP_ILLEGAL;
}
@ -360,16 +360,17 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
state->blksize, state->requested_blksize);
}
else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
size_t tsize = 0;
curl_off_t tsize = 0;
/* tsize should be ignored on upload: Who cares about the size of the
remote file? */
if(!data->state.upload &&
!Curl_str_number(&value, &tsize, SIZE_T_MAX)) {
!Curl_str_number(&value, &tsize, CURL_OFF_T_MAX)) {
if(!tsize) {
failf(data, "invalid tsize -:%s:- value in OACK packet", value);
return CURLE_TFTP_ILLEGAL;
}
infof(data, "tsize parsed from OACK (%zd)", tsize);
infof(data, "tsize parsed from OACK (%" CURL_FORMAT_CURL_OFF_T ")",
tsize);
Curl_pgrsSetDownloadSize(data, tsize);
}
}

View File

@ -1681,7 +1681,7 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
if(!uc && zoneid) {
const char *p = zoneid;
size_t scope;
curl_off_t scope;
if(!Curl_str_number(&p, &scope, UINT_MAX))
/* A plain number, use it directly as a scope id. */
conn->scope_id = (unsigned int)scope;
@ -1919,7 +1919,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
else {
size_t port;
curl_off_t port;
bool valid = TRUE;
if(data->set.use_port && data->state.allow_port)
port = data->set.use_port;
@ -2258,7 +2258,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
(void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
if(portptr) {
size_t num;
curl_off_t num;
const char *p = portptr;
if(!Curl_str_number(&p, &num, 0xffff))
port = (int)num;
@ -2902,7 +2902,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
*host_portno = '\0'; /* cut off number from hostname */
host_portno++;
if(*host_portno) {
size_t portparse;
curl_off_t portparse;
const char *p = host_portno;
if(Curl_str_number(&p, &portparse, 0xffff)) {
failf(data, "No valid port number in connect to host string (%s)",
@ -2981,9 +2981,9 @@ static CURLcode parse_connect_to_string(struct Curl_easy *data,
/* check whether the URL's port matches */
char *ptr_next = strchr(ptr, ':');
if(ptr_next) {
size_t port_to_match;
curl_off_t port_to_match;
if(!Curl_str_number(&ptr, &port_to_match, 0xffff) &&
(port_to_match == (size_t)conn->remote_port))
(port_to_match == (curl_off_t)conn->remote_port))
port_match = TRUE;
ptr = ptr_next + 1;
}

View File

@ -468,7 +468,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
portptr = strchr(hostname, ':');
if(portptr) {
size_t port;
curl_off_t port;
size_t keep = portptr - hostname;
/* Browser behavior adaptation. If there is a colon with no digits after,
@ -489,7 +489,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
u->portnum = (unsigned short) port;
/* generate a new port number string to get rid of leading zeroes etc */
free(u->port);
u->port = aprintf("%zd", port);
u->port = aprintf("%" CURL_FORMAT_CURL_OFF_T, port);
if(!u->port)
return CURLUE_OUT_OF_MEMORY;
}
@ -596,7 +596,7 @@ static int ipv4_normalize(struct dynbuf *host)
bool done = FALSE;
int n = 0;
const char *c = Curl_dyn_ptr(host);
unsigned long parts[4] = {0, 0, 0, 0};
unsigned int parts[4] = {0, 0, 0, 0};
CURLcode result = CURLE_OK;
if(*c == '[')
@ -604,22 +604,24 @@ static int ipv4_normalize(struct dynbuf *host)
errno = 0; /* for strtoul */
while(!done) {
char *endp = NULL;
unsigned long l;
if(!ISDIGIT(*c))
/* most importantly this does not allow a leading plus or minus */
return HOST_NAME;
l = strtoul(c, &endp, 0);
if(errno)
return HOST_NAME;
#if SIZEOF_LONG > 4
/* a value larger than 32 bits */
if(l > UINT_MAX)
return HOST_NAME;
#endif
int rc;
curl_off_t l;
if(*c == '0') {
c++;
if(*c == 'x') {
c++; /* skip the prefix */
rc = Curl_str_hex(&c, &l, UINT_MAX);
}
else
rc = Curl_str_octal(&c, &l, UINT_MAX);
}
else
rc = Curl_str_number(&c, &l, UINT_MAX);
parts[n] = l;
c = endp;
if(rc)
return HOST_NAME;
parts[n] = (unsigned int)l;
switch(*c) {
case '.':
@ -643,30 +645,30 @@ static int ipv4_normalize(struct dynbuf *host)
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
(unsigned int)(parts[0] >> 24),
(unsigned int)((parts[0] >> 16) & 0xff),
(unsigned int)((parts[0] >> 8) & 0xff),
(unsigned int)(parts[0] & 0xff));
(parts[0] >> 24),
((parts[0] >> 16) & 0xff),
((parts[0] >> 8) & 0xff),
(parts[0] & 0xff));
break;
case 1: /* a.b -- 8.24 bits */
if((parts[0] > 0xff) || (parts[1] > 0xffffff))
return HOST_NAME;
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
(unsigned int)(parts[0]),
(unsigned int)((parts[1] >> 16) & 0xff),
(unsigned int)((parts[1] >> 8) & 0xff),
(unsigned int)(parts[1] & 0xff));
(parts[0]),
((parts[1] >> 16) & 0xff),
((parts[1] >> 8) & 0xff),
(parts[1] & 0xff));
break;
case 2: /* a.b.c -- 8.8.16 bits */
if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xffff))
return HOST_NAME;
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
(unsigned int)(parts[0]),
(unsigned int)(parts[1]),
(unsigned int)((parts[2] >> 8) & 0xff),
(unsigned int)(parts[2] & 0xff));
(parts[0]),
(parts[1]),
((parts[2] >> 8) & 0xff),
(parts[2] & 0xff));
break;
case 3: /* a.b.c.d -- 8.8.8.8 bits */
if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff) ||
@ -674,10 +676,10 @@ static int ipv4_normalize(struct dynbuf *host)
return HOST_NAME;
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
(unsigned int)(parts[0]),
(unsigned int)(parts[1]),
(unsigned int)(parts[2]),
(unsigned int)(parts[3]));
(parts[0]),
(parts[1]),
(parts[2]),
(parts[3]));
break;
}
if(result)
@ -1745,11 +1747,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
return CURLUE_BAD_PORT_NUMBER;
else {
char *tmp;
size_t port;
curl_off_t port;
if(Curl_str_number(&part, &port, 0xffff) || *part)
/* weirdly provided number, not good! */
return CURLUE_BAD_PORT_NUMBER;
tmp = aprintf("%zd", port);
tmp = aprintf("%" CURL_FORMAT_CURL_OFF_T, port);
if(!tmp)
return CURLUE_OUT_OF_MEMORY;
free(u->port);

View File

@ -1,3 +1,5 @@
banfunc strerror
banfunc strncpy
banfunc sscanf
banfunc strtoul
banfunc strtol

View File

@ -81,10 +81,10 @@ CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx)
#endif
#ifdef DEBUGBUILD
{
char *p = getenv("CURL_DBG_QUIC_WBLOCK");
const char *p = getenv("CURL_DBG_QUIC_WBLOCK");
if(p) {
long l = strtol(p, NULL, 10);
if(l >= 0 && l <= 100)
curl_off_t l;
if(!Curl_str_number(&p, &l, 100))
qctx->wblock_percent = (int)l;
}
}

View File

@ -2871,9 +2871,12 @@ static void sftp_quote_stat(struct Curl_easy *data)
/* Now set the new attributes... */
if(strncasecompare(cmd, "chgrp", 5)) {
sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
const char *p = sshc->quote_path1;
curl_off_t gid;
(void)Curl_str_number(&p, &gid, UINT_MAX);
sshc->quote_attrs->gid = (uint32_t)gid;
if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
!sshc->acceptfail) {
!sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chgrp gid not a number");
@ -2885,10 +2888,9 @@ static void sftp_quote_stat(struct Curl_easy *data)
sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
}
else if(strncasecompare(cmd, "chmod", 5)) {
mode_t perms;
perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
/* permissions are octal */
if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
curl_off_t perms;
const char *p = sshc->quote_path1;
if(Curl_str_octal(&p, &perms, 07777)) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chmod permissions not a number");
@ -2897,13 +2899,15 @@ static void sftp_quote_stat(struct Curl_easy *data)
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
}
sshc->quote_attrs->permissions = perms;
sshc->quote_attrs->permissions = (mode_t)perms;
sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
}
else if(strncasecompare(cmd, "chown", 5)) {
sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
const char *p = sshc->quote_path1;
curl_off_t uid;
(void)Curl_str_number(&p, &uid, UINT_MAX);
if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
!sshc->acceptfail) {
!sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chown uid not a number");

View File

@ -73,7 +73,7 @@
#include "select.h"
#include "warnless.h"
#include "curl_path.h"
#include "strparse.h"
#include <curl_base64.h> /* for base64 encoding/decoding */
#include <curl_sha256.h>
@ -1368,7 +1368,10 @@ sftp_quote_stat(struct Curl_easy *data,
/* Now set the new attributes... */
if(strncasecompare(cmd, "chgrp", 5)) {
sshp->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
const char *p = sshc->quote_path1;
curl_off_t gid;
(void)Curl_str_number(&p, &gid, ULONG_MAX);
sshp->quote_attrs.gid = (unsigned long)gid;
sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
!sshc->acceptfail) {
@ -1377,17 +1380,22 @@ sftp_quote_stat(struct Curl_easy *data,
}
}
else if(strncasecompare(cmd, "chmod", 5)) {
sshp->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
curl_off_t perms;
const char *p = sshc->quote_path1;
/* permissions are octal */
if(sshp->quote_attrs.permissions == 0 &&
!ISDIGIT(sshc->quote_path1[0])) {
if(Curl_str_octal(&p, &perms, 07777)) {
failf(data, "Syntax error: chmod permissions not a number");
goto fail;
}
sshp->quote_attrs.permissions = (unsigned long)perms;
sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
}
else if(strncasecompare(cmd, "chown", 5)) {
sshp->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
const char *p = sshc->quote_path1;
curl_off_t uid;
(void)Curl_str_number(&p, &uid, ULONG_MAX);
sshp->quote_attrs.uid = (unsigned long)uid;
sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
!sshc->acceptfail) {

View File

@ -34,7 +34,6 @@
#include "sendf.h"
#include "progress.h"
#include "curl_path.h"
#include "strtoofft.h"
#include "transfer.h"
#include "speedcheck.h"
#include "select.h"

View File

@ -1,3 +1,5 @@
banfunc strerror
banfunc strncpy
banfunc sscanf
banfunc strtoul
banfunc strtol

View File

@ -55,6 +55,7 @@
#include "multiif.h"
#include "version_win32.h"
#include "rand.h"
#include "strparse.h"
/* The last #include file should be: */
#include "curl_memory.h"
@ -344,9 +345,9 @@ static const struct algo algs[]= {
};
static int
get_alg_id_by_name(char *name)
get_alg_id_by_name(const char *name)
{
char *nameEnd = strchr(name, ':');
const char *nameEnd = strchr(name, ':');
size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name);
int i;
@ -363,12 +364,13 @@ static CURLcode
set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
ALG_ID *algIds)
{
char *startCur = ciphers;
const char *startCur = ciphers;
int algCount = 0;
while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) {
long alg = strtol(startCur, 0, 0);
if(!alg)
curl_off_t alg;
if(Curl_str_number(&startCur, &alg, INT_MAX) || !alg)
alg = get_alg_id_by_name(startCur);
if(alg)
algIds[algCount++] = (ALG_ID)alg;
else if(!strncmp(startCur, "USE_STRONG_CRYPTO",

View File

@ -39,6 +39,7 @@
#include "transfer.h"
#include "select.h"
#include "nonblock.h"
#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -778,12 +779,11 @@ CURLcode Curl_ws_accept(struct Curl_easy *data,
data->conn->proto.ws = ws;
#ifdef DEBUGBUILD
{
char *p = getenv("CURL_WS_CHUNK_SIZE");
const char *p = getenv("CURL_WS_CHUNK_SIZE");
if(p) {
long l = strtol(p, NULL, 10);
if(l > 0 && l <= (1*1024*1024)) {
curl_off_t l;
if(!Curl_str_number(&p, &l, 1*1024*1024))
chunk_size = (size_t)l;
}
}
}
#endif
@ -1032,12 +1032,11 @@ static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws,
/* Simulate a blocking send after this chunk has been sent */
bool eagain_next = FALSE;
size_t chunk_egain = 0;
char *p = getenv("CURL_WS_CHUNK_EAGAIN");
const char *p = getenv("CURL_WS_CHUNK_EAGAIN");
if(p) {
long l = strtol(p, NULL, 10);
if(l > 0 && l <= (1*1024*1024)) {
curl_off_t l;
if(!Curl_str_number(&p, &l, 1*1024*1024))
chunk_egain = (size_t)l;
}
}
#endif

View File

@ -152,6 +152,8 @@ rem
for /f "delims=" %%r in ('dir /b ..\src\*.rc') do call :element %1 src "%%r" %3
) else if "!var!" == "CURL_SRC_X_C_FILES" (
call :element %1 lib "strtoofft.c" %3
call :element %1 lib "strparse.c" %3
call :element %1 lib "strcase.c" %3
call :element %1 lib "timediff.c" %3
call :element %1 lib "nonblock.c" %3
call :element %1 lib "warnless.c" %3
@ -163,6 +165,8 @@ rem
call :element %1 lib "config-win32.h" %3
call :element %1 lib "curl_setup.h" %3
call :element %1 lib "strtoofft.h" %3
call :element %1 lib "strparse.h" %3
call :element %1 lib "strcase.h" %3
call :element %1 lib "timediff.h" %3
call :element %1 lib "nonblock.h" %3
call :element %1 lib "warnless.h" %3

View File

@ -42,6 +42,8 @@ CURLX_CFILES = \
../lib/dynbuf.c \
../lib/nonblock.c \
../lib/strtoofft.c \
../lib/strparse.c \
../lib/strcase.c \
../lib/timediff.c \
../lib/version_win32.c \
../lib/warnless.c
@ -53,6 +55,8 @@ CURLX_HFILES = \
../lib/dynbuf.h \
../lib/nonblock.h \
../lib/strtoofft.h \
../lib/strparse.h \
../lib/strcase.h \
../lib/timediff.h \
../lib/version_win32.h \
../lib/warnless.h

View File

@ -97,9 +97,9 @@ Curl_str_number
10: (" 123") 8, [0] line 0
11: ("") 8, [0] line 0
Curl_str_number / max
0: ("9223372036854775808") 0, [9223372036854775808] line 19
1: ("9223372036854775809") 0, [9223372036854775809] line 19
2: ("18446744073709551615") 0, [18446744073709551615] line 20
0: ("9223372036854775807") 0, [9223372036854775807] line 19
1: ("9223372036854775808") 7, [0] line 18
2: ("18446744073709551615") 7, [0] line 19
3: ("18446744073709551616") 7, [0] line 19
4: ("18446744073709551617") 7, [0] line 19
Curl_str_newline
@ -115,6 +115,38 @@ Curl_str_newline
8: ("
") 0, line 1
9: ("") 6, line 0
Curl_str_hex
0: ("1") 0, [1] line 1
1: ("1000") 0, [4096] line 4
2: ("1234") 0, [4660] line 4
3: ("1235") 0, [4661] line 4
4: ("1236") 1, [0] line 3
5: ("01234") 0, [4660] line 5
6: ("00000000000000000000000000001234") 0, [4660] line 32
7: ("0123 345") 0, [291] line 4
8: ("0123O345") 0, [291] line 4
9: ("-12") 8, [0] line 0
10: (" 123") 8, [0] line 0
11: ("") 8, [0] line 0
Curl_str_octal
0: ("1") 0, [1] line 1
1: ("1000") 0, [512] line 4
2: ("1234") 0, [668] line 4
3: ("1235") 0, [669] line 4
4: ("1236") 1, [0] line 3
5: ("01234") 0, [668] line 5
6: ("00000000000000000000000000001234") 0, [668] line 32
7: ("0123 345") 0, [83] line 4
8: ("0123O345") 0, [83] line 4
9: ("-12") 8, [0] line 0
10: (" 123") 8, [0] line 0
11: ("") 8, [0] line 0
Curl_str_octal / max
0: ("777777777777777777777") 0, [9223372036854775807] line 21
1: ("1000000000000000000000") 7, [0] line 21
Curl_str_hex / max
0: ("7FFFFFFFFFFFFFFF") 0, [9223372036854775807] line 16
1: ("8000000000000000") 7, [0] line 15
</stdout>
</verify>
</testcase>

View File

@ -29,6 +29,8 @@ CURLX_SRCS = \
../../lib/mprintf.c \
../../lib/nonblock.c \
../../lib/strtoofft.c \
../../lib/strparse.c \
../../lib/strequal.c \
../../lib/warnless.c \
../../lib/timediff.c \
../../lib/dynbuf.c \
@ -41,10 +43,12 @@ CURLX_HDRS = \
../../lib/curlx.h \
../../lib/nonblock.h \
../../lib/strtoofft.h \
../../lib/strcase.h \
../../lib/warnless.h \
../../lib/timediff.h \
../../lib/curl_ctype.h \
../../lib/dynbuf.h \
../../lib/strcase.h \
../../lib/strdup.h \
../../lib/curl_get_line.h \
../../lib/curl_multibyte.h

View File

@ -196,7 +196,7 @@ UNITTEST_START
};
printf("Curl_str_number\n");
for(i = 0; nums[i]; i++) {
size_t num;
curl_off_t num;
const char *line = nums[i];
const char *orgline = line;
int rc = Curl_str_number(&line, &num, 1235);
@ -206,10 +206,10 @@ UNITTEST_START
}
{
/* SIZE_T_MAX is typically 18446744073709551615 */
/* CURL_OFF_T is typically 9223372036854775807 */
static const char *nums[] = {
"9223372036854775808", /* 2^63 */
"9223372036854775809", /* 2^63 + 1 */
"9223372036854775807", /* 2^63 -1 */
"9223372036854775808", /* 2^63 */
"18446744073709551615", /* 2^64 - 1 */
"18446744073709551616", /* 2^64 */
"18446744073709551617", /* 2^64 + 1 */
@ -217,11 +217,11 @@ UNITTEST_START
};
printf("Curl_str_number / max\n");
for(i = 0; nums[i]; i++) {
size_t num;
curl_off_t num;
const char *line = nums[i];
const char *orgline = line;
int rc = Curl_str_number(&line, &num, SIZE_T_MAX);
printf("%u: (\"%s\") %d, [%zu] line %d\n",
int rc = Curl_str_number(&line, &num, CURL_OFF_T_MAX);
printf("%u: (\"%s\") %d, [%" CURL_FORMAT_CURL_OFF_T "] line %d\n",
i, orgline, rc, num, (int)(line - orgline));
}
}
@ -250,5 +250,95 @@ UNITTEST_START
}
}
{
static const char *nums[] = {
"1",
"1000",
"1234",
"1235",
"1236",
"01234",
"00000000000000000000000000001234",
"0123 345",
"0123O345",
"-12",
" 123",
"",
NULL
};
printf("Curl_str_hex\n");
for(i = 0; nums[i]; i++) {
curl_off_t num;
const char *line = nums[i];
const char *orgline = line;
int rc = Curl_str_hex(&line, &num, 0x1235);
printf("%u: (\"%s\") %d, [%u] line %d\n",
i, orgline, rc, (int)num, (int)(line - orgline));
}
}
{
static const char *nums[] = {
"1",
"1000",
"1234",
"1235",
"1236",
"01234",
"00000000000000000000000000001234",
"0123 345",
"0123O345",
"-12",
" 123",
"",
NULL
};
printf("Curl_str_octal\n");
for(i = 0; nums[i]; i++) {
curl_off_t num;
const char *line = nums[i];
const char *orgline = line;
int rc = Curl_str_octal(&line, &num, 01235);
printf("%u: (\"%s\") %d, [%u] line %d\n",
i, orgline, rc, (int)num, (int)(line - orgline));
}
}
{
/* CURL_OFF_T is typically 2^63-1 */
static const char *nums[] = {
"777777777777777777777", /* 2^63 -1 */
"1000000000000000000000", /* 2^63 */
NULL
};
printf("Curl_str_octal / max\n");
for(i = 0; nums[i]; i++) {
curl_off_t num;
const char *line = nums[i];
const char *orgline = line;
int rc = Curl_str_octal(&line, &num, CURL_OFF_T_MAX);
printf("%u: (\"%s\") %d, [%" CURL_FORMAT_CURL_OFF_T "] line %d\n",
i, orgline, rc, num, (int)(line - orgline));
}
}
{
/* CURL_OFF_T is typically 2^63-1 */
static const char *nums[] = {
"7FFFFFFFFFFFFFFF", /* 2^63 -1 */
"8000000000000000", /* 2^63 */
NULL
};
printf("Curl_str_hex / max\n");
for(i = 0; nums[i]; i++) {
curl_off_t num;
const char *line = nums[i];
const char *orgline = line;
int rc = Curl_str_hex(&line, &num, CURL_OFF_T_MAX);
printf("%u: (\"%s\") %d, [%" CURL_FORMAT_CURL_OFF_T "] line %d\n",
i, orgline, rc, num, (int)(line - orgline));
}
}
}
UNITTEST_STOP

View File

@ -692,6 +692,8 @@ CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP)
CURL_FROM_LIBCURL=\
$(CURL_DIROBJ)\nonblock.obj \
$(CURL_DIROBJ)\strtoofft.obj \
$(CURL_DIROBJ)\strparse.obj \
$(CURL_DIROBJ)\strcase.obj \
$(CURL_DIROBJ)\warnless.obj \
$(CURL_DIROBJ)\curl_get_line.obj \
$(CURL_DIROBJ)\curl_multibyte.obj \
@ -718,6 +720,10 @@ $(CURL_DIROBJ)\nonblock.obj: ../lib/nonblock.c
$(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/nonblock.c
$(CURL_DIROBJ)\strtoofft.obj: ../lib/strtoofft.c
$(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/strtoofft.c
$(CURL_DIROBJ)\strparse.obj: ../lib/strparse.c
$(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/strparse.c
$(CURL_DIROBJ)\strcase.obj: ../lib/strcase.c
$(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/strcase.c
$(CURL_DIROBJ)\warnless.obj: ../lib/warnless.c
$(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/warnless.c
$(CURL_DIROBJ)\curl_get_line.obj: ../lib/curl_get_line.c