static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of, ngx_log_t *log) { ngx_fd_t fd; ngx_file_info_t fi; if (of->fd != NGX_INVALID_FILE) { if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) { of->fd = NGX_INVALID_FILE; return NGX_ERROR; } // 判断文件是否被改变 if (of->uniq == ngx_file_uniq(&fi)) { goto done; } } else if (of->test_dir) { if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) { of->fd = NGX_INVALID_FILE; return NGX_ERROR; } if (ngx_is_dir(&fi)) { goto done; } } // 否则重新打开 if (!of->log) { /* * Use non-blocking open() not to hang on FIFO files, etc. * This flag has no effect on a regular files. */ fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, NGX_FILE_OPEN, 0, log); } else { fd = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS, log); } if (fd == NGX_INVALID_FILE) { of->fd = NGX_INVALID_FILE; return NGX_ERROR; } if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, ngx_fd_info_n " \"%V\" failed", name); if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%V\" failed", name); } of->fd = NGX_INVALID_FILE; return NGX_ERROR; } if (ngx_is_dir(&fi)) { if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%V\" failed", name); } of->fd = NGX_INVALID_FILE; } else { of->fd = fd; if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) { if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_read_ahead_n " \"%V\" failed", name); } } if (of->directio <= ngx_file_size(&fi)) { if (ngx_directio_on(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_on_n " \"%V\" failed", name); } else { of->is_directio = 1; } } } done: of->uniq = ngx_file_uniq(&fi); of->mtime = ngx_file_mtime(&fi); of->size = ngx_file_size(&fi); of->fs_size = ngx_file_fs_size(&fi); of->is_dir = ngx_is_dir(&fi); of->is_file = ngx_is_file(&fi); of->is_link = ngx_is_link(&fi); of->is_exec = ngx_is_exec(&fi); return NGX_OK; }
ngx_int_t ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name, ngx_open_file_info_t *of, ngx_pool_t *pool) { time_t now; uint32_t hash; ngx_int_t rc; ngx_file_info_t fi; ngx_pool_cleanup_t *cln; ngx_cached_open_file_t *file; ngx_pool_cleanup_file_t *clnf; ngx_open_file_cache_cleanup_t *ofcln; of->fd = NGX_INVALID_FILE; of->err = 0; if (cache == NULL) { if (of->test_only) { if (ngx_file_info_wrapper(name, of, &fi, pool->log) == NGX_FILE_ERROR) { return NGX_ERROR; } of->uniq = ngx_file_uniq(&fi); of->mtime = ngx_file_mtime(&fi); of->size = ngx_file_size(&fi); of->fs_size = ngx_file_fs_size(&fi); of->is_dir = ngx_is_dir(&fi); of->is_file = ngx_is_file(&fi); of->is_link = ngx_is_link(&fi); of->is_exec = ngx_is_exec(&fi); return NGX_OK; } cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); if (cln == NULL) { return NGX_ERROR; } rc = ngx_open_and_stat_file(name, of, pool->log); if (rc == NGX_OK && !of->is_dir) { cln->handler = ngx_pool_cleanup_file; clnf = cln->data; clnf->fd = of->fd; clnf->name = name->data; clnf->log = pool->log; } return rc; } cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t)); if (cln == NULL) { return NGX_ERROR; } now = ngx_time(); // 计算hash hash = ngx_crc32_long(name->data, name->len); // 根据名字查找对应的file对象 file = ngx_open_file_lookup(cache, name, hash); if (file) { file->uses++; ngx_queue_remove(&file->queue); if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) { /* file was not used often enough to keep open */ rc = ngx_open_and_stat_file(name, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; } goto add_event; } if (file->use_event || (file->event == NULL && (of->uniq == 0 || of->uniq == file->uniq) && now - file->created < of->valid #if (NGX_HAVE_OPENAT) && of->disable_symlinks == file->disable_symlinks && of->disable_symlinks_from == file->disable_symlinks_from #endif )) { if (file->err == 0) { of->fd = file->fd; of->uniq = file->uniq; of->mtime = file->mtime; of->size = file->size; of->is_dir = file->is_dir; of->is_file = file->is_file; of->is_link = file->is_link; of->is_exec = file->is_exec; of->is_directio = file->is_directio; if (!file->is_dir) { file->count++; ngx_open_file_add_event(cache, file, of, pool->log); } } else { of->err = file->err; #if (NGX_HAVE_OPENAT) of->failed = file->disable_symlinks ? ngx_openat_file_n : ngx_open_file_n; #else of->failed = ngx_open_file_n; #endif } goto found; } ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, "retest open file: %s, fd:%d, c:%d, e:%d", file->name, file->fd, file->count, file->err); if (file->is_dir) { /* * chances that directory became file are very small * so test_dir flag allows to use a single syscall * in ngx_file_info() instead of three syscalls */ of->test_dir = 1; } of->fd = file->fd; of->uniq = file->uniq; // 打开文件,保存文件信息 rc = ngx_open_and_stat_file(name, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; } if (of->is_dir) { if (file->is_dir || file->err) { goto update; } /* file became directory */ } else if (of->err == 0) { /* file */ if (file->is_dir || file->err) { goto add_event; } if (of->uniq == file->uniq) { if (file->event) { file->use_event = 1; } of->is_directio = file->is_directio; goto update; } /* file was changed */ } else { /* error to cache */ if (file->err || file->is_dir) { goto update; } /* file was removed, etc. */ } if (file->count == 0) { ngx_open_file_del_event(file); if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%V\" failed", name); } goto add_event; } ngx_rbtree_delete(&cache->rbtree, &file->node); cache->current--; file->close = 1; goto create; } /* not found */ rc = ngx_open_and_stat_file(name, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; } create: // max为open_file_cache命令中定义的那个max指令, // 而current也就是当前cache的文件个数 if (cache->current >= cache->max) { // 如果大于max,则需要强制expire几个元素 ngx_expire_old_cached_files(cache, 0, pool->log); } file = ngx_alloc(sizeof(ngx_cached_open_file_t), pool->log); if (file == NULL) { goto failed; } file->name = ngx_alloc(name->len + 1, pool->log); if (file->name == NULL) { ngx_free(file); file = NULL; goto failed; } ngx_cpystrn(file->name, name->data, name->len + 1); file->node.key = hash; ngx_rbtree_insert(&cache->rbtree, &file->node); cache->current++; file->uses = 1; file->count = 0; file->use_event = 0; file->event = NULL; add_event: ngx_open_file_add_event(cache, file, of, pool->log); update: file->fd = of->fd; file->err = of->err; #if (NGX_HAVE_OPENAT) file->disable_symlinks = of->disable_symlinks; file->disable_symlinks_from = of->disable_symlinks_from; #endif if (of->err == 0) { file->uniq = of->uniq; file->mtime = of->mtime; file->size = of->size; file->close = 0; file->is_dir = of->is_dir; file->is_file = of->is_file; file->is_link = of->is_link; file->is_exec = of->is_exec; file->is_directio = of->is_directio; if (!of->is_dir) { file->count++; } } file->created = now; found: // 更新存取时间 file->accessed = now; // 将文件插入到超时队列中 ngx_queue_insert_head(&cache->expire_queue, &file->queue); ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0, "cached open file: %s, fd:%d, c:%d, e:%d, u:%d", file->name, file->fd, file->count, file->err, file->uses); if (of->err == 0) { if (!of->is_dir) { // 这里很关键,将cln的handler cln->handler = ngx_open_file_cleanup; ofcln = cln->data; ofcln->cache = cache; ofcln->file = file; ofcln->min_uses = of->min_uses; ofcln->log = pool->log; } return NGX_OK; } return NGX_ERROR; failed: if (file) { ngx_rbtree_delete(&cache->rbtree, &file->node); cache->current--; if (file->count == 0) { if (file->fd != NGX_INVALID_FILE) { if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%s\" failed", file->name); } } ngx_free(file->name); ngx_free(file); } else { file->close = 1; } } if (of->fd != NGX_INVALID_FILE) { if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%V\" failed", name); } } return NGX_ERROR; }
static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log) { ngx_fd_t fd; ngx_file_info_t fi; of->fd = NGX_INVALID_FILE; if (of->test_dir) { if (ngx_file_info(name, &fi) == -1) { of->err = ngx_errno; return NGX_ERROR; } of->uniq = ngx_file_uniq(&fi); of->mtime = ngx_file_mtime(&fi); of->size = ngx_file_size(&fi); of->is_dir = ngx_is_dir(&fi); of->is_file = ngx_is_file(&fi); of->is_link = ngx_is_link(&fi); of->is_exec = ngx_is_exec(&fi); if (of->is_dir) { return NGX_OK; } } fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); if (fd == NGX_INVALID_FILE) { of->err = ngx_errno; return NGX_ERROR; } if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, ngx_fd_info_n " \"%s\" failed", name); if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name); } return NGX_ERROR; } if (ngx_is_dir(&fi)) { if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name); } fd = NGX_INVALID_FILE; } of->fd = fd; of->uniq = ngx_file_uniq(&fi); of->mtime = ngx_file_mtime(&fi); of->size = ngx_file_size(&fi); of->is_dir = ngx_is_dir(&fi); of->is_file = ngx_is_file(&fi); of->is_link = ngx_is_link(&fi); of->is_exec = ngx_is_exec(&fi); return NGX_OK; }
static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log) { int mode; ngx_fd_t fd; ngx_file_info_t fi; if (of->fd != NGX_INVALID_FILE) { if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) { of->failed = ngx_file_info_n; goto failed; } if (of->uniq == ngx_file_uniq(&fi)) { goto done; } } else if (of->test_dir) { if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) { of->failed = ngx_file_info_n; goto failed; } if (ngx_is_dir(&fi)) { goto done; } } if (!of->log) { /* * Use non-blocking open() not to hang on FIFO files, etc. * This flag has no effect on a regular files. */ mode = NGX_FILE_RDONLY|NGX_FILE_NONBLOCK; #if (NGX_WIN32 && NGX_HAVE_FILE_AIO) if (ngx_event_flags & NGX_USE_IOCP_EVENT && of->aio) { mode |= NGX_FILE_OVERLAPPED; } #endif fd = ngx_open_file(name, mode, NGX_FILE_OPEN, 0); } else { fd = ngx_open_file(name, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS); } if (fd == NGX_INVALID_FILE) { of->failed = ngx_open_file_n; goto failed; } if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, ngx_fd_info_n " \"%s\" failed", name); if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name); } of->fd = NGX_INVALID_FILE; return NGX_ERROR; } if (ngx_is_dir(&fi)) { if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name); } of->fd = NGX_INVALID_FILE; } else { of->fd = fd; if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) { if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_read_ahead_n " \"%s\" failed", name); } } if (of->directio <= ngx_file_size(&fi)) { if (ngx_directio_on(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_on_n " \"%s\" failed", name); } else { of->is_directio = 1; } } } done: of->uniq = ngx_file_uniq(&fi); of->mtime = ngx_file_mtime(&fi); of->size = ngx_file_size(&fi); of->fs_size = ngx_file_fs_size(&fi); of->is_dir = ngx_is_dir(&fi); of->is_file = ngx_is_file(&fi); of->is_link = ngx_is_link(&fi); of->is_exec = ngx_is_exec(&fi); return NGX_OK; failed: of->fd = NGX_INVALID_FILE; of->err = ngx_errno; return NGX_ERROR; }
static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) { u_char *last; ngx_fd_t fd; ngx_int_t rc; ngx_uint_t level; ngx_str_t name, location; ngx_err_t err; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_file_info_t fi; ngx_http_cleanup_t *file_cleanup, *redirect_cleanup; ngx_http_log_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; ngx_http_static_loc_conf_t *slcf; #if (NGX_HTTP_CACHE) uint32_t file_crc, redirect_crc; ngx_http_cache_t *file, *redirect; #endif if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_body(r); if (rc != NGX_OK && rc != NGX_AGAIN) { return rc; } #if (NGX_HTTP_CACHE) /* * there is a valid cached open file, i.e by the index handler, * and it should be already registered in r->cleanup */ if (r->cache && !r->cache->expired) { return ngx_http_send_cached(r); } #endif log = r->connection->log; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); /* * make a file name, reserve 2 bytes for a trailing '/' * in a possible redirect and for the last '\0' */ if (clcf->alias) { name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2 - clcf->name.len); if (name.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_cpymem(name.data, clcf->root.data, clcf->root.len); last = ngx_cpystrn(last, r->uri.data + clcf->name.len, r->uri.len + 1 - clcf->name.len); name.len = last - name.data; location.data = ngx_palloc(r->pool, r->uri.len + 2); if (location.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); #if 0 /* * aliases usually have trailling "/", * set it in the start of the possible redirect */ if (*location.data != '/') { location.data--; } #endif location.len = last - location.data + 1; } else { name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2); if (name.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len); last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); name.len = last - name.data; location.len = last - location.data + 1; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", name.data); /* allocate cleanups */ if (!(file_cleanup = ngx_push_array(&r->cleanup))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } file_cleanup->valid = 0; slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module); if (slcf->redirect_cache) { if (!(redirect_cleanup = ngx_push_array(&r->cleanup))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } redirect_cleanup->valid = 0; } else { redirect_cleanup = NULL; } #if (NGX_HTTP_CACHE) /* look up an open files cache */ if (clcf->open_files) { file = ngx_http_cache_get(clcf->open_files, file_cleanup, &name, &file_crc); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http open file cache get: " PTR_FMT, file); if (file && !file->expired) { r->cache = file; return ngx_http_send_cached(r); } } else { file = NULL; } /* look up an redirect cache */ if (slcf->redirect_cache) { redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup, &name, &redirect_crc); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http redirect cache get: " PTR_FMT, redirect); if (redirect && !redirect->expired) { /* * We do not copy a cached value so the cache entry is locked * until the end of the request. In a single threaded model * the redirected request should complete before other event * will be processed. In a multithreaded model this locking * should keep more popular redirects in cache. */ if (!(r->headers_out.location = ngx_http_add_header(&r->headers_out, ngx_http_headers_out))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->headers_out.location->value = redirect->data.value; return NGX_HTTP_MOVED_PERMANENTLY; } } else { redirect = NULL; } #endif /* open file */ #if (WIN9X) /* TODO: redirect cache */ if (ngx_win32_version < NGX_WIN_NT) { /* * there is no way to open a file or a directory in Win9X with * one syscall because Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag * so we need to check its type before the opening */ if (ngx_file_info(name.data, &fi) == NGX_FILE_ERROR) { err = ngx_errno; ngx_log_error(NGX_LOG_ERR, log, err, ngx_file_info_n " \"%s\" failed", name.data); if (err == NGX_ENOENT || err == NGX_ENOTDIR) { return NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { return NGX_HTTP_FORBIDDEN; } else { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } if (ngx_is_dir(&fi)) { ngx_log_debug(log, "HTTP DIR: '%s'" _ name.data); if (!(r->headers_out.location = ngx_http_add_header(&r->headers_out, ngx_http_headers_out))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } *last++ = '/'; *last = '\0'; r->headers_out.location->value.len = last - location; r->headers_out.location->value.data = location; return NGX_HTTP_MOVED_PERMANENTLY; } } #endif fd = ngx_open_file(name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN); if (fd == NGX_INVALID_FILE) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR) { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; } else { level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_error(level, log, err, ngx_open_file_n " \"%s\" failed", name.data); return rc; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd); if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, ngx_fd_info_n " \"%s\" failed", name.data); if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_is_dir(&fi)) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } *last++ = '/'; *last = '\0'; r->headers_out.location = ngx_list_push(&r->headers_out.headers); if (r->headers_out.location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->headers_out.location->value = location; #if (NGX_HTTP_CACHE) if (slcf->redirect_cache) { if (redirect) { if (location.len == redirect->data.value.len && ngx_memcmp(redirect->data.value.data, location.data, location.len) == 0) { redirect->accessed = ngx_cached_time; redirect->updated = ngx_cached_time; /* * we can unlock the cache entry because * we have the local copy anyway */ ngx_http_cache_unlock(slcf->redirect_cache, redirect, log); redirect_cleanup->valid = 0; return NGX_HTTP_MOVED_PERMANENTLY; } } location.len++; redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect, redirect_cleanup, &name, redirect_crc, &location, log); location.len--; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http redirect cache alloc: " PTR_FMT, redirect); if (redirect) { redirect->fd = NGX_INVALID_FILE; redirect->accessed = ngx_cached_time; redirect->last_modified = 0; redirect->updated = ngx_cached_time; redirect->memory = 1; ngx_http_cache_unlock(slcf->redirect_cache, redirect, log); redirect_cleanup->valid = 0; } } #endif return NGX_HTTP_MOVED_PERMANENTLY; } #if !(WIN32) /* the not regular files are probably Unix specific */ if (!ngx_is_file(&fi)) { ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, "%s is not a regular file", name.data); if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } return NGX_HTTP_NOT_FOUND; } #endif #if (NGX_HTTP_CACHE) if (clcf->open_files) { #if (NGX_USE_HTTP_FILE_CACHE_UNIQ) if (file && file->uniq == ngx_file_uniq(&fi)) { if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } file->accessed = ngx_cached_time; file->updated = ngx_cached_time; file->expired = 0; r->cache = file; return ngx_http_send_cached(r); } else { if (file) { ngx_http_cache_unlock(clcf->open_files, file, log); file = NULL; } file = ngx_http_cache_alloc(clcf->open_files, file, file_cleanup, &name, file_crc, NULL, log); if (file) { file->uniq = ngx_file_uniq(&fi); } } #else file = ngx_http_cache_alloc(clcf->open_files, file, file_cleanup, &name, file_crc, NULL, log); #endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http open file cache alloc: " PTR_FMT, file); if (file) { file->fd = fd; file->data.size = ngx_file_size(&fi); file->accessed = ngx_cached_time; file->last_modified = ngx_file_mtime(&fi); file->updated = ngx_cached_time; r->cache = file; } return ngx_http_send_cached(r); } #endif ctx = log->data; ctx->action = "sending response to client"; file_cleanup->data.file.fd = fd; file_cleanup->data.file.name = name.data; file_cleanup->valid = 1; file_cleanup->cache = 0; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = ngx_file_size(&fi); r->headers_out.last_modified_time = ngx_file_mtime(&fi); if (r->headers_out.content_length_n == 0) { r->header_only = 1; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } #if (NGX_SUPPRESS_WARN) b = NULL; #endif if (!r->header_only) { /* we need to allocate all before the header would be sent */ if (!(b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (!(b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->filter_allow_ranges = 1; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->in_file = 1; if (!r->main) { b->last_buf = 1; } b->file_pos = 0; b->file_last = ngx_file_size(&fi); b->file->fd = fd; b->file->log = log; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }