libmicrohttpd

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

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 }