* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
#include "tool_cfgable.h"
#include "tool_easysrc.h"
#include "tool_setopt.h"
+#include "tool_convert.h"
+#include "mime.h"
#include "memdebug.h" /* keep this as LAST include */
/* Lookup tables for converting setopt values back to symbols */
NV1(CURLOPT_TCP_NODELAY, 1),
NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1),
NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1),
+ NV1(CURLOPT_SOCKS5_AUTH, 1),
NVEND
};
/* Escape string to C string syntax. Return NULL if out of memory.
* Is this correct for those wacky EBCDIC guys? */
-static char *c_escape(const char *str)
+static char *c_escape(const char *str, size_t len)
{
- size_t len = 0;
const char *s;
unsigned char c;
char *escaped, *e;
+
+ if(len == CURL_ZERO_TERMINATED)
+ len = strlen(str);
+
+ /* Check for possible overflow. */
+ if(len > (~(size_t) 0) / 4)
+ return NULL;
+
/* Allocate space based on worst-case */
- len = strlen(str);
escaped = malloc(4 * len + 1);
if(!escaped)
return NULL;
e = escaped;
- for(s=str; (c=*s) != '\0'; s++) {
- if(c=='\n') {
+ for(s = str; (c = *s) != '\0'; s++) {
+ if(c == '\n') {
strcpy(e, "\\n");
e += 2;
}
- else if(c=='\r') {
+ else if(c == '\r') {
strcpy(e, "\\r");
e += 2;
}
- else if(c=='\t') {
+ else if(c == '\t') {
strcpy(e, "\\t");
e += 2;
}
- else if(c=='\\') {
+ else if(c == '\\') {
strcpy(e, "\\\\");
e += 2;
}
- else if(c=='"') {
+ else if(c == '"') {
strcpy(e, "\\\"");
e += 2;
}
if(config->libcurl && !skip && !ret) {
/* we only use this for real if --libcurl was used */
const NameValue *nv = NULL;
- for(nv=nvlist; nv->name; nv++) {
+ for(nv = nvlist; nv->name; nv++) {
if(nv->value == lval) break; /* found it */
}
if(! nv->name) {
const NameValue *nv = NULL;
snprintf(preamble, sizeof(preamble),
"curl_easy_setopt(hnd, %s, ", name);
- for(nv=nvlist; nv->name; nv++) {
+ for(nv = nvlist; nv->name; nv++) {
if((nv->value & ~ rest) == 0) {
/* all value flags contained in rest */
rest &= ~ nv->value; /* remove bits handled here */
const NameValueUnsigned *nv = NULL;
snprintf(preamble, sizeof(preamble),
"curl_easy_setopt(hnd, %s, ", name);
- for(nv=nvlist; nv->name; nv++) {
+ for(nv = nvlist; nv->name; nv++) {
if((nv->value & ~ rest) == 0) {
/* all value flags contained in rest */
rest &= ~ nv->value; /* remove bits handled here */
return ret;
}
-/* setopt wrapper for CURLOPT_HTTPPOST */
-CURLcode tool_setopt_httppost(CURL *curl, struct GlobalConfig *config,
- const char *name, CURLoption tag,
- struct curl_httppost *post)
+/* Generate code for a struct curl_slist. */
+static CURLcode libcurl_generate_slist(struct curl_slist *slist, int *slistno)
{
CURLcode ret = CURLE_OK;
char *escaped = NULL;
- bool skip = FALSE;
- ret = curl_easy_setopt(curl, tag, post);
- if(!post)
- skip = TRUE;
+ /* May need several slist variables, so invent name */
+ *slistno = ++easysrc_slist_count;
+
+ DECL1("struct curl_slist *slist%d;", *slistno);
+ DATA1("slist%d = NULL;", *slistno);
+ CLEAN1("curl_slist_free_all(slist%d);", *slistno);
+ CLEAN1("slist%d = NULL;", *slistno);
+ for(; slist; slist = slist->next) {
+ Curl_safefree(escaped);
+ escaped = c_escape(slist->data, CURL_ZERO_TERMINATED);
+ if(!escaped)
+ return CURLE_OUT_OF_MEMORY;
+ DATA3("slist%d = curl_slist_append(slist%d, \"%s\");",
+ *slistno, *slistno, escaped);
+ }
- if(config->libcurl && !skip && !ret) {
- struct curl_httppost *pp, *p;
- int i;
- /* May use several httppost lists, if multiple POST actions */
- i = ++ easysrc_form_count;
- DECL1("struct curl_httppost *post%d;", i);
- DATA1("post%d = NULL;", i);
- CLEAN1("curl_formfree(post%d);", i);
- CLEAN1("post%d = NULL;", i);
- if(i == 1)
- DECL0("struct curl_httppost *postend;");
- DATA0("postend = NULL;");
- for(p=post; p; p=p->next) {
- DATA1("curl_formadd(&post%d, &postend,", i);
- DATA1(" CURLFORM_COPYNAME, \"%s\",", p->name);
- for(pp=p; pp; pp=pp->more) {
- /* May be several files uploaded for one name;
- * these are linked through the 'more' pointer */
+ nomem:
+ Curl_safefree(escaped);
+ return ret;
+}
+
+/* Generate source code for a mime structure. */
+static CURLcode libcurl_generate_mime(curl_mime *mime, int *mimeno)
+{
+ CURLcode ret = CURLE_OK;
+ int i;
+ curl_off_t size;
+ curl_mimepart *part;
+ char *filename;
+ char *escaped = NULL;
+ char *cp;
+ char *data;
+
+ /* May need several mime variables, so invent name */
+ *mimeno = ++easysrc_mime_count;
+
+ DECL1("curl_mime *mime%d;", *mimeno);
+ DATA1("mime%d = NULL;", *mimeno);
+ CODE1("mime%d = curl_mime_init(hnd);", *mimeno);
+ CLEAN1("curl_mime_free(mime%d);", *mimeno);
+ CLEAN1("mime%d = NULL;", *mimeno);
+ if(mime->firstpart) {
+ DECL1("curl_mimepart *part%d;", *mimeno);
+ for(part = mime->firstpart; part; part = part->nextpart) {
+ CODE2("part%d = curl_mime_addpart(mime%d);", *mimeno, *mimeno);
+ filename = part->filename;
+ switch(part->kind) {
+ case MIMEKIND_FILE:
Curl_safefree(escaped);
- escaped = c_escape(pp->contents);
- if(!escaped) {
- ret = CURLE_OUT_OF_MEMORY;
- goto nomem;
- }
- if(pp->flags & CURL_HTTPPOST_FILENAME) {
- /* file upload as for -F @filename */
- DATA1(" CURLFORM_FILE, \"%s\",", escaped);
+ escaped = c_escape(part->data, CURL_ZERO_TERMINATED);
+ if(!escaped)
+ return CURLE_OUT_OF_MEMORY;
+ CODE2("curl_mime_filedata(part%d, \"%s\");", *mimeno, escaped);
+ if(!filename)
+ CODE1("curl_mime_filename(part%d, NULL);", *mimeno);
+ else {
+ /* Fast check to see if remote file name is base name. */
+ filename = part->data;
+ for(cp = filename; *cp; cp++)
+ if(*cp == '/' || *cp == '\\')
+ filename = cp + 1;
+ if(!part->filename || !strcmp(filename, part->filename))
+ filename = NULL;
+ else
+ filename = part->filename;
}
- else if(pp->flags & CURL_HTTPPOST_READFILE) {
- /* content from file as for -F <filename */
- DATA1(" CURLFORM_FILECONTENT, \"%s\",", escaped);
- }
- else
- DATA1(" CURLFORM_COPYCONTENTS, \"%s\",", escaped);
- if(pp->showfilename) {
- Curl_safefree(escaped);
- escaped = c_escape(pp->showfilename);
- if(!escaped) {
+ break;
+ case MIMEKIND_CALLBACK:
+ /* Can only be reading stdin in the current context. */
+ CODE1("curl_mime_data_cb(part%d, -1, (curl_read_callback) fread, \\",
+ *mimeno);
+ CODE0(" (curl_seek_callback) fseek, NULL, stdin);");
+ break;
+ case MIMEKIND_DATA:
+#ifdef CURL_DOES_CONVERSIONS
+ /* Data is stored in ASCII and we want in in the host character
+ code. Convert it back for output. */
+ data = malloc(part->datasize + 1);
+ if(!data) {
ret = CURLE_OUT_OF_MEMORY;
goto nomem;
}
- DATA1(" CURLFORM_FILENAME, \"%s\",", escaped);
- }
- if(pp->contenttype) {
- Curl_safefree(escaped);
- escaped = c_escape(pp->contenttype);
- if(!escaped) {
- ret = CURLE_OUT_OF_MEMORY;
+ memcpy(data, part->data, part->datasize + 1);
+ ret = convert_from_network(data, strlen(data));
+ if(ret) {
+ Curl_safefree(data);
goto nomem;
}
- DATA1(" CURLFORM_CONTENTTYPE, \"%s\",", escaped);
- }
+#else
+ data = part->data;
+#endif
+
+ /* Are there any nul byte in data? */
+ for(cp = data; *cp; cp++)
+ ;
+ size = (cp == data + part->datasize)? (curl_off_t) -1: part->datasize;
+ Curl_safefree(escaped);
+ escaped = c_escape(data, (size_t) part->datasize);
+#ifdef CURL_DOES_CONVERSIONS
+ Curl_safefree(data);
+#endif
+ if(!escaped)
+ return CURLE_OUT_OF_MEMORY;
+ if(size >= 0)
+ CODE3("curl_mime_data(part%d, \"%s\", %" CURL_FORMAT_CURL_OFF_T ");",
+ *mimeno, escaped, size);
+ else
+ CODE2("curl_mime_data(part%d, \"%s\", CURL_ZERO_TERMINATED);",
+ *mimeno, escaped);
+ break;
+ case MIMEKIND_MULTIPART:
+ ret = libcurl_generate_mime(part->arg, &i);
+ if(ret)
+ goto nomem;
+ CODE2("curl_mime_subparts(part%d, mime%d);", *mimeno, i);
+ CODE1("mime%d = NULL;", i); /* Avoid freeing in CLEAN sequence. */
+ break;
+ default:
+ /* Other cases not possible in this context. */
+ break;
+ }
+
+ if(part->encoder) {
+ Curl_safefree(escaped);
+ escaped = c_escape(part->encoder->name, CURL_ZERO_TERMINATED);
+ if(!escaped)
+ return CURLE_OUT_OF_MEMORY;
+ CODE2("curl_mime_encoder(part%d, \"%s\");", *mimeno, escaped);
+ }
+
+ if(filename) {
+ Curl_safefree(escaped);
+ escaped = c_escape(filename, CURL_ZERO_TERMINATED);
+ if(!escaped)
+ return CURLE_OUT_OF_MEMORY;
+ CODE2("curl_mime_filename(part%d, \"%s\");", *mimeno, escaped);
+ }
+
+ if(part->name) {
+ Curl_safefree(escaped);
+ escaped = c_escape(part->name, CURL_ZERO_TERMINATED);
+ if(!escaped)
+ return CURLE_OUT_OF_MEMORY;
+ CODE2("curl_mime_name(part%d, \"%s\");", *mimeno, escaped);
+ }
+
+ if(part->mimetype) {
+ Curl_safefree(escaped);
+ escaped = c_escape(part->mimetype, CURL_ZERO_TERMINATED);
+ if(!escaped)
+ return CURLE_OUT_OF_MEMORY;
+ CODE2("curl_mime_type(part%d, \"%s\");", *mimeno, escaped);
+ }
+
+ if(part->userheaders) {
+ int ownership = part->flags & MIME_USERHEADERS_OWNER? 1: 0;
+
+ ret = libcurl_generate_slist(part->userheaders, &i);
+ if(ret)
+ goto nomem;
+ CODE3("curl_mime_headers(part%d, slist%d, %d);",
+ *mimeno, i, ownership);
+ if(ownership)
+ CODE1("slist%d = NULL;", i); /* Prevent freeing in CLEAN sequence. */
}
- DATA0(" CURLFORM_END);");
}
- CODE2("curl_easy_setopt(hnd, %s, post%d);", name, i);
}
- nomem:
+nomem:
Curl_safefree(escaped);
return ret;
}
+/* setopt wrapper for CURLOPT_MIMEPOST */
+CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config,
+ const char *name, CURLoption tag,
+ curl_mime *mimepost)
+{
+ CURLcode ret = CURLE_OK;
+
+ ret = curl_easy_setopt(curl, tag, mimepost);
+
+ if(config->libcurl && mimepost && !ret) {
+ int i;
+
+ ret = libcurl_generate_mime(mimepost, &i);
+
+ if(!ret)
+ CODE2("curl_easy_setopt(hnd, %s, mime%d);", name, i);
+ }
+
+nomem:
+ return ret;
+}
+
/* setopt wrapper for curl_slist options */
CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config,
const char *name, CURLoption tag,
struct curl_slist *list)
{
CURLcode ret = CURLE_OK;
- char *escaped = NULL;
- bool skip = FALSE;
ret = curl_easy_setopt(curl, tag, list);
- if(!list)
- skip = TRUE;
- if(config->libcurl && !skip && !ret) {
- struct curl_slist *s;
+ if(config->libcurl && list && !ret) {
int i;
- /* May need several slist variables, so invent name */
- i = ++ easysrc_slist_count;
- DECL1("struct curl_slist *slist%d;", i);
- DATA1("slist%d = NULL;", i);
- CLEAN1("curl_slist_free_all(slist%d);", i);
- CLEAN1("slist%d = NULL;", i);
- for(s=list; s; s=s->next) {
- Curl_safefree(escaped);
- escaped = c_escape(s->data);
- if(!escaped) {
- ret = CURLE_OUT_OF_MEMORY;
- goto nomem;
- }
- DATA3("slist%d = curl_slist_append(slist%d, \"%s\");", i, i, escaped);
- }
- CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i);
+
+ ret = libcurl_generate_slist(list, &i);
+ if(!ret)
+ CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i);
}
nomem:
- Curl_safefree(escaped);
return ret;
}
long lval = va_arg(arg, long);
long defval = 0L;
const NameValue *nv = NULL;
- for(nv=setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) {
+ for(nv = setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) {
if(!strcmp(name, nv->name)) {
defval = nv->value;
break; /* found it */
REM2("%s set to a %s", name, value);
else {
if(escape) {
- escaped = c_escape(value);
+ escaped = c_escape(value, CURL_ZERO_TERMINATED);
if(!escaped) {
ret = CURLE_OUT_OF_MEMORY;
goto nomem;