source: EcnlProtoTool/trunk/curl-7.57.0/lib/formdata.c@ 331

Last change on this file since 331 was 331, checked in by coas-nagasima, 6 years ago

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 30.6 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2017, 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 "mime.h"
36#include "non-ascii.h"
37#include "vtls/vtls.h"
38#include "strcase.h"
39#include "sendf.h"
40#include "strdup.h"
41#include "rand.h"
42/* The last 3 #include files should be in this order */
43#include "curl_printf.h"
44#include "curl_memory.h"
45#include "memdebug.h"
46
47
48/* What kind of Content-Type to use on un-specified files with unrecognized
49 extensions. */
50#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
51
52#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
53#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
54#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
55#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
56#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
57#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
58#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
59
60/***************************************************************************
61 *
62 * AddHttpPost()
63 *
64 * Adds a HttpPost structure to the list, if parent_post is given becomes
65 * a subpost of parent_post instead of a direct list element.
66 *
67 * Returns newly allocated HttpPost on success and NULL if malloc failed.
68 *
69 ***************************************************************************/
70static struct curl_httppost *
71AddHttpPost(char *name, size_t namelength,
72 char *value, curl_off_t contentslength,
73 char *buffer, size_t bufferlength,
74 char *contenttype,
75 long flags,
76 struct curl_slist *contentHeader,
77 char *showfilename, char *userp,
78 struct curl_httppost *parent_post,
79 struct curl_httppost **httppost,
80 struct curl_httppost **last_post)
81{
82 struct curl_httppost *post;
83 post = calloc(1, sizeof(struct curl_httppost));
84 if(post) {
85 post->name = name;
86 post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
87 post->contents = value;
88 post->contentlen = contentslength;
89 post->buffer = buffer;
90 post->bufferlength = (long)bufferlength;
91 post->contenttype = contenttype;
92 post->contentheader = contentHeader;
93 post->showfilename = showfilename;
94 post->userp = userp;
95 post->flags = flags | CURL_HTTPPOST_LARGE;
96 }
97 else
98 return NULL;
99
100 if(parent_post) {
101 /* now, point our 'more' to the original 'more' */
102 post->more = parent_post->more;
103
104 /* then move the original 'more' to point to ourselves */
105 parent_post->more = post;
106 }
107 else {
108 /* make the previous point to this */
109 if(*last_post)
110 (*last_post)->next = post;
111 else
112 (*httppost) = post;
113
114 (*last_post) = post;
115 }
116 return post;
117}
118
119/***************************************************************************
120 *
121 * AddFormInfo()
122 *
123 * Adds a FormInfo structure to the list presented by parent_form_info.
124 *
125 * Returns newly allocated FormInfo on success and NULL if malloc failed/
126 * parent_form_info is NULL.
127 *
128 ***************************************************************************/
129static FormInfo * AddFormInfo(char *value,
130 char *contenttype,
131 FormInfo *parent_form_info)
132{
133 FormInfo *form_info;
134 form_info = calloc(1, sizeof(struct FormInfo));
135 if(form_info) {
136 if(value)
137 form_info->value = value;
138 if(contenttype)
139 form_info->contenttype = contenttype;
140 form_info->flags = HTTPPOST_FILENAME;
141 }
142 else
143 return NULL;
144
145 if(parent_form_info) {
146 /* now, point our 'more' to the original 'more' */
147 form_info->more = parent_form_info->more;
148
149 /* then move the original 'more' to point to ourselves */
150 parent_form_info->more = form_info;
151 }
152
153 return form_info;
154}
155
156/***************************************************************************
157 *
158 * ContentTypeForFilename()
159 *
160 * Provides content type for filename if one of the known types (else
161 * (either the prevtype or the default is returned).
162 *
163 * Returns some valid contenttype for filename.
164 *
165 ***************************************************************************/
166static const char *ContentTypeForFilename(const char *filename,
167 const char *prevtype)
168{
169 const char *contenttype = NULL;
170 unsigned int i;
171 /*
172 * No type was specified, we scan through a few well-known
173 * extensions and pick the first we match!
174 */
175 struct ContentType {
176 const char *extension;
177 const char *type;
178 };
179 static const struct ContentType ctts[]={
180 {".gif", "image/gif"},
181 {".jpg", "image/jpeg"},
182 {".jpeg", "image/jpeg"},
183 {".txt", "text/plain"},
184 {".html", "text/html"},
185 {".xml", "application/xml"}
186 };
187
188 if(prevtype)
189 /* default to the previously set/used! */
190 contenttype = prevtype;
191 else
192 contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
193
194 if(filename) { /* in case a NULL was passed in */
195 for(i = 0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
196 if(strlen(filename) >= strlen(ctts[i].extension)) {
197 if(strcasecompare(filename +
198 strlen(filename) - strlen(ctts[i].extension),
199 ctts[i].extension)) {
200 contenttype = ctts[i].type;
201 break;
202 }
203 }
204 }
205 }
206 /* we have a contenttype by now */
207 return contenttype;
208}
209
210/***************************************************************************
211 *
212 * FormAdd()
213 *
214 * Stores a formpost parameter and builds the appropriate linked list.
215 *
216 * Has two principal functionalities: using files and byte arrays as
217 * post parts. Byte arrays are either copied or just the pointer is stored
218 * (as the user requests) while for files only the filename and not the
219 * content is stored.
220 *
221 * While you may have only one byte array for each name, multiple filenames
222 * are allowed (and because of this feature CURLFORM_END is needed after
223 * using CURLFORM_FILE).
224 *
225 * Examples:
226 *
227 * Simple name/value pair with copied contents:
228 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
229 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
230 *
231 * name/value pair where only the content pointer is remembered:
232 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
233 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
234 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
235 *
236 * storing a filename (CONTENTTYPE is optional!):
237 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
238 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
239 * CURLFORM_END);
240 *
241 * storing multiple filenames:
242 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
243 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
244 *
245 * Returns:
246 * CURL_FORMADD_OK on success
247 * CURL_FORMADD_MEMORY if the FormInfo allocation fails
248 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
249 * CURL_FORMADD_NULL if a null pointer was given for a char
250 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
251 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
252 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
253 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
254 * CURL_FORMADD_MEMORY if some allocation for string copying failed.
255 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
256 *
257 ***************************************************************************/
258
259static
260CURLFORMcode FormAdd(struct curl_httppost **httppost,
261 struct curl_httppost **last_post,
262 va_list params)
263{
264 FormInfo *first_form, *current_form, *form = NULL;
265 CURLFORMcode return_value = CURL_FORMADD_OK;
266 const char *prevtype = NULL;
267 struct curl_httppost *post = NULL;
268 CURLformoption option;
269 struct curl_forms *forms = NULL;
270 char *array_value = NULL; /* value read from an array */
271
272 /* This is a state variable, that if TRUE means that we're parsing an
273 array that we got passed to us. If FALSE we're parsing the input
274 va_list arguments. */
275 bool array_state = FALSE;
276
277 /*
278 * We need to allocate the first struct to fill in.
279 */
280 first_form = calloc(1, sizeof(struct FormInfo));
281 if(!first_form)
282 return CURL_FORMADD_MEMORY;
283
284 current_form = first_form;
285
286 /*
287 * Loop through all the options set. Break if we have an error to report.
288 */
289 while(return_value == CURL_FORMADD_OK) {
290
291 /* first see if we have more parts of the array param */
292 if(array_state && forms) {
293 /* get the upcoming option from the given array */
294 option = forms->option;
295 array_value = (char *)forms->value;
296
297 forms++; /* advance this to next entry */
298 if(CURLFORM_END == option) {
299 /* end of array state */
300 array_state = FALSE;
301 continue;
302 }
303 }
304 else {
305 /* This is not array-state, get next option */
306 option = va_arg(params, CURLformoption);
307 if(CURLFORM_END == option)
308 break;
309 }
310
311 switch(option) {
312 case CURLFORM_ARRAY:
313 if(array_state)
314 /* we don't support an array from within an array */
315 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
316 else {
317 forms = va_arg(params, struct curl_forms *);
318 if(forms)
319 array_state = TRUE;
320 else
321 return_value = CURL_FORMADD_NULL;
322 }
323 break;
324
325 /*
326 * Set the Name property.
327 */
328 case CURLFORM_PTRNAME:
329#ifdef CURL_DOES_CONVERSIONS
330 /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
331 * the data in all cases so that we'll have safe memory for the eventual
332 * conversion.
333 */
334#else
335 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
336#endif
337 /* FALLTHROUGH */
338 case CURLFORM_COPYNAME:
339 if(current_form->name)
340 return_value = CURL_FORMADD_OPTION_TWICE;
341 else {
342 char *name = array_state?
343 array_value:va_arg(params, char *);
344 if(name)
345 current_form->name = name; /* store for the moment */
346 else
347 return_value = CURL_FORMADD_NULL;
348 }
349 break;
350 case CURLFORM_NAMELENGTH:
351 if(current_form->namelength)
352 return_value = CURL_FORMADD_OPTION_TWICE;
353 else
354 current_form->namelength =
355 array_state?(size_t)array_value:(size_t)va_arg(params, long);
356 break;
357
358 /*
359 * Set the contents property.
360 */
361 case CURLFORM_PTRCONTENTS:
362 current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
363 case CURLFORM_COPYCONTENTS:
364 if(current_form->value)
365 return_value = CURL_FORMADD_OPTION_TWICE;
366 else {
367 char *value =
368 array_state?array_value:va_arg(params, char *);
369 if(value)
370 current_form->value = value; /* store for the moment */
371 else
372 return_value = CURL_FORMADD_NULL;
373 }
374 break;
375 case CURLFORM_CONTENTSLENGTH:
376 current_form->contentslength =
377 array_state?(size_t)array_value:(size_t)va_arg(params, long);
378 break;
379
380 case CURLFORM_CONTENTLEN:
381 current_form->flags |= CURL_HTTPPOST_LARGE;
382 current_form->contentslength =
383 array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
384 break;
385
386 /* Get contents from a given file name */
387 case CURLFORM_FILECONTENT:
388 if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
389 return_value = CURL_FORMADD_OPTION_TWICE;
390 else {
391 const char *filename = array_state?
392 array_value:va_arg(params, char *);
393 if(filename) {
394 current_form->value = strdup(filename);
395 if(!current_form->value)
396 return_value = CURL_FORMADD_MEMORY;
397 else {
398 current_form->flags |= HTTPPOST_READFILE;
399 current_form->value_alloc = TRUE;
400 }
401 }
402 else
403 return_value = CURL_FORMADD_NULL;
404 }
405 break;
406
407 /* We upload a file */
408 case CURLFORM_FILE:
409 {
410 const char *filename = array_state?array_value:
411 va_arg(params, char *);
412
413 if(current_form->value) {
414 if(current_form->flags & HTTPPOST_FILENAME) {
415 if(filename) {
416 char *fname = strdup(filename);
417 if(!fname)
418 return_value = CURL_FORMADD_MEMORY;
419 else {
420 form = AddFormInfo(fname, NULL, current_form);
421 if(!form) {
422 free(fname);
423 return_value = CURL_FORMADD_MEMORY;
424 }
425 else {
426 form->value_alloc = TRUE;
427 current_form = form;
428 form = NULL;
429 }
430 }
431 }
432 else
433 return_value = CURL_FORMADD_NULL;
434 }
435 else
436 return_value = CURL_FORMADD_OPTION_TWICE;
437 }
438 else {
439 if(filename) {
440 current_form->value = strdup(filename);
441 if(!current_form->value)
442 return_value = CURL_FORMADD_MEMORY;
443 else {
444 current_form->flags |= HTTPPOST_FILENAME;
445 current_form->value_alloc = TRUE;
446 }
447 }
448 else
449 return_value = CURL_FORMADD_NULL;
450 }
451 break;
452 }
453
454 case CURLFORM_BUFFERPTR:
455 current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
456 if(current_form->buffer)
457 return_value = CURL_FORMADD_OPTION_TWICE;
458 else {
459 char *buffer =
460 array_state?array_value:va_arg(params, char *);
461 if(buffer) {
462 current_form->buffer = buffer; /* store for the moment */
463 current_form->value = buffer; /* make it non-NULL to be accepted
464 as fine */
465 }
466 else
467 return_value = CURL_FORMADD_NULL;
468 }
469 break;
470
471 case CURLFORM_BUFFERLENGTH:
472 if(current_form->bufferlength)
473 return_value = CURL_FORMADD_OPTION_TWICE;
474 else
475 current_form->bufferlength =
476 array_state?(size_t)array_value:(size_t)va_arg(params, long);
477 break;
478
479 case CURLFORM_STREAM:
480 current_form->flags |= HTTPPOST_CALLBACK;
481 if(current_form->userp)
482 return_value = CURL_FORMADD_OPTION_TWICE;
483 else {
484 char *userp =
485 array_state?array_value:va_arg(params, char *);
486 if(userp) {
487 current_form->userp = userp;
488 current_form->value = userp; /* this isn't strictly true but we
489 derive a value from this later on
490 and we need this non-NULL to be
491 accepted as a fine form part */
492 }
493 else
494 return_value = CURL_FORMADD_NULL;
495 }
496 break;
497
498 case CURLFORM_CONTENTTYPE:
499 {
500 const char *contenttype =
501 array_state?array_value:va_arg(params, char *);
502 if(current_form->contenttype) {
503 if(current_form->flags & HTTPPOST_FILENAME) {
504 if(contenttype) {
505 char *type = strdup(contenttype);
506 if(!type)
507 return_value = CURL_FORMADD_MEMORY;
508 else {
509 form = AddFormInfo(NULL, type, current_form);
510 if(!form) {
511 free(type);
512 return_value = CURL_FORMADD_MEMORY;
513 }
514 else {
515 form->contenttype_alloc = TRUE;
516 current_form = form;
517 form = NULL;
518 }
519 }
520 }
521 else
522 return_value = CURL_FORMADD_NULL;
523 }
524 else
525 return_value = CURL_FORMADD_OPTION_TWICE;
526 }
527 else {
528 if(contenttype) {
529 current_form->contenttype = strdup(contenttype);
530 if(!current_form->contenttype)
531 return_value = CURL_FORMADD_MEMORY;
532 else
533 current_form->contenttype_alloc = TRUE;
534 }
535 else
536 return_value = CURL_FORMADD_NULL;
537 }
538 break;
539 }
540 case CURLFORM_CONTENTHEADER:
541 {
542 /* this "cast increases required alignment of target type" but
543 we consider it OK anyway */
544 struct curl_slist *list = array_state?
545 (struct curl_slist *)(void *)array_value:
546 va_arg(params, struct curl_slist *);
547
548 if(current_form->contentheader)
549 return_value = CURL_FORMADD_OPTION_TWICE;
550 else
551 current_form->contentheader = list;
552
553 break;
554 }
555 case CURLFORM_FILENAME:
556 case CURLFORM_BUFFER:
557 {
558 const char *filename = array_state?array_value:
559 va_arg(params, char *);
560 if(current_form->showfilename)
561 return_value = CURL_FORMADD_OPTION_TWICE;
562 else {
563 current_form->showfilename = strdup(filename);
564 if(!current_form->showfilename)
565 return_value = CURL_FORMADD_MEMORY;
566 else
567 current_form->showfilename_alloc = TRUE;
568 }
569 break;
570 }
571 default:
572 return_value = CURL_FORMADD_UNKNOWN_OPTION;
573 break;
574 }
575 }
576
577 if(CURL_FORMADD_OK != return_value) {
578 /* On error, free allocated fields for all nodes of the FormInfo linked
579 list without deallocating nodes. List nodes are deallocated later on */
580 FormInfo *ptr;
581 for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
582 if(ptr->name_alloc) {
583 Curl_safefree(ptr->name);
584 ptr->name_alloc = FALSE;
585 }
586 if(ptr->value_alloc) {
587 Curl_safefree(ptr->value);
588 ptr->value_alloc = FALSE;
589 }
590 if(ptr->contenttype_alloc) {
591 Curl_safefree(ptr->contenttype);
592 ptr->contenttype_alloc = FALSE;
593 }
594 if(ptr->showfilename_alloc) {
595 Curl_safefree(ptr->showfilename);
596 ptr->showfilename_alloc = FALSE;
597 }
598 }
599 }
600
601 if(CURL_FORMADD_OK == return_value) {
602 /* go through the list, check for completeness and if everything is
603 * alright add the HttpPost item otherwise set return_value accordingly */
604
605 post = NULL;
606 for(form = first_form;
607 form != NULL;
608 form = form->more) {
609 if(((!form->name || !form->value) && !post) ||
610 ( (form->contentslength) &&
611 (form->flags & HTTPPOST_FILENAME) ) ||
612 ( (form->flags & HTTPPOST_FILENAME) &&
613 (form->flags & HTTPPOST_PTRCONTENTS) ) ||
614
615 ( (!form->buffer) &&
616 (form->flags & HTTPPOST_BUFFER) &&
617 (form->flags & HTTPPOST_PTRBUFFER) ) ||
618
619 ( (form->flags & HTTPPOST_READFILE) &&
620 (form->flags & HTTPPOST_PTRCONTENTS) )
621 ) {
622 return_value = CURL_FORMADD_INCOMPLETE;
623 break;
624 }
625 if(((form->flags & HTTPPOST_FILENAME) ||
626 (form->flags & HTTPPOST_BUFFER)) &&
627 !form->contenttype) {
628 char *f = form->flags & HTTPPOST_BUFFER?
629 form->showfilename : form->value;
630
631 /* our contenttype is missing */
632 form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
633 if(!form->contenttype) {
634 return_value = CURL_FORMADD_MEMORY;
635 break;
636 }
637 form->contenttype_alloc = TRUE;
638 }
639 if(form->name && form->namelength) {
640 /* Name should not contain nul bytes. */
641 size_t i;
642 for(i = 0; i < form->namelength; i++)
643 if(!form->name[i]) {
644 return_value = CURL_FORMADD_NULL;
645 break;
646 }
647 if(return_value != CURL_FORMADD_OK)
648 break;
649 }
650 if(!(form->flags & HTTPPOST_PTRNAME) &&
651 (form == first_form) ) {
652 /* Note that there's small risk that form->name is NULL here if the
653 app passed in a bad combo, so we better check for that first. */
654 if(form->name) {
655 /* copy name (without strdup; possibly not nul-terminated) */
656 form->name = Curl_memdup(form->name, form->namelength?
657 form->namelength:
658 strlen(form->name) + 1);
659 }
660 if(!form->name) {
661 return_value = CURL_FORMADD_MEMORY;
662 break;
663 }
664 form->name_alloc = TRUE;
665 }
666 if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
667 HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
668 HTTPPOST_CALLBACK)) && form->value) {
669 /* copy value (without strdup; possibly contains null characters) */
670 size_t clen = (size_t) form->contentslength;
671 if(!clen)
672 clen = strlen(form->value) + 1;
673
674 form->value = Curl_memdup(form->value, clen);
675
676 if(!form->value) {
677 return_value = CURL_FORMADD_MEMORY;
678 break;
679 }
680 form->value_alloc = TRUE;
681 }
682 post = AddHttpPost(form->name, form->namelength,
683 form->value, form->contentslength,
684 form->buffer, form->bufferlength,
685 form->contenttype, form->flags,
686 form->contentheader, form->showfilename,
687 form->userp,
688 post, httppost,
689 last_post);
690
691 if(!post) {
692 return_value = CURL_FORMADD_MEMORY;
693 break;
694 }
695
696 if(form->contenttype)
697 prevtype = form->contenttype;
698 }
699 if(CURL_FORMADD_OK != return_value) {
700 /* On error, free allocated fields for nodes of the FormInfo linked
701 list which are not already owned by the httppost linked list
702 without deallocating nodes. List nodes are deallocated later on */
703 FormInfo *ptr;
704 for(ptr = form; ptr != NULL; ptr = ptr->more) {
705 if(ptr->name_alloc) {
706 Curl_safefree(ptr->name);
707 ptr->name_alloc = FALSE;
708 }
709 if(ptr->value_alloc) {
710 Curl_safefree(ptr->value);
711 ptr->value_alloc = FALSE;
712 }
713 if(ptr->contenttype_alloc) {
714 Curl_safefree(ptr->contenttype);
715 ptr->contenttype_alloc = FALSE;
716 }
717 if(ptr->showfilename_alloc) {
718 Curl_safefree(ptr->showfilename);
719 ptr->showfilename_alloc = FALSE;
720 }
721 }
722 }
723 }
724
725 /* Always deallocate FormInfo linked list nodes without touching node
726 fields given that these have either been deallocated or are owned
727 now by the httppost linked list */
728 while(first_form) {
729 FormInfo *ptr = first_form->more;
730 free(first_form);
731 first_form = ptr;
732 }
733
734 return return_value;
735}
736
737/*
738 * curl_formadd() is a public API to add a section to the multipart formpost.
739 *
740 * @unittest: 1308
741 */
742
743CURLFORMcode curl_formadd(struct curl_httppost **httppost,
744 struct curl_httppost **last_post,
745 ...)
746{
747 va_list arg;
748 CURLFORMcode result;
749 va_start(arg, last_post);
750 result = FormAdd(httppost, last_post, arg);
751 va_end(arg);
752 return result;
753}
754
755/*
756 * curl_formget()
757 * Serialize a curl_httppost struct.
758 * Returns 0 on success.
759 *
760 * @unittest: 1308
761 */
762int curl_formget(struct curl_httppost *form, void *arg,
763 curl_formget_callback append)
764{
765 CURLcode result;
766 curl_mimepart toppart;
767
768 Curl_mime_initpart(&toppart, NULL); /* default form is empty */
769 result = Curl_getformdata(NULL, &toppart, form, NULL);
770 if(!result)
771 result = Curl_mime_prepare_headers(&toppart, "multipart/form-data",
772 NULL, MIMESTRATEGY_FORM);
773
774 while(!result) {
775 char buffer[8192];
776 size_t nread = Curl_mime_read(buffer, 1, sizeof buffer, &toppart);
777
778 if(!nread)
779 break;
780
781 switch(nread) {
782 default:
783 if(append(arg, buffer, nread) != nread)
784 result = CURLE_READ_ERROR;
785 break;
786 case CURL_READFUNC_ABORT:
787 case CURL_READFUNC_PAUSE:
788 break;
789 }
790 }
791
792 Curl_mime_cleanpart(&toppart);
793 return (int) result;
794}
795
796/*
797 * curl_formfree() is an external function to free up a whole form post
798 * chain
799 */
800void curl_formfree(struct curl_httppost *form)
801{
802 struct curl_httppost *next;
803
804 if(!form)
805 /* no form to free, just get out of this */
806 return;
807
808 do {
809 next = form->next; /* the following form line */
810
811 /* recurse to sub-contents */
812 curl_formfree(form->more);
813
814 if(!(form->flags & HTTPPOST_PTRNAME))
815 free(form->name); /* free the name */
816 if(!(form->flags &
817 (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
818 )
819 free(form->contents); /* free the contents */
820 free(form->contenttype); /* free the content type */
821 free(form->showfilename); /* free the faked file name */
822 free(form); /* free the struct */
823 form = next;
824 } while(form); /* continue */
825}
826
827
828/* Set mime part name, taking care of non nul-terminated name string. */
829static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
830{
831 char *zname;
832 CURLcode res;
833
834 if(!name || !len)
835 return curl_mime_name(part, name);
836 zname = malloc(len + 1);
837 if(!zname)
838 return CURLE_OUT_OF_MEMORY;
839 memcpy(zname, name, len);
840 zname[len] = '\0';
841 res = curl_mime_name(part, zname);
842 free(zname);
843 return res;
844}
845
846/*
847 * Curl_getformdata() converts a linked list of "meta data" into a mime
848 * structure. The input list is in 'post', while the output is stored in
849 * mime part at '*finalform'.
850 *
851 * This function will not do a failf() for the potential memory failures but
852 * should for all other errors it spots. Just note that this function MAY get
853 * a NULL pointer in the 'data' argument.
854 */
855
856CURLcode Curl_getformdata(struct Curl_easy *data,
857 curl_mimepart *finalform,
858 struct curl_httppost *post,
859 curl_read_callback fread_func)
860{
861 CURLcode result = CURLE_OK;
862 curl_mime *form = NULL;
863 curl_mime *multipart;
864 curl_mimepart *part;
865 struct curl_httppost *file;
866
867 Curl_mime_cleanpart(finalform); /* default form is empty */
868
869 if(!post)
870 return result; /* no input => no output! */
871
872 form = curl_mime_init(data);
873 if(!form)
874 result = CURLE_OUT_OF_MEMORY;
875
876 if(!result)
877 result = curl_mime_subparts(finalform, form);
878
879 /* Process each top part. */
880 for(; !result && post; post = post->next) {
881 /* If we have more than a file here, create a mime subpart and fill it. */
882 multipart = form;
883 if(post->more) {
884 part = curl_mime_addpart(form);
885 if(!part)
886 result = CURLE_OUT_OF_MEMORY;
887 if(!result)
888 result = setname(part, post->name, post->namelength);
889 if(!result) {
890 multipart = curl_mime_init(data);
891 if(!multipart)
892 result = CURLE_OUT_OF_MEMORY;
893 }
894 if(!result)
895 result = curl_mime_subparts(part, multipart);
896 }
897
898 /* Generate all the part contents. */
899 for(file = post; !result && file; file = file->more) {
900 /* Create the part. */
901 part = curl_mime_addpart(multipart);
902 if(!part)
903 result = CURLE_OUT_OF_MEMORY;
904
905 /* Set the headers. */
906 if(!result)
907 result = curl_mime_headers(part, file->contentheader, 0);
908
909 /* Set the content type. */
910 if(!result && file->contenttype)
911 result = curl_mime_type(part, file->contenttype);
912
913 /* Set field name. */
914 if(!result && !post->more)
915 result = setname(part, post->name, post->namelength);
916
917 /* Process contents. */
918 if(!result) {
919 curl_off_t clen = post->contentslength;
920
921 if(post->flags & CURL_HTTPPOST_LARGE)
922 clen = post->contentlen;
923 if(!clen)
924 clen = -1;
925
926 if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
927 if(!strcmp(file->contents, "-")) {
928 /* There are a few cases where the code below won't work; in
929 particular, freopen(stdin) by the caller is not guaranteed
930 to result as expected. This feature has been kept for backward
931 compatibility: use of "-" pseudo file name should be avoided. */
932 result = curl_mime_data_cb(part, (curl_off_t) -1,
933 (curl_read_callback) fread,
934 (curl_seek_callback) fseek,
935 NULL, (void *) stdin);
936 }
937 else
938 result = curl_mime_filedata(part, file->contents);
939 if(!result && (post->flags & HTTPPOST_READFILE))
940 result = curl_mime_filename(part, NULL);
941 }
942 else if(post->flags & HTTPPOST_BUFFER)
943 result = curl_mime_data(part, post->buffer,
944 post->bufferlength? post->bufferlength: -1);
945 else if(post->flags & HTTPPOST_CALLBACK)
946 /* the contents should be read with the callback and the size is set
947 with the contentslength */
948 result = curl_mime_data_cb(part, clen,
949 fread_func, NULL, NULL, post->userp);
950 else {
951 result = curl_mime_data(part, post->contents, (ssize_t) clen);
952#ifdef CURL_DOES_CONVERSIONS
953 /* Convert textual contents now. */
954 if(!result && data && part->datasize)
955 result = Curl_convert_to_network(data, part->data, part->datasize);
956#endif
957 }
958 }
959
960 /* Set fake file name. */
961 if(!result && post->showfilename)
962 if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
963 HTTPPOST_CALLBACK)))
964 result = curl_mime_filename(part, post->showfilename);
965 }
966 }
967
968 if(result)
969 Curl_mime_cleanpart(finalform);
970
971 return result;
972}
973
974#else /* CURL_DISABLE_HTTP */
975CURLFORMcode curl_formadd(struct curl_httppost **httppost,
976 struct curl_httppost **last_post,
977 ...)
978{
979 (void)httppost;
980 (void)last_post;
981 return CURL_FORMADD_DISABLED;
982}
983
984int curl_formget(struct curl_httppost *form, void *arg,
985 curl_formget_callback append)
986{
987 (void) form;
988 (void) arg;
989 (void) append;
990 return CURL_FORMADD_DISABLED;
991}
992
993void curl_formfree(struct curl_httppost *form)
994{
995 (void)form;
996 /* does nothing HTTP is disabled */
997}
998
999
1000#endif /* !defined(CURL_DISABLE_HTTP) */
Note: See TracBrowser for help on using the repository browser.