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