Permalink
Browse files

curl now can uploading file with ',' or ';' in filename.

  • Loading branch information...
1 parent 4ed6b07 commit 1e9910082e1b0bdc40ae7846210171b5941f4172 @ulion committed Jan 17, 2013
Showing with 173 additions and 5 deletions.
  1. +8 −0 docs/curl.1
  2. +49 −2 src/tool_formparse.c
  3. +1 −1 tests/data/Makefile.am
  4. +95 −0 tests/data/test1133
  5. +20 −2 tests/data/test39
View
8 docs/curl.1
@@ -484,6 +484,14 @@ filename=, like this:
\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.
This option can be used multiple times.
View
51 src/tool_formparse.c
@@ -40,7 +40,8 @@
*
* 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>'.
*
* If literal_value is set, any initial '@' or '<' in the value string
@@ -50,6 +51,10 @@
* multiple files by writing it like:
*
* '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:
*
@@ -64,7 +69,11 @@
* To upload a file, but to fake the file name that will be included in the
* 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
* the old curl_formparse code.
@@ -115,6 +124,27 @@ int formparse(struct Configurable *config,
char *ptr;
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, ';');
sep2 = strchr(contp, ',');
@@ -124,6 +154,7 @@ int formparse(struct Configurable *config,
/* no type was specified! */
}
+ }
type = NULL;
@@ -182,6 +213,21 @@ int formparse(struct Configurable *config,
}
else if(checkprefix("filename=", ptr)) {
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, ';');
if(!ptr) {
ptr = strchr(filename, ',');
@@ -190,6 +236,7 @@ int formparse(struct Configurable *config,
*ptr = '\0'; /* zero terminate */
ptr++;
}
+ }
}
else
/* confusion, bail out of loop */
View
2 tests/data/Makefile.am
@@ -75,7 +75,7 @@ test1094 test1095 test1096 test1097 test1098 test1099 test1100 test1101 \
test1102 test1103 test1104 test1105 test1106 test1107 test1108 test1109 \
test1110 test1111 test1112 test1113 test1114 test1115 test1116 test1117 \
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 \
test1208 test1209 test1210 test1211 \
test1220 test1221 test1222 test1223 \
View
95 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>
View
22 tests/data/test39
@@ -26,7 +26,7 @@ http
HTTP RFC1867-type formposting with filename= and type=
</name>
<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>
# We create this file before the command is invoked!
<file name="log/test39.txt">
@@ -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
Host: %HOSTIP:%HTTPPORT
Accept: */*
-Content-Length: 810
+Content-Length: 1164
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32
@@ -85,6 +85,24 @@ This is a bar foo
bar
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--
</protocol>
</verify>

0 comments on commit 1e99100

Please sign in to comment.