1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker #include "tool_setup.h"
25*6236dae4SAndroid Build Coastguard Worker
26*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
27*6236dae4SAndroid Build Coastguard Worker
28*6236dae4SAndroid Build Coastguard Worker #include "curlx.h"
29*6236dae4SAndroid Build Coastguard Worker
30*6236dae4SAndroid Build Coastguard Worker #include "tool_cfgable.h"
31*6236dae4SAndroid Build Coastguard Worker #include "tool_msgs.h"
32*6236dae4SAndroid Build Coastguard Worker #include "tool_binmode.h"
33*6236dae4SAndroid Build Coastguard Worker #include "tool_getparam.h"
34*6236dae4SAndroid Build Coastguard Worker #include "tool_paramhlp.h"
35*6236dae4SAndroid Build Coastguard Worker #include "tool_formparse.h"
36*6236dae4SAndroid Build Coastguard Worker
37*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h" /* keep this as LAST include */
38*6236dae4SAndroid Build Coastguard Worker
39*6236dae4SAndroid Build Coastguard Worker /* tool_mime functions. */
tool_mime_new(struct tool_mime * parent,toolmimekind kind)40*6236dae4SAndroid Build Coastguard Worker static struct tool_mime *tool_mime_new(struct tool_mime *parent,
41*6236dae4SAndroid Build Coastguard Worker toolmimekind kind)
42*6236dae4SAndroid Build Coastguard Worker {
43*6236dae4SAndroid Build Coastguard Worker struct tool_mime *m = (struct tool_mime *) calloc(1, sizeof(*m));
44*6236dae4SAndroid Build Coastguard Worker
45*6236dae4SAndroid Build Coastguard Worker if(m) {
46*6236dae4SAndroid Build Coastguard Worker m->kind = kind;
47*6236dae4SAndroid Build Coastguard Worker m->parent = parent;
48*6236dae4SAndroid Build Coastguard Worker if(parent) {
49*6236dae4SAndroid Build Coastguard Worker m->prev = parent->subparts;
50*6236dae4SAndroid Build Coastguard Worker parent->subparts = m;
51*6236dae4SAndroid Build Coastguard Worker }
52*6236dae4SAndroid Build Coastguard Worker }
53*6236dae4SAndroid Build Coastguard Worker return m;
54*6236dae4SAndroid Build Coastguard Worker }
55*6236dae4SAndroid Build Coastguard Worker
tool_mime_new_parts(struct tool_mime * parent)56*6236dae4SAndroid Build Coastguard Worker static struct tool_mime *tool_mime_new_parts(struct tool_mime *parent)
57*6236dae4SAndroid Build Coastguard Worker {
58*6236dae4SAndroid Build Coastguard Worker return tool_mime_new(parent, TOOLMIME_PARTS);
59*6236dae4SAndroid Build Coastguard Worker }
60*6236dae4SAndroid Build Coastguard Worker
tool_mime_new_data(struct tool_mime * parent,char * mime_data)61*6236dae4SAndroid Build Coastguard Worker static struct tool_mime *tool_mime_new_data(struct tool_mime *parent,
62*6236dae4SAndroid Build Coastguard Worker char *mime_data)
63*6236dae4SAndroid Build Coastguard Worker {
64*6236dae4SAndroid Build Coastguard Worker char *mime_data_copy;
65*6236dae4SAndroid Build Coastguard Worker struct tool_mime *m = NULL;
66*6236dae4SAndroid Build Coastguard Worker
67*6236dae4SAndroid Build Coastguard Worker mime_data_copy = strdup(mime_data);
68*6236dae4SAndroid Build Coastguard Worker if(mime_data_copy) {
69*6236dae4SAndroid Build Coastguard Worker m = tool_mime_new(parent, TOOLMIME_DATA);
70*6236dae4SAndroid Build Coastguard Worker if(!m)
71*6236dae4SAndroid Build Coastguard Worker free(mime_data_copy);
72*6236dae4SAndroid Build Coastguard Worker else
73*6236dae4SAndroid Build Coastguard Worker m->data = mime_data_copy;
74*6236dae4SAndroid Build Coastguard Worker }
75*6236dae4SAndroid Build Coastguard Worker return m;
76*6236dae4SAndroid Build Coastguard Worker }
77*6236dae4SAndroid Build Coastguard Worker
tool_mime_new_filedata(struct tool_mime * parent,const char * filename,bool isremotefile,CURLcode * errcode)78*6236dae4SAndroid Build Coastguard Worker static struct tool_mime *tool_mime_new_filedata(struct tool_mime *parent,
79*6236dae4SAndroid Build Coastguard Worker const char *filename,
80*6236dae4SAndroid Build Coastguard Worker bool isremotefile,
81*6236dae4SAndroid Build Coastguard Worker CURLcode *errcode)
82*6236dae4SAndroid Build Coastguard Worker {
83*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
84*6236dae4SAndroid Build Coastguard Worker struct tool_mime *m = NULL;
85*6236dae4SAndroid Build Coastguard Worker
86*6236dae4SAndroid Build Coastguard Worker *errcode = CURLE_OUT_OF_MEMORY;
87*6236dae4SAndroid Build Coastguard Worker if(strcmp(filename, "-")) {
88*6236dae4SAndroid Build Coastguard Worker /* This is a normal file. */
89*6236dae4SAndroid Build Coastguard Worker char *filedup = strdup(filename);
90*6236dae4SAndroid Build Coastguard Worker if(filedup) {
91*6236dae4SAndroid Build Coastguard Worker m = tool_mime_new(parent, TOOLMIME_FILE);
92*6236dae4SAndroid Build Coastguard Worker if(!m)
93*6236dae4SAndroid Build Coastguard Worker free(filedup);
94*6236dae4SAndroid Build Coastguard Worker else {
95*6236dae4SAndroid Build Coastguard Worker m->data = filedup;
96*6236dae4SAndroid Build Coastguard Worker if(!isremotefile)
97*6236dae4SAndroid Build Coastguard Worker m->kind = TOOLMIME_FILEDATA;
98*6236dae4SAndroid Build Coastguard Worker *errcode = CURLE_OK;
99*6236dae4SAndroid Build Coastguard Worker }
100*6236dae4SAndroid Build Coastguard Worker }
101*6236dae4SAndroid Build Coastguard Worker }
102*6236dae4SAndroid Build Coastguard Worker else { /* Standard input. */
103*6236dae4SAndroid Build Coastguard Worker int fd = fileno(stdin);
104*6236dae4SAndroid Build Coastguard Worker char *data = NULL;
105*6236dae4SAndroid Build Coastguard Worker curl_off_t size;
106*6236dae4SAndroid Build Coastguard Worker curl_off_t origin;
107*6236dae4SAndroid Build Coastguard Worker struct_stat sbuf;
108*6236dae4SAndroid Build Coastguard Worker
109*6236dae4SAndroid Build Coastguard Worker set_binmode(stdin);
110*6236dae4SAndroid Build Coastguard Worker origin = ftell(stdin);
111*6236dae4SAndroid Build Coastguard Worker /* If stdin is a regular file, do not buffer data but read it
112*6236dae4SAndroid Build Coastguard Worker when needed. */
113*6236dae4SAndroid Build Coastguard Worker if(fd >= 0 && origin >= 0 && !fstat(fd, &sbuf) &&
114*6236dae4SAndroid Build Coastguard Worker #ifdef __VMS
115*6236dae4SAndroid Build Coastguard Worker sbuf.st_fab_rfm != FAB$C_VAR && sbuf.st_fab_rfm != FAB$C_VFC &&
116*6236dae4SAndroid Build Coastguard Worker #endif
117*6236dae4SAndroid Build Coastguard Worker S_ISREG(sbuf.st_mode)) {
118*6236dae4SAndroid Build Coastguard Worker size = sbuf.st_size - origin;
119*6236dae4SAndroid Build Coastguard Worker if(size < 0)
120*6236dae4SAndroid Build Coastguard Worker size = 0;
121*6236dae4SAndroid Build Coastguard Worker }
122*6236dae4SAndroid Build Coastguard Worker else { /* Not suitable for direct use, buffer stdin data. */
123*6236dae4SAndroid Build Coastguard Worker size_t stdinsize = 0;
124*6236dae4SAndroid Build Coastguard Worker
125*6236dae4SAndroid Build Coastguard Worker switch(file2memory(&data, &stdinsize, stdin)) {
126*6236dae4SAndroid Build Coastguard Worker case PARAM_NO_MEM:
127*6236dae4SAndroid Build Coastguard Worker return m;
128*6236dae4SAndroid Build Coastguard Worker case PARAM_READ_ERROR:
129*6236dae4SAndroid Build Coastguard Worker result = CURLE_READ_ERROR;
130*6236dae4SAndroid Build Coastguard Worker break;
131*6236dae4SAndroid Build Coastguard Worker default:
132*6236dae4SAndroid Build Coastguard Worker if(!stdinsize) {
133*6236dae4SAndroid Build Coastguard Worker /* Zero-length data has been freed. Re-create it. */
134*6236dae4SAndroid Build Coastguard Worker data = strdup("");
135*6236dae4SAndroid Build Coastguard Worker if(!data)
136*6236dae4SAndroid Build Coastguard Worker return m;
137*6236dae4SAndroid Build Coastguard Worker }
138*6236dae4SAndroid Build Coastguard Worker break;
139*6236dae4SAndroid Build Coastguard Worker }
140*6236dae4SAndroid Build Coastguard Worker size = curlx_uztoso(stdinsize);
141*6236dae4SAndroid Build Coastguard Worker origin = 0;
142*6236dae4SAndroid Build Coastguard Worker }
143*6236dae4SAndroid Build Coastguard Worker m = tool_mime_new(parent, TOOLMIME_STDIN);
144*6236dae4SAndroid Build Coastguard Worker if(!m)
145*6236dae4SAndroid Build Coastguard Worker Curl_safefree(data);
146*6236dae4SAndroid Build Coastguard Worker else {
147*6236dae4SAndroid Build Coastguard Worker m->data = data;
148*6236dae4SAndroid Build Coastguard Worker m->origin = origin;
149*6236dae4SAndroid Build Coastguard Worker m->size = size;
150*6236dae4SAndroid Build Coastguard Worker m->curpos = 0;
151*6236dae4SAndroid Build Coastguard Worker if(!isremotefile)
152*6236dae4SAndroid Build Coastguard Worker m->kind = TOOLMIME_STDINDATA;
153*6236dae4SAndroid Build Coastguard Worker *errcode = result;
154*6236dae4SAndroid Build Coastguard Worker }
155*6236dae4SAndroid Build Coastguard Worker }
156*6236dae4SAndroid Build Coastguard Worker return m;
157*6236dae4SAndroid Build Coastguard Worker }
158*6236dae4SAndroid Build Coastguard Worker
tool_mime_free(struct tool_mime * mime)159*6236dae4SAndroid Build Coastguard Worker void tool_mime_free(struct tool_mime *mime)
160*6236dae4SAndroid Build Coastguard Worker {
161*6236dae4SAndroid Build Coastguard Worker if(mime) {
162*6236dae4SAndroid Build Coastguard Worker if(mime->subparts)
163*6236dae4SAndroid Build Coastguard Worker tool_mime_free(mime->subparts);
164*6236dae4SAndroid Build Coastguard Worker if(mime->prev)
165*6236dae4SAndroid Build Coastguard Worker tool_mime_free(mime->prev);
166*6236dae4SAndroid Build Coastguard Worker Curl_safefree(mime->name);
167*6236dae4SAndroid Build Coastguard Worker Curl_safefree(mime->filename);
168*6236dae4SAndroid Build Coastguard Worker Curl_safefree(mime->type);
169*6236dae4SAndroid Build Coastguard Worker Curl_safefree(mime->encoder);
170*6236dae4SAndroid Build Coastguard Worker Curl_safefree(mime->data);
171*6236dae4SAndroid Build Coastguard Worker curl_slist_free_all(mime->headers);
172*6236dae4SAndroid Build Coastguard Worker free(mime);
173*6236dae4SAndroid Build Coastguard Worker }
174*6236dae4SAndroid Build Coastguard Worker }
175*6236dae4SAndroid Build Coastguard Worker
176*6236dae4SAndroid Build Coastguard Worker
177*6236dae4SAndroid Build Coastguard Worker /* Mime part callbacks for stdin. */
tool_mime_stdin_read(char * buffer,size_t size,size_t nitems,void * arg)178*6236dae4SAndroid Build Coastguard Worker size_t tool_mime_stdin_read(char *buffer,
179*6236dae4SAndroid Build Coastguard Worker size_t size, size_t nitems, void *arg)
180*6236dae4SAndroid Build Coastguard Worker {
181*6236dae4SAndroid Build Coastguard Worker struct tool_mime *sip = (struct tool_mime *) arg;
182*6236dae4SAndroid Build Coastguard Worker curl_off_t bytesleft;
183*6236dae4SAndroid Build Coastguard Worker (void) size; /* Always 1: ignored. */
184*6236dae4SAndroid Build Coastguard Worker
185*6236dae4SAndroid Build Coastguard Worker if(sip->size >= 0) {
186*6236dae4SAndroid Build Coastguard Worker if(sip->curpos >= sip->size)
187*6236dae4SAndroid Build Coastguard Worker return 0; /* At eof. */
188*6236dae4SAndroid Build Coastguard Worker bytesleft = sip->size - sip->curpos;
189*6236dae4SAndroid Build Coastguard Worker if(curlx_uztoso(nitems) > bytesleft)
190*6236dae4SAndroid Build Coastguard Worker nitems = curlx_sotouz(bytesleft);
191*6236dae4SAndroid Build Coastguard Worker }
192*6236dae4SAndroid Build Coastguard Worker if(nitems) {
193*6236dae4SAndroid Build Coastguard Worker if(sip->data) {
194*6236dae4SAndroid Build Coastguard Worker /* Return data from memory. */
195*6236dae4SAndroid Build Coastguard Worker memcpy(buffer, sip->data + curlx_sotouz(sip->curpos), nitems);
196*6236dae4SAndroid Build Coastguard Worker }
197*6236dae4SAndroid Build Coastguard Worker else {
198*6236dae4SAndroid Build Coastguard Worker /* Read from stdin. */
199*6236dae4SAndroid Build Coastguard Worker nitems = fread(buffer, 1, nitems, stdin);
200*6236dae4SAndroid Build Coastguard Worker if(ferror(stdin)) {
201*6236dae4SAndroid Build Coastguard Worker /* Show error only once. */
202*6236dae4SAndroid Build Coastguard Worker if(sip->config) {
203*6236dae4SAndroid Build Coastguard Worker warnf(sip->config, "stdin: %s", strerror(errno));
204*6236dae4SAndroid Build Coastguard Worker sip->config = NULL;
205*6236dae4SAndroid Build Coastguard Worker }
206*6236dae4SAndroid Build Coastguard Worker return CURL_READFUNC_ABORT;
207*6236dae4SAndroid Build Coastguard Worker }
208*6236dae4SAndroid Build Coastguard Worker }
209*6236dae4SAndroid Build Coastguard Worker sip->curpos += curlx_uztoso(nitems);
210*6236dae4SAndroid Build Coastguard Worker }
211*6236dae4SAndroid Build Coastguard Worker return nitems;
212*6236dae4SAndroid Build Coastguard Worker }
213*6236dae4SAndroid Build Coastguard Worker
tool_mime_stdin_seek(void * instream,curl_off_t offset,int whence)214*6236dae4SAndroid Build Coastguard Worker int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence)
215*6236dae4SAndroid Build Coastguard Worker {
216*6236dae4SAndroid Build Coastguard Worker struct tool_mime *sip = (struct tool_mime *) instream;
217*6236dae4SAndroid Build Coastguard Worker
218*6236dae4SAndroid Build Coastguard Worker switch(whence) {
219*6236dae4SAndroid Build Coastguard Worker case SEEK_CUR:
220*6236dae4SAndroid Build Coastguard Worker offset += sip->curpos;
221*6236dae4SAndroid Build Coastguard Worker break;
222*6236dae4SAndroid Build Coastguard Worker case SEEK_END:
223*6236dae4SAndroid Build Coastguard Worker offset += sip->size;
224*6236dae4SAndroid Build Coastguard Worker break;
225*6236dae4SAndroid Build Coastguard Worker }
226*6236dae4SAndroid Build Coastguard Worker if(offset < 0)
227*6236dae4SAndroid Build Coastguard Worker return CURL_SEEKFUNC_CANTSEEK;
228*6236dae4SAndroid Build Coastguard Worker if(!sip->data) {
229*6236dae4SAndroid Build Coastguard Worker if(fseek(stdin, (long) (offset + sip->origin), SEEK_SET))
230*6236dae4SAndroid Build Coastguard Worker return CURL_SEEKFUNC_CANTSEEK;
231*6236dae4SAndroid Build Coastguard Worker }
232*6236dae4SAndroid Build Coastguard Worker sip->curpos = offset;
233*6236dae4SAndroid Build Coastguard Worker return CURL_SEEKFUNC_OK;
234*6236dae4SAndroid Build Coastguard Worker }
235*6236dae4SAndroid Build Coastguard Worker
236*6236dae4SAndroid Build Coastguard Worker /* Translate an internal mime tree into a libcurl mime tree. */
237*6236dae4SAndroid Build Coastguard Worker
tool2curlparts(CURL * curl,struct tool_mime * m,curl_mime * mime)238*6236dae4SAndroid Build Coastguard Worker static CURLcode tool2curlparts(CURL *curl, struct tool_mime *m,
239*6236dae4SAndroid Build Coastguard Worker curl_mime *mime)
240*6236dae4SAndroid Build Coastguard Worker {
241*6236dae4SAndroid Build Coastguard Worker CURLcode ret = CURLE_OK;
242*6236dae4SAndroid Build Coastguard Worker curl_mimepart *part = NULL;
243*6236dae4SAndroid Build Coastguard Worker curl_mime *submime = NULL;
244*6236dae4SAndroid Build Coastguard Worker const char *filename = NULL;
245*6236dae4SAndroid Build Coastguard Worker
246*6236dae4SAndroid Build Coastguard Worker if(m) {
247*6236dae4SAndroid Build Coastguard Worker ret = tool2curlparts(curl, m->prev, mime);
248*6236dae4SAndroid Build Coastguard Worker if(!ret) {
249*6236dae4SAndroid Build Coastguard Worker part = curl_mime_addpart(mime);
250*6236dae4SAndroid Build Coastguard Worker if(!part)
251*6236dae4SAndroid Build Coastguard Worker ret = CURLE_OUT_OF_MEMORY;
252*6236dae4SAndroid Build Coastguard Worker }
253*6236dae4SAndroid Build Coastguard Worker if(!ret) {
254*6236dae4SAndroid Build Coastguard Worker filename = m->filename;
255*6236dae4SAndroid Build Coastguard Worker switch(m->kind) {
256*6236dae4SAndroid Build Coastguard Worker case TOOLMIME_PARTS:
257*6236dae4SAndroid Build Coastguard Worker ret = tool2curlmime(curl, m, &submime);
258*6236dae4SAndroid Build Coastguard Worker if(!ret) {
259*6236dae4SAndroid Build Coastguard Worker ret = curl_mime_subparts(part, submime);
260*6236dae4SAndroid Build Coastguard Worker if(ret)
261*6236dae4SAndroid Build Coastguard Worker curl_mime_free(submime);
262*6236dae4SAndroid Build Coastguard Worker }
263*6236dae4SAndroid Build Coastguard Worker break;
264*6236dae4SAndroid Build Coastguard Worker
265*6236dae4SAndroid Build Coastguard Worker case TOOLMIME_DATA:
266*6236dae4SAndroid Build Coastguard Worker ret = curl_mime_data(part, m->data, CURL_ZERO_TERMINATED);
267*6236dae4SAndroid Build Coastguard Worker break;
268*6236dae4SAndroid Build Coastguard Worker
269*6236dae4SAndroid Build Coastguard Worker case TOOLMIME_FILE:
270*6236dae4SAndroid Build Coastguard Worker case TOOLMIME_FILEDATA:
271*6236dae4SAndroid Build Coastguard Worker ret = curl_mime_filedata(part, m->data);
272*6236dae4SAndroid Build Coastguard Worker if(!ret && m->kind == TOOLMIME_FILEDATA && !filename)
273*6236dae4SAndroid Build Coastguard Worker ret = curl_mime_filename(part, NULL);
274*6236dae4SAndroid Build Coastguard Worker break;
275*6236dae4SAndroid Build Coastguard Worker
276*6236dae4SAndroid Build Coastguard Worker case TOOLMIME_STDIN:
277*6236dae4SAndroid Build Coastguard Worker if(!filename)
278*6236dae4SAndroid Build Coastguard Worker filename = "-";
279*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
280*6236dae4SAndroid Build Coastguard Worker case TOOLMIME_STDINDATA:
281*6236dae4SAndroid Build Coastguard Worker ret = curl_mime_data_cb(part, m->size,
282*6236dae4SAndroid Build Coastguard Worker (curl_read_callback) tool_mime_stdin_read,
283*6236dae4SAndroid Build Coastguard Worker (curl_seek_callback) tool_mime_stdin_seek,
284*6236dae4SAndroid Build Coastguard Worker NULL, m);
285*6236dae4SAndroid Build Coastguard Worker break;
286*6236dae4SAndroid Build Coastguard Worker
287*6236dae4SAndroid Build Coastguard Worker default:
288*6236dae4SAndroid Build Coastguard Worker /* Other cases not possible in this context. */
289*6236dae4SAndroid Build Coastguard Worker break;
290*6236dae4SAndroid Build Coastguard Worker }
291*6236dae4SAndroid Build Coastguard Worker }
292*6236dae4SAndroid Build Coastguard Worker if(!ret && filename)
293*6236dae4SAndroid Build Coastguard Worker ret = curl_mime_filename(part, filename);
294*6236dae4SAndroid Build Coastguard Worker if(!ret)
295*6236dae4SAndroid Build Coastguard Worker ret = curl_mime_type(part, m->type);
296*6236dae4SAndroid Build Coastguard Worker if(!ret)
297*6236dae4SAndroid Build Coastguard Worker ret = curl_mime_headers(part, m->headers, 0);
298*6236dae4SAndroid Build Coastguard Worker if(!ret)
299*6236dae4SAndroid Build Coastguard Worker ret = curl_mime_encoder(part, m->encoder);
300*6236dae4SAndroid Build Coastguard Worker if(!ret)
301*6236dae4SAndroid Build Coastguard Worker ret = curl_mime_name(part, m->name);
302*6236dae4SAndroid Build Coastguard Worker }
303*6236dae4SAndroid Build Coastguard Worker return ret;
304*6236dae4SAndroid Build Coastguard Worker }
305*6236dae4SAndroid Build Coastguard Worker
tool2curlmime(CURL * curl,struct tool_mime * m,curl_mime ** mime)306*6236dae4SAndroid Build Coastguard Worker CURLcode tool2curlmime(CURL *curl, struct tool_mime *m, curl_mime **mime)
307*6236dae4SAndroid Build Coastguard Worker {
308*6236dae4SAndroid Build Coastguard Worker CURLcode ret = CURLE_OK;
309*6236dae4SAndroid Build Coastguard Worker
310*6236dae4SAndroid Build Coastguard Worker *mime = curl_mime_init(curl);
311*6236dae4SAndroid Build Coastguard Worker if(!*mime)
312*6236dae4SAndroid Build Coastguard Worker ret = CURLE_OUT_OF_MEMORY;
313*6236dae4SAndroid Build Coastguard Worker else
314*6236dae4SAndroid Build Coastguard Worker ret = tool2curlparts(curl, m->subparts, *mime);
315*6236dae4SAndroid Build Coastguard Worker if(ret) {
316*6236dae4SAndroid Build Coastguard Worker curl_mime_free(*mime);
317*6236dae4SAndroid Build Coastguard Worker *mime = NULL;
318*6236dae4SAndroid Build Coastguard Worker }
319*6236dae4SAndroid Build Coastguard Worker return ret;
320*6236dae4SAndroid Build Coastguard Worker }
321*6236dae4SAndroid Build Coastguard Worker
322*6236dae4SAndroid Build Coastguard Worker /*
323*6236dae4SAndroid Build Coastguard Worker * helper function to get a word from form param
324*6236dae4SAndroid Build Coastguard Worker * after call get_parm_word, str either point to string end
325*6236dae4SAndroid Build Coastguard Worker * or point to any of end chars.
326*6236dae4SAndroid Build Coastguard Worker */
get_param_word(struct OperationConfig * config,char ** str,char ** end_pos,char endchar)327*6236dae4SAndroid Build Coastguard Worker static char *get_param_word(struct OperationConfig *config, char **str,
328*6236dae4SAndroid Build Coastguard Worker char **end_pos, char endchar)
329*6236dae4SAndroid Build Coastguard Worker {
330*6236dae4SAndroid Build Coastguard Worker char *ptr = *str;
331*6236dae4SAndroid Build Coastguard Worker /* the first non-space char is here */
332*6236dae4SAndroid Build Coastguard Worker char *word_begin = ptr;
333*6236dae4SAndroid Build Coastguard Worker char *ptr2;
334*6236dae4SAndroid Build Coastguard Worker char *escape = NULL;
335*6236dae4SAndroid Build Coastguard Worker
336*6236dae4SAndroid Build Coastguard Worker if(*ptr == '"') {
337*6236dae4SAndroid Build Coastguard Worker ++ptr;
338*6236dae4SAndroid Build Coastguard Worker while(*ptr) {
339*6236dae4SAndroid Build Coastguard Worker if(*ptr == '\\') {
340*6236dae4SAndroid Build Coastguard Worker if(ptr[1] == '\\' || ptr[1] == '"') {
341*6236dae4SAndroid Build Coastguard Worker /* remember the first escape position */
342*6236dae4SAndroid Build Coastguard Worker if(!escape)
343*6236dae4SAndroid Build Coastguard Worker escape = ptr;
344*6236dae4SAndroid Build Coastguard Worker /* skip escape of back-slash or double-quote */
345*6236dae4SAndroid Build Coastguard Worker ptr += 2;
346*6236dae4SAndroid Build Coastguard Worker continue;
347*6236dae4SAndroid Build Coastguard Worker }
348*6236dae4SAndroid Build Coastguard Worker }
349*6236dae4SAndroid Build Coastguard Worker if(*ptr == '"') {
350*6236dae4SAndroid Build Coastguard Worker bool trailing_data = FALSE;
351*6236dae4SAndroid Build Coastguard Worker *end_pos = ptr;
352*6236dae4SAndroid Build Coastguard Worker if(escape) {
353*6236dae4SAndroid Build Coastguard Worker /* has escape, we restore the unescaped string here */
354*6236dae4SAndroid Build Coastguard Worker ptr = ptr2 = escape;
355*6236dae4SAndroid Build Coastguard Worker do {
356*6236dae4SAndroid Build Coastguard Worker if(*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '"'))
357*6236dae4SAndroid Build Coastguard Worker ++ptr;
358*6236dae4SAndroid Build Coastguard Worker *ptr2++ = *ptr++;
359*6236dae4SAndroid Build Coastguard Worker }
360*6236dae4SAndroid Build Coastguard Worker while(ptr < *end_pos);
361*6236dae4SAndroid Build Coastguard Worker *end_pos = ptr2;
362*6236dae4SAndroid Build Coastguard Worker }
363*6236dae4SAndroid Build Coastguard Worker ++ptr;
364*6236dae4SAndroid Build Coastguard Worker while(*ptr && *ptr != ';' && *ptr != endchar) {
365*6236dae4SAndroid Build Coastguard Worker if(!ISSPACE(*ptr))
366*6236dae4SAndroid Build Coastguard Worker trailing_data = TRUE;
367*6236dae4SAndroid Build Coastguard Worker ++ptr;
368*6236dae4SAndroid Build Coastguard Worker }
369*6236dae4SAndroid Build Coastguard Worker if(trailing_data)
370*6236dae4SAndroid Build Coastguard Worker warnf(config->global, "Trailing data after quoted form parameter");
371*6236dae4SAndroid Build Coastguard Worker *str = ptr;
372*6236dae4SAndroid Build Coastguard Worker return word_begin + 1;
373*6236dae4SAndroid Build Coastguard Worker }
374*6236dae4SAndroid Build Coastguard Worker ++ptr;
375*6236dae4SAndroid Build Coastguard Worker }
376*6236dae4SAndroid Build Coastguard Worker /* end quote is missing, treat it as non-quoted. */
377*6236dae4SAndroid Build Coastguard Worker ptr = word_begin;
378*6236dae4SAndroid Build Coastguard Worker }
379*6236dae4SAndroid Build Coastguard Worker
380*6236dae4SAndroid Build Coastguard Worker while(*ptr && *ptr != ';' && *ptr != endchar)
381*6236dae4SAndroid Build Coastguard Worker ++ptr;
382*6236dae4SAndroid Build Coastguard Worker *str = *end_pos = ptr;
383*6236dae4SAndroid Build Coastguard Worker return word_begin;
384*6236dae4SAndroid Build Coastguard Worker }
385*6236dae4SAndroid Build Coastguard Worker
386*6236dae4SAndroid Build Coastguard Worker /* Append slist item and return -1 if failed. */
slist_append(struct curl_slist ** plist,const char * data)387*6236dae4SAndroid Build Coastguard Worker static int slist_append(struct curl_slist **plist, const char *data)
388*6236dae4SAndroid Build Coastguard Worker {
389*6236dae4SAndroid Build Coastguard Worker struct curl_slist *s = curl_slist_append(*plist, data);
390*6236dae4SAndroid Build Coastguard Worker
391*6236dae4SAndroid Build Coastguard Worker if(!s)
392*6236dae4SAndroid Build Coastguard Worker return -1;
393*6236dae4SAndroid Build Coastguard Worker
394*6236dae4SAndroid Build Coastguard Worker *plist = s;
395*6236dae4SAndroid Build Coastguard Worker return 0;
396*6236dae4SAndroid Build Coastguard Worker }
397*6236dae4SAndroid Build Coastguard Worker
398*6236dae4SAndroid Build Coastguard Worker /* Read headers from a file and append to list. */
read_field_headers(struct OperationConfig * config,const char * filename,FILE * fp,struct curl_slist ** pheaders)399*6236dae4SAndroid Build Coastguard Worker static int read_field_headers(struct OperationConfig *config,
400*6236dae4SAndroid Build Coastguard Worker const char *filename, FILE *fp,
401*6236dae4SAndroid Build Coastguard Worker struct curl_slist **pheaders)
402*6236dae4SAndroid Build Coastguard Worker {
403*6236dae4SAndroid Build Coastguard Worker size_t hdrlen = 0;
404*6236dae4SAndroid Build Coastguard Worker size_t pos = 0;
405*6236dae4SAndroid Build Coastguard Worker bool incomment = FALSE;
406*6236dae4SAndroid Build Coastguard Worker int lineno = 1;
407*6236dae4SAndroid Build Coastguard Worker char hdrbuf[999] = ""; /* Max. header length + 1. */
408*6236dae4SAndroid Build Coastguard Worker
409*6236dae4SAndroid Build Coastguard Worker for(;;) {
410*6236dae4SAndroid Build Coastguard Worker int c = getc(fp);
411*6236dae4SAndroid Build Coastguard Worker if(c == EOF || (!pos && !ISSPACE(c))) {
412*6236dae4SAndroid Build Coastguard Worker /* Strip and flush the current header. */
413*6236dae4SAndroid Build Coastguard Worker while(hdrlen && ISSPACE(hdrbuf[hdrlen - 1]))
414*6236dae4SAndroid Build Coastguard Worker hdrlen--;
415*6236dae4SAndroid Build Coastguard Worker if(hdrlen) {
416*6236dae4SAndroid Build Coastguard Worker hdrbuf[hdrlen] = '\0';
417*6236dae4SAndroid Build Coastguard Worker if(slist_append(pheaders, hdrbuf)) {
418*6236dae4SAndroid Build Coastguard Worker errorf(config->global, "Out of memory for field headers");
419*6236dae4SAndroid Build Coastguard Worker return -1;
420*6236dae4SAndroid Build Coastguard Worker }
421*6236dae4SAndroid Build Coastguard Worker hdrlen = 0;
422*6236dae4SAndroid Build Coastguard Worker }
423*6236dae4SAndroid Build Coastguard Worker }
424*6236dae4SAndroid Build Coastguard Worker
425*6236dae4SAndroid Build Coastguard Worker switch(c) {
426*6236dae4SAndroid Build Coastguard Worker case EOF:
427*6236dae4SAndroid Build Coastguard Worker if(ferror(fp)) {
428*6236dae4SAndroid Build Coastguard Worker errorf(config->global, "Header file %s read error: %s", filename,
429*6236dae4SAndroid Build Coastguard Worker strerror(errno));
430*6236dae4SAndroid Build Coastguard Worker return -1;
431*6236dae4SAndroid Build Coastguard Worker }
432*6236dae4SAndroid Build Coastguard Worker return 0; /* Done. */
433*6236dae4SAndroid Build Coastguard Worker case '\r':
434*6236dae4SAndroid Build Coastguard Worker continue; /* Ignore. */
435*6236dae4SAndroid Build Coastguard Worker case '\n':
436*6236dae4SAndroid Build Coastguard Worker pos = 0;
437*6236dae4SAndroid Build Coastguard Worker incomment = FALSE;
438*6236dae4SAndroid Build Coastguard Worker lineno++;
439*6236dae4SAndroid Build Coastguard Worker continue;
440*6236dae4SAndroid Build Coastguard Worker case '#':
441*6236dae4SAndroid Build Coastguard Worker if(!pos)
442*6236dae4SAndroid Build Coastguard Worker incomment = TRUE;
443*6236dae4SAndroid Build Coastguard Worker break;
444*6236dae4SAndroid Build Coastguard Worker }
445*6236dae4SAndroid Build Coastguard Worker
446*6236dae4SAndroid Build Coastguard Worker pos++;
447*6236dae4SAndroid Build Coastguard Worker if(!incomment) {
448*6236dae4SAndroid Build Coastguard Worker if(hdrlen == sizeof(hdrbuf) - 1) {
449*6236dae4SAndroid Build Coastguard Worker warnf(config->global, "File %s line %d: header too long (truncated)",
450*6236dae4SAndroid Build Coastguard Worker filename, lineno);
451*6236dae4SAndroid Build Coastguard Worker c = ' ';
452*6236dae4SAndroid Build Coastguard Worker }
453*6236dae4SAndroid Build Coastguard Worker if(hdrlen <= sizeof(hdrbuf) - 1)
454*6236dae4SAndroid Build Coastguard Worker hdrbuf[hdrlen++] = (char) c;
455*6236dae4SAndroid Build Coastguard Worker }
456*6236dae4SAndroid Build Coastguard Worker }
457*6236dae4SAndroid Build Coastguard Worker /* NOTREACHED */
458*6236dae4SAndroid Build Coastguard Worker }
459*6236dae4SAndroid Build Coastguard Worker
get_param_part(struct OperationConfig * config,char endchar,char ** str,char ** pdata,char ** ptype,char ** pfilename,char ** pencoder,struct curl_slist ** pheaders)460*6236dae4SAndroid Build Coastguard Worker static int get_param_part(struct OperationConfig *config, char endchar,
461*6236dae4SAndroid Build Coastguard Worker char **str, char **pdata, char **ptype,
462*6236dae4SAndroid Build Coastguard Worker char **pfilename, char **pencoder,
463*6236dae4SAndroid Build Coastguard Worker struct curl_slist **pheaders)
464*6236dae4SAndroid Build Coastguard Worker {
465*6236dae4SAndroid Build Coastguard Worker char *p = *str;
466*6236dae4SAndroid Build Coastguard Worker char *type = NULL;
467*6236dae4SAndroid Build Coastguard Worker char *filename = NULL;
468*6236dae4SAndroid Build Coastguard Worker char *encoder = NULL;
469*6236dae4SAndroid Build Coastguard Worker char *endpos;
470*6236dae4SAndroid Build Coastguard Worker char *tp;
471*6236dae4SAndroid Build Coastguard Worker char sep;
472*6236dae4SAndroid Build Coastguard Worker char type_major[128] = "";
473*6236dae4SAndroid Build Coastguard Worker char type_minor[128] = "";
474*6236dae4SAndroid Build Coastguard Worker char *endct = NULL;
475*6236dae4SAndroid Build Coastguard Worker struct curl_slist *headers = NULL;
476*6236dae4SAndroid Build Coastguard Worker
477*6236dae4SAndroid Build Coastguard Worker if(ptype)
478*6236dae4SAndroid Build Coastguard Worker *ptype = NULL;
479*6236dae4SAndroid Build Coastguard Worker if(pfilename)
480*6236dae4SAndroid Build Coastguard Worker *pfilename = NULL;
481*6236dae4SAndroid Build Coastguard Worker if(pheaders)
482*6236dae4SAndroid Build Coastguard Worker *pheaders = NULL;
483*6236dae4SAndroid Build Coastguard Worker if(pencoder)
484*6236dae4SAndroid Build Coastguard Worker *pencoder = NULL;
485*6236dae4SAndroid Build Coastguard Worker while(ISSPACE(*p))
486*6236dae4SAndroid Build Coastguard Worker p++;
487*6236dae4SAndroid Build Coastguard Worker tp = p;
488*6236dae4SAndroid Build Coastguard Worker *pdata = get_param_word(config, &p, &endpos, endchar);
489*6236dae4SAndroid Build Coastguard Worker /* If not quoted, strip trailing spaces. */
490*6236dae4SAndroid Build Coastguard Worker if(*pdata == tp)
491*6236dae4SAndroid Build Coastguard Worker while(endpos > *pdata && ISSPACE(endpos[-1]))
492*6236dae4SAndroid Build Coastguard Worker endpos--;
493*6236dae4SAndroid Build Coastguard Worker sep = *p;
494*6236dae4SAndroid Build Coastguard Worker *endpos = '\0';
495*6236dae4SAndroid Build Coastguard Worker while(sep == ';') {
496*6236dae4SAndroid Build Coastguard Worker while(p++ && ISSPACE(*p))
497*6236dae4SAndroid Build Coastguard Worker ;
498*6236dae4SAndroid Build Coastguard Worker
499*6236dae4SAndroid Build Coastguard Worker if(!endct && checkprefix("type=", p)) {
500*6236dae4SAndroid Build Coastguard Worker for(p += 5; ISSPACE(*p); p++)
501*6236dae4SAndroid Build Coastguard Worker ;
502*6236dae4SAndroid Build Coastguard Worker /* set type pointer */
503*6236dae4SAndroid Build Coastguard Worker type = p;
504*6236dae4SAndroid Build Coastguard Worker
505*6236dae4SAndroid Build Coastguard Worker /* verify that this is a fine type specifier */
506*6236dae4SAndroid Build Coastguard Worker if(2 != sscanf(type, "%127[^/ ]/%127[^;, \n]", type_major, type_minor)) {
507*6236dae4SAndroid Build Coastguard Worker warnf(config->global, "Illegally formatted content-type field");
508*6236dae4SAndroid Build Coastguard Worker curl_slist_free_all(headers);
509*6236dae4SAndroid Build Coastguard Worker return -1; /* illegal content-type syntax! */
510*6236dae4SAndroid Build Coastguard Worker }
511*6236dae4SAndroid Build Coastguard Worker
512*6236dae4SAndroid Build Coastguard Worker /* now point beyond the content-type specifier */
513*6236dae4SAndroid Build Coastguard Worker p = type + strlen(type_major) + strlen(type_minor) + 1;
514*6236dae4SAndroid Build Coastguard Worker for(endct = p; *p && *p != ';' && *p != endchar; p++)
515*6236dae4SAndroid Build Coastguard Worker if(!ISSPACE(*p))
516*6236dae4SAndroid Build Coastguard Worker endct = p + 1;
517*6236dae4SAndroid Build Coastguard Worker sep = *p;
518*6236dae4SAndroid Build Coastguard Worker }
519*6236dae4SAndroid Build Coastguard Worker else if(checkprefix("filename=", p)) {
520*6236dae4SAndroid Build Coastguard Worker if(endct) {
521*6236dae4SAndroid Build Coastguard Worker *endct = '\0';
522*6236dae4SAndroid Build Coastguard Worker endct = NULL;
523*6236dae4SAndroid Build Coastguard Worker }
524*6236dae4SAndroid Build Coastguard Worker for(p += 9; ISSPACE(*p); p++)
525*6236dae4SAndroid Build Coastguard Worker ;
526*6236dae4SAndroid Build Coastguard Worker tp = p;
527*6236dae4SAndroid Build Coastguard Worker filename = get_param_word(config, &p, &endpos, endchar);
528*6236dae4SAndroid Build Coastguard Worker /* If not quoted, strip trailing spaces. */
529*6236dae4SAndroid Build Coastguard Worker if(filename == tp)
530*6236dae4SAndroid Build Coastguard Worker while(endpos > filename && ISSPACE(endpos[-1]))
531*6236dae4SAndroid Build Coastguard Worker endpos--;
532*6236dae4SAndroid Build Coastguard Worker sep = *p;
533*6236dae4SAndroid Build Coastguard Worker *endpos = '\0';
534*6236dae4SAndroid Build Coastguard Worker }
535*6236dae4SAndroid Build Coastguard Worker else if(checkprefix("headers=", p)) {
536*6236dae4SAndroid Build Coastguard Worker if(endct) {
537*6236dae4SAndroid Build Coastguard Worker *endct = '\0';
538*6236dae4SAndroid Build Coastguard Worker endct = NULL;
539*6236dae4SAndroid Build Coastguard Worker }
540*6236dae4SAndroid Build Coastguard Worker p += 8;
541*6236dae4SAndroid Build Coastguard Worker if(*p == '@' || *p == '<') {
542*6236dae4SAndroid Build Coastguard Worker char *hdrfile;
543*6236dae4SAndroid Build Coastguard Worker FILE *fp;
544*6236dae4SAndroid Build Coastguard Worker /* Read headers from a file. */
545*6236dae4SAndroid Build Coastguard Worker
546*6236dae4SAndroid Build Coastguard Worker do {
547*6236dae4SAndroid Build Coastguard Worker p++;
548*6236dae4SAndroid Build Coastguard Worker } while(ISSPACE(*p));
549*6236dae4SAndroid Build Coastguard Worker tp = p;
550*6236dae4SAndroid Build Coastguard Worker hdrfile = get_param_word(config, &p, &endpos, endchar);
551*6236dae4SAndroid Build Coastguard Worker /* If not quoted, strip trailing spaces. */
552*6236dae4SAndroid Build Coastguard Worker if(hdrfile == tp)
553*6236dae4SAndroid Build Coastguard Worker while(endpos > hdrfile && ISSPACE(endpos[-1]))
554*6236dae4SAndroid Build Coastguard Worker endpos--;
555*6236dae4SAndroid Build Coastguard Worker sep = *p;
556*6236dae4SAndroid Build Coastguard Worker *endpos = '\0';
557*6236dae4SAndroid Build Coastguard Worker fp = fopen(hdrfile, FOPEN_READTEXT);
558*6236dae4SAndroid Build Coastguard Worker if(!fp)
559*6236dae4SAndroid Build Coastguard Worker warnf(config->global, "Cannot read from %s: %s", hdrfile,
560*6236dae4SAndroid Build Coastguard Worker strerror(errno));
561*6236dae4SAndroid Build Coastguard Worker else {
562*6236dae4SAndroid Build Coastguard Worker int i = read_field_headers(config, hdrfile, fp, &headers);
563*6236dae4SAndroid Build Coastguard Worker
564*6236dae4SAndroid Build Coastguard Worker fclose(fp);
565*6236dae4SAndroid Build Coastguard Worker if(i) {
566*6236dae4SAndroid Build Coastguard Worker curl_slist_free_all(headers);
567*6236dae4SAndroid Build Coastguard Worker return -1;
568*6236dae4SAndroid Build Coastguard Worker }
569*6236dae4SAndroid Build Coastguard Worker }
570*6236dae4SAndroid Build Coastguard Worker }
571*6236dae4SAndroid Build Coastguard Worker else {
572*6236dae4SAndroid Build Coastguard Worker char *hdr;
573*6236dae4SAndroid Build Coastguard Worker
574*6236dae4SAndroid Build Coastguard Worker while(ISSPACE(*p))
575*6236dae4SAndroid Build Coastguard Worker p++;
576*6236dae4SAndroid Build Coastguard Worker tp = p;
577*6236dae4SAndroid Build Coastguard Worker hdr = get_param_word(config, &p, &endpos, endchar);
578*6236dae4SAndroid Build Coastguard Worker /* If not quoted, strip trailing spaces. */
579*6236dae4SAndroid Build Coastguard Worker if(hdr == tp)
580*6236dae4SAndroid Build Coastguard Worker while(endpos > hdr && ISSPACE(endpos[-1]))
581*6236dae4SAndroid Build Coastguard Worker endpos--;
582*6236dae4SAndroid Build Coastguard Worker sep = *p;
583*6236dae4SAndroid Build Coastguard Worker *endpos = '\0';
584*6236dae4SAndroid Build Coastguard Worker if(slist_append(&headers, hdr)) {
585*6236dae4SAndroid Build Coastguard Worker errorf(config->global, "Out of memory for field header");
586*6236dae4SAndroid Build Coastguard Worker curl_slist_free_all(headers);
587*6236dae4SAndroid Build Coastguard Worker return -1;
588*6236dae4SAndroid Build Coastguard Worker }
589*6236dae4SAndroid Build Coastguard Worker }
590*6236dae4SAndroid Build Coastguard Worker }
591*6236dae4SAndroid Build Coastguard Worker else if(checkprefix("encoder=", p)) {
592*6236dae4SAndroid Build Coastguard Worker if(endct) {
593*6236dae4SAndroid Build Coastguard Worker *endct = '\0';
594*6236dae4SAndroid Build Coastguard Worker endct = NULL;
595*6236dae4SAndroid Build Coastguard Worker }
596*6236dae4SAndroid Build Coastguard Worker for(p += 8; ISSPACE(*p); p++)
597*6236dae4SAndroid Build Coastguard Worker ;
598*6236dae4SAndroid Build Coastguard Worker tp = p;
599*6236dae4SAndroid Build Coastguard Worker encoder = get_param_word(config, &p, &endpos, endchar);
600*6236dae4SAndroid Build Coastguard Worker /* If not quoted, strip trailing spaces. */
601*6236dae4SAndroid Build Coastguard Worker if(encoder == tp)
602*6236dae4SAndroid Build Coastguard Worker while(endpos > encoder && ISSPACE(endpos[-1]))
603*6236dae4SAndroid Build Coastguard Worker endpos--;
604*6236dae4SAndroid Build Coastguard Worker sep = *p;
605*6236dae4SAndroid Build Coastguard Worker *endpos = '\0';
606*6236dae4SAndroid Build Coastguard Worker }
607*6236dae4SAndroid Build Coastguard Worker else if(endct) {
608*6236dae4SAndroid Build Coastguard Worker /* This is part of content type. */
609*6236dae4SAndroid Build Coastguard Worker for(endct = p; *p && *p != ';' && *p != endchar; p++)
610*6236dae4SAndroid Build Coastguard Worker if(!ISSPACE(*p))
611*6236dae4SAndroid Build Coastguard Worker endct = p + 1;
612*6236dae4SAndroid Build Coastguard Worker sep = *p;
613*6236dae4SAndroid Build Coastguard Worker }
614*6236dae4SAndroid Build Coastguard Worker else {
615*6236dae4SAndroid Build Coastguard Worker /* unknown prefix, skip to next block */
616*6236dae4SAndroid Build Coastguard Worker char *unknown = get_param_word(config, &p, &endpos, endchar);
617*6236dae4SAndroid Build Coastguard Worker
618*6236dae4SAndroid Build Coastguard Worker sep = *p;
619*6236dae4SAndroid Build Coastguard Worker *endpos = '\0';
620*6236dae4SAndroid Build Coastguard Worker if(*unknown)
621*6236dae4SAndroid Build Coastguard Worker warnf(config->global, "skip unknown form field: %s", unknown);
622*6236dae4SAndroid Build Coastguard Worker }
623*6236dae4SAndroid Build Coastguard Worker }
624*6236dae4SAndroid Build Coastguard Worker
625*6236dae4SAndroid Build Coastguard Worker /* Terminate content type. */
626*6236dae4SAndroid Build Coastguard Worker if(endct)
627*6236dae4SAndroid Build Coastguard Worker *endct = '\0';
628*6236dae4SAndroid Build Coastguard Worker
629*6236dae4SAndroid Build Coastguard Worker if(ptype)
630*6236dae4SAndroid Build Coastguard Worker *ptype = type;
631*6236dae4SAndroid Build Coastguard Worker else if(type)
632*6236dae4SAndroid Build Coastguard Worker warnf(config->global, "Field content type not allowed here: %s", type);
633*6236dae4SAndroid Build Coastguard Worker
634*6236dae4SAndroid Build Coastguard Worker if(pfilename)
635*6236dae4SAndroid Build Coastguard Worker *pfilename = filename;
636*6236dae4SAndroid Build Coastguard Worker else if(filename)
637*6236dae4SAndroid Build Coastguard Worker warnf(config->global,
638*6236dae4SAndroid Build Coastguard Worker "Field filename not allowed here: %s", filename);
639*6236dae4SAndroid Build Coastguard Worker
640*6236dae4SAndroid Build Coastguard Worker if(pencoder)
641*6236dae4SAndroid Build Coastguard Worker *pencoder = encoder;
642*6236dae4SAndroid Build Coastguard Worker else if(encoder)
643*6236dae4SAndroid Build Coastguard Worker warnf(config->global,
644*6236dae4SAndroid Build Coastguard Worker "Field encoder not allowed here: %s", encoder);
645*6236dae4SAndroid Build Coastguard Worker
646*6236dae4SAndroid Build Coastguard Worker if(pheaders)
647*6236dae4SAndroid Build Coastguard Worker *pheaders = headers;
648*6236dae4SAndroid Build Coastguard Worker else if(headers) {
649*6236dae4SAndroid Build Coastguard Worker warnf(config->global,
650*6236dae4SAndroid Build Coastguard Worker "Field headers not allowed here: %s", headers->data);
651*6236dae4SAndroid Build Coastguard Worker curl_slist_free_all(headers);
652*6236dae4SAndroid Build Coastguard Worker }
653*6236dae4SAndroid Build Coastguard Worker
654*6236dae4SAndroid Build Coastguard Worker *str = p;
655*6236dae4SAndroid Build Coastguard Worker return sep & 0xFF;
656*6236dae4SAndroid Build Coastguard Worker }
657*6236dae4SAndroid Build Coastguard Worker
658*6236dae4SAndroid Build Coastguard Worker
659*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
660*6236dae4SAndroid Build Coastguard Worker *
661*6236dae4SAndroid Build Coastguard Worker * formparse()
662*6236dae4SAndroid Build Coastguard Worker *
663*6236dae4SAndroid Build Coastguard Worker * Reads a 'name=value' parameter and builds the appropriate linked list.
664*6236dae4SAndroid Build Coastguard Worker *
665*6236dae4SAndroid Build Coastguard Worker * If the value is of the form '<filename', field data is read from the
666*6236dae4SAndroid Build Coastguard Worker * given file.
667*6236dae4SAndroid Build Coastguard Worker
668*6236dae4SAndroid Build Coastguard Worker * Specify files to upload with 'name=@filename', or 'name=@"filename"'
669*6236dae4SAndroid Build Coastguard Worker * in case the filename contain ',' or ';'. Supports specified
670*6236dae4SAndroid Build Coastguard Worker * given Content-Type of the files. Such as ';type=<content-type>'.
671*6236dae4SAndroid Build Coastguard Worker *
672*6236dae4SAndroid Build Coastguard Worker * If literal_value is set, any initial '@' or '<' in the value string
673*6236dae4SAndroid Build Coastguard Worker * loses its special meaning, as does any embedded ';type='.
674*6236dae4SAndroid Build Coastguard Worker *
675*6236dae4SAndroid Build Coastguard Worker * You may specify more than one file for a single name (field). Specify
676*6236dae4SAndroid Build Coastguard Worker * multiple files by writing it like:
677*6236dae4SAndroid Build Coastguard Worker *
678*6236dae4SAndroid Build Coastguard Worker * 'name=@filename,filename2,filename3'
679*6236dae4SAndroid Build Coastguard Worker *
680*6236dae4SAndroid Build Coastguard Worker * or use double-quotes quote the filename:
681*6236dae4SAndroid Build Coastguard Worker *
682*6236dae4SAndroid Build Coastguard Worker * 'name=@"filename","filename2","filename3"'
683*6236dae4SAndroid Build Coastguard Worker *
684*6236dae4SAndroid Build Coastguard Worker * If you want content-types specified for each too, write them like:
685*6236dae4SAndroid Build Coastguard Worker *
686*6236dae4SAndroid Build Coastguard Worker * 'name=@filename;type=image/gif,filename2,filename3'
687*6236dae4SAndroid Build Coastguard Worker *
688*6236dae4SAndroid Build Coastguard Worker * If you want custom headers added for a single part, write them in a separate
689*6236dae4SAndroid Build Coastguard Worker * file and do like this:
690*6236dae4SAndroid Build Coastguard Worker *
691*6236dae4SAndroid Build Coastguard Worker * 'name=foo;headers=@headerfile' or why not
692*6236dae4SAndroid Build Coastguard Worker * 'name=@filemame;headers=@headerfile'
693*6236dae4SAndroid Build Coastguard Worker *
694*6236dae4SAndroid Build Coastguard Worker * To upload a file, but to fake the filename that will be included in the
695*6236dae4SAndroid Build Coastguard Worker * formpost, do like this:
696*6236dae4SAndroid Build Coastguard Worker *
697*6236dae4SAndroid Build Coastguard Worker * 'name=@filename;filename=/dev/null' or quote the faked filename like:
698*6236dae4SAndroid Build Coastguard Worker * 'name=@filename;filename="play, play, and play.txt"'
699*6236dae4SAndroid Build Coastguard Worker *
700*6236dae4SAndroid Build Coastguard Worker * If filename/path contains ',' or ';', it must be quoted by double-quotes,
701*6236dae4SAndroid Build Coastguard Worker * else curl will fail to figure out the correct filename. if the filename
702*6236dae4SAndroid Build Coastguard Worker * tobe quoted contains '"' or '\', '"' and '\' must be escaped by backslash.
703*6236dae4SAndroid Build Coastguard Worker *
704*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
705*6236dae4SAndroid Build Coastguard Worker
706*6236dae4SAndroid Build Coastguard Worker #define SET_TOOL_MIME_PTR(m, field) \
707*6236dae4SAndroid Build Coastguard Worker do { \
708*6236dae4SAndroid Build Coastguard Worker if(field) { \
709*6236dae4SAndroid Build Coastguard Worker (m)->field = strdup(field); \
710*6236dae4SAndroid Build Coastguard Worker if(!(m)->field) \
711*6236dae4SAndroid Build Coastguard Worker goto fail; \
712*6236dae4SAndroid Build Coastguard Worker } \
713*6236dae4SAndroid Build Coastguard Worker } while(0)
714*6236dae4SAndroid Build Coastguard Worker
formparse(struct OperationConfig * config,const char * input,struct tool_mime ** mimeroot,struct tool_mime ** mimecurrent,bool literal_value)715*6236dae4SAndroid Build Coastguard Worker int formparse(struct OperationConfig *config,
716*6236dae4SAndroid Build Coastguard Worker const char *input,
717*6236dae4SAndroid Build Coastguard Worker struct tool_mime **mimeroot,
718*6236dae4SAndroid Build Coastguard Worker struct tool_mime **mimecurrent,
719*6236dae4SAndroid Build Coastguard Worker bool literal_value)
720*6236dae4SAndroid Build Coastguard Worker {
721*6236dae4SAndroid Build Coastguard Worker /* input MUST be a string in the format 'name=contents' and we will
722*6236dae4SAndroid Build Coastguard Worker build a linked list with the info */
723*6236dae4SAndroid Build Coastguard Worker char *name = NULL;
724*6236dae4SAndroid Build Coastguard Worker char *contents = NULL;
725*6236dae4SAndroid Build Coastguard Worker char *contp;
726*6236dae4SAndroid Build Coastguard Worker char *data;
727*6236dae4SAndroid Build Coastguard Worker char *type = NULL;
728*6236dae4SAndroid Build Coastguard Worker char *filename = NULL;
729*6236dae4SAndroid Build Coastguard Worker char *encoder = NULL;
730*6236dae4SAndroid Build Coastguard Worker struct curl_slist *headers = NULL;
731*6236dae4SAndroid Build Coastguard Worker struct tool_mime *part = NULL;
732*6236dae4SAndroid Build Coastguard Worker CURLcode res;
733*6236dae4SAndroid Build Coastguard Worker int err = 1;
734*6236dae4SAndroid Build Coastguard Worker
735*6236dae4SAndroid Build Coastguard Worker /* Allocate the main mime structure if needed. */
736*6236dae4SAndroid Build Coastguard Worker if(!*mimecurrent) {
737*6236dae4SAndroid Build Coastguard Worker *mimeroot = tool_mime_new_parts(NULL);
738*6236dae4SAndroid Build Coastguard Worker if(!*mimeroot)
739*6236dae4SAndroid Build Coastguard Worker goto fail;
740*6236dae4SAndroid Build Coastguard Worker *mimecurrent = *mimeroot;
741*6236dae4SAndroid Build Coastguard Worker }
742*6236dae4SAndroid Build Coastguard Worker
743*6236dae4SAndroid Build Coastguard Worker /* Make a copy we can overwrite. */
744*6236dae4SAndroid Build Coastguard Worker contents = strdup(input);
745*6236dae4SAndroid Build Coastguard Worker if(!contents)
746*6236dae4SAndroid Build Coastguard Worker goto fail;
747*6236dae4SAndroid Build Coastguard Worker
748*6236dae4SAndroid Build Coastguard Worker /* Scan for the end of the name. */
749*6236dae4SAndroid Build Coastguard Worker contp = strchr(contents, '=');
750*6236dae4SAndroid Build Coastguard Worker if(contp) {
751*6236dae4SAndroid Build Coastguard Worker int sep = '\0';
752*6236dae4SAndroid Build Coastguard Worker if(contp > contents)
753*6236dae4SAndroid Build Coastguard Worker name = contents;
754*6236dae4SAndroid Build Coastguard Worker *contp++ = '\0';
755*6236dae4SAndroid Build Coastguard Worker
756*6236dae4SAndroid Build Coastguard Worker if(*contp == '(' && !literal_value) {
757*6236dae4SAndroid Build Coastguard Worker /* Starting a multipart. */
758*6236dae4SAndroid Build Coastguard Worker sep = get_param_part(config, '\0',
759*6236dae4SAndroid Build Coastguard Worker &contp, &data, &type, NULL, NULL, &headers);
760*6236dae4SAndroid Build Coastguard Worker if(sep < 0)
761*6236dae4SAndroid Build Coastguard Worker goto fail;
762*6236dae4SAndroid Build Coastguard Worker part = tool_mime_new_parts(*mimecurrent);
763*6236dae4SAndroid Build Coastguard Worker if(!part)
764*6236dae4SAndroid Build Coastguard Worker goto fail;
765*6236dae4SAndroid Build Coastguard Worker *mimecurrent = part;
766*6236dae4SAndroid Build Coastguard Worker part->headers = headers;
767*6236dae4SAndroid Build Coastguard Worker headers = NULL;
768*6236dae4SAndroid Build Coastguard Worker SET_TOOL_MIME_PTR(part, type);
769*6236dae4SAndroid Build Coastguard Worker }
770*6236dae4SAndroid Build Coastguard Worker else if(!name && !strcmp(contp, ")") && !literal_value) {
771*6236dae4SAndroid Build Coastguard Worker /* Ending a multipart. */
772*6236dae4SAndroid Build Coastguard Worker if(*mimecurrent == *mimeroot) {
773*6236dae4SAndroid Build Coastguard Worker warnf(config->global, "no multipart to terminate");
774*6236dae4SAndroid Build Coastguard Worker goto fail;
775*6236dae4SAndroid Build Coastguard Worker }
776*6236dae4SAndroid Build Coastguard Worker *mimecurrent = (*mimecurrent)->parent;
777*6236dae4SAndroid Build Coastguard Worker }
778*6236dae4SAndroid Build Coastguard Worker else if('@' == contp[0] && !literal_value) {
779*6236dae4SAndroid Build Coastguard Worker
780*6236dae4SAndroid Build Coastguard Worker /* we use the @-letter to indicate filename(s) */
781*6236dae4SAndroid Build Coastguard Worker
782*6236dae4SAndroid Build Coastguard Worker struct tool_mime *subparts = NULL;
783*6236dae4SAndroid Build Coastguard Worker
784*6236dae4SAndroid Build Coastguard Worker do {
785*6236dae4SAndroid Build Coastguard Worker /* since this was a file, it may have a content-type specifier
786*6236dae4SAndroid Build Coastguard Worker at the end too, or a filename. Or both. */
787*6236dae4SAndroid Build Coastguard Worker ++contp;
788*6236dae4SAndroid Build Coastguard Worker sep = get_param_part(config, ',', &contp,
789*6236dae4SAndroid Build Coastguard Worker &data, &type, &filename, &encoder, &headers);
790*6236dae4SAndroid Build Coastguard Worker if(sep < 0) {
791*6236dae4SAndroid Build Coastguard Worker goto fail;
792*6236dae4SAndroid Build Coastguard Worker }
793*6236dae4SAndroid Build Coastguard Worker
794*6236dae4SAndroid Build Coastguard Worker /* now contp point to comma or string end.
795*6236dae4SAndroid Build Coastguard Worker If more files to come, make sure we have multiparts. */
796*6236dae4SAndroid Build Coastguard Worker if(!subparts) {
797*6236dae4SAndroid Build Coastguard Worker if(sep != ',') /* If there is a single file. */
798*6236dae4SAndroid Build Coastguard Worker subparts = *mimecurrent;
799*6236dae4SAndroid Build Coastguard Worker else {
800*6236dae4SAndroid Build Coastguard Worker subparts = tool_mime_new_parts(*mimecurrent);
801*6236dae4SAndroid Build Coastguard Worker if(!subparts)
802*6236dae4SAndroid Build Coastguard Worker goto fail;
803*6236dae4SAndroid Build Coastguard Worker }
804*6236dae4SAndroid Build Coastguard Worker }
805*6236dae4SAndroid Build Coastguard Worker
806*6236dae4SAndroid Build Coastguard Worker /* Store that file in a part. */
807*6236dae4SAndroid Build Coastguard Worker part = tool_mime_new_filedata(subparts, data, TRUE, &res);
808*6236dae4SAndroid Build Coastguard Worker if(!part)
809*6236dae4SAndroid Build Coastguard Worker goto fail;
810*6236dae4SAndroid Build Coastguard Worker part->headers = headers;
811*6236dae4SAndroid Build Coastguard Worker headers = NULL;
812*6236dae4SAndroid Build Coastguard Worker part->config = config->global;
813*6236dae4SAndroid Build Coastguard Worker if(res == CURLE_READ_ERROR) {
814*6236dae4SAndroid Build Coastguard Worker /* An error occurred while reading stdin: if read has started,
815*6236dae4SAndroid Build Coastguard Worker issue the error now. Else, delay it until processed by
816*6236dae4SAndroid Build Coastguard Worker libcurl. */
817*6236dae4SAndroid Build Coastguard Worker if(part->size > 0) {
818*6236dae4SAndroid Build Coastguard Worker warnf(config->global,
819*6236dae4SAndroid Build Coastguard Worker "error while reading standard input");
820*6236dae4SAndroid Build Coastguard Worker goto fail;
821*6236dae4SAndroid Build Coastguard Worker }
822*6236dae4SAndroid Build Coastguard Worker Curl_safefree(part->data);
823*6236dae4SAndroid Build Coastguard Worker part->data = NULL;
824*6236dae4SAndroid Build Coastguard Worker part->size = -1;
825*6236dae4SAndroid Build Coastguard Worker res = CURLE_OK;
826*6236dae4SAndroid Build Coastguard Worker }
827*6236dae4SAndroid Build Coastguard Worker SET_TOOL_MIME_PTR(part, filename);
828*6236dae4SAndroid Build Coastguard Worker SET_TOOL_MIME_PTR(part, type);
829*6236dae4SAndroid Build Coastguard Worker SET_TOOL_MIME_PTR(part, encoder);
830*6236dae4SAndroid Build Coastguard Worker
831*6236dae4SAndroid Build Coastguard Worker /* *contp could be '\0', so we just check with the delimiter */
832*6236dae4SAndroid Build Coastguard Worker } while(sep); /* loop if there is another filename */
833*6236dae4SAndroid Build Coastguard Worker part = (*mimecurrent)->subparts; /* Set name on group. */
834*6236dae4SAndroid Build Coastguard Worker }
835*6236dae4SAndroid Build Coastguard Worker else {
836*6236dae4SAndroid Build Coastguard Worker if(*contp == '<' && !literal_value) {
837*6236dae4SAndroid Build Coastguard Worker ++contp;
838*6236dae4SAndroid Build Coastguard Worker sep = get_param_part(config, '\0', &contp,
839*6236dae4SAndroid Build Coastguard Worker &data, &type, NULL, &encoder, &headers);
840*6236dae4SAndroid Build Coastguard Worker if(sep < 0)
841*6236dae4SAndroid Build Coastguard Worker goto fail;
842*6236dae4SAndroid Build Coastguard Worker
843*6236dae4SAndroid Build Coastguard Worker part = tool_mime_new_filedata(*mimecurrent, data, FALSE,
844*6236dae4SAndroid Build Coastguard Worker &res);
845*6236dae4SAndroid Build Coastguard Worker if(!part)
846*6236dae4SAndroid Build Coastguard Worker goto fail;
847*6236dae4SAndroid Build Coastguard Worker part->headers = headers;
848*6236dae4SAndroid Build Coastguard Worker headers = NULL;
849*6236dae4SAndroid Build Coastguard Worker part->config = config->global;
850*6236dae4SAndroid Build Coastguard Worker if(res == CURLE_READ_ERROR) {
851*6236dae4SAndroid Build Coastguard Worker /* An error occurred while reading stdin: if read has started,
852*6236dae4SAndroid Build Coastguard Worker issue the error now. Else, delay it until processed by
853*6236dae4SAndroid Build Coastguard Worker libcurl. */
854*6236dae4SAndroid Build Coastguard Worker if(part->size > 0) {
855*6236dae4SAndroid Build Coastguard Worker warnf(config->global,
856*6236dae4SAndroid Build Coastguard Worker "error while reading standard input");
857*6236dae4SAndroid Build Coastguard Worker goto fail;
858*6236dae4SAndroid Build Coastguard Worker }
859*6236dae4SAndroid Build Coastguard Worker Curl_safefree(part->data);
860*6236dae4SAndroid Build Coastguard Worker part->data = NULL;
861*6236dae4SAndroid Build Coastguard Worker part->size = -1;
862*6236dae4SAndroid Build Coastguard Worker res = CURLE_OK;
863*6236dae4SAndroid Build Coastguard Worker }
864*6236dae4SAndroid Build Coastguard Worker }
865*6236dae4SAndroid Build Coastguard Worker else {
866*6236dae4SAndroid Build Coastguard Worker if(literal_value)
867*6236dae4SAndroid Build Coastguard Worker data = contp;
868*6236dae4SAndroid Build Coastguard Worker else {
869*6236dae4SAndroid Build Coastguard Worker sep = get_param_part(config, '\0', &contp,
870*6236dae4SAndroid Build Coastguard Worker &data, &type, &filename, &encoder, &headers);
871*6236dae4SAndroid Build Coastguard Worker if(sep < 0)
872*6236dae4SAndroid Build Coastguard Worker goto fail;
873*6236dae4SAndroid Build Coastguard Worker }
874*6236dae4SAndroid Build Coastguard Worker
875*6236dae4SAndroid Build Coastguard Worker part = tool_mime_new_data(*mimecurrent, data);
876*6236dae4SAndroid Build Coastguard Worker if(!part)
877*6236dae4SAndroid Build Coastguard Worker goto fail;
878*6236dae4SAndroid Build Coastguard Worker part->headers = headers;
879*6236dae4SAndroid Build Coastguard Worker headers = NULL;
880*6236dae4SAndroid Build Coastguard Worker }
881*6236dae4SAndroid Build Coastguard Worker
882*6236dae4SAndroid Build Coastguard Worker SET_TOOL_MIME_PTR(part, filename);
883*6236dae4SAndroid Build Coastguard Worker SET_TOOL_MIME_PTR(part, type);
884*6236dae4SAndroid Build Coastguard Worker SET_TOOL_MIME_PTR(part, encoder);
885*6236dae4SAndroid Build Coastguard Worker
886*6236dae4SAndroid Build Coastguard Worker if(sep) {
887*6236dae4SAndroid Build Coastguard Worker *contp = (char) sep;
888*6236dae4SAndroid Build Coastguard Worker warnf(config->global,
889*6236dae4SAndroid Build Coastguard Worker "garbage at end of field specification: %s", contp);
890*6236dae4SAndroid Build Coastguard Worker }
891*6236dae4SAndroid Build Coastguard Worker }
892*6236dae4SAndroid Build Coastguard Worker
893*6236dae4SAndroid Build Coastguard Worker /* Set part name. */
894*6236dae4SAndroid Build Coastguard Worker SET_TOOL_MIME_PTR(part, name);
895*6236dae4SAndroid Build Coastguard Worker }
896*6236dae4SAndroid Build Coastguard Worker else {
897*6236dae4SAndroid Build Coastguard Worker warnf(config->global, "Illegally formatted input field");
898*6236dae4SAndroid Build Coastguard Worker goto fail;
899*6236dae4SAndroid Build Coastguard Worker }
900*6236dae4SAndroid Build Coastguard Worker err = 0;
901*6236dae4SAndroid Build Coastguard Worker fail:
902*6236dae4SAndroid Build Coastguard Worker Curl_safefree(contents);
903*6236dae4SAndroid Build Coastguard Worker curl_slist_free_all(headers);
904*6236dae4SAndroid Build Coastguard Worker return err;
905*6236dae4SAndroid Build Coastguard Worker }
906