1
0

formdata.c 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2004, 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 http://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. * $Id$
  22. ***************************************************************************/
  23. /*
  24. Debug the form generator stand-alone by compiling this source file with:
  25. gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
  26. run the 'formdata' executable the output should end with:
  27. All Tests seem to have worked ...
  28. and the following parts should be there:
  29. Content-Disposition: form-data; name="simple_COPYCONTENTS"
  30. value for simple COPYCONTENTS
  31. Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE"
  32. Content-Type: image/gif
  33. value for COPYCONTENTS + CONTENTTYPE
  34. Content-Disposition: form-data; name="PRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH"
  35. vlue for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH
  36. (or you might see P^@RNAME and v^@lue at the start)
  37. Content-Disposition: form-data; name="simple_PTRCONTENTS"
  38. value for simple PTRCONTENTS
  39. Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH"
  40. vlue for PTRCONTENTS + CONTENTSLENGTH
  41. (or you might see v^@lue at the start)
  42. Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"
  43. Content-Type: text/plain
  44. vlue for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE
  45. (or you might see v^@lue at the start)
  46. Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h"
  47. Content-Type: text/html
  48. ...
  49. Content-Disposition: form-data; name="FILE1_+_FILE2"
  50. Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz
  51. ...
  52. Content-Disposition: attachment; filename="inet_ntoa_r.h"
  53. Content-Type: text/plain
  54. ...
  55. Content-Disposition: attachment; filename="Makefile.b32.resp"
  56. Content-Type: text/plain
  57. ...
  58. Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3"
  59. Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
  60. ...
  61. Content-Disposition: attachment; filename="inet_ntoa_r.h"
  62. Content-Type: text/plain
  63. ...
  64. Content-Disposition: attachment; filename="Makefile.b32.resp"
  65. Content-Type: text/plain
  66. ...
  67. Content-Disposition: attachment; filename="inet_ntoa_r.h"
  68. Content-Type: text/plain
  69. ...
  70. Content-Disposition: form-data; name="ARRAY: FILE1_+_FILE2_+_FILE3"
  71. Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
  72. ...
  73. Content-Disposition: attachment; filename="inet_ntoa_r.h"
  74. Content-Type: text/plain
  75. ...
  76. Content-Disposition: attachment; filename="Makefile.b32.resp"
  77. Content-Type: text/plain
  78. ...
  79. Content-Disposition: attachment; filename="inet_ntoa_r.h"
  80. Content-Type: text/plain
  81. ...
  82. Content-Disposition: form-data; name="FILECONTENT"
  83. ...
  84. */
  85. #include "setup.h"
  86. #include <curl/curl.h>
  87. /* Length of the random boundary string. */
  88. #define BOUNDARY_LENGTH 40
  89. #ifndef CURL_DISABLE_HTTP
  90. #include <stdio.h>
  91. #include <stdlib.h>
  92. #include <string.h>
  93. #include <stdarg.h>
  94. #include <time.h>
  95. #include <sys/stat.h>
  96. #include "formdata.h"
  97. #include "strequal.h"
  98. #include "curl_memory.h"
  99. #define _MPRINTF_REPLACE /* use our functions only */
  100. #include <curl/mprintf.h>
  101. /* The last #include file should be: */
  102. #include "memdebug.h"
  103. /* What kind of Content-Type to use on un-specified files with unrecognized
  104. extensions. */
  105. #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
  106. #define FORM_FILE_SEPARATOR ','
  107. #define FORM_TYPE_SEPARATOR ';'
  108. /***************************************************************************
  109. *
  110. * AddHttpPost()
  111. *
  112. * Adds a HttpPost structure to the list, if parent_post is given becomes
  113. * a subpost of parent_post instead of a direct list element.
  114. *
  115. * Returns newly allocated HttpPost on success and NULL if malloc failed.
  116. *
  117. ***************************************************************************/
  118. static struct curl_httppost *
  119. AddHttpPost(char * name, size_t namelength,
  120. char * value, size_t contentslength,
  121. char * buffer, size_t bufferlength,
  122. char *contenttype,
  123. long flags,
  124. struct curl_slist* contentHeader,
  125. char *showfilename,
  126. struct curl_httppost *parent_post,
  127. struct curl_httppost **httppost,
  128. struct curl_httppost **last_post)
  129. {
  130. struct curl_httppost *post;
  131. post = (struct curl_httppost *)calloc(sizeof(struct curl_httppost), 1);
  132. if(post) {
  133. post->name = name;
  134. post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
  135. post->contents = value;
  136. post->contentslength = (long)contentslength;
  137. post->buffer = buffer;
  138. post->bufferlength = (long)bufferlength;
  139. post->contenttype = contenttype;
  140. post->contentheader = contentHeader;
  141. post->showfilename = showfilename;
  142. post->flags = flags;
  143. }
  144. else
  145. return NULL;
  146. if (parent_post) {
  147. /* now, point our 'more' to the original 'more' */
  148. post->more = parent_post->more;
  149. /* then move the original 'more' to point to ourselves */
  150. parent_post->more = post;
  151. }
  152. else {
  153. /* make the previous point to this */
  154. if(*last_post)
  155. (*last_post)->next = post;
  156. else
  157. (*httppost) = post;
  158. (*last_post) = post;
  159. }
  160. return post;
  161. }
  162. /***************************************************************************
  163. *
  164. * AddFormInfo()
  165. *
  166. * Adds a FormInfo structure to the list presented by parent_form_info.
  167. *
  168. * Returns newly allocated FormInfo on success and NULL if malloc failed/
  169. * parent_form_info is NULL.
  170. *
  171. ***************************************************************************/
  172. static FormInfo * AddFormInfo(char *value,
  173. char *contenttype,
  174. FormInfo *parent_form_info)
  175. {
  176. FormInfo *form_info;
  177. form_info = (FormInfo *)malloc(sizeof(FormInfo));
  178. if(form_info) {
  179. memset(form_info, 0, sizeof(FormInfo));
  180. if (value)
  181. form_info->value = value;
  182. if (contenttype)
  183. form_info->contenttype = contenttype;
  184. form_info->flags = HTTPPOST_FILENAME;
  185. }
  186. else
  187. return NULL;
  188. if (parent_form_info) {
  189. /* now, point our 'more' to the original 'more' */
  190. form_info->more = parent_form_info->more;
  191. /* then move the original 'more' to point to ourselves */
  192. parent_form_info->more = form_info;
  193. }
  194. else
  195. return NULL;
  196. return form_info;
  197. }
  198. /***************************************************************************
  199. *
  200. * ContentTypeForFilename()
  201. *
  202. * Provides content type for filename if one of the known types (else
  203. * (either the prevtype or the default is returned).
  204. *
  205. * Returns some valid contenttype for filename.
  206. *
  207. ***************************************************************************/
  208. static const char * ContentTypeForFilename (const char *filename,
  209. const char *prevtype)
  210. {
  211. const char *contenttype;
  212. unsigned int i;
  213. /*
  214. * No type was specified, we scan through a few well-known
  215. * extensions and pick the first we match!
  216. */
  217. struct ContentType {
  218. const char *extension;
  219. const char *type;
  220. };
  221. static struct ContentType ctts[]={
  222. {".gif", "image/gif"},
  223. {".jpg", "image/jpeg"},
  224. {".jpeg", "image/jpeg"},
  225. {".txt", "text/plain"},
  226. {".html", "text/html"}
  227. };
  228. if(prevtype)
  229. /* default to the previously set/used! */
  230. contenttype = prevtype;
  231. else
  232. /* It seems RFC1867 defines no Content-Type to default to
  233. text/plain so we don't actually need to set this: */
  234. contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
  235. for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
  236. if(strlen(filename) >= strlen(ctts[i].extension)) {
  237. if(strequal(filename +
  238. strlen(filename) - strlen(ctts[i].extension),
  239. ctts[i].extension)) {
  240. contenttype = ctts[i].type;
  241. break;
  242. }
  243. }
  244. }
  245. /* we have a contenttype by now */
  246. return contenttype;
  247. }
  248. /***************************************************************************
  249. *
  250. * memdup()
  251. *
  252. * Copies the 'source' data to a newly allocated buffer buffer (that is
  253. * returned). Uses buffer_length if not null, else uses strlen to determine
  254. * the length of the buffer to be copied
  255. *
  256. * Returns the new pointer or NULL on failure.
  257. *
  258. ***************************************************************************/
  259. static char *memdup(const char *src, size_t buffer_length)
  260. {
  261. size_t length;
  262. bool add = FALSE;
  263. char *buffer;
  264. if (buffer_length)
  265. length = buffer_length;
  266. else {
  267. length = strlen(src);
  268. add = TRUE;
  269. }
  270. buffer = (char*)malloc(length+add);
  271. if (!buffer)
  272. return NULL; /* fail */
  273. memcpy(buffer, src, length);
  274. /* if length unknown do null termination */
  275. if (add)
  276. buffer[length] = '\0';
  277. return buffer;
  278. }
  279. /***************************************************************************
  280. *
  281. * FormAdd()
  282. *
  283. * Stores a formpost parameter and builds the appropriate linked list.
  284. *
  285. * Has two principal functionalities: using files and byte arrays as
  286. * post parts. Byte arrays are either copied or just the pointer is stored
  287. * (as the user requests) while for files only the filename and not the
  288. * content is stored.
  289. *
  290. * While you may have only one byte array for each name, multiple filenames
  291. * are allowed (and because of this feature CURLFORM_END is needed after
  292. * using CURLFORM_FILE).
  293. *
  294. * Examples:
  295. *
  296. * Simple name/value pair with copied contents:
  297. * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
  298. * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
  299. *
  300. * name/value pair where only the content pointer is remembered:
  301. * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
  302. * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
  303. * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
  304. *
  305. * storing a filename (CONTENTTYPE is optional!):
  306. * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
  307. * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
  308. * CURLFORM_END);
  309. *
  310. * storing multiple filenames:
  311. * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
  312. * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
  313. *
  314. * Returns:
  315. * CURL_FORMADD_OK on success
  316. * CURL_FORMADD_MEMORY if the FormInfo allocation fails
  317. * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
  318. * CURL_FORMADD_NULL if a null pointer was given for a char
  319. * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
  320. * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
  321. * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error)
  322. * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
  323. * CURL_FORMADD_MEMORY if some allocation for string copying failed.
  324. * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
  325. *
  326. ***************************************************************************/
  327. static
  328. CURLFORMcode FormAdd(struct curl_httppost **httppost,
  329. struct curl_httppost **last_post,
  330. va_list params)
  331. {
  332. FormInfo *first_form, *current_form, *form = NULL;
  333. CURLFORMcode return_value = CURL_FORMADD_OK;
  334. const char *prevtype = NULL;
  335. struct curl_httppost *post;
  336. CURLformoption option;
  337. struct curl_forms *forms = NULL;
  338. char *array_value=NULL; /* value read from an array */
  339. /* This is a state variable, that if TRUE means that we're parsing an
  340. array that we got passed to us. If FALSE we're parsing the input
  341. va_list arguments. */
  342. bool array_state = FALSE;
  343. /*
  344. * We need to allocate the first struct to fill in.
  345. */
  346. first_form = (FormInfo *)calloc(sizeof(struct FormInfo), 1);
  347. if(!first_form)
  348. return CURL_FORMADD_MEMORY;
  349. current_form = first_form;
  350. /*
  351. * Loop through all the options set. Break if we have an error to report.
  352. */
  353. while (return_value == CURL_FORMADD_OK) {
  354. /* first see if we have more parts of the array param */
  355. if ( array_state ) {
  356. /* get the upcoming option from the given array */
  357. option = forms->option;
  358. array_value = (char *)forms->value;
  359. forms++; /* advance this to next entry */
  360. if (CURLFORM_END == option) {
  361. /* end of array state */
  362. array_state = FALSE;
  363. continue;
  364. }
  365. }
  366. else {
  367. /* This is not array-state, get next option */
  368. option = va_arg(params, CURLformoption);
  369. if (CURLFORM_END == option)
  370. break;
  371. }
  372. switch (option) {
  373. case CURLFORM_ARRAY:
  374. if(array_state)
  375. /* we don't support an array from within an array */
  376. return_value = CURL_FORMADD_ILLEGAL_ARRAY;
  377. else {
  378. forms = va_arg(params, struct curl_forms *);
  379. if (forms)
  380. array_state = TRUE;
  381. else
  382. return_value = CURL_FORMADD_NULL;
  383. }
  384. break;
  385. /*
  386. * Set the Name property.
  387. */
  388. case CURLFORM_PTRNAME:
  389. current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
  390. case CURLFORM_COPYNAME:
  391. if (current_form->name)
  392. return_value = CURL_FORMADD_OPTION_TWICE;
  393. else {
  394. char *name = array_state?
  395. array_value:va_arg(params, char *);
  396. if (name)
  397. current_form->name = name; /* store for the moment */
  398. else
  399. return_value = CURL_FORMADD_NULL;
  400. }
  401. break;
  402. case CURLFORM_NAMELENGTH:
  403. if (current_form->namelength)
  404. return_value = CURL_FORMADD_OPTION_TWICE;
  405. else
  406. current_form->namelength =
  407. array_state?(long)array_value:va_arg(params, long);
  408. break;
  409. /*
  410. * Set the contents property.
  411. */
  412. case CURLFORM_PTRCONTENTS:
  413. current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
  414. case CURLFORM_COPYCONTENTS:
  415. if (current_form->value)
  416. return_value = CURL_FORMADD_OPTION_TWICE;
  417. else {
  418. char *value =
  419. array_state?array_value:va_arg(params, char *);
  420. if (value)
  421. current_form->value = value; /* store for the moment */
  422. else
  423. return_value = CURL_FORMADD_NULL;
  424. }
  425. break;
  426. case CURLFORM_CONTENTSLENGTH:
  427. if (current_form->contentslength)
  428. return_value = CURL_FORMADD_OPTION_TWICE;
  429. else
  430. current_form->contentslength =
  431. array_state?(long)array_value:va_arg(params, long);
  432. break;
  433. /* Get contents from a given file name */
  434. case CURLFORM_FILECONTENT:
  435. if (current_form->flags != 0)
  436. return_value = CURL_FORMADD_OPTION_TWICE;
  437. else {
  438. char *filename = array_state?
  439. array_value:va_arg(params, char *);
  440. if (filename) {
  441. current_form->value = strdup(filename);
  442. if(!current_form->value)
  443. return_value = CURL_FORMADD_MEMORY;
  444. else {
  445. current_form->flags |= HTTPPOST_READFILE;
  446. current_form->value_alloc = TRUE;
  447. }
  448. }
  449. else
  450. return_value = CURL_FORMADD_NULL;
  451. }
  452. break;
  453. /* We upload a file */
  454. case CURLFORM_FILE:
  455. {
  456. char *filename = array_state?array_value:
  457. va_arg(params, char *);
  458. if (current_form->value) {
  459. if (current_form->flags & HTTPPOST_FILENAME) {
  460. if (filename) {
  461. if (!(current_form = AddFormInfo(strdup(filename),
  462. NULL, current_form)))
  463. return_value = CURL_FORMADD_MEMORY;
  464. }
  465. else
  466. return_value = CURL_FORMADD_NULL;
  467. }
  468. else
  469. return_value = CURL_FORMADD_OPTION_TWICE;
  470. }
  471. else {
  472. if (filename) {
  473. current_form->value = strdup(filename);
  474. if(!current_form->value)
  475. return_value = CURL_FORMADD_MEMORY;
  476. else {
  477. current_form->flags |= HTTPPOST_FILENAME;
  478. current_form->value_alloc = TRUE;
  479. }
  480. }
  481. else
  482. return_value = CURL_FORMADD_NULL;
  483. }
  484. break;
  485. }
  486. case CURLFORM_BUFFER:
  487. {
  488. char *filename = array_state?array_value:
  489. va_arg(params, char *);
  490. if (current_form->value) {
  491. if (current_form->flags & HTTPPOST_BUFFER) {
  492. if (filename) {
  493. if (!(current_form = AddFormInfo(strdup(filename),
  494. NULL, current_form)))
  495. return_value = CURL_FORMADD_MEMORY;
  496. }
  497. else
  498. return_value = CURL_FORMADD_NULL;
  499. }
  500. else
  501. return_value = CURL_FORMADD_OPTION_TWICE;
  502. }
  503. else {
  504. if (filename) {
  505. current_form->value = strdup(filename);
  506. if(!current_form->value)
  507. return_value = CURL_FORMADD_MEMORY;
  508. }
  509. else
  510. return_value = CURL_FORMADD_NULL;
  511. current_form->flags |= HTTPPOST_BUFFER;
  512. }
  513. break;
  514. }
  515. case CURLFORM_BUFFERPTR:
  516. current_form->flags |= HTTPPOST_PTRBUFFER;
  517. if (current_form->buffer)
  518. return_value = CURL_FORMADD_OPTION_TWICE;
  519. else {
  520. char *buffer =
  521. array_state?array_value:va_arg(params, char *);
  522. if (buffer)
  523. current_form->buffer = buffer; /* store for the moment */
  524. else
  525. return_value = CURL_FORMADD_NULL;
  526. }
  527. break;
  528. case CURLFORM_BUFFERLENGTH:
  529. if (current_form->bufferlength)
  530. return_value = CURL_FORMADD_OPTION_TWICE;
  531. else
  532. current_form->bufferlength =
  533. array_state?(long)array_value:va_arg(params, long);
  534. break;
  535. case CURLFORM_CONTENTTYPE:
  536. {
  537. char *contenttype =
  538. array_state?array_value:va_arg(params, char *);
  539. if (current_form->contenttype) {
  540. if (current_form->flags & HTTPPOST_FILENAME) {
  541. if (contenttype) {
  542. if (!(current_form = AddFormInfo(NULL,
  543. strdup(contenttype),
  544. current_form)))
  545. return_value = CURL_FORMADD_MEMORY;
  546. }
  547. else
  548. return_value = CURL_FORMADD_NULL;
  549. }
  550. else
  551. return_value = CURL_FORMADD_OPTION_TWICE;
  552. }
  553. else {
  554. if (contenttype) {
  555. current_form->contenttype = strdup(contenttype);
  556. if(!current_form->contenttype)
  557. return_value = CURL_FORMADD_MEMORY;
  558. else
  559. current_form->contenttype_alloc = TRUE;
  560. }
  561. else
  562. return_value = CURL_FORMADD_NULL;
  563. }
  564. break;
  565. }
  566. case CURLFORM_CONTENTHEADER:
  567. {
  568. /* this "cast increases required alignment of target type" but
  569. we consider it OK anyway */
  570. struct curl_slist* list = 0;
  571. if ( array_state )
  572. {
  573. memcpy(&list, &array_value, sizeof(struct curl_slist*));
  574. }
  575. else
  576. {
  577. list = va_arg(params, struct curl_slist*);
  578. }
  579. if( current_form->contentheader )
  580. return_value = CURL_FORMADD_OPTION_TWICE;
  581. else
  582. current_form->contentheader = list;
  583. break;
  584. }
  585. case CURLFORM_FILENAME:
  586. {
  587. char *filename = array_state?array_value:
  588. va_arg(params, char *);
  589. if( current_form->showfilename )
  590. return_value = CURL_FORMADD_OPTION_TWICE;
  591. else {
  592. current_form->showfilename = strdup(filename);
  593. if(!current_form->showfilename)
  594. return_value = CURL_FORMADD_MEMORY;
  595. else
  596. current_form->showfilename_alloc = TRUE;
  597. }
  598. break;
  599. }
  600. default:
  601. return_value = CURL_FORMADD_UNKNOWN_OPTION;
  602. }
  603. }
  604. if(CURL_FORMADD_OK == return_value) {
  605. /* go through the list, check for copleteness and if everything is
  606. * alright add the HttpPost item otherwise set return_value accordingly */
  607. post = NULL;
  608. for(form = first_form;
  609. form != NULL;
  610. form = form->more) {
  611. if ( ((!form->name || !form->value) && !post) ||
  612. ( (form->contentslength) &&
  613. (form->flags & HTTPPOST_FILENAME) ) ||
  614. ( (form->flags & HTTPPOST_FILENAME) &&
  615. (form->flags & HTTPPOST_PTRCONTENTS) ) ||
  616. ( (!form->buffer) &&
  617. (form->flags & HTTPPOST_BUFFER) &&
  618. (form->flags & HTTPPOST_PTRBUFFER) ) ||
  619. ( (form->flags & HTTPPOST_READFILE) &&
  620. (form->flags & HTTPPOST_PTRCONTENTS) )
  621. ) {
  622. return_value = CURL_FORMADD_INCOMPLETE;
  623. break;
  624. }
  625. else {
  626. if ( ((form->flags & HTTPPOST_FILENAME) ||
  627. (form->flags & HTTPPOST_BUFFER)) &&
  628. !form->contenttype ) {
  629. /* our contenttype is missing */
  630. form->contenttype
  631. = strdup(ContentTypeForFilename(form->value, prevtype));
  632. if(!form->contenttype) {
  633. return_value = CURL_FORMADD_MEMORY;
  634. break;
  635. }
  636. form->contenttype_alloc = TRUE;
  637. }
  638. if ( !(form->flags & HTTPPOST_PTRNAME) &&
  639. (form == first_form) ) {
  640. /* copy name (without strdup; possibly contains null characters) */
  641. form->name = memdup(form->name, form->namelength);
  642. if (!form->name) {
  643. return_value = CURL_FORMADD_MEMORY;
  644. break;
  645. }
  646. form->name_alloc = TRUE;
  647. }
  648. if ( !(form->flags & HTTPPOST_FILENAME) &&
  649. !(form->flags & HTTPPOST_READFILE) &&
  650. !(form->flags & HTTPPOST_PTRCONTENTS) &&
  651. !(form->flags & HTTPPOST_PTRBUFFER) ) {
  652. /* copy value (without strdup; possibly contains null characters) */
  653. form->value = memdup(form->value, form->contentslength);
  654. if (!form->value) {
  655. return_value = CURL_FORMADD_MEMORY;
  656. break;
  657. }
  658. form->value_alloc = TRUE;
  659. }
  660. post = AddHttpPost(form->name, form->namelength,
  661. form->value, form->contentslength,
  662. form->buffer, form->bufferlength,
  663. form->contenttype, form->flags,
  664. form->contentheader, form->showfilename,
  665. post, httppost,
  666. last_post);
  667. if(!post) {
  668. return_value = CURL_FORMADD_MEMORY;
  669. break;
  670. }
  671. if (form->contenttype)
  672. prevtype = form->contenttype;
  673. }
  674. }
  675. }
  676. if(return_value) {
  677. /* we return on error, free possibly allocated fields */
  678. if(!form)
  679. form = current_form;
  680. if(form) {
  681. if(form->name_alloc)
  682. free(form->name);
  683. if(form->value_alloc)
  684. free(form->value);
  685. if(form->contenttype_alloc)
  686. free(form->contenttype);
  687. if(form->showfilename_alloc)
  688. free(form->showfilename);
  689. }
  690. }
  691. /* always delete the allocated memory before returning */
  692. form = first_form;
  693. while (form != NULL) {
  694. FormInfo *delete_form;
  695. delete_form = form;
  696. form = form->more;
  697. free (delete_form);
  698. }
  699. return return_value;
  700. }
  701. /*
  702. * curl_formadd() is a public API to add a section to the multipart formpost.
  703. */
  704. CURLFORMcode curl_formadd(struct curl_httppost **httppost,
  705. struct curl_httppost **last_post,
  706. ...)
  707. {
  708. va_list arg;
  709. CURLFORMcode result;
  710. va_start(arg, last_post);
  711. result = FormAdd(httppost, last_post, arg);
  712. va_end(arg);
  713. return result;
  714. }
  715. /*
  716. * AddFormData() adds a chunk of data to the FormData linked list.
  717. *
  718. * size is incremented by the chunk length, unless it is NULL
  719. */
  720. static CURLcode AddFormData(struct FormData **formp,
  721. enum formtype type,
  722. const void *line,
  723. size_t length,
  724. curl_off_t *size)
  725. {
  726. struct FormData *newform = (struct FormData *)
  727. malloc(sizeof(struct FormData));
  728. if (!newform)
  729. return CURLE_OUT_OF_MEMORY;
  730. newform->next = NULL;
  731. /* we make it easier for plain strings: */
  732. if(!length)
  733. length = strlen((char *)line);
  734. newform->line = (char *)malloc(length+1);
  735. if (!newform->line) {
  736. free(newform);
  737. return CURLE_OUT_OF_MEMORY;
  738. }
  739. memcpy(newform->line, line, length);
  740. newform->length = length;
  741. newform->line[length]=0; /* zero terminate for easier debugging */
  742. newform->type = type;
  743. if(*formp) {
  744. (*formp)->next = newform;
  745. *formp = newform;
  746. }
  747. else
  748. *formp = newform;
  749. if (size) {
  750. if(type == FORM_DATA)
  751. *size += length;
  752. else {
  753. /* Since this is a file to be uploaded here, add the size of the actual
  754. file */
  755. if(!strequal("-", newform->line)) {
  756. struct stat file;
  757. if(!stat(newform->line, &file)) {
  758. *size += file.st_size;
  759. }
  760. }
  761. }
  762. }
  763. return CURLE_OK;
  764. }
  765. /*
  766. * AddFormDataf() adds printf()-style formatted data to the formdata chain.
  767. */
  768. static CURLcode AddFormDataf(struct FormData **formp,
  769. curl_off_t *size,
  770. const char *fmt, ...)
  771. {
  772. char s[4096];
  773. va_list ap;
  774. va_start(ap, fmt);
  775. vsnprintf(s, sizeof(s), fmt, ap);
  776. va_end(ap);
  777. return AddFormData(formp, FORM_DATA, s, 0, size);
  778. }
  779. /*
  780. * Curl_formclean() is used from http.c, this cleans a built FormData linked
  781. * list
  782. */
  783. void Curl_formclean(struct FormData *form)
  784. {
  785. struct FormData *next;
  786. if(!form)
  787. return;
  788. do {
  789. next=form->next; /* the following form line */
  790. free(form->line); /* free the line */
  791. free(form); /* free the struct */
  792. } while((form=next)); /* continue */
  793. }
  794. /*
  795. * curl_formfree() is an external function to free up a whole form post
  796. * chain
  797. */
  798. void curl_formfree(struct curl_httppost *form)
  799. {
  800. struct curl_httppost *next;
  801. if(!form)
  802. /* no form to free, just get out of this */
  803. return;
  804. do {
  805. next=form->next; /* the following form line */
  806. /* recurse to sub-contents */
  807. if(form->more)
  808. curl_formfree(form->more);
  809. if( !(form->flags & HTTPPOST_PTRNAME) && form->name)
  810. free(form->name); /* free the name */
  811. if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents)
  812. free(form->contents); /* free the contents */
  813. if(form->contenttype)
  814. free(form->contenttype); /* free the content type */
  815. if(form->showfilename)
  816. free(form->showfilename); /* free the faked file name */
  817. free(form); /* free the struct */
  818. } while((form=next)); /* continue */
  819. }
  820. /*
  821. * Curl_getFormData() converts a linked list of "meta data" into a complete
  822. * (possibly huge) multipart formdata. The input list is in 'post', while the
  823. * output resulting linked lists gets stored in '*finalform'. *sizep will get
  824. * the total size of the whole POST.
  825. */
  826. CURLcode Curl_getFormData(struct FormData **finalform,
  827. struct curl_httppost *post,
  828. curl_off_t *sizep)
  829. {
  830. struct FormData *form = NULL;
  831. struct FormData *firstform;
  832. struct curl_httppost *file;
  833. CURLcode result = CURLE_OK;
  834. curl_off_t size=0; /* support potentially ENORMOUS formposts */
  835. char *boundary;
  836. char *fileboundary=NULL;
  837. struct curl_slist* curList;
  838. *finalform=NULL; /* default form is empty */
  839. if(!post)
  840. return result; /* no input => no output! */
  841. boundary = Curl_FormBoundary();
  842. if(!boundary)
  843. return CURLE_OUT_OF_MEMORY;
  844. /* Make the first line of the output */
  845. result = AddFormDataf(&form, NULL,
  846. "Content-Type: multipart/form-data;"
  847. " boundary=%s\r\n",
  848. boundary);
  849. if (result) {
  850. free(boundary);
  851. return result;
  852. }
  853. /* we DO NOT include that line in the total size of the POST, since it'll be
  854. part of the header! */
  855. firstform = form;
  856. do {
  857. if(size) {
  858. result = AddFormDataf(&form, &size, "\r\n");
  859. if (result)
  860. break;
  861. }
  862. /* boundary */
  863. result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
  864. if (result)
  865. break;
  866. result = AddFormDataf(&form, &size,
  867. "Content-Disposition: form-data; name=\"");
  868. if (result)
  869. break;
  870. result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
  871. &size);
  872. if (result)
  873. break;
  874. result = AddFormDataf(&form, &size, "\"");
  875. if (result)
  876. break;
  877. if(post->more) {
  878. /* If used, this is a link to more file names, we must then do
  879. the magic to include several files with the same field name */
  880. fileboundary = Curl_FormBoundary();
  881. result = AddFormDataf(&form, &size,
  882. "\r\nContent-Type: multipart/mixed,"
  883. " boundary=%s\r\n",
  884. fileboundary);
  885. if (result)
  886. break;
  887. }
  888. file = post;
  889. do {
  890. /* If 'showfilename' is set, that is a faked name passed on to us
  891. to use to in the formpost. If that is not set, the actually used
  892. local file name should be added. */
  893. if(post->more) {
  894. /* if multiple-file */
  895. result = AddFormDataf(&form, &size,
  896. "\r\n--%s\r\nContent-Disposition: "
  897. "attachment; filename=\"%s\"",
  898. fileboundary,
  899. (file->showfilename?file->showfilename:
  900. file->contents));
  901. if (result)
  902. break;
  903. }
  904. else if((post->flags & HTTPPOST_FILENAME) ||
  905. (post->flags & HTTPPOST_BUFFER)) {
  906. result = AddFormDataf(&form, &size,
  907. "; filename=\"%s\"",
  908. (post->showfilename?post->showfilename:
  909. post->contents));
  910. if (result)
  911. break;
  912. }
  913. if(file->contenttype) {
  914. /* we have a specified type */
  915. result = AddFormDataf(&form, &size,
  916. "\r\nContent-Type: %s",
  917. file->contenttype);
  918. if (result)
  919. break;
  920. }
  921. curList = file->contentheader;
  922. while( curList ) {
  923. /* Process the additional headers specified for this form */
  924. result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
  925. if (result)
  926. break;
  927. curList = curList->next;
  928. }
  929. if (result) {
  930. Curl_formclean(firstform);
  931. free(boundary);
  932. return result;
  933. }
  934. #if 0
  935. /* The header Content-Transfer-Encoding: seems to confuse some receivers
  936. * (like the built-in PHP engine). While I can't see any reason why it
  937. * should, I can just as well skip this to the benefit of the users who
  938. * are using such confused receivers.
  939. */
  940. if(file->contenttype &&
  941. !checkprefix("text/", file->contenttype)) {
  942. /* this is not a text content, mention our binary encoding */
  943. size += AddFormData(&form, "\r\nContent-Transfer-Encoding: binary", 0);
  944. }
  945. #endif
  946. result = AddFormDataf(&form, &size, "\r\n\r\n");
  947. if (result)
  948. break;
  949. if((post->flags & HTTPPOST_FILENAME) ||
  950. (post->flags & HTTPPOST_READFILE)) {
  951. /* we should include the contents from the specified file */
  952. FILE *fileread;
  953. fileread = strequal("-", file->contents)?
  954. stdin:fopen(file->contents, "rb"); /* binary read for win32 */
  955. /*
  956. * VMS: This only allows for stream files on VMS. Stream files are
  957. * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
  958. * every record needs to have a \n appended & 1 added to SIZE
  959. */
  960. if(fileread) {
  961. if(fileread != stdin) {
  962. /* close the file again */
  963. fclose(fileread);
  964. /* add the file name only - for later reading from this */
  965. result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
  966. }
  967. else {
  968. /* When uploading from stdin, we can't know the size of the file,
  969. * thus must read the full file as before. We *could* use chunked
  970. * transfer-encoding, but that only works for HTTP 1.1 and we
  971. * can't be sure we work with such a server.
  972. */
  973. size_t nread;
  974. char buffer[512];
  975. while((nread = fread(buffer, 1, sizeof(buffer), fileread))) {
  976. result = AddFormData(&form, FORM_DATA, buffer, nread, &size);
  977. if (result)
  978. break;
  979. }
  980. }
  981. if (result) {
  982. Curl_formclean(firstform);
  983. free(boundary);
  984. return result;
  985. }
  986. }
  987. else {
  988. Curl_formclean(firstform);
  989. free(boundary);
  990. *finalform = NULL;
  991. return CURLE_READ_ERROR;
  992. }
  993. }
  994. else if (post->flags & HTTPPOST_BUFFER) {
  995. /* include contents of buffer */
  996. result = AddFormData(&form, FORM_DATA, post->buffer,
  997. post->bufferlength, &size);
  998. if (result)
  999. break;
  1000. }
  1001. else {
  1002. /* include the contents we got */
  1003. result = AddFormData(&form, FORM_DATA, post->contents,
  1004. post->contentslength, &size);
  1005. if (result)
  1006. break;
  1007. }
  1008. } while((file = file->more)); /* for each specified file for this field */
  1009. if (result) {
  1010. Curl_formclean(firstform);
  1011. free(boundary);
  1012. return result;
  1013. }
  1014. if(post->more) {
  1015. /* this was a multiple-file inclusion, make a termination file
  1016. boundary: */
  1017. result = AddFormDataf(&form, &size,
  1018. "\r\n--%s--",
  1019. fileboundary);
  1020. free(fileboundary);
  1021. if (result)
  1022. break;
  1023. }
  1024. } while((post=post->next)); /* for each field */
  1025. if (result) {
  1026. Curl_formclean(firstform);
  1027. free(boundary);
  1028. return result;
  1029. }
  1030. /* end-boundary for everything */
  1031. result = AddFormDataf(&form, &size,
  1032. "\r\n--%s--\r\n",
  1033. boundary);
  1034. if (result) {
  1035. Curl_formclean(firstform);
  1036. free(boundary);
  1037. return result;
  1038. }
  1039. *sizep = size;
  1040. free(boundary);
  1041. *finalform=firstform;
  1042. return result;
  1043. }
  1044. /*
  1045. * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
  1046. * and resets the 'sent' counter.
  1047. */
  1048. int Curl_FormInit(struct Form *form, struct FormData *formdata )
  1049. {
  1050. if(!formdata)
  1051. return 1; /* error */
  1052. form->data = formdata;
  1053. form->sent = 0;
  1054. form->fp = NULL;
  1055. return 0;
  1056. }
  1057. static size_t readfromfile(struct Form *form, char *buffer, size_t size)
  1058. {
  1059. size_t nread;
  1060. if(!form->fp) {
  1061. /* this file hasn't yet been opened */
  1062. form->fp = fopen(form->data->line, "rb"); /* b is for binary */
  1063. if(!form->fp)
  1064. return -1; /* failure */
  1065. }
  1066. nread = fread(buffer, 1, size, form->fp);
  1067. if(nread != size) {
  1068. /* this is the last chunk form the file, move on */
  1069. fclose(form->fp);
  1070. form->fp = NULL;
  1071. form->data = form->data->next;
  1072. }
  1073. return nread;
  1074. }
  1075. /*
  1076. * Curl_FormReader() is the fread() emulation function that will be used to
  1077. * deliver the formdata to the transfer loop and then sent away to the peer.
  1078. */
  1079. size_t Curl_FormReader(char *buffer,
  1080. size_t size,
  1081. size_t nitems,
  1082. FILE *mydata)
  1083. {
  1084. struct Form *form;
  1085. size_t wantedsize;
  1086. size_t gotsize = 0;
  1087. form=(struct Form *)mydata;
  1088. wantedsize = size * nitems;
  1089. if(!form->data)
  1090. return 0; /* nothing, error, empty */
  1091. if(form->data->type == FORM_FILE)
  1092. return readfromfile(form, buffer, wantedsize);
  1093. do {
  1094. if( (form->data->length - form->sent ) > wantedsize - gotsize) {
  1095. memcpy(buffer + gotsize , form->data->line + form->sent,
  1096. wantedsize - gotsize);
  1097. form->sent += wantedsize-gotsize;
  1098. return wantedsize;
  1099. }
  1100. memcpy(buffer+gotsize,
  1101. form->data->line + form->sent,
  1102. (form->data->length - form->sent) );
  1103. gotsize += form->data->length - form->sent;
  1104. form->sent = 0;
  1105. form->data = form->data->next; /* advance */
  1106. } while(form->data && (form->data->type == FORM_DATA));
  1107. /* If we got an empty line and we have more data, we proceed to the next
  1108. line immediately to avoid returning zero before we've reached the end.
  1109. This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
  1110. return gotsize;
  1111. }
  1112. /*
  1113. * Curl_formpostheader() returns the first line of the formpost, the
  1114. * request-header part (which is not part of the request-body like the rest of
  1115. * the post).
  1116. */
  1117. char *Curl_formpostheader(void *formp, size_t *len)
  1118. {
  1119. char *header;
  1120. struct Form *form=(struct Form *)formp;
  1121. if(!form->data)
  1122. return 0; /* nothing, ERROR! */
  1123. header = form->data->line;
  1124. *len = form->data->length;
  1125. form->data = form->data->next; /* advance */
  1126. return header;
  1127. }
  1128. #ifdef _FORM_DEBUG
  1129. int FormAddTest(const char * errormsg,
  1130. struct curl_httppost **httppost,
  1131. struct curl_httppost **last_post,
  1132. ...)
  1133. {
  1134. int result;
  1135. va_list arg;
  1136. va_start(arg, last_post);
  1137. if ((result = FormAdd(httppost, last_post, arg)))
  1138. fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
  1139. errormsg);
  1140. va_end(arg);
  1141. return result;
  1142. }
  1143. int main()
  1144. {
  1145. char name1[] = "simple_COPYCONTENTS";
  1146. char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
  1147. char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
  1148. char name4[] = "simple_PTRCONTENTS";
  1149. char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH";
  1150. char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
  1151. char name7[] = "FILE1_+_CONTENTTYPE";
  1152. char name8[] = "FILE1_+_FILE2";
  1153. char name9[] = "FILE1_+_FILE2_+_FILE3";
  1154. char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
  1155. char name11[] = "FILECONTENT";
  1156. char value1[] = "value for simple COPYCONTENTS";
  1157. char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
  1158. char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
  1159. char value4[] = "value for simple PTRCONTENTS";
  1160. char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
  1161. char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
  1162. char value7[] = "inet_ntoa_r.h";
  1163. char value8[] = "Makefile.b32.resp";
  1164. char type2[] = "image/gif";
  1165. char type6[] = "text/plain";
  1166. char type7[] = "text/html";
  1167. int name3length = strlen(name3);
  1168. int value3length = strlen(value3);
  1169. int value5length = strlen(value4);
  1170. int value6length = strlen(value5);
  1171. int errors = 0;
  1172. int size;
  1173. size_t nread;
  1174. char buffer[4096];
  1175. struct curl_httppost *httppost=NULL;
  1176. struct curl_httppost *last_post=NULL;
  1177. struct curl_forms forms[4];
  1178. struct FormData *form;
  1179. struct Form formread;
  1180. if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
  1181. CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
  1182. CURLFORM_END))
  1183. ++errors;
  1184. if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post,
  1185. CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
  1186. CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
  1187. ++errors;
  1188. /* make null character at start to check that contentslength works
  1189. correctly */
  1190. name3[1] = '\0';
  1191. value3[1] = '\0';
  1192. if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
  1193. &httppost, &last_post,
  1194. CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3,
  1195. CURLFORM_CONTENTSLENGTH, value3length,
  1196. CURLFORM_NAMELENGTH, name3length, CURLFORM_END))
  1197. ++errors;
  1198. if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
  1199. CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
  1200. CURLFORM_END))
  1201. ++errors;
  1202. /* make null character at start to check that contentslength works
  1203. correctly */
  1204. value5[1] = '\0';
  1205. if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
  1206. CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
  1207. CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END))
  1208. ++errors;
  1209. /* make null character at start to check that contentslength works
  1210. correctly */
  1211. value6[1] = '\0';
  1212. if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
  1213. &httppost, &last_post,
  1214. CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6,
  1215. CURLFORM_CONTENTSLENGTH, value6length,
  1216. CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
  1217. ++errors;
  1218. if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
  1219. CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7,
  1220. CURLFORM_CONTENTTYPE, type7, CURLFORM_END))
  1221. ++errors;
  1222. if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
  1223. CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7,
  1224. CURLFORM_FILE, value8, CURLFORM_END))
  1225. ++errors;
  1226. if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post,
  1227. CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7,
  1228. CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END))
  1229. ++errors;
  1230. forms[0].option = CURLFORM_FILE;
  1231. forms[0].value = value7;
  1232. forms[1].option = CURLFORM_FILE;
  1233. forms[1].value = value8;
  1234. forms[2].option = CURLFORM_FILE;
  1235. forms[2].value = value7;
  1236. forms[3].option = CURLFORM_END;
  1237. if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post,
  1238. CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms,
  1239. CURLFORM_END))
  1240. ++errors;
  1241. if (FormAddTest("FILECONTENT test", &httppost, &last_post,
  1242. CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7,
  1243. CURLFORM_END))
  1244. ++errors;
  1245. form=Curl_getFormData(httppost, &size);
  1246. Curl_FormInit(&formread, form);
  1247. do {
  1248. nread = Curl_FormReader(buffer, 1, sizeof(buffer),
  1249. (FILE *)&formread);
  1250. if(-1 == nread)
  1251. break;
  1252. fwrite(buffer, nread, 1, stdout);
  1253. } while(1);
  1254. fprintf(stdout, "size: %d\n", size);
  1255. if (errors)
  1256. fprintf(stdout, "\n==> %d Test(s) failed!\n", errors);
  1257. else
  1258. fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
  1259. return 0;
  1260. }
  1261. #endif
  1262. #else /* CURL_DISABLE_HTTP */
  1263. CURLFORMcode curl_formadd(struct curl_httppost **httppost,
  1264. struct curl_httppost **last_post,
  1265. ...)
  1266. {
  1267. (void)httppost;
  1268. (void)last_post;
  1269. return CURL_FORMADD_DISABLED;
  1270. }
  1271. void curl_formfree(struct curl_httppost *form)
  1272. {
  1273. (void)form;
  1274. /* does nothing HTTP is disabled */
  1275. }
  1276. #endif /* CURL_DISABLE_HTTP */
  1277. /*
  1278. * Curl_FormBoundary() creates a suitable boundary string and returns an
  1279. * allocated one. This is also used by SSL-code so it must be present even
  1280. * if HTTP is disabled!
  1281. */
  1282. char *Curl_FormBoundary(void)
  1283. {
  1284. char *retstring;
  1285. static int randomizer=0; /* this is just so that two boundaries within
  1286. the same form won't be identical */
  1287. size_t i;
  1288. static char table16[]="abcdef0123456789";
  1289. retstring = (char *)malloc(BOUNDARY_LENGTH+1);
  1290. if(!retstring)
  1291. return NULL; /* failed */
  1292. srand(time(NULL)+randomizer++); /* seed */
  1293. strcpy(retstring, "----------------------------");
  1294. for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
  1295. retstring[i] = table16[rand()%16];
  1296. /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
  1297. combinations */
  1298. retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
  1299. return retstring;
  1300. }