formdata.c 44 KB

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