Skip to content

Commit

Permalink
curl now can uploading file with ',' or ';' in filename.
Browse files Browse the repository at this point in the history
  • Loading branch information
ulion committed Jan 17, 2013
1 parent 4ed6b07 commit 1e99100
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 5 deletions.
8 changes: 8 additions & 0 deletions docs/curl.1
Expand Up @@ -484,6 +484,14 @@ filename=, like this:


\fBcurl\fP -F "file=@localfile;filename=nameinpost" url.com \fBcurl\fP -F "file=@localfile;filename=nameinpost" url.com


If filename/path contains ',' or ';', it must be quoted by double-quotes like:

\fBcurl\fP -F "file=@\\"localfile\\";filename=\\"nameinpost\\"" url.com

or

\fBcurl\fP -F 'file=@"localfile";filename="nameinpost"' url.com

See further examples and details in the MANUAL. See further examples and details in the MANUAL.


This option can be used multiple times. This option can be used multiple times.
Expand Down
51 changes: 49 additions & 2 deletions src/tool_formparse.c
Expand Up @@ -40,7 +40,8 @@
* *
* Reads a 'name=value' parameter and builds the appropriate linked list. * Reads a 'name=value' parameter and builds the appropriate linked list.
* *
* Specify files to upload with 'name=@filename'. Supports specified * Specify files to upload with 'name=@filename', or 'name=@"filename"'
* in case the filename contain ',' or ';'. Supports specified
* given Content-Type of the files. Such as ';type=<content-type>'. * given Content-Type of the files. Such as ';type=<content-type>'.
* *
* If literal_value is set, any initial '@' or '<' in the value string * If literal_value is set, any initial '@' or '<' in the value string
Expand All @@ -50,6 +51,10 @@
* multiple files by writing it like: * multiple files by writing it like:
* *
* 'name=@filename,filename2,filename3' * 'name=@filename,filename2,filename3'
*
* or use double-quotes quote the filename:
*
* 'name=@"filename","filename2","filename3"'
* *
* If you want content-types specified for each too, write them like: * If you want content-types specified for each too, write them like:
* *
Expand All @@ -64,7 +69,11 @@
* To upload a file, but to fake the file name that will be included in the * To upload a file, but to fake the file name that will be included in the
* formpost, do like this: * formpost, do like this:
* *
* 'name=@filename;filename=/dev/null' * 'name=@filename;filename=/dev/null' or quote the faked filename like:
* 'name=@filename;filename="play, play, and play.txt"'
*
* If filename/path contains ',' or ';', it must be quoted by double-quotes,
* else curl will fail to figure out the correct filename.
* *
* This function uses curl_formadd to fulfill it's job. Is heavily based on * This function uses curl_formadd to fulfill it's job. Is heavily based on
* the old curl_formparse code. * the old curl_formparse code.
Expand Down Expand Up @@ -115,6 +124,27 @@ int formparse(struct Configurable *config,
char *ptr; char *ptr;
char *filename = NULL; char *filename = NULL;


/* check whether the file part is quoted */
sep = NULL;
if ('"' == contp[0]) {
sep = strchr(contp+1, '"');
}
if (sep) {
contp += 1;
*sep = '\0'; /* terminate file name at the end quot */
ptr = sep+1; /* point to the text following the quot */

sep = strchr(ptr, ';');
sep2 = strchr(ptr, ',');

/* pick the closest */
if(sep2 && (sep2 < sep)) {
sep = sep2;

/* no type was specified! */
}
}
else {
sep = strchr(contp, ';'); sep = strchr(contp, ';');
sep2 = strchr(contp, ','); sep2 = strchr(contp, ',');


Expand All @@ -124,6 +154,7 @@ int formparse(struct Configurable *config,


/* no type was specified! */ /* no type was specified! */
} }
}


type = NULL; type = NULL;


Expand Down Expand Up @@ -182,6 +213,21 @@ int formparse(struct Configurable *config,
} }
else if(checkprefix("filename=", ptr)) { else if(checkprefix("filename=", ptr)) {
filename = &ptr[9]; filename = &ptr[9];
ptr = NULL;
if ('"' == filename[0]) {
ptr = strchr(filename+1, '"');
}
if (ptr) {
filename += 1;
*ptr = '\0'; /* zero terminate */
ptr++;
sep = strchr(ptr, ';');
if(!sep) {
sep = strchr(ptr, ',');
}
ptr = sep ? (sep + 1) : NULL;
}
else {
ptr = strchr(filename, ';'); ptr = strchr(filename, ';');
if(!ptr) { if(!ptr) {
ptr = strchr(filename, ','); ptr = strchr(filename, ',');
Expand All @@ -190,6 +236,7 @@ int formparse(struct Configurable *config,
*ptr = '\0'; /* zero terminate */ *ptr = '\0'; /* zero terminate */
ptr++; ptr++;
} }
}
} }
else else
/* confusion, bail out of loop */ /* confusion, bail out of loop */
Expand Down
2 changes: 1 addition & 1 deletion tests/data/Makefile.am
Expand Up @@ -75,7 +75,7 @@ test1094 test1095 test1096 test1097 test1098 test1099 test1100 test1101 \
test1102 test1103 test1104 test1105 test1106 test1107 test1108 test1109 \ test1102 test1103 test1104 test1105 test1106 test1107 test1108 test1109 \
test1110 test1111 test1112 test1113 test1114 test1115 test1116 test1117 \ test1110 test1111 test1112 test1113 test1114 test1115 test1116 test1117 \
test1118 test1119 test1120 test1121 test1122 test1123 test1124 test1125 \ test1118 test1119 test1120 test1121 test1122 test1123 test1124 test1125 \
test1126 test1127 test1128 test1129 test1130 test1131 test1132 \ test1126 test1127 test1128 test1129 test1130 test1131 test1132 test1133 \
test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \ test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \
test1208 test1209 test1210 test1211 \ test1208 test1209 test1210 test1211 \
test1220 test1221 test1222 test1223 \ test1220 test1221 test1222 test1223 \
Expand Down
95 changes: 95 additions & 0 deletions tests/data/test1133
@@ -0,0 +1,95 @@
<testcase>
<info>
<keywords>
HTTP
HTTP FORMPOST
</keywords>
</info>
# Server-side
<reply>
<data>
HTTP/1.1 200 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 10

blablabla
</data>
</reply>

# Client-side
<client>
<server>
http
</server>
<name>
HTTP RFC1867-type formposting with filename contains ',' and ';'
</name>
<command>
http://%HOSTIP:%HTTPPORT/we/want/1133 -F "file=@\"log/test1133,and;.txt\";type=mo/foo;filename=\"faker,and;.txt\"" -F 'file2=@"log/test1133,and;.txt"' -F 'file3=@"log/test1133,and;.txt";type=m/f,"log/test1133,and;.txt"'
</command>
# We create this file before the command is invoked!
<file name="log/test1133,and;.txt">
foo bar
This is a bar foo
bar
foo
</file>
</client>

# Verify data after the test has been "shot"
<verify>
<strip>
^(User-Agent:|Content-Type: multipart/form-data;|Content-Type: multipart/mixed, boundary=|-------).*
</strip>
<protocol>
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
Host: %HOSTIP:%HTTPPORT
Accept: */*
Content-Length: 961
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32

------------------------------24e78000bd32
Content-Disposition: form-data; name="file"; filename="faker,and;.txt"
Content-Type: mo/foo

foo bar
This is a bar foo
bar
foo

------------------------------24e78000bd32
Content-Disposition: form-data; name="file2"; filename="test1133,and;.txt"
Content-Type: text/plain

foo bar
This is a bar foo
bar
foo

------------------------------24e78000bd32
Content-Disposition: form-data; name="file3"
Content-Type: multipart/mixed, boundary=----------------------------7f0e85a48b0b

Content-Disposition: attachment; filename="test1133,and;.txt"
Content-Type: m/f

foo bar
This is a bar foo
bar
foo

Content-Disposition: attachment; filename="test1133,and;.txt"
Content-Type: text/plain

foo bar
This is a bar foo
bar
foo

------------------------------24e78000bd32--
</protocol>
</verify>
</testcase>
22 changes: 20 additions & 2 deletions tests/data/test39
Expand Up @@ -26,7 +26,7 @@ http
HTTP RFC1867-type formposting with filename= and type= HTTP RFC1867-type formposting with filename= and type=
</name> </name>
<command> <command>
http://%HOSTIP:%HTTPPORT/we/want/39 -F name=daniel -F tool=curl --form-string "str1=@literal" --form-string "str2=<verbatim;type=xxx/yyy" -F "file=@log/test39.txt;type=moo/foobar;filename=fakerfile" -F file2=@log/test39.txt http://%HOSTIP:%HTTPPORT/we/want/39 -F name=daniel -F tool=curl --form-string "str1=@literal" --form-string "str2=<verbatim;type=xxx/yyy" -F "file=@log/test39.txt;type=moo/foobar;filename=fakerfile" -F file2=@log/test39.txt -F "file3=@\"log/test39.txt\";type=mo/foo;filename=\"faker,and;.txt\"" -F 'file4=@"log/test39.txt"'
</command> </command>
# We create this file before the command is invoked! # We create this file before the command is invoked!
<file name="log/test39.txt"> <file name="log/test39.txt">
Expand All @@ -47,7 +47,7 @@ POST /we/want/39 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: 810 Content-Length: 1164
Expect: 100-continue Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32 Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32


Expand Down Expand Up @@ -85,6 +85,24 @@ This is a bar foo
bar bar
foo foo


------------------------------24e78000bd32
Content-Disposition: form-data; name="file3"; filename="faker,and;.txt"
Content-Type: mo/foo

foo bar
This is a bar foo
bar
foo

------------------------------24e78000bd32
Content-Disposition: form-data; name="file4"; filename="test39.txt"
Content-Type: text/plain

foo bar
This is a bar foo
bar
foo

------------------------------24e78000bd32-- ------------------------------24e78000bd32--
</protocol> </protocol>
</verify> </verify>
Expand Down

0 comments on commit 1e99100

Please sign in to comment.