mirror of
https://github.com/curl/curl.git
synced 2026-08-24 12:03:34 +03:00
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
23 changed files with 463 additions and 30 deletions
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue