ngx_int_t ngx_file_reader_init( ngx_file_reader_state_t* state, ngx_async_read_callback_t read_callback, void* callback_context, ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, ngx_str_t* path, uint32_t flags) { ngx_open_file_info_t of; ngx_int_t rc; state->r = r; state->file.name = *path; state->file.log = r->connection->log; state->directio = clcf->directio; state->log_not_found = clcf->log_not_found; state->log = r->connection->log; #if (NGX_HAVE_FILE_AIO) state->use_aio = clcf->aio; state->read_callback = read_callback; state->callback_context = callback_context; #endif rc = ngx_file_reader_init_open_file_info(&of, r, clcf, path); if (rc != NGX_OK) { return rc; } rc = ngx_open_cached_file( (flags & OPEN_FILE_NO_CACHE) != 0 ? NULL : clcf->open_file_cache, path, &of, r->pool); return ngx_file_reader_update_state_file_info(state, &of, rc); }
static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, u_char *path, u_char *last) { u_char c; ngx_str_t dir; ngx_open_file_info_t of; c = *last; if (c != '/' || path == last) { /* "alias" without trailing slash */ c = *(++last); } *last = '\0'; dir.len = last - path; dir.data = path; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http index check dir: \"%V\"", &dir); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.test_dir = 1; of.test_only = 1; of.valid = clcf->open_file_cache_valid; of.errors = clcf->open_file_cache_errors; if (ngx_http_set_disable_symlinks(r, clcf, &dir, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool) != NGX_OK) { if (of.err) { #if (NGX_HAVE_OPENAT) if (of.err == NGX_EMLINK || of.err == NGX_ELOOP) { return NGX_HTTP_FORBIDDEN; } #endif if (of.err == NGX_ENOENT) { *last = c; return ngx_http_index_error(r, clcf, dir.data, NGX_ENOENT); } if (of.err == NGX_EACCES) { *last = c; /* * ngx_http_index_test_dir() is called after the first index * file testing has returned an error distinct from NGX_EACCES. * This means that directory searching is allowed. */ return NGX_OK; } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, dir.data); } return NGX_HTTP_INTERNAL_SERVER_ERROR; } *last = c; if (of.is_dir) { return NGX_OK; } ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "\"%s\" is not a directory", dir.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; }
/****************************************************************** index指令的理解,当访问某个目录时未指定文件,如果此location 设置了index指令,将返回index指令设置的页面 ******************************************************************/ static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r) { u_char *p, *name; size_t len, root, reserve, allocated; ngx_int_t rc; ngx_str_t path, uri; ngx_uint_t i, dir_tested; ngx_http_index_t *index; ngx_open_file_info_t of; ngx_http_script_code_pt code; ngx_http_script_engine_t e; ngx_http_core_loc_conf_t *clcf; ngx_http_index_loc_conf_t *ilcf; ngx_http_script_len_code_pt lcode; if (r->uri.data[r->uri.len - 1] != '/') { // uri不是“/”结尾时,说明uri中最后指定了文件,index和autoindex模块将不处理,交由static模块处理 return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_DECLINED; } // 这里获取的r->loc_conf可能是server层的也有可能是location层的,需要检查是否有匹配到配置文件中的Location ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); allocated = 0; root = 0; dir_tested = 0; name = NULL; /* suppress MSVC warning */ path.data = NULL; index = ilcf->indices->elts; for (i = 0; i < ilcf->indices->nelts; i++) { // 遍历index指令指定的每个参数 if (index[i].lengths == NULL) { // index指令参数中没有使用变量时 if (index[i].name.data[0] == '/') { // index指定的参数以"/"开始的, 将产生内部重定向。 return ngx_http_internal_redirect(r, &index[i].name, &r->args); } reserve = ilcf->max_index_len; len = index[i].name.len; } else { // index指令参数使用了变量 // 计算index指令参数指定的变量+常量字符串的长度 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = index[i].lengths->elts; e.request = r; e.flushed = 1; /* 1 is for terminating '\0' as in static names */ len = 1; while (*(uintptr_t *) e.ip) { lcode = *(ngx_http_script_len_code_pt *) e.ip; len += lcode(&e); } /* 16 bytes are preallocation */ reserve = len + 16; } if (reserve > allocated) { name = ngx_http_map_uri_to_path(r, &path, &root, reserve); if (name == NULL) { return NGX_ERROR; } allocated = path.data + path.len - name; // ??? } if (index[i].values == NULL) { /* index[i].name.len includes the terminating '\0' */ ngx_memcpy(name, index[i].name.data, index[i].name.len); // 拷贝index指令指定的参数(e.g. "/usr/local/nginx/html/index1/index.html") path.len = (name + index[i].name.len - 1) - path.data; } else { e.ip = index[i].values->elts; e.pos = name; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } if (*name == '/') { uri.len = len - 1; uri.data = name; return ngx_http_internal_redirect(r, &uri, &r->args); } path.len = e.pos - path.data; *e.pos = '\0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "open index \"%V\"", &path); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } #if (NGX_HAVE_OPENAT) if (of.err == NGX_EMLINK || of.err == NGX_ELOOP) { return NGX_HTTP_FORBIDDEN; } #endif if (of.err == NGX_ENOTDIR || of.err == NGX_ENAMETOOLONG || of.err == NGX_EACCES) { return ngx_http_index_error(r, clcf, path.data, of.err); } if (!dir_tested) { rc = ngx_http_index_test_dir(r, clcf, path.data, name - 1); if (rc != NGX_OK) { return rc; } dir_tested = 1; } if (of.err == NGX_ENOENT) { continue; } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } uri.len = r->uri.len + len - 1; if (!clcf->alias) { uri.data = path.data + root; } else { uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } p = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(p, name, len - 1); } return ngx_http_internal_redirect(r, &uri, &r->args); }// End for return NGX_DECLINED; }
/* 配置index index.html index_large.html gmime-gmime-cipher-context.html; 2025/02/14 08:24:04[ ngx_http_process_request_headers, 1412] [debug] 2955#2955: *2 http header done 2025/02/14 08:24:04[ ngx_event_del_timer, 39] [debug] 2955#2955: *2 < ngx_http_process_request, 2013> event timer del: 3: 30909486 2025/02/14 08:24:04[ ngx_http_core_rewrite_phase, 1810] [debug] 2955#2955: *2 rewrite phase: 0 (NGX_HTTP_SERVER_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1868] [debug] 2955#2955: *2 find config phase: 1 (NGX_HTTP_FIND_CONFIG_PHASE), uri:/ 2025/02/14 08:24:04[ ngx_http_core_find_static_location, 2753] [debug] 2955#2955: *2 static_locations test location: "/", client uri:/ 2025/02/14 08:24:04[ ngx_http_core_find_location, 2693] [debug] 2955#2955: *2 ngx pcre test location: ~ "/1mytest" 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1888] [debug] 2955#2955: *2 using configuration "/" 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1895] [debug] 2955#2955: *2 http cl:-1 max:1048576 2025/02/14 08:24:04[ ngx_http_core_rewrite_phase, 1810] [debug] 2955#2955: *2 rewrite phase: 2 (NGX_HTTP_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_post_rewrite_phase, 1963] [debug] 2955#2955: *2 post rewrite phase: 3 (NGX_HTTP_POST_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_generic_phase, 1746] [debug] 2955#2955: *2 generic phase: 4 (NGX_HTTP_PREACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_generic_phase, 1746] [debug] 2955#2955: *2 generic phase: 5 (NGX_HTTP_PREACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_access_phase, 2061] [debug] 2955#2955: *2 access phase: 6 (NGX_HTTP_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_access_phase, 2061] [debug] 2955#2955: *2 access phase: 7 (NGX_HTTP_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_post_access_phase, 2163] [debug] 2955#2955: *2 post access phase: 8 (NGX_HTTP_POST_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_content_phase, 2491] [debug] 2955#2955: *2 content phase: 9 (NGX_HTTP_CONTENT_PHASE) 2025/02/14 08:24:04[ ngx_http_index_handler, 144] [debug] 2955#2955: *2 yang test ... index-count:3 2025/02/14 08:24:04[ ngx_http_index_handler, 216] [debug] 2955#2955: *2 open index "/usr/local/nginx/html/index.html" 2025/02/14 08:24:04[ ngx_http_internal_redirect, 3853] [debug] 2955#2955: *2 internal redirect: "/index.html?" 2025/02/14 08:24:04[ ngx_http_core_rewrite_phase, 1810] [debug] 2955#2955: *2 rewrite phase: 0 (NGX_HTTP_SERVER_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1868] [debug] 2955#2955: *2 find config phase: 1 (NGX_HTTP_FIND_CONFIG_PHASE), uri:/index.html 2025/02/14 08:24:04[ ngx_http_core_find_static_location, 2753] [debug] 2955#2955: *2 static_locations test location: "/", client uri:/index.html 2025/02/14 08:24:04[ ngx_http_core_find_static_location, 2753] [debug] 2955#2955: *2 static_locations test location: "proxy1", client uri:/index.html 2025/02/14 08:24:04[ ngx_http_core_find_static_location, 2753] [debug] 2955#2955: *2 static_locations test location: "mytest", client uri:/index.html 2025/02/14 08:24:04[ ngx_http_core_find_location, 2693] [debug] 2955#2955: *2 ngx pcre test location: ~ "/1mytest" 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1888] [debug] 2955#2955: *2 using configuration "/" 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1895] [debug] 2955#2955: *2 http cl:-1 max:1048576 2025/02/14 08:24:04[ ngx_http_core_rewrite_phase, 1810] [debug] 2955#2955: *2 rewrite phase: 2 (NGX_HTTP_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_post_rewrite_phase, 1963] [debug] 2955#2955: *2 post rewrite phase: 3 (NGX_HTTP_POST_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_generic_phase, 1746] [debug] 2955#2955: *2 generic phase: 4 (NGX_HTTP_PREACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_generic_phase, 1746] [debug] 2955#2955: *2 generic phase: 5 (NGX_HTTP_PREACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_access_phase, 2061] [debug] 2955#2955: *2 access phase: 6 (NGX_HTTP_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_access_phase, 2061] [debug] 2955#2955: *2 access phase: 7 (NGX_HTTP_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_post_access_phase, 2163] [debug] 2955#2955: *2 post access phase: 8 (NGX_HTTP_POST_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_content_phase, 2491] [debug] 2955#2955: *2 content phase: 9 (NGX_HTTP_CONTENT_PHASE) 2025/02/14 08:24:04[ ngx_http_core_content_phase, 2491] [debug] 2955#2955: *2 content phase: 10 (NGX_HTTP_CONTENT_PHASE) 2025/02/14 08:24:04[ ngx_http_core_content_phase, 2491] [debug] 2955#2955: *2 content phase: 11 (NGX_HTTP_CONTENT_PHASE) 2025/02/14 08:24:04[ ngx_http_static_handler, 85] [debug] 2955#2955: *2 http filename: "/usr/local/nginx/html/index.html" 2025/02/14 08:24:04[ ngx_http_static_handler, 145] [debug] 2955#2955: *2 http static fd: 11 2025/02/14 08:24:04[ ngx_http_discard_request_body, 734] [debug] 2955#2955: *2 http set discard body */ static ngx_int_t //主要功能是检查uri中的文件是否存在,不存在直接关闭连接,存在则做内部重定向,重定向后由于是文件路径,因此末尾没有/,走到该函数直接退出,然后在static-module中获取文件内容 ngx_http_index_handler(ngx_http_request_t *r) {//注意:ngx_http_static_handler如果uri不是以/结尾返回,ngx_http_index_handler不以/结尾返回 //循环遍历index index.html index_large.html gmime-gmime-cipher-context.html;配置的文件,存在则返回,找到一个不在遍历后面的文件 //ngx_http_static_handler ngx_http_index_handler每次都要获取缓存信息stat信息,因此每次获取很可能是上一次stat执行的时候获取的信息,除非缓存过期 u_char *p, *name; size_t len, root, reserve, allocated; ngx_int_t rc; ngx_str_t path, uri; ngx_uint_t i, dir_tested; ngx_http_index_t *index; ngx_open_file_info_t of; ngx_http_script_code_pt code; ngx_http_script_engine_t e; ngx_http_core_loc_conf_t *clcf; ngx_http_index_loc_conf_t *ilcf; ngx_http_script_len_code_pt lcode; /* 一般匹配到location / { }的时候,才会执行下面的index,然后进行内部跳转 */ /* 如果浏览器输入:http://10.135.10.167/ABC/,则也会满足要求,uri会变为/ABC/index.html,打印如下 2015/10/16 12:08:03[ ngx_event_del_timer, 39] [debug] 12610#12610: *2 < ngx_http_process_request, 2013> event timer del: 3: 1859492499 2015/10/16 12:08:03[ ngx_http_core_rewrite_phase, 1810] [debug] 12610#12610: *2 rewrite phase: 0 (NGX_HTTP_SERVER_REWRITE_PHASE) 2015/10/16 12:08:03[ ngx_http_core_find_config_phase, 1868] [debug] 12610#12610: *2 find config phase: 1 (NGX_HTTP_FIND_CONFIG_PHASE), uri:/ABC/ 2015/10/16 12:08:03[ ngx_http_core_find_static_location, 2753] [debug] 12610#12610: *2 static_locations test location: "/", client uri:/ABC/ 2015/10/16 12:08:03[ ngx_http_core_find_static_location, 2753] [debug] 12610#12610: *2 static_locations test location: "proxy1", client uri:/ABC/ 2015/10/16 12:08:03[ ngx_http_core_find_static_location, 2753] [debug] 12610#12610: *2 static_locations test location: "mytest", client uri:/ABC/ 2015/10/16 12:08:03[ ngx_http_core_find_location, 2693] [debug] 12610#12610: *2 ngx pcre test location: ~ "\.php$" 2015/10/16 12:08:03[ ngx_http_core_find_location, 2693] [debug] 12610#12610: *2 ngx pcre test location: ~ "/1mytest" 2015/10/16 12:08:03[ ngx_http_core_find_config_phase, 1888] [debug] 12610#12610: *2 using configuration "/" 2015/10/16 12:08:03[ ngx_http_core_find_config_phase, 1895] [debug] 12610#12610: *2 http cl:-1 max:1048576 2015/10/16 12:08:03[ ngx_http_core_rewrite_phase, 1810] [debug] 12610#12610: *2 rewrite phase: 2 (NGX_HTTP_REWRITE_PHASE) 2015/10/16 12:08:03[ ngx_http_core_post_rewrite_phase, 1963] [debug] 12610#12610: *2 post rewrite phase: 3 (NGX_HTTP_POST_REWRITE_PHASE) 2015/10/16 12:08:03[ ngx_http_core_generic_phase, 1746] [debug] 12610#12610: *2 generic phase: 4 (NGX_HTTP_PREACCESS_PHASE) 2015/10/16 12:08:03[ ngx_http_core_generic_phase, 1746] [debug] 12610#12610: *2 generic phase: 5 (NGX_HTTP_PREACCESS_PHASE) 2015/10/16 12:08:03[ ngx_http_core_access_phase, 2061] [debug] 12610#12610: *2 access phase: 6 (NGX_HTTP_ACCESS_PHASE) 2015/10/16 12:08:03[ ngx_http_core_access_phase, 2061] [debug] 12610#12610: *2 access phase: 7 (NGX_HTTP_ACCESS_PHASE) 2015/10/16 12:08:03[ ngx_http_core_post_access_phase, 2163] [debug] 12610#12610: *2 post access phase: 8 (NGX_HTTP_POST_ACCESS_PHASE) 2015/10/16 12:08:03[ ngx_http_core_content_phase, 2491] [debug] 12610#12610: *2 content phase: 9 (NGX_HTTP_CONTENT_PHASE) 2015/10/16 12:08:03[ ngx_http_index_handler, 191] [debug] 12610#12610: *2 yang test ... index-count:3 2015/10/16 12:08:03[ ngx_http_index_handler, 263] [debug] 12610#12610: *2 open index "/var/yyz/www/ABC/index.html" 2015/10/16 12:08:03[ ngx_http_index_handler, 283] [debug] 12610#12610: *2 stat() "/var/yyz/www/ABC/index.html" failed (2: No such file or directory) 2015/10/16 12:08:03[ ngx_http_index_test_dir, 364] [debug] 12610#12610: *2 http index check dir: "/var/yyz/www/ABC" */ //默认http://10.2.13.167的时候,浏览器都会转换为http://10.2.13.167/发送到nginx服务器 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; } ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); allocated = 0; root = 0; dir_tested = 0; name = NULL; /* suppress MSVC warning */ path.data = NULL; index = ilcf->indices->elts; //indices上默认有一个NGX_HTTP_DEFAULT_INDEX for (i = 0; i < ilcf->indices->nelts; i++) {//循环遍历index配置的文件,如果有该文件,则进行内部重定向,从新走NGX_HTTP_SERVER_REWRITE_PHASE if (index[i].lengths == NULL) { if (index[i].name.data[0] == '/') { return ngx_http_internal_redirect(r, &index[i].name, &r->args); } reserve = ilcf->max_index_len; len = index[i].name.len; } else { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = index[i].lengths->elts; e.request = r; e.flushed = 1; /* 1 is for terminating '\0' as in static names */ len = 1; while (*(uintptr_t *) e.ip) { lcode = *(ngx_http_script_len_code_pt *) e.ip; len += lcode(&e); } /* 16 bytes are preallocation */ reserve = len + 16; } if (reserve > allocated) { name = ngx_http_map_uri_to_path(r, &path, &root, reserve); if (name == NULL) { return NGX_ERROR; } allocated = path.data + path.len - name; } if (index[i].values == NULL) { /* index[i].name.len includes the terminating '\0' */ ngx_memcpy(name, index[i].name.data, index[i].name.len); path.len = (name + index[i].name.len - 1) - path.data; } else { e.ip = index[i].values->elts; e.pos = name; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } if (*name == '/') { uri.len = len - 1; uri.data = name; return ngx_http_internal_redirect(r, &uri, &r->args); } path.len = e.pos - path.data; *e.pos = '\0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "open index \"%V\"", &path); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } #if (NGX_HAVE_OPENAT) if (of.err == NGX_EMLINK || of.err == NGX_ELOOP) { return NGX_HTTP_FORBIDDEN; } #endif if (of.err == NGX_ENOTDIR || of.err == NGX_ENAMETOOLONG || of.err == NGX_EACCES) { return ngx_http_index_error(r, clcf, path.data, of.err); } if (!dir_tested) { rc = ngx_http_index_test_dir(r, clcf, path.data, name - 1); if (rc != NGX_OK) { return rc; } dir_tested = 1; } if (of.err == NGX_ENOENT) { continue; //stat获取的参数file_name指定的文件不存在 } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } uri.len = r->uri.len + len - 1; if (!clcf->alias) { uri.data = path.data + root; } else { uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } p = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(p, name, len - 1); } return ngx_http_internal_redirect(r, &uri, &r->args); //内部重定向 } return NGX_DECLINED; }
static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r) { u_char *p, *name; size_t len, root, reserve, allocated; ngx_int_t rc; ngx_str_t path, uri; ngx_uint_t i, dir_tested; ngx_http_index_t *index; ngx_open_file_info_t of; ngx_http_script_code_pt code; ngx_http_script_engine_t e; ngx_http_core_loc_conf_t *clcf; ngx_http_index_loc_conf_t *ilcf; ngx_http_script_len_code_pt lcode; 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; } ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); allocated = 0; root = 0; dir_tested = 0; name = NULL; /* suppress MSVC warning */ path.data = NULL; index = ilcf->indices->elts; for (i = 0; i < ilcf->indices->nelts; i++) { if (index[i].lengths == NULL) { if (index[i].name.data[0] == '/') { return ngx_http_internal_redirect(r, &index[i].name, &r->args); } reserve = ilcf->max_index_len; len = index[i].name.len; } else { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = index[i].lengths->elts; e.request = r; e.flushed = 1; /* 1 is for terminating '\0' as in static names */ len = 1; while (*(uintptr_t *) e.ip) { lcode = *(ngx_http_script_len_code_pt *) e.ip; len += lcode(&e); } /* 16 bytes are preallocation */ reserve = len + 16; } if (reserve > allocated) { name = ngx_http_map_uri_to_path(r, &path, &root, reserve); if (name == NULL) { return NGX_ERROR; } allocated = path.data + path.len - name; } if (index[i].values == NULL) { /* index[i].name.len includes the terminating '\0' */ ngx_memcpy(name, index[i].name.data, index[i].name.len); path.len = (name + index[i].name.len - 1) - path.data; } else { e.ip = index[i].values->elts; e.pos = name; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } if (*name == '/') { uri.len = len - 1; uri.data = name; return ngx_http_internal_redirect(r, &uri, &r->args); } path.len = e.pos - path.data; *e.pos = '\0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "open index \"%V\"", &path); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (of.err == NGX_ENOTDIR || of.err == NGX_ENAMETOOLONG || of.err == NGX_EACCES) { return ngx_http_index_error(r, clcf, path.data, of.err); } if (!dir_tested) { rc = ngx_http_index_test_dir(r, clcf, path.data, name - 1); if (rc != NGX_OK) { return rc; } dir_tested = 1; } if (of.err == NGX_ENOENT) { continue; } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } uri.len = r->uri.len + len - 1; if (!clcf->alias) { uri.data = path.data + root; } else { uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } p = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(p, name, len - 1); } return ngx_http_internal_redirect(r, &uri, &r->args); } return NGX_DECLINED; }
ngx_int_t passenger_static_content_handler(ngx_http_request_t *r, ngx_str_t *filename) { u_char *last, *location; size_t len; ngx_int_t rc; ngx_uint_t level; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } log = r->connection->log; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", filename->data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, filename, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, ngx_open_file_n " \"%s\" failed", filename->data); } return rc; } r->root_tested = !r->error_page; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); if (of.is_dir) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); if (r->headers_out.location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } len = r->uri.len + 1; if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { location = filename->data + clcf->root.len; } else { if (r->args.len) { len += r->args.len + 1; } location = ngx_pnalloc(r->pool, len); if (location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(location, r->uri.data, r->uri.len); *last = '/'; if (r->args.len) { *++last = '?'; ngx_memcpy(++last, r->args.data, r->args.len); } } /* * we do not need to set the r->headers_out.location->hash and * r->headers_out.location->key fields */ r->headers_out.location->value.len = len; r->headers_out.location->value.data = location; return NGX_HTTP_MOVED_PERMANENTLY; } #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", filename->data); return NGX_HTTP_NOT_FOUND; } #endif if (r->method & NGX_HTTP_POST) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; set_request_extension(r, filename); if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (r != r->main && of.size == 0) { return ngx_http_send_header(r); } r->allow_ranges = 1; /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = *filename; b->file->log = log; b->file->directio = of.is_directio; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_gzip_static_handler(ngx_http_request_t *r) { u_char *p; size_t root; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_table_elt_t *h; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; ngx_http_gzip_static_conf_t *gzcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module); if (gzcf->enable == NGX_HTTP_GZIP_STATIC_OFF) { return NGX_DECLINED; } if (gzcf->enable == NGX_HTTP_GZIP_STATIC_ON) { rc = ngx_http_gzip_ok(r); } else { /* always */ rc = NGX_OK; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (!clcf->gzip_vary && rc != NGX_OK) { return NGX_DECLINED; } log = r->connection->log; p = ngx_http_map_uri_to_path(r, &path, &root, sizeof(".gz") - 1); if (p == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } *p++ = '.'; *p++ = 'g'; *p++ = 'z'; *p = '\0'; path.len = p - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: return NGX_DECLINED; case NGX_EACCES: #if (NGX_HAVE_OPENAT) case NGX_EMLINK: case NGX_ELOOP: #endif level = NGX_LOG_ERR; break; default: level = NGX_LOG_CRIT; break; } ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); return NGX_DECLINED; } if (gzcf->enable == NGX_HTTP_GZIP_STATIC_ON) { r->gzip_vary = 1; if (rc != NGX_OK) { return NGX_DECLINED; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); if (of.is_dir) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); return NGX_DECLINED; } #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data); return NGX_HTTP_NOT_FOUND; } #endif r->root_tested = !r->error_page; rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; if (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } h = ngx_list_push(&r->headers_out.headers); if (h == NULL) { return NGX_ERROR; } h->hash = 1; ngx_str_set(&h->key, "Content-Encoding"); ngx_str_set(&h->value, "gzip"); r->headers_out.content_encoding = h; /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_streaming_handler(ngx_http_request_t *r) { size_t root; ngx_int_t rc; ngx_uint_t level; ngx_str_t path; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; if(!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) return NGX_HTTP_NOT_ALLOWED; if(r->uri.data[r->uri.len - 1] == '/') return NGX_DECLINED; rc = ngx_http_discard_request_body(r); if(rc != NGX_OK) return rc; mp4_split_options_t *options = mp4_split_options_init(r); if(r->args.len && !mp4_split_options_set(r, options, (const char *)r->args.data, r->args.len)) { mp4_split_options_exit(r, options); return NGX_DECLINED; } if(!options) return NGX_DECLINED; if(!ngx_http_map_uri_to_path(r, &path, &root, 1)) { mp4_split_options_exit(r, options); return NGX_HTTP_INTERNAL_SERVER_ERROR; } u_int m3u8 = 0; struct bucket_t *bucket = bucket_init(r); int result = 0; { if(ngx_strstr(path.data, "m3u8")) m3u8 = 1; char *ext = strrchr((const char *)path.data, '.'); strcpy(ext, ".mp4"); path.len = ((u_char *)ext - path.data) + 4; // ngx_open_and_stat_file in ngx_open_cached_file expects the name to be zero-terminated. path.data[path.len] = '\0'; } ngx_log_t *nlog = r->connection->log; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, nlog, 0, "http mp4 filename: \"%s\"", path.data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = NGX_MAX_OFF_T_VALUE; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if(ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { mp4_split_options_exit(r, options); switch(of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if(rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, nlog, of.err, ngx_open_file_n " \"%s\" failed", path.data); } return rc; } if(!of.is_file) { mp4_split_options_exit(r, options); if(ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, ngx_close_file_n " \"%s\" failed", path.data); } return NGX_DECLINED; } ngx_file_t *file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if(file == NULL) { mp4_split_options_exit(r, options); return NGX_HTTP_INTERNAL_SERVER_ERROR; } file->fd = of.fd; file->name = path; file->log = nlog; mp4_context_t *mp4_context = mp4_open(r, file, of.size, MP4_OPEN_MOOV); if(!mp4_context) { mp4_split_options_exit(r, options); ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, "mp4_open failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } mp4_context->root = root; if(m3u8) { if((result = mp4_create_m3u8(mp4_context, bucket))) { char action[50]; sprintf(action, "ios_playlist&segments=%d", result); view_count(mp4_context, (char *)path.data, options ? options->hash : NULL, action); } r->allow_ranges = 0; // dirty hack r->headers_out.content_type.data = (u_char *)"application/vnd.apple.mpegurl"; r->headers_out.content_type.len = 29; r->headers_out.content_type_len = r->headers_out.content_type.len; } else { result = output_ts(mp4_context, bucket, options); if(!options || !result) { mp4_close(mp4_context); ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, "output_ts failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } char action[50] = "ios_view"; view_count(mp4_context, (char *)path.data, options->hash, action); r->allow_ranges = 1; } mp4_close(mp4_context); mp4_split_options_exit(r, options); result = result == 0 ? 415 : 200; r->root_tested = !r->error_page; if(result && bucket) { nlog->action = "sending mp4 to client"; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, nlog, 0, "content_length: %d", bucket->content_length); r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = bucket->content_length; r->headers_out.last_modified_time = of.mtime; if(ngx_http_set_content_type(r) != NGX_OK) return NGX_HTTP_INTERNAL_SERVER_ERROR; if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } //ngx_table_elt_t *h = ngx_list_push(&r->headers_out.headers); //if(h == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; //h->hash = 1; //h->key.len = sizeof(X_MOD_HLS_KEY) - 1; //h->key.data = (u_char *)X_MOD_HLS_KEY; //h->value.len = sizeof(X_MOD_HLS_VERSION) - 1; //h->value.data = (u_char *)X_MOD_HLS_VERSION; rc = ngx_http_send_header(r); if(rc == NGX_ERROR || rc > NGX_OK || r->header_only) { ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, ngx_close_file_n "ngx_http_send_header failed"); return rc; } return ngx_http_output_filter(r, bucket->first); } else return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; }
static ngx_int_t ngx_http_slice_handler(ngx_http_request_t *r) { u_char *last; off_t begin, end, len; size_t root; ngx_int_t rc; ngx_uint_t level, i; ngx_str_t path, value; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out[3]; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; ngx_http_slice_loc_conf_t *slcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_module); rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } log = r->connection->log; path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http slice filename: \"%V\"", &path); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); } return rc; } if (!of.is_file) { if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", path.data); } return NGX_DECLINED; } r->root_tested = !r->error_page; begin = 0; end = of.size; if (r->args.len) { if (ngx_http_arg(r, slcf->begin.data, slcf->begin.len, &value) == NGX_OK) { begin = ngx_atoof(value.data, value.len); if (begin == NGX_ERROR || begin >= of.size) { begin = 0; } } if (ngx_http_arg(r, slcf->end.data, slcf->end.len, &value) == NGX_OK) { end = ngx_atoof(value.data, value.len); if (end == NGX_ERROR || end >= of.size) { end = of.size; } } } end = end < begin ? of.size : end; len = (end == begin) ? 0 : ((end - begin) + ((begin == 0 && slcf->header_first) ? slcf->header.len : 0) + ((end == of.size && slcf->footer_last) ? slcf->footer.len : 0)); log->action = "sending slice to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = len; r->headers_out.last_modified_time = of.mtime; if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (len == 0) { r->header_only = 1; return ngx_http_send_header(r); } /* * add header when the first header is not denied */ if (slcf->header.len && !(begin == 0 && !slcf->header_first)) { b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->pos = slcf->header.data; b->last = slcf->header.data + slcf->header.len; b->memory = 1; out[0].buf = b; out[0].next = &out[1]; i = 0; } else { i = 1; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->allow_ranges = 1; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = begin; b->file_last = end; b->in_file = b->file_last ? 1: 0; b->last_buf = 1; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; out[1].buf = b; out[1].next = NULL; /* * add footer when the last footer is not denied */ if (slcf->footer.len && !(end == of.size && !slcf->footer_last)) { b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->pos = slcf->footer.data; b->last = slcf->footer.data + slcf->footer.len; b->memory = 1; b->last_buf = 1; b->last_in_chain = 1; out[2].buf = b; out[2].next = NULL; out[1].buf->last_buf = 0; out[1].buf->last_in_chain = 0; out[1].next = &out[2]; } return ngx_http_output_filter(r, &out[i]); }
static ngx_int_t ngx_estreaming_handler(ngx_http_request_t * r) { size_t root; ngx_int_t rc; ngx_uint_t level; ngx_str_t path; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; video_buffer *destination; if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) return NGX_HTTP_NOT_ALLOWED; if (r->uri.data[r->uri.len - 1] == '/') return NGX_DECLINED; rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) return rc; mp4_split_options_t * options = mp4_split_options_init(r); if (!ngx_http_map_uri_to_path(r, &path, &root, 1)) { mp4_split_options_exit(r, options); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (r->args.len && !mp4_split_options_set(r, options, (const char *) r->args.data, r->args.len)) { mp4_split_options_exit(r, options); return NGX_DECLINED; } if (!options) return NGX_DECLINED; ngx_log_t * nlog = r->connection->log; struct bucket_t * bucket = bucket_init(r); int result = 0; u_int m3u8 = 0, len_ = 0; int64_t duration = 0; if (ngx_memcmp(r->exten.data, "mp4", r->exten.len) == 0) { return ngx_http_mp4_handler(r); } else if (ngx_memcmp(r->exten.data, "m3u8", r->exten.len) == 0) { m3u8 = 1; } else if (ngx_memcmp(r->exten.data, "len", r->exten.len) == 0) {// this is for length request len_ = 1; } else if (ngx_memcmp(r->exten.data, "ts", r->exten.len) == 0) { // don't do anything } else { return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; } // change file name to mp4 // in order to lookup file in filesystem char *ext = strrchr((const char *) path.data, '.'); strcpy(ext, ".mp4"); path.len = ((u_char *) ext - path.data) + 4; path.data[path.len] = '\0'; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof (ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = NGX_MAX_OFF_T_VALUE; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { mp4_split_options_exit(r, options); switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, nlog, of.err, ngx_open_file_n " \"%s\" failed", path.data); } return rc; } if (!of.is_file) { mp4_split_options_exit(r, options); if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, ngx_close_file_n " \"%s\" failed", path.data); } return NGX_DECLINED; } /* move atom to beginning of file if it's in the last*/ hls_conf_t *mlcf; mlcf = ngx_http_get_module_loc_conf(r, ngx_http_estreaming_module); if (mlcf->mp4_enhance == 1) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "examine mp4 filename: \"%V\"", &path); if (ngx_http_enable_fast_start(&path, of.fd, r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } ngx_file_t *file = ngx_pcalloc(r->pool, sizeof (ngx_file_t)); if (file == NULL) { mp4_split_options_exit(r, options); return NGX_HTTP_INTERNAL_SERVER_ERROR; } file->fd = of.fd; file->name = path; file->log = nlog; mp4_context_t *mp4_context = mp4_open(r, file, of.size, MP4_OPEN_MOOV); if (!mp4_context) { mp4_split_options_exit(r, options); ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, "mp4_open failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } mp4_context->root = root; if (m3u8 || len_) { int ret, video_width = 0; // only request for master playlist need to use ffmpeg api to open video // this takes time and cpu, we should avoid it as much as possible if ((m3u8) && (options->adbr || options->org)) goto no_ffmpeg; AVFormatContext *fmt_ctx = NULL; unsigned int i; av_register_all(); if ((ret = avformat_open_input(&fmt_ctx, (const char*) path.data, NULL, NULL)) < 0) { mp4_split_options_exit(r, options); mp4_close(mp4_context); if (fmt_ctx) avformat_close_input(&fmt_ctx); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) { if (fmt_ctx) avformat_close_input(&fmt_ctx); mp4_close(mp4_context); mp4_split_options_exit(r, options); av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (len_) { duration = fmt_ctx->duration; u_char *buffer = (u_char *) ngx_palloc(mp4_context->r->pool, 10 * sizeof (char)); u_char * p = buffer; if (buffer == NULL) { mp4_split_options_exit(r, options); mp4_close(mp4_context); if (fmt_ctx) avformat_close_input(&fmt_ctx); return NGX_HTTP_INTERNAL_SERVER_ERROR; } // this is stolen from ffmpeg source code if (duration != AV_NOPTS_VALUE) { duration = duration + 5000; int secs; secs = duration / AV_TIME_BASE; p = ngx_sprintf(p, "%02d\n", secs); } else { p = ngx_sprintf(p, "N/A\n"); } bucket_insert(bucket, buffer, p - buffer); ngx_pfree(mp4_context->r->pool, buffer); if (fmt_ctx) avformat_close_input(&fmt_ctx); r->allow_ranges = 0; result = 1; goto response; } else { for (i = 0; i < fmt_ctx->nb_streams; i++) { AVStream *stream; AVCodecContext *codec_ctx; stream = fmt_ctx->streams[i]; codec_ctx = stream->codec; if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { av_log(NULL, AV_LOG_ERROR, "source video w:%d", codec_ctx->width); if (video_width == 0) { video_width = codec_ctx->width; } else if ((video_width != 0) && (video_width < codec_ctx->width)) { // has 2 video streams video_width = codec_ctx->width; } else break; } } avformat_close_input(&fmt_ctx); } // finish getting video width no_ffmpeg: if ((result = mp4_create_m3u8(mp4_context, bucket, options, video_width))) { char action[50]; sprintf(action, "ios_playlist&segments=%d", result); view_count(mp4_context, (char *) path.data, options ? options->hash : NULL, action); } r->allow_ranges = 0; } else { result = output_ts(mp4_context, bucket, options); if (!options || !result) { mp4_close(mp4_context); ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, "output_ts failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (options->adbr) { destination = ngx_pcalloc(r->pool, sizeof (video_buffer)); destination->data = NULL; destination->len = 0; destination->pool = r->pool; if (ngx_estreaming_adaptive_bitrate(r, bucket->first, destination, options) == NGX_OK) { ngx_buf_t *b = ngx_pcalloc(r->pool, sizeof (ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } bucket->first->buf = b; bucket->first->next = NULL; b->pos = destination->data; b->last = destination->data + (destination->len * sizeof (unsigned char)); b->memory = 1; b->last_buf = 1; bucket->content_length = destination->len; } ngx_pfree(r->pool, destination); } char action[50] = "ios_view"; view_count(mp4_context, (char *) path.data, options->hash, action); r->allow_ranges = 1; } response: mp4_close(mp4_context); mp4_split_options_exit(r, options); result = result == 0 ? 415 : 200; r->root_tested = !r->error_page; if (result && bucket) { nlog->action = "sending mp4 to client"; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, nlog, 0, "content_length: %d", bucket->content_length); if (bucket->content_length == 0) return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = bucket->content_length; r->headers_out.last_modified_time = of.mtime; if (m3u8) { r->headers_out.content_type.len = sizeof ("application/vnd.apple.mpegurl") - 1; r->headers_out.content_type.data = (u_char *) "application/vnd.apple.mpegurl"; } else if (len_) { r->headers_out.content_type.len = sizeof ("text/html") - 1; r->headers_out.content_type.data = (u_char *) "text/html"; } else { r->headers_out.content_type.len = sizeof ("video/MP2T") - 1; r->headers_out.content_type.data = (u_char *) "video/MP2T"; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, ngx_close_file_n "ngx_http_send_header failed"); return rc; } return ngx_http_output_filter(r, bucket->first); } else return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; }
//ngx_http_static_module模块主要是在nginx系统中查找uri指定文件是否存在,存在则直接返回给客户端 static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) {//注意:ngx_http_static_handler如果uri不是以/结尾返回,ngx_http_index_handler不以/结尾返回 //ngx_http_static_handler ngx_http_index_handler每次都要获取缓存信息stat信息,因此每次获取很可能是上一次stat执行的时候获取的信息,除非缓存过期 u_char *last, *location; size_t root, len; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { //注意:ngx_http_static_handler如果uri不是以/结尾返回,ngx_http_index_handler不以/结尾返回 return NGX_DECLINED; } log = r->connection->log; /* * ngx_http_map_uri_to_path() allocates memory for terminating '\0' * so we do not need to reserve memory for '/' for possible redirect */ last = ngx_http_map_uri_to_path(r, &path, &root, 0); //通过r->uri获取整个路径或者文件绝对路径 if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: #if (NGX_HAVE_OPENAT) case NGX_EMLINK: case NGX_ELOOP: #endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } /* 如果文件不存在,则返回出去后会结束请求 2016/02/16 10:27:36[ ngx_http_static_handler, 139] [error] 19131#19131: *1 open() "/var/yyz/www/ttt/xx.html" failed (2: No such file or directory), client: 10.2.13.167, server: localhost, request: "GET / HTTP/1.1", host: "10.2.13.167" 2016/02/16 10:27:36[ ngx_http_finalize_request, 2598] [debug] 19131#19131: *1 http finalize request rc: 404, "/ttt/xx.html?" a:1, c:2 */ if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); } return rc; } r->root_tested = !r->error_page; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); if (of.is_dir) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); ngx_http_clear_location(r); r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); if (r->headers_out.location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } len = r->uri.len + 1; if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { location = path.data + clcf->root.len; *last = '/'; } else { if (r->args.len) { len += r->args.len + 1; } location = ngx_pnalloc(r->pool, len); if (location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(location, r->uri.data, r->uri.len); *last = '/'; if (r->args.len) { *++last = '?'; ngx_memcpy(++last, r->args.data, r->args.len); } } /* * we do not need to set the r->headers_out.location->hash and * r->headers_out.location->key fields */ r->headers_out.location->value.len = len; r->headers_out.location->value.data = location; return NGX_HTTP_MOVED_PERMANENTLY; } #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data); return NGX_HTTP_NOT_FOUND; } #endif if (r->method & NGX_HTTP_POST) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; //文件最后被修改的时间 if (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (r != r->main && of.size == 0) { return ngx_http_send_header(r); } r->allow_ranges = 1; /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; //注意这里如果文件大小大于direction设置,则置1,后面会使能direct I/O方式,见ngx_directio_on out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_minify_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_buf_t *b; ngx_int_t rc; ngx_str_t *filename; ngx_uint_t level; ngx_chain_t *cl; ngx_open_file_info_t of; ngx_http_minify_conf_t *conf; ngx_http_core_loc_conf_t *ccf; ccf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); conf = ngx_http_get_module_loc_conf(r,ngx_http_minify_filter_module); if (!conf->enable){ return ngx_http_next_body_filter(r,in); } if(ngx_http_test_content_type(r, &conf->types) == NULL){ return ngx_http_next_body_filter(r,in); } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http minify filter"); for (cl = in; cl; cl = cl->next) { b = cl->buf; if (cl->buf->in_file){ ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = ccf->read_ahead; of.directio = ccf->directio; of.valid = ccf->open_file_cache_valid; of.min_uses = ccf->open_file_cache_min_uses; of.errors = ccf->open_file_cache_errors; of.events = ccf->open_file_cache_events; filename = &cl->buf->file->name; if (ngx_open_cached_file(ccf->open_file_cache, filename, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || ccf->log_not_found) { ngx_log_error(level, r->connection->log, of.err, "%s \"%V\" failed", of.failed, filename); } return rc; } if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, "\"%V\" is not a regular file", filename); return NGX_HTTP_NOT_FOUND; } if (of.size == 0) { continue; } ngx_http_minify_buf(b,r,&of); } else { if (b->pos == NULL) { continue; } ngx_http_minify_buf_in_memory(b,r); } } return ngx_http_next_body_filter(r,in); }
static void ngx_http_graphicsmagick_command_handler(ngx_http_request_t *r) { ngx_str_t *source; ngx_str_t *dest; ngx_str_t *ai; ngx_str_t *cmd; ngx_str_t *uri; ngx_array_t *tokens; ngx_int_t rc; ngx_uint_t i; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_fd_t fd; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; size_t argc; char **argv; u_char *cp; u_char *last; size_t root; ngx_temp_file_t *tf; unsigned int status; log = r->connection->log; tokens = ngx_array_create(r->pool, 10, sizeof(ngx_str_t)); if (tokens == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai = ngx_array_push(tokens); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai->data = (u_char *) "convert"; ai->len = 7; // get command from HTTP headers or queryString cmd = ngx_http_graphicsmagick_get_command(r); if (cmd == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ngx_log_error(NGX_LOG_ERR, log, 0, "graphicsmagick convert command: \"%s\"", cmd->data); //ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, // "graphicsmagick convert command: \"%s\"", cmd->data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->method & NGX_HTTP_POST) { source = dest = &r->request_body->temp_file->file.name; } else { uri = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); source = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); cp = cmd->data; while (cp < cmd->data + cmd->len) { if (*cp == ' ') { uri->data = cmd->data; uri->len = cp - cmd->data; cmd->data = cp + 1; cmd->len = cmd->len - uri->len - 1; break; } cp++; } if (uri->len == 0) { ngx_http_graphicsmagick_server_error(r); return; } last = ngx_http_graphicsmagickd_map_uri_to_path(r, uri, source, &root, 0); if (last == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } source->len = last - source->data; tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } tf->file.fd = NGX_INVALID_FILE; tf->file.log = r->connection->log; tf->path = clcf->client_body_temp_path; tf->pool = r->pool; tf->log_level = r->request_body_file_log_level; tf->persistent = r->request_body_in_persistent_file; tf->clean = 1; if (r->request_body_file_group_access) { tf->access = 0660; } if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access) != NGX_OK) { ngx_http_graphicsmagick_server_error(r); return; } dest = &tf->file.name; } // push source file name into tokens ai = ngx_array_push(tokens); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } *ai = *source; // tokenize command, and push them into tokens array rc = ngx_http_graphicsmagick_tokenize_command(r, cmd, tokens); if (rc == NGX_ERROR) { ngx_http_graphicsmagick_server_error(r); return; } ai = ngx_array_push_n(tokens, 2); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai->data = (u_char *) "-compress"; ai->len = 9; ai++; ai->data = (u_char *) "JPEG"; ai->len = 4; // push dest filename into tokens again, to save generated thumbnail into dest file ai = ngx_array_push(tokens); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } *ai = *dest; // OK, prepare convert args argc = tokens->nelts; argv = ngx_palloc(r->pool, argc * sizeof(char*)); if (argv == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai = tokens->elts; for (i = 0; i < argc; i++) { argv[i] = (char *) ai[i].data; ngx_log_error(NGX_LOG_ERR, log, 0, "current[%d]: %s", i, argv[i]); } ngx_array_destroy(tokens); // DO graphicsmagick converting status = ngx_http_graphicsmagick_convert(argv, argc); if (status == 0) { ngx_http_graphicsmagick_server_error(r); return; } // Done, write response of.test_dir = 0; //of.retest = clcf->open_file_cache_retest; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; rc = ngx_open_cached_file(clcf->open_file_cache, dest, &of, r->pool); if (rc == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, log, of.err, "failed to open file \"%s\"", dest->data); ngx_http_graphicsmagick_server_error(r); return; } fd = of.fd; log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_type.len = sizeof("image/jpeg") - 1; r->headers_out.content_type.data = (u_char *) "image/jpeg"; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; if (r != r->main && of.size == 0) { rc = ngx_http_send_header(r); ngx_http_finalize_request(r, rc); return; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { ngx_http_graphicsmagick_server_error(r); return; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { ngx_http_graphicsmagick_server_error(r); return; } rc = ngx_http_send_header(r); b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = fd; b->file->name = *dest; b->file->log = log; out.buf = b; out.next = NULL; rc = ngx_http_output_filter(r, &out); ngx_http_finalize_request(r, rc); return; }
static ngx_int_t ngx_http_concat_handler(ngx_http_request_t *r) { off_t length; size_t root, last_len; time_t last_modified; u_char *p, *v, *e, *last, *last_type; ngx_int_t rc; ngx_str_t *uri, *filename, path; ngx_buf_t *b; ngx_uint_t i, j, level; ngx_flag_t timestamp; ngx_array_t uris; ngx_chain_t out, **last_out, *cl; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *ccf; ngx_http_concat_loc_conf_t *clcf; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_concat_module); if (!clcf->enable) { return NGX_DECLINED; } /* the length of args must be greater than or equal to 2 */ if (r->args.len < 2 || r->args.data[0] != '?') { return NGX_DECLINED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http concat root: \"%V\"", &path); ccf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); #if (NGX_SUPPRESS_WARN) ngx_memzero(&uris, sizeof(ngx_array_t)); #endif if (ngx_array_init(&uris, r->pool, 8, sizeof(ngx_str_t)) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } e = r->args.data + r->args.len; for (p = r->args.data + 1, v = p, timestamp = 0; p != e; p++) { if (*p == ',') { if (p == v || timestamp == 1) { v = p + 1; timestamp = 0; continue; } rc = ngx_http_concat_add_path(r, &uris, clcf->max_files, &path, p, v); if (rc != NGX_OK) { return rc; } v = p + 1; } else if (*p == '?') { if (timestamp == 1) { v = p; continue; } rc = ngx_http_concat_add_path(r, &uris, clcf->max_files, &path, p, v); if (rc != NGX_OK) { return rc; } v = p; timestamp = 1; } } if (p - v > 0 && timestamp == 0) { rc = ngx_http_concat_add_path(r, &uris, clcf->max_files, &path, p, v); if (rc != NGX_OK) { return rc; } } last_modified = 0; last_len = 0; last_out = NULL; b = NULL; last_type = NULL; length = 0; uri = uris.elts; for (i = 0; i < uris.nelts; i++) { filename = uri + i; for (j = filename->len - 1; j > 1; j--) { if (filename->data[j] == '.' && filename->data[j - 1] != '/') { r->exten.len = filename->len - j - 1; r->exten.data = &filename->data[j + 1]; break; } else if (filename->data[j] == '/') { break; } } r->headers_out.content_type.len = 0; if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->headers_out.content_type_lowcase = NULL; if (ngx_http_test_content_type(r, &clcf->types) == NULL) { return NGX_HTTP_BAD_REQUEST; } if (clcf->unique) { /* test if all the content types are the same */ if ((i > 0) && (last_len != r->headers_out.content_type_len || (last_type != NULL && r->headers_out.content_type_lowcase != NULL && ngx_memcmp(last_type, r->headers_out.content_type_lowcase, last_len) != 0))) { return NGX_HTTP_BAD_REQUEST; } last_len = r->headers_out.content_type_len; last_type = r->headers_out.content_type_lowcase; } ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = ccf->read_ahead; of.directio = ccf->directio; of.valid = ccf->open_file_cache_valid; of.min_uses = ccf->open_file_cache_min_uses; of.errors = ccf->open_file_cache_errors; of.events = ccf->open_file_cache_events; if (ngx_open_cached_file(ccf->open_file_cache, filename, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || ccf->log_not_found) { ngx_log_error(level, r->connection->log, of.err, "%s \"%V\" failed", of.failed, filename); } if (clcf->ignore_file_error && (rc == NGX_HTTP_NOT_FOUND || rc == NGX_HTTP_FORBIDDEN)) { continue; } return rc; } if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, "\"%V\" is not a regular file", filename); if (clcf->ignore_file_error) { continue; } return NGX_HTTP_NOT_FOUND; } if (of.size == 0) { continue; } length += of.size; if (last_out == NULL) { last_modified = of.mtime; } else { if (of.mtime > last_modified) { last_modified = of.mtime; } } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1 : 0; b->file->fd = of.fd; b->file->name = *filename; b->file->log = r->connection->log; b->file->directio = of.is_directio; if (last_out == NULL) { out.buf = b; last_out = &out.next; out.next = NULL; } else { cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = b; *last_out = cl; last_out = &cl->next; cl->next = NULL; } if (i + 1 == uris.nelts || clcf->delimiter.len == 0) { continue; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->pos = clcf->delimiter.data; b->last = b->pos + clcf->delimiter.len; b->memory = 1; length += clcf->delimiter.len; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = b; *last_out = cl; last_out = &cl->next; cl->next = NULL; } r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = length; r->headers_out.last_modified_time = last_modified; if (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_weak_etag(r); if (b == NULL) { r->header_only = 1; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } if (b != NULL) { b->last_in_chain = 1; b->last_buf = 1; } return ngx_http_output_filter(r, &out); }
/* 静态页面处理函数 */ static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) { u_char *last, *location; size_t root, len; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_HTTP_NOT_ALLOWED; } /* 如果是http://127.0.0.1:8000,则此时的r->uri为/index.html */ if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } log = r->connection->log; /* * ngx_http_map_uri_to_path() allocates memory for terminating '\0' * so we do not need to reserve memory for '/' for possible redirect */ last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* 打开需要发送的文件 */ if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: #if (NGX_HAVE_OPENAT) case NGX_EMLINK: case NGX_ELOOP: #endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); } return rc; } r->root_tested = !r->error_page; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); if (of.is_dir) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); ngx_http_clear_location(r); r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); if (r->headers_out.location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } len = r->uri.len + 1; if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { location = path.data + clcf->root.len; *last = '/'; } else { if (r->args.len) { len += r->args.len + 1; } location = ngx_pnalloc(r->pool, len); if (location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(location, r->uri.data, r->uri.len); *last = '/'; if (r->args.len) { *++last = '?'; ngx_memcpy(++last, r->args.data, r->args.len); } } /* * we do not need to set the r->headers_out.location->hash and * r->headers_out.location->key fields */ r->headers_out.location->value.len = len; r->headers_out.location->value.data = location; return NGX_HTTP_MOVED_PERMANENTLY; } #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data); return NGX_HTTP_NOT_FOUND; } #endif /* nginx默认是不允许对静态文件进行post请求 */ if (r->method == NGX_HTTP_POST) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; if (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (r != r->main && of.size == 0) { return ngx_http_send_header(r); } r->allow_ranges = 1; /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* 发送响应头 */ rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; out.buf = b; out.next = NULL; /* 开始对输出进行过滤 */ return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_storage_handler (ngx_http_request_t *r) { ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out; ngx_uint_t level; if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body (r); if (rc != NGX_OK && rc != NGX_AGAIN) { return rc; } if (r->headers_in.if_modified_since) { return NGX_HTTP_NOT_MODIFIED; } char filename[PATH_BUFFSIZE]; unsigned int i; for (i = 0; i < r->uri.len; i++) { if (r->uri.data[i] == ':') { break; } } if (i >= r->uri.len) { ngx_log_error (NGX_LOG_ERR, r->connection->log, 0, "secret not found"); return NGX_HTTP_NOT_FOUND; } if (i >= PATH_BUFFSIZE) { ngx_log_error (NGX_LOG_ERR, r->connection->log, 0, "path too long"); return NGX_HTTP_NOT_FOUND; } memcpy (filename, r->uri.data, i); filename[i] = 0; ngx_str_t path; path.len = i; path.data = (u_char *) filename; long long offset; int content_type; char base64url_secret[12]; int parsed_args = sscanf ((char*) &r->uri.data[i+1], "%llx:%11[0-9A-Za-z_-]:%x", &offset, base64url_secret, &content_type); if (parsed_args != 3) { ngx_log_error (NGX_LOG_ERR, r->connection->log, 0, "offset:secret:type not found (parsed_args = %d, %s)", parsed_args, (char *) &r->uri.data[i+1]); return NGX_HTTP_NOT_FOUND; } unsigned long long secret = decode_secret ((unsigned char *) base64url_secret); ngx_http_core_loc_conf_t *clcf = ngx_http_get_module_loc_conf (r, ngx_http_core_module); ngx_open_file_info_t of; ngx_memzero (&of, sizeof (ngx_open_file_info_t)); of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file (clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error (level, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); } return rc; } if (!of.is_file) { if (ngx_close_file (of.fd) == NGX_FILE_ERROR) { ngx_log_error (NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_file_n " \"%s\" failed", path.data); } return NGX_DECLINED; } int fd = of.fd; /* if (fd < 0) { ngx_log_error (NGX_LOG_ERR, r->connection->log, 0, "couldn't open %s", filename); return NGX_HTTP_NOT_FOUND; } */ //ngx_read_file (of.file, &E, sizeof (E), offset); struct lev_storage_file E; if (sizeof (E) != pread (fd, &E, sizeof (E), offset)) { ngx_log_error (NGX_LOG_ERR, r->connection->log, 0, "read fail"); //close (fd); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (E.content_type >= ct_last || E.content_type < 0) { ngx_log_error (NGX_LOG_ERR, r->connection->log, 0, "illegal content type"); //close (fd); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (E.type != LEV_STORAGE_FILE) { ngx_log_error (NGX_LOG_ERR, r->connection->log, 0, "illegal E.type"); //close (fd); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (E.secret != secret) { ngx_log_error (NGX_LOG_ERR, r->connection->log, 0, "secret doesn't match"); //close (fd); return NGX_HTTP_FORBIDDEN; } if (E.content_type != content_type) { ngx_log_error (NGX_LOG_ERR, r->connection->log, 0, "content type doesn't match"); //close (fd); return NGX_HTTP_FORBIDDEN; } char *ct = ContentTypes[content_type]; r->headers_out.content_type.len = strlen (ct); r->headers_out.content_type.data = (u_char *) ct; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = E.size; r->allow_ranges = 1; r->headers_out.last_modified_time = E.mtime; if (r->method == NGX_HTTP_HEAD) { rc = ngx_http_send_header (r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } } b = ngx_pcalloc (r->pool, sizeof (ngx_buf_t)); if (b == NULL) { ngx_log_error (NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer."); //close (fd); return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc (r->pool, sizeof (ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_send_header (r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } out.buf = b; out.next = NULL; b->file_pos = offset + sizeof (E); b->file_last = b->file_pos + E.size; b->in_file = 1; b->last_buf = 1; b->file->fd = of.fd; b->file->name.len = path.len; b->file->name.data = ngx_pstrdup (r->pool, &path); b->file->log = r->connection->log; b->file->directio = of.is_directio; return ngx_http_output_filter (r, &out); }
static ngx_int_t ngx_http_flv_handler(ngx_http_request_t *r) { u_char *last; off_t start, len; size_t root; ngx_int_t rc; ngx_uint_t level, i; ngx_str_t path, value; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out[2]; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } log = r->connection->log; path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http flv filename: \"%V\"", &path); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); } return rc; } if (!of.is_file) { if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", path.data); } return NGX_DECLINED; } r->root_tested = !r->error_page; start = 0; len = of.size; i = 1; if (r->args.len) { if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) { start = ngx_atoof(value.data, value.len); if (start == NGX_ERROR || start >= len) { start = 0; } if (start) { len = sizeof(ngx_flv_header) - 1 + len - start; i = 0; } } } log->action = "sending flv to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = len; r->headers_out.last_modified_time = of.mtime; if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (i == 0) { b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->pos = ngx_flv_header; b->last = ngx_flv_header + sizeof(ngx_flv_header) - 1; b->memory = 1; out[0].buf = b; out[0].next = &out[1]; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->allow_ranges = 1; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = start; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = 1; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; out[1].buf = b; out[1].next = NULL; return ngx_http_output_filter(r, &out[i]); }
ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r) { ngx_int_t rc, rv; ngx_uint_t cold, test; ngx_http_cache_t *c; ngx_pool_cleanup_t *cln; ngx_open_file_info_t of; ngx_http_file_cache_t *cache; ngx_http_core_loc_conf_t *clcf; c = r->cache; if (c->waiting) { return NGX_AGAIN; } if (c->buf) { return ngx_http_file_cache_read(r, c); } cache = c->file_cache; if (c->node == NULL) { cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_ERROR; } cln->handler = ngx_http_file_cache_cleanup; cln->data = c; } rc = ngx_http_file_cache_exists(cache, c); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache exists: %i e:%d", rc, c->exists); if (rc == NGX_ERROR) { return rc; } if (rc == NGX_AGAIN) { return NGX_HTTP_CACHE_SCARCE; } cold = cache->sh->cold; if (rc == NGX_OK) { if (c->error) { return c->error; } c->temp_file = 1; test = c->exists ? 1 : 0; rv = NGX_DECLINED; } else { /* rc == NGX_DECLINED */ if (c->min_uses > 1) { if (!cold) { return NGX_HTTP_CACHE_SCARCE; } test = 1; rv = NGX_HTTP_CACHE_SCARCE; } else { c->temp_file = 1; test = cold ? 1 : 0; rv = NGX_DECLINED; } } if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) { return NGX_ERROR; } if (!test) { goto done; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.uniq = c->uniq; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.events = clcf->open_file_cache_events; of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; of.read_ahead = clcf->read_ahead; if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: goto done; default: ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, ngx_open_file_n " \"%s\" failed", c->file.name.data); return NGX_ERROR; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache fd: %d", of.fd); c->file.fd = of.fd; c->file.log = r->connection->log; c->uniq = of.uniq; c->length = of.size; c->fs_size = (of.fs_size + cache->bsize - 1) / cache->bsize; c->buf = ngx_create_temp_buf(r->pool, c->body_start); if (c->buf == NULL) { return NGX_ERROR; } return ngx_http_file_cache_read(r, c); done: if (rv == NGX_DECLINED) { return ngx_http_file_cache_lock(r, c); } return rv; }
static ngx_int_t ngx_http_ts_split_index_info(ngx_http_request_t *r, ngx_str_t *index_path, ngx_int_t media_seq, ngx_uint_t *media_begin, ngx_uint_t *media_len) { ngx_http_ts_split_media_index_t *addr; ngx_open_file_info_t of; ngx_log_t *log; ngx_http_core_loc_conf_t *clcf; ngx_uint_t level; ngx_int_t rc; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); log = r->connection->log; ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, index_path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, index_path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: #if (NGX_HAVE_OPENAT) case NGX_EMLINK: case NGX_ELOOP: #endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, index_path->data); } return rc; } addr = (ngx_http_ts_split_media_index_t *)mmap(NULL, of.size, PROT_READ, MAP_SHARED, of.fd, 0); if (addr == MAP_FAILED) { ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, "mmap(%uz) \"%V\" %s", of.size, index_path, strerror(errno)); return NGX_ERROR; } ngx_http_ts_split_media_index_t *media_index = (ngx_http_ts_split_media_index_t *)addr + media_seq/10; *media_begin = media_index->media_begin; *media_len = media_index->media_len; return NGX_OK; }
static ssize_t ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len) { size_t root; ssize_t n; ngx_str_t log, path; ngx_open_file_info_t of; ngx_http_log_loc_conf_t *llcf; ngx_http_core_loc_conf_t *clcf; if (!r->root_tested) { /* test root directory existance */ if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { /* simulate successfull logging */ return len; } path.data[root] = '\0'; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.test_dir = 1; of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { if (of.err == 0) { /* simulate successfull logging */ return len; } ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err, "testing \"%s\" existence failed", path.data); /* simulate successfull logging */ return len; } if (!of.is_dir) { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR, "testing \"%s\" existence failed", path.data); /* simulate successfull logging */ return len; } } if (ngx_http_script_run(r, &log, script->lengths->elts, 1, script->values->elts) == NULL) { /* simulate successfull logging */ return len; } log.data[log.len - 1] = '\0'; *name = log.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http log \"%s\"", log.data); llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.log = 1; of.valid = llcf->open_file_cache_valid; of.min_uses = llcf->open_file_cache_min_uses; of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool) != NGX_OK) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, "%s \"%s\" failed", of.failed, log.data); /* simulate successfull logging */ return len; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http log #%d", of.fd); n = ngx_write_fd(of.fd, buf, len); return n; }
static ngx_int_t ngx_http_ts_split_handler(ngx_http_request_t *r) { u_char *last; size_t root; ngx_str_t path, index_path, media_path; ngx_str_t first, second, media_name; ngx_int_t rc, media_seq; ngx_uint_t media_begin, media_len; ngx_uint_t level; ngx_buf_t *b; ngx_chain_t out; ngx_open_file_info_t of; ngx_log_t *log; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } ngx_str_null(&media_name); ngx_str_null(&second); log = r->connection->log; /* * ngx_http_map_uri_to_path() allocates memory for terminating '\0' * so we do not need to reserve memory for '/' for possible redirect */ last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); ngx_http_ts_split_rpartition(&path, &first, &second, '/'); index_path.len = first.len + sizeof("index.m3u8") + 1; index_path.data = ngx_palloc(r->pool, index_path.len); ngx_snprintf(index_path.data, index_path.len, "%V/index.m3u8", &first); index_path.data[index_path.len-1] = '\0'; media_name = ngx_http_ts_split_get_media_name(&second); media_path.len = first.len + 5 + media_name.len; media_path.data = ngx_palloc(r->pool, media_path.len); ngx_snprintf(media_path.data, media_path.len, "%V/%V.ts", &first, &media_name); media_path.data[media_path.len-1] = '\0'; media_seq = ngx_http_ts_split_get_media_seq(&second); media_begin = 0; media_len = 0; if (ngx_http_ts_split_index_info(r, &index_path, media_seq, &media_begin, &media_len) != NGX_OK) { return NGX_ERROR; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &media_path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &media_path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: #if (NGX_HAVE_OPENAT) case NGX_EMLINK: case NGX_ELOOP: #endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, media_path.data); } return rc; } r->root_tested = !r->error_page; #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data); return NGX_HTTP_NOT_FOUND; } #endif if (r->method & NGX_HTTP_POST) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = media_len; if (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (r != r->main && of.size == 0) { return ngx_http_send_header(r); } /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = media_begin; b->file_last = media_begin + media_len; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = media_path; b->file->log = log; b->file->directio = of.is_directio; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r) { u_char *p; ngx_int_t rc, rv; ngx_uint_t cold, test; ngx_path_t *path; ngx_http_cache_t *c; ngx_pool_cleanup_t *cln; ngx_open_file_info_t of; ngx_http_file_cache_t *cache; ngx_http_core_loc_conf_t *clcf; c = r->cache; if (c->buf) { return ngx_http_file_cache_read(r, c); } cache = c->file_cache; cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_ERROR; } rc = ngx_http_file_cache_exists(cache, c); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache exists: %i e:%d", rc, c->exists); if (rc == NGX_ERROR) { return rc; } cln->handler = ngx_http_file_cache_cleanup; cln->data = c; if (rc == NGX_AGAIN) { return NGX_HTTP_CACHE_SCARCE; } cold = cache->sh->cold; if (rc == NGX_OK) { if (c->error) { return c->error; } c->temp_file = 1; test = c->exists ? 1 : 0; rv = NGX_DECLINED; } else { /* rc == NGX_DECLINED */ if (c->min_uses > 1) { if (!cold) { return NGX_HTTP_CACHE_SCARCE; } test = 1; rv = NGX_HTTP_CACHE_SCARCE; } else { c->temp_file = 1; test = cold ? 1 : 0; rv = NGX_DECLINED; } } path = cache->path; c->file.name.len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1); if (c->file.name.data == NULL) { return NGX_ERROR; } ngx_memcpy(c->file.name.data, path->name.data, path->name.len); p = c->file.name.data + path->name.len + 1 + path->len; p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN); *p = '\0'; ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "cache file: \"%s\"", c->file.name.data); if (!test) { return NGX_DECLINED; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.uniq = c->uniq; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.events = clcf->open_file_cache_events; of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; of.read_ahead = clcf->read_ahead; if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: return rv; default: ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, ngx_open_file_n " \"%s\" failed", c->file.name.data); return NGX_ERROR; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache fd: %d", of.fd); c->file.fd = of.fd; c->file.log = r->connection->log; c->uniq = of.uniq; c->length = of.size; c->buf = ngx_create_temp_buf(r->pool, c->body_start); if (c->buf == NULL) { return NGX_ERROR; } return ngx_http_file_cache_read(r, c); }
static jlong JNICALL jni_ngx_create_file_buf (JNIEnv *env, jclass cls, jlong r, jlong file, jlong name_len, jint last_buf) { ngx_http_request_t *req = (ngx_http_request_t *) r; ngx_buf_t *b; ngx_str_t path; // = {(ngx_int_t)name_len, (u_char *)file}; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf = ngx_http_get_module_loc_conf(req, ngx_http_core_module); ngx_uint_t level; ngx_log_t *log = req->connection->log; /*make VS 2010 happy*/ path.data = (u_char *)file; path.len = (ngx_int_t)name_len; /*just like http_static module */ ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, req->pool) != NGX_OK) { ngx_int_t rc = 0; switch (of.err) { case 0: return -NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); } return -rc; } if (of.is_dir) { return -NGX_HTTP_NOT_FOUND; } #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data); return -NGX_HTTP_NOT_FOUND; } #endif req->allow_ranges = 1; b = ngx_pcalloc(req->pool, sizeof(ngx_buf_t)); if (b == NULL) { return -NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(req->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return -NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = last_buf; b->last_in_chain = last_buf; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; if (req->headers_out.content_length_n < 0) { req->headers_out.content_length_n = of.size; } else { req->headers_out.content_length_n += of.size; } if (req->headers_out.last_modified_time != -2 && req->headers_out.last_modified_time < of.mtime) { req->headers_out.last_modified_time = of.mtime; } return (uintptr_t)b; }