fileserver_example.c (4375B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007 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 fileserver_example.c 22 * @brief minimal example for how to use libmicrohttpd to serve files 23 * @author Christian Grothoff 24 * @author Karlson2k (Evgeny Grin) 25 */ 26 27 #include "platform.h" 28 #include <microhttpd.h> 29 #ifdef HAVE_UNISTD_H 30 #include <unistd.h> 31 #endif /* HAVE_UNISTD_H */ 32 #ifdef HAVE_SYS_STAT_H 33 #include <sys/stat.h> 34 #endif /* HAVE_SYS_STAT_H */ 35 #ifdef HAVE_FCNTL_H 36 #include <fcntl.h> 37 #endif /* HAVE_FCNTL_H */ 38 39 #define PAGE \ 40 "<html><head><title>File not found</title></head><body>File not found</body></html>" 41 42 #ifndef S_ISREG 43 #define S_ISREG(x) (S_IFREG == (x & S_IFREG)) 44 #endif /* S_ISREG */ 45 46 static enum MHD_Result 47 ahc_echo (void *cls, 48 struct MHD_Connection *connection, 49 const char *url, 50 const char *method, 51 const char *version, 52 const char *upload_data, 53 size_t *upload_data_size, void **req_cls) 54 { 55 static int aptr; 56 struct MHD_Response *response; 57 enum MHD_Result ret; 58 int fd; 59 struct stat buf; 60 (void) cls; /* Unused. Silent compiler warning. */ 61 (void) version; /* Unused. Silent compiler warning. */ 62 (void) upload_data; /* Unused. Silent compiler warning. */ 63 (void) upload_data_size; /* Unused. Silent compiler warning. */ 64 65 if ( (0 != strcmp (method, MHD_HTTP_METHOD_GET)) && 66 (0 != strcmp (method, MHD_HTTP_METHOD_HEAD)) ) 67 return MHD_NO; /* unexpected method */ 68 if (&aptr != *req_cls) 69 { 70 /* do never respond on first call */ 71 *req_cls = &aptr; 72 return MHD_YES; 73 } 74 *req_cls = NULL; /* reset when done */ 75 /* WARNING: direct usage of url as filename is for example only! 76 * NEVER pass received data directly as parameter to file manipulation 77 * functions. Always check validity of data before using. 78 */ 79 if (NULL != strstr (url, "../")) /* Very simplified check! */ 80 fd = -1; /* Do not allow usage of parent directories. */ 81 else 82 fd = open (url + 1, O_RDONLY); 83 if (-1 != fd) 84 { 85 if ( (0 != fstat (fd, &buf)) || 86 (! S_ISREG (buf.st_mode)) ) 87 { 88 /* not a regular file, refuse to serve */ 89 if (0 != close (fd)) 90 abort (); 91 fd = -1; 92 } 93 } 94 if (-1 == fd) 95 { 96 response = MHD_create_response_from_buffer_static (strlen (PAGE), 97 PAGE); 98 ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response); 99 MHD_destroy_response (response); 100 } 101 else 102 { 103 response = MHD_create_response_from_fd64 ((uint64_t) buf.st_size, fd); 104 if (NULL == response) 105 { 106 if (0 != close (fd)) 107 abort (); 108 return MHD_NO; 109 } 110 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 111 MHD_destroy_response (response); 112 } 113 return ret; 114 } 115 116 117 int 118 main (int argc, char *const *argv) 119 { 120 struct MHD_Daemon *d; 121 int port; 122 123 if (argc != 2) 124 { 125 printf ("%s PORT\n", argv[0]); 126 return 1; 127 } 128 port = atoi (argv[1]); 129 if ( (1 > port) || (port > 65535) ) 130 { 131 fprintf (stderr, 132 "Port must be a number between 1 and 65535.\n"); 133 return 1; 134 } 135 136 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION 137 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, 138 (uint16_t) port, 139 NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); 140 if (d == NULL) 141 return 1; 142 (void) getc (stdin); 143 MHD_stop_daemon (d); 144 return 0; 145 }