terom@27: #include terom@27: #include terom@27: #include terom@27: #include terom@27: #include terom@27: #include terom@27: #include terom@27: #include terom@27: terom@27: #include terom@27: #include terom@27: terom@27: #include "static.h" terom@27: #include "common.h" terom@27: terom@27: static void _static_hit (struct evhttp_request *request, void *arg) { terom@27: struct static_file *ctx = arg; terom@27: struct evbuffer *buf = NULL; terom@27: int err = -1; terom@27: terom@27: // create the new buffer terom@27: if ((buf = evbuffer_new()) == NULL) terom@27: ERROR("evbuffer_new"); terom@27: terom@27: // XXX: this is so very, very wasteful... terom@27: if (evbuffer_add(buf, ctx->mmap_addr, ctx->size)) terom@27: ERROR("evbuffer_add %zu", ctx->size); terom@27: terom@27: // send the reply... terom@27: evhttp_send_reply(request, HTTP_OK, "OK", buf); terom@27: terom@27: err = 0; terom@27: terom@27: error : terom@27: // free the buffer terom@27: if (buf) terom@27: evbuffer_free(buf); terom@27: terom@27: if (err) terom@27: evhttp_send_error(request, 505, "Internal Server Error"); terom@27: } terom@27: terom@27: int static_init (struct static_file *ctx, struct evhttp *http_server, const char *url, const char *path) { terom@27: struct stat stat_buf; terom@27: terom@27: // clear the ctx terom@27: memset(ctx, 0, sizeof(*ctx)); terom@27: terom@27: // open the file... terom@27: if ((ctx->fh = open(path, O_RDONLY)) == -1) terom@27: PERROR("open(O_RDONLY): %s", path); terom@27: terom@27: // stat the file to get its size terom@27: if (fstat(ctx->fh, &stat_buf)) terom@27: PERROR("fstat: %s", path); terom@27: terom@27: ctx->size = stat_buf.st_size; terom@27: terom@27: // then mmap the file. MAP_POPULATE so that we block now, not later... terom@27: if ((ctx->mmap_addr = mmap(NULL, ctx->size, PROT_READ, MAP_SHARED | MAP_POPULATE, ctx->fh, 0)) == MAP_FAILED) terom@27: PERROR("mmap: %s 0 -> %zu", path, ctx->size); terom@27: terom@27: // finally, add the HTTP request handler terom@27: evhttp_set_cb(http_server, url, &_static_hit, ctx); terom@27: terom@27: INFO("%s -> %s", url, path); terom@27: terom@27: // return terom@27: return 0; terom@27: terom@27: error : terom@27: static_deinit(ctx); terom@27: terom@27: return -1; terom@27: } terom@27: terom@27: void static_deinit (struct static_file *ctx) { terom@27: if (ctx->fh) terom@27: if (close(ctx->fh)) terom@27: PWARNING("close"); terom@27: terom@27: if (ctx->mmap_addr && ctx->mmap_addr != MAP_FAILED) terom@27: if (munmap(ctx->mmap_addr, ctx->size)) terom@27: PWARNING("munmap"); terom@27: } terom@27: terom@27: int static_dir_init (struct static_dir *ctx, struct evhttp *http_server, const char *url_prefix, const char *dir_path) { terom@27: DIR *dir = NULL; terom@27: struct dirent *ent; terom@27: int i = 0; terom@27: char url_buf[STATIC_PATH_MAX], path_buf[STATIC_PATH_MAX]; terom@27: terom@27: // init the ctx terom@27: ctx->file_count = 0; terom@27: terom@27: // open the dir terom@27: if ((dir = opendir(dir_path)) == NULL) terom@27: PERROR("opendir: %s", dir_path); terom@27: terom@27: // scan the files terom@27: while ((ent = readdir(dir)) != NULL) { terom@27: // skip dotfiles terom@27: if (ent->d_name[0] == '.') terom@27: continue; terom@27: terom@27: // check we still have space terom@27: if (i >= STATIC_DIR_MAX) { terom@27: PWARNING("static_dir is full: %d", i); terom@27: break; terom@27: } terom@27: terom@27: // format the url/path bufs terom@27: snprintf(url_buf, STATIC_PATH_MAX, "%s/%s", url_prefix, ent->d_name); terom@27: snprintf(path_buf, STATIC_PATH_MAX, "%s/%s", dir_path, ent->d_name); terom@27: terom@27: // init the static_file terom@27: static_init(&ctx->files[i], http_server, url_buf, path_buf); terom@27: terom@27: // remember how many files are in use and move on to the next one terom@27: ctx->file_count = ++i; terom@27: } terom@27: terom@27: terom@27: // ok terom@27: return 0; terom@27: terom@27: error: terom@27: static_dir_deinit(ctx); terom@27: terom@27: return -1; terom@27: } terom@27: terom@27: void static_dir_deinit (struct static_dir *ctx) { terom@27: for (int i = 0; i < ctx->file_count; i++) { terom@27: static_deinit(&ctx->files[i]); terom@27: } terom@27: }