1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, 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.haxx.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 ***************************************************************************/
22
23 #include "curl_setup.h"
24
25 #include <curl/curl.h>
26
27 #ifndef CURL_DISABLE_HTTP
28
29 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
30 #include <libgen.h>
31 #endif
32
33 #include "urldata.h" /* for struct Curl_easy */
34 #include "formdata.h"
35 #include "vtls/vtls.h"
36 #include "strcase.h"
37 #include "sendf.h"
38 #include "strdup.h"
39 #include "rand.h"
40 /* The last 3 #include files should be in this order */
41 #include "curl_printf.h"
42 #include "curl_memory.h"
43 #include "memdebug.h"
44
45 #ifndef HAVE_BASENAME
46 static char *Curl_basename(char *path);
47 #define basename(x) Curl_basename((x))
48 #endif
49
50 static size_t readfromfile(struct Form *form, char *buffer, size_t size);
51 static char *formboundary(struct Curl_easy *data);
52
53 /* What kind of Content-Type to use on un-specified files with unrecognized
54 extensions. */
55 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
56
57 #define FORM_FILE_SEPARATOR ','
58 #define FORM_TYPE_SEPARATOR ';'
59
60 #define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
61 #define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
62 #define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
63 #define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
64 #define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
65 #define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
66 #define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
67
68 /***************************************************************************
69 *
70 * AddHttpPost()
71 *
72 * Adds a HttpPost structure to the list, if parent_post is given becomes
73 * a subpost of parent_post instead of a direct list element.
74 *
75 * Returns newly allocated HttpPost on success and NULL if malloc failed.
76 *
77 ***************************************************************************/
78 static struct curl_httppost *
AddHttpPost(char * name,size_t namelength,char * value,curl_off_t contentslength,char * buffer,size_t bufferlength,char * contenttype,long flags,struct curl_slist * contentHeader,char * showfilename,char * userp,struct curl_httppost * parent_post,struct curl_httppost ** httppost,struct curl_httppost ** last_post)79 AddHttpPost(char *name, size_t namelength,
80 char *value, curl_off_t contentslength,
81 char *buffer, size_t bufferlength,
82 char *contenttype,
83 long flags,
84 struct curl_slist *contentHeader,
85 char *showfilename, char *userp,
86 struct curl_httppost *parent_post,
87 struct curl_httppost **httppost,
88 struct curl_httppost **last_post)
89 {
90 struct curl_httppost *post;
91 post = calloc(1, sizeof(struct curl_httppost));
92 if(post) {
93 post->name = name;
94 post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
95 post->contents = value;
96 post->contentlen = contentslength;
97 post->buffer = buffer;
98 post->bufferlength = (long)bufferlength;
99 post->contenttype = contenttype;
100 post->contentheader = contentHeader;
101 post->showfilename = showfilename;
102 post->userp = userp,
103 post->flags = flags | CURL_HTTPPOST_LARGE;
104 }
105 else
106 return NULL;
107
108 if(parent_post) {
109 /* now, point our 'more' to the original 'more' */
110 post->more = parent_post->more;
111
112 /* then move the original 'more' to point to ourselves */
113 parent_post->more = post;
114 }
115 else {
116 /* make the previous point to this */
117 if(*last_post)
118 (*last_post)->next = post;
119 else
120 (*httppost) = post;
121
122 (*last_post) = post;
123 }
124 return post;
125 }
126
127 /***************************************************************************
128 *
129 * AddFormInfo()
130 *
131 * Adds a FormInfo structure to the list presented by parent_form_info.
132 *
133 * Returns newly allocated FormInfo on success and NULL if malloc failed/
134 * parent_form_info is NULL.
135 *
136 ***************************************************************************/
AddFormInfo(char * value,char * contenttype,FormInfo * parent_form_info)137 static FormInfo * AddFormInfo(char *value,
138 char *contenttype,
139 FormInfo *parent_form_info)
140 {
141 FormInfo *form_info;
142 form_info = calloc(1, sizeof(struct FormInfo));
143 if(form_info) {
144 if(value)
145 form_info->value = value;
146 if(contenttype)
147 form_info->contenttype = contenttype;
148 form_info->flags = HTTPPOST_FILENAME;
149 }
150 else
151 return NULL;
152
153 if(parent_form_info) {
154 /* now, point our 'more' to the original 'more' */
155 form_info->more = parent_form_info->more;
156
157 /* then move the original 'more' to point to ourselves */
158 parent_form_info->more = form_info;
159 }
160
161 return form_info;
162 }
163
164 /***************************************************************************
165 *
166 * ContentTypeForFilename()
167 *
168 * Provides content type for filename if one of the known types (else
169 * (either the prevtype or the default is returned).
170 *
171 * Returns some valid contenttype for filename.
172 *
173 ***************************************************************************/
ContentTypeForFilename(const char * filename,const char * prevtype)174 static const char *ContentTypeForFilename(const char *filename,
175 const char *prevtype)
176 {
177 const char *contenttype = NULL;
178 unsigned int i;
179 /*
180 * No type was specified, we scan through a few well-known
181 * extensions and pick the first we match!
182 */
183 struct ContentType {
184 const char *extension;
185 const char *type;
186 };
187 static const struct ContentType ctts[]={
188 {".gif", "image/gif"},
189 {".jpg", "image/jpeg"},
190 {".jpeg", "image/jpeg"},
191 {".txt", "text/plain"},
192 {".html", "text/html"},
193 {".xml", "application/xml"}
194 };
195
196 if(prevtype)
197 /* default to the previously set/used! */
198 contenttype = prevtype;
199 else
200 contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
201
202 if(filename) { /* in case a NULL was passed in */
203 for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
204 if(strlen(filename) >= strlen(ctts[i].extension)) {
205 if(strcasecompare(filename +
206 strlen(filename) - strlen(ctts[i].extension),
207 ctts[i].extension)) {
208 contenttype = ctts[i].type;
209 break;
210 }
211 }
212 }
213 }
214 /* we have a contenttype by now */
215 return contenttype;
216 }
217
218 /***************************************************************************
219 *
220 * FormAdd()
221 *
222 * Stores a formpost parameter and builds the appropriate linked list.
223 *
224 * Has two principal functionalities: using files and byte arrays as
225 * post parts. Byte arrays are either copied or just the pointer is stored
226 * (as the user requests) while for files only the filename and not the
227 * content is stored.
228 *
229 * While you may have only one byte array for each name, multiple filenames
230 * are allowed (and because of this feature CURLFORM_END is needed after
231 * using CURLFORM_FILE).
232 *
233 * Examples:
234 *
235 * Simple name/value pair with copied contents:
236 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
237 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
238 *
239 * name/value pair where only the content pointer is remembered:
240 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
241 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
242 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
243 *
244 * storing a filename (CONTENTTYPE is optional!):
245 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
246 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
247 * CURLFORM_END);
248 *
249 * storing multiple filenames:
250 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
251 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
252 *
253 * Returns:
254 * CURL_FORMADD_OK on success
255 * CURL_FORMADD_MEMORY if the FormInfo allocation fails
256 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
257 * CURL_FORMADD_NULL if a null pointer was given for a char
258 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
259 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
260 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
261 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
262 * CURL_FORMADD_MEMORY if some allocation for string copying failed.
263 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
264 *
265 ***************************************************************************/
266
267 static
FormAdd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,va_list params)268 CURLFORMcode FormAdd(struct curl_httppost **httppost,
269 struct curl_httppost **last_post,
270 va_list params)
271 {
272 FormInfo *first_form, *current_form, *form = NULL;
273 CURLFORMcode return_value = CURL_FORMADD_OK;
274 const char *prevtype = NULL;
275 struct curl_httppost *post = NULL;
276 CURLformoption option;
277 struct curl_forms *forms = NULL;
278 char *array_value=NULL; /* value read from an array */
279
280 /* This is a state variable, that if TRUE means that we're parsing an
281 array that we got passed to us. If FALSE we're parsing the input
282 va_list arguments. */
283 bool array_state = FALSE;
284
285 /*
286 * We need to allocate the first struct to fill in.
287 */
288 first_form = calloc(1, sizeof(struct FormInfo));
289 if(!first_form)
290 return CURL_FORMADD_MEMORY;
291
292 current_form = first_form;
293
294 /*
295 * Loop through all the options set. Break if we have an error to report.
296 */
297 while(return_value == CURL_FORMADD_OK) {
298
299 /* first see if we have more parts of the array param */
300 if(array_state && forms) {
301 /* get the upcoming option from the given array */
302 option = forms->option;
303 array_value = (char *)forms->value;
304
305 forms++; /* advance this to next entry */
306 if(CURLFORM_END == option) {
307 /* end of array state */
308 array_state = FALSE;
309 continue;
310 }
311 }
312 else {
313 /* This is not array-state, get next option */
314 option = va_arg(params, CURLformoption);
315 if(CURLFORM_END == option)
316 break;
317 }
318
319 switch (option) {
320 case CURLFORM_ARRAY:
321 if(array_state)
322 /* we don't support an array from within an array */
323 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
324 else {
325 forms = va_arg(params, struct curl_forms *);
326 if(forms)
327 array_state = TRUE;
328 else
329 return_value = CURL_FORMADD_NULL;
330 }
331 break;
332
333 /*
334 * Set the Name property.
335 */
336 case CURLFORM_PTRNAME:
337 #ifdef CURL_DOES_CONVERSIONS
338 /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
339 * the data in all cases so that we'll have safe memory for the eventual
340 * conversion.
341 */
342 #else
343 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
344 #endif
345 case CURLFORM_COPYNAME:
346 if(current_form->name)
347 return_value = CURL_FORMADD_OPTION_TWICE;
348 else {
349 char *name = array_state?
350 array_value:va_arg(params, char *);
351 if(name)
352 current_form->name = name; /* store for the moment */
353 else
354 return_value = CURL_FORMADD_NULL;
355 }
356 break;
357 case CURLFORM_NAMELENGTH:
358 if(current_form->namelength)
359 return_value = CURL_FORMADD_OPTION_TWICE;
360 else
361 current_form->namelength =
362 array_state?(size_t)array_value:(size_t)va_arg(params, long);
363 break;
364
365 /*
366 * Set the contents property.
367 */
368 case CURLFORM_PTRCONTENTS:
369 current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
370 case CURLFORM_COPYCONTENTS:
371 if(current_form->value)
372 return_value = CURL_FORMADD_OPTION_TWICE;
373 else {
374 char *value =
375 array_state?array_value:va_arg(params, char *);
376 if(value)
377 current_form->value = value; /* store for the moment */
378 else
379 return_value = CURL_FORMADD_NULL;
380 }
381 break;
382 case CURLFORM_CONTENTSLENGTH:
383 current_form->contentslength =
384 array_state?(size_t)array_value:(size_t)va_arg(params, long);
385 break;
386
387 case CURLFORM_CONTENTLEN:
388 current_form->flags |= CURL_HTTPPOST_LARGE;
389 current_form->contentslength =
390 array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
391 break;
392
393 /* Get contents from a given file name */
394 case CURLFORM_FILECONTENT:
395 if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
396 return_value = CURL_FORMADD_OPTION_TWICE;
397 else {
398 const char *filename = array_state?
399 array_value:va_arg(params, char *);
400 if(filename) {
401 current_form->value = strdup(filename);
402 if(!current_form->value)
403 return_value = CURL_FORMADD_MEMORY;
404 else {
405 current_form->flags |= HTTPPOST_READFILE;
406 current_form->value_alloc = TRUE;
407 }
408 }
409 else
410 return_value = CURL_FORMADD_NULL;
411 }
412 break;
413
414 /* We upload a file */
415 case CURLFORM_FILE:
416 {
417 const char *filename = array_state?array_value:
418 va_arg(params, char *);
419
420 if(current_form->value) {
421 if(current_form->flags & HTTPPOST_FILENAME) {
422 if(filename) {
423 char *fname = strdup(filename);
424 if(!fname)
425 return_value = CURL_FORMADD_MEMORY;
426 else {
427 form = AddFormInfo(fname, NULL, current_form);
428 if(!form) {
429 free(fname);
430 return_value = CURL_FORMADD_MEMORY;
431 }
432 else {
433 form->value_alloc = TRUE;
434 current_form = form;
435 form = NULL;
436 }
437 }
438 }
439 else
440 return_value = CURL_FORMADD_NULL;
441 }
442 else
443 return_value = CURL_FORMADD_OPTION_TWICE;
444 }
445 else {
446 if(filename) {
447 current_form->value = strdup(filename);
448 if(!current_form->value)
449 return_value = CURL_FORMADD_MEMORY;
450 else {
451 current_form->flags |= HTTPPOST_FILENAME;
452 current_form->value_alloc = TRUE;
453 }
454 }
455 else
456 return_value = CURL_FORMADD_NULL;
457 }
458 break;
459 }
460
461 case CURLFORM_BUFFERPTR:
462 current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
463 if(current_form->buffer)
464 return_value = CURL_FORMADD_OPTION_TWICE;
465 else {
466 char *buffer =
467 array_state?array_value:va_arg(params, char *);
468 if(buffer) {
469 current_form->buffer = buffer; /* store for the moment */
470 current_form->value = buffer; /* make it non-NULL to be accepted
471 as fine */
472 }
473 else
474 return_value = CURL_FORMADD_NULL;
475 }
476 break;
477
478 case CURLFORM_BUFFERLENGTH:
479 if(current_form->bufferlength)
480 return_value = CURL_FORMADD_OPTION_TWICE;
481 else
482 current_form->bufferlength =
483 array_state?(size_t)array_value:(size_t)va_arg(params, long);
484 break;
485
486 case CURLFORM_STREAM:
487 current_form->flags |= HTTPPOST_CALLBACK;
488 if(current_form->userp)
489 return_value = CURL_FORMADD_OPTION_TWICE;
490 else {
491 char *userp =
492 array_state?array_value:va_arg(params, char *);
493 if(userp) {
494 current_form->userp = userp;
495 current_form->value = userp; /* this isn't strictly true but we
496 derive a value from this later on
497 and we need this non-NULL to be
498 accepted as a fine form part */
499 }
500 else
501 return_value = CURL_FORMADD_NULL;
502 }
503 break;
504
505 case CURLFORM_CONTENTTYPE:
506 {
507 const char *contenttype =
508 array_state?array_value:va_arg(params, char *);
509 if(current_form->contenttype) {
510 if(current_form->flags & HTTPPOST_FILENAME) {
511 if(contenttype) {
512 char *type = strdup(contenttype);
513 if(!type)
514 return_value = CURL_FORMADD_MEMORY;
515 else {
516 form = AddFormInfo(NULL, type, current_form);
517 if(!form) {
518 free(type);
519 return_value = CURL_FORMADD_MEMORY;
520 }
521 else {
522 form->contenttype_alloc = TRUE;
523 current_form = form;
524 form = NULL;
525 }
526 }
527 }
528 else
529 return_value = CURL_FORMADD_NULL;
530 }
531 else
532 return_value = CURL_FORMADD_OPTION_TWICE;
533 }
534 else {
535 if(contenttype) {
536 current_form->contenttype = strdup(contenttype);
537 if(!current_form->contenttype)
538 return_value = CURL_FORMADD_MEMORY;
539 else
540 current_form->contenttype_alloc = TRUE;
541 }
542 else
543 return_value = CURL_FORMADD_NULL;
544 }
545 break;
546 }
547 case CURLFORM_CONTENTHEADER:
548 {
549 /* this "cast increases required alignment of target type" but
550 we consider it OK anyway */
551 struct curl_slist *list = array_state?
552 (struct curl_slist *)(void *)array_value:
553 va_arg(params, struct curl_slist *);
554
555 if(current_form->contentheader)
556 return_value = CURL_FORMADD_OPTION_TWICE;
557 else
558 current_form->contentheader = list;
559
560 break;
561 }
562 case CURLFORM_FILENAME:
563 case CURLFORM_BUFFER:
564 {
565 const char *filename = array_state?array_value:
566 va_arg(params, char *);
567 if(current_form->showfilename)
568 return_value = CURL_FORMADD_OPTION_TWICE;
569 else {
570 current_form->showfilename = strdup(filename);
571 if(!current_form->showfilename)
572 return_value = CURL_FORMADD_MEMORY;
573 else
574 current_form->showfilename_alloc = TRUE;
575 }
576 break;
577 }
578 default:
579 return_value = CURL_FORMADD_UNKNOWN_OPTION;
580 break;
581 }
582 }
583
584 if(CURL_FORMADD_OK != return_value) {
585 /* On error, free allocated fields for all nodes of the FormInfo linked
586 list without deallocating nodes. List nodes are deallocated later on */
587 FormInfo *ptr;
588 for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
589 if(ptr->name_alloc) {
590 Curl_safefree(ptr->name);
591 ptr->name_alloc = FALSE;
592 }
593 if(ptr->value_alloc) {
594 Curl_safefree(ptr->value);
595 ptr->value_alloc = FALSE;
596 }
597 if(ptr->contenttype_alloc) {
598 Curl_safefree(ptr->contenttype);
599 ptr->contenttype_alloc = FALSE;
600 }
601 if(ptr->showfilename_alloc) {
602 Curl_safefree(ptr->showfilename);
603 ptr->showfilename_alloc = FALSE;
604 }
605 }
606 }
607
608 if(CURL_FORMADD_OK == return_value) {
609 /* go through the list, check for completeness and if everything is
610 * alright add the HttpPost item otherwise set return_value accordingly */
611
612 post = NULL;
613 for(form = first_form;
614 form != NULL;
615 form = form->more) {
616 if(((!form->name || !form->value) && !post) ||
617 ( (form->contentslength) &&
618 (form->flags & HTTPPOST_FILENAME) ) ||
619 ( (form->flags & HTTPPOST_FILENAME) &&
620 (form->flags & HTTPPOST_PTRCONTENTS) ) ||
621
622 ( (!form->buffer) &&
623 (form->flags & HTTPPOST_BUFFER) &&
624 (form->flags & HTTPPOST_PTRBUFFER) ) ||
625
626 ( (form->flags & HTTPPOST_READFILE) &&
627 (form->flags & HTTPPOST_PTRCONTENTS) )
628 ) {
629 return_value = CURL_FORMADD_INCOMPLETE;
630 break;
631 }
632 else {
633 if(((form->flags & HTTPPOST_FILENAME) ||
634 (form->flags & HTTPPOST_BUFFER)) &&
635 !form->contenttype) {
636 char *f = form->flags & HTTPPOST_BUFFER?
637 form->showfilename : form->value;
638
639 /* our contenttype is missing */
640 form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
641 if(!form->contenttype) {
642 return_value = CURL_FORMADD_MEMORY;
643 break;
644 }
645 form->contenttype_alloc = TRUE;
646 }
647 if(!(form->flags & HTTPPOST_PTRNAME) &&
648 (form == first_form) ) {
649 /* Note that there's small risk that form->name is NULL here if the
650 app passed in a bad combo, so we better check for that first. */
651 if(form->name) {
652 /* copy name (without strdup; possibly contains null characters) */
653 form->name = Curl_memdup(form->name, form->namelength?
654 form->namelength:
655 strlen(form->name)+1);
656 }
657 if(!form->name) {
658 return_value = CURL_FORMADD_MEMORY;
659 break;
660 }
661 form->name_alloc = TRUE;
662 }
663 if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
664 HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
665 HTTPPOST_CALLBACK)) && form->value) {
666 /* copy value (without strdup; possibly contains null characters) */
667 size_t clen = (size_t) form->contentslength;
668 if(!clen)
669 clen = strlen(form->value)+1;
670
671 form->value = Curl_memdup(form->value, clen);
672
673 if(!form->value) {
674 return_value = CURL_FORMADD_MEMORY;
675 break;
676 }
677 form->value_alloc = TRUE;
678 }
679 post = AddHttpPost(form->name, form->namelength,
680 form->value, form->contentslength,
681 form->buffer, form->bufferlength,
682 form->contenttype, form->flags,
683 form->contentheader, form->showfilename,
684 form->userp,
685 post, httppost,
686 last_post);
687
688 if(!post) {
689 return_value = CURL_FORMADD_MEMORY;
690 break;
691 }
692
693 if(form->contenttype)
694 prevtype = form->contenttype;
695 }
696 }
697 if(CURL_FORMADD_OK != return_value) {
698 /* On error, free allocated fields for nodes of the FormInfo linked
699 list which are not already owned by the httppost linked list
700 without deallocating nodes. List nodes are deallocated later on */
701 FormInfo *ptr;
702 for(ptr = form; ptr != NULL; ptr = ptr->more) {
703 if(ptr->name_alloc) {
704 Curl_safefree(ptr->name);
705 ptr->name_alloc = FALSE;
706 }
707 if(ptr->value_alloc) {
708 Curl_safefree(ptr->value);
709 ptr->value_alloc = FALSE;
710 }
711 if(ptr->contenttype_alloc) {
712 Curl_safefree(ptr->contenttype);
713 ptr->contenttype_alloc = FALSE;
714 }
715 if(ptr->showfilename_alloc) {
716 Curl_safefree(ptr->showfilename);
717 ptr->showfilename_alloc = FALSE;
718 }
719 }
720 }
721 }
722
723 /* Always deallocate FormInfo linked list nodes without touching node
724 fields given that these have either been deallocated or are owned
725 now by the httppost linked list */
726 while(first_form) {
727 FormInfo *ptr = first_form->more;
728 free(first_form);
729 first_form = ptr;
730 }
731
732 return return_value;
733 }
734
735 /*
736 * curl_formadd() is a public API to add a section to the multipart formpost.
737 *
738 * @unittest: 1308
739 */
740
curl_formadd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,...)741 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
742 struct curl_httppost **last_post,
743 ...)
744 {
745 va_list arg;
746 CURLFORMcode result;
747 va_start(arg, last_post);
748 result = FormAdd(httppost, last_post, arg);
749 va_end(arg);
750 return result;
751 }
752
753 #ifdef __VMS
754 #include <fabdef.h>
755 /*
756 * get_vms_file_size does what it takes to get the real size of the file
757 *
758 * For fixed files, find out the size of the EOF block and adjust.
759 *
760 * For all others, have to read the entire file in, discarding the contents.
761 * Most posted text files will be small, and binary files like zlib archives
762 * and CD/DVD images should be either a STREAM_LF format or a fixed format.
763 *
764 */
VmsRealFileSize(const char * name,const struct_stat * stat_buf)765 curl_off_t VmsRealFileSize(const char *name,
766 const struct_stat *stat_buf)
767 {
768 char buffer[8192];
769 curl_off_t count;
770 int ret_stat;
771 FILE * file;
772
773 file = fopen(name, FOPEN_READTEXT); /* VMS */
774 if(file == NULL)
775 return 0;
776
777 count = 0;
778 ret_stat = 1;
779 while(ret_stat > 0) {
780 ret_stat = fread(buffer, 1, sizeof(buffer), file);
781 if(ret_stat != 0)
782 count += ret_stat;
783 }
784 fclose(file);
785
786 return count;
787 }
788
789 /*
790 *
791 * VmsSpecialSize checks to see if the stat st_size can be trusted and
792 * if not to call a routine to get the correct size.
793 *
794 */
VmsSpecialSize(const char * name,const struct_stat * stat_buf)795 static curl_off_t VmsSpecialSize(const char *name,
796 const struct_stat *stat_buf)
797 {
798 switch(stat_buf->st_fab_rfm) {
799 case FAB$C_VAR:
800 case FAB$C_VFC:
801 return VmsRealFileSize(name, stat_buf);
802 break;
803 default:
804 return stat_buf->st_size;
805 }
806 }
807
808 #endif
809
810 #ifndef __VMS
811 #define filesize(name, stat_data) (stat_data.st_size)
812 #else
813 /* Getting the expected file size needs help on VMS */
814 #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
815 #endif
816
817 /*
818 * AddFormData() adds a chunk of data to the FormData linked list.
819 *
820 * size is incremented by the chunk length, unless it is NULL
821 */
AddFormData(struct FormData ** formp,enum formtype type,const void * line,curl_off_t length,curl_off_t * size)822 static CURLcode AddFormData(struct FormData **formp,
823 enum formtype type,
824 const void *line,
825 curl_off_t length,
826 curl_off_t *size)
827 {
828 struct FormData *newform;
829 char *alloc2 = NULL;
830 CURLcode result = CURLE_OK;
831 if(length < 0 || (size && *size < 0))
832 return CURLE_BAD_FUNCTION_ARGUMENT;
833
834 newform = malloc(sizeof(struct FormData));
835 if(!newform)
836 return CURLE_OUT_OF_MEMORY;
837 newform->next = NULL;
838
839 if(type <= FORM_CONTENT) {
840 /* we make it easier for plain strings: */
841 if(!length)
842 length = strlen((char *)line);
843 #if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T)
844 else if(length >= (curl_off_t)(size_t)-1) {
845 result = CURLE_BAD_FUNCTION_ARGUMENT;
846 goto error;
847 }
848 #endif
849 if(type != FORM_DATAMEM) {
850 newform->line = malloc((size_t)length+1);
851 if(!newform->line) {
852 result = CURLE_OUT_OF_MEMORY;
853 goto error;
854 }
855 alloc2 = newform->line;
856 memcpy(newform->line, line, (size_t)length);
857
858 /* zero terminate for easier debugging */
859 newform->line[(size_t)length]=0;
860 }
861 else {
862 newform->line = (char *)line;
863 type = FORM_DATA; /* in all other aspects this is just FORM_DATA */
864 }
865 newform->length = (size_t)length;
866 }
867 else
868 /* For callbacks and files we don't have any actual data so we just keep a
869 pointer to whatever this points to */
870 newform->line = (char *)line;
871
872 newform->type = type;
873
874 if(size) {
875 if(type != FORM_FILE)
876 /* for static content as well as callback data we add the size given
877 as input argument */
878 *size += length;
879 else {
880 /* Since this is a file to be uploaded here, add the size of the actual
881 file */
882 if(strcmp("-", newform->line)) {
883 struct_stat file;
884 if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
885 *size += filesize(newform->line, file);
886 else {
887 result = CURLE_BAD_FUNCTION_ARGUMENT;
888 goto error;
889 }
890 }
891 }
892 }
893
894 if(*formp) {
895 (*formp)->next = newform;
896 *formp = newform;
897 }
898 else
899 *formp = newform;
900
901 return CURLE_OK;
902 error:
903 if(newform)
904 free(newform);
905 if(alloc2)
906 free(alloc2);
907 return result;
908 }
909
910 /*
911 * AddFormDataf() adds printf()-style formatted data to the formdata chain.
912 */
913
AddFormDataf(struct FormData ** formp,curl_off_t * size,const char * fmt,...)914 static CURLcode AddFormDataf(struct FormData **formp,
915 curl_off_t *size,
916 const char *fmt, ...)
917 {
918 char *s;
919 CURLcode result;
920 va_list ap;
921 va_start(ap, fmt);
922 s = curl_mvaprintf(fmt, ap);
923 va_end(ap);
924
925 if(!s)
926 return CURLE_OUT_OF_MEMORY;
927
928 result = AddFormData(formp, FORM_DATAMEM, s, 0, size);
929 if(result)
930 free(s);
931
932 return result;
933 }
934
935 /*
936 * Curl_formclean() is used from http.c, this cleans a built FormData linked
937 * list
938 */
Curl_formclean(struct FormData ** form_ptr)939 void Curl_formclean(struct FormData **form_ptr)
940 {
941 struct FormData *next, *form;
942
943 form = *form_ptr;
944 if(!form)
945 return;
946
947 do {
948 next=form->next; /* the following form line */
949 if(form->type <= FORM_CONTENT)
950 free(form->line); /* free the line */
951 free(form); /* free the struct */
952
953 } while((form = next) != NULL); /* continue */
954
955 *form_ptr = NULL;
956 }
957
958 /*
959 * curl_formget()
960 * Serialize a curl_httppost struct.
961 * Returns 0 on success.
962 *
963 * @unittest: 1308
964 */
curl_formget(struct curl_httppost * form,void * arg,curl_formget_callback append)965 int curl_formget(struct curl_httppost *form, void *arg,
966 curl_formget_callback append)
967 {
968 CURLcode result;
969 curl_off_t size;
970 struct FormData *data, *ptr;
971
972 result = Curl_getformdata(NULL, &data, form, NULL, &size);
973 if(result)
974 return (int)result;
975
976 for(ptr = data; ptr; ptr = ptr->next) {
977 if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
978 char buffer[8192];
979 size_t nread;
980 struct Form temp;
981
982 Curl_FormInit(&temp, ptr);
983
984 do {
985 nread = readfromfile(&temp, buffer, sizeof(buffer));
986 if((nread == (size_t) -1) ||
987 (nread > sizeof(buffer)) ||
988 (nread != append(arg, buffer, nread))) {
989 if(temp.fp)
990 fclose(temp.fp);
991 Curl_formclean(&data);
992 return -1;
993 }
994 } while(nread);
995 }
996 else {
997 if(ptr->length != append(arg, ptr->line, ptr->length)) {
998 Curl_formclean(&data);
999 return -1;
1000 }
1001 }
1002 }
1003 Curl_formclean(&data);
1004 return 0;
1005 }
1006
1007 /*
1008 * curl_formfree() is an external function to free up a whole form post
1009 * chain
1010 */
curl_formfree(struct curl_httppost * form)1011 void curl_formfree(struct curl_httppost *form)
1012 {
1013 struct curl_httppost *next;
1014
1015 if(!form)
1016 /* no form to free, just get out of this */
1017 return;
1018
1019 do {
1020 next=form->next; /* the following form line */
1021
1022 /* recurse to sub-contents */
1023 curl_formfree(form->more);
1024
1025 if(!(form->flags & HTTPPOST_PTRNAME))
1026 free(form->name); /* free the name */
1027 if(!(form->flags &
1028 (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
1029 )
1030 free(form->contents); /* free the contents */
1031 free(form->contenttype); /* free the content type */
1032 free(form->showfilename); /* free the faked file name */
1033 free(form); /* free the struct */
1034
1035 } while((form = next) != NULL); /* continue */
1036 }
1037
1038 #ifndef HAVE_BASENAME
1039 /*
1040 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
1041 Edition)
1042
1043 The basename() function shall take the pathname pointed to by path and
1044 return a pointer to the final component of the pathname, deleting any
1045 trailing '/' characters.
1046
1047 If the string pointed to by path consists entirely of the '/' character,
1048 basename() shall return a pointer to the string "/". If the string pointed
1049 to by path is exactly "//", it is implementation-defined whether '/' or "//"
1050 is returned.
1051
1052 If path is a null pointer or points to an empty string, basename() shall
1053 return a pointer to the string ".".
1054
1055 The basename() function may modify the string pointed to by path, and may
1056 return a pointer to static storage that may then be overwritten by a
1057 subsequent call to basename().
1058
1059 The basename() function need not be reentrant. A function that is not
1060 required to be reentrant is not required to be thread-safe.
1061
1062 */
Curl_basename(char * path)1063 static char *Curl_basename(char *path)
1064 {
1065 /* Ignore all the details above for now and make a quick and simple
1066 implementaion here */
1067 char *s1;
1068 char *s2;
1069
1070 s1=strrchr(path, '/');
1071 s2=strrchr(path, '\\');
1072
1073 if(s1 && s2) {
1074 path = (s1 > s2? s1 : s2)+1;
1075 }
1076 else if(s1)
1077 path = s1 + 1;
1078 else if(s2)
1079 path = s2 + 1;
1080
1081 return path;
1082 }
1083 #endif
1084
strippath(const char * fullfile)1085 static char *strippath(const char *fullfile)
1086 {
1087 char *filename;
1088 char *base;
1089 filename = strdup(fullfile); /* duplicate since basename() may ruin the
1090 buffer it works on */
1091 if(!filename)
1092 return NULL;
1093 base = strdup(basename(filename));
1094
1095 free(filename); /* free temporary buffer */
1096
1097 return base; /* returns an allocated string or NULL ! */
1098 }
1099
formdata_add_filename(const struct curl_httppost * file,struct FormData ** form,curl_off_t * size)1100 static CURLcode formdata_add_filename(const struct curl_httppost *file,
1101 struct FormData **form,
1102 curl_off_t *size)
1103 {
1104 CURLcode result = CURLE_OK;
1105 char *filename = file->showfilename;
1106 char *filebasename = NULL;
1107 char *filename_escaped = NULL;
1108
1109 if(!filename) {
1110 filebasename = strippath(file->contents);
1111 if(!filebasename)
1112 return CURLE_OUT_OF_MEMORY;
1113 filename = filebasename;
1114 }
1115
1116 if(strchr(filename, '\\') || strchr(filename, '"')) {
1117 char *p0, *p1;
1118
1119 /* filename need be escaped */
1120 filename_escaped = malloc(strlen(filename)*2+1);
1121 if(!filename_escaped) {
1122 free(filebasename);
1123 return CURLE_OUT_OF_MEMORY;
1124 }
1125 p0 = filename_escaped;
1126 p1 = filename;
1127 while(*p1) {
1128 if(*p1 == '\\' || *p1 == '"')
1129 *p0++ = '\\';
1130 *p0++ = *p1++;
1131 }
1132 *p0 = '\0';
1133 filename = filename_escaped;
1134 }
1135 result = AddFormDataf(form, size,
1136 "; filename=\"%s\"",
1137 filename);
1138 free(filename_escaped);
1139 free(filebasename);
1140 return result;
1141 }
1142
1143 /*
1144 * Curl_getformdata() converts a linked list of "meta data" into a complete
1145 * (possibly huge) multipart formdata. The input list is in 'post', while the
1146 * output resulting linked lists gets stored in '*finalform'. *sizep will get
1147 * the total size of the whole POST.
1148 * A multipart/form_data content-type is built, unless a custom content-type
1149 * is passed in 'custom_content_type'.
1150 *
1151 * This function will not do a failf() for the potential memory failures but
1152 * should for all other errors it spots. Just note that this function MAY get
1153 * a NULL pointer in the 'data' argument.
1154 */
1155
Curl_getformdata(struct Curl_easy * data,struct FormData ** finalform,struct curl_httppost * post,const char * custom_content_type,curl_off_t * sizep)1156 CURLcode Curl_getformdata(struct Curl_easy *data,
1157 struct FormData **finalform,
1158 struct curl_httppost *post,
1159 const char *custom_content_type,
1160 curl_off_t *sizep)
1161 {
1162 struct FormData *form = NULL;
1163 struct FormData *firstform;
1164 struct curl_httppost *file;
1165 CURLcode result = CURLE_OK;
1166
1167 curl_off_t size = 0; /* support potentially ENORMOUS formposts */
1168 char *boundary;
1169 char *fileboundary = NULL;
1170 struct curl_slist *curList;
1171
1172 *finalform = NULL; /* default form is empty */
1173
1174 if(!post)
1175 return result; /* no input => no output! */
1176
1177 boundary = formboundary(data);
1178 if(!boundary)
1179 return CURLE_OUT_OF_MEMORY;
1180
1181 /* Make the first line of the output */
1182 result = AddFormDataf(&form, NULL,
1183 "%s; boundary=%s\r\n",
1184 custom_content_type?custom_content_type:
1185 "Content-Type: multipart/form-data",
1186 boundary);
1187
1188 if(result) {
1189 free(boundary);
1190 return result;
1191 }
1192 /* we DO NOT include that line in the total size of the POST, since it'll be
1193 part of the header! */
1194
1195 firstform = form;
1196
1197 do {
1198
1199 if(size) {
1200 result = AddFormDataf(&form, &size, "\r\n");
1201 if(result)
1202 break;
1203 }
1204
1205 /* boundary */
1206 result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
1207 if(result)
1208 break;
1209
1210 /* Maybe later this should be disabled when a custom_content_type is
1211 passed, since Content-Disposition is not meaningful for all multipart
1212 types.
1213 */
1214 result = AddFormDataf(&form, &size,
1215 "Content-Disposition: form-data; name=\"");
1216 if(result)
1217 break;
1218
1219 result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
1220 &size);
1221 if(result)
1222 break;
1223
1224 result = AddFormDataf(&form, &size, "\"");
1225 if(result)
1226 break;
1227
1228 if(post->more) {
1229 /* If used, this is a link to more file names, we must then do
1230 the magic to include several files with the same field name */
1231
1232 free(fileboundary);
1233 fileboundary = formboundary(data);
1234 if(!fileboundary) {
1235 result = CURLE_OUT_OF_MEMORY;
1236 break;
1237 }
1238
1239 result = AddFormDataf(&form, &size,
1240 "\r\nContent-Type: multipart/mixed;"
1241 " boundary=%s\r\n",
1242 fileboundary);
1243 if(result)
1244 break;
1245 }
1246
1247 file = post;
1248
1249 do {
1250
1251 /* If 'showfilename' is set, that is a faked name passed on to us
1252 to use to in the formpost. If that is not set, the actually used
1253 local file name should be added. */
1254
1255 if(post->more) {
1256 /* if multiple-file */
1257 result = AddFormDataf(&form, &size,
1258 "\r\n--%s\r\nContent-Disposition: "
1259 "attachment",
1260 fileboundary);
1261 if(result)
1262 break;
1263 result = formdata_add_filename(file, &form, &size);
1264 if(result)
1265 break;
1266 }
1267 else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
1268 HTTPPOST_CALLBACK)) {
1269 /* it should be noted that for the HTTPPOST_FILENAME and
1270 HTTPPOST_CALLBACK cases the ->showfilename struct member is always
1271 assigned at this point */
1272 if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
1273 result = formdata_add_filename(post, &form, &size);
1274 }
1275
1276 if(result)
1277 break;
1278 }
1279
1280 if(file->contenttype) {
1281 /* we have a specified type */
1282 result = AddFormDataf(&form, &size,
1283 "\r\nContent-Type: %s",
1284 file->contenttype);
1285 if(result)
1286 break;
1287 }
1288
1289 curList = file->contentheader;
1290 while(curList) {
1291 /* Process the additional headers specified for this form */
1292 result = AddFormDataf(&form, &size, "\r\n%s", curList->data);
1293 if(result)
1294 break;
1295 curList = curList->next;
1296 }
1297 if(result)
1298 break;
1299
1300 result = AddFormDataf(&form, &size, "\r\n\r\n");
1301 if(result)
1302 break;
1303
1304 if((post->flags & HTTPPOST_FILENAME) ||
1305 (post->flags & HTTPPOST_READFILE)) {
1306 /* we should include the contents from the specified file */
1307 FILE *fileread;
1308
1309 fileread = !strcmp("-", file->contents)?
1310 stdin:fopen(file->contents, "rb"); /* binary read for win32 */
1311
1312 /*
1313 * VMS: This only allows for stream files on VMS. Stream files are
1314 * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1315 * every record needs to have a \n appended & 1 added to SIZE
1316 */
1317
1318 if(fileread) {
1319 if(fileread != stdin) {
1320 /* close the file */
1321 fclose(fileread);
1322 /* add the file name only - for later reading from this */
1323 result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
1324 }
1325 else {
1326 /* When uploading from stdin, we can't know the size of the file,
1327 * thus must read the full file as before. We *could* use chunked
1328 * transfer-encoding, but that only works for HTTP 1.1 and we
1329 * can't be sure we work with such a server.
1330 */
1331 size_t nread;
1332 char buffer[512];
1333 while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
1334 result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
1335 if(result)
1336 break;
1337 }
1338 }
1339 }
1340 else {
1341 if(data)
1342 failf(data, "couldn't open file \"%s\"", file->contents);
1343 *finalform = NULL;
1344 result = CURLE_READ_ERROR;
1345 }
1346 }
1347 else if(post->flags & HTTPPOST_BUFFER)
1348 /* include contents of buffer */
1349 result = AddFormData(&form, FORM_CONTENT, post->buffer,
1350 post->bufferlength, &size);
1351 else if(post->flags & HTTPPOST_CALLBACK)
1352 /* the contents should be read with the callback and the size is set
1353 with the contentslength */
1354 result = AddFormData(&form, FORM_CALLBACK, post->userp,
1355 post->flags&CURL_HTTPPOST_LARGE?
1356 post->contentlen:post->contentslength, &size);
1357 else
1358 /* include the contents we got */
1359 result = AddFormData(&form, FORM_CONTENT, post->contents,
1360 post->flags&CURL_HTTPPOST_LARGE?
1361 post->contentlen:post->contentslength, &size);
1362 file = file->more;
1363 } while(file && !result); /* for each specified file for this field */
1364
1365 if(result)
1366 break;
1367
1368 if(post->more) {
1369 /* this was a multiple-file inclusion, make a termination file
1370 boundary: */
1371 result = AddFormDataf(&form, &size,
1372 "\r\n--%s--",
1373 fileboundary);
1374 if(result)
1375 break;
1376 }
1377
1378 } while((post = post->next) != NULL); /* for each field */
1379
1380 /* end-boundary for everything */
1381 if(!result)
1382 result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary);
1383
1384 if(result) {
1385 Curl_formclean(&firstform);
1386 free(fileboundary);
1387 free(boundary);
1388 return result;
1389 }
1390
1391 *sizep = size;
1392
1393 free(fileboundary);
1394 free(boundary);
1395
1396 *finalform = firstform;
1397
1398 return result;
1399 }
1400
1401 /*
1402 * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1403 * and resets the 'sent' counter.
1404 */
Curl_FormInit(struct Form * form,struct FormData * formdata)1405 int Curl_FormInit(struct Form *form, struct FormData *formdata)
1406 {
1407 if(!formdata)
1408 return 1; /* error */
1409
1410 form->data = formdata;
1411 form->sent = 0;
1412 form->fp = NULL;
1413 form->fread_func = ZERO_NULL;
1414
1415 return 0;
1416 }
1417
1418 #ifndef __VMS
1419 # define fopen_read fopen
1420 #else
1421 /*
1422 * vmsfopenread
1423 *
1424 * For upload to work as expected on VMS, different optional
1425 * parameters must be added to the fopen command based on
1426 * record format of the file.
1427 *
1428 */
1429 # define fopen_read vmsfopenread
vmsfopenread(const char * file,const char * mode)1430 static FILE * vmsfopenread(const char *file, const char *mode)
1431 {
1432 struct_stat statbuf;
1433 int result;
1434
1435 result = stat(file, &statbuf);
1436
1437 switch (statbuf.st_fab_rfm) {
1438 case FAB$C_VAR:
1439 case FAB$C_VFC:
1440 case FAB$C_STMCR:
1441 return fopen(file, FOPEN_READTEXT); /* VMS */
1442 break;
1443 default:
1444 return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
1445 }
1446 }
1447 #endif
1448
1449 /*
1450 * readfromfile()
1451 *
1452 * The read callback that this function may use can return a value larger than
1453 * 'size' (which then this function returns) that indicates a problem and it
1454 * must be properly dealt with
1455 */
readfromfile(struct Form * form,char * buffer,size_t size)1456 static size_t readfromfile(struct Form *form, char *buffer,
1457 size_t size)
1458 {
1459 size_t nread;
1460 bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
1461
1462 if(callback) {
1463 if(form->fread_func == ZERO_NULL)
1464 return 0;
1465 else
1466 nread = form->fread_func(buffer, 1, size, form->data->line);
1467 }
1468 else {
1469 if(!form->fp) {
1470 /* this file hasn't yet been opened */
1471 form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
1472 if(!form->fp)
1473 return (size_t)-1; /* failure */
1474 }
1475 nread = fread(buffer, 1, size, form->fp);
1476 }
1477 if(!nread) {
1478 /* this is the last chunk from the file, move on */
1479 if(form->fp) {
1480 fclose(form->fp);
1481 form->fp = NULL;
1482 }
1483 form->data = form->data->next;
1484 }
1485
1486 return nread;
1487 }
1488
1489 /*
1490 * Curl_FormReader() is the fread() emulation function that will be used to
1491 * deliver the formdata to the transfer loop and then sent away to the peer.
1492 */
Curl_FormReader(char * buffer,size_t size,size_t nitems,FILE * mydata)1493 size_t Curl_FormReader(char *buffer,
1494 size_t size,
1495 size_t nitems,
1496 FILE *mydata)
1497 {
1498 struct Form *form;
1499 size_t wantedsize;
1500 size_t gotsize = 0;
1501
1502 form=(struct Form *)mydata;
1503
1504 wantedsize = size * nitems;
1505
1506 if(!form->data)
1507 return 0; /* nothing, error, empty */
1508
1509 if((form->data->type == FORM_FILE) ||
1510 (form->data->type == FORM_CALLBACK)) {
1511 gotsize = readfromfile(form, buffer, wantedsize);
1512
1513 if(gotsize)
1514 /* If positive or -1, return. If zero, continue! */
1515 return gotsize;
1516 }
1517 do {
1518
1519 if((form->data->length - form->sent) > wantedsize - gotsize) {
1520
1521 memcpy(buffer + gotsize, form->data->line + form->sent,
1522 wantedsize - gotsize);
1523
1524 form->sent += wantedsize-gotsize;
1525
1526 return wantedsize;
1527 }
1528
1529 memcpy(buffer+gotsize,
1530 form->data->line + form->sent,
1531 (form->data->length - form->sent) );
1532 gotsize += form->data->length - form->sent;
1533
1534 form->sent = 0;
1535
1536 form->data = form->data->next; /* advance */
1537
1538 } while(form->data && (form->data->type < FORM_CALLBACK));
1539 /* If we got an empty line and we have more data, we proceed to the next
1540 line immediately to avoid returning zero before we've reached the end. */
1541
1542 return gotsize;
1543 }
1544
1545 /*
1546 * Curl_formpostheader() returns the first line of the formpost, the
1547 * request-header part (which is not part of the request-body like the rest of
1548 * the post).
1549 */
Curl_formpostheader(void * formp,size_t * len)1550 char *Curl_formpostheader(void *formp, size_t *len)
1551 {
1552 char *header;
1553 struct Form *form=(struct Form *)formp;
1554
1555 if(!form->data)
1556 return 0; /* nothing, ERROR! */
1557
1558 header = form->data->line;
1559 *len = form->data->length;
1560
1561 form->data = form->data->next; /* advance */
1562
1563 return header;
1564 }
1565
1566 /*
1567 * formboundary() creates a suitable boundary string and returns an allocated
1568 * one.
1569 */
formboundary(struct Curl_easy * data)1570 static char *formboundary(struct Curl_easy *data)
1571 {
1572 /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
1573 combinations */
1574 unsigned int rnd[2];
1575 CURLcode result = Curl_rand(data, &rnd[0], 2);
1576 if(result)
1577 return NULL;
1578
1579 return aprintf("------------------------%08x%08x", rnd[0], rnd[1]);
1580 }
1581
1582 #else /* CURL_DISABLE_HTTP */
curl_formadd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,...)1583 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
1584 struct curl_httppost **last_post,
1585 ...)
1586 {
1587 (void)httppost;
1588 (void)last_post;
1589 return CURL_FORMADD_DISABLED;
1590 }
1591
curl_formget(struct curl_httppost * form,void * arg,curl_formget_callback append)1592 int curl_formget(struct curl_httppost *form, void *arg,
1593 curl_formget_callback append)
1594 {
1595 (void) form;
1596 (void) arg;
1597 (void) append;
1598 return CURL_FORMADD_DISABLED;
1599 }
1600
curl_formfree(struct curl_httppost * form)1601 void curl_formfree(struct curl_httppost *form)
1602 {
1603 (void)form;
1604 /* does nothing HTTP is disabled */
1605 }
1606
1607
1608 #endif /* !defined(CURL_DISABLE_HTTP) */
1609