Exemple #1
0
h2o_filecache_ref_t *h2o_filecache_open_file(h2o_filecache_t *cache, const char *path, int oflag)
{
    khiter_t iter = kh_get(opencache_set, cache->hash, path);
    h2o_filecache_ref_t *ref;
    int dummy;

    /* lookup cache, and return the one if found */
    if (iter != kh_end(cache->hash)) {
        ref = H2O_STRUCT_FROM_MEMBER(h2o_filecache_ref_t, _path, kh_key(cache->hash, iter));
        ++ref->_refcnt;
        goto Exit;
    }

    /* create a new cache entry */
    ref = h2o_mem_alloc(offsetof(h2o_filecache_ref_t, _path) + strlen(path) + 1);
    ref->_refcnt = 1;
    ref->_lru = (h2o_linklist_t){NULL};
    strcpy(ref->_path, path);

    /* if cache is used, then... */
    if (cache->capacity != 0) {
        /* purge one entry from LRU if cache is full */
        if (kh_size(cache->hash) == cache->capacity) {
            h2o_filecache_ref_t *purge_ref = H2O_STRUCT_FROM_MEMBER(h2o_filecache_ref_t, _lru, cache->lru.prev);
            khiter_t purge_iter = kh_get(opencache_set, cache->hash, purge_ref->_path);
            assert(purge_iter != kh_end(cache->hash));
            release_from_cache(cache, purge_iter);
        }
        /* assign the new entry */
        ++ref->_refcnt;
        kh_put(opencache_set, cache->hash, ref->_path, &dummy);
        h2o_linklist_insert(cache->lru.next, &ref->_lru);
    }

    /* open the file, or memoize the error */
    if ((ref->fd = open(path, oflag)) != -1 && fstat(ref->fd, &ref->st) == 0) {
        ref->_last_modified.str[0] = '\0';
        ref->_etag.len = 0;
    } else {
        ref->open_err = errno;
        if (ref->fd != -1) {
            close(ref->fd);
            ref->fd = -1;
        }
    }

Exit:
    /* if the cache entry retains an error, return it instead of the reference */
    if (ref->fd == -1) {
        errno = ref->open_err;
        h2o_filecache_close_file(ref);
        ref = NULL;
    }
    return ref;
}
Exemple #2
0
static struct st_h2o_sendfile_generator_t *create_generator(h2o_req_t *req, const char *path, size_t path_len, int *is_dir,
                                                            int flags)
{
    struct st_h2o_sendfile_generator_t *self;
    h2o_filecache_ref_t *fileref;
    h2o_iovec_t content_encoding;

    *is_dir = 0;

    if ((flags & H2O_FILE_FLAG_SEND_COMPRESSED) != 0 && req->version >= 0x101) {
        int compressible_types = h2o_get_compressible_types(&req->headers);
        if (compressible_types != 0) {
            char *variant_path = h2o_mem_alloc_pool(&req->pool, path_len + sizeof(".gz"));
            memcpy(variant_path, path, path_len);
#define TRY_VARIANT(mask, enc, ext)                                                                                                \
    if ((compressible_types & mask) != 0) {                                                                                        \
        strcpy(variant_path + path_len, ext);                                                                                      \
        if ((fileref = h2o_filecache_open_file(req->conn->ctx->filecache, variant_path, O_RDONLY | O_CLOEXEC)) != NULL) {          \
            content_encoding = h2o_iovec_init(enc, sizeof(enc) - 1);                                                               \
            goto Opened;                                                                                                           \
        }                                                                                                                          \
    }
            TRY_VARIANT(H2O_COMPRESSIBLE_BROTLI, "br", ".br");
            TRY_VARIANT(H2O_COMPRESSIBLE_GZIP, "gzip", ".gz");
#undef TRY_VARIANT
        }
    }
    if ((fileref = h2o_filecache_open_file(req->conn->ctx->filecache, path, O_RDONLY | O_CLOEXEC)) == NULL)
        return NULL;
    content_encoding = (h2o_iovec_t){};

Opened:
    if (S_ISDIR(fileref->st.st_mode)) {
        h2o_filecache_close_file(fileref);
        *is_dir = 1;
        return NULL;
    }

    self = h2o_mem_alloc_pool(&req->pool, sizeof(*self));
    self->super.proceed = do_proceed;
    self->super.stop = do_close;
    self->file.ref = fileref;
    self->file.off = 0;
    self->req = NULL;
    self->bytesleft = self->file.ref->st.st_size;
    self->ranged.range_count = 0;
    self->ranged.range_infos = NULL;
    self->content_encoding = content_encoding;
    self->send_vary = (flags & H2O_FILE_FLAG_SEND_COMPRESSED) != 0;
    self->send_etag = (flags & H2O_FILE_FLAG_NO_ETAG) == 0;

    return self;
}
Exemple #3
0
static inline void release_from_cache(h2o_filecache_t *cache, khiter_t iter)
{
    const char *path = kh_key(cache->hash, iter);
    h2o_filecache_ref_t *ref = H2O_STRUCT_FROM_MEMBER(h2o_filecache_ref_t, _path, path);

    /* detach from list */
    kh_del(opencache_set, cache->hash, iter);
    h2o_linklist_unlink(&ref->_lru);

    /* and close */
    h2o_filecache_close_file(ref);
}
Exemple #4
0
static void do_close(h2o_generator_t *_self, h2o_req_t *req)
{
    struct st_h2o_sendfile_generator_t *self = (void *)_self;
    h2o_filecache_close_file(self->file.ref);
}