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:
parent
6ec28eb687
commit
b20b364764
@ -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 \
|
||||
|
||||
10
docs/cmdline-opts/form-escape.d
Normal file
10
docs/cmdline-opts/form-escape.d
Normal 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.
|
||||
@ -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
|
||||
|
||||
89
docs/libcurl/opts/CURLOPT_MIME_OPTIONS.3
Normal file
89
docs/libcurl/opts/CURLOPT_MIME_OPTIONS.3
Normal 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)"
|
||||
@ -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 \
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
*
|
||||
|
||||
@ -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
|
||||
|
||||
62
lib/mime.c
62
lib/mime.c
@ -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;
|
||||
}
|
||||
|
||||
@ -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],
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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},
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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
98
tests/data/test1186
Normal 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
63
tests/data/test1187
Normal 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
108
tests/data/test1189
Normal 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>
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user