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