static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, ngx_http_request_body_t *body, unsigned vars_action, ngx_array_t *extra_vars) { ngx_http_request_t *r; ngx_int_t rc; ngx_http_core_main_conf_t *cmcf; size_t size; r = sr->parent; sr->header_in = r->header_in; if (body) { sr->request_body = body; rc = ngx_http_lua_set_content_length_header(sr, body->buf ? ngx_buf_size(body->buf) : 0); if (rc != NGX_OK) { return NGX_ERROR; } } else if (method != NGX_HTTP_PUT && method != NGX_HTTP_POST && r->headers_in.content_length_n > 0) { rc = ngx_http_lua_set_content_length_header(sr, 0); if (rc != NGX_OK) { return NGX_ERROR; } #if 1 sr->request_body = NULL; #endif } sr->method = method; switch (method) { case NGX_HTTP_GET: sr->method_name = ngx_http_lua_get_method; break; case NGX_HTTP_POST: sr->method_name = ngx_http_lua_post_method; break; case NGX_HTTP_PUT: sr->method_name = ngx_http_lua_put_method; break; case NGX_HTTP_HEAD: sr->method_name = ngx_http_lua_head_method; break; case NGX_HTTP_DELETE: sr->method_name = ngx_http_lua_delete_method; break; case NGX_HTTP_OPTIONS: sr->method_name = ngx_http_lua_options_method; break; default: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unsupported HTTP method: %u", (unsigned) method); return NGX_ERROR; } /* XXX work-around a bug in ngx_http_subrequest */ if (r->headers_in.headers.last == &r->headers_in.headers.part) { sr->headers_in.headers.last = &sr->headers_in.headers.part; } if (!(vars_action & NGX_HTTP_LUA_SHARE_ALL_VARS)) { /* we do not inherit the parent request's variables */ cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module); size = cmcf->variables.nelts * sizeof(ngx_http_variable_value_t); if (vars_action & NGX_HTTP_LUA_COPY_ALL_VARS) { sr->variables = ngx_palloc(sr->pool, size); if (sr->variables == NULL) { return NGX_ERROR; } ngx_memcpy(sr->variables, r->variables, size); } else { /* we do not inherit the parent request's variables */ sr->variables = ngx_pcalloc(sr->pool, size); if (sr->variables == NULL) { return NGX_ERROR; } } } return ngx_http_lua_subrequest_add_extra_vars(sr, extra_vars); }
static char * ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { ngx_int_t rc; ngx_str_t *value, file; ngx_uint_t i, key; ngx_http_map_conf_ctx_t *ctx; ngx_http_variable_value_t *var, **vp; ctx = cf->ctx; value = cf->args->elts; if (cf->args->nelts == 1 && ngx_strcmp(value[0].data, "hostnames") == 0) { ctx->hostnames = 1; return NGX_CONF_OK; } else if (cf->args->nelts != 2) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid number of the map parameters"); return NGX_CONF_ERROR; } else if (value[0].len == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid first parameter"); return NGX_CONF_ERROR; } if (ngx_strcmp(value[0].data, "include") == 0) { file = value[1]; if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { return NGX_CONF_ERROR; } ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); return ngx_conf_parse(cf, &file); } key = 0; for (i = 0; i < value[1].len; i++) { key = ngx_hash(key, value[1].data[i]); } key %= ctx->keys.hsize; vp = ctx->values_hash[key].elts; if (vp) { for (i = 0; i < ctx->values_hash[key].nelts; i++) { if (value[1].len != (size_t) vp[i]->len) { continue; } if (ngx_strncmp(value[1].data, vp[i]->data, value[1].len) == 0) { var = vp[i]; goto found; } } } else { if (ngx_array_init(&ctx->values_hash[key], cf->pool, 4, sizeof(ngx_http_variable_value_t *)) != NGX_OK) { return NGX_CONF_ERROR; } } var = ngx_palloc(ctx->keys.pool, sizeof(ngx_http_variable_value_t)); if (var == NULL) { return NGX_CONF_ERROR; } var->len = value[1].len; var->data = ngx_pstrdup(ctx->keys.pool, &value[1]); if (var->data == NULL) { return NGX_CONF_ERROR; } var->valid = 1; var->no_cacheable = 0; var->not_found = 0; vp = ngx_array_push(&ctx->values_hash[key]); if (vp == NULL) { return NGX_CONF_ERROR; } *vp = var; found: if (ngx_strcmp(value[0].data, "default") == 0) { if (ctx->default_value) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate default map parameter"); return NGX_CONF_ERROR; } ctx->default_value = var; return NGX_CONF_OK; } if (value[0].len && value[0].data[0] == '!') { value[0].len--; value[0].data++; } rc = ngx_hash_add_key(&ctx->keys, &value[0], var, (ctx->hostnames) ? NGX_HASH_WILDCARD_KEY : 0); if (rc == NGX_OK) { return NGX_CONF_OK; } if (rc == NGX_DECLINED) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid hostname or wildcard \"%V\"", &value[0]); } if (rc == NGX_BUSY) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "conflicting parameter \"%V\"", &value[0]); } return NGX_CONF_ERROR; }
ngx_listening_t * ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen) { size_t len; ngx_listening_t *ls; struct sockaddr *sa; u_char text[NGX_SOCKADDR_STRLEN]; ls = ngx_array_push(&cf->cycle->listening); if (ls == NULL) { return NULL; } ngx_memzero(ls, sizeof(ngx_listening_t)); sa = ngx_palloc(cf->pool, socklen); if (sa == NULL) { return NULL; } ngx_memcpy(sa, sockaddr, socklen); ls->sockaddr = sa; ls->socklen = socklen; len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1); ls->addr_text.len = len; switch (ls->sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN; break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: ls->addr_text_max_len = NGX_UNIX_ADDRSTRLEN; len++; break; #endif case AF_INET: ls->addr_text_max_len = NGX_INET_ADDRSTRLEN; break; default: ls->addr_text_max_len = NGX_SOCKADDR_STRLEN; break; } ls->addr_text.data = ngx_pnalloc(cf->pool, len); if (ls->addr_text.data == NULL) { return NULL; } ngx_memcpy(ls->addr_text.data, text, len); ls->fd = (ngx_socket_t) -1; ls->type = SOCK_STREAM; ls->backlog = NGX_LISTEN_BACKLOG; ls->rcvbuf = -1; ls->sndbuf = -1; #if (NGX_HAVE_SETFIB) ls->setfib = -1; #endif return ls; }
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_HTTP_INTERNAL_SERVER_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_HTTP_INTERNAL_SERVER_ERROR; } if (parsed_sr->location.len == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_http_complex_value(r, &conf->fetch->args, &parsed_sr->args) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &parsed_sr->location, &args, &flags) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_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_HTTP_INTERNAL_SERVER_ERROR; } sr_ctx->in_fetch_subrequest = 1; psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_HTTP_INTERNAL_SERVER_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->fetch_sr = sr; return NGX_OK; }
static int ngx_http_lua_ngx_req_body_finish(lua_State *L) { ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; ngx_buf_t *b; size_t size; ngx_str_t value; ngx_str_t key; ngx_int_t rc; n = lua_gettop(L); if (n != 0) { return luaL_error(L, "expecting 0 argument but seen %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->request_body == NULL || r->request_body->buf == NULL || r->request_body->bufs == NULL) { return luaL_error(L, "request_body not initalized"); } rb = r->request_body; if (rb->temp_file) { /* save the last part */ if (ngx_http_lua_write_request_body(r, rb->bufs) != NGX_OK) { return luaL_error(L, "fail to write file"); } b = ngx_calloc_buf(r->pool); if (b == NULL) { return luaL_error(L, "out of memory"); } b->in_file = 1; b->file_pos = 0; b->file_last = rb->temp_file->file.offset; b->file = &rb->temp_file->file; if (rb->bufs->next) { rb->bufs->next->buf = b; } else { rb->bufs->buf = b; } } /* override input header Content-Length (value must be null terminated) */ value.data = ngx_palloc(r->pool, NGX_SIZE_T_LEN + 1); if (value.data == NULL) { return luaL_error(L, "out of memory"); } size = r->headers_in.content_length_n; value.len = ngx_sprintf(value.data, "%uz", size) - value.data; value.data[value.len] = '\0'; dd("setting request Content-Length to %.*s (%d)", (int) value.len, value.data, (int) size); if (r->headers_in.content_length) { r->headers_in.content_length->value.data = value.data; r->headers_in.content_length->value.len = value.len; } else { ngx_str_set(&key, "Content-Length"); rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc != NGX_OK) { return luaL_error(L, "failed to reset the Content-Length " "input header"); } } return 0; }
static ngx_int_t ngx_http_parallel_init_fiber( ngx_http_request_t *r, ngx_uint_t header_in_count, ngx_flag_t proxy_as_is, ngx_http_parallel_fiber_ctx_t* fiber) { ngx_table_elt_t *h; ngx_int_t rc; // create the post-subrequest fiber->psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (fiber->psr == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_parallel_init_fiber: ngx_palloc failed"); return NGX_ERROR; } fiber->psr->handler = ngx_http_parallel_subrequest_finished_handler; fiber->psr->data = fiber; // copy the input headers fiber->headers_in = r->headers_in; if (proxy_as_is) { return NGX_OK; } // copy the headers list in order to update it rc = ngx_http_parallel_list_copy( r, &fiber->headers_in.headers, &r->headers_in.headers, header_in_count + 1, sizeof(ngx_table_elt_t)); if (rc != NGX_OK) { return rc; } ngx_http_parallel_update_headers(r, &fiber->headers_in); // add a range header if (fiber->headers_in.range == NULL) { h = ngx_list_push(&fiber->headers_in.headers); if (h == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_parallel_init_fiber: ngx_list_push failed"); return NGX_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash('r', 'a'), 'n'), 'g'), 'e'); h->key.data = (u_char*)"Range"; h->key.len = sizeof("Range") - 1; h->lowcase_key = (u_char*)"range"; fiber->headers_in.range = h; } else { h = fiber->headers_in.range; } h->value.data = ngx_pnalloc(r->pool, sizeof(RANGE_FORMAT) + 2 * NGX_OFF_T_LEN); if (h->value.data == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_parallel_init_fiber: ngx_pnalloc failed"); return NGX_ERROR; } return NGX_OK; }
ngx_inline static ngx_http_xrlt_ctx_t * ngx_http_xrlt_create_ctx(ngx_http_request_t *r, size_t id) { ngx_http_xrlt_ctx_t *ctx; ngx_http_xrlt_loc_conf_t *conf; ngx_uint_t i, j; ngx_http_xrlt_param_t *params; xmlChar **xrltparams; conf = ngx_http_get_module_loc_conf(r, ngx_http_xrlt_module); ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_xrlt_ctx_t)); if (ctx == NULL) { return NULL; } if (id == 0) { ngx_pool_cleanup_t *cln; cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NULL; } dd("XRLT context creation"); if (conf->params != NULL && conf->params->nelts > 0) { params = conf->params->elts; xrltparams = ngx_palloc( r->pool, sizeof(xmlChar *) * (conf->params->nelts * 2 + 1) ); j = 0; for (i = 0; i < conf->params->nelts; i++) { xrltparams[j++] = xmlStrndup(params[i].name.data, params[i].name.len); xrltparams[j++] = xmlStrndup(params[i].value.value.data, params[i].value.value.len); } xrltparams[j] = NULL; } else { xrltparams = NULL; } ctx->xctx = xrltContextCreate(conf->sheet, xrltparams); ctx->id = 0; ctx->main_ctx = ctx; if (ctx->xctx == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to create XRLT context"); } cln->handler = ngx_http_xrlt_cleanup_context; cln->data = ctx->xctx; } else { ngx_http_xrlt_ctx_t *main_ctx; main_ctx = ngx_http_get_module_ctx(r->main, ngx_http_xrlt_module); if (main_ctx == NULL || main_ctx->xctx == NULL) { return NULL; } ctx->xctx = main_ctx->xctx; ctx->id = id; ctx->main_ctx = main_ctx; } return ctx; }
ngx_int_t ngx_tcp_regex_exec(ngx_tcp_session_t *s, ngx_tcp_regex_t *re, ngx_str_t *s) { ngx_int_t rc, index; ngx_uint_t i, n, len; ngx_tcp_variable_value_t *vv; ngx_tcp_core_main_conf_t *cmcf; cmcf = ngx_tcp_get_module_main_conf(s, ngx_tcp_core_module); if (re->ncaptures) { len = cmcf->ncaptures; if (r->captures == NULL) { r->captures = ngx_palloc(r->pool, len * sizeof(int)); if (r->captures == NULL) { return NGX_ERROR; } } } else { len = 0; } rc = ngx_regex_exec(re->regex, s, r->captures, len); if (rc == NGX_REGEX_NO_MATCHED) { return NGX_DECLINED; } if (rc < 0) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", rc, s, &re->name); return NGX_ERROR; } for (i = 0; i < re->nvariables; i++) { n = re->variables[i].capture; index = re->variables[i].index; vv = &r->variables[index]; vv->len = r->captures[n + 1] - r->captures[n]; vv->valid = 1; vv->no_cacheable = 0; vv->not_found = 0; vv->data = &s->data[r->captures[n]]; #if (NGX_DEBUG) { ngx_tcp_variable_t *v; v = cmcf->variables.elts; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "tcp regex set $%V to \"%*s\"", &v[index].name, vv->len, vv->data); } #endif } r->ncaptures = rc * 2; r->captures_data = s->data; return NGX_OK; }
ngx_tcp_variable_t * ngx_tcp_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags) { ngx_int_t rc; ngx_uint_t i; ngx_hash_key_t *key; ngx_tcp_variable_t *v; ngx_tcp_core_main_conf_t *cmcf; cmcf = ngx_tcp_conf_get_module_main_conf(cf, ngx_tcp_core_module); key = cmcf->variables_keys->keys.elts; for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) { if (name->len != key[i].key.len || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0) { continue; } v = key[i].value; if (!(v->flags & NGX_TCP_VAR_CHANGEABLE)) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the duplicate \"%V\" variable", name); return NULL; } return v; } v = ngx_palloc(cf->pool, sizeof(ngx_tcp_variable_t)); if (v == NULL) { return NULL; } v->name.len = name->len; v->name.data = ngx_pnalloc(cf->pool, name->len); if (v->name.data == NULL) { return NULL; } ngx_strlow(v->name.data, name->data, name->len); v->set_handler = NULL; v->get_handler = NULL; v->data = 0; v->flags = flags; v->index = 0; rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0); if (rc == NGX_ERROR) { return NULL; } if (rc == NGX_BUSY) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "conflicting variable name \"%V\"", name); return NULL; } return v; }
ngx_tcp_variable_value_t * ngx_tcp_get_variable(ngx_tcp_session_t *s, ngx_str_t *name, ngx_uint_t key) { ngx_tcp_variable_t *v; ngx_tcp_variable_value_t *vv; ngx_tcp_core_main_conf_t *cmcf; cmcf = ngx_tcp_get_module_main_conf(s, ngx_tcp_core_module); v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len); if (v) { if (v->flags & NGX_TCP_VAR_INDEXED) { return NULL;//ngx_tcp_get_flushed_variable(r, v->index); } else { vv = ngx_palloc(s->pool, sizeof(ngx_tcp_variable_value_t)); if (vv && v->get_handler(s, vv, v->data) == NGX_OK) { return vv; } return NULL; } } vv = ngx_palloc(s->pool, sizeof(ngx_tcp_variable_value_t)); if (vv == NULL) { return NULL; } /*if (ngx_strncmp(name->data, "tcp_", 5) == 0) { if (ngx_tcp_variable_unknown_header_in(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } if (ngx_strncmp(name->data, "sent_tcp_", 10) == 0) { if (ngx_tcp_variable_unknown_header_out(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } if (ngx_strncmp(name->data, "upstream_tcp_", 14) == 0) { if (ngx_tcp_upstream_header_variable(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; }*/ vv->not_found = 1; return vv; }
ngx_tcp_regex_t * ngx_tcp_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc) { u_char *p; size_t size; ngx_str_t name; ngx_uint_t i, n; ngx_tcp_variable_t *v; ngx_tcp_regex_t *re; ngx_tcp_regex_variable_t *rv; ngx_tcp_core_main_conf_t *cmcf; rc->pool = cf->pool; if (ngx_regex_compile(rc) != NGX_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err); return NULL; } re = ngx_pcalloc(cf->pool, sizeof(ngx_tcp_regex_t)); if (re == NULL) { return NULL; } re->regex = rc->regex; re->ncaptures = rc->captures; cmcf = ngx_tcp_conf_get_module_main_conf(cf, ngx_tcp_core_module); cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures); n = (ngx_uint_t) rc->named_captures; if (n == 0) { return re; } rv = ngx_palloc(rc->pool, n * sizeof(ngx_tcp_regex_variable_t)); if (rv == NULL) { return NULL; } re->variables = rv; re->nvariables = n; re->name = rc->pattern; size = rc->name_size; p = rc->names; for (i = 0; i < n; i++) { rv[i].capture = 2 * ((p[0] << 8) + p[1]); name.data = &p[2]; name.len = ngx_strlen(name.data); v = ngx_tcp_add_variable(cf, &name, NGX_TCP_VAR_CHANGEABLE); if (v == NULL) { return NULL; } rv[i].index = ngx_tcp_get_variable_index(cf, &name); if (rv[i].index == NGX_ERROR) { return NULL; } v->get_handler = ngx_tcp_variable_not_found; p += size; } return re; }
ngx_int_t ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) { ngx_http_request_t *pr; ngx_http_lua_ctx_t *pr_ctx; ngx_http_lua_ctx_t *ctx; /* subrequest ctx */ ngx_http_lua_co_ctx_t *pr_coctx; size_t len; ngx_str_t *body_str; u_char *p; ngx_chain_t *cl; ngx_http_lua_post_subrequest_data_t *psr_data = data; ctx = psr_data->ctx; if (ctx->run_post_subrequest) { return NGX_OK; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run post subrequest handler: rc:%d", rc); ctx->run_post_subrequest = 1; pr = r->parent; pr_ctx = ngx_http_get_module_ctx(pr, ngx_http_lua_module); if (pr_ctx == NULL) { return NGX_ERROR; } pr_coctx = psr_data->pr_co_ctx; pr_coctx->waiting--; if (pr_coctx->waiting == 0) { pr_coctx->done = 1; } if (pr_ctx->entered_content_phase) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua restoring write event handler"); pr->write_event_handler = ngx_http_lua_content_wev_handler; } dd("status rc = %d", (int) rc); dd("status headers_out.status = %d", (int) r->headers_out.status); dd("uri: %.*s", (int) r->uri.len, r->uri.data); /* capture subrequest response status */ if (rc == NGX_ERROR) { pr_coctx->sr_statuses[ctx->index] = NGX_HTTP_INTERNAL_SERVER_ERROR; } else if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { pr_coctx->sr_statuses[ctx->index] = rc; } else { pr_coctx->sr_statuses[ctx->index] = r->headers_out.status; } if (pr_coctx->sr_statuses[ctx->index] == 0) { pr_coctx->sr_statuses[ctx->index] = NGX_HTTP_OK; } dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); /* copy subrequest response headers */ pr_coctx->sr_headers[ctx->index] = &r->headers_out; /* copy subrequest response body */ body_str = &pr_coctx->sr_bodies[ctx->index]; len = 0; for (cl = ctx->body; cl; cl = cl->next) { /* ignore all non-memory buffers */ len += cl->buf->last - cl->buf->pos; } body_str->len = len; if (len == 0) { body_str->data = NULL; } else { p = ngx_palloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } body_str->data = p; /* copy from and then free the data buffers */ for (cl = ctx->body; cl; cl = cl->next) { p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos); cl->buf->last = cl->buf->pos; #if 0 dd("free body chain link buf ASAP"); ngx_pfree(r->pool, cl->buf->start); #endif } } if (ctx->body) { #if defined(nginx_version) && nginx_version >= 1001004 ngx_chain_update_chains(r->pool, #else ngx_chain_update_chains( #endif &pr_ctx->free_bufs, &pr_ctx->busy_bufs, &ctx->body, (ngx_buf_tag_t) &ngx_http_lua_module); dd("free bufs: %p", pr_ctx->free_bufs); }
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; 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"); } 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"); } 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"); } 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); p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len + sr_bodies_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; coctx->nsubreqs = nsubreqs; coctx->done = 0; coctx->waiting = 0; extra_vars = NULL; for (index = 0; index < nsubreqs; index++) { coctx->waiting++; 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) { args = extra_args; } 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->entry_ref = LUA_NOREF; sr_ctx->ctx_ref = LUA_NOREF; sr_ctx->capture = 1; sr_ctx->index = index; 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) { 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); } return lua_yield(L, 0); }
static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr, ngx_array_t *extra_vars) { ngx_http_core_main_conf_t *cmcf; ngx_http_variable_t *v; ngx_http_variable_value_t *vv; u_char *val; u_char *p; ngx_uint_t i, hash; ngx_str_t name; size_t len; ngx_hash_t *variables_hash; ngx_keyval_t *var; /* set any extra variables that were passed to the subrequest */ if (extra_vars == NULL || extra_vars->nelts == 0) { return NGX_OK; } cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module); variables_hash = &cmcf->variables_hash; var = extra_vars->elts; for (i = 0; i < extra_vars->nelts; i++, var++) { /* copy the variable's name and value because they are allocated * by the lua VM */ len = var->key.len + var->value.len; p = ngx_pnalloc(sr->pool, len); if (p == NULL) { return NGX_ERROR; } name.data = p; name.len = var->key.len; p = ngx_copy(p, var->key.data, var->key.len); hash = ngx_hash_strlow(name.data, name.data, name.len); val = p; len = var->value.len; ngx_memcpy(p, var->value.data, len); v = ngx_hash_find(variables_hash, hash, name.data, name.len); if (v) { if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) { ngx_log_error(NGX_LOG_ERR, sr->connection->log, 0, "variable \"%V\" not changeable", &name); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (v->set_handler) { vv = ngx_palloc(sr->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { return NGX_ERROR; } vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; v->set_handler(sr, vv, v->data); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sr->connection->log, 0, "variable \"%V\" set to value \"%v\"", &name, vv); continue; } if (v->flags & NGX_HTTP_VAR_INDEXED) { vv = &sr->variables[v->index]; vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sr->connection->log, 0, "variable \"%V\" set to value \"%v\"", &name, vv); continue; } } ngx_log_error(NGX_LOG_ERR, sr->connection->log, 0, "variable \"%V\" cannot be assigned a value (maybe you " "forgot to define it first?) ", &name); return NGX_ERROR; } return NGX_OK; }
static char * ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { #if (NGX_HAVE_SCHED_SETAFFINITY) ngx_core_conf_t *ccf = conf; u_char ch; u_long *mask; ngx_str_t *value; ngx_uint_t i, n; if (ccf->cpu_affinity) { return "is duplicate"; } mask = ngx_palloc(cf->pool, (cf->args->nelts - 1) * sizeof(long)); if (mask == NULL) { return NGX_CONF_ERROR; } ccf->cpu_affinity_n = cf->args->nelts - 1; ccf->cpu_affinity = mask; value = cf->args->elts; for (n = 1; n < cf->args->nelts; n++) { if (value[n].len > 32) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"worker_cpu_affinity\" supports up to 32 CPU only"); return NGX_CONF_ERROR; } mask[n - 1] = 0; for (i = 0; i < value[n].len; i++) { ch = value[n].data[i]; if (ch == ' ') { continue; } mask[n - 1] <<= 1; if (ch == '0') { continue; } if (ch == '1') { mask[n - 1] |= 1; continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid character \"%c\" in \"worker_cpu_affinity\"", ch); return NGX_CONF_ERROR; } } #else ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "\"worker_cpu_affinity\" is not supported " "on this platform, ignored"); #endif return NGX_CONF_OK; }
/** * Set nginx internal variable content * * @retval Always return a boolean on Lua stack. Return true when variable * content was modified successfully, false otherwise. * @seealso ngx_tcp_lua_var_get * */ static int ngx_tcp_lua_var_set(lua_State *L) { ngx_tcp_variable_t *v; ngx_tcp_variable_value_t *vv; ngx_tcp_core_main_conf_t *cmcf; u_char *p, *lowcase, *val; size_t len; ngx_str_t name; ngx_uint_t hash; ngx_tcp_session_t *s; int value_type; const char *msg; lua_pushlightuserdata(L, &ngx_tcp_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); s = lua_touserdata(L, -1); lua_pop(L, 1); if (s == NULL) { return luaL_error(L, "no request object found"); } /* we skip the first argument that is the table */ /* we read the variable name */ p = (u_char *) luaL_checklstring(L, 2, &len); lowcase = ngx_palloc(s->pool, len + 1); if (lowcase == NULL) { return luaL_error(L, "memory allocation error"); } lowcase[len] = '\0'; hash = ngx_hash_strlow(lowcase, p, len); name.len = len; name.data = lowcase; /* we read the variable new value */ value_type = lua_type(L, 3); switch (value_type) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) luaL_checklstring(L, 3, &len); val = ngx_palloc(s->pool, len); if (val == NULL) { return luaL_error(L, "memory allocation erorr"); } ngx_memcpy(val, p, len); break; case LUA_TNIL: /* undef the variable */ val = NULL; len = 0; break; default: msg = lua_pushfstring(L, "string, number, or nil expected, " "but got %s", lua_typename(L, value_type)); return luaL_argerror(L, 1, msg); } /* we fetch the variable itself */ cmcf = ngx_tcp_get_module_main_conf(s, ngx_tcp_core_module); v = ngx_hash_find(&cmcf->variables_hash, hash, name.data, name.len); if (v) { if (!(v->flags & NGX_TCP_VAR_CHANGEABLE)) { return luaL_error(L, "variable \"%s\" not changeable", lowcase); } if (v->set_handler) { dd("set variables with set_handler"); vv = ngx_palloc(s->pool, sizeof(ngx_tcp_variable_value_t)); if (vv == NULL) { return luaL_error(L, "out of memory"); } if (value_type == LUA_TNIL) { vv->valid = 0; vv->not_found = 1; vv->no_cacheable = 0; vv->data = NULL; vv->len = 0; } else { vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; } v->set_handler(s, vv, v->data); return 0; } /*if (v->flags & NGX_TCP_VAR_INDEXED) { vv = &s->variables[v->index]; dd("set indexed variable"); if (value_type == LUA_TNIL) { vv->valid = 0; vv->not_found = 1; vv->no_cacheable = 0; vv->data = NULL; vv->len = 0; } else { vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; } return 0; }*/ return luaL_error(L, "variable \"%s\" cannot be assigned a value", lowcase); } /* variable not found */ return luaL_error(L, "varaible \"%s\" not found for writing; " "maybe it is a built-in variable that is not changeable " "or you sould have used \"set $%s '';\" earlier " "in the config file", lowcase, lowcase); }
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r) { //首先建立http上下文结构体ngx_http_mytest_ctx_t ngx_http_mytest_ctx_t* myctx = ngx_http_get_module_ctx(r, ngx_http_mytest_module); if (myctx == NULL) { myctx = ngx_palloc(r->pool, sizeof(ngx_http_mytest_ctx_t)); if (myctx == NULL) { return NGX_ERROR; } //将新建的上下文与请求关联起来 ngx_http_set_ctx(r, myctx, ngx_http_mytest_module); } //对每1个要使用upstream的请求,必须调用且只能调用1次 //ngx_http_upstream_create方法,它会初始化r->upstream成员 if (ngx_http_upstream_create(r) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_upstream_create() failed"); return NGX_ERROR; } //得到配置结构体ngx_http_mytest_conf_t ngx_http_mytest_conf_t *mycf = (ngx_http_mytest_conf_t *) ngx_http_get_module_loc_conf(r, ngx_http_mytest_module); ngx_http_upstream_t *u = r->upstream; //这里用配置文件中的结构体来赋给r->upstream->conf成员 u->conf = &mycf->upstream; //决定转发包体时使用的缓冲区 u->buffering = mycf->upstream.buffering; //以下代码开始初始化resolved结构体,用来保存上游服务器的地址 u->resolved = (ngx_http_upstream_resolved_t*) ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); if (u->resolved == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pcalloc resolved error. %s.", strerror(errno)); return NGX_ERROR; } //这里的上游服务器就是www.google.com static struct sockaddr_in backendSockAddr; struct hostent *pHost = gethostbyname((char*) "www.google.com"); if (pHost == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "gethostbyname fail. %s", strerror(errno)); return NGX_ERROR; } //访问上游服务器的80端口 backendSockAddr.sin_family = AF_INET; backendSockAddr.sin_port = htons((in_port_t) 80); char* pDmsIP = inet_ntoa(*(struct in_addr*) (pHost->h_addr_list[0])); backendSockAddr.sin_addr.s_addr = inet_addr(pDmsIP); myctx->backendServer.data = (u_char*)pDmsIP; myctx->backendServer.len = strlen(pDmsIP); //将地址设置到resolved成员中 u->resolved->sockaddr = (struct sockaddr *)&backendSockAddr; u->resolved->socklen = sizeof(struct sockaddr_in); u->resolved->naddrs = 1; //设置三个必须实现的回调方法,也就是5.3.3节至5.3.5节中实现的3个方法 u->create_request = mytest_upstream_create_request; u->process_header = mytest_process_status_line; u->finalize_request = mytest_upstream_finalize_request; //这里必须将count成员加1,理由见5.1.5节 r->main->count++; //启动upstream ngx_http_upstream_init(r); //必须返回NGX_DONE return NGX_DONE; }
/** * Get nginx internal variables content * * @retval Always return a string or nil on Lua stack. Return nil when failed * to get content, and actual content string when found the specified variable. * @seealso ngx_tcp_lua_var_set * */ static int ngx_tcp_lua_var_get(lua_State *L) { ngx_tcp_session_t *s; u_char *p, *lowcase; size_t len; ngx_uint_t hash; ngx_str_t name; ngx_tcp_variable_value_t *vv; /* #if (NGX_PCRE) u_char *val; ngx_uint_t n; LUA_NUMBER index; int *cap; #endif */ lua_pushlightuserdata(L, &ngx_tcp_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); s = lua_touserdata(L, -1); lua_pop(L, 1); if (s == NULL) { return luaL_error(L, "no request object found"); } /*#if (NGX_PCRE)*/ #if 0 if (lua_type(L, -1) == LUA_TNUMBER) { /* it is a regex capturing variable */ index = lua_tonumber(L, -1); if (index <= 0) { lua_pushnil(L); return 1; } n = (ngx_uint_t) index * 2; /*dd("n = %d, ncaptures = %d", (int) n, (int) s->ncaptures);*/ if (s->captures == NULL || s->captures_data == NULL || n >= s->ncaptures) { lua_pushnil(L); return 1; } /* n >= 0 && n < s->ncaptures */ cap = s->captures; p = s->captures_data; val = &p[cap[n]]; lua_pushlstring(L, (const char *) val, (size_t) (cap[n + 1] - cap[n])); return 1; } #endif p = (u_char *) luaL_checklstring(L, -1, &len); lowcase = ngx_palloc(s->pool, len); if (lowcase == NULL) { return luaL_error(L, "memory allocation error"); } hash = ngx_hash_strlow(lowcase, p, len); name.len = len; name.data = lowcase; vv = ngx_tcp_get_variable(s, &name, hash); if (vv == NULL || vv->not_found) { lua_pushnil(L); return 1; } lua_pushlstring(L, (const char *) vv->data, (size_t) vv->len); return 1; }
static ngx_int_t ngx_http_parallel_start_fiber( ngx_http_request_t *r, ngx_http_parallel_fiber_ctx_t* fiber, uint64_t chunk_index) { ngx_http_parallel_loc_conf_t *conf; ngx_http_parallel_ctx_t *ctx; ngx_http_request_t* sr; ngx_str_t args = ngx_null_string; ngx_table_elt_t *h; ngx_int_t rc; size_t alloc_size; off_t start_offset; off_t end_offset; ngx_chain_t* cl; ngx_buf_t* b; ctx = ngx_http_get_module_ctx(r, ngx_http_parallel_module); conf = ngx_http_get_module_loc_conf(r, ngx_http_parallel_module); // get a buffer for the response cl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (cl == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_parallel_start_fiber: ngx_chain_get_free_buf failed"); return NGX_ERROR; } b = cl->buf; if (cl->buf->start == NULL) { alloc_size = conf->max_headers_size + conf->max_chunk_size; b->start = ngx_palloc(r->pool, alloc_size); if (b->start == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_parallel_start_fiber: ngx_palloc failed"); return NGX_ERROR; } b->pos = b->start; b->last = b->start; b->end = b->last + alloc_size; b->temporary = 1; b->tag = (ngx_buf_tag_t)&ngx_http_parallel_module; ctx->allocated_count++; } // allocate a list for the input headers if (ngx_list_init(&fiber->upstream_headers, r->pool, 8, sizeof(ngx_table_elt_t)) != NGX_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_parallel_start_fiber: ngx_list_init failed"); return NGX_ERROR; } // set the range if (ctx->fiber_count != 1) { start_offset = ctx->range.start; if (chunk_index < ctx->fiber_count) { start_offset += chunk_index * ctx->chunk_size; } else { start_offset += ctx->initial_requested_size + (chunk_index - ctx->fiber_count) * ctx->chunk_size; } end_offset = start_offset + ctx->chunk_size; if (ctx->range.end != 0 && ctx->range.end < end_offset) { end_offset = ctx->range.end; } h = fiber->headers_in.range; h->value.len = ngx_sprintf( h->value.data, RANGE_FORMAT, start_offset, end_offset - 1) - h->value.data; h->value.data[h->value.len] = '\0'; } // start the request r->headers_in = fiber->headers_in; rc = ngx_http_subrequest(r, &ctx->sr_uri, &args, &sr, fiber->psr, NGX_HTTP_SUBREQUEST_WAITED | NGX_HTTP_SUBREQUEST_IN_MEMORY); r->headers_in = ctx->original_headers_in; if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_parallel_start_fiber: ngx_http_subrequest failed %i", rc); return rc; } ngx_http_set_ctx(sr, fiber, ngx_http_parallel_module); ctx->active_fibers++; sr->write_event_handler = ngx_http_parallel_fiber_initial_wev_handler; sr->method = r->method; // copy the method to the subrequest sr->method_name = r->method_name; // (ngx_http_subrequest always uses GET) sr->header_in = r->header_in; // fix the last pointer in headers_in (from echo-nginx-module) if (fiber->headers_in.headers.last == &fiber->headers_in.headers.part) { sr->headers_in.headers.last = &sr->headers_in.headers.part; } fiber->chunk_index = chunk_index; fiber->cl = cl; fiber->sr = sr; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_parallel_start_fiber: started fiber %uL", chunk_index); return NGX_OK; }
static ngx_int_t es_respond_message(subscriber_t *sub, nchan_msg_t *msg) { static ngx_str_t terminal_newlines=ngx_string("\n\n"); full_subscriber_t *fsub = (full_subscriber_t *)sub; u_char *cur = NULL, *last = NULL; ngx_buf_t *msg_buf = msg->buf; ngx_buf_t databuf; ngx_pool_t *pool; nchan_buf_and_chain_t *bc; size_t len; ngx_chain_t *first_link = NULL, *last_link = NULL; ngx_file_t *msg_file; ngx_int_t rc; nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(fsub->sub.request, nchan_module); ctx->prev_msg_id = fsub->sub.last_msgid; update_subscriber_last_msg_id(sub, msg); ctx->msg_id = fsub->sub.last_msgid; es_ensure_headers_sent(fsub); DBG("%p output msg to subscriber", sub); pool = ngx_create_pool(NGX_DEFAULT_LINEBREAK_POOL_SIZE, ngx_cycle->log); assert(pool); ngx_memcpy(&databuf, msg_buf, sizeof(*msg_buf)); databuf.last_buf = 0; if(!databuf.in_file) { cur = msg_buf->start; last = msg_buf->end; do { databuf.start = cur; databuf.pos = cur; databuf.end = last; databuf.last = last; cur = ngx_strlchr(cur, last, '\n'); if(cur == NULL) { //sweet, no newlines! //let's get out of this hellish loop databuf.end = last; databuf.last = last; cur = last + 1; } else { cur++; //include the newline databuf.end = cur; databuf.last = cur; } create_dataline_bufchain(pool, &first_link, &last_link, &databuf); } while(cur <= last); } else { //great, we've gotta scan this whole damn file for line breaks. //EventStream really isn't designed for large chunks of data off_t fcur, flast; ngx_fd_t fd; int chr_int; FILE *stream; msg_file = ngx_palloc(pool, sizeof(*msg_file)); databuf.file = msg_file; ngx_memcpy(msg_file, msg_buf->file, sizeof(*msg_file)); if(msg_file->fd == NGX_INVALID_FILE) { msg_file->fd = nchan_fdcache_get(&msg_file->name); } fd = msg_file->fd; stream = fdopen(dup(fd), "r"); fcur = databuf.file_pos; flast = databuf.file_last; fseek(stream, fcur, SEEK_SET); do { databuf.file_pos = fcur; databuf.file_last = flast; //getc that shit for(;;) { chr_int = getc(stream); if(chr_int == EOF) { break; } else if(chr_int == (int )'\n') { fcur++; break; } fcur++; } databuf.file_last = fcur; create_dataline_bufchain(pool, &first_link, &last_link, &databuf); } while(fcur < flast); fclose(stream); } //now 2 newlines at the end if(last_link) { bc = ngx_palloc(pool, sizeof(*bc)); last_link->next=&bc->chain; ngx_init_set_membuf(&bc->buf, terminal_newlines.data, terminal_newlines.data + terminal_newlines.len); bc->buf.flush = 1; bc->buf.last_buf = 0; bc->chain.next = NULL; bc->chain.buf = &bc->buf; last_link = &bc->chain; } //okay, this crazy data chain is finished. now how about the mesage tag? len = 10 + 2*NGX_INT_T_LEN; bc = ngx_palloc(pool, sizeof(*bc) + len); ngx_memzero(&bc->buf, sizeof(bc->buf)); cur = (u_char *)&bc[1]; ngx_init_set_membuf(&bc->buf, cur, ngx_snprintf(cur, len, "id: %V\n", msgid_to_str(&sub->last_msgid))); bc->chain.buf = &bc->buf; bc->chain.next = first_link; first_link=&bc->chain; rc = nchan_output_filter(fsub->sub.request, first_link); ngx_destroy_pool(pool); return rc; }
ngx_inline static ngx_int_t ngx_http_xrlt_process_transform_result(ngx_http_request_t *r, ngx_http_xrlt_ctx_t *ctx, int result) { xrltString s; if (result & XRLT_STATUS_ERROR) { return NGX_ERROR; } if (result == XRLT_STATUS_WAITING) { // Nothing to do, just wait. return NGX_AGAIN; } if (result & XRLT_STATUS_HEADER) { ngx_table_elt_t *h; xrltHeaderOutType htype; xrltString hname; xrltString hval; ngx_int_t hst; while (xrltHeaderOutListShift(&ctx->xctx->header, &htype, &hname, &hval)) { if (ctx->headers_sent) { dd("Response headers are already sent"); } else { if (htype == XRLT_HEADER_OUT_STATUS) { hst = ngx_atoi((u_char *)hval.data, hval.len); if (hst < 0) { xrltStringClear(&hname); xrltStringClear(&hval); return NGX_ERROR; } r->main->headers_out.status = (ngx_uint_t)hst; } else { h = ngx_list_push(&r->main->headers_out.headers); if (h == NULL) { xrltStringClear(&hname); xrltStringClear(&hval); return NGX_ERROR; } h->hash = 1; XRLT_STR_2_NGX_STR(h->key, hname); XRLT_STR_2_NGX_STR(h->value, hval); dd("Pushing response header (name: %s, value: %s)", h->key.data, h->value.data); } } xrltStringClear(&hname); xrltStringClear(&hval); } } if (result & XRLT_STATUS_REFUSE_SUBREQUEST) { // Cancel r subrequest, there is something wrong with it. ctx->refused = TRUE; } if (result & XRLT_STATUS_SUBREQUEST) { size_t sr_id; xrltHTTPMethod m; xrltSubrequestDataType type; xrltHeaderOutList sr_header; xrltString url, querystring, body, hname, hval; xrltHeaderOutType htype; ngx_http_xrlt_ctx_t *sr_ctx; ngx_str_t sr_uri, sr_querystring, sr_body; ngx_http_request_t *sr; ngx_http_post_subrequest_t *psr; ngx_http_request_body_t *rb; ngx_buf_t *b; ngx_table_elt_t *h; ngx_http_core_main_conf_t *cmcf; while (xrltSubrequestListShift(&ctx->xctx->sr, &sr_id, &m, &type, &sr_header, &url, &querystring, &body)) { sr_ctx = ngx_http_xrlt_create_ctx(r, sr_id); if (sr_ctx == NULL) { xrltHeaderOutListClear(&sr_header); xrltStringClear(&url); xrltStringClear(&querystring); xrltStringClear(&body); return NGX_ERROR; } XRLT_STR_2_NGX_STR(sr_uri, url); XRLT_STR_2_NGX_STR(sr_querystring, querystring); XRLT_STR_2_NGX_STR(sr_body, body); xrltStringClear(&url); xrltStringClear(&querystring); xrltStringClear(&body); psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } psr->handler = ngx_http_xrlt_post_sr; psr->data = sr_ctx; if (ngx_http_subrequest(r->main, &sr_uri, &sr_querystring, &sr, psr, 0) != NGX_OK) { xrltHeaderOutListClear(&sr_header); return NGX_ERROR; } dd("Performing subrequest (r: %p, uri: %s, querystring: %s, " "body: %s)", sr, sr_uri.data, sr_querystring.data, sr_body.data); // Don't inherit parent request variables. Content-Length is // cacheable in proxy module and we don't need Content-Length from // another subrequest. cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module); sr->variables = ngx_pcalloc(sr->pool, cmcf->variables.nelts * sizeof(ngx_http_variable_value_t)); if (sr->variables == NULL) { return NGX_ERROR; } switch (m) { case XRLT_METHOD_GET: sr->method = NGX_HTTP_GET; break; case XRLT_METHOD_HEAD: sr->method = NGX_HTTP_HEAD; sr->method_name = ngx_http_xrlt_head_method; break; case XRLT_METHOD_POST: sr->method = NGX_HTTP_POST; sr->method_name = ngx_http_xrlt_post_method; break; case XRLT_METHOD_PUT: sr->method = NGX_HTTP_PUT; sr->method_name = ngx_http_xrlt_put_method; break; case XRLT_METHOD_DELETE: sr->method = NGX_HTTP_DELETE; sr->method_name = ngx_http_xrlt_delete_method; break; case XRLT_METHOD_TRACE: sr->method = NGX_HTTP_TRACE; sr->method_name = ngx_http_xrlt_trace_method; break; case XRLT_METHOD_OPTIONS: sr->method = NGX_HTTP_OPTIONS; sr->method_name = ngx_http_xrlt_options_method; break; default: sr->method = NGX_HTTP_GET; } if (ngx_http_xrlt_init_subrequest_headers(sr, sr_body.len) == NGX_ERROR) { xrltHeaderOutListClear(&sr_header); return NGX_ERROR; } if (sr_header.first != NULL) { while (xrltHeaderOutListShift(&sr_header, &htype, &hname, &hval)) { h = ngx_list_push(&sr->headers_in.headers); if (h == NULL) { xrltStringClear(&hname); xrltStringClear(&hval); xrltHeaderOutListClear(&sr_header); return NGX_ERROR; } XRLT_STR_2_NGX_STR(h->key, hname); XRLT_STR_2_NGX_STR(h->value, hval); xrltStringClear(&hname); xrltStringClear(&hval); h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { xrltHeaderOutListClear(&sr_header); return NGX_ERROR; } ngx_strlow(h->lowcase_key, h->key.data, h->key.len); } } ngx_http_set_ctx(sr, sr_ctx, ngx_http_xrlt_module); if (sr_body.len > 0) { rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return NGX_ERROR; } b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return NGX_ERROR; } b->temporary = 1; b->start = b->pos = sr_body.data; b->end = b->last = sr_body.data + sr_body.len; b->last_buf = 1; b->last_in_chain = 1; rb->bufs->buf = b; rb->bufs->next = NULL; rb->buf = b; sr->request_body = rb; } } } if (result & XRLT_STATUS_CHUNK) { // Send response chunks out in case we don't have response headers in // progress or if response headers are sent. if (ctx->headers_sent || ctx->xctx->headerCount == 0) { ngx_buf_t *b; ngx_chain_t out; ngx_http_request_t *ar; /* active request */ ngx_int_t rc; while (xrltChunkListShift(&ctx->xctx->chunk, &s)) { if (s.len > 0) { if (!ctx->main_ctx->headers_sent) { ctx->main_ctx->headers_sent = 1; dd("Sending response headers"); if (ngx_http_send_header(r->main) != NGX_OK) { xrltStringClear(&s); return NGX_ERROR; } } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { xrltStringClear(&s); return NGX_ERROR; } b->start = ngx_pcalloc(r->pool, s.len); if (b->start == NULL) { xrltStringClear(&s); return NGX_ERROR; } (void)ngx_copy(b->start, s.data, s.len); b->pos = b->start; b->last = b->end = b->start + s.len; b->temporary = 1; b->last_in_chain = 1; b->flush = 1; b->last_buf = 0; out.buf = b; out.next = NULL; dd("Sending response chunk (len: %zd)", s.len); ar = r->connection->data; if (ar != r->main) { /* bypass ngx_http_postpone_filter_module */ r->connection->data = r->main; rc = ngx_http_output_filter(r->main, &out); r->connection->data = ar; } else { rc = ngx_http_output_filter(r->main, &out); } if (rc == NGX_ERROR) { xrltStringClear(&s); return NGX_ERROR; } } xrltStringClear(&s); } } } if (result & XRLT_STATUS_LOG) { xrltLogType ltype; ngx_uint_t l; while (xrltLogListShift(&ctx->xctx->log, <ype, &s)) { switch (ltype) { case XRLT_ERROR: l = NGX_LOG_ERR; break; case XRLT_WARNING: l = NGX_LOG_WARN; break; case XRLT_DEBUG: l = NGX_LOG_DEBUG; break; case XRLT_INFO: default: l = NGX_LOG_INFO; break; } ngx_log_error(l, r->connection->log, 0, s.data); xrltStringClear(&s); } } if (result & XRLT_STATUS_DONE) { if (!ctx->main_ctx->headers_sent) { ctx->main_ctx->headers_sent = 1; dd("Sending response headers"); if (ngx_http_send_header(r->main) != NGX_OK) { return NGX_ERROR; } } r->main->write_event_handler = ngx_http_xrlt_wev_handler; if (ngx_http_send_special(r->main, NGX_HTTP_LAST) == NGX_ERROR) { return NGX_ERROR; } return NGX_DONE; } return NGX_OK; }
ngx_int_t ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, ngx_uint_t port) { socklen_t len; ngx_uint_t addr; u_char sa[NGX_SOCKADDRLEN]; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) ngx_uint_t i; struct sockaddr_in6 *sin6; #endif addr = 0; if (c->local_socklen) { switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) c->local_sockaddr; for (i = 0; addr == 0 && i < 16; i++) { addr |= sin6->sin6_addr.s6_addr[i]; } break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: addr = 1; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) c->local_sockaddr; addr = sin->sin_addr.s_addr; break; } } if (addr == 0) { len = NGX_SOCKADDRLEN; if (getsockname(c->fd, (struct sockaddr *) &sa, &len) == -1) { ngx_connection_error(c, ngx_socket_errno, "getsockname() failed"); return NGX_ERROR; } c->local_sockaddr = ngx_palloc(c->pool, len); if (c->local_sockaddr == NULL) { return NGX_ERROR; } ngx_memcpy(c->local_sockaddr, &sa, len); c->local_socklen = len; } if (s == NULL) { return NGX_OK; } s->len = ngx_sock_ntop(c->local_sockaddr, c->local_socklen, s->data, s->len, port); return NGX_OK; }
static int ngx_http_lua_ngx_req_set_body_data(lua_State *L) { ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; ngx_temp_file_t *tf; ngx_buf_t *b; ngx_str_t body, key, value; #if 1 ngx_int_t rc; #endif ngx_chain_t *cl; ngx_buf_tag_t tag; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "expecting 1 arguments but seen %d", n); } body.data = (u_char *) luaL_checklstring(L, 1, &body.len); 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, "request object not found"); } if (r->discard_body) { return luaL_error(L, "request body already discarded asynchronously"); } if (r->request_body == NULL) { return luaL_error(L, "request body not read yet"); } rb = r->request_body; tag = (ngx_buf_tag_t) &ngx_http_lua_module; tf = rb->temp_file; if (tf) { if (tf->file.fd != NGX_INVALID_FILE) { dd("cleaning temp file %.*s", (int) tf->file.name.len, tf->file.name.data); ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd); tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, tf->file.name.data); } rb->temp_file = NULL; } if (body.len == 0) { if (rb->bufs) { for (cl = rb->bufs; cl; cl = cl->next) { if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; cl->buf->temporary = 0; } } } rb->bufs = NULL; rb->buf = NULL; dd("request body is set to empty string"); goto set_header; } if (rb->bufs) { for (cl = rb->bufs; cl; cl = cl->next) { if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; cl->buf->temporary = 0; } } rb->bufs->next = NULL; b = rb->bufs->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->temporary = 1; b->tag = tag; b->start = ngx_palloc(r->pool, body.len); if (b->start == NULL) { return luaL_error(L, "out of memory"); } b->end = b->start + body.len; b->pos = b->start; b->last = ngx_copy(b->pos, body.data, body.len); } else { rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return luaL_error(L, "out of memory"); } rb->bufs->next = NULL; b = ngx_create_temp_buf(r->pool, body.len); b->tag = tag; b->last = ngx_copy(b->pos, body.data, body.len); rb->bufs->buf = b; rb->buf = b; } set_header: /* override input header Content-Length (value must be null terminated) */ value.data = ngx_palloc(r->pool, NGX_SIZE_T_LEN + 1); if (value.data == NULL) { return luaL_error(L, "out of memory"); } value.len = ngx_sprintf(value.data, "%uz", body.len) - value.data; value.data[value.len] = '\0'; dd("setting request Content-Length to %.*s (%d)", (int) value.len, value.data, (int) body.len); r->headers_in.content_length_n = body.len; if (r->headers_in.content_length) { r->headers_in.content_length->value.data = value.data; r->headers_in.content_length->value.len = value.len; } else { ngx_str_set(&key, "Content-Length"); rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc != NGX_OK) { return luaL_error(L, "failed to reset the Content-Length " "input header"); } } return 0; }
static char * ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) { ngx_uint_t i, p, last, bind_wildcard; ngx_listening_t *ls; ngx_mail_port_t *mport; ngx_mail_conf_port_t *port; ngx_mail_conf_addr_t *addr; port = ports->elts; for (p = 0; p < ports->nelts; p++) { ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts, sizeof(ngx_mail_conf_addr_t), ngx_mail_cmp_conf_addrs); addr = port[p].addrs.elts; last = port[p].addrs.nelts; /* * if there is the binding to the "*:port" then we need to bind() * to the "*:port" only and ignore the other bindings */ if (addr[last - 1].wildcard) { addr[last - 1].bind = 1; bind_wildcard = 1; } else { bind_wildcard = 0; } i = 0; while (i < last) { if (bind_wildcard && !addr[i].bind) { i++; continue; } ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen); if (ls == NULL) { return NGX_CONF_ERROR; } ls->addr_ntop = 1; ls->handler = ngx_mail_init_connection; ls->pool_size = 256; /* TODO: error_log directive */ ls->logp = &cf->cycle->new_log; ls->log.data = &ls->addr_text; ls->log.handler = ngx_accept_log_error; ls->keepalive = addr[i].so_keepalive; #if (NGX_HAVE_KEEPALIVE_TUNABLE) ls->keepidle = addr[i].tcp_keepidle; ls->keepintvl = addr[i].tcp_keepintvl; ls->keepcnt = addr[i].tcp_keepcnt; #endif #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) ls->ipv6only = addr[i].ipv6only; #endif mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t)); if (mport == NULL) { return NGX_CONF_ERROR; } ls->servers = mport; if (i == last - 1) { mport->naddrs = last; } else { mport->naddrs = 1; i = 0; } switch (ls->sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: if (ngx_mail_add_addrs6(cf, mport, addr) != NGX_OK) { return NGX_CONF_ERROR; } break; #endif default: /* AF_INET */ if (ngx_mail_add_addrs(cf, mport, addr) != NGX_OK) { return NGX_CONF_ERROR; } break; } addr++; last--; } } return NGX_CONF_OK; }
static int ngx_http_lua_ngx_req_set_body_file(lua_State *L) { u_char *p; ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; ngx_temp_file_t *tf; ngx_buf_t *b; ngx_str_t name; ngx_int_t rc; int clean; ngx_open_file_info_t of; ngx_str_t key, value; ngx_pool_cleanup_t *cln; ngx_pool_cleanup_file_t *clnf; ngx_err_t err; ngx_chain_t *cl; ngx_buf_tag_t tag; n = lua_gettop(L); if (n != 1 && n != 2) { return luaL_error(L, "expecting 1 or 2 arguments but seen %d", n); } p = (u_char *) luaL_checklstring(L, 1, &name.len); 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, "request object not found"); } if (r->discard_body) { return luaL_error(L, "request body already discarded asynchronously"); } if (r->request_body == NULL) { return luaL_error(L, "request body not read yet"); } name.data = ngx_palloc(r->pool, name.len + 1); if (name.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(name.data, p, name.len); name.data[name.len] = '\0'; if (n == 2) { luaL_checktype(L, 2, LUA_TBOOLEAN); clean = lua_toboolean(L, 2); } else { clean = 0; } dd("clean: %d", (int) clean); rb = r->request_body; /* clean up existing r->request_body->bufs (if any) */ tag = (ngx_buf_tag_t) &ngx_http_lua_module; if (rb->bufs) { dd("XXX reusing buf"); for (cl = rb->bufs; cl; cl = cl->next) { if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; cl->buf->temporary = 0; } } rb->bufs->next = NULL; b = rb->bufs->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->tag = tag; } else { dd("XXX creating new buf"); rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return luaL_error(L, "out of memory"); } rb->bufs->next = NULL; b = ngx_calloc_buf(r->pool); if (b == NULL) { return luaL_error(L, "out of memory"); } b->tag = tag; rb->bufs->buf = b; rb->buf = b; } b->last_in_chain = 1; /* just make r->request_body->temp_file a bare stub */ tf = rb->temp_file; if (tf) { if (tf->file.fd != NGX_INVALID_FILE) { dd("cleaning temp file %.*s", (int) tf->file.name.len, tf->file.name.data); ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd); ngx_memzero(tf, sizeof(ngx_temp_file_t)); tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, tf->file.name.data); } } else { tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { return luaL_error(L, "out of memory"); } tf->file.fd = NGX_INVALID_FILE; rb->temp_file = tf; } /* read the file info and construct an in-file buf */ ngx_memzero(&of, sizeof(ngx_open_file_info_t)); if (ngx_http_lua_open_and_stat_file(name.data, &of, r->connection->log) != NGX_OK) { return luaL_error(L, "%s \"%s\" failed", of.failed, name.data); } dd("XXX new body file fd: %d", of.fd); tf->file.fd = of.fd; tf->file.name = name; tf->file.log = r->connection->log; /* FIXME we should not always set directio here */ tf->file.directio = 1; if (of.size == 0) { if (clean) { if (ngx_delete_file(name.data) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_delete_file_n " \"%s\" failed", name.data); } } } if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } r->request_body->bufs = NULL; r->request_body->buf = NULL; goto set_header; } /* register file cleanup hook */ cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t)); if (cln == NULL) { return luaL_error(L, "out of memory"); } cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file; clnf = cln->data; clnf->fd = of.fd; clnf->name = name.data; clnf->log = r->pool->log; b->file = &tf->file; if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } dd("XXX file size: %d", (int) of.size); b->file_pos = 0; b->file_last = of.size; b->in_file = 1; dd("buf file: %p, f:%u", b->file, b->in_file); set_header: /* override input header Content-Length (value must be null terminated) */ value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN + 1); if (value.data == NULL) { return luaL_error(L, "out of memory"); } value.len = ngx_sprintf(value.data, "%O", of.size) - value.data; value.data[value.len] = '\0'; r->headers_in.content_length_n = of.size; if (r->headers_in.content_length) { r->headers_in.content_length->value.data = value.data; r->headers_in.content_length->value.len = value.len; } else { ngx_str_set(&key, "Content-Length"); rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc != NGX_OK) { return luaL_error(L, "failed to reset the Content-Length " "input header"); } } return 0; }
ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) { u_char *elts; size_t len; u_short *test; ngx_uint_t i, n, key, size, start, bucket_size; ngx_hash_elt_t *elt, **buckets; for (n = 0; n < nelts; n++) { if (names[n].key.len >= 255) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "the \"%V\" value to hash is to long: %uz bytes, " "the maximum length can be 255 bytes only", &names[n].key, names[n].key.len); return NGX_ERROR; } if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "could not build the %s, you should " "increase %s_bucket_size: %i", hinit->name, hinit->name, hinit->bucket_size); return NGX_ERROR; } } test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log); if (test == NULL) { return NGX_ERROR; } bucket_size = hinit->bucket_size - sizeof(void *); start = nelts / (bucket_size / (2 * sizeof(void *))); start = start ? start : 1; if (hinit->max_size > 10000 && hinit->max_size / nelts < 100) { start = hinit->max_size - 1000; } for (size = start; size < hinit->max_size; size++) { ngx_memzero(test, size * sizeof(u_short)); for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); #if 0 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: %ui %ui \"%V\"", size, key, test[key], &names[n].key); #endif if (test[key] > (u_short) bucket_size) { goto next; } } goto found; next: continue; } ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "could not build the %s, you should increase " "either %s_max_size: %i or %s_bucket_size: %i", hinit->name, hinit->name, hinit->max_size, hinit->name, hinit->bucket_size); ngx_free(test); return NGX_ERROR; found: for (i = 0; i < size; i++) { test[i] = sizeof(void *); } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } len = 0; for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size)); len += test[i]; } if (hinit->hash == NULL) { hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t) + size * sizeof(ngx_hash_elt_t *)); if (hinit->hash == NULL) { ngx_free(test); return NGX_ERROR; } buckets = (ngx_hash_elt_t **) ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t)); } else { buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *)); if (buckets == NULL) { ngx_free(test); return NGX_ERROR; } } elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size); if (elts == NULL) { ngx_free(test); return NGX_ERROR; } elts = ngx_align_ptr(elts, ngx_cacheline_size); for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } buckets[i] = (ngx_hash_elt_t *) elts; elts += test[i]; } for (i = 0; i < size; i++) { test[i] = 0; } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]); elt->value = names[n].value; elt->len = (u_char) names[n].key.len; for (i = 0; i < names[n].key.len; i++) { elt->name[i] = ngx_tolower(names[n].key.data[i]); } test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } for (i = 0; i < size; i++) { if (buckets[i] == NULL) { continue; } elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]); elt->value = NULL; } ngx_free(test); hinit->hash->buckets = buckets; hinit->hash->size = size; #if 0 for (i = 0; i < size; i++) { ngx_str_t val; ngx_uint_t key; elt = buckets[i]; if (elt == NULL) { ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: NULL", i); continue; } while (elt->value) { val.len = elt->len; val.data = &elt->name[0]; key = hinit->key(val.data, val.len); ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: %p \"%V\" %ui", i, elt, &val, key); elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len, sizeof(void *)); } } #endif return NGX_OK; }
static void ngx_http_graphicsmagick_command_handler(ngx_http_request_t *r) { ngx_str_t *source; ngx_str_t *dest; ngx_str_t *ai; ngx_str_t *cmd; ngx_str_t *uri; ngx_array_t *tokens; ngx_int_t rc; ngx_uint_t i; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_fd_t fd; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; size_t argc; char **argv; u_char *cp; u_char *last; size_t root; ngx_temp_file_t *tf; unsigned int status; log = r->connection->log; tokens = ngx_array_create(r->pool, 10, sizeof(ngx_str_t)); if (tokens == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai = ngx_array_push(tokens); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai->data = (u_char *) "convert"; ai->len = 7; // get command from HTTP headers or queryString cmd = ngx_http_graphicsmagick_get_command(r); if (cmd == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ngx_log_error(NGX_LOG_ERR, log, 0, "graphicsmagick convert command: \"%s\"", cmd->data); //ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, // "graphicsmagick convert command: \"%s\"", cmd->data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->method & NGX_HTTP_POST) { source = dest = &r->request_body->temp_file->file.name; } else { uri = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); source = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); cp = cmd->data; while (cp < cmd->data + cmd->len) { if (*cp == ' ') { uri->data = cmd->data; uri->len = cp - cmd->data; cmd->data = cp + 1; cmd->len = cmd->len - uri->len - 1; break; } cp++; } if (uri->len == 0) { ngx_http_graphicsmagick_server_error(r); return; } last = ngx_http_graphicsmagickd_map_uri_to_path(r, uri, source, &root, 0); if (last == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } source->len = last - source->data; tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } tf->file.fd = NGX_INVALID_FILE; tf->file.log = r->connection->log; tf->path = clcf->client_body_temp_path; tf->pool = r->pool; tf->log_level = r->request_body_file_log_level; tf->persistent = r->request_body_in_persistent_file; tf->clean = 1; if (r->request_body_file_group_access) { tf->access = 0660; } if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access) != NGX_OK) { ngx_http_graphicsmagick_server_error(r); return; } dest = &tf->file.name; } // push source file name into tokens ai = ngx_array_push(tokens); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } *ai = *source; // tokenize command, and push them into tokens array rc = ngx_http_graphicsmagick_tokenize_command(r, cmd, tokens); if (rc == NGX_ERROR) { ngx_http_graphicsmagick_server_error(r); return; } ai = ngx_array_push_n(tokens, 2); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai->data = (u_char *) "-compress"; ai->len = 9; ai++; ai->data = (u_char *) "JPEG"; ai->len = 4; // push dest filename into tokens again, to save generated thumbnail into dest file ai = ngx_array_push(tokens); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } *ai = *dest; // OK, prepare convert args argc = tokens->nelts; argv = ngx_palloc(r->pool, argc * sizeof(char*)); if (argv == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai = tokens->elts; for (i = 0; i < argc; i++) { argv[i] = (char *) ai[i].data; ngx_log_error(NGX_LOG_ERR, log, 0, "current[%d]: %s", i, argv[i]); } ngx_array_destroy(tokens); // DO graphicsmagick converting status = ngx_http_graphicsmagick_convert(argv, argc); if (status == 0) { ngx_http_graphicsmagick_server_error(r); return; } // Done, write response of.test_dir = 0; //of.retest = clcf->open_file_cache_retest; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; rc = ngx_open_cached_file(clcf->open_file_cache, dest, &of, r->pool); if (rc == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, log, of.err, "failed to open file \"%s\"", dest->data); ngx_http_graphicsmagick_server_error(r); return; } fd = of.fd; log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_type.len = sizeof("image/jpeg") - 1; r->headers_out.content_type.data = (u_char *) "image/jpeg"; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; if (r != r->main && of.size == 0) { rc = ngx_http_send_header(r); ngx_http_finalize_request(r, rc); return; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { ngx_http_graphicsmagick_server_error(r); return; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { ngx_http_graphicsmagick_server_error(r); return; } rc = ngx_http_send_header(r); b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = fd; b->file->name = *dest; b->file->log = log; out.buf = b; out.next = NULL; rc = ngx_http_output_filter(r, &out); ngx_http_finalize_request(r, rc); return; }
ngx_int_t ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, void *value, ngx_uint_t flags) { size_t len; u_char *p; ngx_str_t *name; ngx_uint_t i, k, n, skip, last; ngx_array_t *keys, *hwc; ngx_hash_key_t *hk; last = key->len; if (flags & NGX_HASH_WILDCARD_KEY) { /* * supported wildcards: * "*.example.com", ".example.com", and "www.example.*" */ n = 0; for (i = 0; i < key->len; i++) { if (key->data[i] == '*') { if (++n > 1) { return NGX_DECLINED; } } if (key->data[i] == '.' && key->data[i + 1] == '.') { return NGX_DECLINED; } } if (key->len > 1 && key->data[0] == '.') { skip = 1; goto wildcard; } if (key->len > 2) { if (key->data[0] == '*' && key->data[1] == '.') { skip = 2; goto wildcard; } if (key->data[i - 2] == '.' && key->data[i - 1] == '*') { skip = 0; last -= 2; goto wildcard; } } if (n) { return NGX_DECLINED; } } /* exact hash */ k = 0; for (i = 0; i < last; i++) { if (!(flags & NGX_HASH_READONLY_KEY)) { key->data[i] = ngx_tolower(key->data[i]); } k = ngx_hash(k, key->data[i]); } k %= ha->hsize; /* check conflicts in exact hash */ name = ha->keys_hash[k].elts; if (name) { for (i = 0; i < ha->keys_hash[k].nelts; i++) { if (last != name[i].len) { continue; } if (ngx_strncmp(key->data, name[i].data, last) == 0) { return NGX_BUSY; } } } else { if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4, sizeof(ngx_str_t)) != NGX_OK) { return NGX_ERROR; } } name = ngx_array_push(&ha->keys_hash[k]); if (name == NULL) { return NGX_ERROR; } *name = *key; hk = ngx_array_push(&ha->keys); if (hk == NULL) { return NGX_ERROR; } hk->key = *key; hk->key_hash = ngx_hash_key(key->data, last); hk->value = value; return NGX_OK; wildcard: /* wildcard hash */ k = 0; for (i = skip; i < last; i++) { key->data[i] = ngx_tolower(key->data[i]); k = ngx_hash(k, key->data[i]); } k %= ha->hsize; if (skip == 1) { /* check conflicts in exact hash for ".example.com" */ name = ha->keys_hash[k].elts; if (name) { len = last - skip; for (i = 0; i < ha->keys_hash[k].nelts; i++) { if (len != name[i].len) { continue; } if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) { return NGX_BUSY; } } } else { if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4, sizeof(ngx_str_t)) != NGX_OK) { return NGX_ERROR; } } name = ngx_array_push(&ha->keys_hash[k]); if (name == NULL) { return NGX_ERROR; } name->len = last - 1; name->data = ngx_palloc(ha->temp_pool, name->len); if (name->data == NULL) { return NGX_ERROR; } ngx_memcpy(name->data, &key->data[1], name->len); } if (skip) { /* * convert "*.example.com" to "com.example.\0" * and ".example.com" to "com.example\0" */ p = ngx_palloc(ha->temp_pool, last); if (p == NULL) { return NGX_ERROR; } len = 0; n = 0; for (i = last - 1; i; i--) { if (key->data[i] == '.') { ngx_memcpy(&p[n], &key->data[i + 1], len); n += len; p[n++] = '.'; len = 0; continue; } len++; } if (len) { ngx_memcpy(&p[n], &key->data[1], len); n += len; } p[n] = '\0'; hwc = &ha->dns_wc_head; keys = &ha->dns_wc_head_hash[k]; } else { /* convert "www.example.*" to "www.example\0" */ last++; p = ngx_palloc(ha->temp_pool, last); if (p == NULL) { return NGX_ERROR; } ngx_cpystrn(p, key->data, last); hwc = &ha->dns_wc_tail; keys = &ha->dns_wc_tail_hash[k]; } hk = ngx_array_push(hwc); if (hk == NULL) { return NGX_ERROR; } hk->key.len = last - 1; hk->key.data = p; hk->key_hash = 0; hk->value = value; /* check conflicts in wildcard hash */ name = keys->elts; if (name) { len = last - skip; for (i = 0; i < keys->nelts; i++) { if (len != name[i].len) { continue; } if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) { return NGX_BUSY; } } } else { if (ngx_array_init(keys, ha->temp_pool, 4, sizeof(ngx_str_t)) != NGX_OK) { return NGX_ERROR; } } name = ngx_array_push(keys); if (name == NULL) { return NGX_ERROR; } name->len = last - skip; name->data = ngx_palloc(ha->temp_pool, name->len); if (name->data == NULL) { return NGX_ERROR; } ngx_memcpy(name->data, key->data + skip, name->len); return NGX_OK; }
ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle) { size_t len; ngx_uint_t i; ngx_listening_t *ls; socklen_t olen; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) ngx_err_t err; struct accept_filter_arg af; #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) int timeout; #endif ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].sockaddr = ngx_palloc(cycle->pool, NGX_SOCKADDRLEN); if (ls[i].sockaddr == NULL) { return NGX_ERROR; } ls[i].socklen = NGX_SOCKADDRLEN; if (getsockname(ls[i].fd, ls[i].sockaddr, &ls[i].socklen) == -1) { ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, "getsockname() of the inherited " "socket #%d failed", ls[i].fd); ls[i].ignore = 1; continue; } switch (ls[i].sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN; len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1; break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN; len = NGX_UNIX_ADDRSTRLEN; break; #endif case AF_INET: ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN; len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; break; default: ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, "the inherited socket #%d has " "an unsupported protocol family", ls[i].fd); ls[i].ignore = 1; continue; } ls[i].addr_text.data = ngx_pnalloc(cycle->pool, len); if (ls[i].addr_text.data == NULL) { return NGX_ERROR; } len = ngx_sock_ntop(ls[i].sockaddr, ls[i].addr_text.data, len, 1); if (len == 0) { return NGX_ERROR; } ls[i].addr_text.len = len; ls[i].backlog = NGX_LISTEN_BACKLOG; olen = sizeof(int); if (getsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (void *) &ls[i].rcvbuf, &olen) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "getsockopt(SO_RCVBUF) %V failed, ignored", &ls[i].addr_text); ls[i].rcvbuf = -1; } olen = sizeof(int); if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF, (void *) &ls[i].sndbuf, &olen) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "getsockopt(SO_SNDBUF) %V failed, ignored", &ls[i].addr_text); ls[i].sndbuf = -1; } #if 0 /* SO_SETFIB is currently a set only option */ #if (NGX_HAVE_SETFIB) if (getsockopt(ls[i].setfib, SOL_SOCKET, SO_SETFIB, (void *) &ls[i].setfib, &olen) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "getsockopt(SO_SETFIB) %V failed, ignored", &ls[i].addr_text); ls[i].setfib = -1; } #endif #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) ngx_memzero(&af, sizeof(struct accept_filter_arg)); olen = sizeof(struct accept_filter_arg); if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen) == -1) { err = ngx_errno; if (err == NGX_EINVAL) { continue; } ngx_log_error(NGX_LOG_NOTICE, cycle->log, err, "getsockopt(SO_ACCEPTFILTER) for %V failed, ignored", &ls[i].addr_text); continue; } if (olen < sizeof(struct accept_filter_arg) || af.af_name[0] == '\0') { continue; } ls[i].accept_filter = ngx_palloc(cycle->pool, 16); if (ls[i].accept_filter == NULL) { return NGX_ERROR; } (void) ngx_cpystrn((u_char *) ls[i].accept_filter, (u_char *) af.af_name, 16); #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) timeout = 0; olen = sizeof(int); if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen) == -1) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, ngx_errno, "getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored", &ls[i].addr_text); continue; } if (olen < sizeof(int) || timeout == 0) { continue; } ls[i].deferred_accept = 1; #endif } return NGX_OK; }
static ngx_int_t ngx_http_fancyindex_handler(ngx_http_request_t *r) { ngx_http_request_t *sr; ngx_str_t *sr_uri; ngx_str_t rel_uri; ngx_int_t rc; ngx_http_fancyindex_loc_conf_t *alcf; ngx_chain_t out[3] = { { NULL, NULL }, { NULL, NULL}, { NULL, NULL }}; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } /* TODO: Win32 */ if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } alcf = ngx_http_get_module_loc_conf(r, ngx_http_fancyindex_module); if (!alcf->enable) { return NGX_DECLINED; } if ((rc = make_content_buf(r, &out[0].buf, alcf) != NGX_OK)) return rc; out[0].buf->last_in_chain = 1; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_type_len = ngx_sizeof_ssz("text/html"); r->headers_out.content_type.len = ngx_sizeof_ssz("text/html"); r->headers_out.content_type.data = (u_char *) "text/html"; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } if (alcf->header.len > 0) { /* URI is configured, make Nginx take care of with a subrequest. */ sr_uri = &alcf->header; if (*sr_uri->data != '/') { /* Relative path */ rel_uri.len = r->uri.len + alcf->header.len; rel_uri.data = ngx_palloc(r->pool, rel_uri.len); if (rel_uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_memcpy(ngx_cpymem(rel_uri.data, r->uri.data, r->uri.len), alcf->header.data, alcf->header.len); sr_uri = &rel_uri; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: header subrequest \"%V\"", sr_uri); rc = ngx_http_subrequest(r, sr_uri, NULL, &sr, NULL, 0); if (rc == NGX_ERROR || rc == NGX_DONE) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: header subrequest for \"%V\" failed", sr_uri); return rc; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: header subrequest status = %i", sr->headers_out.status); if (sr->headers_out.status != NGX_HTTP_OK) { /* * XXX: Should we write a message to the error log just in case * we get something different from a 404? */ goto add_builtin_header; } } else { add_builtin_header: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: adding built-in header"); /* Make space before */ out[1].next = out[0].next; out[1].buf = out[0].buf; /* Chain header buffer */ out[0].next = &out[1]; out[0].buf = make_header_buf(r); } /* If footer is disabled, chain up footer buffer. */ if (alcf->footer.len == 0) { ngx_uint_t last = (alcf->header.len == 0) ? 2 : 1; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: adding built-in footer at %i", last); out[last-1].next = &out[last]; out[last].buf = make_footer_buf(r); out[last-1].buf->last_in_chain = 0; out[last].buf->last_in_chain = 1; out[last].buf->last_buf = 1; /* Send everything with a single call :D */ return ngx_http_output_filter(r, &out[0]); } /* * If we reach here, we were asked to send a custom footer. We need to: * partially send whatever is referenced from out[0] and then send the * footer as a subrequest. If the subrequest fails, we should send the * standard footer as well. */ rc = ngx_http_output_filter(r, &out[0]); if (rc != NGX_OK && rc != NGX_AGAIN) return NGX_HTTP_INTERNAL_SERVER_ERROR; /* URI is configured, make Nginx take care of with a subrequest. */ sr_uri = &alcf->footer; if (*sr_uri->data != '/') { /* Relative path */ rel_uri.len = r->uri.len + alcf->footer.len; rel_uri.data = ngx_palloc(r->pool, rel_uri.len); if (rel_uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_memcpy(ngx_cpymem(rel_uri.data, r->uri.data, r->uri.len), alcf->footer.data, alcf->footer.len); sr_uri = &rel_uri; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: footer subrequest \"%V\"", sr_uri); rc = ngx_http_subrequest(r, sr_uri, NULL, &sr, NULL, 0); if (rc == NGX_ERROR || rc == NGX_DONE) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: footer subrequest for \"%V\" failed", sr_uri); return rc; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: header subrequest status = %i", sr->headers_out.status); if (sr->headers_out.status != NGX_HTTP_OK) { /* * XXX: Should we write a message to the error log just in case * we get something different from a 404? */ out[0].next = NULL; out[0].buf = make_footer_buf(r); out[0].buf->last_in_chain = 1; out[0].buf->last_buf = 1; /* Directly send out the builtin footer */ return ngx_http_output_filter(r, &out[0]); } return (r != r->main) ? rc : ngx_http_send_special(r, NGX_HTTP_LAST); }