ngx_int_t ngx_http_echo_exec_exec(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { /* ngx_int_t rc; */ ngx_str_t *uri; ngx_str_t *user_args; ngx_str_t args; ngx_uint_t flags; ngx_str_t *computed_arg; computed_arg = computed_args->elts; uri = &computed_arg[0]; if (uri->len == 0) { return NGX_HTTP_BAD_REQUEST; } if (computed_args->nelts > 1) { user_args = &computed_arg[1]; } else { user_args = NULL; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (args.len > 0 && user_args == NULL) { user_args = &args; } /* rc = ngx_http_echo_send_header_if_needed(r, ctx); if (r->header_only || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } */ if (uri->data[0] == '@') { if (user_args && user_args->len > 0) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "query strings %V ignored when exec'ing named location %V", user_args, uri); } return ngx_http_named_location(r, uri); } return ngx_http_internal_redirect(r, uri, user_args); }
static ngx_int_t ngx_http_sysguard_do_redirect(ngx_http_request_t *r, ngx_str_t *path) { if (path->len == 0) { return NGX_HTTP_SERVICE_UNAVAILABLE; } else if (path->data[0] == '@') { (void) ngx_http_named_location(r, path); } else { (void) ngx_http_internal_redirect(r, path, &r->args); } ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; }
/** * ngx_http_status_page_send_page * @r: request * @page: error page to send * @in_body: 1 for body filters, 0 for phases & header filters * * return: NGX_DONE * */ ngx_int_t ngx_http_status_page_send_page(ngx_http_request_t *r, ngx_str_t *page, ngx_int_t in_body, ngx_uint_t status) { ngx_list_part_t *part; #if (NGX_HTTP_SESSION) ngx_http_ns_jump_bit_set(r, NGX_HTTP_NETEYE_SESSION); #endif ngx_http_status_page_set_bypass(r); ngx_http_ns_set_bypass_all(r); if (status != 0) { ngx_http_status_page_set_change_status(r); ngx_http_status_page_set_status(r, status); } r->headers_out.content_length = NULL; r->headers_out.date = NULL; r->headers_out.content_type.len = 0; r->headers_out.server = NULL; r->headers_out.location = NULL; r->headers_out.last_modified = NULL; r->headers_out.status_line.len = 0; part = &r->headers_out.headers.part; part->nelts = 0; if (in_body) { ngx_http_status_page_set_old_header(r); } /* to bypass the method check in http_static_module */ if (r->method & NGX_HTTP_POST) { r->method &= ~NGX_HTTP_POST; r->method |= NGX_HTTP_GET; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "in status page filter, redirect to %V", page); ngx_http_internal_redirect(r, page, NULL); return NGX_DONE; }
/* 配置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; }
ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int nret) { int rv; int cc_ref; lua_State *cc; const char *err, *msg; ngx_int_t rc; /* set Lua VM panic handler */ lua_atpanic(L, ngx_http_lua_atpanic); dd("ctx = %p", ctx); NGX_LUA_EXCEPTION_TRY { cc = ctx->cc; cc_ref = ctx->cc_ref; /* run code */ rv = lua_resume(cc, nret); dd("lua resume returns %d", (int) rv); switch (rv) { case LUA_YIELD: /* yielded, let event handler do the rest job */ /* FIXME: add io cmd dispatcher here */ dd("lua coroutine yielded"); #if 0 ngx_http_lua_dump_postponed(r); #endif lua_settop(cc, 0); return NGX_AGAIN; case 0: dd("normal end %.*s", (int) r->uri.len, r->uri.data); #if 0 ngx_http_lua_dump_postponed(r); #endif ngx_http_lua_del_thread(r, L, cc_ref, 0); ctx->cc_ref = LUA_NOREF; if (ctx->cleanup) { dd("cleaning up cleanup"); *ctx->cleanup = NULL; ctx->cleanup = NULL; } if (ctx->entered_content_phase) { rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } } return NGX_OK; case LUA_ERRRUN: err = "runtime error"; break; case LUA_ERRSYNTAX: err = "syntax error"; break; case LUA_ERRMEM: err = "memory allocation error"; break; case LUA_ERRERR: err = "error handler error"; break; default: err = "unknown error"; break; } if (lua_isstring(cc, -1)) { dd("user custom error msg"); msg = lua_tostring(cc, -1); } else { if (lua_isnil(cc, -1)) { if (ctx->exited) { dd("run here...exiting... %d", (int) ctx->exit_code); ngx_http_lua_del_thread(r, L, cc_ref, 0); ctx->cc_ref = LUA_NOREF; if (ctx->cleanup) { *ctx->cleanup = NULL; ctx->cleanup = NULL; } if (ctx->exit_code == NGX_OK) { if (ctx->entered_content_phase) { rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } } } return ctx->exit_code; } if (ctx->exec_uri.len) { ngx_http_lua_del_thread(r, L, cc_ref, 0); ctx->cc_ref = LUA_NOREF; if (ctx->cleanup) { *ctx->cleanup = NULL; ctx->cleanup = NULL; } if (ctx->exec_uri.data[0] == '@') { if (ctx->exec_args.len > 0) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "query strings %V ignored when exec'ing " "named location %V", &ctx->exec_args, &ctx->exec_uri); } #if defined(nginx_version) && nginx_version >= 8011 /* ngx_http_named_location always increments * r->main->count, which is not we want for * non-content phases */ if (! ctx->entered_content_phase) { r->main->count--; } #endif return ngx_http_named_location(r, &ctx->exec_uri); } dd("internal redirect to %.*s", (int) ctx->exec_uri.len, ctx->exec_uri.data); #if defined(nginx_version) && nginx_version >= 8011 /* ngx_http_internal_redirect always increments * r->main->count, which is not we want for * non-content phases */ if (! ctx->entered_content_phase) { r->main->count--; } #endif return ngx_http_internal_redirect(r, &ctx->exec_uri, &ctx->exec_args); } } msg = "unknown reason"; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "content_by_lua aborted: %s: %s", err, msg); ngx_http_lua_del_thread(r, L, cc_ref, 0); ctx->cc_ref = LUA_NOREF; if (ctx->cleanup) { *ctx->cleanup = NULL; ctx->cleanup = NULL; } dd("headers sent? %d", ctx->headers_sent ? 1 : 0); return ctx->headers_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; } NGX_LUA_EXCEPTION_CATCH { dd("nginx execution restored"); } return NGX_ERROR; }
static ngx_int_t ngx_http_limit_req_handler(ngx_http_request_t *r) { uint32_t hash; ngx_str_t key; ngx_int_t rc; ngx_uint_t n, excess; ngx_msec_t delay; ngx_http_limit_req_ctx_t *ctx; ngx_http_limit_req_conf_t *lrcf; ngx_http_limit_req_limit_t *limit, *limits; if (r->main->limit_req_set) { return NGX_DECLINED; } lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module); limits = lrcf->limits.elts; #if (T_LIMIT_REQ) if (!lrcf->enable) { return NGX_DECLINED; } /* filter whitelist */ if (ngx_http_limit_req_ip_filter(r, lrcf) == NGX_OK) { return NGX_DECLINED; } #endif excess = 0; rc = NGX_DECLINED; #if (NGX_SUPPRESS_WARN) limit = NULL; #endif for (n = 0; n < lrcf->limits.nelts; n++) { limit = &limits[n]; ctx = limit->shm_zone->data; #if (T_LIMIT_REQ_RATE_VAR) if (ngx_http_limit_req_rate_value(r, ctx) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } #endif if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (key.len == 0) { continue; } if (key.len > 65535) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the value of the \"%V\" key " "is more than 65535 bytes: \"%V\"", &ctx->key.value, &key); continue; } hash = ngx_crc32_short(key.data, key.len); ngx_shmtx_lock(&ctx->shpool->mutex); rc = ngx_http_limit_req_lookup(limit, hash, &key, &excess, (n == lrcf->limits.nelts - 1)); ngx_shmtx_unlock(&ctx->shpool->mutex); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit_req[%ui]: %i %ui.%03ui", n, rc, excess / 1000, excess % 1000); if (rc != NGX_AGAIN) { break; } } if (rc == NGX_DECLINED) { return NGX_DECLINED; } r->main->limit_req_set = 1; if (rc == NGX_BUSY || rc == NGX_ERROR) { if (rc == NGX_BUSY) { ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, excess: %ui.%03ui by zone \"%V\"", excess / 1000, excess % 1000, &limit->shm_zone->shm.name); } while (n--) { ctx = limits[n].shm_zone->data; if (ctx->node == NULL) { continue; } ngx_shmtx_lock(&ctx->shpool->mutex); ctx->node->count--; ngx_shmtx_unlock(&ctx->shpool->mutex); ctx->node = NULL; } #if (T_LIMIT_REQ) if (rc == NGX_ERROR || limit->forbid_action.len == 0) { return lrcf->status_code; } else if (limit->forbid_action.data[0] == '@') { ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, forbid_action is %V", &limit->forbid_action); (void) ngx_http_named_location(r, &limit->forbid_action); } else { ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, forbid_action is %V", &limit->forbid_action); (void) ngx_http_internal_redirect(r, &limit->forbid_action, &r->args); } ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; #else return lrcf->status_code; #endif } /* rc == NGX_AGAIN || rc == NGX_OK */ if (rc == NGX_AGAIN) { excess = 0; } delay = ngx_http_limit_req_account(limits, n, &excess, &limit); if (!delay) { return NGX_DECLINED; } ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, "delaying request, excess: %ui.%03ui, by zone \"%V\"", excess / 1000, excess % 1000, &limit->shm_zone->shm.name); if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->read_event_handler = ngx_http_test_reading; r->write_event_handler = ngx_http_limit_req_delay; r->connection->write->delayed = 1; ngx_add_timer(r->connection->write, delay); return NGX_AGAIN; }
static ngx_int_t ngx_http_limit_speed_handler(ngx_http_request_t *r) { size_t len, n; uint32_t hash; ngx_int_t rc; ngx_uint_t speed; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node, *sentinel; ngx_pool_cleanup_t *cln; ngx_http_variable_value_t *vv; ngx_http_limit_speed_ctx_t *ctx; ngx_http_limit_speed_node_t *ls; ngx_http_limit_speed_conf_t *lscf; ngx_http_limit_speed_cleanup_t *lscln; ngx_http_limit_speed_req_ctx_t *rctx; lscf = ngx_http_get_module_loc_conf(r, ngx_http_limit_speed_module); if (lscf->shm_zone == NULL || lscf->speed == 0) { return NGX_DECLINED; } if (r->main->limit_rate) { return NGX_DECLINED; } ctx = lscf->shm_zone->data; vv = ngx_http_get_indexed_variable(r, ctx->index); if (vv == NULL || vv->not_found) { return NGX_DECLINED; } len = vv->len; if (len == 0) { return NGX_DECLINED; } if (lscf->var_max_len) { len = len > lscf->var_max_len ? lscf->var_max_len : len; } hash = ngx_crc32_short(vv->data, len); cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_speed_cleanup_t)); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } shpool = (ngx_slab_pool_t *) lscf->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); node = ctx->rbtree->root; sentinel = ctx->rbtree->sentinel; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ do { ls = (ngx_http_limit_speed_node_t *) &node->color; rc = ngx_memn2cmp(vv->data, ls->data, len, (size_t) ls->len); if (rc == 0) { ls->conn++; goto done; } node = (rc < 0) ? node->left : node->right; } while (node != sentinel && hash == node->key); break; } n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_limit_speed_node_t, data) + len; node = ngx_slab_alloc_locked(shpool, n); if (node == NULL) { ngx_shmtx_unlock(&shpool->mutex); return NGX_DECLINED; } ls = (ngx_http_limit_speed_node_t *) &node->color; node->key = hash; ls->len = (u_char) len; ls->conn = 1; ngx_memcpy(ls->data, vv->data, len); ngx_rbtree_insert(ctx->rbtree, node); done: speed = lscf->speed; r->main->limit_rate = speed / ls->conn; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit speed zone: %08XD conn=%d, speed=%d", node->key, ls->conn, r->main->limit_rate); ngx_shmtx_unlock(&shpool->mutex); cln->handler = ngx_http_limit_speed_cleanup; lscln = cln->data; lscln->shm_zone = lscf->shm_zone; lscln->node = node; if (lscf->minimum && r->main->limit_rate <= lscf->minimum) { r->main->limit_rate = 0; if (lscf->rewrite.len == 0) { return NGX_HTTP_SERVICE_UNAVAILABLE; } if (lscf->rewrite.data[0] == '@') { (void) ngx_http_named_location(r, &lscf->rewrite); } else { (void) ngx_http_internal_redirect(r, &lscf->rewrite, &r->args); } ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } if (ngx_http_limit_speed_get_ctx(r) != NGX_OK) { return NGX_DECLINED; } rctx = ngx_http_get_module_ctx(r, ngx_http_limit_speed_module); rctx->speed = speed; rctx->ls = ls; return NGX_DECLINED; }
// like Nginx rewrite keywords // used like this: // => http code 3xx location in browser // => internal redirection in nginx static mrb_value ngx_mrb_redirect(mrb_state *mrb, mrb_value self) { int argc; u_char *str; ngx_int_t rc; mrb_value uri, code; ngx_str_t ns; ngx_table_elt_t *location; ngx_http_request_t *r = ngx_mrb_get_request(); argc = mrb_get_args(mrb, "o|oo", &uri, &code); // get status code from args if (argc == 2) { rc = mrb_fixnum(code); } else { rc = NGX_HTTP_MOVED_TEMPORARILY; } // get redirect uri from args if (mrb_type(uri) != MRB_TT_STRING) { uri = mrb_funcall(mrb, uri, "to_s", 0, NULL); } // save location uri to ns ns.len = RSTRING_LEN(uri); if (ns.len == 0) { return mrb_nil_value(); } ns.data = ngx_palloc(r->pool, ns.len); ngx_memcpy(ns.data, RSTRING_PTR(uri), ns.len); // if uri start with scheme prefix // return 3xx for redirect // else generate a internal redirection and response to raw request // request.path is not changed if (ngx_strncmp(ns.data, "http://", sizeof("http://") - 1) == 0 || ngx_strncmp(ns.data, "https://", sizeof("https://") - 1) == 0 || ngx_strncmp(ns.data, "$scheme", sizeof("$scheme") - 1) == 0) { str = ngx_pstrdup(r->pool, &ns); if (str == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory"); } str[ns.len] = '\0'; // build redirect location location = ngx_list_push(&r->headers_out.headers); if (location == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory"); } location->hash = 1; ngx_str_set(&location->key, "Location"); location->value = ns; location->lowcase_key = ngx_pnalloc(r->pool, location->value.len); if (location->lowcase_key == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory"); } ngx_strlow(location->lowcase_key, location->value.data, location->value.len); // set location and response code for hreaders r->headers_out.location = location; r->headers_out.status = rc; } else { ngx_http_internal_redirect(r, &ns, &r->args); ngx_http_finalize_request(r, NGX_DONE); } return self; }
void ngx_http_memcachep_process(ngx_event_t *wev, ngx_str_t uri) { ngx_connection_t *c; ngx_http_memcachedp_session_t *s; ngx_http_conf_ctx_t *ctx; c = wev->data; s = c->data; ctx = (ngx_http_conf_ctx_t *) c->listening->servers; if (1) { ngx_http_request_t *r; r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)); r->main = r; r->pool = c->pool; r->main_conf = ctx->main_conf; r->srv_conf = ctx->srv_conf; r->loc_conf = ctx->loc_conf; r->ctx = (void *) ngx_modules; r->connection = ngx_pcalloc(c->pool, sizeof(ngx_connection_t)); r->connection->log = c->log; r->connection->read = ngx_pcalloc(c->pool, sizeof(ngx_event_t)); r->connection->write = r->connection->read; r->connection->write->data = c; r->connection->write->ready = 1; r->connection->write->delayed = 1; r->subrequest_in_memory = 1; r->buffered = 1; r->connection->buffered = 1; r->main_filter_need_in_memory = 1; r->filter_need_in_memory = 1; r->method = NGX_HTTP_GET; r->out = ngx_pcalloc(c->pool, sizeof(ngx_chain_t)); r->variables = ngx_pcalloc(r->pool, 1 * sizeof(ngx_http_variable_value_t)); if (r->variables == NULL) { ngx_http_memcachep_close_connection(c); return; } r->method_name.data = ngx_pcalloc(c->pool, sizeof(u_char *) * (uri.len + 30)); r->method_name.len = ngx_sprintf(r->method_name.data, "GET %s HTTP/1.1", uri.data) - r->method_name.data; if (ngx_http_internal_redirect(r, &uri, NULL) != NGX_DONE) { ngx_http_memcachep_close_connection(c); return; } // ngx_http_postponed_request_t に入って r->postponed の中に response body が入ってる? // データが帰って来たのでレスポンス返す if (r->postponed && r->postponed->out && r->postponed->out->buf) { ngx_chain_t *cl; ngx_str_t crlf = ngx_string("\r\n"); ngx_str_t end = ngx_string("END\r\n"); s->out.len = (10 + uri.len) * 3; s->out.data = ngx_pnalloc(c->pool, s->out.len); if (s->out.data == NULL) { ngx_http_memcachep_close_connection(c); return; } s->out.len = ngx_sprintf(s->out.data, "VALUE %s 0 %d" CRLF, (char *)uri.data, (int)r->headers_out.content_length_n) - s->out.data; ngx_http_memcachep_send(wev); for (cl = r->postponed->out; cl; cl = cl->next) { ssize_t n, size; s->out.data = cl->buf->pos; s->out.len = cl->buf->last - cl->buf->pos; ngx_http_memcachep_send(wev); if (!cl->buf->file || !cl->buf->file->fd) { continue; } // 4096 のサイズずつ転送 while (1) { size = (r->headers_out.content_length_n - cl->buf->file_last); if (size == 0) { break; } if (size > 4096) { size = 4096; } n = ngx_read_file(cl->buf->file, s->out_buffer.data, (size_t) size, cl->buf->file_last); if (n != size) { ngx_http_memcachep_close_connection(c); return; } s->out.data = s->out_buffer.data; s->out.len = n; ngx_http_memcachep_send(wev); cl->buf->file_last += n; } } s->out = crlf; ngx_http_memcachep_send(wev); s->out = end; ngx_http_memcachep_send(wev); } } }
static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) { ngx_int_t overwrite; ngx_str_t uri, args; ngx_table_elt_t *location; ngx_http_core_loc_conf_t *clcf; overwrite = err_page->overwrite; if (overwrite && overwrite != NGX_HTTP_OK) { r->expect_tested = 1; } if (overwrite >= 0) { r->err_status = overwrite; } if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) { return NGX_ERROR; } if (uri.len && uri.data[0] == '/') { if (err_page->value.lengths) { ngx_http_split_args(r, &uri, &args); } else { args = err_page->args; } if (r->method != NGX_HTTP_HEAD) { r->method = NGX_HTTP_GET; r->method_name = ngx_http_get_name; } return ngx_http_internal_redirect(r, &uri, &args); } if (uri.len && uri.data[0] == '@') { return ngx_http_named_location(r, &uri); } location = ngx_list_push(&r->headers_out.headers); if (location == NULL) { return NGX_ERROR; } if (overwrite != NGX_HTTP_MOVED_PERMANENTLY && overwrite != NGX_HTTP_MOVED_TEMPORARILY && overwrite != NGX_HTTP_SEE_OTHER && overwrite != NGX_HTTP_TEMPORARY_REDIRECT) { r->err_status = NGX_HTTP_MOVED_TEMPORARILY; } location->hash = 1; ngx_str_set(&location->key, "Location"); location->value = uri; ngx_http_clear_location(r); r->headers_out.location = location; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->msie_refresh && r->headers_in.msie) { return ngx_http_send_refresh(r); } return ngx_http_send_special_response(r, clcf, r->err_status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX); }
static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) { u_char ch, *p, *last; ngx_str_t *uri, *args, u, a; ngx_table_elt_t *location; ngx_http_core_loc_conf_t *clcf; r->err_status = err_page->overwrite; r->method = NGX_HTTP_GET; r->method_name = ngx_http_get_name; r->zero_in_uri = 0; args = NULL; if (err_page->uri_lengths) { if (ngx_http_script_run(r, &u, err_page->uri_lengths->elts, 0, err_page->uri_values->elts) == NULL) { return NGX_ERROR; } p = u.data; uri = &u; if (*p == '/') { last = p + uri->len; while (p < last) { ch = *p++; if (ch == '?') { a.len = last - p; a.data = p; args = &a; u.len = p - 1 - u.data; while (p < last) { if (*p++ == '\0') { r->zero_in_uri = 1; break; } } break; } if (ch == '\0') { r->zero_in_uri = 1; continue; } } } } else { uri = &err_page->uri; } if (uri->data[0] == '/') { return ngx_http_internal_redirect(r, uri, args); } if (uri->data[0] == '@') { return ngx_http_named_location(r, uri); } location = ngx_list_push(&r->headers_out.headers); if (location == NULL) { return NGX_ERROR; } r->err_status = NGX_HTTP_MOVED_TEMPORARILY; location->hash = 1; location->key.len = sizeof("Location") - 1; location->key.data = (u_char *) "Location"; location->value = *uri; r->headers_out.location = location; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->msie_refresh && r->headers_in.msie) { return ngx_http_send_refresh(r); } return ngx_http_send_special_response(r, clcf, NGX_HTTP_MOVED_TEMPORARILY - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200); }
static ngx_int_t ngx_http_internal_redirect_handler(ngx_http_request_t *r) { u_char *p; ngx_uint_t i; ngx_str_t uri, args; ngx_http_script_code_pt code; ngx_http_script_engine_t e; ngx_http_variable_value_t stack[10]; ngx_http_internal_redirect_entry_t *redirects; ngx_http_internal_redirect_main_conf_t *imcf; ngx_http_internal_redirect_loc_conf_t *ilcf; ngx_http_core_main_conf_t *cmcf; ngx_http_phase_handler_t *ph, *cur_ph, *last_ph, tmp; imcf = ngx_http_get_module_main_conf(r, ngx_http_internal_redirect_module); if (!imcf->postponed) { imcf->postponed = 1; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ph = cmcf->phase_engine.handlers; cur_ph = &ph[r->phase_handler]; last_ph = &ph[cur_ph->next - 1]; if (cur_ph < last_ph) { tmp = *cur_ph; ngx_memmove(cur_ph, cur_ph + 1, (last_ph - cur_ph) * sizeof(ngx_http_phase_handler_t)); *last_ph = tmp; r->phase_handler--; /* redo the current ph */ return NGX_DECLINED; } } ilcf = ngx_http_get_module_loc_conf(r, ngx_http_internal_redirect_module); if (ilcf->redirects == NULL) { return NGX_DECLINED; } redirects = ilcf->redirects->elts; for (i = 0; i < ilcf->redirects->nelts; i++) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); ngx_memzero(&stack, sizeof(stack)); e.sp = stack; e.ip = redirects[i].codes->elts; e.request = r; e.quote = 1; e.log = 1; e.status = NGX_DECLINED; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code(&e); } e.sp--; if (e.sp->len && (e.sp->len != 1 || e.sp->data[0] != '0')) { break; } } if (i == ilcf->redirects->nelts) { return NGX_DECLINED; } if (redirects[i].code) { return redirects[i].code; } if (redirects[i].lengths) { if (ngx_http_script_run(r, &uri, redirects[i].lengths->elts, 0, redirects->values->elts) == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } else { uri = redirects[i].name; } if (uri.data[0] == '@') { (void) ngx_http_named_location(r, &uri); } else { if (uri.data[0] != '/') { p = ngx_pcalloc(r->pool, uri.len + 1); if (p == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } uri.len++; *p = '/'; ngx_memcpy(p + 1, uri.data, uri.len); uri.data = p; } ngx_http_split_args(r, &uri, &args); (void) ngx_http_internal_redirect(r, &uri, &args); } ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; }
static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) { ngx_int_t overwrite; ngx_str_t uri, args; ngx_table_elt_t *location; ngx_http_core_loc_conf_t *clcf; overwrite = err_page->overwrite; if (overwrite && overwrite != NGX_HTTP_OK) { r->expect_tested = 1; } r->err_status = overwrite; r->zero_in_uri = 0; if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) { return NGX_ERROR; } if (uri.data[0] == '/') { if (err_page->value.lengths) { ngx_http_split_args(r, &uri, &args); } else { args = err_page->args; } if (r->method != NGX_HTTP_HEAD) { r->method = NGX_HTTP_GET; r->method_name = ngx_http_get_name; } return ngx_http_internal_redirect(r, &uri, &args); } if (uri.data[0] == '@') { return ngx_http_named_location(r, &uri); } location = ngx_list_push(&r->headers_out.headers); if (location == NULL) { return NGX_ERROR; } r->err_status = NGX_HTTP_MOVED_TEMPORARILY; location->hash = 1; location->key.len = sizeof("Location") - 1; location->key.data = (u_char *) "Location"; location->value = uri; r->headers_out.location = location; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->msie_refresh && r->headers_in.msie) { return ngx_http_send_refresh(r); } return ngx_http_send_special_response(r, clcf, NGX_HTTP_MOVED_TEMPORARILY - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200); }
// like Nginx rewrite keywords // used like this: // => http code 3xx location in browser // => internal redirection in nginx static mrb_value ngx_http_mruby_redirect(mrb_state *mrb, mrb_value self) { int argc; u_char *str; ngx_int_t rc; mrb_value uri, code; ngx_str_t ns; ngx_http_request_t *r; ngx_http_mruby_ctx_t *ctx; r = ngx_http_mruby_get_request(); ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module); argc = mrb_get_args(mrb, "o|oo", &uri, &code); if (argc == 2) { rc = mrb_fixnum(code); } else { rc = NGX_HTTP_MOVED_TEMPORARILY; } uri = mrb_obj_as_string(mrb, uri); // save location uri to ns ns.data = (u_char *)RSTRING_PTR(uri); ns.len = RSTRING_LEN(uri); if (ns.len == 0) { return mrb_nil_value(); } // if uri start with scheme prefix // return 3xx for redirect // else generate a internal redirection and response to raw request // request.path is not changed if (ngx_strncmp(ns.data, "http://", sizeof("http://") - 1) == 0 || ngx_strncmp(ns.data, "https://", sizeof("https://") - 1) == 0 || ngx_strncmp(ns.data, "$scheme", sizeof("$scheme") - 1) == 0) { if ((str = ngx_pnalloc(r->pool, ns.len + 1)) == NULL) { return self; } ngx_memcpy(str, ns.data, ns.len); str[ns.len] = '\0'; // build redirect location r->headers_out.location = ngx_list_push(&r->headers_out.headers); if (r->headers_out.location == NULL) { return self; } r->headers_out.location->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash( ngx_hash('l', 'o'), 'c'), 'a'), 't'), 'i'), 'o'), 'n'); r->headers_out.location->value.data = ns.data; r->headers_out.location->value.len = ns.len; ngx_str_set(&r->headers_out.location->key, "Location"); r->headers_out.status = rc; ctx->exited = 1; ctx->exit_code = rc; } else { ctx->exited = 1; ctx->exit_code = ngx_http_internal_redirect(r, &ns, &r->args); } return self; }
ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, int error) { ngx_int_t rc; ngx_uint_t err, i, msie_padding; ngx_buf_t *b; ngx_chain_t *out, **ll, *cl; ngx_http_err_page_t *err_page; ngx_http_core_loc_conf_t *clcf; rc = ngx_http_discard_body(r); if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { error = NGX_HTTP_INTERNAL_SERVER_ERROR; } r->headers_out.status = error; if (r->keepalive != 0) { switch (error) { case NGX_HTTP_BAD_REQUEST: case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE: case NGX_HTTP_REQUEST_URI_TOO_LARGE: case NGX_HTTP_TO_HTTPS: case NGX_HTTP_INTERNAL_SERVER_ERROR: r->keepalive = 0; } } if (r->lingering_close == 1) { switch (error) { case NGX_HTTP_BAD_REQUEST: case NGX_HTTP_TO_HTTPS: r->lingering_close = 0; } } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->err_ctx == NULL && clcf->error_pages) { err_page = clcf->error_pages->elts; for (i = 0; i < clcf->error_pages->nelts; i++) { if (err_page[i].status == error) { if (err_page[i].overwrite) { r->err_status = err_page[i].overwrite; } else { r->err_status = error; } r->err_ctx = r->ctx; return ngx_http_internal_redirect(r, &err_page[i].uri, NULL); } } } if (error < NGX_HTTP_BAD_REQUEST) { /* 3XX */ err = error - NGX_HTTP_MOVED_PERMANENTLY; } else if (error < NGX_HTTP_NGX_CODES) { /* 4XX */ err = error - NGX_HTTP_BAD_REQUEST + 3; } else { /* 49X, 5XX */ err = error - NGX_HTTP_NGX_CODES + 3 + 17; switch (error) { case NGX_HTTP_TO_HTTPS: r->headers_out.status = NGX_HTTP_BAD_REQUEST; error = NGX_HTTP_BAD_REQUEST; break; case NGX_HTTP_INVALID_HOST: r->headers_out.status = NGX_HTTP_NOT_FOUND; error = NGX_HTTP_NOT_FOUND; break; } } msie_padding = 0; if (error_pages[err].len) { r->headers_out.content_length_n = error_pages[err].len + sizeof(error_tail) - 1; if (clcf->msie_padding && r->headers_in.msie && r->http_version >= NGX_HTTP_VERSION_10 && error >= NGX_HTTP_BAD_REQUEST && error != NGX_HTTP_REQUEST_URI_TOO_LARGE) { r->headers_out.content_length_n += sizeof(msie_stub) - 1; msie_padding = 1; } r->headers_out.content_type = ngx_list_push(&r->headers_out.headers); if (r->headers_out.content_type == NULL) { return NGX_ERROR; } r->headers_out.content_type->key.len = sizeof("Content-Type") - 1; r->headers_out.content_type->key.data = (u_char *) "Content-Type"; r->headers_out.content_type->value.len = sizeof("text/html") - 1; r->headers_out.content_type->value.data = (u_char *) "text/html"; } else { r->headers_out.content_length_n = -1; } if (r->headers_out.content_length) { r->headers_out.content_length->key.len = 0; r->headers_out.content_length = NULL; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || r->header_only) { return rc; } if (error_pages[err].len == 0) { return NGX_OK; } out = NULL; ll = NULL; if (!(b = ngx_calloc_buf(r->pool))) { return NGX_ERROR; } b->memory = 1; b->pos = error_pages[err].data; b->last = error_pages[err].data + error_pages[err].len; ngx_alloc_link_and_set_buf(cl, b, r->pool, NGX_ERROR); ngx_chain_add_link(out, ll, cl); if (!(b = ngx_calloc_buf(r->pool))) { return NGX_ERROR; } b->memory = 1; b->pos = error_tail; b->last = error_tail + sizeof(error_tail) - 1; ngx_alloc_link_and_set_buf(cl, b, r->pool, NGX_ERROR); ngx_chain_add_link(out, ll, cl); if (msie_padding) { if (!(b = ngx_calloc_buf(r->pool))) { return NGX_ERROR; } b->memory = 1; b->pos = msie_stub; b->last = msie_stub + sizeof(msie_stub) - 1; ngx_alloc_link_and_set_buf(cl, b, r->pool, NGX_ERROR); ngx_chain_add_link(out, ll, cl); } b->last_buf = 1; return ngx_http_output_filter(r, out); }
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; }
/****************************************************************** 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; }
static ngx_int_t ngx_http_random_index_handler(ngx_http_request_t *r) { u_char *last, *filename; size_t len, allocated, root; ngx_err_t err; ngx_int_t rc; ngx_str_t path, uri, *name; ngx_dir_t dir; ngx_uint_t n, level; ngx_array_t names; ngx_http_random_index_loc_conf_t *rlcf; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_DECLINED; } rlcf = ngx_http_get_module_loc_conf(r, ngx_http_random_index_module); if (!rlcf->enable) { return NGX_DECLINED; } #if (NGX_HAVE_D_TYPE) len = NGX_DIR_MASK_LEN; #else len = NGX_HTTP_RANDOM_INDEX_PREALLOCATE; #endif last = ngx_http_map_uri_to_path(r, &path, &root, len); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } allocated = path.len; path.len = last - path.data - 1; path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http random index: \"%s\"", path.data); if (ngx_open_dir(&path, &dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; } else { level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_error(level, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } if (ngx_array_init(&names, r->pool, 32, sizeof(ngx_str_t)) != NGX_OK) { return ngx_http_random_index_error(r, &dir, &path); } filename = path.data; filename[path.len] = '/'; for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_random_index_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http random index file: \"%s\"", ngx_de_name(&dir)); if (ngx_de_name(&dir)[0] == '.') { continue; } len = ngx_de_namelen(&dir); if (dir.type == 0 || ngx_de_is_link(&dir)) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_RANDOM_INDEX_PREALLOCATE; filename = ngx_pnalloc(r->pool, allocated); if (filename == NULL) { return ngx_http_random_index_error(r, &dir, &path); } last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); return ngx_http_random_index_error(r, &dir, &path); } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_random_index_error(r, &dir, &path); } } } if (!ngx_de_is_file(&dir)) { continue; } name = ngx_array_push(&names); if (name == NULL) { return ngx_http_random_index_error(r, &dir, &path); } name->len = len; name->data = ngx_pnalloc(r->pool, len); if (name->data == NULL) { return ngx_http_random_index_error(r, &dir, &path); } ngx_memcpy(name->data, ngx_de_name(&dir), len); } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", &path); } n = names.nelts; if (n == 0) { return NGX_DECLINED; } name = names.elts; n = (ngx_uint_t) (((uint64_t) ngx_random() * n) / 0x80000000); uri.len = r->uri.len + name[n].len; uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(last, name[n].data, name[n].len); return ngx_http_internal_redirect(r, &uri, &r->args); }
static ngx_int_t ngx_http_limit_req2_handler(ngx_http_request_t *r) { size_t n, total_len; uint32_t hash; ngx_int_t rc; ngx_msec_t delay_time; ngx_uint_t excess, delay_excess, delay_postion, nodelay, i; ngx_time_t *tp; ngx_rbtree_node_t *node; ngx_http_limit_req2_t *limit_req2; ngx_http_limit_req2_ctx_t *ctx; ngx_http_limit_req2_node_t *lr; ngx_http_limit_req2_conf_t *lrcf; delay_excess = 0; excess = 0; delay_postion = 0; nodelay = 0; ctx = NULL; rc = NGX_DECLINED; if (r->main->limit_req_set) { return NGX_DECLINED; } lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req2_module); if (lrcf->rules == NULL) { return NGX_DECLINED; } if (!lrcf->enable) { return NGX_DECLINED; } /* filter whitelist */ if (ngx_http_limit_req2_ip_filter(r, lrcf) == NGX_OK) { return NGX_DECLINED; } /* to match limit_req2 rule*/ limit_req2 = lrcf->rules->elts; for (i = 0; i < lrcf->rules->nelts; i++) { ctx = limit_req2[i].shm_zone->data; ngx_crc32_init(hash); total_len = 0; total_len = ngx_http_limit_req2_copy_variables(r, &hash, ctx, NULL); if (total_len == 0) { continue; } ngx_crc32_final(hash); ngx_shmtx_lock(&ctx->shpool->mutex); ngx_http_limit_req2_expire(r, ctx, 1); rc = ngx_http_limit_req2_lookup(r, &limit_req2[i], hash, &excess); ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit_req2 module: %i %ui.%03ui " "hash is %ui total_len is %i", rc, excess / 1000, excess % 1000, hash, total_len); /* first limit_req2 */ if (rc == NGX_DECLINED) { n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_limit_req2_node_t, data) + total_len; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { ngx_http_limit_req2_expire(r, ctx, 0); node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_HTTP_SERVICE_UNAVAILABLE; } } lr = (ngx_http_limit_req2_node_t *) &node->color; node->key = hash; lr->len = (u_char) total_len; tp = ngx_timeofday(); lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); lr->excess = 0; ngx_http_limit_req2_copy_variables(r, &hash, ctx, lr); ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_shmtx_unlock(&ctx->shpool->mutex); continue; } ngx_shmtx_unlock(&ctx->shpool->mutex); if (rc == NGX_BUSY || rc == NGX_ERROR) { break; } /* NGX_AGAIN or NGX_OK */ if (delay_excess < excess) { delay_excess = excess; nodelay = limit_req2[i].nodelay; delay_postion = i; } } r->main->limit_req_set = 1; if (rc == NGX_BUSY || rc == NGX_ERROR) { if (rc == NGX_BUSY) { ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, excess: %ui.%03ui by zone \"%V\"", excess / 1000, excess % 1000, &limit_req2[i].shm_zone->shm.name); } if (rc == NGX_ERROR || limit_req2[i].forbid_action.len == 0) { return NGX_HTTP_SERVICE_UNAVAILABLE; } else if (limit_req2[i].forbid_action.data[0] == '@') { ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, forbid_action is %V", &limit_req2[i].forbid_action); (void) ngx_http_named_location(r, &limit_req2[i].forbid_action); } else { ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, forbid_action is %V", &limit_req2[i].forbid_action); (void) ngx_http_internal_redirect(r, &limit_req2[i].forbid_action, &r->args); } ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } /* rc = NGX_AGAIN */ if (delay_excess != 0) { if (nodelay) { return NGX_DECLINED; } delay_time = (ngx_msec_t) delay_excess * 1000 / ctx->rate; ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, "delaying request," "excess: %ui.%03ui, by zone \"%V\", delay \"%ui\" s", delay_excess / 1000, delay_excess % 1000, &limit_req2[delay_postion].shm_zone->shm.name, delay_time); if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->read_event_handler = ngx_http_test_reading; r->write_event_handler = ngx_http_limit_req2_delay; ngx_add_timer(r->connection->write, delay_time); return NGX_AGAIN; } /* rc == NGX_OK or rc == NGX_DECLINED */ return NGX_DECLINED; }
void ngx_http_perl_handle_request(ngx_http_request_t *r) { SV *sub; ngx_int_t rc; ngx_str_t uri, args, *handler; ngx_http_perl_ctx_t *ctx; ngx_http_perl_loc_conf_t *plcf; ngx_http_perl_main_conf_t *pmcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler"); ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); if (ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t)); if (ctx == NULL) { ngx_http_finalize_request(r, NGX_ERROR); return; } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); } pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); { dTHXa(pmcf->perl); PERL_SET_CONTEXT(pmcf->perl); if (ctx->next == NULL) { plcf = ngx_http_get_module_loc_conf(r, ngx_http_perl_module); sub = plcf->sub; handler = &plcf->handler; } else { sub = ctx->next; handler = &ngx_null_name; ctx->next = NULL; } rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler, NULL); } if (rc == NGX_DONE) { return; } if (rc > 600) { rc = NGX_OK; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler done: %i", rc); if (ctx->redirect_uri.len) { uri = ctx->redirect_uri; args = ctx->redirect_args; } else { uri.len = 0; } ctx->filename.data = NULL; ctx->redirect_uri.len = 0; if (ctx->done || ctx->next) { return; } if (uri.len) { ngx_http_internal_redirect(r, &uri, &args); return; } if (rc == NGX_OK || rc == NGX_HTTP_OK) { ngx_http_send_special(r, NGX_HTTP_LAST); ctx->done = 1; } ngx_http_finalize_request(r, rc); }
static ngx_int_t ngx_http_limit_req_handler(ngx_http_request_t *r) { size_t len; uint32_t hash; ngx_int_t rc; ngx_uint_t n, excess; ngx_msec_t delay; ngx_http_limit_req_ctx_t *ctx; ngx_http_limit_req_conf_t *lrcf; ngx_http_limit_req_limit_t *limit, *limits; if (r->main->limit_req_set) { return NGX_DECLINED; } lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module); limits = lrcf->limits.elts; /* filter whitelist */ if (ngx_http_limit_req_ip_filter(r, lrcf) == NGX_OK) { return NGX_DECLINED; } excess = 0; rc = NGX_DECLINED; #if (NGX_SUPPRESS_WARN) limit = NULL; #endif for (n = 0; n < lrcf->limits.nelts; n++) { limit = &limits[n]; ctx = limit->shm_zone->data; ngx_crc32_init(hash); len = ngx_http_limit_req_copy_variables(r, &hash, ctx, NULL); if (len == 0) { continue; } ngx_crc32_final(hash); ngx_shmtx_lock(&ctx->shpool->mutex); rc = ngx_http_limit_req_lookup(r, limit, hash, len, &excess, (n == lrcf->limits.nelts - 1)); ngx_shmtx_unlock(&ctx->shpool->mutex); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limits[%ui]: %i %ui.%03ui", n, rc, excess / 1000, excess % 1000); if (rc != NGX_AGAIN) { break; } } if (rc == NGX_DECLINED) { return NGX_DECLINED; } r->main->limit_req_set = 1; if (rc == NGX_BUSY || rc == NGX_ERROR) { if (rc == NGX_BUSY) { ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, excess: %ui.%03ui by zone \"%V\"", excess / 1000, excess % 1000, &limit->shm_zone->shm.name); } while (n--) { ctx = limits[n].shm_zone->data; if (ctx->node == NULL) { continue; } ngx_shmtx_lock(&ctx->shpool->mutex); ctx->node->count--; ngx_shmtx_unlock(&ctx->shpool->mutex); ctx->node = NULL; } if (rc == NGX_ERROR || limit->forbid_action.len == 0) { return lrcf->status_code; } else if (limit->forbid_action.data[0] == '@') { ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, forbid_action is %V", &limit->forbid_action); (void) ngx_http_named_location(r, &limit->forbid_action); } else { ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, forbid_action is %V", &limit->forbid_action); (void) ngx_http_internal_redirect(r, &limit->forbid_action, &r->args); } ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } /* rc == NGX_AGAIN || rc == NGX_OK */ if (rc == NGX_AGAIN) { excess = 0; } delay = ngx_http_limit_req_account(limits, n, &excess, &limit); if (!delay) { return NGX_DECLINED; } ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, "delaying request, excess: %ui.%03ui, by zone \"%V\"", excess / 1000, excess % 1000, &limit->shm_zone->shm.name); if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->read_event_handler = ngx_http_test_reading; r->write_event_handler = ngx_http_limit_req_delay; ngx_add_timer(r->connection->write, delay); return NGX_AGAIN; }
ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int nret) { int rv; int cc_ref; lua_State *cc; const char *err, *msg; ngx_int_t rc; /* set Lua VM panic handler */ lua_atpanic(L, ngx_http_lua_atpanic); dd("ctx = %p", ctx); NGX_LUA_EXCEPTION_TRY { cc = ctx->cc; cc_ref = ctx->cc_ref; /* XXX: work-around to nginx regex subsystem */ ngx_http_lua_pcre_malloc_init(r->pool); /* run code */ rv = lua_resume(cc, nret); /* XXX: work-around to nginx regex subsystem */ ngx_http_lua_pcre_malloc_done(); dd("lua resume returns %d", (int) rv); switch (rv) { case LUA_YIELD: /* yielded, let event handler do the rest job */ /* FIXME: add io cmd dispatcher here */ dd("lua coroutine yielded"); #if 0 ngx_http_lua_dump_postponed(r); #endif lua_settop(cc, 0); return NGX_AGAIN; case 0: dd("normal end %.*s", (int) r->uri.len, r->uri.data); #if 0 ngx_http_lua_dump_postponed(r); #endif ngx_http_lua_del_thread(r, L, cc_ref, 0); ctx->cc_ref = LUA_NOREF; if (ctx->cleanup) { dd("cleaning up cleanup"); *ctx->cleanup = NULL; ctx->cleanup = NULL; } if (ctx->entered_content_phase) { rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } } return NGX_OK; case LUA_ERRRUN: err = "runtime error"; break; case LUA_ERRSYNTAX: err = "syntax error"; break; case LUA_ERRMEM: err = "memory allocation error"; break; case LUA_ERRERR: err = "error handler error"; break; default: err = "unknown error"; break; } if (lua_isstring(cc, -1)) { dd("user custom error msg"); msg = lua_tostring(cc, -1); } else { if (lua_isnil(cc, -1)) { if (ctx->exited) { dd("run here...exiting... %d", (int) ctx->exit_code); ngx_http_lua_del_thread(r, L, cc_ref, 0); ctx->cc_ref = LUA_NOREF; if (ctx->cleanup) { *ctx->cleanup = NULL; ctx->cleanup = NULL; } if ((ctx->exit_code == NGX_OK && ctx->entered_content_phase) || (ctx->exit_code >= NGX_HTTP_OK && ctx->exit_code < NGX_HTTP_SPECIAL_RESPONSE)) { rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } } return ctx->exit_code; } if (ctx->exec_uri.len) { ngx_http_lua_del_thread(r, L, cc_ref, 0); ctx->cc_ref = LUA_NOREF; if (ctx->cleanup) { *ctx->cleanup = NULL; ctx->cleanup = NULL; } if (ctx->exec_uri.data[0] == '@') { if (ctx->exec_args.len > 0) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "query strings %V ignored when exec'ing " "named location %V", &ctx->exec_args, &ctx->exec_uri); } r->write_event_handler = ngx_http_request_empty_handler; rc = ngx_http_named_location(r, &ctx->exec_uri); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } if (! ctx->entered_content_phase && r != r->connection->data) { /* XXX ensure the main request ref count * is decreased because the current * request will be quit */ r->main->count--; } return NGX_DONE; } dd("internal redirect to %.*s", (int) ctx->exec_uri.len, ctx->exec_uri.data); /* resume the write event handler */ r->write_event_handler = ngx_http_request_empty_handler; rc = ngx_http_internal_redirect(r, &ctx->exec_uri, &ctx->exec_args); dd("internal redirect returned %d when in content phase? " "%d", (int) rc, ctx->entered_content_phase); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } dd("XXYY HERE %d\n", (int) r->main->count); if (! ctx->entered_content_phase && r != r->connection->data) { /* XXX ensure the main request ref count * is decreased because the current * request will be quit */ r->main->count--; } return NGX_DONE; } } msg = "unknown reason"; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: %s: %s", err, msg); ngx_http_lua_del_thread(r, L, cc_ref, 0); ctx->cc_ref = LUA_NOREF; if (ctx->cleanup) { *ctx->cleanup = NULL; ctx->cleanup = NULL; } dd("headers sent? %d", ctx->headers_sent ? 1 : 0); return ctx->headers_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; } NGX_LUA_EXCEPTION_CATCH { dd("nginx execution restored"); } return NGX_ERROR; }
// like Nginx rewrite keywords // used like this: // => http code 3xx location in browser // => internal redirection in nginx static mrb_value ngx_mrb_redirect(mrb_state *mrb, mrb_value self) { int argc; u_char *str; ngx_buf_t *b; ngx_int_t rc; mrb_value uri, code; ngx_str_t ns; ngx_http_mruby_ctx_t *ctx; ngx_table_elt_t *location; ngx_mrb_rputs_chain_list_t *chain; ngx_http_request_t *r = ngx_mrb_get_request(); argc = mrb_get_args(mrb, "o|oo", &uri, &code); // get status code from args if (argc == 2) { rc = mrb_fixnum(code); } else { rc = NGX_HTTP_MOVED_TEMPORARILY; } // get redirect uri from args if (mrb_type(uri) != MRB_TT_STRING) { uri = mrb_funcall(mrb, uri, "to_s", 0, NULL); } // save location uri to ns ns.data = (u_char *)RSTRING_PTR(uri); ns.len = ngx_strlen(ns.data); if (ns.len == 0) { return mrb_nil_value(); } // if uri start with scheme prefix // return 3xx for redirect // else generate a internal redirection and response to raw request // request.path is not changed if (ngx_strncmp(ns.data, "http://", sizeof("http://") - 1) == 0 || ngx_strncmp(ns.data, "https://", sizeof("https://") - 1) == 0 || ngx_strncmp(ns.data, "$scheme", sizeof("$scheme") - 1) == 0) { ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module); if (ctx == NULL) { ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "get mruby context failed." ); } if (ctx->rputs_chain == NULL) { chain = ngx_pcalloc(r->pool, sizeof(ngx_mrb_rputs_chain_list_t)); chain->out = ngx_alloc_chain_link(r->pool); chain->last = &chain->out; } else { chain = ctx->rputs_chain; (*chain->last)->next = ngx_alloc_chain_link(r->pool); chain->last = &(*chain->last)->next; } // allocate space for body b = ngx_calloc_buf(r->pool); (*chain->last)->buf = b; (*chain->last)->next = NULL; str = ngx_pstrdup(r->pool, &ns); str[ns.len] = '\0'; (*chain->last)->buf->pos = str; (*chain->last)->buf->last = str+ns.len; (*chain->last)->buf->memory = 1; ctx->rputs_chain = chain; ngx_http_set_ctx(r, ctx, ngx_http_mruby_module); if (r->headers_out.content_length_n == -1) { r->headers_out.content_length_n += ns.len + 1; } else { r->headers_out.content_length_n += ns.len; } // build redirect location location = ngx_list_push(&r->headers_out.headers); location->hash = 1; ngx_str_set(&location->key, "Location"); location->value = ns; location->lowcase_key = ngx_pnalloc(r->pool, location->value.len); ngx_strlow(location->lowcase_key, location->value.data, location->value.len); // set location and response code for hreaders r->headers_out.location = location; r->headers_out.status = rc; ngx_http_send_header(r); ngx_http_output_filter(r, chain->out); } else { ngx_http_internal_redirect(r, &ns, &r->args); } return self; }