PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/tool_formparse.c

http://github.com/bagder/curl
C | 917 lines | 712 code | 75 blank | 130 comment | 205 complexity | 6999aa472121b734690684d280c45611 MD5 | raw file
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. ***************************************************************************/
  22. #include "tool_setup.h"
  23. #include "strcase.h"
  24. #define ENABLE_CURLX_PRINTF
  25. /* use our own printf() functions */
  26. #include "curlx.h"
  27. #include "tool_cfgable.h"
  28. #include "tool_convert.h"
  29. #include "tool_msgs.h"
  30. #include "tool_binmode.h"
  31. #include "tool_getparam.h"
  32. #include "tool_paramhlp.h"
  33. #include "tool_formparse.h"
  34. #include "memdebug.h" /* keep this as LAST include */
  35. /* Macros to free const pointers. */
  36. #define CONST_FREE(x) free((void *) (x))
  37. #define CONST_SAFEFREE(x) Curl_safefree(*((void **) &(x)))
  38. /* tool_mime functions. */
  39. static tool_mime *tool_mime_new(tool_mime *parent, toolmimekind kind)
  40. {
  41. tool_mime *m = (tool_mime *) calloc(1, sizeof(*m));
  42. if(m) {
  43. m->kind = kind;
  44. m->parent = parent;
  45. if(parent) {
  46. m->prev = parent->subparts;
  47. parent->subparts = m;
  48. }
  49. }
  50. return m;
  51. }
  52. static tool_mime *tool_mime_new_parts(tool_mime *parent)
  53. {
  54. return tool_mime_new(parent, TOOLMIME_PARTS);
  55. }
  56. static tool_mime *tool_mime_new_data(tool_mime *parent, const char *data)
  57. {
  58. tool_mime *m = NULL;
  59. data = strdup(data);
  60. if(data) {
  61. m = tool_mime_new(parent, TOOLMIME_DATA);
  62. if(!m)
  63. CONST_FREE(data);
  64. else
  65. m->data = data;
  66. }
  67. return m;
  68. }
  69. static tool_mime *tool_mime_new_filedata(tool_mime *parent,
  70. const char *filename,
  71. bool isremotefile,
  72. CURLcode *errcode)
  73. {
  74. CURLcode result = CURLE_OK;
  75. tool_mime *m = NULL;
  76. *errcode = CURLE_OUT_OF_MEMORY;
  77. if(strcmp(filename, "-")) {
  78. /* This is a normal file. */
  79. filename = strdup(filename);
  80. if(filename) {
  81. m = tool_mime_new(parent, TOOLMIME_FILE);
  82. if(!m)
  83. CONST_FREE(filename);
  84. else {
  85. m->data = filename;
  86. if(!isremotefile)
  87. m->kind = TOOLMIME_FILEDATA;
  88. *errcode = CURLE_OK;
  89. }
  90. }
  91. }
  92. else { /* Standard input. */
  93. int fd = fileno(stdin);
  94. char *data = NULL;
  95. curl_off_t size;
  96. curl_off_t origin;
  97. struct_stat sbuf;
  98. set_binmode(stdin);
  99. origin = ftell(stdin);
  100. /* If stdin is a regular file, do not buffer data but read it
  101. when needed. */
  102. if(fd >= 0 && origin >= 0 && !fstat(fd, &sbuf) &&
  103. #ifdef __VMS
  104. sbuf.st_fab_rfm != FAB$C_VAR && sbuf.st_fab_rfm != FAB$C_VFC &&
  105. #endif
  106. S_ISREG(sbuf.st_mode)) {
  107. size = sbuf.st_size - origin;
  108. if(size < 0)
  109. size = 0;
  110. }
  111. else { /* Not suitable for direct use, buffer stdin data. */
  112. size_t stdinsize = 0;
  113. if(file2memory(&data, &stdinsize, stdin) != PARAM_OK) {
  114. /* Out of memory. */
  115. return m;
  116. }
  117. if(ferror(stdin)) {
  118. result = CURLE_READ_ERROR;
  119. Curl_safefree(data);
  120. data = NULL;
  121. }
  122. else if(!stdinsize) {
  123. /* Zero-length data has been freed. Re-create it. */
  124. data = strdup("");
  125. if(!data)
  126. return m;
  127. }
  128. size = curlx_uztoso(stdinsize);
  129. origin = 0;
  130. }
  131. m = tool_mime_new(parent, TOOLMIME_STDIN);
  132. if(!m)
  133. Curl_safefree(data);
  134. else {
  135. m->data = data;
  136. m->origin = origin;
  137. m->size = size;
  138. m->curpos = 0;
  139. if(!isremotefile)
  140. m->kind = TOOLMIME_STDINDATA;
  141. *errcode = result;
  142. }
  143. }
  144. return m;
  145. }
  146. void tool_mime_free(tool_mime *mime)
  147. {
  148. if(mime) {
  149. if(mime->subparts)
  150. tool_mime_free(mime->subparts);
  151. if(mime->prev)
  152. tool_mime_free(mime->prev);
  153. CONST_SAFEFREE(mime->name);
  154. CONST_SAFEFREE(mime->filename);
  155. CONST_SAFEFREE(mime->type);
  156. CONST_SAFEFREE(mime->encoder);
  157. CONST_SAFEFREE(mime->data);
  158. curl_slist_free_all(mime->headers);
  159. free(mime);
  160. }
  161. }
  162. /* Mime part callbacks for stdin. */
  163. size_t tool_mime_stdin_read(char *buffer,
  164. size_t size, size_t nitems, void *arg)
  165. {
  166. tool_mime *sip = (tool_mime *) arg;
  167. curl_off_t bytesleft;
  168. (void) size; /* Always 1: ignored. */
  169. if(sip->size >= 0) {
  170. if(sip->curpos >= sip->size)
  171. return 0; /* At eof. */
  172. bytesleft = sip->size - sip->curpos;
  173. if(curlx_uztoso(nitems) > bytesleft)
  174. nitems = curlx_sotouz(bytesleft);
  175. }
  176. if(nitems) {
  177. if(sip->data) {
  178. /* Return data from memory. */
  179. memcpy(buffer, sip->data + curlx_sotouz(sip->curpos), nitems);
  180. }
  181. else {
  182. /* Read from stdin. */
  183. nitems = fread(buffer, 1, nitems, stdin);
  184. if(ferror(stdin)) {
  185. /* Show error only once. */
  186. if(sip->config) {
  187. warnf(sip->config, "stdin: %s\n", strerror(errno));
  188. sip->config = NULL;
  189. }
  190. return CURL_READFUNC_ABORT;
  191. }
  192. }
  193. sip->curpos += curlx_uztoso(nitems);
  194. }
  195. return nitems;
  196. }
  197. int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence)
  198. {
  199. tool_mime *sip = (tool_mime *) instream;
  200. switch(whence) {
  201. case SEEK_CUR:
  202. offset += sip->curpos;
  203. break;
  204. case SEEK_END:
  205. offset += sip->size;
  206. break;
  207. }
  208. if(offset < 0)
  209. return CURL_SEEKFUNC_CANTSEEK;
  210. if(!sip->data) {
  211. if(fseek(stdin, (long) (offset + sip->origin), SEEK_SET))
  212. return CURL_SEEKFUNC_CANTSEEK;
  213. }
  214. sip->curpos = offset;
  215. return CURL_SEEKFUNC_OK;
  216. }
  217. /* Translate an internal mime tree into a libcurl mime tree. */
  218. static CURLcode tool2curlparts(CURL *curl, tool_mime *m, curl_mime *mime)
  219. {
  220. CURLcode ret = CURLE_OK;
  221. curl_mimepart *part = NULL;
  222. curl_mime *submime = NULL;
  223. const char *filename = NULL;
  224. if(m) {
  225. ret = tool2curlparts(curl, m->prev, mime);
  226. if(!ret) {
  227. part = curl_mime_addpart(mime);
  228. if(!part)
  229. ret = CURLE_OUT_OF_MEMORY;
  230. }
  231. if(!ret) {
  232. filename = m->filename;
  233. switch(m->kind) {
  234. case TOOLMIME_PARTS:
  235. ret = tool2curlmime(curl, m, &submime);
  236. if(!ret) {
  237. ret = curl_mime_subparts(part, submime);
  238. if(ret)
  239. curl_mime_free(submime);
  240. }
  241. break;
  242. case TOOLMIME_DATA:
  243. #ifdef CURL_DOES_CONVERSIONS
  244. /* Our data is always textual: convert it to ASCII. */
  245. {
  246. size_t size = strlen(m->data);
  247. char *cp = malloc(size + 1);
  248. if(!cp)
  249. ret = CURLE_OUT_OF_MEMORY;
  250. else {
  251. memcpy(cp, m->data, size + 1);
  252. ret = convert_to_network(cp, size);
  253. if(!ret)
  254. ret = curl_mime_data(part, cp, CURL_ZERO_TERMINATED);
  255. free(cp);
  256. }
  257. }
  258. #else
  259. ret = curl_mime_data(part, m->data, CURL_ZERO_TERMINATED);
  260. #endif
  261. break;
  262. case TOOLMIME_FILE:
  263. case TOOLMIME_FILEDATA:
  264. ret = curl_mime_filedata(part, m->data);
  265. if(!ret && m->kind == TOOLMIME_FILEDATA && !filename)
  266. ret = curl_mime_filename(part, NULL);
  267. break;
  268. case TOOLMIME_STDIN:
  269. if(!filename)
  270. filename = "-";
  271. /* FALLTHROUGH */
  272. case TOOLMIME_STDINDATA:
  273. ret = curl_mime_data_cb(part, m->size,
  274. (curl_read_callback) tool_mime_stdin_read,
  275. (curl_seek_callback) tool_mime_stdin_seek,
  276. NULL, m);
  277. break;
  278. default:
  279. /* Other cases not possible in this context. */
  280. break;
  281. }
  282. }
  283. if(!ret && filename)
  284. ret = curl_mime_filename(part, filename);
  285. if(!ret)
  286. ret = curl_mime_type(part, m->type);
  287. if(!ret)
  288. ret = curl_mime_headers(part, m->headers, 0);
  289. if(!ret)
  290. ret = curl_mime_encoder(part, m->encoder);
  291. if(!ret)
  292. ret = curl_mime_name(part, m->name);
  293. }
  294. return ret;
  295. }
  296. CURLcode tool2curlmime(CURL *curl, tool_mime *m, curl_mime **mime)
  297. {
  298. CURLcode ret = CURLE_OK;
  299. *mime = curl_mime_init(curl);
  300. if(!*mime)
  301. ret = CURLE_OUT_OF_MEMORY;
  302. else
  303. ret = tool2curlparts(curl, m->subparts, *mime);
  304. if(ret) {
  305. curl_mime_free(*mime);
  306. *mime = NULL;
  307. }
  308. return ret;
  309. }
  310. /*
  311. * helper function to get a word from form param
  312. * after call get_parm_word, str either point to string end
  313. * or point to any of end chars.
  314. */
  315. static char *get_param_word(char **str, char **end_pos, char endchar)
  316. {
  317. char *ptr = *str;
  318. /* the first non-space char is here */
  319. char *word_begin = ptr;
  320. char *ptr2;
  321. char *escape = NULL;
  322. if(*ptr == '"') {
  323. ++ptr;
  324. while(*ptr) {
  325. if(*ptr == '\\') {
  326. if(ptr[1] == '\\' || ptr[1] == '"') {
  327. /* remember the first escape position */
  328. if(!escape)
  329. escape = ptr;
  330. /* skip escape of back-slash or double-quote */
  331. ptr += 2;
  332. continue;
  333. }
  334. }
  335. if(*ptr == '"') {
  336. *end_pos = ptr;
  337. if(escape) {
  338. /* has escape, we restore the unescaped string here */
  339. ptr = ptr2 = escape;
  340. do {
  341. if(*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '"'))
  342. ++ptr;
  343. *ptr2++ = *ptr++;
  344. }
  345. while(ptr < *end_pos);
  346. *end_pos = ptr2;
  347. }
  348. while(*ptr && *ptr != ';' && *ptr != endchar)
  349. ++ptr;
  350. *str = ptr;
  351. return word_begin + 1;
  352. }
  353. ++ptr;
  354. }
  355. /* end quote is missing, treat it as non-quoted. */
  356. ptr = word_begin;
  357. }
  358. while(*ptr && *ptr != ';' && *ptr != endchar)
  359. ++ptr;
  360. *str = *end_pos = ptr;
  361. return word_begin;
  362. }
  363. /* Append slist item and return -1 if failed. */
  364. static int slist_append(struct curl_slist **plist, const char *data)
  365. {
  366. struct curl_slist *s = curl_slist_append(*plist, data);
  367. if(!s)
  368. return -1;
  369. *plist = s;
  370. return 0;
  371. }
  372. /* Read headers from a file and append to list. */
  373. static int read_field_headers(struct OperationConfig *config,
  374. const char *filename, FILE *fp,
  375. struct curl_slist **pheaders)
  376. {
  377. size_t hdrlen = 0;
  378. size_t pos = 0;
  379. bool incomment = FALSE;
  380. int lineno = 1;
  381. char hdrbuf[999]; /* Max. header length + 1. */
  382. for(;;) {
  383. int c = getc(fp);
  384. if(c == EOF || (!pos && !ISSPACE(c))) {
  385. /* Strip and flush the current header. */
  386. while(hdrlen && ISSPACE(hdrbuf[hdrlen - 1]))
  387. hdrlen--;
  388. if(hdrlen) {
  389. hdrbuf[hdrlen] = '\0';
  390. if(slist_append(pheaders, hdrbuf)) {
  391. fprintf(config->global->errors,
  392. "Out of memory for field headers!\n");
  393. return -1;
  394. }
  395. hdrlen = 0;
  396. }
  397. }
  398. switch(c) {
  399. case EOF:
  400. if(ferror(fp)) {
  401. fprintf(config->global->errors,
  402. "Header file %s read error: %s\n", filename, strerror(errno));
  403. return -1;
  404. }
  405. return 0; /* Done. */
  406. case '\r':
  407. continue; /* Ignore. */
  408. case '\n':
  409. pos = 0;
  410. incomment = FALSE;
  411. lineno++;
  412. continue;
  413. case '#':
  414. if(!pos)
  415. incomment = TRUE;
  416. break;
  417. }
  418. pos++;
  419. if(!incomment) {
  420. if(hdrlen == sizeof(hdrbuf) - 1) {
  421. warnf(config->global, "File %s line %d: header too long (truncated)\n",
  422. filename, lineno);
  423. c = ' ';
  424. }
  425. if(hdrlen <= sizeof(hdrbuf) - 1)
  426. hdrbuf[hdrlen++] = (char) c;
  427. }
  428. }
  429. /* NOTREACHED */
  430. }
  431. static int get_param_part(struct OperationConfig *config, char endchar,
  432. char **str, char **pdata, char **ptype,
  433. char **pfilename, char **pencoder,
  434. struct curl_slist **pheaders)
  435. {
  436. char *p = *str;
  437. char *type = NULL;
  438. char *filename = NULL;
  439. char *encoder = NULL;
  440. char *endpos;
  441. char *tp;
  442. char sep;
  443. char type_major[128] = "";
  444. char type_minor[128] = "";
  445. char *endct = NULL;
  446. struct curl_slist *headers = NULL;
  447. if(ptype)
  448. *ptype = NULL;
  449. if(pfilename)
  450. *pfilename = NULL;
  451. if(pheaders)
  452. *pheaders = NULL;
  453. if(pencoder)
  454. *pencoder = NULL;
  455. while(ISSPACE(*p))
  456. p++;
  457. tp = p;
  458. *pdata = get_param_word(&p, &endpos, endchar);
  459. /* If not quoted, strip trailing spaces. */
  460. if(*pdata == tp)
  461. while(endpos > *pdata && ISSPACE(endpos[-1]))
  462. endpos--;
  463. sep = *p;
  464. *endpos = '\0';
  465. while(sep == ';') {
  466. while(ISSPACE(*++p))
  467. ;
  468. if(!endct && checkprefix("type=", p)) {
  469. for(p += 5; ISSPACE(*p); p++)
  470. ;
  471. /* set type pointer */
  472. type = p;
  473. /* verify that this is a fine type specifier */
  474. if(2 != sscanf(type, "%127[^/ ]/%127[^;, \n]", type_major, type_minor)) {
  475. warnf(config->global, "Illegally formatted content-type field!\n");
  476. curl_slist_free_all(headers);
  477. return -1; /* illegal content-type syntax! */
  478. }
  479. /* now point beyond the content-type specifier */
  480. p = type + strlen(type_major) + strlen(type_minor) + 1;
  481. for(endct = p; *p && *p != ';' && *p != endchar; p++)
  482. if(!ISSPACE(*p))
  483. endct = p + 1;
  484. sep = *p;
  485. }
  486. else if(checkprefix("filename=", p)) {
  487. if(endct) {
  488. *endct = '\0';
  489. endct = NULL;
  490. }
  491. for(p += 9; ISSPACE(*p); p++)
  492. ;
  493. tp = p;
  494. filename = get_param_word(&p, &endpos, endchar);
  495. /* If not quoted, strip trailing spaces. */
  496. if(filename == tp)
  497. while(endpos > filename && ISSPACE(endpos[-1]))
  498. endpos--;
  499. sep = *p;
  500. *endpos = '\0';
  501. }
  502. else if(checkprefix("headers=", p)) {
  503. if(endct) {
  504. *endct = '\0';
  505. endct = NULL;
  506. }
  507. p += 8;
  508. if(*p == '@' || *p == '<') {
  509. char *hdrfile;
  510. FILE *fp;
  511. /* Read headers from a file. */
  512. do {
  513. p++;
  514. } while(ISSPACE(*p));
  515. tp = p;
  516. hdrfile = get_param_word(&p, &endpos, endchar);
  517. /* If not quoted, strip trailing spaces. */
  518. if(hdrfile == tp)
  519. while(endpos > hdrfile && ISSPACE(endpos[-1]))
  520. endpos--;
  521. sep = *p;
  522. *endpos = '\0';
  523. fp = fopen(hdrfile, FOPEN_READTEXT);
  524. if(!fp)
  525. warnf(config->global, "Cannot read from %s: %s\n", hdrfile,
  526. strerror(errno));
  527. else {
  528. int i = read_field_headers(config, hdrfile, fp, &headers);
  529. fclose(fp);
  530. if(i) {
  531. curl_slist_free_all(headers);
  532. return -1;
  533. }
  534. }
  535. }
  536. else {
  537. char *hdr;
  538. while(ISSPACE(*p))
  539. p++;
  540. tp = p;
  541. hdr = get_param_word(&p, &endpos, endchar);
  542. /* If not quoted, strip trailing spaces. */
  543. if(hdr == tp)
  544. while(endpos > hdr && ISSPACE(endpos[-1]))
  545. endpos--;
  546. sep = *p;
  547. *endpos = '\0';
  548. if(slist_append(&headers, hdr)) {
  549. fprintf(config->global->errors, "Out of memory for field header!\n");
  550. curl_slist_free_all(headers);
  551. return -1;
  552. }
  553. }
  554. }
  555. else if(checkprefix("encoder=", p)) {
  556. if(endct) {
  557. *endct = '\0';
  558. endct = NULL;
  559. }
  560. for(p += 8; ISSPACE(*p); p++)
  561. ;
  562. tp = p;
  563. encoder = get_param_word(&p, &endpos, endchar);
  564. /* If not quoted, strip trailing spaces. */
  565. if(encoder == tp)
  566. while(endpos > encoder && ISSPACE(endpos[-1]))
  567. endpos--;
  568. sep = *p;
  569. *endpos = '\0';
  570. }
  571. else if(endct) {
  572. /* This is part of content type. */
  573. for(endct = p; *p && *p != ';' && *p != endchar; p++)
  574. if(!ISSPACE(*p))
  575. endct = p + 1;
  576. sep = *p;
  577. }
  578. else {
  579. /* unknown prefix, skip to next block */
  580. char *unknown = get_param_word(&p, &endpos, endchar);
  581. sep = *p;
  582. *endpos = '\0';
  583. if(*unknown)
  584. warnf(config->global, "skip unknown form field: %s\n", unknown);
  585. }
  586. }
  587. /* Terminate content type. */
  588. if(endct)
  589. *endct = '\0';
  590. if(ptype)
  591. *ptype = type;
  592. else if(type)
  593. warnf(config->global, "Field content type not allowed here: %s\n", type);
  594. if(pfilename)
  595. *pfilename = filename;
  596. else if(filename)
  597. warnf(config->global,
  598. "Field file name not allowed here: %s\n", filename);
  599. if(pencoder)
  600. *pencoder = encoder;
  601. else if(encoder)
  602. warnf(config->global,
  603. "Field encoder not allowed here: %s\n", encoder);
  604. if(pheaders)
  605. *pheaders = headers;
  606. else if(headers) {
  607. warnf(config->global,
  608. "Field headers not allowed here: %s\n", headers->data);
  609. curl_slist_free_all(headers);
  610. }
  611. *str = p;
  612. return sep & 0xFF;
  613. }
  614. /***************************************************************************
  615. *
  616. * formparse()
  617. *
  618. * Reads a 'name=value' parameter and builds the appropriate linked list.
  619. *
  620. * If the value is of the form '<filename', field data is read from the
  621. * given file.
  622. * Specify files to upload with 'name=@filename', or 'name=@"filename"'
  623. * in case the filename contain ',' or ';'. Supports specified
  624. * given Content-Type of the files. Such as ';type=<content-type>'.
  625. *
  626. * If literal_value is set, any initial '@' or '<' in the value string
  627. * loses its special meaning, as does any embedded ';type='.
  628. *
  629. * You may specify more than one file for a single name (field). Specify
  630. * multiple files by writing it like:
  631. *
  632. * 'name=@filename,filename2,filename3'
  633. *
  634. * or use double-quotes quote the filename:
  635. *
  636. * 'name=@"filename","filename2","filename3"'
  637. *
  638. * If you want content-types specified for each too, write them like:
  639. *
  640. * 'name=@filename;type=image/gif,filename2,filename3'
  641. *
  642. * If you want custom headers added for a single part, write them in a separate
  643. * file and do like this:
  644. *
  645. * 'name=foo;headers=@headerfile' or why not
  646. * 'name=@filemame;headers=@headerfile'
  647. *
  648. * To upload a file, but to fake the file name that will be included in the
  649. * formpost, do like this:
  650. *
  651. * 'name=@filename;filename=/dev/null' or quote the faked filename like:
  652. * 'name=@filename;filename="play, play, and play.txt"'
  653. *
  654. * If filename/path contains ',' or ';', it must be quoted by double-quotes,
  655. * else curl will fail to figure out the correct filename. if the filename
  656. * tobe quoted contains '"' or '\', '"' and '\' must be escaped by backslash.
  657. *
  658. ***************************************************************************/
  659. /* Convenience macros for null pointer check. */
  660. #define NULL_CHECK(ptr, init, retcode) { \
  661. (ptr) = (init); \
  662. if(!(ptr)) { \
  663. warnf(config->global, "out of memory!\n"); \
  664. curl_slist_free_all(headers); \
  665. Curl_safefree(contents); \
  666. return retcode; \
  667. } \
  668. }
  669. #define SET_TOOL_MIME_PTR(m, field, retcode) { \
  670. if(field) \
  671. NULL_CHECK((m)->field, strdup(field), retcode); \
  672. }
  673. int formparse(struct OperationConfig *config,
  674. const char *input,
  675. tool_mime **mimeroot,
  676. tool_mime **mimecurrent,
  677. bool literal_value)
  678. {
  679. /* input MUST be a string in the format 'name=contents' and we'll
  680. build a linked list with the info */
  681. char *name = NULL;
  682. char *contents = NULL;
  683. char *contp;
  684. char *data;
  685. char *type = NULL;
  686. char *filename = NULL;
  687. char *encoder = NULL;
  688. struct curl_slist *headers = NULL;
  689. tool_mime *part = NULL;
  690. CURLcode res;
  691. /* Allocate the main mime structure if needed. */
  692. if(!*mimecurrent) {
  693. NULL_CHECK(*mimeroot, tool_mime_new_parts(NULL), 1);
  694. *mimecurrent = *mimeroot;
  695. }
  696. /* Make a copy we can overwrite. */
  697. NULL_CHECK(contents, strdup(input), 2);
  698. /* Scan for the end of the name. */
  699. contp = strchr(contents, '=');
  700. if(contp) {
  701. int sep = '\0';
  702. if(contp > contents)
  703. name = contents;
  704. *contp++ = '\0';
  705. if(*contp == '(' && !literal_value) {
  706. /* Starting a multipart. */
  707. sep = get_param_part(config, '\0',
  708. &contp, &data, &type, NULL, NULL, &headers);
  709. if(sep < 0) {
  710. Curl_safefree(contents);
  711. return 3;
  712. }
  713. NULL_CHECK(part, tool_mime_new_parts(*mimecurrent), 4);
  714. *mimecurrent = part;
  715. part->headers = headers;
  716. headers = NULL;
  717. SET_TOOL_MIME_PTR(part, type, 5);
  718. }
  719. else if(!name && !strcmp(contp, ")") && !literal_value) {
  720. /* Ending a multipart. */
  721. if(*mimecurrent == *mimeroot) {
  722. warnf(config->global, "no multipart to terminate!\n");
  723. Curl_safefree(contents);
  724. return 6;
  725. }
  726. *mimecurrent = (*mimecurrent)->parent;
  727. }
  728. else if('@' == contp[0] && !literal_value) {
  729. /* we use the @-letter to indicate file name(s) */
  730. tool_mime *subparts = NULL;
  731. do {
  732. /* since this was a file, it may have a content-type specifier
  733. at the end too, or a filename. Or both. */
  734. ++contp;
  735. sep = get_param_part(config, ',', &contp,
  736. &data, &type, &filename, &encoder, &headers);
  737. if(sep < 0) {
  738. Curl_safefree(contents);
  739. return 7;
  740. }
  741. /* now contp point to comma or string end.
  742. If more files to come, make sure we have multiparts. */
  743. if(!subparts) {
  744. if(sep != ',') /* If there is a single file. */
  745. subparts = *mimecurrent;
  746. else
  747. NULL_CHECK(subparts, tool_mime_new_parts(*mimecurrent), 8);
  748. }
  749. /* Store that file in a part. */
  750. NULL_CHECK(part,
  751. tool_mime_new_filedata(subparts, data, TRUE, &res), 9);
  752. part->headers = headers;
  753. headers = NULL;
  754. part->config = config->global;
  755. if(res == CURLE_READ_ERROR) {
  756. /* An error occurred while reading stdin: if read has started,
  757. issue the error now. Else, delay it until processed by
  758. libcurl. */
  759. if(part->size > 0) {
  760. warnf(config->global,
  761. "error while reading standard input\n");
  762. Curl_safefree(contents);
  763. return 10;
  764. }
  765. CONST_SAFEFREE(part->data);
  766. part->data = NULL;
  767. part->size = -1;
  768. res = CURLE_OK;
  769. }
  770. SET_TOOL_MIME_PTR(part, filename, 11);
  771. SET_TOOL_MIME_PTR(part, type, 12);
  772. SET_TOOL_MIME_PTR(part, encoder, 13);
  773. /* *contp could be '\0', so we just check with the delimiter */
  774. } while(sep); /* loop if there's another file name */
  775. part = (*mimecurrent)->subparts; /* Set name on group. */
  776. }
  777. else {
  778. if(*contp == '<' && !literal_value) {
  779. ++contp;
  780. sep = get_param_part(config, '\0', &contp,
  781. &data, &type, NULL, &encoder, &headers);
  782. if(sep < 0) {
  783. Curl_safefree(contents);
  784. return 14;
  785. }
  786. NULL_CHECK(part, tool_mime_new_filedata(*mimecurrent, data, FALSE,
  787. &res), 15);
  788. part->headers = headers;
  789. headers = NULL;
  790. part->config = config->global;
  791. if(res == CURLE_READ_ERROR) {
  792. /* An error occurred while reading stdin: if read has started,
  793. issue the error now. Else, delay it until processed by
  794. libcurl. */
  795. if(part->size > 0) {
  796. warnf(config->global,
  797. "error while reading standard input\n");
  798. Curl_safefree(contents);
  799. return 16;
  800. }
  801. CONST_SAFEFREE(part->data);
  802. part->data = NULL;
  803. part->size = -1;
  804. res = CURLE_OK;
  805. }
  806. }
  807. else {
  808. if(literal_value)
  809. data = contp;
  810. else {
  811. sep = get_param_part(config, '\0', &contp,
  812. &data, &type, &filename, &encoder, &headers);
  813. if(sep < 0) {
  814. Curl_safefree(contents);
  815. return 17;
  816. }
  817. }
  818. NULL_CHECK(part, tool_mime_new_data(*mimecurrent, data), 18);
  819. part->headers = headers;
  820. headers = NULL;
  821. }
  822. SET_TOOL_MIME_PTR(part, filename, 19);
  823. SET_TOOL_MIME_PTR(part, type, 20);
  824. SET_TOOL_MIME_PTR(part, encoder, 21);
  825. if(sep) {
  826. *contp = (char) sep;
  827. warnf(config->global,
  828. "garbage at end of field specification: %s\n", contp);
  829. }
  830. }
  831. /* Set part name. */
  832. SET_TOOL_MIME_PTR(part, name, 22);
  833. }
  834. else {
  835. warnf(config->global, "Illegally formatted input field!\n");
  836. Curl_safefree(contents);
  837. return 23;
  838. }
  839. Curl_safefree(contents);
  840. return 0;
  841. }