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 }