mirror of
https://github.com/curl/curl.git
synced 2026-08-02 09:30:29 +03:00
tool_urlglob: add named globs
Idea-by: Bastian Jesuiter Verified by test 2408 - 2411 Closes #21409
This commit is contained in:
parent
2a2104f3cf
commit
cb0636980b
13 changed files with 432 additions and 58 deletions
|
|
@ -39,4 +39,17 @@ probably have to put the full URL within double quotes to avoid the shell from
|
|||
interfering with it. This also goes for other characters treated special, like
|
||||
for example '&', '?' and '*'.
|
||||
|
||||
The separate globbing components can be referenced in the --output option to
|
||||
allow pieces to be reused in the target filename.
|
||||
|
||||
Starting in curl 8.21.0, the separate globbing parts can be named and
|
||||
referenced by their names. The case sensitive alphanumeric name is set
|
||||
enclosed within angle brackets after the opening character. Examples:
|
||||
|
||||
https://fun.example/{<number>one,two,three}.jpg
|
||||
|
||||
ftp://ftp.example.com/file[<range>1-100].txt
|
||||
|
||||
Setting the same glob name twice is an error.
|
||||
|
||||
Switch off globbing with --globoff.
|
||||
|
|
|
|||
|
|
@ -69,3 +69,14 @@ override curl's internal binary output in terminal prevention:
|
|||
|
||||
Note that the binary output may be caused by the response being compressed, in
|
||||
which case you may want to use the --compressed option.
|
||||
|
||||
Starting in curl 8.21.0, the separate globbing parts can be named and
|
||||
referenced by their names. The case sensitive alphanumeric name is set
|
||||
enclosed within angle brackets after the opening character. Examples:
|
||||
|
||||
curl "https://fun.example/{<num>one,two}.jpg" -o "save-#<num>"
|
||||
|
||||
curl "ftp://ftp.example/file[<range>1-100].txt" \
|
||||
-o "save-#<range>.txt"
|
||||
|
||||
Referencing a named glob that is not set, causes an error.
|
||||
|
|
|
|||
|
|
@ -1067,7 +1067,12 @@ static CURLcode setup_outfile(struct OperationConfig *config,
|
|||
}
|
||||
else if(result) {
|
||||
/* bad globbing */
|
||||
warnf("bad output glob");
|
||||
if(state->urlglob.error) {
|
||||
glob_show_error(&state->urlglob, u->outfile, tool_stderr, result);
|
||||
config->synthetic_error = TRUE;
|
||||
}
|
||||
else
|
||||
warnf("bad output glob");
|
||||
return result;
|
||||
}
|
||||
if(!*per->outfile) {
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ static CURLcode glob_fixed(struct URLGlob *glob, char *fixed, size_t len)
|
|||
|
||||
pat->c.set.palloc = 1;
|
||||
pat->c.set.size = 1;
|
||||
pat->name = NULL; /* unnamed */
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +90,7 @@ static int multiply(curl_off_t *amount, curl_off_t with)
|
|||
|
||||
static CURLcode glob_set(struct URLGlob *glob, const char **patternp,
|
||||
size_t *posp, curl_off_t *amount,
|
||||
int globindex)
|
||||
int globindex, const struct Curl_str *name)
|
||||
{
|
||||
/* processes a set expression with the point behind the opening '{'
|
||||
','-separated elements are collected until the next closing '}'
|
||||
|
|
@ -103,6 +104,7 @@ static CURLcode glob_set(struct URLGlob *glob, const char **patternp,
|
|||
size_t size = 0;
|
||||
char **elem = NULL;
|
||||
size_t palloc = 0; /* start with this */
|
||||
DEBUGASSERT(name);
|
||||
|
||||
while(!done) {
|
||||
switch(*pattern) {
|
||||
|
|
@ -198,6 +200,15 @@ static CURLcode glob_set(struct URLGlob *glob, const char **patternp,
|
|||
pat->c.set.size = size;
|
||||
pat->c.set.idx = 0;
|
||||
pat->c.set.palloc = palloc;
|
||||
if(curlx_strlen(name)) {
|
||||
pat->name = curlx_memdup0(curlx_str(name), curlx_strlen(name));
|
||||
if(!pat->name) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
pat->name = NULL; /* no name */
|
||||
|
||||
return CURLE_OK;
|
||||
error:
|
||||
|
|
@ -212,7 +223,7 @@ error:
|
|||
|
||||
static CURLcode glob_range(struct URLGlob *glob, const char **patternp,
|
||||
size_t *posp, curl_off_t *amount,
|
||||
int globindex)
|
||||
int globindex, const struct Curl_str *name)
|
||||
{
|
||||
/* processes a range expression with the point behind the opening '['
|
||||
- char range: e.g. "a-z]", "B-Q]"
|
||||
|
|
@ -224,8 +235,10 @@ static CURLcode glob_range(struct URLGlob *glob, const char **patternp,
|
|||
const char *pattern = *patternp;
|
||||
const char *c;
|
||||
|
||||
DEBUGASSERT(name);
|
||||
pat = &glob->pattern[glob->pnum];
|
||||
pat->globindex = globindex;
|
||||
pat->name = NULL; /* no name (so far) */
|
||||
|
||||
if(ISALPHA(*pattern)) {
|
||||
/* character range detected */
|
||||
|
|
@ -340,6 +353,11 @@ static CURLcode glob_range(struct URLGlob *glob, const char **patternp,
|
|||
return globerror(glob, "bad range specification", *posp,
|
||||
CURLE_URL_MALFORMAT);
|
||||
|
||||
if(curlx_strlen(name)) {
|
||||
pat->name = curlx_memdup0(curlx_str(name), curlx_strlen(name));
|
||||
if(!pat->name)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
*patternp = pattern;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
|
@ -407,12 +425,31 @@ static CURLcode add_glob(struct URLGlob *glob, size_t pos)
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* returns the named glob pattern (case sensitively) if it exists, otherwise
|
||||
NULL
|
||||
*/
|
||||
static struct URLPattern *glob_find_name(struct URLGlob *glob,
|
||||
struct Curl_str *name)
|
||||
{
|
||||
size_t i;
|
||||
/* find the correct glob entry */
|
||||
for(i = 0; i < glob->pnum; i++) {
|
||||
if(glob->pattern[i].name &&
|
||||
curlx_str_cmp(name, glob->pattern[i].name))
|
||||
return &glob->pattern[i];
|
||||
}
|
||||
return NULL; /* no match */
|
||||
}
|
||||
|
||||
#define MAX_GLOBNAME_LEN 64
|
||||
|
||||
static CURLcode glob_parse(struct URLGlob *glob, const char *pattern,
|
||||
size_t pos, curl_off_t *amount)
|
||||
{
|
||||
/* processes a literal string component of a URL
|
||||
special characters '{' and '[' branch to set/range processing functions
|
||||
*/
|
||||
const char *ipattern = pattern; /* start position */
|
||||
CURLcode result = CURLE_OK;
|
||||
int globindex = 0; /* count "actual" globs */
|
||||
|
||||
|
|
@ -464,21 +501,39 @@ static CURLcode glob_parse(struct URLGlob *glob, const char *pattern,
|
|||
curlx_dyn_reset(&glob->buf);
|
||||
}
|
||||
else {
|
||||
struct Curl_str name;
|
||||
if(!*pattern) /* done */
|
||||
break;
|
||||
else if(*pattern == '{') {
|
||||
/* process set pattern */
|
||||
else if((*pattern == '{') || (*pattern == '[')) {
|
||||
bool set = (*pattern == '{');
|
||||
const char *start;
|
||||
pattern++;
|
||||
pos++;
|
||||
result = glob_set(glob, &pattern, &pos, amount, globindex++);
|
||||
if(!result)
|
||||
result = add_glob(glob, pos);
|
||||
}
|
||||
else if(*pattern == '[') {
|
||||
/* process range pattern */
|
||||
pattern++;
|
||||
pos++;
|
||||
result = glob_range(glob, &pattern, &pos, amount, globindex++);
|
||||
start = pattern;
|
||||
/* fetch the name, if provided */
|
||||
if(curlx_str_single(&pattern, '<') ||
|
||||
curlx_str_until(&pattern, &name, MAX_GLOBNAME_LEN, '>') ||
|
||||
curlx_str_single(&pattern, '>')) {
|
||||
/* Not a proper name. This is not reporting errors on syntax errors
|
||||
on purpose: it means that if there is an existing use case that
|
||||
uses what looks like a broken named-glob syntax (now introduced)
|
||||
we let that function like before. */
|
||||
curlx_str_init(&name);
|
||||
pattern = start; /* reset any partial patch */
|
||||
}
|
||||
else {
|
||||
/* check that the name is not already used */
|
||||
struct URLPattern *p = glob_find_name(glob, &name);
|
||||
if(p)
|
||||
return globerror(glob, "Duplicate glob name", 2 + start - ipattern,
|
||||
CURLE_URL_MALFORMAT);
|
||||
}
|
||||
if(set)
|
||||
result = glob_set(glob, &pattern, &pos, amount, globindex++, &name);
|
||||
else
|
||||
result = glob_range(glob, &pattern, &pos, amount, globindex++,
|
||||
&name);
|
||||
|
||||
if(!result)
|
||||
result = add_glob(glob, pos);
|
||||
}
|
||||
|
|
@ -492,6 +547,26 @@ bool glob_inuse(struct URLGlob *glob)
|
|||
return glob->palloc ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/* a glob error has been confirmed, this outputs details about it to the set
|
||||
error stream */
|
||||
void glob_show_error(struct URLGlob *glob, const char *url, FILE *error,
|
||||
CURLcode result)
|
||||
{
|
||||
char text[512];
|
||||
const char *t;
|
||||
if(glob->pos) {
|
||||
curl_msnprintf(text, sizeof(text), "%s in position %zu:\n%s\n%*s^",
|
||||
glob->error,
|
||||
glob->pos, url, (int)glob->pos - 1, " ");
|
||||
t = text;
|
||||
}
|
||||
else
|
||||
t = glob->error;
|
||||
|
||||
/* send error description to the error-stream */
|
||||
curl_mfprintf(error, "curl: (%d) %s\n", result, t);
|
||||
}
|
||||
|
||||
CURLcode glob_url(struct URLGlob *glob, const char *url, curl_off_t *urlnum,
|
||||
FILE *error)
|
||||
{
|
||||
|
|
@ -511,21 +586,8 @@ CURLcode glob_url(struct URLGlob *glob, const char *url, curl_off_t *urlnum,
|
|||
|
||||
result = glob_parse(glob, url, 1, &amount);
|
||||
if(result) {
|
||||
if(error && glob->error) {
|
||||
char text[512];
|
||||
const char *t;
|
||||
if(glob->pos) {
|
||||
curl_msnprintf(text, sizeof(text), "%s in URL position %zu:\n%s\n%*s^",
|
||||
glob->error,
|
||||
glob->pos, url, (int)glob->pos - 1, " ");
|
||||
t = text;
|
||||
}
|
||||
else
|
||||
t = glob->error;
|
||||
|
||||
/* send error description to the error-stream */
|
||||
curl_mfprintf(error, "curl: (%d) %s\n", result, t);
|
||||
}
|
||||
if(error && glob->error)
|
||||
glob_show_error(glob, url, error, result);
|
||||
*urlnum = 1;
|
||||
return result;
|
||||
}
|
||||
|
|
@ -547,6 +609,7 @@ void glob_cleanup(struct URLGlob *glob)
|
|||
curlx_safefree(glob->pattern[i].c.set.elem[elem]);
|
||||
curlx_safefree(glob->pattern[i].c.set.elem);
|
||||
}
|
||||
curlx_safefree(glob->pattern[i].name);
|
||||
}
|
||||
curlx_safefree(glob->pattern);
|
||||
glob->palloc = 0;
|
||||
|
|
@ -643,6 +706,7 @@ CURLcode glob_match_url(char **output, const char *filename,
|
|||
struct URLGlob *glob, SANITIZEcode *sc)
|
||||
{
|
||||
struct dynbuf dyn;
|
||||
const char *ifilename = filename;
|
||||
*output = NULL;
|
||||
*sc = SANITIZE_ERR_OK;
|
||||
|
||||
|
|
@ -650,11 +714,11 @@ CURLcode glob_match_url(char **output, const char *filename,
|
|||
|
||||
while(*filename) {
|
||||
CURLcode result = CURLE_OK;
|
||||
struct URLPattern *pat = NULL;
|
||||
if(*filename == '#' && ISDIGIT(filename[1])) {
|
||||
const char *ptr = filename;
|
||||
/* a numbered glob reference */
|
||||
const char *ptr = filename++;
|
||||
curl_off_t num;
|
||||
struct URLPattern *pat = NULL;
|
||||
filename++;
|
||||
if(!curlx_str_number(&filename, &num, glob->pnum) && num) {
|
||||
size_t i;
|
||||
num--; /* make it zero based */
|
||||
|
|
@ -666,31 +730,49 @@ CURLcode glob_match_url(char **output, const char *filename,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(pat) {
|
||||
switch(pat->type) {
|
||||
case GLOB_SET:
|
||||
if(pat->c.set.elem)
|
||||
result = curlx_dyn_add(&dyn, pat->c.set.elem[pat->c.set.idx]);
|
||||
break;
|
||||
case GLOB_ASCII: {
|
||||
char letter = (char)pat->c.ascii.letter;
|
||||
result = curlx_dyn_addn(&dyn, &letter, 1);
|
||||
break;
|
||||
}
|
||||
case GLOB_NUM:
|
||||
result = curlx_dyn_addf(&dyn, "%0*" CURL_FORMAT_CURL_OFF_T,
|
||||
pat->c.num.npad, pat->c.num.idx);
|
||||
break;
|
||||
default:
|
||||
DEBUGASSERT(0);
|
||||
if(!pat)
|
||||
filename = ptr;
|
||||
}
|
||||
else if(*filename == '#' && (filename[1] == '<')) {
|
||||
/* a named glob reference */
|
||||
struct Curl_str name;
|
||||
const char *ptr = filename;
|
||||
filename += 2; /* pass both leading bytes */
|
||||
if(!curlx_str_until(&filename, &name, MAX_GLOBNAME_LEN, '>') &&
|
||||
!curlx_str_single(&filename, '>')) {
|
||||
/* find the correct glob entry */
|
||||
pat = glob_find_name(glob, &name);
|
||||
if(!pat) {
|
||||
/* when the name is given correctly, it needs to be an existing glob
|
||||
name, which makes this an error */
|
||||
curlx_dyn_free(&dyn);
|
||||
return CURLE_FAILED_INIT;
|
||||
return globerror(glob, "no glob exists with this name",
|
||||
filename - ifilename, CURLE_BAD_FUNCTION_ARGUMENT);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* #[num] out of range, use the #[num] in the output */
|
||||
result = curlx_dyn_addn(&dyn, ptr, filename - ptr);
|
||||
if(!pat)
|
||||
filename = ptr;
|
||||
}
|
||||
if(pat) {
|
||||
switch(pat->type) {
|
||||
case GLOB_SET:
|
||||
if(pat->c.set.elem)
|
||||
result = curlx_dyn_add(&dyn, pat->c.set.elem[pat->c.set.idx]);
|
||||
break;
|
||||
case GLOB_ASCII: {
|
||||
char letter = (char)pat->c.ascii.letter;
|
||||
result = curlx_dyn_addn(&dyn, &letter, 1);
|
||||
break;
|
||||
}
|
||||
case GLOB_NUM:
|
||||
result = curlx_dyn_addf(&dyn, "%0*" CURL_FORMAT_CURL_OFF_T,
|
||||
pat->c.num.npad, pat->c.num.idx);
|
||||
break;
|
||||
default:
|
||||
DEBUGASSERT(0);
|
||||
curlx_dyn_free(&dyn);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
}
|
||||
else
|
||||
result = curlx_dyn_addn(&dyn, filename++, 1);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ typedef enum {
|
|||
|
||||
struct URLPattern {
|
||||
globtype type;
|
||||
char *name; /* if not NULL */
|
||||
int globindex; /* the number of this particular glob or -1 if not used
|
||||
within {} or [] */
|
||||
union {
|
||||
|
|
@ -71,6 +72,9 @@ struct URLGlob {
|
|||
size_t pos; /* column position of error or 0 */
|
||||
};
|
||||
|
||||
void glob_show_error(struct URLGlob *glob, const char *url, FILE *error,
|
||||
CURLcode result);
|
||||
|
||||
CURLcode glob_url(struct URLGlob *glob, const char *url, curl_off_t *urlnum,
|
||||
FILE *error);
|
||||
CURLcode glob_next_url(char **globbed, struct URLGlob *glob);
|
||||
|
|
|
|||
|
|
@ -265,6 +265,7 @@ test2300 test2301 test2302 test2303 test2304 test2306 test2307 test2308 \
|
|||
test2309 \
|
||||
\
|
||||
test2400 test2401 test2402 test2403 test2404 test2405 test2406 test2407 \
|
||||
test2408 test2409 test2410 test2411 \
|
||||
\
|
||||
test2500 test2501 test2502 test2503 test2504 test2505 test2506 \
|
||||
\
|
||||
|
|
|
|||
92
tests/data/test2408
Normal file
92
tests/data/test2408
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="US-ASCII"?>
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
globbing
|
||||
{} list
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data crlf="headers" nocheck="yes">
|
||||
HTTP/1.1 200 OK
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
moo
|
||||
</data>
|
||||
<data2 crlf="headers">
|
||||
HTTP/1.1 200 OK
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
foo
|
||||
</data2>
|
||||
<data3 crlf="headers">
|
||||
HTTP/1.1 200 OK
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
hoo
|
||||
</data3>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
multiple requests using named {} globs in URL
|
||||
</name>
|
||||
<command option="no-output">
|
||||
"%HOSTIP:%HTTPPORT/{%LTtest%GT%TESTNUMBER,%TESTNUMBER0002,%TESTNUMBER0003}" -o "%LOGDIR/dump-#%LTtest%GT"
|
||||
</command>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol crlf="headers">
|
||||
GET /%TESTNUMBER HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
GET /%TESTNUMBER0002 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
GET /%TESTNUMBER0003 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
|
||||
<file name="%LOGDIR/dump-%TESTNUMBER" crlf="headers">
|
||||
HTTP/1.1 200 OK
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
moo
|
||||
</file>
|
||||
<file2 name="%LOGDIR/dump-%TESTNUMBER0002" crlf="headers">
|
||||
HTTP/1.1 200 OK
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
foo
|
||||
</file2>
|
||||
<file3 name="%LOGDIR/dump-%TESTNUMBER0003" crlf="headers">
|
||||
HTTP/1.1 200 OK
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
hoo
|
||||
</file3>
|
||||
|
||||
</verify>
|
||||
</testcase>
|
||||
92
tests/data/test2409
Normal file
92
tests/data/test2409
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="US-ASCII"?>
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
globbing
|
||||
{} list
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data crlf="headers" nocheck="yes">
|
||||
HTTP/1.1 200 swsbounce
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
moo
|
||||
</data>
|
||||
<data1 crlf="headers">
|
||||
HTTP/1.1 200 swsbounce
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
foo
|
||||
</data1>
|
||||
<data2 crlf="headers">
|
||||
HTTP/1.1 200 OK
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
hoo
|
||||
</data2>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
multiple requests using named [] globs in URL
|
||||
</name>
|
||||
<command option="no-output">
|
||||
"%HOSTIP:%HTTPPORT/hello[%LTtest%GT7-9]" -o "%LOGDIR/dump-#%LTtest%GT"
|
||||
</command>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol crlf="headers">
|
||||
GET /hello7 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
GET /hello8 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
GET /hello9 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
User-Agent: curl/%VERSION
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
|
||||
<file name="%LOGDIR/dump-7" crlf="headers">
|
||||
HTTP/1.1 200 swsbounce
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
moo
|
||||
</file>
|
||||
<file2 name="%LOGDIR/dump-8" crlf="headers">
|
||||
HTTP/1.1 200 swsbounce
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
foo
|
||||
</file2>
|
||||
<file3 name="%LOGDIR/dump-9" crlf="headers">
|
||||
HTTP/1.1 200 OK
|
||||
Funny-head: yesyes
|
||||
Content-Length: 4
|
||||
|
||||
hoo
|
||||
</file3>
|
||||
|
||||
</verify>
|
||||
</testcase>
|
||||
37
tests/data/test2410
Normal file
37
tests/data/test2410
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="US-ASCII"?>
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
globbing
|
||||
{} list
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
duplicate named glob
|
||||
</name>
|
||||
<command option="no-output">
|
||||
"%HOSTIP:%HTTPPORT/{%LTtest%GTA,B}{%LTtest%GTC,D}" -o "%LOGDIR/dump"
|
||||
</command>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<stderr mode="text">
|
||||
curl: (3) Duplicate glob name in position 30:
|
||||
%HOSTIP:%HTTPPORT/{%LTtest%GTA,B}{%LTtest%GTC,D}
|
||||
^
|
||||
</stderr>
|
||||
<errorcode>
|
||||
3
|
||||
</errorcode>
|
||||
</verify>
|
||||
</testcase>
|
||||
37
tests/data/test2411
Normal file
37
tests/data/test2411
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="US-ASCII"?>
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
globbing
|
||||
{} list
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
reference a named glob not set
|
||||
</name>
|
||||
<command option="no-output">
|
||||
"%HOSTIP:%HTTPPORT/{%LTtest%GTA,B}{%LTmoo%GTC,D}" -o "somewhere/#%LTfoo%GT"
|
||||
</command>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<stderr mode="text">
|
||||
curl: (43) no glob exists with this name in position 16:
|
||||
somewhere/#%LTfoo%GT
|
||||
^
|
||||
</stderr>
|
||||
<errorcode>
|
||||
43
|
||||
</errorcode>
|
||||
</verify>
|
||||
</testcase>
|
||||
|
|
@ -31,7 +31,7 @@ HTTP, urlglob retrieval with bad range
|
|||
3
|
||||
</errorcode>
|
||||
<stdout mode="text">
|
||||
curl: (3) bad range in URL position 47:
|
||||
curl: (3) bad range in position 47:
|
||||
http://a-site-never-accessed.example.org/[2-1]
|
||||
^
|
||||
</stdout>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ glob '{,'
|
|||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
# curl: (3) unmatched brace in URL position 1:
|
||||
# curl: (3) unmatched brace in position 1:
|
||||
<errorcode>
|
||||
3
|
||||
</errorcode>
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ http://testingthis/%repeat[201 x {a}b]%
|
|||
3
|
||||
</errorcode>
|
||||
<stderr mode="text">
|
||||
curl: (3) too many {} sets in URL position 403:
|
||||
http://testingthis/%repeat[113 x {a}b]%{a
|
||||
curl: (3) too many {} sets in position 403:
|
||||
http://testingthis/%repeat[114 x {a}b]%{a
|
||||
</stderr>
|
||||
</verify>
|
||||
</testcase>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue