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; }
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; }
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); }
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; }
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; }
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_jstore_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_core_main_conf_t *cmcf; ngx_http_jstore_loc_conf_t *jlcf; ngx_http_jstore_ctx_t *ctx; ngx_http_request_t *sr = NULL; ngx_http_upstream_t *u; ngx_chain_t *cl, *jchain; ngx_buf_t *buf, *jbuf; ngx_int_t rc, rc_next; ssize_t n; off_t clen; off_t content_length = r->headers_out.content_length_n; if(in == NULL) { goto pipe; } /* skip jstore's subrequest's response body */ if(ngx_http_jstore_is_subrequest(r)) { for(cl = in; cl; cl = cl->next) { buf = cl->buf; buf->file_pos = buf->file_last; buf->pos = buf->last; buf->sync = 1; buf->memory = 0; buf->in_file = 0; } return NGX_OK; } ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "jstore body filter"); ctx = ngx_http_get_module_ctx(r, ngx_http_jstore_filter_module); if(ctx == NULL || !ctx->store_enable || ctx->subr_sent) { goto pipe; } for(cl = in; cl; cl = cl->next) { buf = cl->buf; if(ngx_buf_special(buf)) { continue; } clen = ngx_buf_size(buf); if(content_length >= 0 && clen + ctx->copied_length > content_length) { ngx_log_error(NGX_LOG_ERR,r->connection->log, 0, "body(%d) is larger than Content-Length(%d)", clen + ctx->copied_length, content_length); goto fail; } /* alloc new buffer, and link it */ jbuf = ngx_create_temp_buf(r->pool, clen); if(jbuf == NULL) { goto fail; } jchain = ngx_alloc_chain_link(r->pool); if(jchain == NULL) { goto pipe; } if(ctx->buf_chain_head == NULL) { ctx->buf_chain_head = jchain; } else { ctx->buf_chain_tail->next = jchain; } ctx->buf_chain_tail = jchain; jchain->buf = jbuf; jchain->next = NULL; /* copy content */ if(buf->in_file && buf->file){ n = ngx_read_file(buf->file, jbuf->start, clen, buf->file_pos); if(n < 0){ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_read_file failed! ret: %d", n); goto fail; } buf->file->offset -= n; } else { ngx_memcpy(jbuf->start, buf->pos, clen); } jbuf->last += clen; ctx->copied_length += clen; } /* upstream done? buffering and non-buffering */ u = r->upstream; if(!(u->pipe && u->pipe->upstream_done) && u->length != 0) { goto pipe; } /* should not happen */ if(content_length >= 0 && ctx->copied_length != content_length) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "JSTORE bug!!"); goto fail; } /* now we have collect all response, so send a subrequest to store it */ /* send the main request first */ rc_next = ngx_http_next_body_filter(r, in); ctx->subr_sent = 1; /* create subrequest */ rc = ngx_http_subrequest(r, &(r->uri), &(r->args), &sr, NULL, 0); if(rc == NGX_ERROR) { goto fail; } /* method */ sr->method = NGX_HTTP_POST; sr->method_name.data = JSUBR_METHOD_STR; sr->method_name.len = JSUBR_METHOD_LEN; /* request headers */ sr->headers_in.headers = u->headers_in.headers; sr->headers_in.content_length_n = ctx->copied_length; /* $proxy_internal_body_length is cacheable, and the subrequest * has different content-lenght with main request, so we have * to clear the variables. */ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); sr->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts * sizeof(ngx_http_variable_value_t)); /* request body */ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if(sr->request_body == NULL) { goto fail; } sr->request_body->bufs = ctx->buf_chain_head; /* ngx_http_subrequest() and ngx_http_named_location() both * increase @r->count, but we want it to be incresed once * actually. */ r->count--; /* jump to the named location */ ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "jstore: named-location"); jlcf = ngx_http_get_module_loc_conf(r, ngx_http_jstore_filter_module); ngx_http_named_location(sr, &jlcf->target); return rc_next; fail: ngx_http_set_ctx(r, NULL, ngx_http_jstore_filter_module); pipe: return ngx_http_next_body_filter(r, in); }
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); }
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; }