mirror of https://github.com/moparisthebest/curl
cli tool: in -F option arg, comma is a delimiter for files only
Also upgrade test 1133 to cover this case and clarify man page about form data quoting. Bug: https://github.com/curl/curl/issues/2022 Reported-By: omau on github
This commit is contained in:
parent
7ee59512f8
commit
f82f952d2f
|
@ -57,6 +57,11 @@ or
|
||||||
Note that if a filename/path is quoted by double-quotes, any double-quote
|
Note that if a filename/path is quoted by double-quotes, any double-quote
|
||||||
or backslash within the filename must be escaped by backslash.
|
or backslash within the filename must be escaped by backslash.
|
||||||
|
|
||||||
|
Quoting must also be applied to non-file data if it contains semicolons,
|
||||||
|
leading/trailing spaces or leading double quotes:
|
||||||
|
|
||||||
|
curl -F 'colors="red; green; blue";type=text/x-myapp' example.com
|
||||||
|
|
||||||
You can add custom headers to the field by setting headers=, like
|
You can add custom headers to the field by setting headers=, like
|
||||||
|
|
||||||
curl -F "submit=OK;headers=\\"X-submit-type: OK\\"" example.com
|
curl -F "submit=OK;headers=\\"X-submit-type: OK\\"" example.com
|
||||||
|
|
|
@ -52,13 +52,12 @@ typedef struct {
|
||||||
* after call get_parm_word, str either point to string end
|
* after call get_parm_word, str either point to string end
|
||||||
* or point to any of end chars.
|
* or point to any of end chars.
|
||||||
*/
|
*/
|
||||||
static char *get_param_word(char **str, char **end_pos)
|
static char *get_param_word(char **str, char **end_pos, char endchar)
|
||||||
{
|
{
|
||||||
char *ptr = *str;
|
char *ptr = *str;
|
||||||
char *word_begin = NULL;
|
char *word_begin = NULL;
|
||||||
char *ptr2;
|
char *ptr2;
|
||||||
char *escape = NULL;
|
char *escape = NULL;
|
||||||
const char *end_chars = ";,";
|
|
||||||
|
|
||||||
/* the first non-space char is here */
|
/* the first non-space char is here */
|
||||||
word_begin = ptr;
|
word_begin = ptr;
|
||||||
|
@ -88,7 +87,7 @@ static char *get_param_word(char **str, char **end_pos)
|
||||||
while(ptr < *end_pos);
|
while(ptr < *end_pos);
|
||||||
*end_pos = ptr2;
|
*end_pos = ptr2;
|
||||||
}
|
}
|
||||||
while(*ptr && NULL == strchr(end_chars, *ptr))
|
while(*ptr && *ptr != ';' && *ptr != endchar)
|
||||||
++ptr;
|
++ptr;
|
||||||
*str = ptr;
|
*str = ptr;
|
||||||
return word_begin + 1;
|
return word_begin + 1;
|
||||||
|
@ -99,7 +98,7 @@ static char *get_param_word(char **str, char **end_pos)
|
||||||
ptr = word_begin;
|
ptr = word_begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(*ptr && NULL == strchr(end_chars, *ptr))
|
while(*ptr && *ptr != ';' && *ptr != endchar)
|
||||||
++ptr;
|
++ptr;
|
||||||
*str = *end_pos = ptr;
|
*str = *end_pos = ptr;
|
||||||
return word_begin;
|
return word_begin;
|
||||||
|
@ -181,9 +180,10 @@ static int read_field_headers(struct OperationConfig *config,
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_param_part(struct OperationConfig *config, char **str,
|
static int get_param_part(struct OperationConfig *config, char endchar,
|
||||||
char **pdata, char **ptype, char **pfilename,
|
char **str, char **pdata, char **ptype,
|
||||||
char **pencoder, struct curl_slist **pheaders)
|
char **pfilename, char **pencoder,
|
||||||
|
struct curl_slist **pheaders)
|
||||||
{
|
{
|
||||||
char *p = *str;
|
char *p = *str;
|
||||||
char *type = NULL;
|
char *type = NULL;
|
||||||
|
@ -208,7 +208,7 @@ static int get_param_part(struct OperationConfig *config, char **str,
|
||||||
while(ISSPACE(*p))
|
while(ISSPACE(*p))
|
||||||
p++;
|
p++;
|
||||||
tp = p;
|
tp = p;
|
||||||
*pdata = get_param_word(&p, &endpos);
|
*pdata = get_param_word(&p, &endpos, endchar);
|
||||||
/* If not quoted, strip trailing spaces. */
|
/* If not quoted, strip trailing spaces. */
|
||||||
if(*pdata == tp)
|
if(*pdata == tp)
|
||||||
while(endpos > *pdata && ISSPACE(endpos[-1]))
|
while(endpos > *pdata && ISSPACE(endpos[-1]))
|
||||||
|
@ -249,7 +249,7 @@ static int get_param_part(struct OperationConfig *config, char **str,
|
||||||
for(p += 9; ISSPACE(*p); p++)
|
for(p += 9; ISSPACE(*p); p++)
|
||||||
;
|
;
|
||||||
tp = p;
|
tp = p;
|
||||||
filename = get_param_word(&p, &endpos);
|
filename = get_param_word(&p, &endpos, endchar);
|
||||||
/* If not quoted, strip trailing spaces. */
|
/* If not quoted, strip trailing spaces. */
|
||||||
if(filename == tp)
|
if(filename == tp)
|
||||||
while(endpos > filename && ISSPACE(endpos[-1]))
|
while(endpos > filename && ISSPACE(endpos[-1]))
|
||||||
|
@ -272,7 +272,7 @@ static int get_param_part(struct OperationConfig *config, char **str,
|
||||||
p++;
|
p++;
|
||||||
} while(ISSPACE(*p));
|
} while(ISSPACE(*p));
|
||||||
tp = p;
|
tp = p;
|
||||||
hdrfile = get_param_word(&p, &endpos);
|
hdrfile = get_param_word(&p, &endpos, endchar);
|
||||||
/* If not quoted, strip trailing spaces. */
|
/* If not quoted, strip trailing spaces. */
|
||||||
if(hdrfile == tp)
|
if(hdrfile == tp)
|
||||||
while(endpos > hdrfile && ISSPACE(endpos[-1]))
|
while(endpos > hdrfile && ISSPACE(endpos[-1]))
|
||||||
|
@ -300,7 +300,7 @@ static int get_param_part(struct OperationConfig *config, char **str,
|
||||||
while(ISSPACE(*p))
|
while(ISSPACE(*p))
|
||||||
p++;
|
p++;
|
||||||
tp = p;
|
tp = p;
|
||||||
hdr = get_param_word(&p, &endpos);
|
hdr = get_param_word(&p, &endpos, endchar);
|
||||||
/* If not quoted, strip trailing spaces. */
|
/* If not quoted, strip trailing spaces. */
|
||||||
if(hdr == tp)
|
if(hdr == tp)
|
||||||
while(endpos > hdr && ISSPACE(endpos[-1]))
|
while(endpos > hdr && ISSPACE(endpos[-1]))
|
||||||
|
@ -322,7 +322,7 @@ static int get_param_part(struct OperationConfig *config, char **str,
|
||||||
for(p += 8; ISSPACE(*p); p++)
|
for(p += 8; ISSPACE(*p); p++)
|
||||||
;
|
;
|
||||||
tp = p;
|
tp = p;
|
||||||
encoder = get_param_word(&p, &endpos);
|
encoder = get_param_word(&p, &endpos, endchar);
|
||||||
/* If not quoted, strip trailing spaces. */
|
/* If not quoted, strip trailing spaces. */
|
||||||
if(encoder == tp)
|
if(encoder == tp)
|
||||||
while(endpos > encoder && ISSPACE(endpos[-1]))
|
while(endpos > encoder && ISSPACE(endpos[-1]))
|
||||||
|
@ -332,7 +332,7 @@ static int get_param_part(struct OperationConfig *config, char **str,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* unknown prefix, skip to next block */
|
/* unknown prefix, skip to next block */
|
||||||
char *unknown = get_param_word(&p, &endpos);
|
char *unknown = get_param_word(&p, &endpos, endchar);
|
||||||
|
|
||||||
sep = *p;
|
sep = *p;
|
||||||
if(endct)
|
if(endct)
|
||||||
|
@ -598,7 +598,8 @@ int formparse(struct OperationConfig *config,
|
||||||
curl_mime *subparts;
|
curl_mime *subparts;
|
||||||
|
|
||||||
/* Starting a multipart. */
|
/* Starting a multipart. */
|
||||||
sep = get_param_part(config, &contp, &data, &type, NULL, NULL, &headers);
|
sep = get_param_part(config, '\0',
|
||||||
|
&contp, &data, &type, NULL, NULL, &headers);
|
||||||
if(sep < 0) {
|
if(sep < 0) {
|
||||||
Curl_safefree(contents);
|
Curl_safefree(contents);
|
||||||
return 3;
|
return 3;
|
||||||
|
@ -657,7 +658,7 @@ int formparse(struct OperationConfig *config,
|
||||||
/* since this was a file, it may have a content-type specifier
|
/* since this was a file, it may have a content-type specifier
|
||||||
at the end too, or a filename. Or both. */
|
at the end too, or a filename. Or both. */
|
||||||
++contp;
|
++contp;
|
||||||
sep = get_param_part(config, &contp,
|
sep = get_param_part(config, ',', &contp,
|
||||||
&data, &type, &filename, &encoder, &headers);
|
&data, &type, &filename, &encoder, &headers);
|
||||||
if(sep < 0) {
|
if(sep < 0) {
|
||||||
if(subparts != *mimecurrent)
|
if(subparts != *mimecurrent)
|
||||||
|
@ -767,7 +768,7 @@ int formparse(struct OperationConfig *config,
|
||||||
|
|
||||||
if(*contp == '<' && !literal_value) {
|
if(*contp == '<' && !literal_value) {
|
||||||
++contp;
|
++contp;
|
||||||
sep = get_param_part(config, &contp,
|
sep = get_param_part(config, '\0', &contp,
|
||||||
&data, &type, NULL, &encoder, &headers);
|
&data, &type, NULL, &encoder, &headers);
|
||||||
if(sep < 0) {
|
if(sep < 0) {
|
||||||
Curl_safefree(contents);
|
Curl_safefree(contents);
|
||||||
|
@ -796,7 +797,7 @@ int formparse(struct OperationConfig *config,
|
||||||
if(literal_value)
|
if(literal_value)
|
||||||
data = contp;
|
data = contp;
|
||||||
else {
|
else {
|
||||||
sep = get_param_part(config, &contp,
|
sep = get_param_part(config, '\0', &contp,
|
||||||
&data, &type, &filename, &encoder, &headers);
|
&data, &type, &filename, &encoder, &headers);
|
||||||
if(sep < 0) {
|
if(sep < 0) {
|
||||||
Curl_safefree(contents);
|
Curl_safefree(contents);
|
||||||
|
|
|
@ -23,10 +23,10 @@ blablabla
|
||||||
http
|
http
|
||||||
</server>
|
</server>
|
||||||
<name>
|
<name>
|
||||||
HTTP RFC1867-type formposting with filename contains ',', ';', '"'
|
HTTP RFC1867-type formposting with filename/data contains ',', ';', '"'
|
||||||
</name>
|
</name>
|
||||||
<command>
|
<command>
|
||||||
http://%HOSTIP:%HTTPPORT/we/want/1133 -F "file=@\"log/test1133,a\\\"nd;.txt\";type=mo/foo;filename=\"faker,and;.txt\"" -F 'file2=@"log/test1133,a\"nd;.txt"' -F 'file3=@"log/test1133,a\"nd;.txt";type=m/f,"log/test1133,a\"nd;.txt"'
|
http://%HOSTIP:%HTTPPORT/we/want/1133 -F "file=@\"log/test1133,a\\\"nd;.txt\";type=mo/foo;filename=\"faker,and;.txt\"" -F 'file2=@"log/test1133,a\"nd;.txt"' -F 'file3=@"log/test1133,a\"nd;.txt";type=m/f,"log/test1133,a\"nd;.txt"' -F a="{\"field1\":\"value1\",\"field2\":\"value2\"}" -F 'b=" \\value1;type=\"whatever\" "; type=text/foo; charset=utf-8 ; filename=param_b'
|
||||||
</command>
|
</command>
|
||||||
# We create this file before the command is invoked!
|
# We create this file before the command is invoked!
|
||||||
<file name=log/test1133,a"nd;.txt>
|
<file name=log/test1133,a"nd;.txt>
|
||||||
|
@ -47,7 +47,8 @@ POST /we/want/1133 HTTP/1.1
|
||||||
User-Agent: curl/7.10.4 (i686-pc-linux-gnu) libcurl/7.10.4 OpenSSL/0.9.7a ipv6 zlib/1.1.3
|
User-Agent: curl/7.10.4 (i686-pc-linux-gnu) libcurl/7.10.4 OpenSSL/0.9.7a ipv6 zlib/1.1.3
|
||||||
Host: %HOSTIP:%HTTPPORT
|
Host: %HOSTIP:%HTTPPORT
|
||||||
Accept: */*
|
Accept: */*
|
||||||
Content-Length: 969
|
Content-Length: 1270
|
||||||
|
Expect: 100-continue
|
||||||
Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32
|
Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32
|
||||||
|
|
||||||
------------------------------24e78000bd32
|
------------------------------24e78000bd32
|
||||||
|
@ -89,6 +90,13 @@ bar
|
||||||
foo
|
foo
|
||||||
|
|
||||||
|
|
||||||
|
Content-Disposition: form-data; name="a"
|
||||||
|
|
||||||
|
{"field1":"value1","field2":"value2"}
|
||||||
|
Content-Disposition: form-data; name="b"; filename="param_b"
|
||||||
|
Content-Type: text/foo; charset=utf-8
|
||||||
|
|
||||||
|
\value1;type="whatever"
|
||||||
------------------------------24e78000bd32--
|
------------------------------24e78000bd32--
|
||||||
</protocol>
|
</protocol>
|
||||||
</verify>
|
</verify>
|
||||||
|
|
Loading…
Reference in New Issue