static ngx_int_t ngx_http_vhost_traffic_status_display_handler_default(ngx_http_request_t *r) { size_t len; u_char *o, *s; ngx_str_t uri, type; ngx_int_t size, format, rc; ngx_buf_t *b; ngx_chain_t out; ngx_slab_pool_t *shpool; ngx_http_vhost_traffic_status_ctx_t *ctx; ngx_http_vhost_traffic_status_loc_conf_t *vtscf; ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); if (!ctx->enable) { return NGX_HTTP_NOT_IMPLEMENTED; } if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { return NGX_HTTP_NOT_ALLOWED; } uri = r->uri; format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_NONE; if (uri.len == 1) { if (ngx_strncmp(uri.data, "/", 1) == 0) { uri.len = 0; } } o = (u_char *) r->uri.data; s = o; len = r->uri.len; while(sizeof("/format/type") - 1 <= len) { if (ngx_strncasecmp(s, (u_char *) "/format/", sizeof("/format/") - 1) == 0) { uri.data = o; uri.len = (o == s) ? 0 : (size_t) (s - o); s += sizeof("/format/") - 1; if (ngx_strncasecmp(s, (u_char *) "jsonp", sizeof("jsonp") - 1) == 0) { format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP; } else if (ngx_strncasecmp(s, (u_char *) "json", sizeof("json") - 1) == 0) { format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON; } else if (ngx_strncasecmp(s, (u_char *) "html", sizeof("html") - 1) == 0) { format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_HTML; } else if (ngx_strncasecmp(s, (u_char *) "prometheus", sizeof("prometheus") - 1) == 0) { format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS; } else { s -= 2; } if (format != NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_NONE) { break; } } if ((s = (u_char *) ngx_strchr(++s, '/')) == NULL) { break; } if (r->uri.len <= (size_t) (s - o)) { break; } len = r->uri.len - (size_t) (s - o); } format = (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_NONE) ? vtscf->format : format; rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON) { ngx_str_set(&type, "application/json"); } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP) { ngx_str_set(&type, "application/javascript"); } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS) { ngx_str_set(&type, "text/plain"); } else { ngx_str_set(&type, "text/html"); } r->headers_out.content_type_len = type.len; r->headers_out.content_type = type; if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } } size = ngx_http_vhost_traffic_status_display_get_size(r, format); if (size == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "display_handler_default::display_get_size() failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON) { shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); b->last = ngx_http_vhost_traffic_status_display_set(r, b->last); ngx_shmtx_unlock(&shpool->mutex); if (b->last == b->pos) { b->last = ngx_sprintf(b->last, "{}"); } } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP) { shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); b->last = ngx_sprintf(b->last, "%V", &vtscf->jsonp); b->last = ngx_sprintf(b->last, "("); b->last = ngx_http_vhost_traffic_status_display_set(r, b->last); b->last = ngx_sprintf(b->last, ")"); ngx_shmtx_unlock(&shpool->mutex); } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS) { shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); b->last = ngx_http_vhost_traffic_status_display_prometheus_set(r, b->last); ngx_shmtx_unlock(&shpool->mutex); if (b->last == b->pos) { b->last = ngx_sprintf(b->last, "#"); } } else { b->last = ngx_sprintf(b->last, NGX_HTTP_VHOST_TRAFFIC_STATUS_HTML_DATA, &uri, &uri); } r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = b->last - b->pos; b->last_buf = (r == r->main) ? 1 : 0; /* if subrequest 0 else 1 */ b->last_in_chain = 1; out.buf = b; out.next = NULL; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_tfs_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_tfs_t *t; ngx_http_tfs_loc_conf_t *tlcf; ngx_http_tfs_srv_conf_t *tscf; ngx_http_tfs_main_conf_t *tmcf; tlcf = ngx_http_get_module_loc_conf(r, ngx_http_tfs_module); tscf = ngx_http_get_module_srv_conf(r, ngx_http_tfs_module); tmcf = ngx_http_get_module_main_conf(r, ngx_http_tfs_module); t = ngx_pcalloc(r->pool, sizeof(ngx_http_tfs_t)); if (t == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "alloc ngx_http_tfs_t failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } t->pool = r->pool; t->data = r; t->log = r->connection->log; t->loc_conf = tlcf; t->srv_conf = tscf; t->main_conf = tmcf; t->output.tag = (ngx_buf_tag_t) &ngx_http_tfs_module; if (tmcf->local_block_cache_ctx != NULL) { t->block_cache_ctx.use_cache |= NGX_HTTP_TFS_LOCAL_BLOCK_CACHE; t->block_cache_ctx.local_ctx = tmcf->local_block_cache_ctx; } if (tmcf->enable_remote_block_cache == NGX_HTTP_TFS_YES) { t->block_cache_ctx.use_cache |= NGX_HTTP_TFS_REMOTE_BLOCK_CACHE; } t->block_cache_ctx.remote_ctx.data = t; t->block_cache_ctx.remote_ctx.tair_instance = &tmcf->remote_block_cache_instance; t->block_cache_ctx.curr_lookup_cache = NGX_HTTP_TFS_LOCAL_BLOCK_CACHE; rc = ngx_http_restful_parse(r, &t->r_ctx); if (rc != NGX_OK) { return rc; } t->header_only = r->header_only; if (!t->loc_conf->upstream->enable_rcs && t->r_ctx.version == 2) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "custom file requires tfs_enable_rcs on," " and make sure you have MetaServer and RootServer!"); return NGX_HTTP_BAD_REQUEST; } switch (t->r_ctx.action.code) { case NGX_HTTP_TFS_ACTION_CREATE_DIR: case NGX_HTTP_TFS_ACTION_CREATE_FILE: case NGX_HTTP_TFS_ACTION_REMOVE_DIR: case NGX_HTTP_TFS_ACTION_REMOVE_FILE: case NGX_HTTP_TFS_ACTION_MOVE_DIR: case NGX_HTTP_TFS_ACTION_MOVE_FILE: case NGX_HTTP_TFS_ACTION_LS_DIR: case NGX_HTTP_TFS_ACTION_LS_FILE: case NGX_HTTP_TFS_ACTION_STAT_FILE: case NGX_HTTP_TFS_ACTION_KEEPALIVE: case NGX_HTTP_TFS_ACTION_READ_FILE: case NGX_HTTP_TFS_ACTION_GET_APPID: rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } r->headers_out.content_length_n = -1; ngx_http_set_ctx(r, t, ngx_http_tfs_module); r->main->count++; ngx_http_tfs_read_body_handler(r); break; case NGX_HTTP_TFS_ACTION_WRITE_FILE: r->headers_out.content_length_n = -1; ngx_http_set_ctx(r, t, ngx_http_tfs_module); rc = ngx_http_read_client_request_body(r, ngx_http_tfs_read_body_handler); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } break; } return NGX_DONE; }
void ngx_http_lua_wev_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_lua_ctx_t *ctx; ngx_http_lua_main_conf_t *lmcf; lua_State *cc; ngx_chain_t *cl; size_t len; u_char *pos, *last; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { goto error; } dd("request done: %d", (int) r->done); dd("cleanup done: %p", ctx->cleanup); #if 1 if (ctx->cleanup == NULL) { return; } #endif if (ctx->waiting && ! ctx->done) { if (r->main->posted_requests && r->main->posted_requests->request != r) { dd("postpone our wev handler"); #if defined(nginx_version) && nginx_version >= 8012 ngx_http_post_request(r, NULL); #else ngx_http_post_request(r); #endif return; } } ctx->done = 0; len = 0; for (cl = ctx->sr_body; cl; cl = cl->next) { /* ignore all non-memory buffers */ len += cl->buf->last - cl->buf->pos; } if (len == 0) { pos = NULL; } else { last = pos = ngx_palloc(r->pool, len); if (pos == NULL) { goto error; } for (cl = ctx->sr_body; cl; cl = cl->next) { /* ignore all non-memory buffers */ last = ngx_copy(last, cl->buf->pos, cl->buf->last - cl->buf->pos); } } cc = ctx->cc; /* {{{ construct ret value */ lua_newtable(cc); /* copy captured status */ lua_pushinteger(cc, ctx->sr_status); lua_setfield(cc, -2, "status"); /* copy captured body */ lua_pushlstring(cc, (const char*)pos, len); lua_setfield(cc, -2, "body"); /* }}} */ lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); dd("about to run thread..."); rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 1); dd("already run thread..."); if (rc == NGX_AGAIN || rc == NGX_DONE) { ctx->waiting = 1; ctx->done = 0; } else { ctx->waiting = 0; ctx->done = 1; ngx_http_finalize_request(r, rc); } return; error: ngx_http_finalize_request(r, ctx->headers_sent ? NGX_ERROR: NGX_HTTP_INTERNAL_SERVER_ERROR); return; }
static int ngx_http_lua_ngx_re_match(lua_State *L) { /* u_char *p; */ ngx_http_request_t *r; ngx_str_t subj; ngx_str_t pat; ngx_str_t opts; ngx_lua_regex_compile_t re_comp; ngx_http_lua_regex_t *re; const char *msg; ngx_int_t rc; ngx_uint_t n; int i; ngx_int_t pos = 0; int nargs; int *cap = NULL; int ovecsize; ngx_uint_t flags; ngx_pool_t *pool, *old_pool; ngx_http_lua_main_conf_t *lmcf = NULL; u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; pcre_extra *sd = NULL; nargs = lua_gettop(L); if (nargs != 2 && nargs != 3 && nargs != 4) { return luaL_error(L, "expecting two or three or four arguments, " "but got %d", nargs); } 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"); } subj.data = (u_char *) luaL_checklstring(L, 1, &subj.len); pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len); ngx_memzero(&re_comp, sizeof(ngx_lua_regex_compile_t)); if (nargs >= 3) { opts.data = (u_char *) luaL_checklstring(L, 3, &opts.len); if (nargs == 4) { luaL_checktype(L, 4, LUA_TTABLE); lua_getfield(L, 4, "pos"); if (lua_isnumber(L, -1)) { pos = (ngx_int_t) lua_tointeger(L, -1); if (pos < 0) { pos = 0; } } else if (lua_isnil(L, -1)) { pos = 0; } else { msg = lua_pushfstring(L, "bad pos field type in the ctx table " "argument: %s", luaL_typename(L, -1)); return luaL_argerror(L, 4, msg); } lua_pop(L, 1); } } else { opts.data = (u_char *) ""; opts.len = 0; } re_comp.options = 0; flags = ngx_http_lua_ngx_re_parse_opts(L, &re_comp, &opts, 3); if (flags & NGX_LUA_RE_COMPILE_ONCE) { lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); pool = lmcf->pool; dd("server pool %p", lmcf->pool); lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); lua_pushvalue(L, 2); /* table regex */ dd("options size: %d", (int) sizeof(re_comp.options)); lua_pushlstring(L, (char *) &re_comp.options, sizeof(re_comp.options)); /* table regex opts */ lua_concat(L, 3); /* table key */ lua_pushvalue(L, -1); /* table key key */ dd("regex cache key: %.*s", (int) (pat.len + sizeof(re_comp.options)), lua_tostring(L, -1)); lua_rawget(L, -3); /* table key re */ re = lua_touserdata(L, -1); lua_pop(L, 1); /* table key */ if (re) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua regex cache hit for match regex \"%s\" with " "options \"%s\"", pat.data, opts.data); lua_pop(L, 2); dd("restoring regex %p, ncaptures %d, captures %p", re->regex, re->ncaptures, re->captures); re_comp.regex = re->regex; sd = re->regex_sd; re_comp.captures = re->ncaptures; cap = re->captures; if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; } else { ovecsize = (re->ncaptures + 1) * 3; } goto exec; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua regex cache miss for match regex \"%s\" " "with options \"%s\"", pat.data, opts.data); if (lmcf->regex_cache_entries >= lmcf->regex_cache_max_entries) { if (lmcf->regex_cache_entries == lmcf->regex_cache_max_entries) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "lua exceeding regex cache max entries (%i)", lmcf->regex_cache_max_entries); lmcf->regex_cache_entries++; } pool = r->pool; flags &= ~NGX_LUA_RE_COMPILE_ONCE; } } else { pool = r->pool; } dd("pool %p, r pool %p", pool, r->pool); re_comp.pattern = pat; re_comp.err.len = NGX_MAX_CONF_ERRSTR; re_comp.err.data = errstr; re_comp.pool = pool; ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua compiling match regex \"%s\" with options \"%s\" " "(compile once: %d) (dfa mode: %d) (jit mode: %d)", pat.data, opts.data, (flags & NGX_LUA_RE_COMPILE_ONCE) != 0, (flags & NGX_LUA_RE_MODE_DFA) != 0, (flags & NGX_LUA_RE_MODE_JIT) != 0); old_pool = ngx_http_lua_pcre_malloc_init(pool); rc = ngx_lua_regex_compile(&re_comp); ngx_http_lua_pcre_malloc_done(old_pool); if (rc != NGX_OK) { dd("compile failed"); re_comp.err.data[re_comp.err.len] = '\0'; msg = lua_pushfstring(L, "failed to compile regex \"%s\": %s", pat.data, re_comp.err.data); return luaL_argerror(L, 2, msg); } #if LUA_HAVE_PCRE_JIT if (flags & NGX_LUA_RE_MODE_JIT) { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) dd("sd = %p", sd); if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", msg, sd); } if (sd != NULL) { int jitted; old_pool = ngx_http_lua_pcre_malloc_init(pool); pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted); ngx_http_lua_pcre_malloc_done(old_pool); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre JIT compiling result: %d", jitted); } # endif /* NGX_DEBUG */ } else { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp.regex, 0, &msg); ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) dd("sd = %p", sd); if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre_study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", msg, sd); } # endif /* NGX_DEBUG */ } #else /* LUA_HAVE_PCRE_JIT */ if (flags & NGX_LUA_RE_MODE_JIT) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "your pcre build does not have JIT support and " "the \"j\" regex option is ignored"); } #endif /* LUA_HAVE_PCRE_JIT */ dd("compile done, captures %d", (int) re_comp.captures); if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; } else { ovecsize = (re_comp.captures + 1) * 3; } dd("allocating cap with size: %d", (int) ovecsize); cap = ngx_palloc(pool, ovecsize * sizeof(int)); if (cap == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; msg = "out of memory"; goto error; } if (flags & NGX_LUA_RE_COMPILE_ONCE) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua saving compiled regex (%d captures) into the cache " "(entries %i)", re_comp.captures, lmcf ? lmcf->regex_cache_entries : 0); re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { return luaL_error(L, "out of memory"); } dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, re_comp.captures, cap); re->regex = re_comp.regex; re->regex_sd = sd; re->ncaptures = re_comp.captures; re->captures = cap; re->replace = NULL; lua_pushlightuserdata(L, re); /* table key value */ lua_rawset(L, -3); /* table */ lua_pop(L, 1); if (lmcf) { lmcf->regex_cache_entries++; } } exec: if (flags & NGX_LUA_RE_MODE_DFA) { #if LUA_HAVE_PCRE_DFA int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; rc = ngx_http_lua_regex_dfa_exec(re_comp.regex, sd, &subj, (int) pos, cap, ovecsize, ws, NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT); #else /* LUA_HAVE_PCRE_DFA */ msg = "at least pcre 6.0 is required for the DFA mode"; goto error; #endif /* LUA_HAVE_PCRE_DFA */ } else { rc = ngx_http_lua_regex_exec(re_comp.regex, sd, &subj, (int) pos, cap, ovecsize); } if (rc == NGX_REGEX_NO_MATCHED) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "regex \"%s\" not matched on string \"%s\" starting from %z", pat.data, subj.data, pos); if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { if (sd) { ngx_http_lua_regex_free_study_data(pool, sd); } ngx_pfree(pool, re_comp.regex); ngx_pfree(pool, cap); } lua_pushnil(L); return 1; } if (rc < 0) { msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d on \"%s\" " "using \"%s\"", (int) rc, subj.data, pat.data); goto error; } if (rc == 0) { if (flags & NGX_LUA_RE_MODE_DFA) { rc = 1; } else { msg = "capture size too small"; goto error; } } dd("rc = %d", (int) rc); lua_createtable(L, rc - 1 /* narr */, 1 /* nrec */); for (i = 0, n = 0; i < rc; i++, n += 2) { dd("capture %d: %d %d", i, cap[n], cap[n + 1]); if (cap[n] < 0) { lua_pushnil(L); } else { lua_pushlstring(L, (char *) &subj.data[cap[n]], cap[n + 1] - cap[n]); dd("pushing capture %s at %d", lua_tostring(L, -1), (int) i); } lua_rawseti(L, -2, (int) i); } if (nargs == 4) { /* having ctx table */ pos = cap[1]; lua_pushinteger(L, (lua_Integer) pos); lua_setfield(L, 4, "pos"); } if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { if (sd) { ngx_http_lua_regex_free_study_data(pool, sd); } ngx_pfree(pool, re_comp.regex); ngx_pfree(pool, cap); } return 1; error: if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { if (sd) { ngx_http_lua_regex_free_study_data(pool, sd); } if (re_comp.regex) { ngx_pfree(pool, re_comp.regex); } if (cap) { ngx_pfree(pool, cap); } } return luaL_error(L, msg); }
static ngx_int_t ngx_http_touch_handler(ngx_http_request_t *r) { //main config ngx_http_upstream_main_conf_t * umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); //server config //ngx_http_upstream_srv_conf_t * umsf = r->srv_conf[ngx_http_upstream_module.ctx_index]; //location config //ngx_http_core_loc_conf_t * hclf = (*(r->loc_conf)); ngx_http_upstream_srv_conf_t **uscfp, *uscf; ngx_uint_t i, j, len; u_char *p, *b; ngx_chain_t *cl; ngx_http_upstream_server_t *us; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_touch_handler"); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "umcfaddress=%d", umcf); if (umcf == NULL || umcf->upstreams.nelts <= 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "NGX_HTTP_NO_CONTENT"); return NGX_HTTP_NO_CONTENT; } //response content buffer length len = 1024 * 16; p = b = ngx_palloc(r->pool, len); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "umcf->upstreams.nelts=%ui\n", umcf->upstreams.nelts); ngx_http_variable_value_t *upstreamname, *servername; ngx_uint_t hash; hash = ngx_hash_key(arg_upstream.data, arg_upstream.len); upstreamname = ngx_http_get_variable(r, &arg_upstream, hash); hash = ngx_hash_key(arg_server.data, arg_server.len); servername = ngx_http_get_variable(r, &arg_server, hash); p = ngx_slprintf(p, b + len, "Worker id: %P\n", ngx_pid); uscfp = umcf->upstreams.elts; for (i = 0; i < umcf->upstreams.nelts; i++) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "i=%d", i); uscf = uscfp[i]; // ngx_slprintf(start, last, fmt, args) p = ngx_slprintf(p, b + len, "upstream name: %V\n", &uscf->host); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "upstream name:%V", &uscf->host); if(uscf->servers != NULL && uscf->servers->nelts > 0) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uscf->servers->nelts = %ui", uscf->servers->nelts); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uscf->servers->size = %ui", uscf->servers->size); for (j = 0; j < uscf->servers->nelts; j++) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "j=%d", j); //us = (ngx_http_upstream_server_t *)(uscf->servers->elts + j * uscf->servers->size); us = (ngx_http_upstream_server_t *)uscf->servers->elts + j; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "us=%d", us); if (us != NULL) { if (upstreamname && upstreamname->not_found == 0 && servername && servername->not_found == 0 && ngx_strncmp(upstreamname->data, uscf->host.data, upstreamname->len) == 0 && ngx_strncmp(servername->data, us->addrs->name.data, servername->len) == 0) { ngx_http_touch_set_upstream_server(r, us, uscf); } ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "usaddress=%d, weight=%d, max_fails=%d, fail_timeout=%d, down=%d, backup=%d", us, us->weight, us->max_fails, us->fail_timeout, us->down, us->backup); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "server name=%V", &us->addrs->name); if (us->addrs != NULL) { // socket to string // parameters :sockaddr, start, max_length, port print? p += ngx_sock_ntop(us->addrs->sockaddr, p, b - p + len, 1); } p = ngx_slprintf(p, b + len, " weight=%d, max_fails=%d, fail_timeout=%d, down=%d, backup=%d\n", us->weight, us->max_fails, us->fail_timeout, us->down, us->backup); } } } } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_alloc_chain_link"); cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_alloc_chain_link error"); return NGX_ERROR; } cl->next = NULL; cl->buf = ngx_calloc_buf(r->pool); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_calloc_buf"); if (cl->buf == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_calloc_buf error"); return NGX_ERROR; } cl->buf->pos = b; cl->buf->last = p; cl->buf->last_buf = 1;/* this is last , and there will be no more buffers in the request */ cl->buf->memory = 1; /* content is in read-only memory */ /* (i.e., filters should copy it rather than rewrite in place) */ r->headers_out.content_length_n = p - b; r->headers_out.status = NGX_HTTP_OK; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_http_send_header(r)"); if (ngx_http_send_header(r) != NGX_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_http_send_header(r) error"); return NGX_ERROR; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_http_output_filter"); return ngx_http_output_filter(r, cl); }
static int ngx_http_lua_ngx_re_gmatch(lua_State *L) { ngx_http_lua_main_conf_t *lmcf = NULL; ngx_http_request_t *r; ngx_str_t subj; ngx_str_t pat; ngx_str_t opts; int ovecsize; ngx_http_lua_regex_t *re; ngx_lua_regex_compile_t re_comp; ngx_http_lua_regex_ctx_t *ctx; const char *msg; int nargs; ngx_int_t flags; int *cap = NULL; ngx_int_t rc; ngx_pool_t *pool, *old_pool; u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; pcre_extra *sd = NULL; ngx_http_cleanup_t *cln; nargs = lua_gettop(L); if (nargs != 2 && nargs != 3) { return luaL_error(L, "expecting two or three arguments, but got %d", nargs); } 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"); } subj.data = (u_char *) luaL_checklstring(L, 1, &subj.len); pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len); if (nargs == 3) { opts.data = (u_char *) luaL_checklstring(L, 3, &opts.len); lua_pop(L, 1); } else { opts.data = (u_char *) ""; opts.len = 0; } /* stack: subj regex */ re_comp.options = 0; flags = ngx_http_lua_ngx_re_parse_opts(L, &re_comp, &opts, 3); if (flags & NGX_LUA_RE_COMPILE_ONCE) { lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); pool = lmcf->pool; dd("server pool %p", lmcf->pool); lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); lua_pushvalue(L, 2); /* table regex */ dd("options size: %d", (int) sizeof(re_comp.options)); lua_pushlstring(L, (char *) &re_comp.options, sizeof(re_comp.options)); /* table regex opts */ lua_concat(L, 3); /* table key */ lua_pushvalue(L, -1); /* table key key */ dd("regex cache key: %.*s", (int) (pat.len + sizeof(re_comp.options)), lua_tostring(L, -1)); lua_rawget(L, -3); /* table key re */ re = lua_touserdata(L, -1); lua_pop(L, 1); /* table key */ if (re) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua regex cache hit for match regex \"%s\" " "with options \"%s\"", pat.data, opts.data); lua_pop(L, 2); dd("restoring regex %p, ncaptures %d, captures %p", re->regex, re->ncaptures, re->captures); re_comp.regex = re->regex; sd = re->regex_sd; re_comp.captures = re->ncaptures; cap = re->captures; if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; } else { ovecsize = (re->ncaptures + 1) * 3; } goto compiled; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua regex cache miss for match regex \"%s\" " "with options \"%s\"", pat.data, opts.data); if (lmcf->regex_cache_entries >= lmcf->regex_cache_max_entries) { if (lmcf->regex_cache_entries == lmcf->regex_cache_max_entries) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "lua exceeding regex cache max entries (%i)", lmcf->regex_cache_max_entries); lmcf->regex_cache_entries++; } pool = r->pool; flags &= ~NGX_LUA_RE_COMPILE_ONCE; } } else { pool = r->pool; } re_comp.pattern = pat; re_comp.err.len = NGX_MAX_CONF_ERRSTR; re_comp.err.data = errstr; re_comp.pool = pool; ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua compiling gmatch regex \"%s\" with options \"%s\" " "(compile once: %d) (dfa mode: %d) (jit mode: %d)", pat.data, opts.data, (flags & NGX_LUA_RE_COMPILE_ONCE) != 0, (flags & NGX_LUA_RE_MODE_DFA) != 0, (flags & NGX_LUA_RE_MODE_JIT) != 0); old_pool = ngx_http_lua_pcre_malloc_init(pool); rc = ngx_lua_regex_compile(&re_comp); ngx_http_lua_pcre_malloc_done(old_pool); if (rc != NGX_OK) { dd("compile failed"); re_comp.err.data[re_comp.err.len] = '\0'; msg = lua_pushfstring(L, "failed to compile regex \"%s\": %s", pat.data, re_comp.err.data); return luaL_argerror(L, 2, msg); } #if LUA_HAVE_PCRE_JIT if (flags & NGX_LUA_RE_MODE_JIT) { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) dd("sd = %p", sd); if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre_study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", msg, sd); } if (sd != NULL) { int jitted; old_pool = ngx_http_lua_pcre_malloc_init(pool); pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted); ngx_http_lua_pcre_malloc_done(old_pool); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre JIT compiling result: %d", jitted); } # endif /* NGX_DEBUG */ } else { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp.regex, 0, &msg); ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) dd("sd = %p", sd); if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", msg, sd); } # endif /* NGX_DEBUG */ } #else /* LUA_HAVE_PCRE_JIT */ if (flags & NGX_LUA_RE_MODE_JIT) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "your pcre build does not have JIT support and " "the \"j\" regex option is ignored"); } #endif /* LUA_HAVE_PCRE_JIT */ dd("compile done, captures %d", re_comp.captures); if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; } else { ovecsize = (re_comp.captures + 1) * 3; } cap = ngx_palloc(pool, ovecsize * sizeof(int)); if (cap == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; msg = "out of memory"; goto error; } if (flags & NGX_LUA_RE_COMPILE_ONCE) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua saving compiled regex (%d captures) into the cache " "(entries %i)", re_comp.captures, lmcf ? lmcf->regex_cache_entries : 0); re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { return luaL_error(L, "out of memory"); } dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, re_comp.captures, cap); re->regex = re_comp.regex; re->regex_sd = sd; re->ncaptures = re_comp.captures; re->captures = cap; re->replace = NULL; lua_pushlightuserdata(L, re); /* table key value */ lua_rawset(L, -3); /* table */ lua_pop(L, 1); if (lmcf) { lmcf->regex_cache_entries++; } } compiled: lua_settop(L, 1); ctx = lua_newuserdata(L, sizeof(ngx_http_lua_regex_ctx_t)); ctx->request = r; ctx->regex = re_comp.regex; ctx->regex_sd = sd; ctx->ncaptures = re_comp.captures; ctx->captures = cap; ctx->captures_len = ovecsize; ctx->flags = (uint8_t) flags; if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return luaL_error(L, "out of memory"); } cln->handler = ngx_http_lua_ngx_re_gmatch_cleanup; cln->data = ctx; } lua_pushinteger(L, 0); /* upvalues in order: subj ctx offset */ lua_pushcclosure(L, ngx_http_lua_ngx_re_gmatch_iterator, 3); return 1; error: if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { if (sd) { ngx_http_lua_regex_free_study_data(pool, sd); } if (re_comp.regex) { ngx_pfree(pool, re_comp.regex); } if (cap) { ngx_pfree(pool, cap); } } return luaL_error(L, msg); }
static int ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) { ngx_http_lua_regex_t *re; ngx_http_request_t *r; ngx_str_t subj; ngx_str_t pat; ngx_str_t opts; ngx_str_t tpl; ngx_http_lua_main_conf_t *lmcf = NULL; ngx_pool_t *pool, *old_pool; ngx_lua_regex_compile_t re_comp; const char *msg; ngx_int_t rc; ngx_uint_t n; ngx_int_t i; int nargs; int *cap = NULL; int ovecsize; int type; unsigned func; int offset; size_t count; luaL_Buffer luabuf; ngx_int_t flags; u_char *p; u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; pcre_extra *sd = NULL; ngx_http_lua_complex_value_t *ctpl = NULL; ngx_http_lua_compile_complex_value_t ccv; nargs = lua_gettop(L); if (nargs != 3 && nargs != 4) { return luaL_error(L, "expecting three or four arguments, but got %d", nargs); } 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"); } subj.data = (u_char *) luaL_checklstring(L, 1, &subj.len); pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len); func = 0; type = lua_type(L, 3); switch (type) { case LUA_TFUNCTION: func = 1; tpl.len = 0; tpl.data = (u_char *) ""; break; case LUA_TNUMBER: case LUA_TSTRING: tpl.data = (u_char *) lua_tolstring(L, 3, &tpl.len); break; default: msg = lua_pushfstring(L, "string, number, or function expected, " "got %s", lua_typename(L, type)); return luaL_argerror(L, 3, msg); } ngx_memzero(&re_comp, sizeof(ngx_lua_regex_compile_t)); if (nargs == 4) { opts.data = (u_char *) luaL_checklstring(L, 4, &opts.len); lua_pop(L, 1); } else { /* nargs == 3 */ opts.data = (u_char *) ""; opts.len = 0; } /* stack: subj regex repl */ re_comp.options = 0; flags = ngx_http_lua_ngx_re_parse_opts(L, &re_comp, &opts, 4); if (flags & NGX_LUA_RE_COMPILE_ONCE) { lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); pool = lmcf->pool; dd("server pool %p", lmcf->pool); lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "s"); lua_pushinteger(L, tpl.len); lua_pushliteral(L, ":"); lua_pushvalue(L, 2); if (tpl.len != 0) { lua_pushvalue(L, 3); } dd("options size: %d", (int) sizeof(re_comp.options)); lua_pushlstring(L, (char *) &re_comp.options, sizeof(re_comp.options)); /* table regex opts */ if (tpl.len == 0) { lua_concat(L, 5); /* table key */ } else { lua_concat(L, 6); /* table key */ } lua_pushvalue(L, -1); /* table key key */ dd("regex cache key: %.*s", (int) (pat.len + sizeof(re_comp.options)), lua_tostring(L, -1)); lua_rawget(L, -3); /* table key re */ re = lua_touserdata(L, -1); lua_pop(L, 1); /* table key */ if (re) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua regex cache hit for sub regex \"%s\" with options " "\"%s\" and replace \"%s\"", pat.data, opts.data, func ? (u_char *) "<func>" : tpl.data); lua_pop(L, 2); dd("restoring regex %p, ncaptures %d, captures %p", re->regex, re->ncaptures, re->captures); re_comp.regex = re->regex; sd = re->regex_sd; re_comp.captures = re->ncaptures; cap = re->captures; ctpl = re->replace; if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; } else { ovecsize = (re->ncaptures + 1) * 3; } goto exec; } ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua regex cache miss for %ssub regex \"%s\" with options " "\"%s\" and replace \"%s\"", global ? "g" : "", pat.data, opts.data, func ? (u_char *) "<func>" : tpl.data); if (lmcf->regex_cache_entries >= lmcf->regex_cache_max_entries) { if (lmcf->regex_cache_entries == lmcf->regex_cache_max_entries) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "lua exceeding regex cache max entries (%i)", lmcf->regex_cache_max_entries); lmcf->regex_cache_entries++; } pool = r->pool; flags &= ~NGX_LUA_RE_COMPILE_ONCE; } } else { pool = r->pool; } re_comp.pattern = pat; re_comp.err.len = NGX_MAX_CONF_ERRSTR; re_comp.err.data = errstr; re_comp.pool = pool; dd("compiling regex"); ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua compiling %ssub regex \"%s\" with options \"%s\" " "(compile once: %d) (dfa mode: %d) (jit mode: %d)", global ? "g" : "", pat.data, opts.data, (flags & NGX_LUA_RE_COMPILE_ONCE) != 0, (flags & NGX_LUA_RE_MODE_DFA) != 0, (flags & NGX_LUA_RE_MODE_JIT) != 0); old_pool = ngx_http_lua_pcre_malloc_init(pool); rc = ngx_lua_regex_compile(&re_comp); ngx_http_lua_pcre_malloc_done(old_pool); if (rc != NGX_OK) { dd("compile failed"); re_comp.err.data[re_comp.err.len] = '\0'; msg = lua_pushfstring(L, "failed to compile regex \"%s\": %s", pat.data, re_comp.err.data); return luaL_argerror(L, 2, msg); } #if LUA_HAVE_PCRE_JIT if (flags & NGX_LUA_RE_MODE_JIT) { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) dd("sd = %p", sd); if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", msg, sd); } if (sd != NULL) { int jitted; old_pool = ngx_http_lua_pcre_malloc_init(pool); pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted); ngx_http_lua_pcre_malloc_done(old_pool); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre JIT compiling result: %d", jitted); } # endif /* NGX_DEBUG */ } else { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp.regex, 0, &msg); ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) dd("sd = %p", sd); if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre_study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", msg, sd); } # endif /* NGX_DEBUG */ } #else /* LUA_HAVE_PCRE_JIT */ if (flags & NGX_LUA_RE_MODE_JIT) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "your pcre build does not have JIT support and " "the \"j\" regex option is ignored"); } #endif /* LUA_HAVE_PCRE_JIT */ dd("compile done, captures %d", re_comp.captures); if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; } else { ovecsize = (re_comp.captures + 1) * 3; } cap = ngx_palloc(pool, ovecsize * sizeof(int)); if (cap == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; msg = "out of memory"; goto error; } if (func) { ctpl = NULL; } else { ctpl = ngx_palloc(pool, sizeof(ngx_http_lua_complex_value_t)); if (ctpl == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; msg = "out of memory"; goto error; } if ((flags & NGX_LUA_RE_COMPILE_ONCE) && tpl.len != 0) { /* copy the string buffer pointed to by tpl.data from Lua VM */ p = ngx_palloc(pool, tpl.len + 1); if (p == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; msg = "out of memory"; goto error; } ngx_memcpy(p, tpl.data, tpl.len); p[tpl.len] = '\0'; tpl.data = p; } ngx_memzero(&ccv, sizeof(ngx_http_lua_compile_complex_value_t)); ccv.pool = pool; ccv.log = r->connection->log; ccv.value = &tpl; ccv.complex_value = ctpl; if (ngx_http_lua_compile_complex_value(&ccv) != NGX_OK) { ngx_pfree(pool, cap); ngx_pfree(pool, ctpl); if ((flags & NGX_LUA_RE_COMPILE_ONCE) && tpl.len != 0) { ngx_pfree(pool, tpl.data); } if (sd) { ngx_http_lua_regex_free_study_data(pool, sd); } ngx_pfree(pool, re_comp.regex); return luaL_error(L, "bad template for substitution: \"%s\"", lua_tostring(L, 3)); } } if (flags & NGX_LUA_RE_COMPILE_ONCE) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua saving compiled sub regex (%d captures) into the cache " "(entries %i)", re_comp.captures, lmcf ? lmcf->regex_cache_entries : 0); re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { return luaL_error(L, "out of memory"); } dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, re_comp.captures, cap); re->regex = re_comp.regex; re->regex_sd = sd; re->ncaptures = re_comp.captures; re->captures = cap; re->replace = ctpl; lua_pushlightuserdata(L, re); /* table key value */ lua_rawset(L, -3); /* table */ lua_pop(L, 1); if (lmcf) { lmcf->regex_cache_entries++; } } exec: count = 0; offset = 0; for (;;) { if (subj.len == 0) { break; } if (flags & NGX_LUA_RE_MODE_DFA) { #if LUA_HAVE_PCRE_DFA int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; rc = ngx_http_lua_regex_dfa_exec(re_comp.regex, sd, &subj, offset, cap, ovecsize, ws, NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT); #else /* LUA_HAVE_PCRE_DFA */ msg = "at least pcre 6.0 is required for the DFA mode"; goto error; #endif /* LUA_HAVE_PCRE_DFA */ } else { rc = ngx_http_lua_regex_exec(re_comp.regex, sd, &subj, offset, cap, ovecsize); } if (rc == NGX_REGEX_NO_MATCHED) { break; } if (rc < 0) { msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d on \"%s\" " "using \"%s\"", (int) rc, subj.data, pat.data); goto error; } if (rc == 0) { if (flags & NGX_LUA_RE_MODE_DFA) { rc = 1; } else { msg = "capture size too small"; goto error; } } dd("rc = %d", (int) rc); count++; if (count == 1) { luaL_buffinit(L, &luabuf); } if (func) { lua_pushvalue(L, -1); lua_createtable(L, rc - 1 /* narr */, 1 /* nrec */); for (i = 0, n = 0; i < rc; i++, n += 2) { dd("capture %d: %d %d", (int) i, cap[n], cap[n + 1]); if (cap[n] < 0) { lua_pushnil(L); } else { lua_pushlstring(L, (char *) &subj.data[cap[n]], cap[n + 1] - cap[n]); dd("pushing capture %s at %d", lua_tostring(L, -1), (int) i); } lua_rawseti(L, -2, (int) i); } dd("stack size at call: %d", lua_gettop(L)); lua_call(L, 1 /* nargs */, 1 /* nresults */); type = lua_type(L, -1); switch (type) { case LUA_TNUMBER: case LUA_TSTRING: tpl.data = (u_char *) lua_tolstring(L, -1, &tpl.len); break; default: msg = lua_pushfstring(L, "string or number expected to be " "returned by the replace function, got %s", lua_typename(L, type)); return luaL_argerror(L, 3, msg); } luaL_addlstring(&luabuf, (char *) &subj.data[offset], cap[0] - offset); luaL_addlstring(&luabuf, (char *) tpl.data, tpl.len); lua_pop(L, 1); offset = cap[1]; if (global) { continue; } break; } rc = ngx_http_lua_complex_value(r, &subj, offset, rc, cap, ctpl, &luabuf); if (rc != NGX_OK) { msg = lua_pushfstring(L, "failed to eval the template for " "replacement: \"%s\"", tpl.data); goto error; } offset = cap[1]; if (global) { continue; } break; } if (count == 0) { dd("no match, just the original subject"); lua_settop(L, 1); } else { if (offset != (int) subj.len) { dd("adding trailer: %s (len %d)", &subj.data[offset], (int) (subj.len - offset)); luaL_addlstring(&luabuf, (char *) &subj.data[offset], subj.len - offset); } luaL_pushresult(&luabuf); dd("the dst string: %s", lua_tostring(L, -1)); } if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { if (sd) { ngx_http_lua_regex_free_study_data(pool, sd); } if (re_comp.regex) { ngx_pfree(pool, re_comp.regex); } if (ctpl) { ngx_pfree(pool, ctpl); } if (cap) { ngx_pfree(pool, cap); } } lua_pushinteger(L, count); return 2; error: if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { if (sd) { ngx_http_lua_regex_free_study_data(pool, sd); } if (re_comp.regex) { ngx_pfree(pool, re_comp.regex); } if (ctpl) { ngx_pfree(pool, ctpl); } if (cap) { ngx_pfree(pool, cap); } } return luaL_error(L, msg); }
//ngx_http_parse_status_line解析应答行,mytest_upstream_process_header解析头部行中的其中一行 static ngx_int_t mytest_upstream_process_header(ngx_http_request_t *r) { ngx_int_t rc; ngx_table_elt_t *h; ngx_http_upstream_header_t *hh; ngx_http_upstream_main_conf_t *umcf; //这里将upstream模块配置项ngx_http_upstream_main_conf_t取了 //出来,目的只有1个,对将要转发给下游客户端的http响应头部作统一 //处理。该结构体中存储了需要做统一处理的http头部名称和回调方法 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); //循环的解析所有的http头部 for ( ;; ) { // http框架提供了基础性的ngx_http_parse_header_line方法,它用于解析http头部 rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1); //返回NGX_OK表示解析出一行http头部 if (rc == NGX_OK) { //向headers_in.headers这个ngx_list_t链表中添加http头部 h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { return NGX_ERROR; } //以下开始构造刚刚添加到headers链表中的http头部 h->hash = r->header_hash; h->key.len = r->header_name_end - r->header_name_start; h->value.len = r->header_end - r->header_start; //必须由内存池中分配解析出的这一行信息,存放解析出的这一行http头部的内存 h->key.data = ngx_pnalloc(r->pool, h->key.len + 1 + h->value.len + 1 + h->key.len); if (h->key.data == NULL) { return NGX_ERROR; } /* key + value + 小写key */ h->value.data = h->key.data + h->key.len + 1; //value存放在key后面 h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1; //最后存放key的小写字符串 ngx_memcpy(h->key.data, r->header_name_start, h->key.len); h->key.data[h->key.len] = '\0'; ngx_memcpy(h->value.data, r->header_start, h->value.len); h->value.data[h->value.len] = '\0'; if (h->key.len == r->lowcase_index) { ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); } else { ngx_strlow(h->lowcase_key, h->key.data, h->key.len); } //upstream模块会对一些http头部做特殊处理 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, h->lowcase_key, h->key.len); if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { return NGX_ERROR; } continue; } //返回NGX_HTTP_PARSE_HEADER_DONE表示响应中所有的http头部都解析 //完毕,接下来再接收到的都将是http包体 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { //如果之前解析http头部时没有发现server和date头部,以下会 //根据http协议添加这两个头部 if (r->upstream->headers_in.server == NULL) { h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { return NGX_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash( ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r'); ngx_str_set(&h->key, "Server"); ngx_str_null(&h->value); h->lowcase_key = (u_char *) "server"; } if (r->upstream->headers_in.date == NULL) { h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { return NGX_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e'); ngx_str_set(&h->key, "Date"); ngx_str_null(&h->value); h->lowcase_key = (u_char *) "date"; } return NGX_OK; } //如果返回NGX_AGAIN则表示状态机还没有解析到完整的http头部, //要求upstream模块继续接收新的字符流再交由process_header //回调方法解析 if (rc == NGX_AGAIN) { return NGX_AGAIN; } //其他返回值都是非法的 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid header"); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } }
int ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, const u_char *addr, size_t addr_len, int port, char **err) { ngx_url_t url; ngx_http_lua_ctx_t *ctx; ngx_http_upstream_t *u; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_balancer_peer_data_t *bp; if (r == NULL) { *err = "no request found"; return NGX_ERROR; } u = r->upstream; if (u == NULL) { *err = "no upstream found"; return NGX_ERROR; } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { *err = "no ctx found"; return NGX_ERROR; } if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) { *err = "API disabled in the current context"; return NGX_ERROR; } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); /* we cannot read r->upstream->peer.data here directly because * it could be overridden by other modules like * ngx_http_upstream_keepalive_module. */ bp = lmcf->balancer_peer_data; if (bp == NULL) { *err = "no upstream peer data found"; return NGX_ERROR; } ngx_memzero(&url, sizeof(ngx_url_t)); url.url.data = ngx_palloc(r->pool, addr_len); if (url.url.data == NULL) { *err = "no memory"; return NGX_ERROR; } ngx_memcpy(url.url.data, addr, addr_len); url.url.len = addr_len; url.default_port = (in_port_t) port; url.uri_part = 0; url.no_resolve = 1; if (ngx_parse_url(r->pool, &url) != NGX_OK) { if (url.err) { *err = url.err; } return NGX_ERROR; } if (url.addrs && url.addrs[0].sockaddr) { bp->sockaddr = url.addrs[0].sockaddr; bp->socklen = url.addrs[0].socklen; bp->host = url.addrs[0].name; } else { *err = "no host allowed"; return NGX_ERROR; } return NGX_OK; }
static ngx_int_t ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) { lua_State *L; ngx_int_t rc; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_srv_conf_t *lscf; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_balancer_peer_data_t *bp = data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua balancer peer, try: %ui", pc->tries); lscf = bp->conf; r = bp->request; ngx_http_lua_assert(lscf->balancer.handler && r); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } L = ngx_http_lua_get_lua_vm(r, ctx); } else { L = ngx_http_lua_get_lua_vm(r, ctx); dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); } ctx->context = NGX_HTTP_LUA_CONTEXT_BALANCER; bp->sockaddr = NULL; bp->socklen = 0; bp->more_tries = 0; bp->total_tries++; lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); /* balancer_by_lua does not support yielding and * there cannot be any conflicts among concurrent requests, * thus it is safe to store the peer data in the main conf. */ lmcf->balancer_peer_data = bp; rc = lscf->balancer.handler(r, lscf, L); if (rc == NGX_ERROR) { return NGX_ERROR; } if (ctx->exited && ctx->exit_code != NGX_OK) { rc = ctx->exit_code; if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { return rc; } if (rc > NGX_OK) { return NGX_ERROR; } } if (bp->sockaddr && bp->socklen) { pc->sockaddr = bp->sockaddr; pc->socklen = bp->socklen; pc->name = &bp->host; bp->rrp.peers->single = 0; if (bp->more_tries) { r->upstream->peer.tries += bp->more_tries; } dd("tries: %d", (int) r->upstream->peer.tries); return NGX_OK; } return bp->get_rr_peer(pc, &bp->rrp); }