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