static.c
changeset 27 1e79b4cc8f1b
equal deleted inserted replaced
26:6d615203d963 27:1e79b4cc8f1b
       
     1 #include <sys/types.h>
       
     2 #include <sys/stat.h>
       
     3 #include <dirent.h>
       
     4 #include <fcntl.h>
       
     5 #include <unistd.h>
       
     6 #include <sys/mman.h>
       
     7 #include <stdio.h>
       
     8 #include <string.h>
       
     9 
       
    10 #include <event2/http.h>
       
    11 #include <event2/buffer.h>
       
    12 
       
    13 #include "static.h"
       
    14 #include "common.h"
       
    15 
       
    16 static void _static_hit (struct evhttp_request *request, void *arg) {
       
    17     struct static_file *ctx = arg;
       
    18     struct evbuffer *buf = NULL;
       
    19     int err = -1;
       
    20     
       
    21     // create the new buffer
       
    22     if ((buf = evbuffer_new()) == NULL)
       
    23         ERROR("evbuffer_new");
       
    24     
       
    25     // XXX: this is so very, very wasteful...
       
    26     if (evbuffer_add(buf, ctx->mmap_addr, ctx->size))
       
    27         ERROR("evbuffer_add %zu", ctx->size);
       
    28     
       
    29     // send the reply...
       
    30     evhttp_send_reply(request, HTTP_OK, "OK", buf);
       
    31     
       
    32     err = 0;
       
    33 
       
    34 error :
       
    35     // free the buffer
       
    36     if (buf)
       
    37         evbuffer_free(buf);
       
    38 
       
    39     if (err)
       
    40         evhttp_send_error(request, 505, "Internal Server Error");
       
    41 }
       
    42 
       
    43 int static_init (struct static_file *ctx, struct evhttp *http_server, const char *url, const char *path) {
       
    44     struct stat stat_buf;
       
    45 
       
    46     // clear the ctx
       
    47     memset(ctx, 0, sizeof(*ctx));
       
    48     
       
    49     // open the file...
       
    50     if ((ctx->fh = open(path, O_RDONLY)) == -1)
       
    51         PERROR("open(O_RDONLY): %s", path);
       
    52 
       
    53     // stat the file to get its size
       
    54     if (fstat(ctx->fh, &stat_buf))
       
    55         PERROR("fstat: %s", path);
       
    56     
       
    57     ctx->size = stat_buf.st_size;
       
    58 
       
    59     // then mmap the file. MAP_POPULATE so that we block now, not later...
       
    60     if ((ctx->mmap_addr = mmap(NULL, ctx->size, PROT_READ, MAP_SHARED | MAP_POPULATE, ctx->fh, 0)) == MAP_FAILED)
       
    61         PERROR("mmap: %s 0 -> %zu", path, ctx->size);
       
    62     
       
    63     // finally, add the HTTP request handler
       
    64     evhttp_set_cb(http_server, url, &_static_hit, ctx);
       
    65     
       
    66     INFO("%s -> %s", url, path);
       
    67 
       
    68     // return 
       
    69     return 0;
       
    70 
       
    71 error :
       
    72     static_deinit(ctx);
       
    73 
       
    74     return -1;
       
    75 }
       
    76 
       
    77 void static_deinit (struct static_file *ctx) {
       
    78     if (ctx->fh)
       
    79         if (close(ctx->fh))
       
    80             PWARNING("close");
       
    81 
       
    82     if (ctx->mmap_addr && ctx->mmap_addr != MAP_FAILED)
       
    83         if (munmap(ctx->mmap_addr, ctx->size))
       
    84             PWARNING("munmap");
       
    85 }
       
    86 
       
    87 int static_dir_init (struct static_dir *ctx, struct evhttp *http_server, const char *url_prefix, const char *dir_path) {
       
    88     DIR *dir = NULL;
       
    89     struct dirent *ent;
       
    90     int i = 0;
       
    91     char url_buf[STATIC_PATH_MAX], path_buf[STATIC_PATH_MAX];
       
    92 
       
    93     // init the ctx
       
    94     ctx->file_count = 0;
       
    95 
       
    96     // open the dir
       
    97     if ((dir = opendir(dir_path)) == NULL)
       
    98         PERROR("opendir: %s", dir_path);
       
    99     
       
   100     // scan the files
       
   101     while ((ent = readdir(dir)) != NULL) {
       
   102         // skip dotfiles
       
   103         if (ent->d_name[0] == '.')
       
   104             continue;
       
   105 
       
   106         // check we still have space
       
   107         if (i >= STATIC_DIR_MAX) {
       
   108             PWARNING("static_dir is full: %d", i);
       
   109             break;
       
   110         }
       
   111 
       
   112         // format the url/path bufs
       
   113         snprintf(url_buf, STATIC_PATH_MAX, "%s/%s", url_prefix, ent->d_name);
       
   114         snprintf(path_buf, STATIC_PATH_MAX, "%s/%s", dir_path, ent->d_name);
       
   115         
       
   116         // init the static_file
       
   117         static_init(&ctx->files[i], http_server, url_buf, path_buf);
       
   118         
       
   119         // remember how many files are in use and move on to the next one
       
   120         ctx->file_count = ++i;
       
   121     }
       
   122     
       
   123 
       
   124     // ok
       
   125     return 0;
       
   126 
       
   127 error:
       
   128     static_dir_deinit(ctx);
       
   129 
       
   130     return -1;
       
   131 }
       
   132 
       
   133 void static_dir_deinit (struct static_dir *ctx) {
       
   134     for (int i = 0; i < ctx->file_count; i++) {
       
   135         static_deinit(&ctx->files[i]);
       
   136     }
       
   137 }