demo_https.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  1. /*
  2. This file is part of libmicrohttpd
  3. Copyright (C) 2013 Christian Grothoff (and other contributing authors)
  4. Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. /**
  18. * @file demo_https.c
  19. * @brief complex demonstration site: create directory index, offer
  20. * upload via form and HTTP POST, download with mime type detection
  21. * and error reporting (403, etc.) --- and all of this with
  22. * high-performance settings (large buffers, thread pool).
  23. * If you want to benchmark MHD, this code should be used to
  24. * run tests against. Note that the number of threads may need
  25. * to be adjusted depending on the number of available cores.
  26. * Logic is identical to demo.c, just adds HTTPS support.
  27. * This demonstration uses key/cert stored in static string. Optionally,
  28. * use gnutls_load_file() to load them from file.
  29. * @author Christian Grothoff
  30. * @author Karlson2k (Evgeny Grin)
  31. */
  32. #include "platform.h"
  33. #include <microhttpd.h>
  34. #include <unistd.h>
  35. #include <pthread.h>
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #include <dirent.h>
  39. #ifdef MHD_HAVE_LIBMAGIC
  40. #include <magic.h>
  41. #endif /* MHD_HAVE_LIBMAGIC */
  42. #include <limits.h>
  43. #include <ctype.h>
  44. #include <errno.h>
  45. #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
  46. #undef MHD_CPU_COUNT
  47. #endif
  48. #if ! defined(MHD_CPU_COUNT)
  49. #define MHD_CPU_COUNT 2
  50. #endif
  51. #ifndef PATH_MAX
  52. /* Some platforms (namely: GNU Hurd) do no define PATH_MAX.
  53. As it is only example for MHD, just use reasonable value for PATH_MAX. */
  54. #define PATH_MAX 16384
  55. #endif
  56. /**
  57. * Number of threads to run in the thread pool. Should (roughly) match
  58. * the number of cores on your system.
  59. */
  60. #define NUMBER_OF_THREADS MHD_CPU_COUNT
  61. #ifdef MHD_HAVE_LIBMAGIC
  62. /**
  63. * How many bytes of a file do we give to libmagic to determine the mime type?
  64. * 16k might be a bit excessive, but ought not hurt performance much anyway,
  65. * and should definitively be on the safe side.
  66. */
  67. #define MAGIC_HEADER_SIZE (16 * 1024)
  68. #endif /* MHD_HAVE_LIBMAGIC */
  69. /**
  70. * Page returned for file-not-found.
  71. */
  72. #define FILE_NOT_FOUND_PAGE \
  73. "<html><head><title>File not found</title></head><body>File not found</body></html>"
  74. /**
  75. * Page returned for internal errors.
  76. */
  77. #define INTERNAL_ERROR_PAGE \
  78. "<html><head><title>Internal error</title></head><body>Internal error</body></html>"
  79. /**
  80. * Page returned for refused requests.
  81. */
  82. #define REQUEST_REFUSED_PAGE \
  83. "<html><head><title>Request refused</title></head><body>Request refused (file exists?)</body></html>"
  84. /**
  85. * Head of index page.
  86. */
  87. #define INDEX_PAGE_HEADER \
  88. "<html>\n<head><title>Welcome</title></head>\n<body>\n" \
  89. "<h1>Upload</h1>\n" \
  90. "<form method=\"POST\" enctype=\"multipart/form-data\" action=\"/\">\n" \
  91. "<dl><dt>Content type:</dt><dd>" \
  92. "<input type=\"radio\" name=\"category\" value=\"books\">Book</input>" \
  93. "<input type=\"radio\" name=\"category\" value=\"images\">Image</input>" \
  94. "<input type=\"radio\" name=\"category\" value=\"music\">Music</input>" \
  95. "<input type=\"radio\" name=\"category\" value=\"software\">Software</input>" \
  96. "<input type=\"radio\" name=\"category\" value=\"videos\">Videos</input>\n" \
  97. "<input type=\"radio\" name=\"category\" value=\"other\" checked>Other</input></dd>" \
  98. "<dt>Language:</dt><dd>" \
  99. "<input type=\"radio\" name=\"language\" value=\"no-lang\" checked>none</input>" \
  100. "<input type=\"radio\" name=\"language\" value=\"en\">English</input>" \
  101. "<input type=\"radio\" name=\"language\" value=\"de\">German</input>" \
  102. "<input type=\"radio\" name=\"language\" value=\"fr\">French</input>" \
  103. "<input type=\"radio\" name=\"language\" value=\"es\">Spanish</input></dd>\n" \
  104. "<dt>File:</dt><dd>" \
  105. "<input type=\"file\" name=\"upload\"/></dd></dl>" \
  106. "<input type=\"submit\" value=\"Send!\"/>\n" \
  107. "</form>\n" \
  108. "<h1>Download</h1>\n" \
  109. "<ol>\n"
  110. /**
  111. * Footer of index page.
  112. */
  113. #define INDEX_PAGE_FOOTER "</ol>\n</body>\n</html>"
  114. /**
  115. * NULL-terminated array of supported upload categories. Should match HTML
  116. * in the form.
  117. */
  118. static const char *const categories[] = {
  119. "books",
  120. "images",
  121. "music",
  122. "software",
  123. "videos",
  124. "other",
  125. NULL,
  126. };
  127. /**
  128. * Specification of a supported language.
  129. */
  130. struct Language
  131. {
  132. /**
  133. * Directory name for the language.
  134. */
  135. const char *dirname;
  136. /**
  137. * Long name for humans.
  138. */
  139. const char *longname;
  140. };
  141. /**
  142. * NULL-terminated array of supported upload categories. Should match HTML
  143. * in the form.
  144. */
  145. static const struct Language languages[] = {
  146. { "no-lang", "No language specified" },
  147. { "en", "English" },
  148. { "de", "German" },
  149. { "fr", "French" },
  150. { "es", "Spanish" },
  151. { NULL, NULL },
  152. };
  153. /**
  154. * Response returned if the requested file does not exist (or is not accessible).
  155. */
  156. static struct MHD_Response *file_not_found_response;
  157. /**
  158. * Response returned for internal errors.
  159. */
  160. static struct MHD_Response *internal_error_response;
  161. /**
  162. * Response returned for '/' (GET) to list the contents of the directory and allow upload.
  163. */
  164. static struct MHD_Response *cached_directory_response;
  165. /**
  166. * Response returned for refused uploads.
  167. */
  168. static struct MHD_Response *request_refused_response;
  169. /**
  170. * Mutex used when we update the cached directory response object.
  171. */
  172. static pthread_mutex_t mutex;
  173. #ifdef MHD_HAVE_LIBMAGIC
  174. /**
  175. * Global handle to MAGIC data.
  176. */
  177. static magic_t magic;
  178. #endif /* MHD_HAVE_LIBMAGIC */
  179. /**
  180. * Mark the given response as HTML for the browser.
  181. *
  182. * @param response response to mark
  183. */
  184. static void
  185. mark_as_html (struct MHD_Response *response)
  186. {
  187. (void) MHD_add_response_header (response,
  188. MHD_HTTP_HEADER_CONTENT_TYPE,
  189. "text/html");
  190. }
  191. /**
  192. * Replace the existing 'cached_directory_response' with the
  193. * given response.
  194. *
  195. * @param response new directory response
  196. */
  197. static void
  198. update_cached_response (struct MHD_Response *response)
  199. {
  200. (void) pthread_mutex_lock (&mutex);
  201. if (NULL != cached_directory_response)
  202. MHD_destroy_response (cached_directory_response);
  203. cached_directory_response = response;
  204. (void) pthread_mutex_unlock (&mutex);
  205. }
  206. /**
  207. * Context keeping the data for the response we're building.
  208. */
  209. struct ResponseDataContext
  210. {
  211. /**
  212. * Response data string.
  213. */
  214. char *buf;
  215. /**
  216. * Number of bytes allocated for 'buf'.
  217. */
  218. size_t buf_len;
  219. /**
  220. * Current position where we append to 'buf'. Must be smaller or equal to 'buf_len'.
  221. */
  222. size_t off;
  223. };
  224. /**
  225. * Create a listing of the files in 'dirname' in HTML.
  226. *
  227. * @param rdc where to store the list of files
  228. * @param dirname name of the directory to list
  229. * @return MHD_YES on success, MHD_NO on error
  230. */
  231. static enum MHD_Result
  232. list_directory (struct ResponseDataContext *rdc,
  233. const char *dirname)
  234. {
  235. char fullname[PATH_MAX];
  236. struct stat sbuf;
  237. DIR *dir;
  238. struct dirent *de;
  239. if (NULL == (dir = opendir (dirname)))
  240. return MHD_NO;
  241. while (NULL != (de = readdir (dir)))
  242. {
  243. int res;
  244. if ('.' == de->d_name[0])
  245. continue;
  246. if (sizeof (fullname) <= (size_t)
  247. snprintf (fullname, sizeof (fullname),
  248. "%s/%s",
  249. dirname, de->d_name))
  250. continue; /* ugh, file too long? how can this be!? */
  251. if (0 != stat (fullname, &sbuf))
  252. continue; /* ugh, failed to 'stat' */
  253. if (! S_ISREG (sbuf.st_mode))
  254. continue; /* not a regular file, skip */
  255. if (rdc->off + 1024 > rdc->buf_len)
  256. {
  257. void *r;
  258. if ( (2 * rdc->buf_len + 1024) < rdc->buf_len)
  259. break; /* more than SIZE_T _index_ size? Too big for us */
  260. rdc->buf_len = 2 * rdc->buf_len + 1024;
  261. if (NULL == (r = realloc (rdc->buf, rdc->buf_len)))
  262. break; /* out of memory */
  263. rdc->buf = r;
  264. }
  265. res = snprintf (&rdc->buf[rdc->off],
  266. rdc->buf_len - rdc->off,
  267. "<li><a href=\"/%s\">%s</a></li>\n",
  268. fullname,
  269. de->d_name);
  270. if (0 >= res)
  271. continue; /* snprintf() error */
  272. if (rdc->buf_len - rdc->off <= (size_t) res)
  273. continue; /* buffer too small?? */
  274. rdc->off += (size_t) res;
  275. }
  276. (void) closedir (dir);
  277. return MHD_YES;
  278. }
  279. /**
  280. * Re-scan our local directory and re-build the index.
  281. */
  282. static void
  283. update_directory (void)
  284. {
  285. static size_t initial_allocation = 32 * 1024; /* initial size for response buffer */
  286. struct MHD_Response *response;
  287. struct ResponseDataContext rdc;
  288. unsigned int language_idx;
  289. unsigned int category_idx;
  290. const struct Language *language;
  291. const char *category;
  292. char dir_name[128];
  293. struct stat sbuf;
  294. int res;
  295. size_t len;
  296. rdc.buf_len = initial_allocation;
  297. if (NULL == (rdc.buf = malloc (rdc.buf_len)))
  298. {
  299. update_cached_response (NULL);
  300. return;
  301. }
  302. len = strlen (INDEX_PAGE_HEADER);
  303. if (rdc.buf_len <= len)
  304. { /* buffer too small */
  305. free (rdc.buf);
  306. update_cached_response (NULL);
  307. return;
  308. }
  309. memcpy (rdc.buf, INDEX_PAGE_HEADER, len);
  310. rdc.off = len;
  311. for (language_idx = 0; NULL != languages[language_idx].dirname;
  312. language_idx++)
  313. {
  314. language = &languages[language_idx];
  315. if (0 != stat (language->dirname, &sbuf))
  316. continue; /* empty */
  317. /* we ensured always +1k room, filenames are ~256 bytes,
  318. so there is always still enough space for the header
  319. without need for an additional reallocation check. */
  320. res = snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
  321. "<h2>%s</h2>\n",
  322. language->longname);
  323. if (0 >= res)
  324. continue; /* snprintf() error */
  325. if (rdc.buf_len - rdc.off <= (size_t) res)
  326. continue; /* buffer too small?? */
  327. rdc.off += (size_t) res;
  328. for (category_idx = 0; NULL != categories[category_idx]; category_idx++)
  329. {
  330. category = categories[category_idx];
  331. res = snprintf (dir_name, sizeof (dir_name),
  332. "%s/%s",
  333. language->dirname,
  334. category);
  335. if ((0 >= res) || (sizeof (dir_name) <= (size_t) res))
  336. continue; /* cannot print dir name */
  337. if (0 != stat (dir_name, &sbuf))
  338. continue; /* empty */
  339. /* we ensured always +1k room, filenames are ~256 bytes,
  340. so there is always still enough space for the header
  341. without need for an additional reallocation check. */
  342. res = snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
  343. "<h3>%s</h3>\n",
  344. category);
  345. if (0 >= res)
  346. continue; /* snprintf() error */
  347. if (rdc.buf_len - rdc.off <= (size_t) res)
  348. continue; /* buffer too small?? */
  349. rdc.off += (size_t) res;
  350. if (MHD_NO == list_directory (&rdc, dir_name))
  351. {
  352. free (rdc.buf);
  353. update_cached_response (NULL);
  354. return;
  355. }
  356. }
  357. }
  358. /* we ensured always +1k room, filenames are ~256 bytes,
  359. so there is always still enough space for the footer
  360. without need for a final reallocation check. */
  361. len = strlen (INDEX_PAGE_FOOTER);
  362. if (rdc.buf_len - rdc.off <= len)
  363. { /* buffer too small */
  364. free (rdc.buf);
  365. update_cached_response (NULL);
  366. return;
  367. }
  368. memcpy (rdc.buf, INDEX_PAGE_FOOTER, len);
  369. rdc.off += len;
  370. initial_allocation = rdc.buf_len; /* remember for next time */
  371. response =
  372. MHD_create_response_from_buffer_with_free_callback (rdc.off,
  373. rdc.buf,
  374. &free);
  375. mark_as_html (response);
  376. #ifdef FORCE_CLOSE
  377. (void) MHD_add_response_header (response,
  378. MHD_HTTP_HEADER_CONNECTION,
  379. "close");
  380. #endif
  381. update_cached_response (response);
  382. }
  383. /**
  384. * Context we keep for an upload.
  385. */
  386. struct UploadContext
  387. {
  388. /**
  389. * Handle where we write the uploaded file to.
  390. */
  391. int fd;
  392. /**
  393. * Name of the file on disk (used to remove on errors).
  394. */
  395. char *filename;
  396. /**
  397. * Language for the upload.
  398. */
  399. char *language;
  400. /**
  401. * Category for the upload.
  402. */
  403. char *category;
  404. /**
  405. * Post processor we're using to process the upload.
  406. */
  407. struct MHD_PostProcessor *pp;
  408. /**
  409. * Handle to connection that we're processing the upload for.
  410. */
  411. struct MHD_Connection *connection;
  412. /**
  413. * Response to generate, NULL to use directory.
  414. */
  415. struct MHD_Response *response;
  416. };
  417. /**
  418. * Append the 'size' bytes from 'data' to '*ret', adding
  419. * 0-termination. If '*ret' is NULL, allocate an empty string first.
  420. *
  421. * @param ret string to update, NULL or 0-terminated
  422. * @param data data to append
  423. * @param size number of bytes in 'data'
  424. * @return #MHD_NO on allocation failure, #MHD_YES on success
  425. */
  426. static enum MHD_Result
  427. do_append (char **ret,
  428. const char *data,
  429. size_t size)
  430. {
  431. char *buf;
  432. size_t old_len;
  433. if (NULL == *ret)
  434. old_len = 0;
  435. else
  436. old_len = strlen (*ret);
  437. if (NULL == (buf = malloc (old_len + size + 1)))
  438. return MHD_NO;
  439. if (NULL != *ret)
  440. {
  441. memcpy (buf,
  442. *ret,
  443. old_len);
  444. free (*ret);
  445. }
  446. memcpy (&buf[old_len],
  447. data,
  448. size);
  449. buf[old_len + size] = '\0';
  450. *ret = buf;
  451. return MHD_YES;
  452. }
  453. /**
  454. * Iterator over key-value pairs where the value
  455. * maybe made available in increments and/or may
  456. * not be zero-terminated. Used for processing
  457. * POST data.
  458. *
  459. * @param cls user-specified closure
  460. * @param kind type of the value, always MHD_POSTDATA_KIND when called from MHD
  461. * @param key 0-terminated key for the value
  462. * @param filename name of the uploaded file, NULL if not known
  463. * @param content_type mime-type of the data, NULL if not known
  464. * @param transfer_encoding encoding of the data, NULL if not known
  465. * @param data pointer to size bytes of data at the
  466. * specified offset
  467. * @param off offset of data in the overall value
  468. * @param size number of bytes in data available
  469. * @return #MHD_YES to continue iterating,
  470. * #MHD_NO to abort the iteration
  471. */
  472. static enum MHD_Result
  473. process_upload_data (void *cls,
  474. enum MHD_ValueKind kind,
  475. const char *key,
  476. const char *filename,
  477. const char *content_type,
  478. const char *transfer_encoding,
  479. const char *data,
  480. uint64_t off,
  481. size_t size)
  482. {
  483. struct UploadContext *uc = cls;
  484. size_t i;
  485. int res;
  486. (void) kind; /* Unused. Silent compiler warning. */
  487. (void) content_type; /* Unused. Silent compiler warning. */
  488. (void) transfer_encoding; /* Unused. Silent compiler warning. */
  489. (void) off; /* Unused. Silent compiler warning. */
  490. if (0 == strcmp (key, "category"))
  491. return do_append (&uc->category, data, size);
  492. if (0 == strcmp (key, "language"))
  493. return do_append (&uc->language, data, size);
  494. if (0 != strcmp (key, "upload"))
  495. {
  496. fprintf (stderr,
  497. "Ignoring unexpected form value `%s'\n",
  498. key);
  499. return MHD_YES; /* ignore */
  500. }
  501. if (NULL == filename)
  502. {
  503. fprintf (stderr, "No filename, aborting upload.\n");
  504. return MHD_NO; /* no filename, error */
  505. }
  506. if ( (NULL == uc->category) ||
  507. (NULL == uc->language) )
  508. {
  509. fprintf (stderr,
  510. "Missing form data for upload `%s'\n",
  511. filename);
  512. uc->response = request_refused_response;
  513. return MHD_NO;
  514. }
  515. if (-1 == uc->fd)
  516. {
  517. char fn[PATH_MAX];
  518. if ( (NULL != strstr (filename, "..")) ||
  519. (NULL != strchr (filename, '/')) ||
  520. (NULL != strchr (filename, '\\')) )
  521. {
  522. uc->response = request_refused_response;
  523. return MHD_NO;
  524. }
  525. /* create directories -- if they don't exist already */
  526. #ifdef WINDOWS
  527. (void) mkdir (uc->language);
  528. #else
  529. (void) mkdir (uc->language, S_IRWXU);
  530. #endif
  531. snprintf (fn, sizeof (fn),
  532. "%s/%s",
  533. uc->language,
  534. uc->category);
  535. #ifdef WINDOWS
  536. (void) mkdir (fn);
  537. #else
  538. (void) mkdir (fn, S_IRWXU);
  539. #endif
  540. /* open file */
  541. res = snprintf (fn, sizeof (fn),
  542. "%s/%s/%s",
  543. uc->language,
  544. uc->category,
  545. filename);
  546. if ((0 >= res) || (sizeof (fn) <= (size_t) res))
  547. {
  548. uc->response = request_refused_response;
  549. return MHD_NO;
  550. }
  551. for (i = 0; i < (size_t) res; i++)
  552. if (! isprint ((unsigned char) fn[i]))
  553. fn[i] = '_';
  554. uc->fd = open (fn,
  555. O_CREAT | O_EXCL
  556. #ifdef O_LARGEFILE
  557. | O_LARGEFILE
  558. #endif
  559. | O_WRONLY,
  560. S_IRUSR | S_IWUSR);
  561. if (-1 == uc->fd)
  562. {
  563. fprintf (stderr,
  564. "Error opening file `%s' for upload: %s\n",
  565. fn,
  566. strerror (errno));
  567. uc->response = request_refused_response;
  568. return MHD_NO;
  569. }
  570. uc->filename = strdup (fn);
  571. }
  572. if ( (0 != size) &&
  573. #if ! defined(_WIN32) || defined(__CYGWIN__)
  574. (size != (size_t) write (uc->fd, data, size))
  575. #else /* Native W32 */
  576. (size != (size_t) write (uc->fd, data, (unsigned int) size))
  577. #endif /* Native W32 */
  578. )
  579. {
  580. /* write failed; likely: disk full */
  581. fprintf (stderr,
  582. "Error writing to file `%s': %s\n",
  583. uc->filename,
  584. strerror (errno));
  585. uc->response = internal_error_response;
  586. (void) close (uc->fd);
  587. uc->fd = -1;
  588. if (NULL != uc->filename)
  589. {
  590. unlink (uc->filename);
  591. free (uc->filename);
  592. uc->filename = NULL;
  593. }
  594. return MHD_NO;
  595. }
  596. return MHD_YES;
  597. }
  598. /**
  599. * Function called whenever a request was completed.
  600. * Used to clean up 'struct UploadContext' objects.
  601. *
  602. * @param cls client-defined closure, NULL
  603. * @param connection connection handle
  604. * @param req_cls value as set by the last call to
  605. * the MHD_AccessHandlerCallback, points to NULL if this was
  606. * not an upload
  607. * @param toe reason for request termination
  608. */
  609. static void
  610. response_completed_callback (void *cls,
  611. struct MHD_Connection *connection,
  612. void **req_cls,
  613. enum MHD_RequestTerminationCode toe)
  614. {
  615. struct UploadContext *uc = *req_cls;
  616. (void) cls; /* Unused. Silent compiler warning. */
  617. (void) connection; /* Unused. Silent compiler warning. */
  618. (void) toe; /* Unused. Silent compiler warning. */
  619. if (NULL == uc)
  620. return; /* this request wasn't an upload request */
  621. if (NULL != uc->pp)
  622. {
  623. MHD_destroy_post_processor (uc->pp);
  624. uc->pp = NULL;
  625. }
  626. if (-1 != uc->fd)
  627. {
  628. (void) close (uc->fd);
  629. if (NULL != uc->filename)
  630. {
  631. fprintf (stderr,
  632. "Upload of file `%s' failed (incomplete or aborted), removing file.\n",
  633. uc->filename);
  634. (void) unlink (uc->filename);
  635. }
  636. }
  637. if (NULL != uc->filename)
  638. free (uc->filename);
  639. free (uc);
  640. }
  641. /**
  642. * Return the current directory listing.
  643. *
  644. * @param connection connection to return the directory for
  645. * @return MHD_YES on success, MHD_NO on error
  646. */
  647. static enum MHD_Result
  648. return_directory_response (struct MHD_Connection *connection)
  649. {
  650. enum MHD_Result ret;
  651. (void) pthread_mutex_lock (&mutex);
  652. if (NULL == cached_directory_response)
  653. ret = MHD_queue_response (connection,
  654. MHD_HTTP_INTERNAL_SERVER_ERROR,
  655. internal_error_response);
  656. else
  657. ret = MHD_queue_response (connection,
  658. MHD_HTTP_OK,
  659. cached_directory_response);
  660. (void) pthread_mutex_unlock (&mutex);
  661. return ret;
  662. }
  663. /**
  664. * Main callback from MHD, used to generate the page.
  665. *
  666. * @param cls NULL
  667. * @param connection connection handle
  668. * @param url requested URL
  669. * @param method GET, PUT, POST, etc.
  670. * @param version HTTP version
  671. * @param upload_data data from upload (PUT/POST)
  672. * @param upload_data_size number of bytes in "upload_data"
  673. * @param req_cls our context
  674. * @return #MHD_YES on success, #MHD_NO to drop connection
  675. */
  676. static enum MHD_Result
  677. generate_page (void *cls,
  678. struct MHD_Connection *connection,
  679. const char *url,
  680. const char *method,
  681. const char *version,
  682. const char *upload_data,
  683. size_t *upload_data_size, void **req_cls)
  684. {
  685. struct MHD_Response *response;
  686. enum MHD_Result ret;
  687. int fd;
  688. struct stat buf;
  689. (void) cls; /* Unused. Silent compiler warning. */
  690. (void) version; /* Unused. Silent compiler warning. */
  691. if (0 != strcmp (url, "/"))
  692. {
  693. /* should be file download */
  694. #ifdef MHD_HAVE_LIBMAGIC
  695. char file_data[MAGIC_HEADER_SIZE];
  696. ssize_t got;
  697. #endif /* MHD_HAVE_LIBMAGIC */
  698. const char *mime;
  699. if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
  700. return MHD_NO; /* unexpected method (we're not polite...) */
  701. fd = -1;
  702. if ( (NULL == strstr (&url[1], "..")) &&
  703. ('/' != url[1]) )
  704. {
  705. fd = open (&url[1], O_RDONLY);
  706. if ( (-1 != fd) &&
  707. ( (0 != fstat (fd, &buf)) ||
  708. (! S_ISREG (buf.st_mode)) ) )
  709. {
  710. (void) close (fd);
  711. fd = -1;
  712. }
  713. }
  714. if (-1 == fd)
  715. return MHD_queue_response (connection,
  716. MHD_HTTP_NOT_FOUND,
  717. file_not_found_response);
  718. #ifdef MHD_HAVE_LIBMAGIC
  719. /* read beginning of the file to determine mime type */
  720. got = read (fd, file_data, sizeof (file_data));
  721. (void) lseek (fd, 0, SEEK_SET);
  722. if (-1 != got)
  723. mime = magic_buffer (magic, file_data, got);
  724. else
  725. #endif /* MHD_HAVE_LIBMAGIC */
  726. mime = NULL;
  727. if (NULL == (response = MHD_create_response_from_fd ((size_t) buf.st_size,
  728. fd)))
  729. {
  730. /* internal error (i.e. out of memory) */
  731. (void) close (fd);
  732. return MHD_NO;
  733. }
  734. /* add mime type if we had one */
  735. if (NULL != mime)
  736. (void) MHD_add_response_header (response,
  737. MHD_HTTP_HEADER_CONTENT_TYPE,
  738. mime);
  739. ret = MHD_queue_response (connection,
  740. MHD_HTTP_OK,
  741. response);
  742. MHD_destroy_response (response);
  743. return ret;
  744. }
  745. if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
  746. {
  747. /* upload! */
  748. struct UploadContext *uc = *req_cls;
  749. if (NULL == uc)
  750. {
  751. if (NULL == (uc = malloc (sizeof (struct UploadContext))))
  752. return MHD_NO; /* out of memory, close connection */
  753. memset (uc, 0, sizeof (struct UploadContext));
  754. uc->fd = -1;
  755. uc->connection = connection;
  756. uc->pp = MHD_create_post_processor (connection,
  757. 64 * 1024 /* buffer size */,
  758. &process_upload_data, uc);
  759. if (NULL == uc->pp)
  760. {
  761. /* out of memory, close connection */
  762. free (uc);
  763. return MHD_NO;
  764. }
  765. *req_cls = uc;
  766. return MHD_YES;
  767. }
  768. if (0 != *upload_data_size)
  769. {
  770. if (NULL == uc->response)
  771. (void) MHD_post_process (uc->pp,
  772. upload_data,
  773. *upload_data_size);
  774. *upload_data_size = 0;
  775. return MHD_YES;
  776. }
  777. /* end of upload, finish it! */
  778. MHD_destroy_post_processor (uc->pp);
  779. uc->pp = NULL;
  780. if (-1 != uc->fd)
  781. {
  782. close (uc->fd);
  783. uc->fd = -1;
  784. }
  785. if (NULL != uc->response)
  786. {
  787. return MHD_queue_response (connection,
  788. MHD_HTTP_FORBIDDEN,
  789. uc->response);
  790. }
  791. else
  792. {
  793. update_directory ();
  794. return return_directory_response (connection);
  795. }
  796. }
  797. if (0 == strcmp (method, MHD_HTTP_METHOD_GET))
  798. {
  799. return return_directory_response (connection);
  800. }
  801. /* unexpected request, refuse */
  802. return MHD_queue_response (connection,
  803. MHD_HTTP_FORBIDDEN,
  804. request_refused_response);
  805. }
  806. #ifndef MINGW
  807. /**
  808. * Function called if we get a SIGPIPE. Does nothing.
  809. *
  810. * @param sig will be SIGPIPE (ignored)
  811. */
  812. static void
  813. catcher (int sig)
  814. {
  815. (void) sig; /* Unused. Silent compiler warning. */
  816. /* do nothing */
  817. }
  818. /**
  819. * setup handlers to ignore SIGPIPE.
  820. */
  821. static void
  822. ignore_sigpipe (void)
  823. {
  824. struct sigaction oldsig;
  825. struct sigaction sig;
  826. sig.sa_handler = &catcher;
  827. sigemptyset (&sig.sa_mask);
  828. #ifdef SA_INTERRUPT
  829. sig.sa_flags = SA_INTERRUPT; /* SunOS */
  830. #else
  831. sig.sa_flags = SA_RESTART;
  832. #endif
  833. if (0 != sigaction (SIGPIPE, &sig, &oldsig))
  834. fprintf (stderr,
  835. "Failed to install SIGPIPE handler: %s\n", strerror (errno));
  836. }
  837. #endif
  838. /* test server key */
  839. static const char srv_signed_key_pem[] =
  840. "-----BEGIN PRIVATE KEY-----\n\
  841. MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCff7amw9zNSE+h\n\
  842. rOMhBrzbbsJluUP3gmd8nOKY5MUimoPkxmAXfp2L0il+MPZT/ZEmo11q0k6J2jfG\n\
  843. UBQ+oZW9ahNZ9gCDjbYlBblo/mqTai+LdeLO3qk53d0zrZKXvCO6sA3uKpG2WR+g\n\
  844. +sNKxfYpIHCpanqBU6O+degIV/+WKy3nQ2Fwp7K5HUNj1u0pg0QQ18yf68LTnKFU\n\
  845. HFjZmmaaopWki5wKSBieHivzQy6w+04HSTogHHRK/y/UcoJNSG7xnHmoPPo1vLT8\n\
  846. CMRIYnSSgU3wJ43XBJ80WxrC2dcoZjV2XZz+XdQwCD4ZrC1ihykcAmiQA+sauNm7\n\
  847. dztOMkGzAgMBAAECggEAIbKDzlvXDG/YkxnJqrKXt+yAmak4mNQuNP+YSCEdHSBz\n\
  848. +SOILa6MbnvqVETX5grOXdFp7SWdfjZiTj2g6VKOJkSA7iKxHRoVf2DkOTB3J8np\n\
  849. XZd8YaRdMGKVV1O2guQ20Dxd1RGdU18k9YfFNsj4Jtw5sTFTzHr1P0n9ybV9xCXp\n\
  850. znSxVfRg8U6TcMHoRDJR9EMKQMO4W3OQEmreEPoGt2/+kMuiHjclxLtbwDxKXTLP\n\
  851. pD0gdg3ibvlufk/ccKl/yAglDmd0dfW22oS7NgvRKUve7tzDxY1Q6O5v8BCnLFSW\n\
  852. D+z4hS1PzooYRXRkM0xYudvPkryPyu+1kEpw3fNsoQKBgQDRfXJo82XQvlX8WPdZ\n\
  853. Ts3PfBKKMVu3Wf8J3SYpuvYT816qR3ot6e4Ivv5ZCQkdDwzzBKe2jAv6JddMJIhx\n\
  854. pkGHc0KKOodd9HoBewOd8Td++hapJAGaGblhL5beIidLKjXDjLqtgoHRGlv5Cojo\n\
  855. zHa7Viel1eOPPcBumhp83oJ+mQKBgQDC6PmdETZdrW3QPm7ZXxRzF1vvpC55wmPg\n\
  856. pRfTRM059jzRzAk0QiBgVp3yk2a6Ob3mB2MLfQVDgzGf37h2oO07s5nspSFZTFnM\n\
  857. KgSjFy0xVOAVDLe+0VpbmLp1YUTYvdCNowaoTE7++5rpePUDu3BjAifx07/yaSB+\n\
  858. W+YPOfOuKwKBgQCGK6g5G5qcJSuBIaHZ6yTZvIdLRu2M8vDral5k3793a6m3uWvB\n\
  859. OFAh/eF9ONJDcD5E7zhTLEMHhXDs7YEN+QODMwjs6yuDu27gv97DK5j1lEsrLUpx\n\
  860. XgRjAE3KG2m7NF+WzO1K74khWZaKXHrvTvTEaxudlO3X8h7rN3u7ee9uEQKBgQC2\n\
  861. wI1zeTUZhsiFTlTPWfgppchdHPs6zUqq0wFQ5Zzr8Pa72+zxY+NJkU2NqinTCNsG\n\
  862. ePykQ/gQgk2gUrt595AYv2De40IuoYk9BlTMuql0LNniwsbykwd/BOgnsSlFdEy8\n\
  863. 0RQn70zOhgmNSg2qDzDklJvxghLi7zE5aV9//V1/ewKBgFRHHZN1a8q/v8AAOeoB\n\
  864. ROuXfgDDpxNNUKbzLL5MO5odgZGi61PBZlxffrSOqyZoJkzawXycNtoBP47tcVzT\n\
  865. QPq5ZOB3kjHTcN7dRLmPWjji9h4O3eHCX67XaPVMSWiMuNtOZIg2an06+jxGFhLE\n\
  866. qdJNJ1DkyUc9dN2cliX4R+rG\n\
  867. -----END PRIVATE KEY-----";
  868. /* test server CA signed certificates */
  869. static const char srv_signed_cert_pem[] =
  870. "-----BEGIN CERTIFICATE-----\n\
  871. MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n\
  872. DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n\
  873. LWxpYm1pY3JvaHR0cGQxITAfBgkqhkiG9w0BCQEWEm5vYm9keUBleGFtcGxlLm9y\n\
  874. ZzEQMA4GA1UEAwwHdGVzdC1DQTAgFw0yMjA0MjAxODQzMDJaGA8yMTIyMDMyNjE4\n\
  875. NDMwMlowZTELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwG\n\
  876. TW9zY293MRswGQYDVQQKDBJ0ZXN0LWxpYm1pY3JvaHR0cGQxFzAVBgNVBAMMDnRl\n\
  877. c3QtbWhkc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn3+2\n\
  878. psPczUhPoazjIQa8227CZblD94JnfJzimOTFIpqD5MZgF36di9IpfjD2U/2RJqNd\n\
  879. atJOido3xlAUPqGVvWoTWfYAg422JQW5aP5qk2ovi3Xizt6pOd3dM62Sl7wjurAN\n\
  880. 7iqRtlkfoPrDSsX2KSBwqWp6gVOjvnXoCFf/list50NhcKeyuR1DY9btKYNEENfM\n\
  881. n+vC05yhVBxY2ZpmmqKVpIucCkgYnh4r80MusPtOB0k6IBx0Sv8v1HKCTUhu8Zx5\n\
  882. qDz6Nby0/AjESGJ0koFN8CeN1wSfNFsawtnXKGY1dl2c/l3UMAg+GawtYocpHAJo\n\
  883. kAPrGrjZu3c7TjJBswIDAQABo4HmMIHjMAsGA1UdDwQEAwIFoDAMBgNVHRMBAf8E\n\
  884. AjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMBMDEGA1UdEQQqMCiCDnRlc3QtbWhk\n\
  885. c2VydmVyhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMB0GA1UdDgQWBBQ57Z06WJae\n\
  886. 8fJIHId4QGx/HsRgDDAoBglghkgBhvhCAQ0EGxYZVGVzdCBsaWJtaWNyb2h0dHBk\n\
  887. IHNlcnZlcjARBglghkgBhvhCAQEEBAMCBkAwHwYDVR0jBBgwFoAUWHVDwKVqMcOF\n\
  888. Nd0arI3/QB3W6SwwDQYJKoZIhvcNAQELBQADggIBAI7Lggm/XzpugV93H5+KV48x\n\
  889. X+Ct8unNmPCSzCaI5hAHGeBBJpvD0KME5oiJ5p2wfCtK5Dt9zzf0S0xYdRKqU8+N\n\
  890. aKIvPoU1hFixXLwTte1qOp6TviGvA9Xn2Fc4n36dLt6e9aiqDnqPbJgBwcVO82ll\n\
  891. HJxVr3WbrAcQTB3irFUMqgAke/Cva9Bw79VZgX4ghb5EnejDzuyup4pHGzV10Myv\n\
  892. hdg+VWZbAxpCe0S4eKmstZC7mWsFCLeoRTf/9Pk1kQ6+azbTuV/9QOBNfFi8QNyb\n\
  893. 18jUjmm8sc2HKo8miCGqb2sFqaGD918hfkWmR+fFkzQ3DZQrT+eYbKq2un3k0pMy\n\
  894. UySy8SRn1eadfab+GwBVb68I9TrPRMrJsIzysNXMX4iKYl2fFE/RSNnaHtPw0C8y\n\
  895. B7memyxPRl+H2xg6UjpoKYh3+8e44/XKm0rNIzXjrwA8f8gnw2TbqmMDkj1YqGnC\n\
  896. SCj5A27zUzaf2pT/YsnQXIWOJjVvbEI+YKj34wKWyTrXA093y8YI8T3mal7Kr9YM\n\
  897. WiIyPts0/aVeziM0Gunglz+8Rj1VesL52FTurobqusPgM/AME82+qb/qnxuPaCKj\n\
  898. OT1qAbIblaRuWqCsid8BzP7ZQiAnAWgMRSUg1gzDwSwRhrYQRRWAyn/Qipzec+27\n\
  899. /w0gW9EVWzFhsFeGEssi\n\
  900. -----END CERTIFICATE-----";
  901. /**
  902. * Entry point to demo. Note: this HTTP server will make all
  903. * files in the current directory and its subdirectories available
  904. * to anyone. Press ENTER to stop the server once it has started.
  905. *
  906. * @param argc number of arguments in argv
  907. * @param argv first and only argument should be the port number
  908. * @return 0 on success
  909. */
  910. int
  911. main (int argc, char *const *argv)
  912. {
  913. struct MHD_Daemon *d;
  914. unsigned int port;
  915. if ( (argc != 2) ||
  916. (1 != sscanf (argv[1], "%u", &port)) ||
  917. (UINT16_MAX < port) )
  918. {
  919. fprintf (stderr,
  920. "%s PORT\n", argv[0]);
  921. return 1;
  922. }
  923. #ifndef MINGW
  924. ignore_sigpipe ();
  925. #endif
  926. #ifdef MHD_HAVE_LIBMAGIC
  927. magic = magic_open (MAGIC_MIME_TYPE);
  928. (void) magic_load (magic, NULL);
  929. #endif /* MHD_HAVE_LIBMAGIC */
  930. (void) pthread_mutex_init (&mutex, NULL);
  931. file_not_found_response =
  932. MHD_create_response_from_buffer_static (strlen (FILE_NOT_FOUND_PAGE),
  933. (const void *) FILE_NOT_FOUND_PAGE);
  934. mark_as_html (file_not_found_response);
  935. request_refused_response =
  936. MHD_create_response_from_buffer_static (strlen (REQUEST_REFUSED_PAGE),
  937. (const void *)
  938. REQUEST_REFUSED_PAGE);
  939. mark_as_html (request_refused_response);
  940. internal_error_response =
  941. MHD_create_response_from_buffer_static (strlen (INTERNAL_ERROR_PAGE),
  942. (const void *) INTERNAL_ERROR_PAGE);
  943. mark_as_html (internal_error_response);
  944. update_directory ();
  945. d = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD
  946. | MHD_USE_ERROR_LOG | MHD_USE_TLS,
  947. (uint16_t) port,
  948. NULL, NULL,
  949. &generate_page, NULL,
  950. MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (256
  951. * 1024),
  952. #ifdef PRODUCTION
  953. MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) (64),
  954. #endif
  955. MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
  956. int) (120 /* seconds */),
  957. MHD_OPTION_THREAD_POOL_SIZE, (unsigned
  958. int) NUMBER_OF_THREADS,
  959. MHD_OPTION_NOTIFY_COMPLETED,
  960. &response_completed_callback, NULL,
  961. /* Optionally, the gnutls_load_file() can be used to
  962. load the key and the certificate from file. */
  963. MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
  964. MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
  965. MHD_OPTION_END);
  966. if (NULL == d)
  967. return 1;
  968. fprintf (stderr, "HTTP server running. Press ENTER to stop the server.\n");
  969. (void) getc (stdin);
  970. MHD_stop_daemon (d);
  971. MHD_destroy_response (file_not_found_response);
  972. MHD_destroy_response (request_refused_response);
  973. MHD_destroy_response (internal_error_response);
  974. update_cached_response (NULL);
  975. (void) pthread_mutex_destroy (&mutex);
  976. #ifdef MHD_HAVE_LIBMAGIC
  977. magic_close (magic);
  978. #endif /* MHD_HAVE_LIBMAGIC */
  979. return 0;
  980. }
  981. /* end of demo_https.c */