typedef struct {
- ngx_array_t indices;
- size_t max_index_len;
+ ngx_array_t indices;
+ size_t max_index_len;
+ ngx_http_cache_hash_t *cache;
} ngx_http_index_conf_t;
#define NGX_HTTP_DEFAULT_INDEX "index.html"
-static int ngx_http_index_test_dir(ngx_http_request_t *r,
- ngx_http_index_ctx_t *ctx);
-static int ngx_http_index_error(ngx_http_request_t *r,
- ngx_http_index_ctx_t *ctx, ngx_err_t err);
+static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r,
+ ngx_http_index_ctx_t *ctx);
+static ngx_int_t ngx_http_index_error(ngx_http_request_t *r,
+ ngx_http_index_ctx_t *ctx, ngx_err_t err);
static int ngx_http_index_init(ngx_cycle_t *cycle);
static void *ngx_http_index_create_conf(ngx_conf_t *cf);
void *conf);
-static ngx_command_t ngx_http_index_commands[] = {
+static ngx_command_t ngx_http_index_commands[] = {
- {ngx_string("index"),
- NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
- ngx_http_index_set_index,
- NGX_HTTP_LOC_CONF_OFFSET,
- 0,
- NULL},
+ { ngx_string("index"),
+ NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_http_index_set_index,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
- ngx_null_command
+ { ngx_string("index_cache"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
+ ngx_http_set_cache_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_index_conf_t, cache),
+ NULL },
+
+ ngx_null_command
};
int ngx_http_index_handler(ngx_http_request_t *r)
{
- int rc;
char *name, *file;
+ uint32_t crc;
+ ngx_int_t rc;
ngx_str_t redirect, *index;
ngx_err_t err;
ngx_fd_t fd;
+ ngx_http_cache_t *cache;
ngx_http_index_ctx_t *ctx;
- ngx_http_index_conf_t *icf;
+ ngx_http_index_conf_t *ilcf;
ngx_http_core_loc_conf_t *clcf;
if (r->uri.data[r->uri.len - 1] != '/') {
return NGX_DECLINED;
}
+ ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);
+
+ if (ilcf->cache) {
+ cache = ngx_http_cache_get(ilcf->cache, &r->uri, &crc);
+
+ngx_log_debug(r->connection->log, "index cache get: %x" _ cache);
+
+ if (cache && ilcf->cache->update >= ngx_cached_time - cache->updated) {
+
+ cache->accessed = ngx_cached_time;
+
+ redirect.len = cache->data.value.len;
+ if (!(redirect.data = ngx_palloc(r->pool, redirect.len + 1))) {
+ ngx_http_cache_unlock(ilcf->cache, cache);
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ ngx_memcpy(redirect.data, cache->data.value.data, redirect.len + 1);
+ ngx_http_cache_unlock(ilcf->cache, cache);
+
+ return ngx_http_internal_redirect(r, &redirect, NULL);
+ }
+
+ } else {
+ cache = NULL;
+ }
+
ctx = ngx_http_get_module_ctx(r, ngx_http_index_module);
if (ctx == NULL) {
ngx_http_create_ctx(r, ctx, ngx_http_index_module,
NGX_HTTP_INTERNAL_SERVER_ERROR);
}
- icf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (r->path.data == NULL) {
r->path_allocated = clcf->doc_root.len + r->uri.len
- + icf->max_index_len;
+ + ilcf->max_index_len;
ngx_test_null(r->path.data,
ngx_palloc(r->pool, r->path_allocated),
NGX_HTTP_INTERNAL_SERVER_ERROR);
file = redirect.data + r->uri.len;
}
- index = icf->indices.elts;
- for (/* void */; ctx->index < icf->indices.nelts; ctx->index++) {
+ index = ilcf->indices.elts;
+ for (/* void */; ctx->index < ilcf->indices.nelts; ctx->index++) {
if (index[ctx->index].data[0] == '/') {
name = index[ctx->index].data;
+ index[ctx->index].len;
}
+ if (ilcf->cache) {
+
+ if (cache) {
+ if (redirect.len == cache->data.value.len
+ && ngx_memcmp(cache->data.value.data, redirect.data,
+ redirect.len) == 0)
+ {
+ cache->accessed = ngx_cached_time;
+ cache->updated = ngx_cached_time;
+ ngx_http_cache_unlock(ilcf->cache, cache);
+
+ return ngx_http_internal_redirect(r, &redirect, NULL);
+
+ } else {
+ if (redirect.len > cache->data.value.len) {
+ ngx_free(cache->data.value.data);
+ cache->data.value.data = NULL;
+ }
+ }
+ }
+
+ if (cache == NULL) {
+ cache = ngx_http_cache_alloc(ilcf->cache, &r->uri, crc,
+ r->connection->log);
+ }
+
+ngx_log_debug(r->connection->log, "index cache alloc: %x" _ cache);
+
+ if (cache) {
+ cache->fd = NGX_INVALID_FILE;
+ cache->accessed = ngx_cached_time;
+ cache->last_modified = 0;
+ cache->updated = ngx_cached_time;
+
+ cache->data.value.len = redirect.len;
+ if (cache->data.value.data == NULL) {
+ cache->data.value.data = ngx_alloc(redirect.len + 1,
+ r->connection->log);
+ if (cache->data.value.data == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+
+ ngx_memcpy(cache->data.value.data, redirect.data,
+ redirect.len + 1);
+ }
+ }
+
+ if (cache) {
+ ngx_http_cache_unlock(ilcf->cache, cache);
+ }
+
return ngx_http_internal_redirect(r, &redirect, NULL);
}
}
-static int ngx_http_index_test_dir(ngx_http_request_t *r,
- ngx_http_index_ctx_t *ctx)
+static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r,
+ ngx_http_index_ctx_t *ctx)
{
ngx_err_t err;
}
-static int ngx_http_index_error(ngx_http_request_t *r,
- ngx_http_index_ctx_t *ctx, ngx_err_t err)
+static ngx_int_t ngx_http_index_error(ngx_http_request_t *r,
+ ngx_http_index_ctx_t *ctx, ngx_err_t err)
{
if (err == NGX_EACCES) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
NGX_CONF_ERROR);
conf->max_index_len = 0;
+ conf->cache = NULL;
+
return conf;
}
conf->max_index_len = prev->max_index_len;
}
+ if (conf->cache == NULL) {
+ conf->cache = prev->cache;
+ }
+
return NGX_CONF_OK;
}
static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
- ngx_http_index_conf_t *icf = conf;
+ ngx_http_index_conf_t *ilcf = conf;
int i;
ngx_str_t *index, *value;
value = cf->args->elts;
- if (value[1].data[0] == '/' && icf->indices.nelts == 0) {
+ if (value[1].data[0] == '/' && ilcf->indices.nelts == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"first index \"%s\" in \"%s\" directive "
"must not be absolute",
return NGX_CONF_ERROR;
}
- ngx_test_null(index, ngx_push_array(&icf->indices), NGX_CONF_ERROR);
+ ngx_test_null(index, ngx_push_array(&ilcf->indices), NGX_CONF_ERROR);
index->len = value[i].len;
index->data = value[i].data;
- if (icf->max_index_len < index->len + 1) {
- icf->max_index_len = index->len + 1;
+ if (ilcf->max_index_len < index->len + 1) {
+ ilcf->max_index_len = index->len + 1;
}
}
*crc = ngx_crc(key->data, key->len);
- c = cache->elts
- + *crc % cache->hash * cache->nelts * sizeof(ngx_http_cache_t);
+ c = cache->elts + *crc % cache->hash * cache->nelts;
+
+ ngx_mutex_lock(&cache->mutex);
for (i = 0; i < cache->nelts; i++) {
if (c[i].crc == *crc
&& ngx_rstrncmp(c[i].key.data, key->data, key->len) == 0)
{
c[i].refs++;
+ ngx_mutex_unlock(&cache->mutex);
return &c[i];
}
}
+ ngx_mutex_unlock(&cache->mutex);
+
return NULL;
}
ngx_uint_t i;
ngx_http_cache_t *c, *found;
- old = ngx_time() + 1;
+ old = ngx_cached_time + 1;
found = NULL;
- c = cache->elts
- + crc % cache->hash * cache->nelts * sizeof(ngx_http_cache_t);
+ c = cache->elts + crc % cache->hash * cache->nelts;
+
+ ngx_mutex_lock(&cache->mutex);
for (i = 0; i < cache->nelts; i++) {
- if (c[i].key.data == NULL) {
+ if (c[i].refs > 0) {
+ /* a busy entry */
+ continue;
+ }
+ if (c[i].key.data == NULL) {
/* a free entry is found */
-
found = &c[i];
break;
}
- /* looking for the oldest cache entry that is not been using */
+ /* looking for the oldest cache entry */
- if (c[i].refs == 0 && old > c[i].accessed) {
+ if (old > c[i].accessed) {
old = c[i].accessed;
found = &c[i];
if (found->key.data == NULL) {
found->key.data = ngx_alloc(key->len, log);
if (found->key.data == NULL) {
+ ngx_mutex_unlock(&cache->mutex);
return NULL;
}
}
found->crc = crc;
found->key.len = key->len;
found->refs = 1;
+ found->count = 0;
found->deleted = 0;
}
+ ngx_mutex_unlock(&cache->mutex);
+
return found;
}
ngx_http_cache_conf_t *prev = parent;
ngx_http_cache_conf_t *conf = child;
+ if (conf->open_files == NULL) {
+ conf->open_files = prev->open_files;
+ }
+
+#if 0
if (conf->open_files == NULL) {
if (prev->open_files) {
conf->open_files = prev->open_files;
}
}
}
+#endif
+
+ return NGX_CONF_OK;
+}
+
+
+char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_int_t i, dup, invalid;
+ ngx_str_t *value, line;
+ ngx_http_cache_hash_t *ch, **chp;
+
+ chp = (ngx_http_cache_hash_t **) (p + cmd->offset);
+ if (*chp) {
+ return "is duplicate";
+ }
+
+ if (!(ch = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_hash_t)))) {
+ return NGX_CONF_ERROR;
+ }
+ *chp = ch;
+
+ dup = 0;
+ invalid = 0;
+
+ value = cf->args->elts;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ if (value[i].data[1] != '=') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid value \"%s\"", value[i].data);
+ return NGX_CONF_ERROR;
+ }
+
+ switch (value[i].data[0]) {
+
+ case 'h':
+ if (ch->hash) {
+ dup = 1;
+ break;
+ }
+
+ ch->hash = ngx_atoi(value[i].data + 2, value[i].len - 2);
+ if (ch->hash == (size_t) NGX_ERROR || ch->hash == 0) {
+ invalid = 1;
+ break;
+ }
+
+ continue;
+
+ case 'n':
+ if (ch->nelts) {
+ dup = 1;
+ break;
+ }
+
+ ch->nelts = ngx_atoi(value[i].data + 2, value[i].len - 2);
+ if (ch->nelts == (size_t) NGX_ERROR || ch->nelts == 0) {
+ invalid = 1;
+ break;
+ }
+
+ continue;
+
+ case 'l':
+ if (ch->life) {
+ dup = 1;
+ break;
+ }
+
+ line.len = value[i].len - 2;
+ line.data = value[i].data + 2;
+
+ ch->life = ngx_parse_time(&line, 1);
+ if (ch->life == NGX_ERROR || ch->life == 0) {
+ invalid = 1;
+ break;
+ }
+
+ continue;
+
+ case 'u':
+ if (ch->update) {
+ dup = 1;
+ break;
+ }
+
+ line.len = value[i].len - 2;
+ line.data = value[i].data + 2;
+
+ ch->update = ngx_parse_time(&line, 1);
+ if (ch->update == NGX_ERROR || ch->update == 0) {
+ invalid = 1;
+ break;
+ }
+
+ continue;
+
+ default:
+ invalid = 1;
+ }
+
+ if (dup) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate value \"%s\"", value[i].data);
+ return NGX_CONF_ERROR;
+ }
+
+ if (invalid) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid value \"%s\"", value[i].data);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ ch->elts = ngx_pcalloc(cf->pool,
+ ch->hash * ch->nelts * sizeof(ngx_http_cache_t));
+ if (ch->elts == NULL) {
+ return NGX_CONF_ERROR;
+ }
return NGX_CONF_OK;
}