static ngx_int_t ngx_extra_var_original_uri(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { ngx_str_t uri, args; u_char *src, *dst, *p; ngx_uint_t flags; uri = r->unparsed_uri; ngx_str_null(&args); flags = 0; if (NGX_OK != ngx_http_parse_unsafe_uri(r, &uri, &args, &flags)) { v->not_found = 1; return NGX_OK; } p = ngx_pnalloc(r->pool, uri.len); if (p == NULL) { return NGX_ERROR; } src = uri.data; dst = p; ngx_unescape_uri(&dst, &src, uri.len, 0); v->len = dst - p; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; v->data = p; return NGX_OK; }
ngx_int_t ngx_http_echo_exec_echo_location_async(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_request_t *sr; /* subrequest object */ ngx_str_t *computed_arg_elts; ngx_str_t location; ngx_str_t *url_args; ngx_str_t args; ngx_uint_t flags = 0; dd_enter(); computed_arg_elts = computed_args->elts; location = computed_arg_elts[0]; if (location.len == 0) { return NGX_ERROR; } if (computed_args->nelts > 1) { url_args = &computed_arg_elts[1]; } else { url_args = NULL; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "echo_location_async sees unsafe uri: \"%V\"", &location); return NGX_ERROR; } if (args.len > 0 && url_args == NULL) { url_args = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } rc = ngx_http_subrequest(r, &location, url_args, &sr, NULL, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr); if (rc != NGX_OK) { return NGX_ERROR; } return NGX_OK; }
ngx_int_t ngx_http_echo_exec_echo_location_async(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_request_t *sr; /* subrequest object */ ngx_str_t *computed_arg_elts; ngx_str_t location; ngx_str_t *url_args; ngx_str_t args; ngx_uint_t flags; computed_arg_elts = computed_args->elts; location = computed_arg_elts[0]; if (location.len == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (computed_args->nelts > 1) { url_args = &computed_arg_elts[1]; } else { url_args = NULL; } dd("location: %s", location.data); dd("location args: %s", (char*) (url_args ? url_args->data : (u_char*)"NULL")); args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (args.len > 0 && url_args == NULL) { url_args = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (r->header_only || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } rc = ngx_http_subrequest(r, &location, url_args, &sr, NULL, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr); if (rc != NGX_OK) { return rc; } return NGX_OK; }
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); }
ngx_int_t ngx_http_echo_exec_echo_subrequest(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_request_t *sr; /* subrequest object */ ngx_http_post_subrequest_t *psr; ngx_http_echo_subrequest_t *parsed_sr; ngx_str_t args; ngx_uint_t flags; rc = ngx_http_echo_parse_subrequest_spec(r, computed_args, &parsed_sr); if (rc != NGX_OK) { return rc; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, parsed_sr->location, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (args.len > 0 && parsed_sr->query_string == NULL) { parsed_sr->query_string = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (r->header_only || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } psr->handler = ngx_http_echo_post_subrequest; psr->data = ctx; rc = ngx_http_subrequest(r, parsed_sr->location, parsed_sr->query_string, &sr, psr, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr, parsed_sr); if (rc != NGX_OK) { return rc; } return NGX_OK; }
ngx_int_t ngx_http_echo_exec_echo_subrequest_async(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_echo_subrequest_t *parsed_sr; ngx_http_request_t *sr; /* subrequest object */ ngx_str_t args; ngx_uint_t flags; rc = ngx_http_echo_parse_subrequest_spec(r, computed_args, &parsed_sr); if (rc != NGX_OK) { return rc; } dd("location: %s", parsed_sr->location->data); dd("location args: %s", (char*) (parsed_sr->query_string ? parsed_sr->query_string->data : (u_char*)"NULL")); args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, parsed_sr->location, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (args.len > 0 && parsed_sr->query_string == NULL) { parsed_sr->query_string = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (r->header_only || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } rc = ngx_http_subrequest(r, parsed_sr->location, parsed_sr->query_string, &sr, NULL, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr, parsed_sr); if (rc != NGX_OK) { return rc; } return NGX_OK; }
static ngx_int_t ngx_http_concat_add_path(ngx_http_request_t *r, ngx_array_t *uris, size_t max, ngx_str_t *path, u_char *p, u_char *v) { u_char *d; ngx_str_t *uri, args; ngx_uint_t flags; if (p == v) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent zero concat filename"); return NGX_HTTP_BAD_REQUEST; } if (uris->nelts >= max) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent too many concat filenames"); return NGX_HTTP_BAD_REQUEST; } uri = ngx_array_push(uris); if (uri == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } uri->len = path->len + p - v; uri->data = ngx_pnalloc(r->pool, uri->len + 1); /* + '\0' */ if (uri->data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } d = ngx_cpymem(uri->data, path->data, path->len); d = ngx_cpymem(d, v, p - v); *d = '\0'; args.len = 0; args.data = NULL; flags = NGX_HTTP_LOG_UNSAFE; if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { return NGX_HTTP_BAD_REQUEST; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http concat add file: \"%s\"", uri->data); return NGX_OK; }
static int ngx_http_lua_ngx_location_capture_multi(lua_State *L) { ngx_http_request_t *r; ngx_http_request_t *sr; /* subrequest object */ ngx_http_post_subrequest_t *psr; ngx_http_lua_ctx_t *sr_ctx; ngx_http_lua_ctx_t *ctx; ngx_array_t *extra_vars; ngx_str_t uri; ngx_str_t args; ngx_str_t extra_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; size_t nargs; int rc; int n; ngx_uint_t method; ngx_http_request_body_t *body; int type; ngx_buf_t *b; unsigned vars_action; ngx_uint_t nsubreqs; ngx_uint_t index; size_t sr_statuses_len; size_t sr_headers_len; size_t sr_bodies_len; size_t sr_flags_len; unsigned custom_ctx; ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_post_subrequest_data_t *psr_data; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "only one argument is expected, but got %d", n); } luaL_checktype(L, 1, LUA_TTABLE); nsubreqs = lua_objlen(L, 1); if (nsubreqs == 0) { return luaL_error(L, "at least one subrequest should be specified"); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); coctx = ctx->cur_co_ctx; if (coctx == NULL) { return luaL_error(L, "no co ctx found"); } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua location capture, uri:\"%V\" c:%ud", &r->uri, r->main->count); sr_statuses_len = nsubreqs * sizeof(ngx_int_t); sr_headers_len = nsubreqs * sizeof(ngx_http_headers_out_t *); sr_bodies_len = nsubreqs * sizeof(ngx_str_t); sr_flags_len = nsubreqs * sizeof(uint8_t); p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len + sr_bodies_len + sr_flags_len); if (p == NULL) { return luaL_error(L, "out of memory"); } coctx->sr_statuses = (void *) p; p += sr_statuses_len; coctx->sr_headers = (void *) p; p += sr_headers_len; coctx->sr_bodies = (void *) p; p += sr_bodies_len; coctx->sr_flags = (void *) p; coctx->nsubreqs = nsubreqs; coctx->pending_subreqs = 0; extra_vars = NULL; for (index = 0; index < nsubreqs; index++) { coctx->pending_subreqs++; lua_rawgeti(L, 1, index + 1); if (lua_isnil(L, -1)) { return luaL_error(L, "only array-like tables are allowed"); } dd("queries query: top %d", lua_gettop(L)); if (lua_type(L, -1) != LUA_TTABLE) { return luaL_error(L, "the query argument %d is not a table, " "but a %s", index, lua_typename(L, lua_type(L, -1))); } nargs = lua_objlen(L, -1); if (nargs != 1 && nargs != 2) { return luaL_error(L, "query argument %d expecting one or " "two arguments", index); } lua_rawgeti(L, 2, 1); /* queries query uri */ dd("queries query uri: %d", lua_gettop(L)); dd("first arg in first query: %s", lua_typename(L, lua_type(L, -1))); body = NULL; extra_args.data = NULL; extra_args.len = 0; if (extra_vars != NULL) { /* flush out existing elements in the array */ extra_vars->nelts = 0; } vars_action = 0; custom_ctx = 0; if (nargs == 2) { /* check out the options table */ lua_rawgeti(L, 2, 2); /* queries query uri opts */ dd("queries query uri opts: %d", lua_gettop(L)); if (lua_type(L, 4) != LUA_TTABLE) { return luaL_error(L, "expecting table as the 2nd argument for " "subrequest %d, but got %s", index, luaL_typename(L, 4)); } dd("queries query uri opts: %d", lua_gettop(L)); /* check the args option */ lua_getfield(L, 4, "args"); type = lua_type(L, -1); switch (type) { case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, -1, &extra_args); break; case LUA_TNIL: /* do nothing */ break; case LUA_TNUMBER: case LUA_TSTRING: extra_args.data = (u_char *) lua_tolstring(L, -1, &len); extra_args.len = len; break; default: return luaL_error(L, "Bad args option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the vars option */ lua_getfield(L, 4, "vars"); switch (lua_type(L, -1)) { case LUA_TTABLE: ngx_http_lua_process_vars_option(r, L, -1, &extra_vars); dd("post process vars top: %d", lua_gettop(L)); break; case LUA_TNIL: /* do nothing */ break; default: return luaL_error(L, "Bad vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the share_all_vars option */ lua_getfield(L, 4, "share_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_SHARE_ALL_VARS; } break; default: return luaL_error(L, "Bad share_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the copy_all_vars option */ lua_getfield(L, 4, "copy_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_COPY_ALL_VARS; } break; default: return luaL_error(L, "Bad copy_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "method" option */ lua_getfield(L, 4, "method"); type = lua_type(L, -1); if (type == LUA_TNIL) { method = NGX_HTTP_GET; } else { if (type != LUA_TNUMBER) { return luaL_error(L, "Bad http request method"); } method = (ngx_uint_t) lua_tonumber(L, -1); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "ctx" option */ lua_getfield(L, 4, "ctx"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TTABLE) { return luaL_error(L, "Bad ctx option value type %s, " "expected a Lua table", lua_typename(L, type)); } custom_ctx = 1; } else { lua_pop(L, 1); } dd("queries query uri opts ctx?: %d", lua_gettop(L)); /* check the "body" option */ lua_getfield(L, 4, "body"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TSTRING && type != LUA_TNUMBER) { return luaL_error(L, "Bad http request body"); } body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (body == NULL) { return luaL_error(L, "out of memory"); } q = (u_char *) lua_tolstring(L, -1, &len); dd("request body: [%.*s]", (int) len, q); if (len) { b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return luaL_error(L, "out of memory"); } b->last = ngx_copy(b->last, q, len); body->bufs = ngx_alloc_chain_link(r->pool); if (body->bufs == NULL) { return luaL_error(L, "out of memory"); } body->bufs->buf = b; body->bufs->next = NULL; body->buf = b; } } lua_pop(L, 1); /* pop the body */ /* stack: queries query uri opts ctx? */ lua_remove(L, 4); /* stack: queries query uri ctx? */ dd("queries query uri ctx?: %d", lua_gettop(L)); } else { method = NGX_HTTP_GET; } /* stack: queries query uri ctx? */ p = (u_char *) luaL_checklstring(L, 3, &len); uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "memory allocation error"); } ngx_memcpy(uri.data, p, len); uri.len = len; args.data = NULL; args.len = 0; flags = 0; rc = ngx_http_parse_unsafe_uri(r, &uri, &args, &flags); if (rc != NGX_OK) { dd("rc = %d", (int) rc); return luaL_error(L, "unsafe uri in argument #1: %s", p); } if (args.len == 0) { if (extra_args.len) { p = ngx_palloc(r->pool, extra_args.len); if (p == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(p, extra_args.data, extra_args.len); args.data = p; args.len = extra_args.len; } } else if (extra_args.len) { /* concatenate the two parts of args together */ len = args.len + (sizeof("&") - 1) + extra_args.len; p = ngx_palloc(r->pool, len); if (p == NULL) { return luaL_error(L, "out of memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, extra_args.data, extra_args.len); args.data = p; args.len = len; } p = ngx_pnalloc(r->pool, sizeof(ngx_http_post_subrequest_t) + sizeof(ngx_http_lua_ctx_t) + sizeof(ngx_http_lua_post_subrequest_data_t)); if (p == NULL) { return luaL_error(L, "out of memory"); } psr = (ngx_http_post_subrequest_t *) p; p += sizeof(ngx_http_post_subrequest_t); sr_ctx = (ngx_http_lua_ctx_t *) p; p += sizeof(ngx_http_lua_ctx_t); psr_data = (ngx_http_lua_post_subrequest_data_t *) p; ngx_memzero(sr_ctx, sizeof(ngx_http_lua_ctx_t)); /* set by ngx_memzero: * sr_ctx->run_post_subrequest = 0 * sr_ctx->free = NULL * sr_ctx->body = NULL */ ngx_http_lua_init_ctx(sr_ctx); sr_ctx->capture = 1; sr_ctx->index = index; sr_ctx->last_body = &sr_ctx->body; psr_data->ctx = sr_ctx; psr_data->pr_co_ctx = coctx; psr->handler = ngx_http_lua_post_subrequest; psr->data = psr_data; rc = ngx_http_lua_subrequest(r, &uri, &args, &sr, psr, 0); if (rc != NGX_OK) { return luaL_error(L, "failed to issue subrequest: %d", (int) rc); } ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module); rc = ngx_http_lua_adjust_subrequest(sr, method, body, vars_action, extra_vars); if (rc != NGX_OK) { ngx_http_lua_cancel_subreq(sr); return luaL_error(L, "failed to adjust the subrequest: %d", (int) rc); } dd("queries query uri opts ctx? %d", lua_gettop(L)); /* stack: queries query uri ctx? */ if (custom_ctx) { ngx_http_lua_ngx_set_ctx_helper(L, sr, sr_ctx, -1); lua_pop(L, 3); } else { lua_pop(L, 2); } /* stack: queries */ } if (extra_vars) { ngx_array_destroy(extra_vars); } ctx->no_abort = 1; return lua_yield(L, 0); }
static ngx_int_t ngx_http_eval_handler(ngx_http_request_t *r) { size_t loc_len; ngx_str_t args; ngx_str_t subrequest_uri; ngx_uint_t flags; ngx_http_core_loc_conf_t *clcf; ngx_http_eval_loc_conf_t *ecf; ngx_http_eval_ctx_t *ctx; ngx_http_request_t *sr; ngx_int_t rc; ngx_http_post_subrequest_t *psr; u_char *p; if(r != r->main && ngx_memn2cmp(r->uri.data, "/eval_", r->uri.len, 6 - 1) == 0) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); loc_len = r->valid_location ? clcf->name.len : 0; if(r->uri.len != loc_len) { r->uri.data += loc_len; r->uri.len -= loc_len; } else { r->uri.len = 1; } } ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module); if(ecf->variables == NULL || !ecf->variables->nelts) { return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module); if(ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->base_conf = ecf; ngx_http_set_ctx(r, ctx, ngx_http_eval_module); } if(ctx->done) { if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) { return NGX_DECLINED; } return ctx->status; } if(ctx->in_progress) { return NGX_AGAIN; } psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } if(ngx_http_eval_init_variables(r, ctx, ecf) != NGX_OK) { return NGX_ERROR; } args.len = 0; args.data = NULL; flags = 0; subrequest_uri.len = ecf->eval_location.len + r->uri.len; p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len); if(p == NULL) { return NGX_ERROR; } p = ngx_copy(p, ecf->eval_location.data, ecf->eval_location.len); p = ngx_copy(p, r->uri.data, r->uri.len); if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) { return NGX_ERROR; } psr->handler = ngx_http_eval_post_subrequest_handler; psr->data = ctx; flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY|NGX_HTTP_SUBREQUEST_WAITED; rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags); if (rc == NGX_ERROR || rc == NGX_DONE) { return rc; } sr->discard_body = 1; ctx->in_progress = 1; /* * Wait for subrequest to complete */ return NGX_AGAIN; }
static ngx_int_t ngx_http_srcache_fetch_subrequest(ngx_http_request_t *r, ngx_http_srcache_loc_conf_t *conf, ngx_http_srcache_ctx_t *ctx) { ngx_http_srcache_ctx_t *sr_ctx; ngx_http_post_subrequest_t *psr; ngx_str_t args; ngx_uint_t flags = 0; ngx_http_request_t *sr; ngx_int_t rc; ngx_http_srcache_parsed_request_t *parsed_sr; dd_enter(); parsed_sr = ngx_palloc(r->pool, sizeof(ngx_http_srcache_parsed_request_t)); if (parsed_sr == NULL) { return NGX_ERROR; } if (conf->fetch == NULL) { return NGX_ERROR; } parsed_sr->method = conf->fetch->method; parsed_sr->method_name = conf->fetch->method_name; parsed_sr->request_body = NULL; parsed_sr->content_length_n = -1; if (ngx_http_complex_value(r, &conf->fetch->location, &parsed_sr->location) != NGX_OK) { return NGX_ERROR; } if (parsed_sr->location.len == 0) { return NGX_ERROR; } if (ngx_http_complex_value(r, &conf->fetch->args, &parsed_sr->args) != NGX_OK) { return NGX_ERROR; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &parsed_sr->location, &args, &flags) != NGX_OK) { return NGX_ERROR; } if (args.len > 0 && parsed_sr->args.len == 0) { parsed_sr->args = args; } sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_ctx_t)); if (sr_ctx == NULL) { return NGX_ERROR; } sr_ctx->in_fetch_subrequest = 1; psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } psr->handler = ngx_http_srcache_fetch_post_subrequest; psr->data = sr_ctx; dd("firing the fetch subrequest"); dd("fetch location: %.*s", (int) parsed_sr->location.len, parsed_sr->location.data); dd("fetch args: %.*s", (int) parsed_sr->args.len, parsed_sr->args.data); rc = ngx_http_subrequest(r, &parsed_sr->location, &parsed_sr->args, &sr, psr, flags); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_srcache_adjust_subrequest(sr, parsed_sr); if (rc != NGX_OK) { return NGX_ERROR; } ngx_http_set_ctx(sr, sr_ctx, ngx_http_srcache_filter_module); ctx->issued_fetch_subrequest = 1; return NGX_OK; }
static ngx_int_t ngx_http_eval_handler(ngx_http_request_t *r) { size_t loc_len; ngx_str_t args; ngx_str_t subrequest_uri; ngx_uint_t flags; ngx_http_core_loc_conf_t *clcf; ngx_http_eval_loc_conf_t *ecf; ngx_http_eval_ctx_t *ctx; ngx_http_request_t *sr; ngx_int_t rc; ngx_http_post_subrequest_t *psr; ngx_http_eval_block_t *block; u_char *p; if(r != r->main && r->uri.len > 6 && r->uri.data[0] == '/' && r->uri.data[1] == 'e' && r->uri.data[2] == 'v' && r->uri.data[3] == 'a' && r->uri.data[4] == 'l' && r->uri.data[5] == '_') { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); loc_len = r->valid_location ? clcf->name.len : 0; if(r->uri.len != loc_len) { r->uri.data += loc_len; r->uri.len -= loc_len; } else { r->uri.len = 1; } } ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module); if(ecf->blocks == NULL || !ecf->blocks->nelts) { return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module); if(ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->base_conf = ecf; ctx->current_block = ecf->blocks->elts; ctx->last_block = ctx->current_block + ecf->blocks->nelts - 1; ngx_http_set_ctx(r, ctx, ngx_http_eval_module); } if(ctx->done) { ctx->in_progress = 0; if(ctx->current_block == ctx->last_block) { if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) { return NGX_DECLINED; } return ctx->status; } ctx->current_block++; } if(ctx->in_progress) { #if defined nginx_version && nginx_version >= 8042 return NGX_DONE; #else return NGX_AGAIN; #endif } /* * Advance to block which has at least one variable */ while(ctx->current_block->variables == NULL || ctx->current_block->variables->nelts == 0) { if(ctx->current_block == ctx->last_block) { return NGX_DECLINED; } ctx->current_block++; } block = ctx->current_block; psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } if(ngx_http_eval_init_variables(r, ctx, block) != NGX_OK) { return NGX_ERROR; } args.len = r->args.len; args.data = r->args.data; flags = 0; subrequest_uri.len = block->eval_location.len + r->uri.len; p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len); if(p == NULL) { return NGX_ERROR; } p = ngx_copy(p, block->eval_location.data, block->eval_location.len); p = ngx_copy(p, r->uri.data, r->uri.len); if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) { return NGX_ERROR; } psr->handler = ngx_http_eval_post_subrequest_handler; psr->data = ctx; flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY|NGX_HTTP_SUBREQUEST_WAITED; rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags); if (rc == NGX_ERROR || rc == NGX_DONE) { return rc; } /* * create a fake request body instead of discarding the real one * in order to avoid attempts to read it */ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (sr->request_body == NULL) { return NGX_ERROR; } ctx->in_progress = 1; ctx->done = 0; /* * Wait for subrequest to complete */ #if defined nginx_version && nginx_version >= 8042 return NGX_DONE; #else return NGX_AGAIN; #endif }
static int ngx_http_lua_ngx_exec(lua_State *L) { int n; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_str_t uri; ngx_str_t args, user_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; const char *msg; n = lua_gettop(L); if (n != 1 && n != 2) { return luaL_error(L, "expecting one or two arguments, but got %d", n); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request object found"); } args.data = NULL; args.len = 0; /* read the 1st argument (uri) */ p = (u_char *) luaL_checklstring(L, 1, &len); if (len == 0) { return luaL_error(L, "The uri argument is empty"); } uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(uri.data, p, len); uri.len = len; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); ngx_http_lua_check_if_abortable(L, ctx); if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (n == 2) { /* read the 2nd argument (args) */ dd("args type: %s", luaL_typename(L, 2)); switch (lua_type(L, 2)) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) lua_tolstring(L, 2, &len); user_args.data = ngx_palloc(r->pool, len); if (user_args.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(user_args.data, p, len); user_args.len = len; break; case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, 2, &user_args); dd("user_args: %.*s", (int) user_args.len, user_args.data); break; case LUA_TNIL: user_args.data = NULL; user_args.len = 0; break; default: msg = lua_pushfstring(L, "string, number, or table expected, " "but got %s", luaL_typename(L, 2)); return luaL_argerror(L, 2, msg); } } else { user_args.data = NULL; user_args.len = 0; } if (user_args.len) { if (args.len == 0) { args = user_args; } else { p = ngx_palloc(r->pool, args.len + user_args.len + 1); if (p == NULL) { return luaL_error(L, "out of memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, user_args.data, user_args.len); args.data = p; args.len += user_args.len + 1; } } if (ctx->headers_sent) { return luaL_error(L, "attempt to call ngx.exec after " "sending out response headers"); } ctx->exec_uri = uri; ctx->exec_args = args; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exec \"%V?%V\"", &ctx->exec_uri, &ctx->exec_args); return lua_yield(L, 0); }
ngx_int_t ngx_http_echo_exec_echo_location(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_request_t *sr; /* subrequest object */ ngx_str_t *computed_arg_elts; ngx_str_t location; ngx_str_t *url_args; ngx_http_post_subrequest_t *psr; ngx_str_t args; ngx_uint_t flags = 0; ngx_http_echo_ctx_t *sr_ctx; computed_arg_elts = computed_args->elts; location = computed_arg_elts[0]; if (location.len == 0) { return NGX_ERROR; } if (computed_args->nelts > 1) { url_args = &computed_arg_elts[1]; } else { url_args = NULL; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "echo_location sees unsafe uri: \"%V\"", &location); return NGX_ERROR; } if (args.len > 0 && url_args == NULL) { url_args = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } sr_ctx = ngx_http_echo_create_ctx(r); psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } psr->handler = ngx_http_echo_post_subrequest; psr->data = sr_ctx; rc = ngx_http_subrequest(r, &location, url_args, &sr, psr, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr); if (rc != NGX_OK) { return NGX_ERROR; } return NGX_AGAIN; }
static ngx_int_t ngx_http_mogilefs_put_handler(ngx_http_request_t *r) { ngx_http_mogilefs_put_ctx_t *ctx; ngx_str_t args; ngx_uint_t flags; ngx_http_request_t *sr; ngx_str_t spare_location = ngx_null_string, uri, value; ngx_int_t rc; u_char *p; ngx_http_core_loc_conf_t *clcf; ngx_http_mogilefs_loc_conf_t *mgcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "mogilefs put handler"); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); mgcf = ngx_http_get_module_loc_conf(r, ngx_http_mogilefs_module); if (clcf->handler != ngx_http_mogilefs_handler || (mgcf->location_type == NGX_MOGILEFS_MAIN && !(r->method & mgcf->methods))) { return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module); if(ctx == NULL) { ctx = ngx_palloc(r->pool, sizeof(ngx_http_mogilefs_put_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ctx->psr = NULL; ctx->state = START; ctx->status = 0; ctx->create_open_ctx = NULL; if(ngx_http_mogilefs_eval_key(r, &ctx->key) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_mogilefs_module); } if(ctx->psr == NULL) { ctx->psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (ctx->psr == NULL) { return NGX_ERROR; } } if(r->request_body == NULL) { rc = ngx_http_read_client_request_body(r, ngx_http_mogilefs_body_handler); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } return NGX_DONE; } // Still receiving body? if(r->request_body->rest) { return NGX_DONE; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "mogilefs put handler state: %ui, status: %i", ctx->state, ctx->status); if(ctx->state == CREATE_OPEN || ctx->state == FETCH || ctx->state == CREATE_CLOSE) { if(ctx->status != NGX_OK && ctx->status != NGX_HTTP_CREATED && ctx->status != NGX_HTTP_NO_CONTENT) { return (ctx->status >= NGX_HTTP_SPECIAL_RESPONSE) ? ctx->status : NGX_HTTP_INTERNAL_SERVER_ERROR; } } switch(ctx->state) { case START: spare_location = mgcf->create_open_spare_location; ctx->state = CREATE_OPEN; break; case CREATE_OPEN: spare_location = mgcf->fetch_location; ctx->state = FETCH; break; case FETCH: spare_location = mgcf->create_close_spare_location; ctx->state = CREATE_CLOSE; break; case CREATE_CLOSE: r->headers_out.content_length_n = 0; r->headers_out.status = NGX_HTTP_CREATED; r->header_only = 1; return ngx_http_send_header(r); } uri.len = spare_location.len + ctx->key.len; uri.data = ngx_palloc(r->pool, uri.len); p = ngx_cpymem(uri.data, spare_location.data, spare_location.len); p = ngx_cpymem(p, ctx->key.data, ctx->key.len); args.len = 0; args.data = NULL; flags = 0; if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { return NGX_ERROR; } ctx->psr->handler = ngx_http_mogilefs_finish_phase_handler; ctx->psr->data = ctx; flags |= NGX_HTTP_SUBREQUEST_WAITED; if(ctx->state == FETCH) { flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY; } rc = ngx_http_subrequest(r, &uri, &args, &sr, ctx->psr, flags); if (rc == NGX_ERROR) { return rc; } if(ctx->state == CREATE_CLOSE) { ngx_http_set_ctx(sr, ctx->create_open_ctx, ngx_http_mogilefs_module); value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN); if(value.data == NULL) { return NGX_ERROR; } value.len = ngx_sprintf(value.data, "%O", r->headers_in.content_length_n) - value.data; if(ngx_http_mogilefs_add_aux_param(sr, &ngx_http_mogilefs_size, &value) != NGX_OK) { return NGX_ERROR; } } /* * Nginx closes temporary file with buffered body * whenever it starts sending reponse from upstream * and it is not doing subrequest in memory. * * Since the request body in create_open subrequest is * inherited from main request, it is necessary to prevent * nginx from closing the temporary file with request body, * before it could be passed to the storage node on fetch/store * stage. * * We do it by "hiding" the request body from nginx internals. */ if(ctx->state == CREATE_OPEN) { sr->request_body = NULL; } sr->method = NGX_HTTP_PUT; sr->method_name = ngx_http_mogilefs_put_method; /* * Wait for subrequest to complete */ return NGX_DONE; }
static ngx_int_t ngx_http_srcache_store_subrequest(ngx_http_request_t *r, ngx_http_srcache_ctx_t *ctx) { ngx_http_srcache_ctx_t *sr_ctx; ngx_str_t args; ngx_uint_t flags = 0; ngx_http_request_t *sr; ngx_int_t rc; ngx_http_request_body_t *rb = NULL; ngx_http_srcache_loc_conf_t *conf; ngx_http_post_subrequest_t *psr; ngx_http_srcache_parsed_request_t *parsed_sr; dd("store subrequest"); conf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module); if (conf->store == NULL) { dd("conf store is NULL"); return NGX_ERROR; } parsed_sr = ngx_palloc(r->pool, sizeof(ngx_http_srcache_parsed_request_t)); if (parsed_sr == NULL) { return NGX_ERROR; } parsed_sr->method = conf->store->method; parsed_sr->method_name = conf->store->method_name; if (ctx->body_to_cache) { dd("found body to cache (len %d)", (int) ctx->response_length); rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return NGX_ERROR; } rb->bufs = ctx->body_to_cache; rb->buf = ctx->body_to_cache->buf; parsed_sr->request_body = rb; } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "srcache_store: no request body for the subrequest"); return NGX_ERROR; } parsed_sr->content_length_n = ctx->response_length; if (ngx_http_complex_value(r, &conf->store->location, &parsed_sr->location) != NGX_OK) { return NGX_ERROR; } if (parsed_sr->location.len == 0) { return NGX_ERROR; } if (ngx_http_complex_value(r, &conf->store->args, &parsed_sr->args) != NGX_OK) { return NGX_ERROR; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &parsed_sr->location, &args, &flags) != NGX_OK) { return NGX_ERROR; } if (args.len > 0 && parsed_sr->args.len == 0) { parsed_sr->args = args; } dd("firing the store subrequest"); dd("store location: %.*s", (int) parsed_sr->location.len, parsed_sr->location.data); dd("store args: %.*s", (int) parsed_sr->args.len, parsed_sr->args.data); sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_ctx_t)); if (sr_ctx == NULL) { return NGX_ERROR; } sr_ctx->in_store_subrequest = 1; psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } psr->handler = ngx_http_srcache_store_post_subrequest; psr->data = sr_ctx; rc = ngx_http_subrequest(r, &parsed_sr->location, &parsed_sr->args, &sr, psr, flags); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_srcache_adjust_subrequest(sr, parsed_sr); if (rc != NGX_OK) { return NGX_ERROR; } ngx_http_set_ctx(sr, sr_ctx, ngx_http_srcache_filter_module); return NGX_OK; }
int ngx_http_lua_ngx_exec(lua_State *L) { int n; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_str_t uri; ngx_str_t args, user_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; n = lua_gettop(L); if (n != 1 && n != 2) { return luaL_error(L, "expecting one or two arguments, but got %d", n); } lua_getglobal(L, GLOBALS_SYMBOL_REQUEST); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request object found"); } args.data = NULL; args.len = 0; /* read the 1st argument (uri) */ p = (u_char *) luaL_checklstring(L, 1, &len); if (len == 0) { return luaL_error(L, "The uri argument is empty"); } uri.data = ngx_palloc(r->pool, len); ngx_memcpy(uri.data, p, len); uri.len = len; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (n == 2) { /* read the 2nd argument (args) */ p = (u_char *) luaL_checklstring(L, 2, &len); user_args.data = ngx_palloc(r->pool, len); ngx_memcpy(user_args.data, p, len); user_args.len = len; } else { user_args.data = NULL; user_args.len = 0; } if (user_args.len) { if (args.len == 0) { args = user_args; } else { p = ngx_palloc(r->pool, args.len + user_args.len + 1); if (p == NULL) { return luaL_error(L, "out of memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; q = ngx_copy(q, user_args.data, user_args.len); args.data = p; args.len += user_args.len + 1; } } if (ctx->headers_sent) { return luaL_error(L, "attempt to call ngx.exec after " "sending out response headers"); } ctx->exec_uri = uri; ctx->exec_args = args; lua_pushnil(L); return lua_error(L); }
ngx_int_t ngx_http_echo_exec_echo_location(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_request_t *sr; /* subrequest object */ ngx_str_t *computed_arg_elts; ngx_str_t location; ngx_str_t *url_args; ngx_http_post_subrequest_t *psr; ngx_str_t args; ngx_uint_t flags; computed_arg_elts = computed_args->elts; location = computed_arg_elts[0]; if (location.len == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (computed_args->nelts > 1) { url_args = &computed_arg_elts[1]; } else { url_args = NULL; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (args.len > 0 && url_args == NULL) { url_args = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (r->header_only || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } psr->handler = ngx_http_echo_post_subrequest; psr->data = ctx; rc = ngx_http_subrequest(r, &location, url_args, &sr, psr, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr); if (rc != NGX_OK) { return rc; } return NGX_OK; }
static ngx_int_t ngx_http_dav_copy_move_handler(ngx_http_request_t *r) { u_char *p, *host, *last, ch; size_t len, root; ngx_err_t err; ngx_int_t rc, depth; ngx_uint_t overwrite, slash, dir, flags; ngx_str_t path, uri, duri, args; ngx_tree_ctx_t tree; ngx_copy_file_t cf; ngx_file_info_t fi; ngx_table_elt_t *dest, *over; ngx_ext_rename_file_t ext; ngx_http_dav_copy_ctx_t copy; ngx_http_dav_loc_conf_t *dlcf; if (r->headers_in.content_length_n > 0) { return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; } dest = r->headers_in.destination; if (dest == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent no \"Destination\" header"); return NGX_HTTP_BAD_REQUEST; } p = dest->value.data; /* there is always '\0' even after empty header value */ if (p[0] == '/') { last = p + dest->value.len; goto destination_done; } len = r->headers_in.server.len; if (len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent no \"Host\" header"); return NGX_HTTP_BAD_REQUEST; } #if (NGX_HTTP_SSL) if (r->connection->ssl) { if (ngx_strncmp(dest->value.data, "https://", sizeof("https://") - 1) != 0) { goto invalid_destination; } host = dest->value.data + sizeof("https://") - 1; } else #endif { if (ngx_strncmp(dest->value.data, "http://", sizeof("http://") - 1) != 0) { goto invalid_destination; } host = dest->value.data + sizeof("http://") - 1; } if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Destination\" URI \"%V\" is handled by " "different repository than the source URI", &dest->value); return NGX_HTTP_BAD_REQUEST; } last = dest->value.data + dest->value.len; for (p = host + len; p < last; p++) { if (*p == '/') { goto destination_done; } } invalid_destination: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid \"Destination\" header: \"%V\"", &dest->value); return NGX_HTTP_BAD_REQUEST; destination_done: duri.len = last - p; duri.data = p; flags = NGX_HTTP_LOG_UNSAFE; if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) { goto invalid_destination; } if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/') || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/')) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "both URI \"%V\" and \"Destination\" URI \"%V\" " "should be either collections or non-collections", &r->uri, &dest->value); return NGX_HTTP_CONFLICT; } depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH); if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) { if (r->method == NGX_HTTP_COPY) { if (depth != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Depth\" header must be 0 or infinity"); return NGX_HTTP_BAD_REQUEST; } } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Depth\" header must be infinity"); return NGX_HTTP_BAD_REQUEST; } } over = r->headers_in.overwrite; if (over) { if (over->value.len == 1) { ch = over->value.data[0]; if (ch == 'T' || ch == 't') { overwrite = 1; goto overwrite_done; } if (ch == 'F' || ch == 'f') { overwrite = 0; goto overwrite_done; } } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid \"Overwrite\" header: \"%V\"", &over->value); return NGX_HTTP_BAD_REQUEST; } overwrite = 1; overwrite_done: ngx_http_map_uri_to_path(r, &path, &root, 0); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http copy from: \"%s\"", path.data); uri = r->uri; r->uri = duri; ngx_http_map_uri_to_path(r, ©.path, &root, 0); r->uri = uri; copy.path.len--; /* omit "\0" */ if (copy.path.data[copy.path.len - 1] == '/') { slash = 1; copy.path.len--; copy.path.data[copy.path.len] = '\0'; } else { slash = 0; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http copy to: \"%s\"", copy.path.data); if (ngx_link_info(copy.path.data, &fi) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { return ngx_http_dav_error(r->connection->log, err, NGX_HTTP_NOT_FOUND, ngx_link_info_n, copy.path.data); } /* destination does not exist */ overwrite = 0; dir = 0; } else { /* destination exists */ if (ngx_is_dir(&fi) && !slash) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"%V\" could not be %Ved to collection \"%V\"", &r->uri, &r->method_name, &dest->value); return NGX_HTTP_CONFLICT; } if (!overwrite) { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EEXIST, "\"%s\" could not be created", copy.path.data); return NGX_HTTP_PRECONDITION_FAILED; } dir = ngx_is_dir(&fi); } if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) { return ngx_http_dav_error(r->connection->log, ngx_errno, NGX_HTTP_NOT_FOUND, ngx_link_info_n, path.data); } if (ngx_is_dir(&fi)) { if (r->uri.data[r->uri.len - 1] != '/') { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"%V\" is collection", &r->uri); return NGX_HTTP_BAD_REQUEST; } if (overwrite) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http delete: \"%s\"", copy.path.data); rc = ngx_http_dav_delete_path(r, ©.path, dir); if (rc != NGX_OK) { return rc; } } } if (ngx_is_dir(&fi)) { path.len -= 2; /* omit "/\0" */ if (r->method == NGX_HTTP_MOVE) { if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) { return NGX_HTTP_CREATED; } } if (ngx_create_dir(copy.path.data, ngx_file_access(&fi)) == NGX_FILE_ERROR) { return ngx_http_dav_error(r->connection->log, ngx_errno, NGX_HTTP_NOT_FOUND, ngx_create_dir_n, copy.path.data); } copy.len = path.len; tree.init_handler = NULL; tree.file_handler = ngx_http_dav_copy_tree_file; tree.pre_tree_handler = ngx_http_dav_copy_dir; tree.post_tree_handler = ngx_http_dav_copy_dir_time; tree.spec_handler = ngx_http_dav_noop; tree.data = © tree.alloc = 0; tree.log = r->connection->log; if (ngx_walk_tree(&tree, &path) == NGX_OK) { if (r->method == NGX_HTTP_MOVE) { rc = ngx_http_dav_delete_path(r, &path, 1); if (rc != NGX_OK) { return rc; } } return NGX_HTTP_CREATED; } } else { if (r->method == NGX_HTTP_MOVE) { dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); ext.access = 0; ext.path_access = dlcf->access; ext.time = -1; ext.create_path = 1; ext.delete_file = 0; ext.log = r->connection->log; if (ngx_ext_rename_file(&path, ©.path, &ext) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } return NGX_HTTP_INTERNAL_SERVER_ERROR; } dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); cf.size = ngx_file_size(&fi); cf.buf_size = 0; cf.access = dlcf->access; cf.time = ngx_file_mtime(&fi); cf.log = r->connection->log; if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } } return NGX_HTTP_INTERNAL_SERVER_ERROR; }
static ngx_int_t ngx_http_eval_handler(ngx_http_request_t *r) { /* size_t loc_len; */ ngx_str_t args; ngx_str_t subrequest_uri; ngx_uint_t flags; /* ngx_http_core_loc_conf_t *clcf; */ ngx_http_eval_loc_conf_t *ecf; ngx_http_eval_ctx_t *ctx; ngx_http_eval_ctx_t *sr_ctx; ngx_http_request_t *sr; ngx_int_t rc; ngx_http_post_subrequest_t *psr; u_char *p; /* if(r != r->main) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); loc_len = r->valid_location ? clcf->name.len : 0; if(r->uri.len != loc_len) { r->uri.data += loc_len; r->uri.len -= loc_len; } else { r->uri.len = 1; } } */ ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module); if(ecf->variables == NULL || !ecf->variables->nelts) { return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module); if(ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->base_conf = ecf; ngx_http_set_ctx(r, ctx, ngx_http_eval_module); } if (ctx->done) { dd("subrequest done"); if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) { return NGX_DECLINED; } dd("status: %d", (int) ctx->status); return ctx->status; } if (ctx->in_progress) { dd("still in progress"); return NGX_DONE; } psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } if(ngx_http_eval_init_variables(r, ctx, ecf) != NGX_OK) { return NGX_ERROR; } args = r->args; flags = 0; subrequest_uri.len = ecf->eval_location.len + r->uri.len; p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len); if(p == NULL) { return NGX_ERROR; } p = ngx_copy(p, ecf->eval_location.data, ecf->eval_location.len); p = ngx_copy(p, r->uri.data, r->uri.len); if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) { return NGX_ERROR; } psr->handler = ngx_http_eval_post_subrequest_handler; psr->data = ctx; flags |= NGX_HTTP_SUBREQUEST_WAITED; dd("subrequest in memory : %d", (int) ecf->subrequest_in_memory); if (ecf->subrequest_in_memory) { flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY; } else { } dd("issue subrequest"); rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags); if (rc == NGX_ERROR || rc == NGX_DONE) { return rc; } sr->discard_body = 1; ctx->in_progress = 1; /* XXX we don't allow eval in subrequests, i think? */ sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t)); if (sr_ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(sr, sr_ctx, ngx_http_eval_module); dd("wait for subrequest to complete"); return NGX_DONE; }