Home | History | Annotate | Download | only in examples
      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007 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 /**
     21  * @file fileserver_example.c
     22  * @brief example for how to use libmicrohttpd to serve files (with directory support)
     23  * @author Christian Grothoff
     24  */
     25 
     26 #include "platform.h"
     27 #include <dirent.h>
     28 #include <microhttpd.h>
     29 #include <unistd.h>
     30 
     31 #define PAGE "<html><head><title>File not found</title></head><body>File not found</body></html>"
     32 
     33 static ssize_t
     34 file_reader (void *cls, uint64_t pos, char *buf, size_t max)
     35 {
     36   FILE *file = cls;
     37 
     38   (void) fseek (file, pos, SEEK_SET);
     39   return fread (buf, 1, max, file);
     40 }
     41 
     42 static void
     43 file_free_callback (void *cls)
     44 {
     45   FILE *file = cls;
     46   fclose (file);
     47 }
     48 
     49 static void
     50 dir_free_callback (void *cls)
     51 {
     52   DIR *dir = cls;
     53   if (dir != NULL)
     54     closedir (dir);
     55 }
     56 
     57 static ssize_t
     58 dir_reader (void *cls, uint64_t pos, char *buf, size_t max)
     59 {
     60   DIR *dir = cls;
     61   struct dirent *e;
     62 
     63   if (max < 512)
     64     return 0;
     65   do
     66     {
     67       e = readdir (dir);
     68       if (e == NULL)
     69         return MHD_CONTENT_READER_END_OF_STREAM;
     70   } while (e->d_name[0] == '.');
     71   return snprintf (buf, max,
     72 		   "<a href=\"/%s\">%s</a><br>",
     73 		   e->d_name,
     74 		   e->d_name);
     75 }
     76 
     77 
     78 static int
     79 ahc_echo (void *cls,
     80           struct MHD_Connection *connection,
     81           const char *url,
     82           const char *method,
     83           const char *version,
     84           const char *upload_data,
     85 	  size_t *upload_data_size, void **ptr)
     86 {
     87   static int aptr;
     88   struct MHD_Response *response;
     89   int ret;
     90   FILE *file;
     91   DIR *dir;
     92   struct stat buf;
     93   char emsg[1024];
     94 
     95   if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
     96     return MHD_NO;              /* unexpected method */
     97   if (&aptr != *ptr)
     98     {
     99       /* do never respond on first call */
    100       *ptr = &aptr;
    101       return MHD_YES;
    102     }
    103   *ptr = NULL;                  /* reset when done */
    104   if ( (0 == stat (&url[1], &buf)) &&
    105        (S_ISREG (buf.st_mode)) )
    106     file = fopen (&url[1], "rb");
    107   else
    108     file = NULL;
    109   if (file == NULL)
    110     {
    111       dir = opendir (".");
    112       if (dir == NULL)
    113 	{
    114 	  /* most likely cause: more concurrent requests than
    115 	     available file descriptors / 2 */
    116 	  snprintf (emsg,
    117 		    sizeof (emsg),
    118 		    "Failed to open directory `.': %s\n",
    119 		    strerror (errno));
    120 	  response = MHD_create_response_from_buffer (strlen (emsg),
    121 						      emsg,
    122 						      MHD_RESPMEM_MUST_COPY);
    123 	  if (response == NULL)
    124 	    return MHD_NO;
    125 	  ret = MHD_queue_response (connection, MHD_HTTP_SERVICE_UNAVAILABLE, response);
    126 	  MHD_destroy_response (response);
    127 	}
    128       else
    129 	{
    130 	  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
    131 							32 * 1024,
    132 							&dir_reader,
    133 							dir,
    134 							&dir_free_callback);
    135 	  if (response == NULL)
    136 	    {
    137 	      closedir (dir);
    138 	      return MHD_NO;
    139 	    }
    140 	  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    141 	  MHD_destroy_response (response);
    142 	}
    143     }
    144   else
    145     {
    146       response = MHD_create_response_from_callback (buf.st_size, 32 * 1024,     /* 32k page size */
    147                                                     &file_reader,
    148                                                     file,
    149                                                     &file_free_callback);
    150       if (response == NULL)
    151 	{
    152 	  fclose (file);
    153 	  return MHD_NO;
    154 	}
    155       ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    156       MHD_destroy_response (response);
    157     }
    158   return ret;
    159 }
    160 
    161 int
    162 main (int argc, char *const *argv)
    163 {
    164   struct MHD_Daemon *d;
    165 
    166   if (argc != 2)
    167     {
    168       printf ("%s PORT\n", argv[0]);
    169       return 1;
    170     }
    171   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
    172                         atoi (argv[1]),
    173                         NULL, NULL, &ahc_echo, PAGE, MHD_OPTION_END);
    174   if (d == NULL)
    175     return 1;
    176   (void) getc (stdin);
    177   MHD_stop_daemon (d);
    178   return 0;
    179 }
    180