1
0
mirror of https://github.com/moparisthebest/curl synced 2024-11-17 06:55:02 -05:00

urlglob: improved error messages and column number on bad use

Introduce a convenience macro and keep of the column better so that it
can point out the offending column better.

Updated test 75 accordingly.
This commit is contained in:
Daniel Stenberg 2013-09-06 23:27:47 +02:00
parent d6cda9e8ab
commit 9fa42beddc
3 changed files with 68 additions and 84 deletions

View File

@ -35,6 +35,9 @@ typedef enum {
GLOB_ERROR = CURLE_URL_MALFORMAT GLOB_ERROR = CURLE_URL_MALFORMAT
} GlobCode; } GlobCode;
#define GLOBERROR(string, column, code) \
glob->error = string, glob->pos = column, code;
void glob_cleanup(URLGlob* glob); void glob_cleanup(URLGlob* glob);
static GlobCode glob_fixed(URLGlob *glob, unsigned long *amount) static GlobCode glob_fixed(URLGlob *glob, unsigned long *amount)
@ -49,15 +52,12 @@ static GlobCode glob_fixed(URLGlob *glob, unsigned long *amount)
pat->content.Set.elements = malloc(sizeof(char*)); pat->content.Set.elements = malloc(sizeof(char*));
if(!pat->content.Set.elements) { if(!pat->content.Set.elements)
snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n"); return GLOBERROR("out of memory", 0, GLOB_NO_MEM);
return GLOB_NO_MEM;
}
pat->content.Set.elements[0] = strdup(glob->glob_buffer); pat->content.Set.elements[0] = strdup(glob->glob_buffer);
if(!pat->content.Set.elements[0]) { if(!pat->content.Set.elements[0])
snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n"); return GLOBERROR("out of memory", 0, GLOB_NO_MEM);
return GLOB_NO_MEM;
}
return GLOB_OK; return GLOB_OK;
} }
@ -76,7 +76,7 @@ static int multiply(unsigned long *amount, long with)
} }
static GlobCode glob_set(URLGlob *glob, char **patternp, static GlobCode glob_set(URLGlob *glob, char **patternp,
size_t pos, unsigned long *amount, size_t *posp, unsigned long *amount,
int globindex) int globindex)
{ {
/* processes a set expression with the point behind the opening '{' /* processes a set expression with the point behind the opening '{'
@ -87,6 +87,7 @@ static GlobCode glob_set(URLGlob *glob, char **patternp,
char *buf = glob->glob_buffer; char *buf = glob->glob_buffer;
char *pattern = *patternp; char *pattern = *patternp;
char *opattern = pattern; char *opattern = pattern;
size_t opos = *posp-1;
pat = &glob->pattern[glob->size]; pat = &glob->pattern[glob->size];
/* patterns 0,1,2,... correspond to size=1,3,5,... */ /* patterns 0,1,2,... correspond to size=1,3,5,... */
@ -99,27 +100,20 @@ static GlobCode glob_set(URLGlob *glob, char **patternp,
while(!done) { while(!done) {
switch (*pattern) { switch (*pattern) {
case '\0': /* URL ended while set was still open */ case '\0': /* URL ended while set was still open */
snprintf(glob->errormsg, sizeof(glob->errormsg), return GLOBERROR("unmatched brace", opos, GLOB_ERROR);
"unmatched brace at pos %zu\n", pos);
return GLOB_ERROR;
case '{': case '{':
case '[': /* no nested expressions at this time */ case '[': /* no nested expressions at this time */
snprintf(glob->errormsg, sizeof(glob->errormsg), return GLOBERROR("nested brace", *posp, GLOB_ERROR);
"nested braces not supported at pos %zu\n", pos);
return GLOB_ERROR;
case '}': /* set element completed */ case '}': /* set element completed */
if(opattern == pattern) { if(opattern == pattern)
snprintf(glob->errormsg, sizeof(glob->errormsg), return GLOBERROR("empty string within braces", *posp, GLOB_ERROR);
"no string within braces at pos %zu\n", pos);
return GLOB_ERROR;
}
/* add 1 to size since it'll be incremented below */ /* add 1 to size since it'll be incremented below */
if(multiply(amount, pat->content.Set.size+1)) { if(multiply(amount, pat->content.Set.size+1))
strcpy(glob->errormsg, "range overflow!\n"); return GLOBERROR("range overflow", 0, GLOB_ERROR);
return GLOB_ERROR;
}
/* fall-through */ /* fall-through */
case ',': case ',':
@ -127,27 +121,21 @@ static GlobCode glob_set(URLGlob *glob, char **patternp,
if(pat->content.Set.elements) { if(pat->content.Set.elements) {
char **new_arr = realloc(pat->content.Set.elements, char **new_arr = realloc(pat->content.Set.elements,
(pat->content.Set.size + 1) * sizeof(char*)); (pat->content.Set.size + 1) * sizeof(char*));
if(!new_arr) { if(!new_arr)
snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n"); return GLOBERROR("out of memory", 0, GLOB_NO_MEM);
return GLOB_NO_MEM;
}
pat->content.Set.elements = new_arr; pat->content.Set.elements = new_arr;
} }
else else
pat->content.Set.elements = malloc(sizeof(char*)); pat->content.Set.elements = malloc(sizeof(char*));
if(!pat->content.Set.elements) { if(!pat->content.Set.elements)
snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n"); return GLOBERROR("out of memory", 0, GLOB_NO_MEM);
return GLOB_NO_MEM;
}
pat->content.Set.elements[pat->content.Set.size] = pat->content.Set.elements[pat->content.Set.size] =
strdup(glob->glob_buffer); strdup(glob->glob_buffer);
if(!pat->content.Set.elements[pat->content.Set.size]) { if(!pat->content.Set.elements[pat->content.Set.size])
snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n"); return GLOBERROR("out of memory", 0, GLOB_NO_MEM);
return GLOB_NO_MEM;
}
++pat->content.Set.size; ++pat->content.Set.size;
if(*pattern == '}') { if(*pattern == '}') {
@ -158,23 +146,21 @@ static GlobCode glob_set(URLGlob *glob, char **patternp,
buf = glob->glob_buffer; buf = glob->glob_buffer;
++pattern; ++pattern;
++pos; ++(*posp);
break; break;
case ']': /* illegal closing bracket */ case ']': /* illegal closing bracket */
snprintf(glob->errormsg, sizeof(glob->errormsg), return GLOBERROR("unexpected close bracket", *posp, GLOB_ERROR);
"illegal pattern at pos %zu\n", pos);
return GLOB_ERROR;
case '\\': /* escaped character, skip '\' */ case '\\': /* escaped character, skip '\' */
if(pattern[1]) { if(pattern[1]) {
++pattern; ++pattern;
++pos; ++(*posp);
} }
/* intentional fallthrough */ /* intentional fallthrough */
default: default:
*buf++ = *pattern++; /* copy character to set element */ *buf++ = *pattern++; /* copy character to set element */
++pos; ++(*posp);
} }
} }
@ -183,7 +169,7 @@ static GlobCode glob_set(URLGlob *glob, char **patternp,
} }
static GlobCode glob_range(URLGlob *glob, char **patternp, static GlobCode glob_range(URLGlob *glob, char **patternp,
size_t pos, unsigned long *amount, size_t *posp, unsigned long *amount,
int globindex) int globindex)
{ {
/* processes a range expression with the point behind the opening '[' /* processes a range expression with the point behind the opening '['
@ -227,13 +213,12 @@ static GlobCode glob_range(URLGlob *glob, char **patternp,
else else
pattern+=3; pattern+=3;
*posp += (pattern - *patternp);
if((rc != 2) || (min_c >= max_c) || ((max_c - min_c) > ('z' - 'a')) || if((rc != 2) || (min_c >= max_c) || ((max_c - min_c) > ('z' - 'a')) ||
(step < 0) ) { (step < 0) )
/* the pattern is not well-formed */ /* the pattern is not well-formed */
snprintf(glob->errormsg, sizeof(glob->errormsg), return GLOBERROR("bad range", *posp, GLOB_ERROR);
"error: bad range specification after pos %zu\n", pos);
return GLOB_ERROR;
}
/* if there was a ":[num]" thing, use that as step or else use 1 */ /* if there was a ":[num]" thing, use that as step or else use 1 */
pat->content.CharRange.step = step; pat->content.CharRange.step = step;
@ -241,10 +226,8 @@ static GlobCode glob_range(URLGlob *glob, char **patternp,
pat->content.CharRange.max_c = max_c; pat->content.CharRange.max_c = max_c;
if(multiply(amount, (pat->content.CharRange.max_c - if(multiply(amount, (pat->content.CharRange.max_c -
pat->content.CharRange.min_c + 1))) { pat->content.CharRange.min_c + 1)))
strcpy(glob->errormsg, "range overflow!\n"); return GLOBERROR("range overflow", *posp, GLOB_ERROR);
return GLOB_ERROR;
}
} }
else if(ISDIGIT(*pattern)) { else if(ISDIGIT(*pattern)) {
/* numeric range detected */ /* numeric range detected */
@ -295,12 +278,12 @@ static GlobCode glob_range(URLGlob *glob, char **patternp,
} }
} }
if(!endp || (min_n > max_n) || (step_n > (max_n - min_n))) { *posp += (pattern - *patternp);
if(!endp || (min_n > max_n) || (step_n > (max_n - min_n)))
/* the pattern is not well-formed */ /* the pattern is not well-formed */
snprintf(glob->errormsg, sizeof(glob->errormsg), return GLOBERROR("bad range", *posp, GLOB_ERROR);
"error: bad range specification after pos %zu\n", pos);
return GLOB_ERROR;
}
/* typecasting to ints are fine here since we make sure above that we /* typecasting to ints are fine here since we make sure above that we
are within 31 bits */ are within 31 bits */
pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n; pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n;
@ -308,16 +291,11 @@ static GlobCode glob_range(URLGlob *glob, char **patternp,
pat->content.NumRange.step = step_n; pat->content.NumRange.step = step_n;
if(multiply(amount, (pat->content.NumRange.max_n - if(multiply(amount, (pat->content.NumRange.max_n -
pat->content.NumRange.min_n + 1))) { pat->content.NumRange.min_n + 1)))
strcpy(glob->errormsg, "range overflow!\n"); return GLOBERROR("range overflow", *posp, GLOB_ERROR);
return GLOB_ERROR;
}
}
else {
snprintf(glob->errormsg, sizeof(glob->errormsg),
"illegal character in range specification at pos %zu\n", pos);
return GLOB_ERROR;
} }
else
return GLOBERROR("bad range specification", *posp, GLOB_ERROR);
*patternp = pattern; *patternp = pattern;
return GLOB_OK; return GLOB_OK;
@ -336,11 +314,8 @@ static GlobCode glob_parse(URLGlob *glob, char *pattern,
while(*pattern && !res) { while(*pattern && !res) {
int sublen = 0; int sublen = 0;
while(*pattern && *pattern != '{' && *pattern != '[') { while(*pattern && *pattern != '{' && *pattern != '[') {
if(*pattern == '}' || *pattern == ']') { if(*pattern == '}' || *pattern == ']')
snprintf(glob->errormsg, sizeof(glob->errormsg), return GLOBERROR("unmatched close brace/bracket", pos, GLOB_ERROR);
"unmatched close brace/bracket at pos %zu\n", pos);
return GLOB_ERROR;
}
/* only allow \ to escape known "special letters" */ /* only allow \ to escape known "special letters" */
if(*pattern == '\\' && if(*pattern == '\\' &&
@ -371,23 +346,21 @@ static GlobCode glob_parse(URLGlob *glob, char *pattern,
case '{': case '{':
/* process set pattern */ /* process set pattern */
pattern++; pattern++;
res = glob_set(glob, &pattern, ++pos, amount, globindex++); pos++;
res = glob_set(glob, &pattern, &pos, amount, globindex++);
break; break;
case '[': case '[':
/* process range pattern */ /* process range pattern */
pattern++; pattern++;
res = glob_range(glob, &pattern, ++pos, amount, globindex++); pos++;
res = glob_range(glob, &pattern, &pos, amount, globindex++);
break; break;
} }
} }
if(++glob->size > GLOB_PATTERN_NUM) { if(++glob->size > GLOB_PATTERN_NUM)
snprintf(glob->errormsg, sizeof(glob->errormsg), return GLOBERROR("too many globs", pos, GLOB_ERROR);
"too many globs used\n");
return GLOB_ERROR;
}
} }
return res; return res;
} }
@ -421,9 +394,19 @@ int glob_url(URLGlob** glob, char* url, unsigned long *urlnum, FILE *error)
if(!res) if(!res)
*urlnum = amount; *urlnum = amount;
else { else {
if(error && glob_expand->errormsg[0]) { if(error && glob_expand->error) {
char text[128];
const char *t;
if(glob_expand->pos) {
snprintf(text, sizeof(text), "%s in column %zu", glob_expand->error,
glob_expand->pos);
t = text;
}
else
t = glob_expand->error;
/* send error description to the error-stream */ /* send error description to the error-stream */
fprintf(error, "curl: (%d) [globbing] %s", res, glob_expand->errormsg); fprintf(error, "curl: (%d) [globbing] %s\n", res, t);
} }
/* it failed, we cleanup */ /* it failed, we cleanup */
glob_cleanup(glob_expand); glob_cleanup(glob_expand);

View File

@ -64,7 +64,8 @@ typedef struct {
size_t urllen; size_t urllen;
char *glob_buffer; char *glob_buffer;
char beenhere; char beenhere;
char errormsg[80]; /* error message buffer */ const char *error; /* error message */
size_t pos; /* column position of error or 0 */
} URLGlob; } URLGlob;
int glob_url(URLGlob**, char*, unsigned long *, FILE *); int glob_url(URLGlob**, char*, unsigned long *, FILE *);

View File

@ -24,7 +24,7 @@ http
HTTP, urlglob retrieval with bad range HTTP, urlglob retrieval with bad range
</name> </name>
<command option="no-output"> <command option="no-output">
"http://%HOSTIP:%HTTPPORT/[2-1]" -o "log/weee#1.dump" --stderr - "http://a-site-never-accessed.example.org/[2-1]" -o "log/weee#1.dump" --stderr -
</command> </command>
# The error message on stdout implicitly depends on the length of the # The error message on stdout implicitly depends on the length of the
# URL, so refuse to run if the length is unexpected. # URL, so refuse to run if the length is unexpected.
@ -43,7 +43,7 @@ perl %SRCDIR/libtest/test75.pl http://%HOSTIP:%HTTPPORT/ 22
3 3
</errorcode> </errorcode>
<stdout mode="text"> <stdout mode="text">
curl: (3) [globbing] error: bad range specification after pos 24 curl: (3) [globbing] bad range in column 47
</stdout> </stdout>
</verify> </verify>
</testcase> </testcase>