formdata.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include "curl_setup.h"
  25. struct Curl_easy;
  26. #include "formdata.h"
  27. #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
  28. #include "urldata.h" /* for struct Curl_easy */
  29. #include "mime.h"
  30. #include "strdup.h"
  31. #include "bufref.h"
  32. #include "curlx/fopen.h"
  33. #define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
  34. #define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
  35. #define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
  36. #define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
  37. #define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
  38. #define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
  39. #define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
  40. /***************************************************************************
  41. *
  42. * AddHttpPost()
  43. *
  44. * Adds an HttpPost structure to the list, if parent_post is given becomes
  45. * a subpost of parent_post instead of a direct list element.
  46. *
  47. * Returns newly allocated HttpPost on success and NULL if malloc failed.
  48. *
  49. ***************************************************************************/
  50. static struct curl_httppost *AddHttpPost(struct FormInfo *src,
  51. struct curl_httppost *parent_post,
  52. struct curl_httppost **httppost,
  53. struct curl_httppost **last_post)
  54. {
  55. struct curl_httppost *post;
  56. size_t namelength = src->namelength;
  57. if(!namelength && Curl_bufref_ptr(&src->name))
  58. namelength = strlen(Curl_bufref_ptr(&src->name));
  59. if((src->bufferlength > LONG_MAX) || (namelength > LONG_MAX))
  60. /* avoid overflow in typecasts below */
  61. return NULL;
  62. post = curlx_calloc(1, sizeof(struct curl_httppost));
  63. if(post) {
  64. post->name = CURL_UNCONST(Curl_bufref_ptr(&src->name));
  65. post->namelength = (long)namelength;
  66. post->contents = CURL_UNCONST(Curl_bufref_ptr(&src->value));
  67. post->contentlen = src->contentslength;
  68. post->buffer = src->buffer;
  69. post->bufferlength = (long)src->bufferlength;
  70. post->contenttype = CURL_UNCONST(Curl_bufref_ptr(&src->contenttype));
  71. post->flags = src->flags | CURL_HTTPPOST_LARGE;
  72. post->contentheader = src->contentheader;
  73. post->showfilename = CURL_UNCONST(Curl_bufref_ptr(&src->showfilename));
  74. post->userp = src->userp;
  75. }
  76. else
  77. return NULL;
  78. if(parent_post) {
  79. /* now, point our 'more' to the original 'more' */
  80. post->more = parent_post->more;
  81. /* then move the original 'more' to point to ourselves */
  82. parent_post->more = post;
  83. }
  84. else {
  85. /* make the previous point to this */
  86. if(*last_post)
  87. (*last_post)->next = post;
  88. else
  89. (*httppost) = post;
  90. (*last_post) = post;
  91. }
  92. return post;
  93. }
  94. /* Allocate and initialize a new FormInfo structure. */
  95. static struct FormInfo *NewFormInfo(void)
  96. {
  97. struct FormInfo *form_info = curlx_calloc(1, sizeof(struct FormInfo));
  98. if(form_info) {
  99. Curl_bufref_init(&form_info->name);
  100. Curl_bufref_init(&form_info->value);
  101. Curl_bufref_init(&form_info->contenttype);
  102. Curl_bufref_init(&form_info->showfilename);
  103. }
  104. return form_info;
  105. }
  106. /* Replace the target field data by a dynamic copy of it. */
  107. static CURLcode FormInfoCopyField(struct bufref *field, size_t len)
  108. {
  109. const char *value = Curl_bufref_ptr(field);
  110. CURLcode result = CURLE_OK;
  111. if(value) {
  112. if(!len)
  113. len = strlen(value);
  114. result = Curl_bufref_memdup0(field, value, len);
  115. }
  116. return result;
  117. }
  118. /***************************************************************************
  119. *
  120. * AddFormInfo()
  121. *
  122. * Adds a FormInfo structure to the list presented by parent.
  123. *
  124. ***************************************************************************/
  125. static void AddFormInfo(struct FormInfo *form_info, struct FormInfo *parent)
  126. {
  127. form_info->flags |= HTTPPOST_FILENAME;
  128. if(parent) {
  129. /* now, point our 'more' to the original 'more' */
  130. form_info->more = parent->more;
  131. /* then move the original 'more' to point to ourselves */
  132. parent->more = form_info;
  133. }
  134. }
  135. static void free_formlist(struct FormInfo *ptr)
  136. {
  137. for(; ptr != NULL; ptr = ptr->more) {
  138. Curl_bufref_free(&ptr->name);
  139. Curl_bufref_free(&ptr->value);
  140. Curl_bufref_free(&ptr->contenttype);
  141. Curl_bufref_free(&ptr->showfilename);
  142. }
  143. }
  144. /***************************************************************************
  145. *
  146. * FormAdd()
  147. *
  148. * Stores a formpost parameter and builds the appropriate linked list.
  149. *
  150. * Has two principal functionalities: using files and byte arrays as
  151. * post parts. Byte arrays are either copied or just the pointer is stored
  152. * (as the user requests) while for files only the filename and not the
  153. * content is stored.
  154. *
  155. * While you may have only one byte array for each name, multiple filenames
  156. * are allowed (and because of this feature CURLFORM_END is needed after
  157. * using CURLFORM_FILE).
  158. *
  159. * Examples:
  160. *
  161. * Simple name/value pair with copied contents:
  162. * curl_formadd(&post, &last, CURLFORM_COPYNAME, "name",
  163. * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
  164. *
  165. * name/value pair where only the content pointer is remembered:
  166. * curl_formadd(&post, &last, CURLFORM_COPYNAME, "name",
  167. * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10,
  168. * CURLFORM_END);
  169. * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
  170. *
  171. * storing a filename (CONTENTTYPE is optional!):
  172. * curl_formadd(&post, &last, CURLFORM_COPYNAME, "name",
  173. * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
  174. * CURLFORM_END);
  175. *
  176. * storing multiple filenames:
  177. * curl_formadd(&post, &last, CURLFORM_COPYNAME, "name",
  178. * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2",
  179. * CURLFORM_END);
  180. *
  181. * Returns:
  182. * CURL_FORMADD_OK on success
  183. * CURL_FORMADD_MEMORY if the FormInfo allocation fails
  184. * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
  185. * CURL_FORMADD_NULL if a null pointer was given for a char
  186. * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
  187. * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
  188. * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
  189. * CURL_FORMADD_MEMORY if an HttpPost struct cannot be allocated
  190. * CURL_FORMADD_MEMORY if some allocation for string copying failed.
  191. * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
  192. *
  193. ***************************************************************************/
  194. static CURLFORMcode FormAddCheck(struct FormInfo *first_form,
  195. struct curl_httppost **httppost,
  196. struct curl_httppost **last_post)
  197. {
  198. const char *prevtype = NULL;
  199. struct FormInfo *form = NULL;
  200. struct curl_httppost *post = NULL;
  201. /* go through the list, check for completeness and if everything is
  202. * alright add the HttpPost item otherwise set retval accordingly */
  203. for(form = first_form; form != NULL; form = form->more) {
  204. const char *name = Curl_bufref_ptr(&form->name);
  205. if(((!name || !Curl_bufref_ptr(&form->value)) && !post) ||
  206. (form->contentslength &&
  207. (form->flags & HTTPPOST_FILENAME)) ||
  208. ((form->flags & HTTPPOST_FILENAME) &&
  209. (form->flags & HTTPPOST_PTRCONTENTS)) ||
  210. (!form->buffer &&
  211. (form->flags & HTTPPOST_BUFFER) &&
  212. (form->flags & HTTPPOST_PTRBUFFER)) ||
  213. ((form->flags & HTTPPOST_READFILE) &&
  214. (form->flags & HTTPPOST_PTRCONTENTS))
  215. ) {
  216. return CURL_FORMADD_INCOMPLETE;
  217. }
  218. if(((form->flags & HTTPPOST_FILENAME) ||
  219. (form->flags & HTTPPOST_BUFFER)) &&
  220. !Curl_bufref_ptr(&form->contenttype)) {
  221. const char *f = Curl_bufref_ptr((form->flags & HTTPPOST_BUFFER) ?
  222. &form->showfilename : &form->value);
  223. const char *type = Curl_mime_contenttype(f);
  224. if(!type)
  225. type = prevtype;
  226. if(!type)
  227. type = FILE_CONTENTTYPE_DEFAULT;
  228. /* our contenttype is missing */
  229. if(Curl_bufref_memdup0(&form->contenttype, type, strlen(type)))
  230. return CURL_FORMADD_MEMORY;
  231. }
  232. if(name && form->namelength) {
  233. if(memchr(name, 0, form->namelength))
  234. return CURL_FORMADD_NULL;
  235. }
  236. if(!(form->flags & HTTPPOST_PTRNAME)) {
  237. /* Note that there is small risk that form->name is NULL here if the app
  238. passed in a bad combo, so we check for that. */
  239. if(FormInfoCopyField(&form->name, form->namelength))
  240. return CURL_FORMADD_MEMORY;
  241. }
  242. if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
  243. HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
  244. HTTPPOST_CALLBACK))) {
  245. if(FormInfoCopyField(&form->value, (size_t)form->contentslength))
  246. return CURL_FORMADD_MEMORY;
  247. }
  248. post = AddHttpPost(form, post, httppost, last_post);
  249. if(!post)
  250. return CURL_FORMADD_MEMORY;
  251. if(Curl_bufref_ptr(&form->contenttype))
  252. prevtype = Curl_bufref_ptr(&form->contenttype);
  253. }
  254. return CURL_FORMADD_OK;
  255. }
  256. /* Shallow cleanup. Remove the newly created chain, the structs only and not
  257. the content they point to */
  258. static void free_chain(struct curl_httppost *c)
  259. {
  260. while(c) {
  261. struct curl_httppost *next = c->next;
  262. if(c->more)
  263. free_chain(c->more);
  264. curlx_free(c);
  265. c = next;
  266. }
  267. }
  268. static CURLFORMcode FormAdd(struct curl_httppost **httppost,
  269. struct curl_httppost **last_post, va_list params)
  270. {
  271. struct FormInfo *first_form, *curr, *form = NULL;
  272. CURLFORMcode retval = CURL_FORMADD_OK;
  273. CURLformoption option;
  274. struct curl_forms *forms = NULL;
  275. char *avalue = NULL;
  276. struct curl_httppost *newchain = NULL;
  277. struct curl_httppost *lastnode = NULL;
  278. #define form_ptr_arg(t) (forms ? (t)(void *)avalue : va_arg(params, t))
  279. #ifdef HAVE_STDINT_H
  280. #define form_int_arg(t) (forms ? (t)(uintptr_t)avalue : va_arg(params, t))
  281. #else
  282. #define form_int_arg(t) (forms ? (t)(void *)avalue : va_arg(params, t))
  283. #endif
  284. /*
  285. * We need to allocate the first struct to fill in.
  286. */
  287. first_form = NewFormInfo();
  288. if(!first_form)
  289. return CURL_FORMADD_MEMORY;
  290. curr = first_form;
  291. /*
  292. * Loop through all the options set. Break if we have an error to report.
  293. */
  294. while(retval == CURL_FORMADD_OK) {
  295. /* first see if we have more parts of the array param */
  296. if(forms) {
  297. /* get the upcoming option from the given array */
  298. option = forms->option;
  299. avalue = (char *)CURL_UNCONST(forms->value);
  300. forms++; /* advance this to next entry */
  301. if(CURLFORM_END == option) {
  302. /* end of array state */
  303. forms = NULL;
  304. continue;
  305. }
  306. }
  307. else {
  308. /* This is not array-state, get next option. This gets an 'int' with
  309. va_arg() because CURLformoption might be a smaller type than int and
  310. might cause compiler warnings and wrong behavior. */
  311. option = (CURLformoption)va_arg(params, int);
  312. if(CURLFORM_END == option)
  313. break;
  314. }
  315. switch(option) {
  316. case CURLFORM_ARRAY:
  317. if(forms)
  318. /* we do not support an array from within an array */
  319. retval = CURL_FORMADD_ILLEGAL_ARRAY;
  320. else {
  321. forms = va_arg(params, struct curl_forms *);
  322. if(!forms)
  323. retval = CURL_FORMADD_NULL;
  324. }
  325. break;
  326. /*
  327. * Set the Name property.
  328. */
  329. case CURLFORM_PTRNAME:
  330. curr->flags |= HTTPPOST_PTRNAME;
  331. FALLTHROUGH();
  332. case CURLFORM_COPYNAME:
  333. if(Curl_bufref_ptr(&curr->name))
  334. retval = CURL_FORMADD_OPTION_TWICE;
  335. else {
  336. avalue = form_ptr_arg(char *);
  337. if(avalue)
  338. Curl_bufref_set(&curr->name, avalue, 0, NULL); /* No copy yet. */
  339. else
  340. retval = CURL_FORMADD_NULL;
  341. }
  342. break;
  343. case CURLFORM_NAMELENGTH:
  344. if(curr->namelength)
  345. retval = CURL_FORMADD_OPTION_TWICE;
  346. else
  347. curr->namelength = (size_t)form_int_arg(long);
  348. break;
  349. /*
  350. * Set the contents property.
  351. */
  352. case CURLFORM_PTRCONTENTS:
  353. curr->flags |= HTTPPOST_PTRCONTENTS;
  354. FALLTHROUGH();
  355. case CURLFORM_COPYCONTENTS:
  356. if(Curl_bufref_ptr(&curr->value))
  357. retval = CURL_FORMADD_OPTION_TWICE;
  358. else {
  359. avalue = form_ptr_arg(char *);
  360. if(avalue)
  361. Curl_bufref_set(&curr->value, avalue, 0, NULL); /* No copy yet. */
  362. else
  363. retval = CURL_FORMADD_NULL;
  364. }
  365. break;
  366. case CURLFORM_CONTENTSLENGTH:
  367. curr->contentslength = (curl_off_t)(size_t)form_int_arg(long);
  368. break;
  369. case CURLFORM_CONTENTLEN:
  370. curr->flags |= CURL_HTTPPOST_LARGE;
  371. curr->contentslength = form_int_arg(curl_off_t);
  372. break;
  373. /* Get contents from a given filename */
  374. case CURLFORM_FILECONTENT:
  375. if(curr->flags & (HTTPPOST_PTRCONTENTS | HTTPPOST_READFILE))
  376. retval = CURL_FORMADD_OPTION_TWICE;
  377. else {
  378. avalue = form_ptr_arg(char *);
  379. if(avalue) {
  380. if(Curl_bufref_memdup0(&curr->value, avalue, strlen(avalue)))
  381. retval = CURL_FORMADD_MEMORY;
  382. else
  383. curr->flags |= HTTPPOST_READFILE;
  384. }
  385. else
  386. retval = CURL_FORMADD_NULL;
  387. }
  388. break;
  389. /* We upload a file */
  390. case CURLFORM_FILE:
  391. avalue = form_ptr_arg(char *);
  392. if(Curl_bufref_ptr(&curr->value)) {
  393. if(curr->flags & HTTPPOST_FILENAME) {
  394. if(avalue) {
  395. form = NewFormInfo();
  396. if(!form ||
  397. Curl_bufref_memdup0(&form->value, avalue, strlen(avalue))) {
  398. curlx_free(form);
  399. retval = CURL_FORMADD_MEMORY;
  400. }
  401. else {
  402. AddFormInfo(form, curr);
  403. curr = form;
  404. form = NULL;
  405. }
  406. }
  407. else
  408. retval = CURL_FORMADD_NULL;
  409. }
  410. else
  411. retval = CURL_FORMADD_OPTION_TWICE;
  412. }
  413. else {
  414. if(avalue) {
  415. if(Curl_bufref_memdup0(&curr->value, avalue, strlen(avalue)))
  416. retval = CURL_FORMADD_MEMORY;
  417. else
  418. curr->flags |= HTTPPOST_FILENAME;
  419. }
  420. else
  421. retval = CURL_FORMADD_NULL;
  422. }
  423. break;
  424. case CURLFORM_BUFFERPTR:
  425. curr->flags |= HTTPPOST_PTRBUFFER | HTTPPOST_BUFFER;
  426. if(curr->buffer)
  427. retval = CURL_FORMADD_OPTION_TWICE;
  428. else {
  429. avalue = form_ptr_arg(char *);
  430. if(avalue) {
  431. curr->buffer = avalue; /* store for the moment */
  432. /* Make value non-NULL to be accepted as fine */
  433. Curl_bufref_set(&curr->value, avalue, 0, NULL);
  434. }
  435. else
  436. retval = CURL_FORMADD_NULL;
  437. }
  438. break;
  439. case CURLFORM_BUFFERLENGTH:
  440. if(curr->bufferlength)
  441. retval = CURL_FORMADD_OPTION_TWICE;
  442. else
  443. curr->bufferlength = (size_t)form_int_arg(long);
  444. break;
  445. case CURLFORM_STREAM:
  446. curr->flags |= HTTPPOST_CALLBACK;
  447. if(curr->userp)
  448. retval = CURL_FORMADD_OPTION_TWICE;
  449. else {
  450. avalue = form_ptr_arg(char *);
  451. if(avalue) {
  452. curr->userp = avalue;
  453. /* The following line is not strictly true but we derive a value
  454. from this later on and we need this non-NULL to be accepted as
  455. a fine form part */
  456. Curl_bufref_set(&curr->value, avalue, 0, NULL);
  457. }
  458. else
  459. retval = CURL_FORMADD_NULL;
  460. }
  461. break;
  462. case CURLFORM_CONTENTTYPE:
  463. avalue = form_ptr_arg(char *);
  464. if(Curl_bufref_ptr(&curr->contenttype)) {
  465. if(curr->flags & HTTPPOST_FILENAME) {
  466. if(avalue) {
  467. form = NewFormInfo();
  468. if(!form || Curl_bufref_memdup0(&form->contenttype, avalue,
  469. strlen(avalue))) {
  470. curlx_free(form);
  471. retval = CURL_FORMADD_MEMORY;
  472. }
  473. else {
  474. AddFormInfo(form, curr);
  475. curr = form;
  476. form = NULL;
  477. }
  478. }
  479. else
  480. retval = CURL_FORMADD_NULL;
  481. }
  482. else
  483. retval = CURL_FORMADD_OPTION_TWICE;
  484. }
  485. else if(avalue) {
  486. if(Curl_bufref_memdup0(&curr->contenttype, avalue, strlen(avalue)))
  487. retval = CURL_FORMADD_MEMORY;
  488. }
  489. else
  490. retval = CURL_FORMADD_NULL;
  491. break;
  492. case CURLFORM_CONTENTHEADER: {
  493. /* this "cast increases required alignment of target type" but
  494. we consider it OK anyway */
  495. struct curl_slist *list = form_ptr_arg(struct curl_slist *);
  496. if(curr->contentheader)
  497. retval = CURL_FORMADD_OPTION_TWICE;
  498. else
  499. curr->contentheader = list;
  500. break;
  501. }
  502. case CURLFORM_FILENAME:
  503. case CURLFORM_BUFFER:
  504. avalue = form_ptr_arg(char *);
  505. if(Curl_bufref_ptr(&curr->showfilename))
  506. retval = CURL_FORMADD_OPTION_TWICE;
  507. else if(Curl_bufref_memdup0(&curr->showfilename, avalue, strlen(avalue)))
  508. retval = CURL_FORMADD_MEMORY;
  509. break;
  510. default:
  511. retval = CURL_FORMADD_UNKNOWN_OPTION;
  512. break;
  513. }
  514. }
  515. if(!retval)
  516. retval = FormAddCheck(first_form, &newchain, &lastnode);
  517. if(retval)
  518. /* On error, free allocated fields for all nodes of the FormInfo linked
  519. list without deallocating nodes. List nodes are deallocated later on */
  520. free_formlist(first_form);
  521. /* Always deallocate FormInfo linked list nodes without touching node
  522. fields given that these have either been deallocated or are owned
  523. now by the httppost linked list */
  524. while(first_form) {
  525. struct FormInfo *ptr = first_form->more;
  526. curlx_free(first_form);
  527. first_form = ptr;
  528. }
  529. if(!retval) {
  530. /* Only if all is fine, link the new chain into the provided list */
  531. if(*last_post)
  532. (*last_post)->next = newchain;
  533. else
  534. (*httppost) = newchain;
  535. (*last_post) = lastnode;
  536. }
  537. else
  538. free_chain(newchain);
  539. return retval;
  540. #undef form_ptr_arg
  541. #undef form_int_arg
  542. }
  543. /*
  544. * curl_formadd() is a public API to add a section to the multipart formpost.
  545. *
  546. * @unittest: 1308
  547. */
  548. CURLFORMcode curl_formadd(struct curl_httppost **httppost,
  549. struct curl_httppost **last_post, ...)
  550. {
  551. va_list arg;
  552. CURLFORMcode result;
  553. va_start(arg, last_post);
  554. result = FormAdd(httppost, last_post, arg);
  555. va_end(arg);
  556. return result;
  557. }
  558. /*
  559. * curl_formget()
  560. * Serialize a curl_httppost struct.
  561. * Returns 0 on success.
  562. *
  563. * @unittest: 1308
  564. */
  565. int curl_formget(struct curl_httppost *form, void *arg,
  566. curl_formget_callback append)
  567. {
  568. CURLcode result;
  569. curl_mimepart toppart;
  570. /* Validate callback is provided */
  571. if(!append)
  572. return (int)CURLE_BAD_FUNCTION_ARGUMENT;
  573. Curl_mime_initpart(&toppart); /* default form is empty */
  574. result = Curl_getformdata(NULL, &toppart, form, NULL);
  575. if(!result)
  576. result = Curl_mime_prepare_headers(NULL, &toppart, "multipart/form-data",
  577. NULL, MIMESTRATEGY_FORM);
  578. while(!result) {
  579. char buffer[8192];
  580. size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
  581. if(!nread)
  582. break;
  583. if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) {
  584. result = CURLE_READ_ERROR;
  585. if(nread == CURL_READFUNC_ABORT)
  586. result = CURLE_ABORTED_BY_CALLBACK;
  587. }
  588. }
  589. Curl_mime_cleanpart(&toppart);
  590. return (int)result;
  591. }
  592. /*
  593. * curl_formfree() is an external function to free up a whole form post
  594. * chain
  595. */
  596. void curl_formfree(struct curl_httppost *form)
  597. {
  598. struct curl_httppost *next;
  599. if(!form)
  600. /* no form to free, just get out of this */
  601. return;
  602. do {
  603. next = form->next; /* the following form line */
  604. /* recurse to sub-contents */
  605. curl_formfree(form->more);
  606. if(!(form->flags & HTTPPOST_PTRNAME))
  607. curlx_free(form->name); /* free the name */
  608. if(!(form->flags &
  609. (HTTPPOST_PTRCONTENTS | HTTPPOST_BUFFER | HTTPPOST_CALLBACK)))
  610. curlx_free(form->contents); /* free the contents */
  611. curlx_free(form->contenttype); /* free the content type */
  612. curlx_free(form->showfilename); /* free the faked filename */
  613. curlx_free(form); /* free the struct */
  614. form = next;
  615. } while(form); /* continue */
  616. }
  617. /* Set mime part name, taking care of non null-terminated name string. */
  618. static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
  619. {
  620. char *zname;
  621. CURLcode res;
  622. if(!name || !len)
  623. return curl_mime_name(part, name);
  624. zname = Curl_memdup0(name, len);
  625. if(!zname)
  626. return CURLE_OUT_OF_MEMORY;
  627. res = curl_mime_name(part, zname);
  628. curlx_free(zname);
  629. return res;
  630. }
  631. /*
  632. * Curl_getformdata() converts a linked list of "meta data" into a mime
  633. * structure. The input list is in 'post', while the output is stored in
  634. * mime part at '*finalform'.
  635. *
  636. * This function will not do a failf() for the potential memory failures but
  637. * should for all other errors it spots. Just note that this function MAY get
  638. * a NULL pointer in the 'data' argument.
  639. */
  640. CURLcode Curl_getformdata(CURL *data,
  641. curl_mimepart *finalform,
  642. struct curl_httppost *post,
  643. curl_read_callback fread_func)
  644. {
  645. CURLcode result = CURLE_OK;
  646. curl_mime *form = NULL;
  647. curl_mimepart *part;
  648. struct curl_httppost *file;
  649. Curl_mime_cleanpart(finalform); /* default form is empty */
  650. if(!post)
  651. return result; /* no input => no output! */
  652. form = curl_mime_init(data);
  653. if(!form)
  654. result = CURLE_OUT_OF_MEMORY;
  655. if(!result)
  656. result = curl_mime_subparts(finalform, form);
  657. /* Process each top part. */
  658. for(; !result && post; post = post->next) {
  659. /* If we have more than a file here, create a mime subpart and fill it. */
  660. curl_mime *multipart = form;
  661. if(post->more) {
  662. part = curl_mime_addpart(form);
  663. if(!part)
  664. result = CURLE_OUT_OF_MEMORY;
  665. if(!result)
  666. result = setname(part, post->name, post->namelength);
  667. if(!result) {
  668. multipart = curl_mime_init(data);
  669. if(!multipart)
  670. result = CURLE_OUT_OF_MEMORY;
  671. }
  672. if(!result)
  673. result = curl_mime_subparts(part, multipart);
  674. }
  675. /* Generate all the part contents. */
  676. for(file = post; !result && file; file = file->more) {
  677. /* Create the part. */
  678. part = curl_mime_addpart(multipart);
  679. if(!part)
  680. result = CURLE_OUT_OF_MEMORY;
  681. /* Set the headers. */
  682. if(!result)
  683. result = curl_mime_headers(part, file->contentheader, 0);
  684. /* Set the content type. */
  685. if(!result && file->contenttype)
  686. result = curl_mime_type(part, file->contenttype);
  687. /* Set field name. */
  688. if(!result && !post->more)
  689. result = setname(part, post->name, post->namelength);
  690. /* Process contents. */
  691. if(!result) {
  692. curl_off_t clen = post->contentslength;
  693. if(post->flags & CURL_HTTPPOST_LARGE)
  694. clen = post->contentlen;
  695. if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
  696. if(!strcmp(file->contents, "-")) {
  697. /* There are a few cases where the code below will not work; in
  698. particular, freopen(stdin) by the caller is not guaranteed
  699. to result as expected. This feature has been kept for backward
  700. compatibility: use of "-" pseudo filename should be avoided. */
  701. #if defined(__clang__) && __clang_major__ >= 16
  702. #pragma clang diagnostic push
  703. #pragma clang diagnostic ignored "-Wcast-function-type-strict"
  704. #endif
  705. result = curl_mime_data_cb(part, (curl_off_t)-1,
  706. (curl_read_callback)fread,
  707. curlx_fseek,
  708. NULL, (void *)stdin);
  709. #if defined(__clang__) && __clang_major__ >= 16
  710. #pragma clang diagnostic pop
  711. #endif
  712. }
  713. else
  714. result = curl_mime_filedata(part, file->contents);
  715. if(!result && (post->flags & HTTPPOST_READFILE))
  716. result = curl_mime_filename(part, NULL);
  717. }
  718. else if(post->flags & HTTPPOST_BUFFER)
  719. result = curl_mime_data(part, post->buffer,
  720. post->bufferlength ?
  721. post->bufferlength : -1);
  722. else if(post->flags & HTTPPOST_CALLBACK) {
  723. /* the contents should be read with the callback and the size is set
  724. with the contentslength */
  725. if(!clen)
  726. clen = -1;
  727. result = curl_mime_data_cb(part, clen,
  728. fread_func, NULL, NULL, post->userp);
  729. }
  730. else {
  731. size_t uclen;
  732. if(!clen)
  733. uclen = CURL_ZERO_TERMINATED;
  734. else
  735. uclen = (size_t)clen;
  736. result = curl_mime_data(part, post->contents, uclen);
  737. }
  738. }
  739. /* Set fake filename. */
  740. if(!result && post->showfilename)
  741. if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
  742. HTTPPOST_CALLBACK)))
  743. result = curl_mime_filename(part, post->showfilename);
  744. }
  745. }
  746. if(result)
  747. Curl_mime_cleanpart(finalform);
  748. return result;
  749. }
  750. #else
  751. /* if disabled */
  752. CURLFORMcode curl_formadd(struct curl_httppost **httppost,
  753. struct curl_httppost **last_post, ...)
  754. {
  755. (void)httppost;
  756. (void)last_post;
  757. return CURL_FORMADD_DISABLED;
  758. }
  759. int curl_formget(struct curl_httppost *form, void *arg,
  760. curl_formget_callback append)
  761. {
  762. (void)form;
  763. (void)arg;
  764. (void)append;
  765. return CURL_FORMADD_DISABLED;
  766. }
  767. void curl_formfree(struct curl_httppost *form)
  768. {
  769. (void)form;
  770. /* Nothing to do. */
  771. }
  772. #endif /* if disabled */