libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

https_fileserver_example.c (9496B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007, 2008 Christian Grothoff (and other contributing authors)
      4      Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
      5 
      6      This library is free software; you can redistribute it and/or
      7      modify it under the terms of the GNU Lesser General Public
      8      License as published by the Free Software Foundation; either
      9      version 2.1 of the License, or (at your option) any later version.
     10 
     11      This library is distributed in the hope that it will be useful,
     12      but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14      Lesser General Public License for more details.
     15 
     16      You should have received a copy of the GNU Lesser General Public
     17      License along with this library; if not, write to the Free Software
     18      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     19 */
     20 /**
     21  * @file https_fileserver_example.c
     22  * @brief a simple HTTPS file server using TLS.
     23  *
     24  * Usage :
     25  *
     26  *  'http_fileserver_example HTTP-PORT SECONDS-TO-RUN'
     27  *
     28  * The certificate & key are required by the server to operate, omitting the
     29  * path arguments will cause the server to use the hard coded example certificate & key.
     30  *
     31  * 'certtool' may be used to generate these if required.
     32  *
     33  * @author Sagie Amir
     34  * @author Karlson2k (Evgeny Grin)
     35  */
     36 
     37 #include "platform.h"
     38 #include <microhttpd.h>
     39 #include <sys/stat.h>
     40 
     41 #define BUF_SIZE 1024
     42 #define MAX_URL_LEN 255
     43 
     44 #define EMPTY_PAGE \
     45   "<html><head><title>File not found</title></head><body>File not found</body></html>"
     46 
     47 /* test server key */
     48 static const char key_pem[] =
     49   "-----BEGIN PRIVATE KEY-----\n\
     50 MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCff7amw9zNSE+h\n\
     51 rOMhBrzbbsJluUP3gmd8nOKY5MUimoPkxmAXfp2L0il+MPZT/ZEmo11q0k6J2jfG\n\
     52 UBQ+oZW9ahNZ9gCDjbYlBblo/mqTai+LdeLO3qk53d0zrZKXvCO6sA3uKpG2WR+g\n\
     53 +sNKxfYpIHCpanqBU6O+degIV/+WKy3nQ2Fwp7K5HUNj1u0pg0QQ18yf68LTnKFU\n\
     54 HFjZmmaaopWki5wKSBieHivzQy6w+04HSTogHHRK/y/UcoJNSG7xnHmoPPo1vLT8\n\
     55 CMRIYnSSgU3wJ43XBJ80WxrC2dcoZjV2XZz+XdQwCD4ZrC1ihykcAmiQA+sauNm7\n\
     56 dztOMkGzAgMBAAECggEAIbKDzlvXDG/YkxnJqrKXt+yAmak4mNQuNP+YSCEdHSBz\n\
     57 +SOILa6MbnvqVETX5grOXdFp7SWdfjZiTj2g6VKOJkSA7iKxHRoVf2DkOTB3J8np\n\
     58 XZd8YaRdMGKVV1O2guQ20Dxd1RGdU18k9YfFNsj4Jtw5sTFTzHr1P0n9ybV9xCXp\n\
     59 znSxVfRg8U6TcMHoRDJR9EMKQMO4W3OQEmreEPoGt2/+kMuiHjclxLtbwDxKXTLP\n\
     60 pD0gdg3ibvlufk/ccKl/yAglDmd0dfW22oS7NgvRKUve7tzDxY1Q6O5v8BCnLFSW\n\
     61 D+z4hS1PzooYRXRkM0xYudvPkryPyu+1kEpw3fNsoQKBgQDRfXJo82XQvlX8WPdZ\n\
     62 Ts3PfBKKMVu3Wf8J3SYpuvYT816qR3ot6e4Ivv5ZCQkdDwzzBKe2jAv6JddMJIhx\n\
     63 pkGHc0KKOodd9HoBewOd8Td++hapJAGaGblhL5beIidLKjXDjLqtgoHRGlv5Cojo\n\
     64 zHa7Viel1eOPPcBumhp83oJ+mQKBgQDC6PmdETZdrW3QPm7ZXxRzF1vvpC55wmPg\n\
     65 pRfTRM059jzRzAk0QiBgVp3yk2a6Ob3mB2MLfQVDgzGf37h2oO07s5nspSFZTFnM\n\
     66 KgSjFy0xVOAVDLe+0VpbmLp1YUTYvdCNowaoTE7++5rpePUDu3BjAifx07/yaSB+\n\
     67 W+YPOfOuKwKBgQCGK6g5G5qcJSuBIaHZ6yTZvIdLRu2M8vDral5k3793a6m3uWvB\n\
     68 OFAh/eF9ONJDcD5E7zhTLEMHhXDs7YEN+QODMwjs6yuDu27gv97DK5j1lEsrLUpx\n\
     69 XgRjAE3KG2m7NF+WzO1K74khWZaKXHrvTvTEaxudlO3X8h7rN3u7ee9uEQKBgQC2\n\
     70 wI1zeTUZhsiFTlTPWfgppchdHPs6zUqq0wFQ5Zzr8Pa72+zxY+NJkU2NqinTCNsG\n\
     71 ePykQ/gQgk2gUrt595AYv2De40IuoYk9BlTMuql0LNniwsbykwd/BOgnsSlFdEy8\n\
     72 0RQn70zOhgmNSg2qDzDklJvxghLi7zE5aV9//V1/ewKBgFRHHZN1a8q/v8AAOeoB\n\
     73 ROuXfgDDpxNNUKbzLL5MO5odgZGi61PBZlxffrSOqyZoJkzawXycNtoBP47tcVzT\n\
     74 QPq5ZOB3kjHTcN7dRLmPWjji9h4O3eHCX67XaPVMSWiMuNtOZIg2an06+jxGFhLE\n\
     75 qdJNJ1DkyUc9dN2cliX4R+rG\n\
     76 -----END PRIVATE KEY-----";
     77 
     78 /* test server CA signed certificates */
     79 static const char cert_pem[] =
     80   "-----BEGIN CERTIFICATE-----\n\
     81 MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n\
     82 DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n\
     83 LWxpYm1pY3JvaHR0cGQxITAfBgkqhkiG9w0BCQEWEm5vYm9keUBleGFtcGxlLm9y\n\
     84 ZzEQMA4GA1UEAwwHdGVzdC1DQTAgFw0yMjA0MjAxODQzMDJaGA8yMTIyMDMyNjE4\n\
     85 NDMwMlowZTELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwG\n\
     86 TW9zY293MRswGQYDVQQKDBJ0ZXN0LWxpYm1pY3JvaHR0cGQxFzAVBgNVBAMMDnRl\n\
     87 c3QtbWhkc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn3+2\n\
     88 psPczUhPoazjIQa8227CZblD94JnfJzimOTFIpqD5MZgF36di9IpfjD2U/2RJqNd\n\
     89 atJOido3xlAUPqGVvWoTWfYAg422JQW5aP5qk2ovi3Xizt6pOd3dM62Sl7wjurAN\n\
     90 7iqRtlkfoPrDSsX2KSBwqWp6gVOjvnXoCFf/list50NhcKeyuR1DY9btKYNEENfM\n\
     91 n+vC05yhVBxY2ZpmmqKVpIucCkgYnh4r80MusPtOB0k6IBx0Sv8v1HKCTUhu8Zx5\n\
     92 qDz6Nby0/AjESGJ0koFN8CeN1wSfNFsawtnXKGY1dl2c/l3UMAg+GawtYocpHAJo\n\
     93 kAPrGrjZu3c7TjJBswIDAQABo4HmMIHjMAsGA1UdDwQEAwIFoDAMBgNVHRMBAf8E\n\
     94 AjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMBMDEGA1UdEQQqMCiCDnRlc3QtbWhk\n\
     95 c2VydmVyhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMB0GA1UdDgQWBBQ57Z06WJae\n\
     96 8fJIHId4QGx/HsRgDDAoBglghkgBhvhCAQ0EGxYZVGVzdCBsaWJtaWNyb2h0dHBk\n\
     97 IHNlcnZlcjARBglghkgBhvhCAQEEBAMCBkAwHwYDVR0jBBgwFoAUWHVDwKVqMcOF\n\
     98 Nd0arI3/QB3W6SwwDQYJKoZIhvcNAQELBQADggIBAI7Lggm/XzpugV93H5+KV48x\n\
     99 X+Ct8unNmPCSzCaI5hAHGeBBJpvD0KME5oiJ5p2wfCtK5Dt9zzf0S0xYdRKqU8+N\n\
    100 aKIvPoU1hFixXLwTte1qOp6TviGvA9Xn2Fc4n36dLt6e9aiqDnqPbJgBwcVO82ll\n\
    101 HJxVr3WbrAcQTB3irFUMqgAke/Cva9Bw79VZgX4ghb5EnejDzuyup4pHGzV10Myv\n\
    102 hdg+VWZbAxpCe0S4eKmstZC7mWsFCLeoRTf/9Pk1kQ6+azbTuV/9QOBNfFi8QNyb\n\
    103 18jUjmm8sc2HKo8miCGqb2sFqaGD918hfkWmR+fFkzQ3DZQrT+eYbKq2un3k0pMy\n\
    104 UySy8SRn1eadfab+GwBVb68I9TrPRMrJsIzysNXMX4iKYl2fFE/RSNnaHtPw0C8y\n\
    105 B7memyxPRl+H2xg6UjpoKYh3+8e44/XKm0rNIzXjrwA8f8gnw2TbqmMDkj1YqGnC\n\
    106 SCj5A27zUzaf2pT/YsnQXIWOJjVvbEI+YKj34wKWyTrXA093y8YI8T3mal7Kr9YM\n\
    107 WiIyPts0/aVeziM0Gunglz+8Rj1VesL52FTurobqusPgM/AME82+qb/qnxuPaCKj\n\
    108 OT1qAbIblaRuWqCsid8BzP7ZQiAnAWgMRSUg1gzDwSwRhrYQRRWAyn/Qipzec+27\n\
    109 /w0gW9EVWzFhsFeGEssi\n\
    110 -----END CERTIFICATE-----";
    111 
    112 static ssize_t
    113 file_reader (void *cls, uint64_t pos, char *buf, size_t max)
    114 {
    115   FILE *file = (FILE *) cls;
    116   size_t bytes_read;
    117 
    118   /* 'fseek' may not support files larger 2GiB, depending on platform.
    119    * For production code, make sure that 'pos' has valid values, supported by
    120    * 'fseek', or use 'fseeko' or similar function. */
    121   if (0 != fseek (file, (long) pos, SEEK_SET))
    122     return MHD_CONTENT_READER_END_WITH_ERROR;
    123   bytes_read = fread (buf, 1, max, file);
    124   if (0 == bytes_read)
    125     return (0 != ferror (file)) ? MHD_CONTENT_READER_END_WITH_ERROR :
    126            MHD_CONTENT_READER_END_OF_STREAM;
    127   return (ssize_t) bytes_read;
    128 }
    129 
    130 
    131 static void
    132 file_free_callback (void *cls)
    133 {
    134   FILE *file = cls;
    135   fclose (file);
    136 }
    137 
    138 
    139 /* HTTP access handler call back */
    140 static enum MHD_Result
    141 http_ahc (void *cls,
    142           struct MHD_Connection *connection,
    143           const char *url,
    144           const char *method,
    145           const char *version,
    146           const char *upload_data,
    147           size_t *upload_data_size, void **req_cls)
    148 {
    149   static int aptr;
    150   struct MHD_Response *response;
    151   enum MHD_Result ret;
    152   FILE *file;
    153   int fd;
    154   struct stat buf;
    155   (void) cls;               /* Unused. Silent compiler warning. */
    156   (void) version;           /* Unused. Silent compiler warning. */
    157   (void) upload_data;       /* Unused. Silent compiler warning. */
    158   (void) upload_data_size;  /* Unused. Silent compiler warning. */
    159 
    160   if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
    161     return MHD_NO;              /* unexpected method */
    162   if (&aptr != *req_cls)
    163   {
    164     /* do never respond on first call */
    165     *req_cls = &aptr;
    166     return MHD_YES;
    167   }
    168   *req_cls = NULL;                  /* reset when done */
    169 
    170   file = fopen (&url[1], "rb");
    171   if (NULL != file)
    172   {
    173     fd = fileno (file);
    174     if (-1 == fd)
    175     {
    176       (void) fclose (file);
    177       return MHD_NO;     /* internal error */
    178     }
    179     if ( (0 != fstat (fd, &buf)) ||
    180          (! S_ISREG (buf.st_mode)) )
    181     {
    182       /* not a regular file, refuse to serve */
    183       fclose (file);
    184       file = NULL;
    185     }
    186   }
    187 
    188   if (NULL == file)
    189   {
    190     response =
    191       MHD_create_response_from_buffer_static (strlen (EMPTY_PAGE),
    192                                               (const void *) EMPTY_PAGE);
    193     ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response);
    194     MHD_destroy_response (response);
    195   }
    196   else
    197   {
    198     response = MHD_create_response_from_callback ((size_t) buf.st_size,
    199                                                   32 * 1024,   /* 32k page size */
    200                                                   &file_reader, file,
    201                                                   &file_free_callback);
    202     if (NULL == response)
    203     {
    204       fclose (file);
    205       return MHD_NO;
    206     }
    207     ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    208     MHD_destroy_response (response);
    209   }
    210   return ret;
    211 }
    212 
    213 
    214 int
    215 main (int argc, char *const *argv)
    216 {
    217   struct MHD_Daemon *TLS_daemon;
    218   int port;
    219 
    220   if (argc != 2)
    221   {
    222     printf ("%s PORT\n", argv[0]);
    223     return 1;
    224   }
    225   port = atoi (argv[1]);
    226   if ( (1 > port) ||
    227        (port > UINT16_MAX) )
    228   {
    229     fprintf (stderr,
    230              "Port must be a number between 1 and 65535\n");
    231     return 1;
    232   }
    233 
    234   TLS_daemon =
    235     MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
    236                       | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
    237                       | MHD_USE_TLS,
    238                       (uint16_t) port,
    239                       NULL, NULL,
    240                       &http_ahc, NULL,
    241                       MHD_OPTION_CONNECTION_TIMEOUT, 256,
    242                       MHD_OPTION_HTTPS_MEM_KEY, key_pem,
    243                       MHD_OPTION_HTTPS_MEM_CERT, cert_pem,
    244                       MHD_OPTION_END);
    245   if (NULL == TLS_daemon)
    246   {
    247     fprintf (stderr, "Error: failed to start TLS_daemon.\n");
    248     return 1;
    249   }
    250   printf ("MHD daemon listening on port %u\n",
    251           (unsigned int) port);
    252 
    253   (void) getc (stdin);
    254 
    255   MHD_stop_daemon (TLS_daemon);
    256   return 0;
    257 }