Mercurial > hg > nginx-mail
view src/http/ngx_http_file_cache.c @ 436:9b19e26b2660
Mail: smtp pipelining support.
Basically, this does the following two changes (and corresponding
modifications of related code):
1. Does not reset session buffer unless it's reached it's end, and always
wait for LF to terminate command (even if we detected invalid command).
2. Record command name as the first argument to make it available for
handlers (since now we can't assume that command starts from s->buffer->start).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 11 Sep 2008 15:26:25 +0400 |
parents | 13710a1813ad |
children | c8cfb6c462ef |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> #if (NGX_HAVE_OPENSSL_MD5_H) #include <openssl/md5.h> #else #include <md5.h> #endif #if (NGX_OPENSSL_MD5) #define MD5Init MD5_Init #define MD5Update MD5_Update #define MD5Final MD5_Final #endif ngx_int_t ngx_http_file_cache_get(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx) { ngx_uint_t i; ngx_str_t *key; ngx_http_cache_t *c; MD5_CTX md5; c = r->cache; c->file.name.len = ctx->path->name.len + 1 + ctx->path->len + 32; if (!(c->file.name.data = ngx_palloc(r->pool, c->file.name.len + 1))) { return NGX_ABORT; } MD5Init(&md5); key = c->key.elts; for (i = 0; i < c->key.nelts; i++) { MD5Update(&md5, key[i].data, key[i].len); } MD5Update(&md5, ctx->key.data, ctx->key.len); MD5Final(c->md5, &md5); ngx_memcpy(c->file.name.data, ctx->path->name.data, ctx->path->name.len); ngx_md5_text(c->file.name.data + ctx->path->name.len + 1 + ctx->path->len, c->md5); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "file cache key: %V, md5: %s", &ctx->key, c->file.name.data + ctx->path->name.len + 1 + ctx->path->len); ngx_create_hashed_filename(&c->file, ctx->path); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "file cache name: %s", c->file.name.data); return ngx_http_file_cache_open(r->cache); } ngx_int_t ngx_http_file_cache_open(ngx_http_cache_t *c) { ssize_t n; ngx_err_t err; ngx_http_cache_header_t *h; c->file.fd = ngx_open_file(c->file.name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN); if (c->file.fd == NGX_INVALID_FILE) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR) { return NGX_DECLINED; } ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno, ngx_open_file_n " \"%s\" failed", c->file.name.data); return NGX_ERROR; } if (c->uniq) { if (ngx_fd_info(c->file.fd, &c->file.info) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", c->file.name.data); return NGX_ERROR; } if (ngx_file_uniq(&c->file.info) == c->uniq) { if (ngx_close_file(c->file.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, ngx_close_file_n " \"%s\" failed", c->file.name.data); } return NGX_HTTP_CACHE_THE_SAME; } } n = ngx_read_file(&c->file, c->buf->pos, c->buf->end - c->buf->last, 0); if (n == NGX_ERROR || n == NGX_AGAIN) { return n; } if (n <= c->header_size) { ngx_log_error(NGX_LOG_CRIT, c->log, 0, "cache file \"%s\" is too small", c->file.name.data); return NGX_ERROR; } h = (ngx_http_cache_header_t *) c->buf->pos; c->expires = h->expires; c->last_modified= h->last_modified; c->date = h->date; c->length = h->length; if (h->key_len > (size_t) (c->buf->end - c->buf->pos)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "cache file \"%s\" is probably invalid", c->file.name.data); return NGX_DECLINED; } #if 0 /* TODO */ if (c->key_len && h->key_len != c->key_len) { ngx_strncmp(h->key, c->key_data, h->key_len) != 0)) h->key[h->key_len] = '\0'; ngx_log_error(NGX_LOG_ALERT, c->log, 0, "md5 collision: \"%s\" and \"%s\"", h->key, c->key.data); return NGX_DECLINED; } #endif c->buf->last += n; if (c->expires < ngx_time()) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http file cache expired"); return NGX_HTTP_CACHE_STALE; } /* TODO: NGX_HTTP_CACHE_AGED */ /* STUB */ return NGX_DECLINED; return NGX_OK; } #if 0 int ngx_http_cache_update_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx, ngx_str_t *temp_file) { int retry; ngx_err_t err; retry = 0; for ( ;; ) { if (ngx_rename_file(temp_file->data, ctx->file.name.data) == NGX_OK) { return NGX_OK; } err = ngx_errno; #if (NGX_WIN32) if (err == NGX_EEXIST) { if (ngx_win32_rename_file(temp_file, &ctx->file.name, r->pool) == NGX_ERROR) { return NGX_ERROR; } } #endif if (retry || (err != NGX_ENOENT && err != NGX_ENOTDIR)) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_rename_file_n "(\"%s\", \"%s\") failed", temp_file->data, ctx->file.name.data); return NGX_ERROR; } if (ngx_create_path(&ctx->file, ctx->path) == NGX_ERROR) { return NGX_ERROR; } retry = 1; } } #endif ngx_int_t ngx_http_cache_cleaner_handler(ngx_gc_t *gc, ngx_str_t *name, ngx_dir_t *dir) { int rc; ngx_buf_t buf; ngx_http_cache_t c; u_char data[sizeof(ngx_http_cache_header_t)]; ngx_memzero(&c, sizeof(ngx_http_cache_t)); c.file.fd = NGX_INVALID_FILE; c.file.name = *name; c.file.log = gc->log; c.header_size = sizeof(ngx_http_cache_header_t); c.buf = &buf; c.log = gc->log; c.key_len = 0; buf.memory = 1; buf.temporary = 1; buf.pos = data; buf.last = data; buf.start = data; buf.end = data + sizeof(ngx_http_cache_header_t); rc = ngx_http_file_cache_open(&c); /* TODO: NGX_AGAIN */ if (rc != NGX_ERROR&& rc != NGX_DECLINED && rc != NGX_HTTP_CACHE_STALE) { return NGX_OK; } if (ngx_delete_file(name->data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, c.log, ngx_errno, ngx_delete_file_n " \"%s\" failed", name->data); return NGX_ERROR; } gc->deleted++; gc->freed += ngx_de_size(dir); return NGX_OK; }