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