ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree) { void *data, *prev; u_char *p, *name; size_t len; ngx_int_t rc; ngx_err_t err; ngx_str_t file, buf; ngx_dir_t dir; ngx_str_null(&buf); ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "walk tree \"%V\"", tree); if (ngx_open_dir(tree, &dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_open_dir_n " \"%s\" failed", tree->data); return NGX_ERROR; } prev = ctx->data; if (ctx->alloc) { data = ngx_alloc(ctx->alloc, ctx->log); if (data == NULL) { goto failed; } if (ctx->init_handler(data, prev) == NGX_ABORT) { goto failed; } ctx->data = data; } else { data = NULL; } for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOMOREFILES) { rc = NGX_OK; } else { ngx_log_error(NGX_LOG_CRIT, ctx->log, err, ngx_read_dir_n " \"%s\" failed", tree->data); rc = NGX_ERROR; } goto done; } len = ngx_de_namelen(&dir); name = ngx_de_name(&dir); ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree name %uz:\"%s\"", len, name); if (len == 1 && name[0] == '.') { continue; } if (len == 2 && name[0] == '.' && name[1] == '.') { continue; } file.len = tree->len + 1 + len; if (file.len + NGX_DIR_MASK_LEN > buf.len) { if (buf.len) { ngx_free(buf.data); } buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN; buf.data = ngx_alloc(buf.len + 1, ctx->log); if (buf.data == NULL) { goto failed; } } p = ngx_cpymem(buf.data, tree->data, tree->len); *p++ = '/'; ngx_memcpy(p, name, len + 1); file.data = buf.data; ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree path \"%s\"", file.data); if (!dir.valid_info) { if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_de_info_n " \"%s\" failed", file.data); continue; } } if (ngx_de_is_file(&dir)) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree file \"%s\"", file.data); ctx->size = ngx_de_size(&dir); ctx->fs_size = ngx_de_fs_size(&dir); ctx->access = ngx_de_access(&dir); ctx->mtime = ngx_de_mtime(&dir); if (ctx->file_handler(ctx, &file) == NGX_ABORT) { goto failed; } } else if (ngx_de_is_dir(&dir)) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree enter dir \"%s\"", file.data); ctx->access = ngx_de_access(&dir); ctx->mtime = ngx_de_mtime(&dir); rc = ctx->pre_tree_handler(ctx, &file); if (rc == NGX_ABORT) { goto failed; } if (rc == NGX_DECLINED) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree skip dir \"%s\"", file.data); continue; } if (ngx_walk_tree(ctx, &file) == NGX_ABORT) { goto failed; } ctx->access = ngx_de_access(&dir); ctx->mtime = ngx_de_mtime(&dir); if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) { goto failed; } } else { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree special \"%s\"", file.data); if (ctx->spec_handler(ctx, &file) == NGX_ABORT) { goto failed; } } } failed: rc = NGX_ABORT; done: if (buf.len) { ngx_free(buf.data); } if (data) { ngx_free(data); ctx->data = prev; } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", tree->data); } return rc; }
static ngx_int_t ngx_rtmp_dash_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen) { time_t mtime, max_age; u_char *p; u_char path[NGX_MAX_PATH + 1], mpd_path[NGX_MAX_PATH + 1]; ngx_dir_t dir; ngx_err_t err; ngx_str_t name, spath, mpd; ngx_int_t nentries, nerased; ngx_file_info_t fi; ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, "dash: cleanup path='%V' playlen=%M", ppath, playlen); if (ngx_open_dir(ppath, &dir) != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, ngx_errno, "dash: cleanup open dir failed '%V'", ppath); return NGX_ERROR; } nentries = 0; nerased = 0; for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, "dash: cleanup " ngx_close_dir_n " \"%V\" failed", ppath); } if (err == NGX_ENOMOREFILES) { return nentries - nerased; } ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, err, "dash: cleanup " ngx_read_dir_n " '%V' failed", ppath); return NGX_ERROR; } name.data = ngx_de_name(&dir); if (name.data[0] == '.') { continue; } name.len = ngx_de_namelen(&dir); p = ngx_snprintf(path, sizeof(path) - 1, "%V/%V", ppath, &name); *p = 0; spath.data = path; spath.len = p - path; nentries++; if (!dir.valid_info && ngx_de_info(path, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, "dash: cleanup " ngx_de_info_n " \"%V\" failed", &spath); continue; } if (ngx_de_is_dir(&dir)) { if (ngx_rtmp_dash_cleanup_dir(&spath, playlen) == 0) { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, "dash: cleanup dir '%V'", &name); /* * null-termination gets spoiled in win32 * version of ngx_open_dir */ *p = 0; if (ngx_delete_dir(path) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, "dash: cleanup " ngx_delete_dir_n " failed on '%V'", &spath); } else { nerased++; } } continue; } if (!ngx_de_is_file(&dir)) { continue; } if (name.len >= 8 && name.data[name.len - 8] == 'i' && name.data[name.len - 7] == 'n' && name.data[name.len - 6] == 'i' && name.data[name.len - 5] == 't' && name.data[name.len - 4] == '.' && name.data[name.len - 3] == 'm' && name.data[name.len - 2] == '4') { if (name.len == 8) { ngx_str_set(&mpd, "index"); } else { mpd.data = name.data; mpd.len = name.len - 9; } p = ngx_snprintf(mpd_path, sizeof(mpd_path) - 1, "%V/%V.mpd", ppath, &mpd); *p = 0; if (ngx_file_info(mpd_path, &fi) != NGX_FILE_ERROR) { ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, "dash: cleanup '%V' delayed, mpd exists '%s'", &name, mpd_path); continue; } ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, "dash: cleanup '%V' allowed, mpd missing '%s'", &name, mpd_path); max_age = 0; } else if (name.len >= 4 && name.data[name.len - 4] == '.' && name.data[name.len - 3] == 'm' && name.data[name.len - 2] == '4' && name.data[name.len - 1] == 'v') { max_age = playlen / 500; } else if (name.len >= 4 && name.data[name.len - 4] == '.' && name.data[name.len - 3] == 'm' && name.data[name.len - 2] == '4' && name.data[name.len - 1] == 'a') { max_age = playlen / 500; } else if (name.len >= 4 && name.data[name.len - 4] == '.' && name.data[name.len - 3] == 'm' && name.data[name.len - 2] == 'p' && name.data[name.len - 1] == 'd') { max_age = playlen / 500; } else if (name.len >= 4 && name.data[name.len - 4] == '.' && name.data[name.len - 3] == 'r' && name.data[name.len - 2] == 'a' && name.data[name.len - 1] == 'w') { max_age = playlen / 1000; } else { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, "dash: cleanup skip unknown file type '%V'", &name); continue; } mtime = ngx_de_mtime(&dir); if (mtime + max_age > ngx_cached_time->sec) { continue; } ngx_log_debug3(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, "dash: cleanup '%V' mtime=%T age=%T", &name, mtime, ngx_cached_time->sec - mtime); if (ngx_delete_file(path) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, "dash: cleanup " ngx_delete_file_n " failed on '%V'", &spath); continue; } nerased++; } }
/* location / { index index11.html #必须保证新uri所在目录存在并且该目录下面没有index11.html,autoindex对应的ngx_http_autoindex_handler才会生效 autoindex on; } 只有在index11.html文件不存在的时候才会执行autoindex,如果没有设置index则默认打开index.html,必须保证index.html的uri目录存在,如果不存在,是一个不存在的目录也不会执行autoindex */ static ngx_int_t ngx_http_autoindex_handler(ngx_http_request_t *r) //只有在index-module不编译进来的时候该模块才会生效 { //获取uri目录中的所有文件信息组包发送给客户端浏览器 u_char *last, *filename; size_t len, allocated, root; ngx_err_t err; ngx_buf_t *b; ngx_int_t rc; ngx_str_t path, callback; ngx_dir_t dir; ngx_uint_t level, format; ngx_pool_t *pool; ngx_chain_t out; ngx_array_t entries; ngx_http_autoindex_entry_t *entry; ngx_http_autoindex_loc_conf_t *alcf; if (r->uri.data[r->uri.len - 1] != '/') { //autoindex的uri必须是目录形式,最末尾字符/ return NGX_DECLINED; } alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module); //如果没有配置index或者try_files,则匹配location / {}到后会默认使用html/index.html if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module); if (!alcf->enable) { return NGX_DECLINED; } /* NGX_DIR_MASK_LEN is lesser than NGX_HTTP_AUTOINDEX_PREALLOCATE */ last = ngx_http_map_uri_to_path(r, &path, &root, NGX_HTTP_AUTOINDEX_PREALLOCATE); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } allocated = path.len; path.len = last - path.data; if (path.len > 1) { path.len--; } path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex: \"%s\"", path.data); format = alcf->format; if (format == NGX_HTTP_AUTOINDEX_JSONP) { if (ngx_http_autoindex_jsonp_callback(r, &callback) != NGX_OK) { return NGX_HTTP_BAD_REQUEST; } if (callback.len == 0) { format = NGX_HTTP_AUTOINDEX_JSON; } } if (ngx_open_dir(&path, &dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { 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, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } #if (NGX_SUPPRESS_WARN) /* MSVC thinks 'entries' may be used without having been initialized */ ngx_memzero(&entries, sizeof(ngx_array_t)); #endif /* TODO: pool should be temporary pool */ pool = r->pool; if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t)) != NGX_OK) { return ngx_http_autoindex_error(r, &dir, &path); } r->headers_out.status = NGX_HTTP_OK; switch (format) { case NGX_HTTP_AUTOINDEX_JSON: ngx_str_set(&r->headers_out.content_type, "application/json"); break; case NGX_HTTP_AUTOINDEX_JSONP: ngx_str_set(&r->headers_out.content_type, "application/javascript"); break; case NGX_HTTP_AUTOINDEX_XML: ngx_str_set(&r->headers_out.content_type, "text/xml"); ngx_str_set(&r->headers_out.charset, "utf-8"); break; default: /* NGX_HTTP_AUTOINDEX_HTML */ ngx_str_set(&r->headers_out.content_type, "text/html"); break; } r->headers_out.content_type_len = r->headers_out.content_type.len; r->headers_out.content_type_lowcase = NULL; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%V\" failed", &path); } return rc; } filename = path.data; filename[path.len] = '/'; for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_autoindex_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex file: \"%s\"", ngx_de_name(&dir)); len = ngx_de_namelen(&dir); if (ngx_de_name(&dir)[0] == '.') { continue; } if (!dir.valid_info) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_AUTOINDEX_PREALLOCATE; filename = ngx_pnalloc(pool, allocated); if (filename == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT && err != NGX_ELOOP) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); if (err == NGX_EACCES) { continue; } return ngx_http_autoindex_error(r, &dir, &path); } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_autoindex_error(r, &dir, &path); } } } entry = ngx_array_push(&entries); if (entry == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } entry->name.len = len; entry->name.data = ngx_pnalloc(pool, len + 1); if (entry->name.data == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); entry->dir = ngx_de_is_dir(&dir); entry->file = ngx_de_is_file(&dir); entry->mtime = ngx_de_mtime(&dir); entry->size = ngx_de_size(&dir); } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%V\" failed", &path); } if (entries.nelts > 1) { ngx_qsort(entries.elts, (size_t) entries.nelts, sizeof(ngx_http_autoindex_entry_t), ngx_http_autoindex_cmp_entries); } switch (format) { case NGX_HTTP_AUTOINDEX_JSON: b = ngx_http_autoindex_json(r, &entries, NULL); break; case NGX_HTTP_AUTOINDEX_JSONP: b = ngx_http_autoindex_json(r, &entries, &callback); break; case NGX_HTTP_AUTOINDEX_XML: b = ngx_http_autoindex_xml(r, &entries); break; default: /* NGX_HTTP_AUTOINDEX_HTML */ b = ngx_http_autoindex_html(r, &entries); break; } if (b == NULL) { return NGX_ERROR; } /* TODO: free temporary pool */ if (r == r->main) { b->last_buf = 1; } b->last_in_chain = 1; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_random_index_handler(ngx_http_request_t *r) { u_char *last, *filename; size_t len, allocated, root; ngx_err_t err; ngx_int_t rc; ngx_str_t path, uri, *name; ngx_dir_t dir; ngx_uint_t n, level; ngx_array_t names; ngx_http_random_index_loc_conf_t *rlcf; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_DECLINED; } rlcf = ngx_http_get_module_loc_conf(r, ngx_http_random_index_module); if (!rlcf->enable) { return NGX_DECLINED; } #if (NGX_HAVE_D_TYPE) len = NGX_DIR_MASK_LEN; #else len = NGX_HTTP_RANDOM_INDEX_PREALLOCATE; #endif last = ngx_http_map_uri_to_path(r, &path, &root, len); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } allocated = path.len; path.len = last - path.data - 1; path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http random index: \"%s\"", path.data); if (ngx_open_dir(&path, &dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { 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, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } if (ngx_array_init(&names, r->pool, 32, sizeof(ngx_str_t)) != NGX_OK) { return ngx_http_random_index_error(r, &dir, &path); } filename = path.data; filename[path.len] = '/'; for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_random_index_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http random index file: \"%s\"", ngx_de_name(&dir)); if (ngx_de_name(&dir)[0] == '.') { continue; } len = ngx_de_namelen(&dir); if (dir.type == 0 || ngx_de_is_link(&dir)) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_RANDOM_INDEX_PREALLOCATE; filename = ngx_pnalloc(r->pool, allocated); if (filename == NULL) { return ngx_http_random_index_error(r, &dir, &path); } last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); return ngx_http_random_index_error(r, &dir, &path); } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_random_index_error(r, &dir, &path); } } } if (!ngx_de_is_file(&dir)) { continue; } name = ngx_array_push(&names); if (name == NULL) { return ngx_http_random_index_error(r, &dir, &path); } name->len = len; name->data = ngx_pnalloc(r->pool, len); if (name->data == NULL) { return ngx_http_random_index_error(r, &dir, &path); } ngx_memcpy(name->data, ngx_de_name(&dir), len); } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", &path); } n = names.nelts; if (n == 0) { return NGX_DECLINED; } name = names.elts; n = (ngx_uint_t) (((uint64_t) ngx_random() * n) / 0x80000000); uri.len = r->uri.len + name[n].len; uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(last, name[n].data, name[n].len); return ngx_http_internal_redirect(r, &uri, &r->args); }