aboutsummaryrefslogtreecommitdiff
path: root/src/examples/demo_https.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-04-12 19:52:29 +0000
committerChristian Grothoff <christian@grothoff.org>2015-04-12 19:52:29 +0000
commit10a27715a5a01248f97d7853e37f1beb1f4a92db (patch)
tree57b109e91fc0798239f9a0a39b20a50ecd2506a1 /src/examples/demo_https.c
parent4d6fb01f8e229ece8a41fb2f4a94eb61b9e38e02 (diff)
downloadlibmicrohttpd-10a27715a5a01248f97d7853e37f1beb1f4a92db.tar.gz
libmicrohttpd-10a27715a5a01248f97d7853e37f1beb1f4a92db.zip
Adding "testcase" (demo_https) and a fix. -CG
Hi, I am doing test with HTTPS at low bit rate for large files using: wget -v --no-check-certificate --limit-rate=1000 https://.... When the MHD daemon is configured with MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY, I noticed that the thread takes 100% CPU, whereas the MHD_USE_POLL_INTERNALLY configuration show a normal CPU usage. Adding logs I see that the busy loops takes place at daemon.c, line 2605 (0.9.38): daemon->eready_tail never gets NULL most probably due to connection.c, line 2671 to 2721 Thanks, Louis
Diffstat (limited to 'src/examples/demo_https.c')
-rw-r--r--src/examples/demo_https.c960
1 files changed, 960 insertions, 0 deletions
diff --git a/src/examples/demo_https.c b/src/examples/demo_https.c
new file mode 100644
index 00000000..f34a715c
--- /dev/null
+++ b/src/examples/demo_https.c
@@ -0,0 +1,960 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2013 Christian Grothoff (and other contributing authors)
4
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
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file demo_https.c
22 * @brief complex demonstration site: create directory index, offer
23 * upload via form and HTTP POST, download with mime type detection
24 * and error reporting (403, etc.) --- and all of this with
25 * high-performance settings (large buffers, thread pool).
26 * If you want to benchmark MHD, this code should be used to
27 * run tests against. Note that the number of threads may need
28 * to be adjusted depending on the number of available cores.
29 * Logic is identical to demo.c, just adds HTTPS support.
30 * @author Christian Grothoff
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#include <magic.h>
40#include <limits.h>
41#include <ctype.h>
42
43#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
44#undef CPU_COUNT
45#endif
46#if !defined(CPU_COUNT)
47#define CPU_COUNT 2
48#endif
49
50/**
51 * Number of threads to run in the thread pool. Should (roughly) match
52 * the number of cores on your system.
53 */
54#define NUMBER_OF_THREADS CPU_COUNT
55
56/**
57 * How many bytes of a file do we give to libmagic to determine the mime type?
58 * 16k might be a bit excessive, but ought not hurt performance much anyway,
59 * and should definitively be on the safe side.
60 */
61#define MAGIC_HEADER_SIZE (16 * 1024)
62
63
64/**
65 * Page returned for file-not-found.
66 */
67#define FILE_NOT_FOUND_PAGE "<html><head><title>File not found</title></head><body>File not found</body></html>"
68
69
70/**
71 * Page returned for internal errors.
72 */
73#define INTERNAL_ERROR_PAGE "<html><head><title>Internal error</title></head><body>Internal error</body></html>"
74
75
76/**
77 * Page returned for refused requests.
78 */
79#define REQUEST_REFUSED_PAGE "<html><head><title>Request refused</title></head><body>Request refused (file exists?)</body></html>"
80
81
82/**
83 * Head of index page.
84 */
85#define INDEX_PAGE_HEADER "<html>\n<head><title>Welcome</title></head>\n<body>\n"\
86 "<h1>Upload</h1>\n"\
87 "<form method=\"POST\" enctype=\"multipart/form-data\" action=\"/\">\n"\
88 "<dl><dt>Content type:</dt><dd>"\
89 "<input type=\"radio\" name=\"category\" value=\"books\">Book</input>"\
90 "<input type=\"radio\" name=\"category\" value=\"images\">Image</input>"\
91 "<input type=\"radio\" name=\"category\" value=\"music\">Music</input>"\
92 "<input type=\"radio\" name=\"category\" value=\"software\">Software</input>"\
93 "<input type=\"radio\" name=\"category\" value=\"videos\">Videos</input>\n"\
94 "<input type=\"radio\" name=\"category\" value=\"other\" checked>Other</input></dd>"\
95 "<dt>Language:</dt><dd>"\
96 "<input type=\"radio\" name=\"language\" value=\"no-lang\" checked>none</input>"\
97 "<input type=\"radio\" name=\"language\" value=\"en\">English</input>"\
98 "<input type=\"radio\" name=\"language\" value=\"de\">German</input>"\
99 "<input type=\"radio\" name=\"language\" value=\"fr\">French</input>"\
100 "<input type=\"radio\" name=\"language\" value=\"es\">Spanish</input></dd>\n"\
101 "<dt>File:</dt><dd>"\
102 "<input type=\"file\" name=\"upload\"/></dd></dl>"\
103 "<input type=\"submit\" value=\"Send!\"/>\n"\
104 "</form>\n"\
105 "<h1>Download</h1>\n"\
106 "<ol>\n"
107
108/**
109 * Footer of index page.
110 */
111#define INDEX_PAGE_FOOTER "</ol>\n</body>\n</html>"
112
113
114/**
115 * NULL-terminated array of supported upload categories. Should match HTML
116 * in the form.
117 */
118static const char * const categories[] =
119 {
120 "books",
121 "images",
122 "music",
123 "software",
124 "videos",
125 "other",
126 NULL,
127 };
128
129
130/**
131 * Specification of a supported language.
132 */
133struct Language
134{
135 /**
136 * Directory name for the language.
137 */
138 const char *dirname;
139
140 /**
141 * Long name for humans.
142 */
143 const char *longname;
144
145};
146
147/**
148 * NULL-terminated array of supported upload categories. Should match HTML
149 * in the form.
150 */
151static const struct Language languages[] =
152 {
153 { "no-lang", "No language specified" },
154 { "en", "English" },
155 { "de", "German" },
156 { "fr", "French" },
157 { "es", "Spanish" },
158 { NULL, NULL },
159 };
160
161
162/**
163 * Response returned if the requested file does not exist (or is not accessible).
164 */
165static struct MHD_Response *file_not_found_response;
166
167/**
168 * Response returned for internal errors.
169 */
170static struct MHD_Response *internal_error_response;
171
172/**
173 * Response returned for '/' (GET) to list the contents of the directory and allow upload.
174 */
175static struct MHD_Response *cached_directory_response;
176
177/**
178 * Response returned for refused uploads.
179 */
180static struct MHD_Response *request_refused_response;
181
182/**
183 * Mutex used when we update the cached directory response object.
184 */
185static pthread_mutex_t mutex;
186
187/**
188 * Global handle to MAGIC data.
189 */
190static magic_t magic;
191
192
193/**
194 * Mark the given response as HTML for the brower.
195 *
196 * @param response response to mark
197 */
198static void
199mark_as_html (struct MHD_Response *response)
200{
201 (void) MHD_add_response_header (response,
202 MHD_HTTP_HEADER_CONTENT_TYPE,
203 "text/html");
204}
205
206
207/**
208 * Replace the existing 'cached_directory_response' with the
209 * given response.
210 *
211 * @param response new directory response
212 */
213static void
214update_cached_response (struct MHD_Response *response)
215{
216 (void) pthread_mutex_lock (&mutex);
217 if (NULL != cached_directory_response)
218 MHD_destroy_response (cached_directory_response);
219 cached_directory_response = response;
220 (void) pthread_mutex_unlock (&mutex);
221}
222
223
224/**
225 * Context keeping the data for the response we're building.
226 */
227struct ResponseDataContext
228{
229 /**
230 * Response data string.
231 */
232 char *buf;
233
234 /**
235 * Number of bytes allocated for 'buf'.
236 */
237 size_t buf_len;
238
239 /**
240 * Current position where we append to 'buf'. Must be smaller or equal to 'buf_len'.
241 */
242 size_t off;
243
244};
245
246
247/**
248 * Create a listing of the files in 'dirname' in HTML.
249 *
250 * @param rdc where to store the list of files
251 * @param dirname name of the directory to list
252 * @return MHD_YES on success, MHD_NO on error
253 */
254static int
255list_directory (struct ResponseDataContext *rdc,
256 const char *dirname)
257{
258 char fullname[PATH_MAX];
259 struct stat sbuf;
260 DIR *dir;
261 struct dirent *de;
262
263 if (NULL == (dir = opendir (dirname)))
264 return MHD_NO;
265 while (NULL != (de = readdir (dir)))
266 {
267 if ('.' == de->d_name[0])
268 continue;
269 if (sizeof (fullname) <= (size_t)
270 snprintf (fullname, sizeof (fullname),
271 "%s/%s",
272 dirname, de->d_name))
273 continue; /* ugh, file too long? how can this be!? */
274 if (0 != stat (fullname, &sbuf))
275 continue; /* ugh, failed to 'stat' */
276 if (! S_ISREG (sbuf.st_mode))
277 continue; /* not a regular file, skip */
278 if (rdc->off + 1024 > rdc->buf_len)
279 {
280 void *r;
281
282 if ( (2 * rdc->buf_len + 1024) < rdc->buf_len)
283 break; /* more than SIZE_T _index_ size? Too big for us */
284 rdc->buf_len = 2 * rdc->buf_len + 1024;
285 if (NULL == (r = realloc (rdc->buf, rdc->buf_len)))
286 break; /* out of memory */
287 rdc->buf = r;
288 }
289 rdc->off += snprintf (&rdc->buf[rdc->off],
290 rdc->buf_len - rdc->off,
291 "<li><a href=\"/%s\">%s</a></li>\n",
292 fullname,
293 de->d_name);
294 }
295 (void) closedir (dir);
296 return MHD_YES;
297}
298
299
300/**
301 * Re-scan our local directory and re-build the index.
302 */
303static void
304update_directory ()
305{
306 static size_t initial_allocation = 32 * 1024; /* initial size for response buffer */
307 struct MHD_Response *response;
308 struct ResponseDataContext rdc;
309 unsigned int language_idx;
310 unsigned int category_idx;
311 const struct Language *language;
312 const char *category;
313 char dir_name[128];
314 struct stat sbuf;
315
316 rdc.buf_len = initial_allocation;
317 if (NULL == (rdc.buf = malloc (rdc.buf_len)))
318 {
319 update_cached_response (NULL);
320 return;
321 }
322 rdc.off = snprintf (rdc.buf, rdc.buf_len,
323 "%s",
324 INDEX_PAGE_HEADER);
325 for (language_idx = 0; NULL != languages[language_idx].dirname; language_idx++)
326 {
327 language = &languages[language_idx];
328
329 if (0 != stat (language->dirname, &sbuf))
330 continue; /* empty */
331 /* we ensured always +1k room, filenames are ~256 bytes,
332 so there is always still enough space for the header
333 without need for an additional reallocation check. */
334 rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
335 "<h2>%s</h2>\n",
336 language->longname);
337 for (category_idx = 0; NULL != categories[category_idx]; category_idx++)
338 {
339 category = categories[category_idx];
340 snprintf (dir_name, sizeof (dir_name),
341 "%s/%s",
342 language->dirname,
343 category);
344 if (0 != stat (dir_name, &sbuf))
345 continue; /* empty */
346
347 /* we ensured always +1k room, filenames are ~256 bytes,
348 so there is always still enough space for the header
349 without need for an additional reallocation check. */
350 rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
351 "<h3>%s</h3>\n",
352 category);
353
354 if (MHD_NO == list_directory (&rdc, dir_name))
355 {
356 free (rdc.buf);
357 update_cached_response (NULL);
358 return;
359 }
360 }
361 }
362 /* we ensured always +1k room, filenames are ~256 bytes,
363 so there is always still enough space for the footer
364 without need for a final reallocation check. */
365 rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
366 "%s",
367 INDEX_PAGE_FOOTER);
368 initial_allocation = rdc.buf_len; /* remember for next time */
369 response = MHD_create_response_from_buffer (rdc.off,
370 rdc.buf,
371 MHD_RESPMEM_MUST_FREE);
372 mark_as_html (response);
373#if FORCE_CLOSE
374 (void) MHD_add_response_header (response,
375 MHD_HTTP_HEADER_CONNECTION,
376 "close");
377#endif
378 update_cached_response (response);
379}
380
381
382/**
383 * Context we keep for an upload.
384 */
385struct UploadContext
386{
387 /**
388 * Handle where we write the uploaded file to.
389 */
390 int fd;
391
392 /**
393 * Name of the file on disk (used to remove on errors).
394 */
395 char *filename;
396
397 /**
398 * Language for the upload.
399 */
400 char *language;
401
402 /**
403 * Category for the upload.
404 */
405 char *category;
406
407 /**
408 * Post processor we're using to process the upload.
409 */
410 struct MHD_PostProcessor *pp;
411
412 /**
413 * Handle to connection that we're processing the upload for.
414 */
415 struct MHD_Connection *connection;
416
417 /**
418 * Response to generate, NULL to use directory.
419 */
420 struct MHD_Response *response;
421};
422
423
424/**
425 * Append the 'size' bytes from 'data' to '*ret', adding
426 * 0-termination. If '*ret' is NULL, allocate an empty string first.
427 *
428 * @param ret string to update, NULL or 0-terminated
429 * @param data data to append
430 * @param size number of bytes in 'data'
431 * @return MHD_NO on allocation failure, MHD_YES on success
432 */
433static int
434do_append (char **ret,
435 const char *data,
436 size_t size)
437{
438 char *buf;
439 size_t old_len;
440
441 if (NULL == *ret)
442 old_len = 0;
443 else
444 old_len = strlen (*ret);
445 buf = malloc (old_len + size + 1);
446 if (NULL == buf)
447 return MHD_NO;
448 memcpy (buf, *ret, old_len);
449 if (NULL != *ret)
450 free (*ret);
451 memcpy (&buf[old_len], data, size);
452 buf[old_len + size] = '\0';
453 *ret = buf;
454 return MHD_YES;
455}
456
457
458/**
459 * Iterator over key-value pairs where the value
460 * maybe made available in increments and/or may
461 * not be zero-terminated. Used for processing
462 * POST data.
463 *
464 * @param cls user-specified closure
465 * @param kind type of the value, always MHD_POSTDATA_KIND when called from MHD
466 * @param key 0-terminated key for the value
467 * @param filename name of the uploaded file, NULL if not known
468 * @param content_type mime-type of the data, NULL if not known
469 * @param transfer_encoding encoding of the data, NULL if not known
470 * @param data pointer to size bytes of data at the
471 * specified offset
472 * @param off offset of data in the overall value
473 * @param size number of bytes in data available
474 * @return MHD_YES to continue iterating,
475 * MHD_NO to abort the iteration
476 */
477static int
478process_upload_data (void *cls,
479 enum MHD_ValueKind kind,
480 const char *key,
481 const char *filename,
482 const char *content_type,
483 const char *transfer_encoding,
484 const char *data,
485 uint64_t off,
486 size_t size)
487{
488 struct UploadContext *uc = cls;
489 int i;
490
491 if (0 == strcmp (key, "category"))
492 return do_append (&uc->category, data, size);
493 if (0 == strcmp (key, "language"))
494 return do_append (&uc->language, data, size);
495 if (0 != strcmp (key, "upload"))
496 {
497 fprintf (stderr,
498 "Ignoring unexpected form value `%s'\n",
499 key);
500 return MHD_YES; /* ignore */
501 }
502 if (NULL == filename)
503 {
504 fprintf (stderr, "No filename, aborting upload\n");
505 return MHD_NO; /* no filename, error */
506 }
507 if ( (NULL == uc->category) ||
508 (NULL == uc->language) )
509 {
510 fprintf (stderr,
511 "Missing form data for upload `%s'\n",
512 filename);
513 uc->response = request_refused_response;
514 return MHD_NO;
515 }
516 if (-1 == uc->fd)
517 {
518 char fn[PATH_MAX];
519
520 if ( (NULL != strstr (filename, "..")) ||
521 (NULL != strchr (filename, '/')) ||
522 (NULL != strchr (filename, '\\')) )
523 {
524 uc->response = request_refused_response;
525 return MHD_NO;
526 }
527 /* create directories -- if they don't exist already */
528#ifdef WINDOWS
529 (void) mkdir (uc->language);
530#else
531 (void) mkdir (uc->language, S_IRWXU);
532#endif
533 snprintf (fn, sizeof (fn),
534 "%s/%s",
535 uc->language,
536 uc->category);
537#ifdef WINDOWS
538 (void) mkdir (fn);
539#else
540 (void) mkdir (fn, S_IRWXU);
541#endif
542 /* open file */
543 snprintf (fn, sizeof (fn),
544 "%s/%s/%s",
545 uc->language,
546 uc->category,
547 filename);
548 for (i=strlen (fn)-1;i>=0;i--)
549 if (! isprint ((int) fn[i]))
550 fn[i] = '_';
551 uc->fd = open (fn,
552 O_CREAT | O_EXCL
553#if O_LARGEFILE
554 | O_LARGEFILE
555#endif
556 | O_WRONLY,
557 S_IRUSR | S_IWUSR);
558 if (-1 == uc->fd)
559 {
560 fprintf (stderr,
561 "Error opening file `%s' for upload: %s\n",
562 fn,
563 strerror (errno));
564 uc->response = request_refused_response;
565 return MHD_NO;
566 }
567 uc->filename = strdup (fn);
568 }
569 if ( (0 != size) &&
570 (size != (size_t) write (uc->fd, data, size)) )
571 {
572 /* write failed; likely: disk full */
573 fprintf (stderr,
574 "Error writing to file `%s': %s\n",
575 uc->filename,
576 strerror (errno));
577 uc->response = internal_error_response;
578 close (uc->fd);
579 uc->fd = -1;
580 if (NULL != uc->filename)
581 {
582 unlink (uc->filename);
583 free (uc->filename);
584 uc->filename = NULL;
585 }
586 return MHD_NO;
587 }
588 return MHD_YES;
589}
590
591
592/**
593 * Function called whenever a request was completed.
594 * Used to clean up 'struct UploadContext' objects.
595 *
596 * @param cls client-defined closure, NULL
597 * @param connection connection handle
598 * @param con_cls value as set by the last call to
599 * the MHD_AccessHandlerCallback, points to NULL if this was
600 * not an upload
601 * @param toe reason for request termination
602 */
603static void
604response_completed_callback (void *cls,
605 struct MHD_Connection *connection,
606 void **con_cls,
607 enum MHD_RequestTerminationCode toe)
608{
609 struct UploadContext *uc = *con_cls;
610
611 if (NULL == uc)
612 return; /* this request wasn't an upload request */
613 if (NULL != uc->pp)
614 {
615 MHD_destroy_post_processor (uc->pp);
616 uc->pp = NULL;
617 }
618 if (-1 != uc->fd)
619 {
620 (void) close (uc->fd);
621 if (NULL != uc->filename)
622 {
623 fprintf (stderr,
624 "Upload of file `%s' failed (incomplete or aborted), removing file.\n",
625 uc->filename);
626 (void) unlink (uc->filename);
627 }
628 }
629 if (NULL != uc->filename)
630 free (uc->filename);
631 free (uc);
632}
633
634
635/**
636 * Return the current directory listing.
637 *
638 * @param connection connection to return the directory for
639 * @return MHD_YES on success, MHD_NO on error
640 */
641static int
642return_directory_response (struct MHD_Connection *connection)
643{
644 int ret;
645
646 (void) pthread_mutex_lock (&mutex);
647 if (NULL == cached_directory_response)
648 ret = MHD_queue_response (connection,
649 MHD_HTTP_INTERNAL_SERVER_ERROR,
650 internal_error_response);
651 else
652 ret = MHD_queue_response (connection,
653 MHD_HTTP_OK,
654 cached_directory_response);
655 (void) pthread_mutex_unlock (&mutex);
656 return ret;
657}
658
659
660/**
661 * Main callback from MHD, used to generate the page.
662 *
663 * @param cls NULL
664 * @param connection connection handle
665 * @param url requested URL
666 * @param method GET, PUT, POST, etc.
667 * @param version HTTP version
668 * @param upload_data data from upload (PUT/POST)
669 * @param upload_data_size number of bytes in "upload_data"
670 * @param ptr our context
671 * @return MHD_YES on success, MHD_NO to drop connection
672 */
673static int
674generate_page (void *cls,
675 struct MHD_Connection *connection,
676 const char *url,
677 const char *method,
678 const char *version,
679 const char *upload_data,
680 size_t *upload_data_size, void **ptr)
681{
682 struct MHD_Response *response;
683 int ret;
684 int fd;
685 struct stat buf;
686
687 if (0 != strcmp (url, "/"))
688 {
689 /* should be file download */
690 char file_data[MAGIC_HEADER_SIZE];
691 ssize_t got;
692 const char *mime;
693
694 if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
695 return MHD_NO; /* unexpected method (we're not polite...) */
696 if ( (0 == stat (&url[1], &buf)) &&
697 (NULL == strstr (&url[1], "..")) &&
698 ('/' != url[1]))
699 fd = open (&url[1], O_RDONLY);
700 else
701 fd = -1;
702 if (-1 == fd)
703 return MHD_queue_response (connection,
704 MHD_HTTP_NOT_FOUND,
705 file_not_found_response);
706 /* read beginning of the file to determine mime type */
707 got = read (fd, file_data, sizeof (file_data));
708 if (-1 != got)
709 mime = magic_buffer (magic, file_data, got);
710 else
711 mime = NULL;
712 (void) lseek (fd, 0, SEEK_SET);
713
714 if (NULL == (response = MHD_create_response_from_fd (buf.st_size,
715 fd)))
716 {
717 /* internal error (i.e. out of memory) */
718 (void) close (fd);
719 return MHD_NO;
720 }
721
722 /* add mime type if we had one */
723 if (NULL != mime)
724 (void) MHD_add_response_header (response,
725 MHD_HTTP_HEADER_CONTENT_TYPE,
726 mime);
727 ret = MHD_queue_response (connection,
728 MHD_HTTP_OK,
729 response);
730 MHD_destroy_response (response);
731 return ret;
732 }
733
734 if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
735 {
736 /* upload! */
737 struct UploadContext *uc = *ptr;
738
739 if (NULL == uc)
740 {
741 if (NULL == (uc = malloc (sizeof (struct UploadContext))))
742 return MHD_NO; /* out of memory, close connection */
743 memset (uc, 0, sizeof (struct UploadContext));
744 uc->fd = -1;
745 uc->connection = connection;
746 uc->pp = MHD_create_post_processor (connection,
747 64 * 1024 /* buffer size */,
748 &process_upload_data, uc);
749 if (NULL == uc->pp)
750 {
751 /* out of memory, close connection */
752 free (uc);
753 return MHD_NO;
754 }
755 *ptr = uc;
756 return MHD_YES;
757 }
758 if (0 != *upload_data_size)
759 {
760 if (NULL == uc->response)
761 (void) MHD_post_process (uc->pp,
762 upload_data,
763 *upload_data_size);
764 *upload_data_size = 0;
765 return MHD_YES;
766 }
767 /* end of upload, finish it! */
768 MHD_destroy_post_processor (uc->pp);
769 uc->pp = NULL;
770 if (-1 != uc->fd)
771 {
772 close (uc->fd);
773 uc->fd = -1;
774 }
775 if (NULL != uc->response)
776 {
777 return MHD_queue_response (connection,
778 MHD_HTTP_FORBIDDEN,
779 uc->response);
780 }
781 else
782 {
783 update_directory ();
784 return return_directory_response (connection);
785 }
786 }
787 if (0 == strcmp (method, MHD_HTTP_METHOD_GET))
788 {
789 return return_directory_response (connection);
790 }
791
792 /* unexpected request, refuse */
793 return MHD_queue_response (connection,
794 MHD_HTTP_FORBIDDEN,
795 request_refused_response);
796}
797
798
799/**
800 * Function called if we get a SIGPIPE. Does nothing.
801 *
802 * @param sig will be SIGPIPE (ignored)
803 */
804static void
805catcher (int sig)
806{
807 /* do nothing */
808}
809
810
811/**
812 * setup handlers to ignore SIGPIPE.
813 */
814#ifndef MINGW
815static void
816ignore_sigpipe ()
817{
818 struct sigaction oldsig;
819 struct sigaction sig;
820
821 sig.sa_handler = &catcher;
822 sigemptyset (&sig.sa_mask);
823#ifdef SA_INTERRUPT
824 sig.sa_flags = SA_INTERRUPT; /* SunOS */
825#else
826 sig.sa_flags = SA_RESTART;
827#endif
828 if (0 != sigaction (SIGPIPE, &sig, &oldsig))
829 fprintf (stderr,
830 "Failed to install SIGPIPE handler: %s\n", strerror (errno));
831}
832#endif
833
834/* test server key */
835const char srv_signed_key_pem[] = "-----BEGIN RSA PRIVATE KEY-----\n"
836 "MIIEowIBAAKCAQEAvfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW\n"
837 "+K03KwEku55QvnUndwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8IL\n"
838 "q4sw32vo0fbMu5BZF49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ0\n"
839 "20Q5EAAEseD1YtWCIpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6\n"
840 "QYGGh1QmHRPAy3CBII6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6x\n"
841 "yoOl204xuekZOaG9RUPId74Rtmwfi1TLbBzo2wIDAQABAoIBADu09WSICNq5cMe4\n"
842 "+NKCLlgAT1NiQpLls1gKRbDhKiHU9j8QWNvWWkJWrCya4QdUfLCfeddCMeiQmv3K\n"
843 "lJMvDs+5OjJSHFoOsGiuW2Ias7IjnIojaJalfBml6frhJ84G27IXmdz6gzOiTIer\n"
844 "DjeAgcwBaKH5WwIay2TxIaScl7AwHBauQkrLcyb4hTmZuQh6ArVIN6+pzoVuORXM\n"
845 "bpeNWl2l/HSN3VtUN6aCAKbN/X3o0GavCCMn5Fa85uJFsab4ss/uP+2PusU71+zP\n"
846 "sBm6p/2IbGvF5k3VPDA7X5YX61sukRjRBihY8xSnNYx1UcoOsX6AiPnbhifD8+xQ\n"
847 "Tlf8oJUCgYEA0BTfzqNpr9Wxw5/QXaSdw7S/0eP5a0C/nwURvmfSzuTD4equzbEN\n"
848 "d+dI/s2JMxrdj/I4uoAfUXRGaabevQIjFzC9uyE3LaOyR2zhuvAzX+vVcs6bSXeU\n"
849 "pKpCAcN+3Z3evMaX2f+z/nfSUAl2i4J2R+/LQAWJW4KwRky/m+cxpfUCgYEA6bN1\n"
850 "b73bMgM8wpNt6+fcmS+5n0iZihygQ2U2DEud8nZJL4Nrm1dwTnfZfJBnkGj6+0Q0\n"
851 "cOwj2KS0/wcEdJBP0jucU4v60VMhp75AQeHqidIde0bTViSRo3HWKXHBIFGYoU3T\n"
852 "LyPyKndbqsOObnsFXHn56Nwhr2HLf6nw4taGQY8CgYBoSW36FLCNbd6QGvLFXBGt\n"
853 "2lMhEM8az/K58kJ4WXSwOLtr6MD/WjNT2tkcy0puEJLm6BFCd6A6pLn9jaKou/92\n"
854 "SfltZjJPb3GUlp9zn5tAAeSSi7YMViBrfuFiHObij5LorefBXISLjuYbMwL03MgH\n"
855 "Ocl2JtA2ywMp2KFXs8GQWQKBgFyIVv5ogQrbZ0pvj31xr9HjqK6d01VxIi+tOmpB\n"
856 "4ocnOLEcaxX12BzprW55ytfOCVpF1jHD/imAhb3YrHXu0fwe6DXYXfZV4SSG2vB7\n"
857 "IB9z14KBN5qLHjNGFpMQXHSMek+b/ftTU0ZnPh9uEM5D3YqRLVd7GcdUhHvG8P8Q\n"
858 "C9aXAoGBAJtID6h8wOGMP0XYX5YYnhlC7dOLfk8UYrzlp3xhqVkzKthTQTj6wx9R\n"
859 "GtC4k7U1ki8oJsfcIlBNXd768fqDVWjYju5rzShMpo8OCTS6ipAblKjCxPPVhIpv\n"
860 "tWPlbSn1qj6wylstJ5/3Z+ZW5H4wIKp5jmLiioDhcP0L/Ex3Zx8O\n"
861 "-----END RSA PRIVATE KEY-----\n";
862
863/* test server CA signed certificates */
864const char srv_signed_cert_pem[] = "-----BEGIN CERTIFICATE-----\n"
865 "MIIDGzCCAgWgAwIBAgIES0KCvTALBgkqhkiG9w0BAQUwFzEVMBMGA1UEAxMMdGVz\n"
866 "dF9jYV9jZXJ0MB4XDTEwMDEwNTAwMDcyNVoXDTQ1MDMxMjAwMDcyNVowFzEVMBMG\n"
867 "A1UEAxMMdGVzdF9jYV9jZXJ0MIIBHzALBgkqhkiG9w0BAQEDggEOADCCAQkCggEA\n"
868 "vfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW+K03KwEku55QvnUn\n"
869 "dwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8ILq4sw32vo0fbMu5BZ\n"
870 "F49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ020Q5EAAEseD1YtWC\n"
871 "IpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6QYGGh1QmHRPAy3CB\n"
872 "II6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6xyoOl204xuekZOaG9\n"
873 "RUPId74Rtmwfi1TLbBzo2wIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM\n"
874 "MAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHIAAwHQYDVR0OBBYEFOFi4ilKOP1d\n"
875 "XHlWCMwmVKr7mgy8MB8GA1UdIwQYMBaAFP2olB4s2T/xuoQ5pT2RKojFwZo2MAsG\n"
876 "CSqGSIb3DQEBBQOCAQEAHVWPxazupbOkG7Did+dY9z2z6RjTzYvurTtEKQgzM2Vz\n"
877 "GQBA+3pZ3c5mS97fPIs9hZXfnQeelMeZ2XP1a+9vp35bJjZBBhVH+pqxjCgiUflg\n"
878 "A3Zqy0XwwVCgQLE2HyaU3DLUD/aeIFK5gJaOSdNTXZLv43K8kl4cqDbMeRpVTbkt\n"
879 "YmG4AyEOYRNKGTqMEJXJoxD5E3rBUNrVI/XyTjYrulxbNPcMWEHKNeeqWpKDYTFo\n"
880 "Bb01PCthGXiq/4A2RLAFosadzRa8SBpoSjPPfZ0b2w4MJpReHqKbR5+T2t6hzml6\n"
881 "4ToyOKPDmamiTuN5KzLN3cw7DQlvWMvqSOChPLnA3Q==\n"
882 "-----END CERTIFICATE-----\n";
883
884
885/**
886 * Entry point to demo. Note: this HTTP server will make all
887 * files in the current directory and its subdirectories available
888 * to anyone. Press ENTER to stop the server once it has started.
889 *
890 * @param argc number of arguments in argv
891 * @param argv first and only argument should be the port number
892 * @return 0 on success
893 */
894int
895main (int argc, char *const *argv)
896{
897 struct MHD_Daemon *d;
898 unsigned int port;
899
900 if ( (argc != 2) ||
901 (1 != sscanf (argv[1], "%u", &port)) ||
902 (UINT16_MAX < port) )
903 {
904 fprintf (stderr,
905 "%s PORT\n", argv[0]);
906 return 1;
907 }
908 #ifndef MINGW
909 ignore_sigpipe ();
910 #endif
911 magic = magic_open (MAGIC_MIME_TYPE);
912 (void) magic_load (magic, NULL);
913
914 (void) pthread_mutex_init (&mutex, NULL);
915 file_not_found_response = MHD_create_response_from_buffer (strlen (FILE_NOT_FOUND_PAGE),
916 (void *) FILE_NOT_FOUND_PAGE,
917 MHD_RESPMEM_PERSISTENT);
918 mark_as_html (file_not_found_response);
919 request_refused_response = MHD_create_response_from_buffer (strlen (REQUEST_REFUSED_PAGE),
920 (void *) REQUEST_REFUSED_PAGE,
921 MHD_RESPMEM_PERSISTENT);
922 mark_as_html (request_refused_response);
923 internal_error_response = MHD_create_response_from_buffer (strlen (INTERNAL_ERROR_PAGE),
924 (void *) INTERNAL_ERROR_PAGE,
925 MHD_RESPMEM_PERSISTENT);
926 mark_as_html (internal_error_response);
927 update_directory ();
928 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | MHD_USE_SSL
929#if EPOLL_SUPPORT
930 | MHD_USE_EPOLL_LINUX_ONLY
931#endif
932 ,
933 port,
934 NULL, NULL,
935 &generate_page, NULL,
936 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (256 * 1024),
937#if PRODUCTION
938 MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) (64),
939#endif
940 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) (120 /* seconds */),
941 MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) NUMBER_OF_THREADS,
942 MHD_OPTION_NOTIFY_COMPLETED, &response_completed_callback, NULL,
943 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
944 MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
945 MHD_OPTION_END);
946 if (NULL == d)
947 return 1;
948 fprintf (stderr, "HTTP server running. Press ENTER to stop the server\n");
949 (void) getc (stdin);
950 MHD_stop_daemon (d);
951 MHD_destroy_response (file_not_found_response);
952 MHD_destroy_response (request_refused_response);
953 MHD_destroy_response (internal_error_response);
954 update_cached_response (NULL);
955 (void) pthread_mutex_destroy (&mutex);
956 magic_close (magic);
957 return 0;
958}
959
960/* end of demo_https.c */