aboutsummaryrefslogtreecommitdiff
path: root/src/examples/demo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/examples/demo.c')
-rw-r--r--src/examples/demo.c748
1 files changed, 381 insertions, 367 deletions
diff --git a/src/examples/demo.c b/src/examples/demo.c
index e93fb34b..375f2a63 100644
--- a/src/examples/demo.c
+++ b/src/examples/demo.c
@@ -41,10 +41,10 @@
41#include <limits.h> 41#include <limits.h>
42#include <ctype.h> 42#include <ctype.h>
43 43
44#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2 44#if defined(CPU_COUNT) && (CPU_COUNT + 0) < 2
45#undef CPU_COUNT 45#undef CPU_COUNT
46#endif 46#endif
47#if !defined(CPU_COUNT) 47#if ! defined(CPU_COUNT)
48#define CPU_COUNT 2 48#define CPU_COUNT 2
49#endif 49#endif
50 50
@@ -73,46 +73,50 @@
73/** 73/**
74 * Page returned for file-not-found. 74 * Page returned for file-not-found.
75 */ 75 */
76#define FILE_NOT_FOUND_PAGE "<html><head><title>File not found</title></head><body>File not found</body></html>" 76#define FILE_NOT_FOUND_PAGE \
77 "<html><head><title>File not found</title></head><body>File not found</body></html>"
77 78
78 79
79/** 80/**
80 * Page returned for internal errors. 81 * Page returned for internal errors.
81 */ 82 */
82#define INTERNAL_ERROR_PAGE "<html><head><title>Internal error</title></head><body>Internal error</body></html>" 83#define INTERNAL_ERROR_PAGE \
84 "<html><head><title>Internal error</title></head><body>Internal error</body></html>"
83 85
84 86
85/** 87/**
86 * Page returned for refused requests. 88 * Page returned for refused requests.
87 */ 89 */
88#define REQUEST_REFUSED_PAGE "<html><head><title>Request refused</title></head><body>Request refused (file exists?)</body></html>" 90#define REQUEST_REFUSED_PAGE \
91 "<html><head><title>Request refused</title></head><body>Request refused (file exists?)</body></html>"
89 92
90 93
91/** 94/**
92 * Head of index page. 95 * Head of index page.
93 */ 96 */
94#define INDEX_PAGE_HEADER "<html>\n<head><title>Welcome</title></head>\n<body>\n"\ 97#define INDEX_PAGE_HEADER \
95 "<h1>Upload</h1>\n"\ 98 "<html>\n<head><title>Welcome</title></head>\n<body>\n" \
96 "<form method=\"POST\" enctype=\"multipart/form-data\" action=\"/\">\n"\ 99 "<h1>Upload</h1>\n" \
97 "<dl><dt>Content type:</dt><dd>"\ 100 "<form method=\"POST\" enctype=\"multipart/form-data\" action=\"/\">\n" \
98 "<input type=\"radio\" name=\"category\" value=\"books\">Book</input>"\ 101 "<dl><dt>Content type:</dt><dd>" \
99 "<input type=\"radio\" name=\"category\" value=\"images\">Image</input>"\ 102 "<input type=\"radio\" name=\"category\" value=\"books\">Book</input>" \
100 "<input type=\"radio\" name=\"category\" value=\"music\">Music</input>"\ 103 "<input type=\"radio\" name=\"category\" value=\"images\">Image</input>" \
101 "<input type=\"radio\" name=\"category\" value=\"software\">Software</input>"\ 104 "<input type=\"radio\" name=\"category\" value=\"music\">Music</input>" \
102 "<input type=\"radio\" name=\"category\" value=\"videos\">Videos</input>\n"\ 105 "<input type=\"radio\" name=\"category\" value=\"software\">Software</input>" \
103 "<input type=\"radio\" name=\"category\" value=\"other\" checked>Other</input></dd>"\ 106 "<input type=\"radio\" name=\"category\" value=\"videos\">Videos</input>\n" \
104 "<dt>Language:</dt><dd>"\ 107 "<input type=\"radio\" name=\"category\" value=\"other\" checked>Other</input></dd>" \
105 "<input type=\"radio\" name=\"language\" value=\"no-lang\" checked>none</input>"\ 108 "<dt>Language:</dt><dd>" \
106 "<input type=\"radio\" name=\"language\" value=\"en\">English</input>"\ 109 "<input type=\"radio\" name=\"language\" value=\"no-lang\" checked>none</input>" \
107 "<input type=\"radio\" name=\"language\" value=\"de\">German</input>"\ 110 "<input type=\"radio\" name=\"language\" value=\"en\">English</input>" \
108 "<input type=\"radio\" name=\"language\" value=\"fr\">French</input>"\ 111 "<input type=\"radio\" name=\"language\" value=\"de\">German</input>" \
109 "<input type=\"radio\" name=\"language\" value=\"es\">Spanish</input></dd>\n"\ 112 "<input type=\"radio\" name=\"language\" value=\"fr\">French</input>" \
110 "<dt>File:</dt><dd>"\ 113 "<input type=\"radio\" name=\"language\" value=\"es\">Spanish</input></dd>\n" \
111 "<input type=\"file\" name=\"upload\"/></dd></dl>"\ 114 "<dt>File:</dt><dd>" \
112 "<input type=\"submit\" value=\"Send!\"/>\n"\ 115 "<input type=\"file\" name=\"upload\"/></dd></dl>" \
113 "</form>\n"\ 116 "<input type=\"submit\" value=\"Send!\"/>\n" \
114 "<h1>Download</h1>\n"\ 117 "</form>\n" \
115 "<ol>\n" 118 "<h1>Download</h1>\n" \
119 "<ol>\n"
116 120
117/** 121/**
118 * Footer of index page. 122 * Footer of index page.
@@ -124,16 +128,15 @@
124 * NULL-terminated array of supported upload categories. Should match HTML 128 * NULL-terminated array of supported upload categories. Should match HTML
125 * in the form. 129 * in the form.
126 */ 130 */
127static const char * const categories[] = 131static const char *const categories[] = {
128 { 132 "books",
129 "books", 133 "images",
130 "images", 134 "music",
131 "music", 135 "software",
132 "software", 136 "videos",
133 "videos", 137 "other",
134 "other", 138 NULL,
135 NULL, 139};
136 };
137 140
138 141
139/** 142/**
@@ -157,15 +160,14 @@ struct Language
157 * NULL-terminated array of supported upload categories. Should match HTML 160 * NULL-terminated array of supported upload categories. Should match HTML
158 * in the form. 161 * in the form.
159 */ 162 */
160static const struct Language languages[] = 163static const struct Language languages[] = {
161 { 164 { "no-lang", "No language specified" },
162 { "no-lang", "No language specified" }, 165 { "en", "English" },
163 { "en", "English" }, 166 { "de", "German" },
164 { "de", "German" }, 167 { "fr", "French" },
165 { "fr", "French" }, 168 { "es", "Spanish" },
166 { "es", "Spanish" }, 169 { NULL, NULL },
167 { NULL, NULL }, 170};
168 };
169 171
170 172
171/** 173/**
@@ -210,8 +212,8 @@ static void
210mark_as_html (struct MHD_Response *response) 212mark_as_html (struct MHD_Response *response)
211{ 213{
212 (void) MHD_add_response_header (response, 214 (void) MHD_add_response_header (response,
213 MHD_HTTP_HEADER_CONTENT_TYPE, 215 MHD_HTTP_HEADER_CONTENT_TYPE,
214 "text/html"); 216 "text/html");
215} 217}
216 218
217 219
@@ -264,7 +266,7 @@ struct ResponseDataContext
264 */ 266 */
265static int 267static int
266list_directory (struct ResponseDataContext *rdc, 268list_directory (struct ResponseDataContext *rdc,
267 const char *dirname) 269 const char *dirname)
268{ 270{
269 char fullname[PATH_MAX]; 271 char fullname[PATH_MAX];
270 struct stat sbuf; 272 struct stat sbuf;
@@ -274,35 +276,35 @@ list_directory (struct ResponseDataContext *rdc,
274 if (NULL == (dir = opendir (dirname))) 276 if (NULL == (dir = opendir (dirname)))
275 return MHD_NO; 277 return MHD_NO;
276 while (NULL != (de = readdir (dir))) 278 while (NULL != (de = readdir (dir)))
279 {
280 if ('.' == de->d_name[0])
281 continue;
282 if (sizeof (fullname) <= (unsigned int)
283 snprintf (fullname, sizeof (fullname),
284 "%s/%s",
285 dirname, de->d_name))
286 continue; /* ugh, file too long? how can this be!? */
287 if (0 != stat (fullname, &sbuf))
288 continue; /* ugh, failed to 'stat' */
289 if (! S_ISREG (sbuf.st_mode))
290 continue; /* not a regular file, skip */
291 if (rdc->off + 1024 > rdc->buf_len)
277 { 292 {
278 if ('.' == de->d_name[0]) 293 void *r;
279 continue; 294
280 if (sizeof (fullname) <= (unsigned int) 295 if ( (2 * rdc->buf_len + 1024) < rdc->buf_len)
281 snprintf (fullname, sizeof (fullname), 296 break; /* more than SIZE_T _index_ size? Too big for us */
282 "%s/%s", 297 rdc->buf_len = 2 * rdc->buf_len + 1024;
283 dirname, de->d_name)) 298 if (NULL == (r = realloc (rdc->buf, rdc->buf_len)))
284 continue; /* ugh, file too long? how can this be!? */ 299 break; /* out of memory */
285 if (0 != stat (fullname, &sbuf)) 300 rdc->buf = r;
286 continue; /* ugh, failed to 'stat' */
287 if (! S_ISREG (sbuf.st_mode))
288 continue; /* not a regular file, skip */
289 if (rdc->off + 1024 > rdc->buf_len)
290 {
291 void *r;
292
293 if ( (2 * rdc->buf_len + 1024) < rdc->buf_len)
294 break; /* more than SIZE_T _index_ size? Too big for us */
295 rdc->buf_len = 2 * rdc->buf_len + 1024;
296 if (NULL == (r = realloc (rdc->buf, rdc->buf_len)))
297 break; /* out of memory */
298 rdc->buf = r;
299 }
300 rdc->off += snprintf (&rdc->buf[rdc->off],
301 rdc->buf_len - rdc->off,
302 "<li><a href=\"/%s\">%s</a></li>\n",
303 fullname,
304 de->d_name);
305 } 301 }
302 rdc->off += snprintf (&rdc->buf[rdc->off],
303 rdc->buf_len - rdc->off,
304 "<li><a href=\"/%s\">%s</a></li>\n",
305 fullname,
306 de->d_name);
307 }
306 (void) closedir (dir); 308 (void) closedir (dir);
307 return MHD_YES; 309 return MHD_YES;
308} 310}
@@ -326,65 +328,66 @@ update_directory ()
326 328
327 rdc.buf_len = initial_allocation; 329 rdc.buf_len = initial_allocation;
328 if (NULL == (rdc.buf = malloc (rdc.buf_len))) 330 if (NULL == (rdc.buf = malloc (rdc.buf_len)))
329 { 331 {
330 update_cached_response (NULL); 332 update_cached_response (NULL);
331 return; 333 return;
332 } 334 }
333 rdc.off = snprintf (rdc.buf, rdc.buf_len, 335 rdc.off = snprintf (rdc.buf, rdc.buf_len,
334 "%s", 336 "%s",
335 INDEX_PAGE_HEADER); 337 INDEX_PAGE_HEADER);
336 for (language_idx = 0; NULL != languages[language_idx].dirname; language_idx++) 338 for (language_idx = 0; NULL != languages[language_idx].dirname;
339 language_idx++)
340 {
341 language = &languages[language_idx];
342
343 if (0 != stat (language->dirname, &sbuf))
344 continue; /* empty */
345 /* we ensured always +1k room, filenames are ~256 bytes,
346 so there is always still enough space for the header
347 without need for an additional reallocation check. */
348 rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
349 "<h2>%s</h2>\n",
350 language->longname);
351 for (category_idx = 0; NULL != categories[category_idx]; category_idx++)
337 { 352 {
338 language = &languages[language_idx]; 353 category = categories[category_idx];
354 snprintf (dir_name, sizeof (dir_name),
355 "%s/%s",
356 language->dirname,
357 category);
358 if (0 != stat (dir_name, &sbuf))
359 continue; /* empty */
339 360
340 if (0 != stat (language->dirname, &sbuf))
341 continue; /* empty */
342 /* we ensured always +1k room, filenames are ~256 bytes, 361 /* we ensured always +1k room, filenames are ~256 bytes,
343 so there is always still enough space for the header 362 so there is always still enough space for the header
344 without need for an additional reallocation check. */ 363 without need for an additional reallocation check. */
345 rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off, 364 rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
346 "<h2>%s</h2>\n", 365 "<h3>%s</h3>\n",
347 language->longname); 366 category);
348 for (category_idx = 0; NULL != categories[category_idx]; category_idx++) 367
349 { 368 if (MHD_NO == list_directory (&rdc, dir_name))
350 category = categories[category_idx]; 369 {
351 snprintf (dir_name, sizeof (dir_name), 370 free (rdc.buf);
352 "%s/%s", 371 update_cached_response (NULL);
353 language->dirname, 372 return;
354 category); 373 }
355 if (0 != stat (dir_name, &sbuf))
356 continue; /* empty */
357
358 /* we ensured always +1k room, filenames are ~256 bytes,
359 so there is always still enough space for the header
360 without need for an additional reallocation check. */
361 rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
362 "<h3>%s</h3>\n",
363 category);
364
365 if (MHD_NO == list_directory (&rdc, dir_name))
366 {
367 free (rdc.buf);
368 update_cached_response (NULL);
369 return;
370 }
371 }
372 } 374 }
375 }
373 /* we ensured always +1k room, filenames are ~256 bytes, 376 /* we ensured always +1k room, filenames are ~256 bytes,
374 so there is always still enough space for the footer 377 so there is always still enough space for the footer
375 without need for a final reallocation check. */ 378 without need for a final reallocation check. */
376 rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off, 379 rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
377 "%s", 380 "%s",
378 INDEX_PAGE_FOOTER); 381 INDEX_PAGE_FOOTER);
379 initial_allocation = rdc.buf_len; /* remember for next time */ 382 initial_allocation = rdc.buf_len; /* remember for next time */
380 response = MHD_create_response_from_buffer (rdc.off, 383 response = MHD_create_response_from_buffer (rdc.off,
381 rdc.buf, 384 rdc.buf,
382 MHD_RESPMEM_MUST_FREE); 385 MHD_RESPMEM_MUST_FREE);
383 mark_as_html (response); 386 mark_as_html (response);
384#if FORCE_CLOSE 387#if FORCE_CLOSE
385 (void) MHD_add_response_header (response, 388 (void) MHD_add_response_header (response,
386 MHD_HTTP_HEADER_CONNECTION, 389 MHD_HTTP_HEADER_CONNECTION,
387 "close"); 390 "close");
388#endif 391#endif
389 update_cached_response (response); 392 update_cached_response (response);
390} 393}
@@ -443,8 +446,8 @@ struct UploadContext
443 */ 446 */
444static int 447static int
445do_append (char **ret, 448do_append (char **ret,
446 const char *data, 449 const char *data,
447 size_t size) 450 size_t size)
448{ 451{
449 char *buf; 452 char *buf;
450 size_t old_len; 453 size_t old_len;
@@ -456,15 +459,15 @@ do_append (char **ret,
456 if (NULL == (buf = malloc (old_len + size + 1))) 459 if (NULL == (buf = malloc (old_len + size + 1)))
457 return MHD_NO; 460 return MHD_NO;
458 if (NULL != *ret) 461 if (NULL != *ret)
459 { 462 {
460 memcpy (buf, 463 memcpy (buf,
461 *ret, 464 *ret,
462 old_len); 465 old_len);
463 free (*ret); 466 free (*ret);
464 } 467 }
465 memcpy (&buf[old_len], 468 memcpy (&buf[old_len],
466 data, 469 data,
467 size); 470 size);
468 buf[old_len + size] = '\0'; 471 buf[old_len + size] = '\0';
469 *ret = buf; 472 *ret = buf;
470 return MHD_YES; 473 return MHD_YES;
@@ -492,119 +495,119 @@ do_append (char **ret,
492 */ 495 */
493static int 496static int
494process_upload_data (void *cls, 497process_upload_data (void *cls,
495 enum MHD_ValueKind kind, 498 enum MHD_ValueKind kind,
496 const char *key, 499 const char *key,
497 const char *filename, 500 const char *filename,
498 const char *content_type, 501 const char *content_type,
499 const char *transfer_encoding, 502 const char *transfer_encoding,
500 const char *data, 503 const char *data,
501 uint64_t off, 504 uint64_t off,
502 size_t size) 505 size_t size)
503{ 506{
504 struct UploadContext *uc = cls; 507 struct UploadContext *uc = cls;
505 int i; 508 int i;
506 (void)kind; /* Unused. Silent compiler warning. */ 509 (void) kind; /* Unused. Silent compiler warning. */
507 (void)content_type; /* Unused. Silent compiler warning. */ 510 (void) content_type; /* Unused. Silent compiler warning. */
508 (void)transfer_encoding; /* Unused. Silent compiler warning. */ 511 (void) transfer_encoding; /* Unused. Silent compiler warning. */
509 (void)off; /* Unused. Silent compiler warning. */ 512 (void) off; /* Unused. Silent compiler warning. */
510 513
511 if (0 == strcmp (key, "category")) 514 if (0 == strcmp (key, "category"))
512 return do_append (&uc->category, data, size); 515 return do_append (&uc->category, data, size);
513 if (0 == strcmp (key, "language")) 516 if (0 == strcmp (key, "language"))
514 return do_append (&uc->language, data, size); 517 return do_append (&uc->language, data, size);
515 if (0 != strcmp (key, "upload")) 518 if (0 != strcmp (key, "upload"))
516 { 519 {
517 fprintf (stderr, 520 fprintf (stderr,
518 "Ignoring unexpected form value `%s'\n", 521 "Ignoring unexpected form value `%s'\n",
519 key); 522 key);
520 return MHD_YES; /* ignore */ 523 return MHD_YES; /* ignore */
521 } 524 }
522 if (NULL == filename) 525 if (NULL == filename)
523 { 526 {
524 fprintf (stderr, "No filename, aborting upload\n"); 527 fprintf (stderr, "No filename, aborting upload\n");
525 return MHD_NO; /* no filename, error */ 528 return MHD_NO; /* no filename, error */
526 } 529 }
527 if ( (NULL == uc->category) || 530 if ( (NULL == uc->category) ||
528 (NULL == uc->language) ) 531 (NULL == uc->language) )
532 {
533 fprintf (stderr,
534 "Missing form data for upload `%s'\n",
535 filename);
536 uc->response = request_refused_response;
537 return MHD_NO;
538 }
539 if (-1 == uc->fd)
540 {
541 char fn[PATH_MAX];
542
543 if ( (NULL != strstr (filename, "..")) ||
544 (NULL != strchr (filename, '/')) ||
545 (NULL != strchr (filename, '\\')) )
529 { 546 {
530 fprintf (stderr,
531 "Missing form data for upload `%s'\n",
532 filename);
533 uc->response = request_refused_response; 547 uc->response = request_refused_response;
534 return MHD_NO; 548 return MHD_NO;
535 } 549 }
536 if (-1 == uc->fd) 550 /* create directories -- if they don't exist already */
537 {
538 char fn[PATH_MAX];
539
540 if ( (NULL != strstr (filename, "..")) ||
541 (NULL != strchr (filename, '/')) ||
542 (NULL != strchr (filename, '\\')) )
543 {
544 uc->response = request_refused_response;
545 return MHD_NO;
546 }
547 /* create directories -- if they don't exist already */
548#ifdef WINDOWS 551#ifdef WINDOWS
549 (void) mkdir (uc->language); 552 (void) mkdir (uc->language);
550#else 553#else
551 (void) mkdir (uc->language, S_IRWXU); 554 (void) mkdir (uc->language, S_IRWXU);
552#endif 555#endif
553 snprintf (fn, sizeof (fn), 556 snprintf (fn, sizeof (fn),
554 "%s/%s", 557 "%s/%s",
555 uc->language, 558 uc->language,
556 uc->category); 559 uc->category);
557#ifdef WINDOWS 560#ifdef WINDOWS
558 (void) mkdir (fn); 561 (void) mkdir (fn);
559#else 562#else
560 (void) mkdir (fn, S_IRWXU); 563 (void) mkdir (fn, S_IRWXU);
561#endif 564#endif
562 /* open file */ 565 /* open file */
563 snprintf (fn, sizeof (fn), 566 snprintf (fn, sizeof (fn),
564 "%s/%s/%s", 567 "%s/%s/%s",
565 uc->language, 568 uc->language,
566 uc->category, 569 uc->category,
567 filename); 570 filename);
568 for (i=strlen (fn)-1;i>=0;i--) 571 for (i = strlen (fn) - 1; i>=0; i--)
569 if (! isprint ((unsigned char) fn[i])) 572 if (! isprint ((unsigned char) fn[i]))
570 fn[i] = '_'; 573 fn[i] = '_';
571 uc->fd = open (fn, 574 uc->fd = open (fn,
572 O_CREAT | O_EXCL 575 O_CREAT | O_EXCL
573#if O_LARGEFILE 576#if O_LARGEFILE
574 | O_LARGEFILE 577 | O_LARGEFILE
575#endif 578#endif
576 | O_WRONLY, 579 | O_WRONLY,
577 S_IRUSR | S_IWUSR); 580 S_IRUSR | S_IWUSR);
578 if (-1 == uc->fd) 581 if (-1 == uc->fd)
579 { 582 {
580 fprintf (stderr, 583 fprintf (stderr,
581 "Error opening file `%s' for upload: %s\n", 584 "Error opening file `%s' for upload: %s\n",
582 fn, 585 fn,
583 strerror (errno)); 586 strerror (errno));
584 uc->response = request_refused_response; 587 uc->response = request_refused_response;
585 return MHD_NO; 588 return MHD_NO;
586 }
587 uc->filename = strdup (fn);
588 } 589 }
590 uc->filename = strdup (fn);
591 }
589 if ( (0 != size) && 592 if ( (0 != size) &&
590 (size != (size_t) write (uc->fd, data, size)) ) 593 (size != (size_t) write (uc->fd, data, size)) )
594 {
595 /* write failed; likely: disk full */
596 fprintf (stderr,
597 "Error writing to file `%s': %s\n",
598 uc->filename,
599 strerror (errno));
600 uc->response = internal_error_response;
601 (void) close (uc->fd);
602 uc->fd = -1;
603 if (NULL != uc->filename)
591 { 604 {
592 /* write failed; likely: disk full */ 605 unlink (uc->filename);
593 fprintf (stderr, 606 free (uc->filename);
594 "Error writing to file `%s': %s\n", 607 uc->filename = NULL;
595 uc->filename,
596 strerror (errno));
597 uc->response = internal_error_response;
598 (void) close (uc->fd);
599 uc->fd = -1;
600 if (NULL != uc->filename)
601 {
602 unlink (uc->filename);
603 free (uc->filename);
604 uc->filename = NULL;
605 }
606 return MHD_NO;
607 } 608 }
609 return MHD_NO;
610 }
608 return MHD_YES; 611 return MHD_YES;
609} 612}
610 613
@@ -622,32 +625,32 @@ process_upload_data (void *cls,
622 */ 625 */
623static void 626static void
624response_completed_callback (void *cls, 627response_completed_callback (void *cls,
625 struct MHD_Connection *connection, 628 struct MHD_Connection *connection,
626 void **con_cls, 629 void **con_cls,
627 enum MHD_RequestTerminationCode toe) 630 enum MHD_RequestTerminationCode toe)
628{ 631{
629 struct UploadContext *uc = *con_cls; 632 struct UploadContext *uc = *con_cls;
630 (void)cls; /* Unused. Silent compiler warning. */ 633 (void) cls; /* Unused. Silent compiler warning. */
631 (void)connection; /* Unused. Silent compiler warning. */ 634 (void) connection; /* Unused. Silent compiler warning. */
632 (void)toe; /* Unused. Silent compiler warning. */ 635 (void) toe; /* Unused. Silent compiler warning. */
633 636
634 if (NULL == uc) 637 if (NULL == uc)
635 return; /* this request wasn't an upload request */ 638 return; /* this request wasn't an upload request */
636 if (NULL != uc->pp) 639 if (NULL != uc->pp)
637 { 640 {
638 MHD_destroy_post_processor (uc->pp); 641 MHD_destroy_post_processor (uc->pp);
639 uc->pp = NULL; 642 uc->pp = NULL;
640 } 643 }
641 if (-1 != uc->fd) 644 if (-1 != uc->fd)
642 { 645 {
643 (void) close (uc->fd); 646 (void) close (uc->fd);
644 if (NULL != uc->filename) 647 if (NULL != uc->filename)
645 { 648 {
646 fprintf (stderr, 649 fprintf (stderr,
647 "Upload of file `%s' failed (incomplete or aborted), removing file.\n", 650 "Upload of file `%s' failed (incomplete or aborted), removing file.\n",
648 uc->filename); 651 uc->filename);
649 (void) unlink (uc->filename); 652 (void) unlink (uc->filename);
650 } 653 }
651 } 654 }
652 if (NULL != uc->filename) 655 if (NULL != uc->filename)
653 free (uc->filename); 656 free (uc->filename);
@@ -669,12 +672,12 @@ return_directory_response (struct MHD_Connection *connection)
669 (void) pthread_mutex_lock (&mutex); 672 (void) pthread_mutex_lock (&mutex);
670 if (NULL == cached_directory_response) 673 if (NULL == cached_directory_response)
671 ret = MHD_queue_response (connection, 674 ret = MHD_queue_response (connection,
672 MHD_HTTP_INTERNAL_SERVER_ERROR, 675 MHD_HTTP_INTERNAL_SERVER_ERROR,
673 internal_error_response); 676 internal_error_response);
674 else 677 else
675 ret = MHD_queue_response (connection, 678 ret = MHD_queue_response (connection,
676 MHD_HTTP_OK, 679 MHD_HTTP_OK,
677 cached_directory_response); 680 cached_directory_response);
678 (void) pthread_mutex_unlock (&mutex); 681 (void) pthread_mutex_unlock (&mutex);
679 return ret; 682 return ret;
680} 683}
@@ -695,12 +698,12 @@ return_directory_response (struct MHD_Connection *connection)
695 */ 698 */
696static int 699static int
697generate_page (void *cls, 700generate_page (void *cls,
698 struct MHD_Connection *connection, 701 struct MHD_Connection *connection,
699 const char *url, 702 const char *url,
700 const char *method, 703 const char *method,
701 const char *version, 704 const char *version,
702 const char *upload_data, 705 const char *upload_data,
703 size_t *upload_data_size, void **ptr) 706 size_t *upload_data_size, void **ptr)
704{ 707{
705 struct MHD_Response *response; 708 struct MHD_Response *response;
706 int ret; 709 int ret;
@@ -710,117 +713,117 @@ generate_page (void *cls,
710 (void) version; /* Unused. Silent compiler warning. */ 713 (void) version; /* Unused. Silent compiler warning. */
711 714
712 if (0 != strcmp (url, "/")) 715 if (0 != strcmp (url, "/"))
713 { 716 {
714 /* should be file download */ 717 /* should be file download */
715#ifdef MHD_HAVE_LIBMAGIC 718#ifdef MHD_HAVE_LIBMAGIC
716 char file_data[MAGIC_HEADER_SIZE]; 719 char file_data[MAGIC_HEADER_SIZE];
717 ssize_t got; 720 ssize_t got;
718#endif /* MHD_HAVE_LIBMAGIC */ 721#endif /* MHD_HAVE_LIBMAGIC */
719 const char *mime; 722 const char *mime;
720 723
721 if ( (0 != strcmp (method, MHD_HTTP_METHOD_GET)) && 724 if ( (0 != strcmp (method, MHD_HTTP_METHOD_GET)) &&
722 (0 != strcmp (method, MHD_HTTP_METHOD_HEAD)) ) 725 (0 != strcmp (method, MHD_HTTP_METHOD_HEAD)) )
723 return MHD_NO; /* unexpected method (we're not polite...) */ 726 return MHD_NO; /* unexpected method (we're not polite...) */
724 fd = -1; 727 fd = -1;
725 if ( (NULL == strstr (&url[1], "..")) && 728 if ( (NULL == strstr (&url[1], "..")) &&
726 ('/' != url[1]) ) 729 ('/' != url[1]) )
727 { 730 {
728 fd = open (&url[1], O_RDONLY); 731 fd = open (&url[1], O_RDONLY);
729 if ( (-1 != fd) && 732 if ( (-1 != fd) &&
730 ( (0 != fstat (fd, &buf)) || 733 ( (0 != fstat (fd, &buf)) ||
731 (! S_ISREG (buf.st_mode)) ) ) 734 (! S_ISREG (buf.st_mode)) ) )
732 { 735 {
733 (void) close (fd); 736 (void) close (fd);
734 fd = -1; 737 fd = -1;
735 } 738 }
736 } 739 }
737 if (-1 == fd) 740 if (-1 == fd)
738 return MHD_queue_response (connection, 741 return MHD_queue_response (connection,
739 MHD_HTTP_NOT_FOUND, 742 MHD_HTTP_NOT_FOUND,
740 file_not_found_response); 743 file_not_found_response);
741#ifdef MHD_HAVE_LIBMAGIC 744#ifdef MHD_HAVE_LIBMAGIC
742 /* read beginning of the file to determine mime type */ 745 /* read beginning of the file to determine mime type */
743 got = read (fd, file_data, sizeof (file_data)); 746 got = read (fd, file_data, sizeof (file_data));
744 (void) lseek (fd, 0, SEEK_SET); 747 (void) lseek (fd, 0, SEEK_SET);
745 if (-1 != got) 748 if (-1 != got)
746 mime = magic_buffer (magic, file_data, got); 749 mime = magic_buffer (magic, file_data, got);
747 else 750 else
748#endif /* MHD_HAVE_LIBMAGIC */ 751#endif /* MHD_HAVE_LIBMAGIC */
749 mime = NULL; 752 mime = NULL;
750 753
751 if (NULL == (response = MHD_create_response_from_fd (buf.st_size, 754 if (NULL == (response = MHD_create_response_from_fd (buf.st_size,
752 fd))) 755 fd)))
753 { 756 {
754 /* internal error (i.e. out of memory) */ 757 /* internal error (i.e. out of memory) */
755 (void) close (fd); 758 (void) close (fd);
756 return MHD_NO; 759 return MHD_NO;
757 }
758
759 /* add mime type if we had one */
760 if (NULL != mime)
761 (void) MHD_add_response_header (response,
762 MHD_HTTP_HEADER_CONTENT_TYPE,
763 mime);
764 ret = MHD_queue_response (connection,
765 MHD_HTTP_OK,
766 response);
767 MHD_destroy_response (response);
768 return ret;
769 } 760 }
770 761
762 /* add mime type if we had one */
763 if (NULL != mime)
764 (void) MHD_add_response_header (response,
765 MHD_HTTP_HEADER_CONTENT_TYPE,
766 mime);
767 ret = MHD_queue_response (connection,
768 MHD_HTTP_OK,
769 response);
770 MHD_destroy_response (response);
771 return ret;
772 }
773
771 if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) 774 if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
775 {
776 /* upload! */
777 struct UploadContext *uc = *ptr;
778
779 if (NULL == uc)
780 {
781 if (NULL == (uc = malloc (sizeof (struct UploadContext))))
782 return MHD_NO; /* out of memory, close connection */
783 memset (uc, 0, sizeof (struct UploadContext));
784 uc->fd = -1;
785 uc->connection = connection;
786 uc->pp = MHD_create_post_processor (connection,
787 64 * 1024 /* buffer size */,
788 &process_upload_data, uc);
789 if (NULL == uc->pp)
790 {
791 /* out of memory, close connection */
792 free (uc);
793 return MHD_NO;
794 }
795 *ptr = uc;
796 return MHD_YES;
797 }
798 if (0 != *upload_data_size)
799 {
800 if (NULL == uc->response)
801 (void) MHD_post_process (uc->pp,
802 upload_data,
803 *upload_data_size);
804 *upload_data_size = 0;
805 return MHD_YES;
806 }
807 /* end of upload, finish it! */
808 MHD_destroy_post_processor (uc->pp);
809 uc->pp = NULL;
810 if (-1 != uc->fd)
811 {
812 close (uc->fd);
813 uc->fd = -1;
814 }
815 if (NULL != uc->response)
816 {
817 return MHD_queue_response (connection,
818 MHD_HTTP_FORBIDDEN,
819 uc->response);
820 }
821 else
772 { 822 {
773 /* upload! */ 823 update_directory ();
774 struct UploadContext *uc = *ptr; 824 return return_directory_response (connection);
775
776 if (NULL == uc)
777 {
778 if (NULL == (uc = malloc (sizeof (struct UploadContext))))
779 return MHD_NO; /* out of memory, close connection */
780 memset (uc, 0, sizeof (struct UploadContext));
781 uc->fd = -1;
782 uc->connection = connection;
783 uc->pp = MHD_create_post_processor (connection,
784 64 * 1024 /* buffer size */,
785 &process_upload_data, uc);
786 if (NULL == uc->pp)
787 {
788 /* out of memory, close connection */
789 free (uc);
790 return MHD_NO;
791 }
792 *ptr = uc;
793 return MHD_YES;
794 }
795 if (0 != *upload_data_size)
796 {
797 if (NULL == uc->response)
798 (void) MHD_post_process (uc->pp,
799 upload_data,
800 *upload_data_size);
801 *upload_data_size = 0;
802 return MHD_YES;
803 }
804 /* end of upload, finish it! */
805 MHD_destroy_post_processor (uc->pp);
806 uc->pp = NULL;
807 if (-1 != uc->fd)
808 {
809 close (uc->fd);
810 uc->fd = -1;
811 }
812 if (NULL != uc->response)
813 {
814 return MHD_queue_response (connection,
815 MHD_HTTP_FORBIDDEN,
816 uc->response);
817 }
818 else
819 {
820 update_directory ();
821 return return_directory_response (connection);
822 }
823 } 825 }
826 }
824 if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) || 827 if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
825 (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) ) 828 (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
826 { 829 {
@@ -829,8 +832,8 @@ generate_page (void *cls,
829 832
830 /* unexpected request, refuse */ 833 /* unexpected request, refuse */
831 return MHD_queue_response (connection, 834 return MHD_queue_response (connection,
832 MHD_HTTP_FORBIDDEN, 835 MHD_HTTP_FORBIDDEN,
833 request_refused_response); 836 request_refused_response);
834} 837}
835 838
836 839
@@ -843,7 +846,7 @@ generate_page (void *cls,
843static void 846static void
844catcher (int sig) 847catcher (int sig)
845{ 848{
846 (void)sig; /* Unused. Silent compiler warning. */ 849 (void) sig; /* Unused. Silent compiler warning. */
847 /* do nothing */ 850 /* do nothing */
848} 851}
849 852
@@ -889,11 +892,11 @@ main (int argc, char *const *argv)
889 if ( (argc != 2) || 892 if ( (argc != 2) ||
890 (1 != sscanf (argv[1], "%u", &port)) || 893 (1 != sscanf (argv[1], "%u", &port)) ||
891 (UINT16_MAX < port) ) 894 (UINT16_MAX < port) )
892 { 895 {
893 fprintf (stderr, 896 fprintf (stderr,
894 "%s PORT\n", argv[0]); 897 "%s PORT\n", argv[0]);
895 return 1; 898 return 1;
896 } 899 }
897#ifndef MINGW 900#ifndef MINGW
898 ignore_sigpipe (); 901 ignore_sigpipe ();
899#endif 902#endif
@@ -903,31 +906,42 @@ main (int argc, char *const *argv)
903#endif /* MHD_HAVE_LIBMAGIC */ 906#endif /* MHD_HAVE_LIBMAGIC */
904 907
905 (void) pthread_mutex_init (&mutex, NULL); 908 (void) pthread_mutex_init (&mutex, NULL);
906 file_not_found_response = MHD_create_response_from_buffer (strlen (FILE_NOT_FOUND_PAGE), 909 file_not_found_response = MHD_create_response_from_buffer (strlen (
907 (void *) FILE_NOT_FOUND_PAGE, 910 FILE_NOT_FOUND_PAGE),
908 MHD_RESPMEM_PERSISTENT); 911 (void *)
912 FILE_NOT_FOUND_PAGE,
913 MHD_RESPMEM_PERSISTENT);
909 mark_as_html (file_not_found_response); 914 mark_as_html (file_not_found_response);
910 request_refused_response = MHD_create_response_from_buffer (strlen (REQUEST_REFUSED_PAGE), 915 request_refused_response = MHD_create_response_from_buffer (strlen (
911 (void *) REQUEST_REFUSED_PAGE, 916 REQUEST_REFUSED_PAGE),
912 MHD_RESPMEM_PERSISTENT); 917 (void *)
918 REQUEST_REFUSED_PAGE,
919 MHD_RESPMEM_PERSISTENT);
913 mark_as_html (request_refused_response); 920 mark_as_html (request_refused_response);
914 internal_error_response = MHD_create_response_from_buffer (strlen (INTERNAL_ERROR_PAGE), 921 internal_error_response = MHD_create_response_from_buffer (strlen (
915 (void *) INTERNAL_ERROR_PAGE, 922 INTERNAL_ERROR_PAGE),
916 MHD_RESPMEM_PERSISTENT); 923 (void *)
924 INTERNAL_ERROR_PAGE,
925 MHD_RESPMEM_PERSISTENT);
917 mark_as_html (internal_error_response); 926 mark_as_html (internal_error_response);
918 update_directory (); 927 update_directory ();
919 d = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, 928 d = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD
929 | MHD_USE_ERROR_LOG,
920 port, 930 port,
921 NULL, NULL, 931 NULL, NULL,
922 &generate_page, NULL, 932 &generate_page, NULL,
923 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (256 * 1024), 933 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (256
934 * 1024),
924#if PRODUCTION 935#if PRODUCTION
925 MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) (64), 936 MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) (64),
926#endif 937#endif
927 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) (120 /* seconds */), 938 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
928 MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) NUMBER_OF_THREADS, 939 int) (120 /* seconds */),
929 MHD_OPTION_NOTIFY_COMPLETED, &response_completed_callback, NULL, 940 MHD_OPTION_THREAD_POOL_SIZE, (unsigned
930 MHD_OPTION_END); 941 int) NUMBER_OF_THREADS,
942 MHD_OPTION_NOTIFY_COMPLETED,
943 &response_completed_callback, NULL,
944 MHD_OPTION_END);
931 if (NULL == d) 945 if (NULL == d)
932 return 1; 946 return 1;
933 fprintf (stderr, "HTTP server running. Press ENTER to stop the server\n"); 947 fprintf (stderr, "HTTP server running. Press ENTER to stop the server\n");