1 /*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2008 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 * @file https_fileserver_example.c
21 * @brief a simple HTTPS file server using TLS.
22 *
23 * Usage :
24 *
25 * 'http_fileserver_example HTTP-PORT SECONDS-TO-RUN'
26 *
27 * The certificate & key are required by the server to operate, omitting the
28 * path arguments will cause the server to use the hard coded example certificate & key.
29 *
30 * 'certtool' may be used to generate these if required.
31 *
32 * @author Sagie Amir
33 */
34
35 #include "platform.h"
36 #include <microhttpd.h>
37 #include <sys/stat.h>
38
39 #define BUF_SIZE 1024
40 #define MAX_URL_LEN 255
41
42 /* TODO remove if unused */
43 #define CAFILE "ca.pem"
44 #define CRLFILE "crl.pem"
45
46 #define EMPTY_PAGE \
47 "<html><head><title>File not found</title></head><body>File not found</body></html>"
48
49 /* test server key */
50 const char key_pem[] =
51 "-----BEGIN PRIVATE KEY-----\n\
52 MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrm8uH8V0P2Xbl\n\
53 HCMq6PTIphDcMmXEDiciCAAbfS7rVUyEJBgRpKSb+IXpj6jX1+e0+uncBxO9fesZ\n\
54 Vyg4ksOA7jITGlzOjBvX6RzxkE9I96R3RCgzUHyYB8ayVSj1s/WmhorVPhKQjCmd\n\
55 6mi978n//bZKqTpq3OMpDrNC6AWTiHHP5KV9pp3Hsz1iAGK74sSVP3vhYD8IZ5yg\n\
56 CR99TDDHZfIvOmbqS60kx/UclUf2R4mSv/ZZHaHW7PeUhtUxzwOYqWVj0zLv/Lni\n\
57 CGO9uXGOgZHFfL8PhQwt6pNT5DaVmqx/uGwpsLiER4P74ngwroSjMwavYNlykuLF\n\
58 1N8GZZC7AgMBAAECggEAc0F/wR3qUurLX7U2KWuse9aNHFb84mBfCAw3hj7ddFEl\n\
59 wto7EB50MA0KY4OI8u6fQH4E8zINoAciDzLqYJSxmbZhC1N5YX/Yc3qtZdB2b5tj\n\
60 anbsSQqVo8YVPVDU4bCsG9vhArdd4JdCnD0DfA3ArZ3JAPwHsB4Ks1icLSOIGz0/\n\
61 JvOZEryJBdwM6SKbzLMqVOGmYDiY6s7UpJ0rg3cOPqhdg5xv8XZATqXISU0mLBcq\n\
62 RiS7lHZERASYON2rpznhBiCtikOcr/duQhvZ1uDSGfDzDJil+1hdS3RouS9WZCIe\n\
63 p3CtvZhPLmv6kFg9YE+AovDwOOwNr0no3H9oJA2FgQKBgQDSWrE/MRMRpFJFBxxC\n\
64 YckC2v8Y+7sVSMbFNq/0j2eRTql+8AeZBbAoGU4QHUcylCBkv33zDYRY52xNo32E\n\
65 8mmH2O/pIcYy0LafrVZHdulf+fxybncObidxmmjR9C8aLzwRuIMtABz4simaQcBD\n\
66 RhZJ1YCqVkfMr/PlbLzvC8V+FwKBgQDQ2MF/Yz/p7QEDHpfKdtx7+yK6i8IM+V8l\n\
67 d2OuscNkQQywCVqE2vyRZJbjU9y+Om7alNKFPhhBzavdOxNWXGXmlBIlvo3v6M++\n\
68 fTixza77LxHvbghH0ykplSwGh30vpHtvoxsRS5nRFxmsVK9jNYYT/Aes+J6MXlq7\n\
69 PYAiZVQs/QKBgFKYY8JhPZCOyfLqsNDr3matoL6pkTLxSYMETyCi8lKe5XS/QOx3\n\
70 zExia0FujZcxjGqiugymgRH7hI4TpOR/3qoFp2YN6enoA908zYTwDwCtgs9Xyo2y\n\
71 +O/lZkUSMTCB3X9DyNXxlm6cXjOAn8KKkZPaLlQz3qtjZ0vtX14pbBlvAoGBAKw0\n\
72 vsCifvYNZhNDa5gXkFBu0MEPMm/uQ+Up37kRfPKyrJqO6+O2iiH81moWIWN93SBB\n\
73 LKGPhQLlazxdVOGWCLQrDhevW2wiBQKmUFRULF+T/W72xL8sv7k49ndfyvq43ss7\n\
74 q7sEIo4FRTcTERd179uUqmOXEWze9GOGH5y8/r6lAoGAG2YyqRWF+yxKlgR71b1Q\n\
75 Zxv53WgXOUwemGRbXxE4g3gHpW5k9zWh4QTkbd0lDD+SQ0DBwZl/x/FWj43jUS+i\n\
76 a5UojDUx8nYgjiAO7kppMlX3ZaJD1DkwEz+4HW9oPmOFt8smvuTVt0mm6tpmQdRA\n\
77 yLwgQzGDGVJB6ETVJS7cwWs=\n\
78 -----END PRIVATE KEY-----";
79
80 /* test server CA signed certificates */
81 const char cert_pem[] =
82 "-----BEGIN CERTIFICATE-----\n\
83 MIIFaTCCA1GgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n\
84 DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n\
85 LWxpYm1pY3JvaHR0cGQxITAfBgkqhkiG9w0BCQEWEm5vYm9keUBleGFtcGxlLm9y\n\
86 ZzEQMA4GA1UEAwwHdGVzdC1DQTAgFw0yMTA0MDcxNzM2MjFaGA8yMTIxMDMxMzE3\n\
87 MzYyMVowgYcxCzAJBgNVBAYTAlJVMQ8wDQYDVQQIDAZNb3Njb3cxDzANBgNVBAcM\n\
88 Bk1vc2NvdzEbMBkGA1UECgwSdGVzdC1saWJtaWNyb2h0dHBkMRQwEgYDVQQDDAt0\n\
89 ZXN0LXNlcnZlcjEjMCEGA1UdEQwaRE5TOmxvY2FsaG9zdCxJUDoxMjcuMC4wLjEw\n\
90 ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrm8uH8V0P2XblHCMq6PTI\n\
91 phDcMmXEDiciCAAbfS7rVUyEJBgRpKSb+IXpj6jX1+e0+uncBxO9fesZVyg4ksOA\n\
92 7jITGlzOjBvX6RzxkE9I96R3RCgzUHyYB8ayVSj1s/WmhorVPhKQjCmd6mi978n/\n\
93 /bZKqTpq3OMpDrNC6AWTiHHP5KV9pp3Hsz1iAGK74sSVP3vhYD8IZ5ygCR99TDDH\n\
94 ZfIvOmbqS60kx/UclUf2R4mSv/ZZHaHW7PeUhtUxzwOYqWVj0zLv/LniCGO9uXGO\n\
95 gZHFfL8PhQwt6pNT5DaVmqx/uGwpsLiER4P74ngwroSjMwavYNlykuLF1N8GZZC7\n\
96 AgMBAAGjgeEwgd4wCwYDVR0PBAQDAgWgMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/\n\
97 BAwwCgYIKwYBBQUHAwEwLAYDVR0RBCUwI4IJbG9jYWxob3N0hwR/AAABhxAAAAAA\n\
98 AAAAAAAAAAAAAAABMB0GA1UdDgQWBBRifkHd2xWI51NhnH8sL66K8EedpjAoBglg\n\
99 hkgBhvhCAQ0EGxYZVGVzdCBsaWJtaWNyb2h0dHBkIHNlcnZlcjARBglghkgBhvhC\n\
100 AQEEBAMCBkAwHwYDVR0jBBgwFoAUWHVDwKVqMcOFNd0arI3/QB3W6SwwDQYJKoZI\n\
101 hvcNAQELBQADggIBAJoIyNrnwQ+7WcJDaBjjuwSH0ORuK+E3zRI3+nDde08gyfeG\n\
102 K4QozT2L574WzadTVLSiin9lRShYlp0nr60pmUb9+SKE0O7Cx+rYV0Rfu0KLYsYh\n\
103 sAkb9J9t1fdIt54fXNcUtvfGPyM2lEI0KxMCGNV2wXDnwzdSNIU6Nk457MntfZdi\n\
104 r1ISnS6fLd0BIKIGxfCFb10CexhNOSaExgpp1bxZovdYaQWggL0u8eC8j00sJ1C5\n\
105 Qo4gQ1TQsead6zMs6m19TPLlV7hS+hfXj7yeJ/TTUj69bCjTIMp6HCFnfQbD84BI\n\
106 HZDKk4Tob9vBRCKbY58kNXHyQ4nxvSCBlKI03VJjvzpsKTI/vW9JBivtnYtMbMl9\n\
107 ouZal/IVsNqRCeiMTLky62qrFhZr2DHgPG5VcOGQ4y0X4vOgM9n/MMOGWcNBByLX\n\
108 b5ZaYr7DPCcz9dYZgEbwXj8wnuAzM1sJ2igwTmO/vQsn1G2Q/h/JB471CD1avuuI\n\
109 awKRqhU2KhYVrwo7ahJkPV9Lm6eoavq2Tu+e1o4qAFhPLMy/6F+bZmK6GfHMvP+L\n\
110 v+GOQdUJ/vMMus/HB5N3cUZsu9rGnCCVgPW7pkHrp5bRtuVzBT78ISsxkGnOhfT7\n\
111 6Kp7ApvfEX6/Y/vbDFBC4kyAvEIZ+F8AUkbvZ0+k8j5xlarNd6TQ3slEGi6O\n\
112 -----END CERTIFICATE-----";
113
114 static ssize_t
file_reader(void * cls,uint64_t pos,char * buf,size_t max)115 file_reader (void *cls, uint64_t pos, char *buf, size_t max)
116 {
117 FILE *file = cls;
118
119 (void) fseek (file, pos, SEEK_SET);
120 return fread (buf, 1, max, file);
121 }
122
123
124 static void
file_free_callback(void * cls)125 file_free_callback (void *cls)
126 {
127 FILE *file = cls;
128 fclose (file);
129 }
130
131
132 /* HTTP access handler call back */
133 static enum MHD_Result
http_ahc(void * cls,struct MHD_Connection * connection,const char * url,const char * method,const char * version,const char * upload_data,size_t * upload_data_size,void ** ptr)134 http_ahc (void *cls,
135 struct MHD_Connection *connection,
136 const char *url,
137 const char *method,
138 const char *version,
139 const char *upload_data,
140 size_t *upload_data_size, void **ptr)
141 {
142 static int aptr;
143 struct MHD_Response *response;
144 enum MHD_Result ret;
145 FILE *file;
146 int fd;
147 struct stat buf;
148 (void) cls; /* Unused. Silent compiler warning. */
149 (void) version; /* Unused. Silent compiler warning. */
150 (void) upload_data; /* Unused. Silent compiler warning. */
151 (void) upload_data_size; /* Unused. Silent compiler warning. */
152
153 if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
154 return MHD_NO; /* unexpected method */
155 if (&aptr != *ptr)
156 {
157 /* do never respond on first call */
158 *ptr = &aptr;
159 return MHD_YES;
160 }
161 *ptr = NULL; /* reset when done */
162
163 file = fopen (&url[1], "rb");
164 if (NULL != file)
165 {
166 fd = fileno (file);
167 if (-1 == fd)
168 {
169 (void) fclose (file);
170 return MHD_NO; /* internal error */
171 }
172 if ( (0 != fstat (fd, &buf)) ||
173 (! S_ISREG (buf.st_mode)) )
174 {
175 /* not a regular file, refuse to serve */
176 fclose (file);
177 file = NULL;
178 }
179 }
180
181 if (NULL == file)
182 {
183 response = MHD_create_response_from_buffer (strlen (EMPTY_PAGE),
184 (void *) EMPTY_PAGE,
185 MHD_RESPMEM_PERSISTENT);
186 ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response);
187 MHD_destroy_response (response);
188 }
189 else
190 {
191 response = MHD_create_response_from_callback (buf.st_size, 32 * 1024, /* 32k PAGE_NOT_FOUND size */
192 &file_reader, file,
193 &file_free_callback);
194 if (NULL == response)
195 {
196 fclose (file);
197 return MHD_NO;
198 }
199 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
200 MHD_destroy_response (response);
201 }
202 return ret;
203 }
204
205
206 int
main(int argc,char * const * argv)207 main (int argc, char *const *argv)
208 {
209 struct MHD_Daemon *TLS_daemon;
210 int port;
211
212 if (argc != 2)
213 {
214 printf ("%s PORT\n", argv[0]);
215 return 1;
216 }
217 port = atoi (argv[1]);
218 if ( (1 > port) ||
219 (port > UINT16_MAX) )
220 {
221 fprintf (stderr,
222 "Port must be a number between 1 and 65535\n");
223 return 1;
224 }
225
226 TLS_daemon =
227 MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
228 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
229 | MHD_USE_TLS,
230 (uint16_t) port,
231 NULL, NULL,
232 &http_ahc, NULL,
233 MHD_OPTION_CONNECTION_TIMEOUT, 256,
234 MHD_OPTION_HTTPS_MEM_KEY, key_pem,
235 MHD_OPTION_HTTPS_MEM_CERT, cert_pem,
236 MHD_OPTION_END);
237 if (NULL == TLS_daemon)
238 {
239 fprintf (stderr, "Error: failed to start TLS_daemon.\n");
240 return 1;
241 }
242 printf ("MHD daemon listening on port %u\n",
243 (unsigned int) port);
244
245 (void) getc (stdin);
246
247 MHD_stop_daemon (TLS_daemon);
248 return 0;
249 }
250