mime: use percent-escaping for multipart form field and file names

Until now, form field and file names where escaped using the
backslash-escaping algorithm defined for multipart mails. This commit
replaces this with the percent-escaping method for URLs.

As this may introduce incompatibilities with server-side applications, a
new libcurl option CURLOPT_MIME_OPTIONS with bitmask
CURLMIMEOPT_FORMESCAPE is introduced to revert to legacy use of
backslash-escaping. This is controlled by new cli tool option
--form-escape.

New tests and documentation are provided for this feature.

Reported by: Ryan Sleevi
Fixes #7789
Closes #7805
This commit is contained in:
Patrick Monnerat 2021-10-25 12:58:37 +02:00 committed by Daniel Stenberg
parent 6ec28eb687
commit b20b364764
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
23 changed files with 463 additions and 30 deletions

View File

@ -75,6 +75,7 @@ DPAGES = \
fail-with-body.d \
fail.d \
false-start.d \
form-escape.d \
form-string.d \
form.d \
ftp-account.d \

View File

@ -0,0 +1,10 @@
Long: form-escape
Help: Escape multipart form field/file names using backslash
Protocols: HTTP
See-also: form
Added: 7.81.0
Category: http post
Example: --form-escape --form 'field\\name=curl' 'file=@load"this' $URL
---
Tells curl to pass on names of multipart form fields and files using
backslash-escaping instead of percent-encoding.

View File

@ -462,6 +462,8 @@ Upload data. See \fICURLOPT_UPLOAD(3)\fP
Set upload buffer size. See \fICURLOPT_UPLOAD_BUFFERSIZE(3)\fP
.IP CURLOPT_MIMEPOST
Post/send MIME data. See \fICURLOPT_MIMEPOST(3)\fP
.IP CURLOPT_MIME_OPTIONS
Set MIME option flags. See \fICURLOPT_MIME_OPTIONS(3)\fP
.IP CURLOPT_MAXFILESIZE
Maximum file size to get. See \fICURLOPT_MAXFILESIZE(3)\fP
.IP CURLOPT_MAXFILESIZE_LARGE

View File

@ -0,0 +1,89 @@
.\" **************************************************************************
.\" * _ _ ____ _
.\" * Project ___| | | | _ \| |
.\" * / __| | | | |_) | |
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
.\" * are also available at https://curl.se/docs/copyright.html.
.\" *
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
.\" * copies of the Software, and permit persons to whom the Software is
.\" * furnished to do so, under the terms of the COPYING file.
.\" *
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
.\" * KIND, either express or implied.
.\" *
.\" **************************************************************************
.\"
.TH CURLOPT_MIME_OPTIONS 3 "2 Oct 2021" "libcurl 7.81.0" "curl_easy_setopt options"
.SH NAME
CURLOPT_MIME_OPTIONS \- set MIME option flags
.SH SYNOPSIS
#include <curl/curl.h>
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MIME_OPTIONS, long options);
.SH DESCRIPTION
Pass a long that holds a bitmask of CURLMIMEOPT_* defines. Each bit is a
Boolean flag used while encoding a MIME tree or multipart form data.
Available bits are:
.IP CURLMIMEOPT_FORMESCAPE
Tells libcurl to escape multipart form field and file names using the
backslash-escaping algorithm rather than percent-encoding (HTTP only).
Backslash-escaping consists in preceding backslashes and double quotes with
a backslash. Percent encoding maps all occurrences of double quote,
carriage return and line feed to %22, %0D and %0A respectively.
Before version 7.81.0, percent-encoding was never applied.
HTTP browsers used to do backslash-escaping in the past but have over time
transitioned to use percent-encoding. This option allows to address
server-side applications that have not yet have been converted.
As an example, consider field or file name \fIstrange\\name"kind\fP.
When the containing multipart form is sent, this is normally transmitted as
\fIstrange\\name%22kind\fP. When this option is set, it is sent as
\fIstrange\\\\name\\"kind\fP.
.SH DEFAULT
0, meaning disabled.
.SH PROTOCOLS
HTTP, IMAP, SMTP
.SH EXAMPLE
.nf
CURL *curl = curl_easy_init();
curl_mime *form = NULL;
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
curl_easy_setopt(curl, CURLOPT_MIME_OPTIONS, CURLMIMEOPT_FORMESCAPE);
form = curl_mime_init(curl);
if(form) {
curl_mimepart *part = curl_mime_addpart(form);
if(part) {
curl_mime_filedata(part, "strange\\\\file\\\\name");
curl_mime_name(part, "strange\\"field\\"name");
curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
/* Perform the request */
curl_easy_perform(curl);
}
}
curl_easy_cleanup(curl);
curl_mime_free(mime);
}
.fi
.SH AVAILABILITY
Option added in 7.81.0.
.SH RETURN VALUE
Returns CURLE_OK
.SH "SEE ALSO"
.BR CURLOPT_MIMEPOST "(3), " CURLOPT_HTTPPOST "(3)"

View File

@ -233,6 +233,7 @@ man_MANS = \
CURLOPT_MAX_RECV_SPEED_LARGE.3 \
CURLOPT_MAX_SEND_SPEED_LARGE.3 \
CURLOPT_MIMEPOST.3 \
CURLOPT_MIME_OPTIONS.3 \
CURLOPT_NETRC.3 \
CURLOPT_NETRC_FILE.3 \
CURLOPT_NEW_DIRECTORY_PERMS.3 \

View File

@ -324,6 +324,7 @@ CURLKHTYPE_ED25519 7.58.0
CURLKHTYPE_RSA 7.19.6
CURLKHTYPE_RSA1 7.19.6
CURLKHTYPE_UNKNOWN 7.19.6
CURLMIMEOPT_FORMESCAPE 7.81.0
CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE 7.30.0
CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE 7.30.0
CURLMOPT_MAXCONNECTS 7.16.3
@ -504,6 +505,7 @@ CURLOPT_MAXREDIRS 7.5
CURLOPT_MAX_RECV_SPEED_LARGE 7.15.5
CURLOPT_MAX_SEND_SPEED_LARGE 7.15.5
CURLOPT_MIMEPOST 7.56.0
CURLOPT_MIME_OPTIONS 7.81.0
CURLOPT_MUTE 7.1 7.8 7.15.5
CURLOPT_NETRC 7.1
CURLOPT_NETRC_FILE 7.11.0

View File

@ -64,6 +64,7 @@
--fail-with-body 7.76.0
--false-start 7.42.0
--form (-F) 5.0
--form-escape 7.81.0
--form-string 7.13.2
--ftp-account 7.13.0
--ftp-alternative-to-user 7.15.5

View File

@ -2132,6 +2132,9 @@ typedef enum {
* (in seconds) */
CURLOPT(CURLOPT_MAXLIFETIME_CONN, CURLOPTTYPE_LONG, 314),
/* Set MIME option flags. */
CURLOPT(CURLOPT_MIME_OPTIONS, CURLOPTTYPE_LONG, 315),
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
@ -2291,6 +2294,9 @@ CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n);
typedef struct curl_mime curl_mime; /* Mime context. */
typedef struct curl_mimepart curl_mimepart; /* Mime part context. */
/* CURLMIMEOPT_ defines are for the CURLOPT_MIME_OPTIONS option. */
#define CURLMIMEOPT_FORMESCAPE (1<<0) /* Use backslash-escaping for forms. */
/*
* NAME curl_mime_init()
*

View File

@ -170,6 +170,7 @@ struct curl_easyoption Curl_easyopts[] = {
{"MAX_RECV_SPEED_LARGE", CURLOPT_MAX_RECV_SPEED_LARGE, CURLOT_OFF_T, 0},
{"MAX_SEND_SPEED_LARGE", CURLOPT_MAX_SEND_SPEED_LARGE, CURLOT_OFF_T, 0},
{"MIMEPOST", CURLOPT_MIMEPOST, CURLOT_OBJECT, 0},
{"MIME_OPTIONS", CURLOPT_MIME_OPTIONS, CURLOT_LONG, 0},
{"NETRC", CURLOPT_NETRC, CURLOT_VALUES, 0},
{"NETRC_FILE", CURLOPT_NETRC_FILE, CURLOT_STRING, 0},
{"NEW_DIRECTORY_PERMS", CURLOPT_NEW_DIRECTORY_PERMS, CURLOT_LONG, 0},
@ -359,6 +360,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
return ((CURLOPT_LASTENTRY%10000) != (314 + 1));
return ((CURLOPT_LASTENTRY%10000) != (315 + 1));
}
#endif

View File

@ -40,6 +40,7 @@
#include "rand.h"
#include "slist.h"
#include "strcase.h"
#include "dynbuf.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@ -279,29 +280,52 @@ static void mimesetstate(struct mime_state *state,
/* Escape header string into allocated memory. */
static char *escape_string(const char *src)
static char *escape_string(struct Curl_easy *data,
const char *src, enum mimestrategy strategy)
{
size_t bytecount = 0;
size_t i;
char *dst;
CURLcode result;
struct dynbuf db;
const char * const *table;
const char * const *p;
/* replace first character by rest of string. */
static const char * const mimetable[] = {
"\\\\\\",
"\"\\\"",
NULL
};
/* WHATWG HTML living standard 4.10.21.8 2 specifies:
For field names and filenames for file fields, the result of the
encoding in the previous bullet point must be escaped by replacing
any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D`
and 0x22 (") with `%22`.
The user agent must not perform any other escapes. */
static const char * const formtable[] = {
"\"%22",
"\r%0D",
"\n%0A",
NULL
};
for(i = 0; src[i]; i++)
if(src[i] == '"' || src[i] == '\\')
bytecount++;
table = formtable;
/* data can be NULL when this function is called indirectly from
curl_formget(). */
if(strategy == MIMESTRATEGY_MAIL ||
(data && (data->set.mime_options & CURLMIMEOPT_FORMESCAPE)))
table = mimetable;
bytecount += i;
dst = malloc(bytecount + 1);
if(!dst)
return NULL;
Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
for(i = 0; *src; src++) {
if(*src == '"' || *src == '\\')
dst[i++] = '\\';
dst[i++] = *src;
for(result = Curl_dyn_add(&db, ""); !result && *src; src++) {
for(p = table; *p && **p != *src; p++)
;
if(*p)
result = Curl_dyn_add(&db, *p + 1);
else
result = Curl_dyn_addn(&db, src, 1);
}
dst[i] = '\0';
return dst;
return Curl_dyn_ptr(&db);
}
/* Check if header matches. */
@ -1866,12 +1890,12 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
char *filename = NULL;
if(part->name) {
name = escape_string(part->name);
name = escape_string(part->easy, part->name, strategy);
if(!name)
ret = CURLE_OUT_OF_MEMORY;
}
if(!ret && part->filename) {
filename = escape_string(part->filename);
filename = escape_string(part->easy, part->filename, strategy);
if(!filename)
ret = CURLE_OUT_OF_MEMORY;
}

View File

@ -2609,6 +2609,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
#endif
#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \
!defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP)
case CURLOPT_MIME_OPTIONS:
data->set.mime_options = va_arg(param, long);
break;
#endif
case CURLOPT_SASL_AUTHZID:
/* Authorisation identity (identity to act as) */
result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID],

View File

@ -1749,6 +1749,7 @@ struct UserDefined {
unsigned int scope_id; /* Scope id for IPv6 */
long allowed_protocols;
long redir_protocols;
long mime_options; /* Mime option flags. */
struct curl_slist *mail_rcpt; /* linked list of mail recipients */
/* Common RTSP header options */
Curl_RtspReq rtspreq; /* RTSP request type */

View File

@ -1585,6 +1585,8 @@
d c 40310
d CURLOPT_MAXLIFETIME_CONN...
d c 00314
d CURLOPT_MIME_OPTIONS...
d c 00315
*
/if not defined(CURL_NO_OLDIES)
d CURLOPT_FILE c 10001
@ -1676,6 +1678,9 @@
d CURLFORM_CONTENTLEN...
d c 20
*
d CURLMIMEOPT_FORMESCAPE...
d X'0000000'
*
d CURLINFO s 10i 0 based(######ptr######) Enum
d CURLINFO_EFFECTIVE_URL... CURLINFO_STRING + 1
d c X'00100001'

View File

@ -239,6 +239,7 @@ struct OperationConfig {
char *ftp_account; /* for ACCT */
char *ftp_alternative_to_user; /* send command if USER/PASS fails */
int ftp_filemethod;
long mime_options; /* Mime option flags. */
long tftp_blksize; /* TFTP BLKSIZE option */
bool tftp_no_options; /* do not send TFTP options requests */
bool ignorecl; /* --ignore-content-length */

View File

@ -138,6 +138,7 @@ static const struct LongShort aliases[]= {
{"$h", "retry-delay", ARG_STRING},
{"$i", "retry-max-time", ARG_STRING},
{"$k", "proxy-negotiate", ARG_BOOL},
{"$l", "form-escape", ARG_BOOL},
{"$m", "ftp-account", ARG_STRING},
{"$n", "proxy-anyauth", ARG_BOOL},
{"$o", "trace-time", ARG_BOOL},
@ -988,6 +989,12 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
return PARAM_LIBCURL_DOESNT_SUPPORT;
break;
case 'l': /* --form-escape */
config->mime_options &= ~CURLMIMEOPT_FORMESCAPE;
if(toggle)
config->mime_options |= CURLMIMEOPT_FORMESCAPE;
break;
case 'm': /* --ftp-account */
GetStr(&config->ftp_account, nextarg);
break;

View File

@ -193,6 +193,9 @@ const struct helptxt helptext[] = {
{"-F, --form <name=content>",
"Specify multipart MIME data",
CURLHELP_HTTP | CURLHELP_UPLOAD},
{" --form-escape",
"Escape multipart form field/file names using backslash",
CURLHELP_HTTP | CURLHELP_POST},
{" --form-string <name=string>",
"Specify multipart MIME data",
CURLHELP_HTTP | CURLHELP_UPLOAD},

View File

@ -1325,6 +1325,10 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(result)
break;
/* new in libcurl 7.81.0 */
if(config->mime_options)
my_setopt(curl, CURLOPT_MIME_OPTIONS, config->mime_options);
/* new in libcurl 7.10.6 (default is Basic) */
if(config->authtype)
my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, (long)config->authtype);

View File

@ -144,8 +144,7 @@ test1152 test1153 test1154 test1155 test1156 test1157 test1158 test1159 \
test1160 test1161 test1162 test1163 test1164 test1165 test1166 test1167 \
test1168 test1169 test1170 test1171 test1172 test1173 test1174 test1175 \
test1176 test1177 test1178 test1179 test1180 test1181 test1182 test1183 \
test1184 test1185 \
test1188 \
test1184 test1185 test1186 test1187 test1188 test1189 \
\
test1190 test1191 test1192 test1193 test1194 test1195 test1196 test1197 \
test1198 test1199 \

View File

@ -50,11 +50,11 @@ POST /we/want/%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Content-Length: 954
Content-Length: 958
Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32
------------------------------24e78000bd32
Content-Disposition: form-data; name="file"; filename="test%TESTNUMBER\".txt"
Content-Disposition: form-data; name="file"; filename="test%TESTNUMBER%22.txt"
Content-Type: mo/foo
foo bar
@ -63,7 +63,7 @@ bar
foo
------------------------------24e78000bd32
Content-Disposition: form-data; name="file2"; filename="test%TESTNUMBER\".txt"
Content-Disposition: form-data; name="file2"; filename="test%TESTNUMBER%22.txt"
Content-Type: text/plain
foo bar
@ -75,7 +75,7 @@ foo
Content-Disposition: form-data; name="file3"
Content-Type: multipart/mixed; boundary=----------------------------7f0e85a48b0b
Content-Disposition: attachment; filename="test%TESTNUMBER\".txt"
Content-Disposition: attachment; filename="test%TESTNUMBER%22.txt"
Content-Type: m/f
foo bar
@ -83,7 +83,7 @@ This is a bar foo
bar
foo
Content-Disposition: attachment; filename="test%TESTNUMBER\".txt"
Content-Disposition: attachment; filename="test%TESTNUMBER%22.txt"
Content-Type: text/plain
foo bar

98
tests/data/test1186 Normal file
View File

@ -0,0 +1,98 @@
<testcase>
<info>
<keywords>
HTTP
HTTP FORMPOST
</keywords>
</info>
# Server-side
<reply>
<data>
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 10
blablabla
</data>
</reply>
# Client-side
<client>
<server>
http
</server>
<name>
Multipart formposting with backslash-escaping filename containing '"'
</name>
<command>
http://%HOSTIP:%HTTPPORT/we/want/%TESTNUMBER --form-escape -F "file=@\"log/test%TESTNUMBER\\\".txt\";type=mo/foo;filename=\"test%TESTNUMBER\\\".txt\"" -F 'file2=@"log/test%TESTNUMBER\".txt"' -F 'file3=@"log/test%TESTNUMBER\".txt";type=m/f,"log/test%TESTNUMBER\".txt"'
</command>
<precheck>
perl -e "print 'Test requires a system supporting double quotes in file names' if ($^O eq 'msys');"
</precheck>
# We create this file before the command is invoked!
<file name=log/test%TESTNUMBER".txt>
foo bar
This is a bar foo
bar
foo
</file>
</client>
# Verify data after the test has been "shot"
<verify>
<strip>
^(Content-Type: multipart/form-data;|Content-Type: multipart/mixed; boundary=|-------).*
</strip>
<protocol>
POST /we/want/%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Content-Length: 954
Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32
------------------------------24e78000bd32
Content-Disposition: form-data; name="file"; filename="test%TESTNUMBER\".txt"
Content-Type: mo/foo
foo bar
This is a bar foo
bar
foo
------------------------------24e78000bd32
Content-Disposition: form-data; name="file2"; filename="test%TESTNUMBER\".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="test%TESTNUMBER\".txt"
Content-Type: m/f
foo bar
This is a bar foo
bar
foo
Content-Disposition: attachment; filename="test%TESTNUMBER\".txt"
Content-Type: text/plain
foo bar
This is a bar foo
bar
foo
------------------------------24e78000bd32--
</protocol>
</verify>
</testcase>

63
tests/data/test1187 Normal file
View File

@ -0,0 +1,63 @@
<testcase>
<info>
<keywords>
SMTP
MULTIPART
</keywords>
</info>
#
# Server-side
<reply>
</reply>
#
# Client-side
<client>
<server>
smtp
</server>
<name>
SMTP multipart with file name escaping
</name>
<stdin>
From: different
To: another
body
</stdin>
<command>
smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -F "=This is the mail text" -F '=File content;filename="strange\file\"name"'
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<strippart>
s/^--------------------------[a-z0-9]*/------------------------------/
s/boundary=------------------------[a-z0-9]*/boundary=----------------------------/
</strippart>
<protocol>
EHLO %TESTNUMBER
MAIL FROM:<sender@example.com>
RCPT TO:<recipient@example.com>
DATA
QUIT
</protocol>
<upload>
Content-Type: multipart/mixed; boundary=----------------------------
Mime-Version: 1.0
------------------------------
This is the mail text
------------------------------
Content-Disposition: attachment; filename="strange\\file\"name"
File content
--------------------------------
.
</upload>
</verify>
</testcase>

108
tests/data/test1189 Normal file
View File

@ -0,0 +1,108 @@
<testcase>
<info>
<keywords>
HTTP
HTTP FORMPOST
</keywords>
</info>
# Server-side
<reply>
<data>
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 10
blablabla
</data>
</reply>
# Client-side
<client>
<server>
http
</server>
<name>
Multipart formposting with backslash-escaping of name= and filename=
</name>
<command>
http://%HOSTIP:%HTTPPORT/we/want/%TESTNUMBER --form-escape -F name=daniel -F tool=curl --form-string "str1=@literal" --form-string "str2=<verbatim;type=xxx/yyy" -F "file=@log/test%TESTNUMBER.txt;type=moo/foobar;filename=fakerfile" -F file2=@log/test%TESTNUMBER.txt -F "file3=@\"log/test%TESTNUMBER.txt\";type=mo/foo;filename=\"f\\\\\\\\ak\\\\\\er,\\\\an\\d;.t\\\"xt\"" -F 'file4=@"log/test%TESTNUMBER.txt"; filename="A\\AA\"\"\\\"ZZZ"'
</command>
# We create this file before the command is invoked!
<file name="log/test%TESTNUMBER.txt">
foo bar
This is a bar foo
bar
foo
</file>
</client>
# Verify data after the test has been "shot"
<verify>
<strip>
^(Content-Type: multipart/form-data;|-------).*
</strip>
<protocol>
POST /we/want/%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Content-Length: 1186
Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32
------------------------------24e78000bd32
Content-Disposition: form-data; name="name"
daniel
------------------------------24e78000bd32
Content-Disposition: form-data; name="tool"
curl
------------------------------24e78000bd32
Content-Disposition: form-data; name="str1"
@literal
------------------------------24e78000bd32
Content-Disposition: form-data; name="str2"
<verbatim;type=xxx/yyy
------------------------------24e78000bd32
Content-Disposition: form-data; name="file"; filename="fakerfile"
Content-Type: moo/foobar
foo bar
This is a bar foo
bar
foo
------------------------------24e78000bd32
Content-Disposition: form-data; name="file2"; filename="test%TESTNUMBER.txt"
Content-Type: text/plain
foo bar
This is a bar foo
bar
foo
------------------------------24e78000bd32
Content-Disposition: form-data; name="file3"; filename="f\\\\ak\\\\er,\\an\\d;.t\"xt"
Content-Type: mo/foo
foo bar
This is a bar foo
bar
foo
------------------------------24e78000bd32
Content-Disposition: form-data; name="file4"; filename="A\\AA\"\"\\\"ZZZ"
Content-Type: text/plain
foo bar
This is a bar foo
bar
foo
------------------------------24e78000bd32--
</protocol>
</verify>
</testcase>

View File

@ -47,7 +47,7 @@ POST /we/want/%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Content-Length: 1184
Content-Length: 1180
Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32
------------------------------24e78000bd32
@ -85,7 +85,7 @@ bar
foo
------------------------------24e78000bd32
Content-Disposition: form-data; name="file3"; filename="f\\\\ak\\\\er,\\an\\d;.t\"xt"
Content-Disposition: form-data; name="file3"; filename="f\\ak\\er,\an\d;.t%22xt"
Content-Type: mo/foo
foo bar
@ -94,7 +94,7 @@ bar
foo
------------------------------24e78000bd32
Content-Disposition: form-data; name="file4"; filename="A\\AA\"\"\\\"ZZZ"
Content-Disposition: form-data; name="file4"; filename="A\AA%22%22\%22ZZZ"
Content-Type: text/plain
foo bar