static int ngx_http_lua_ngx_header_set(lua_State *L) { ngx_http_request_t *r; u_char *p; ngx_str_t key; ngx_str_t value; ngx_uint_t i; size_t len; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; ngx_uint_t n; ngx_http_lua_loc_conf_t *llcf; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx"); } ngx_http_lua_check_fake_request(L, r); if (r->header_sent || ctx->header_sent) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to " "set ngx.header.HEADER after sending out " "response headers"); return 0; } /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); dd("key: %.*s, len %d", (int) len, p, (int) len); key.data = ngx_palloc(r->pool, len + 1); if (key.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(key.data, p, len); key.data[len] = '\0'; key.len = len; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers) { /* replace "_" with "-" */ p = key.data; for (i = 0; i < len; i++) { if (p[i] == '_') { p[i] = '-'; } } } if (!ctx->headers_set) { rc = ngx_http_lua_set_content_type(r); if (rc != NGX_OK) { return luaL_error(L, "failed to set default content type: %d", (int) rc); } ctx->headers_set = 1; } if (lua_type(L, 3) == LUA_TNIL) { ngx_str_null(&value); } else if (lua_type(L, 3) == LUA_TTABLE) { n = luaL_getn(L, 3); if (n == 0) { ngx_str_null(&value); } else { for (i = 1; i <= n; i++) { dd("header value table index %d", (int) i); lua_rawgeti(L, 3, i); p = (u_char *) luaL_checklstring(L, -1, &len); value.data = ngx_palloc(r->pool, len); if (value.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(value.data, p, len); value.len = len; rc = ngx_http_lua_set_output_header(r, key, value, i == 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", key.data, (int) rc); } } return 0; } } else { p = (u_char *) luaL_checklstring(L, 3, &len); value.data = ngx_palloc(r->pool, len); if (value.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(value.data, p, len); value.len = len; } dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", key.data, (int) rc); } return 0; }
static char * ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_referer_conf_t *rlcf = conf; u_char *p; ngx_str_t *value, uri, name; ngx_uint_t i, n; ngx_http_variable_t *var; ngx_http_server_name_t *sn; ngx_http_core_srv_conf_t *cscf; ngx_str_set(&name, "invalid_referer"); var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); if (var == NULL) { return NGX_CONF_ERROR; } var->get_handler = ngx_http_referer_variable; if (rlcf->keys == NULL) { rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t)); if (rlcf->keys == NULL) { return NGX_CONF_ERROR; } rlcf->keys->pool = cf->pool; rlcf->keys->temp_pool = cf->pool; if (ngx_hash_keys_array_init(rlcf->keys, NGX_HASH_SMALL) != NGX_OK) { return NGX_CONF_ERROR; } } value = cf->args->elts; for (i = 1; i < cf->args->nelts; i++) { if (value[i].len == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid referer \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (ngx_strcmp(value[i].data, "none") == 0) { rlcf->no_referer = 1; continue; } if (ngx_strcmp(value[i].data, "blocked") == 0) { rlcf->blocked_referer = 1; continue; } ngx_str_null(&uri); if (ngx_strcmp(value[i].data, "server_names") == 0) { cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); sn = cscf->server_names.elts; for (n = 0; n < cscf->server_names.nelts; n++) { #if (NGX_PCRE) if (sn[n].regex) { if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name, sn[n].regex->regex) != NGX_OK) { return NGX_CONF_ERROR; } continue; } #endif if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name, &uri) != NGX_OK) { return NGX_CONF_ERROR; } } continue; } if (value[i].data[0] == '~') { if (ngx_http_add_regex_referer(cf, rlcf, &value[i], NULL) != NGX_OK) { return NGX_CONF_ERROR; } continue; } p = (u_char *) ngx_strchr(value[i].data, '/'); if (p) { uri.len = (value[i].data + value[i].len) - p; uri.data = p; value[i].len = p - value[i].data; } if (ngx_http_add_referer(cf, rlcf->keys, &value[i], &uri) != NGX_OK) { return NGX_CONF_ERROR; } } return NGX_CONF_OK; }
char * ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head) { ngx_log_t *new_log; ngx_str_t *value, name; ngx_syslog_peer_t *peer; if (*head != NULL && (*head)->log_level == 0) { new_log = *head; } else { new_log = ngx_pcalloc(cf->pool, sizeof(ngx_log_t)); if (new_log == NULL) { return NGX_CONF_ERROR; } if (*head == NULL) { *head = new_log; } } value = cf->args->elts; if (ngx_strcmp(value[1].data, "stderr") == 0) { ngx_str_null(&name); cf->cycle->log_use_stderr = 1; new_log->file = ngx_conf_open_file(cf->cycle, &name); if (new_log->file == NULL) { return NGX_CONF_ERROR; } } else if (ngx_strncmp(value[1].data, "memory:", 7) == 0) { #if (NGX_DEBUG) size_t size, needed; ngx_pool_cleanup_t *cln; ngx_log_memory_buf_t *buf; value[1].len -= 7; value[1].data += 7; needed = sizeof("MEMLOG :" NGX_LINEFEED) + cf->conf_file->file.name.len + NGX_SIZE_T_LEN + NGX_INT_T_LEN + NGX_MAX_ERROR_STR; size = ngx_parse_size(&value[1]); if (size == (size_t) NGX_ERROR || size < needed) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid buffer size \"%V\"", &value[1]); return NGX_CONF_ERROR; } buf = ngx_pcalloc(cf->pool, sizeof(ngx_log_memory_buf_t)); if (buf == NULL) { return NGX_CONF_ERROR; } buf->start = ngx_pnalloc(cf->pool, size); if (buf->start == NULL) { return NGX_CONF_ERROR; } buf->end = buf->start + size; buf->pos = ngx_slprintf(buf->start, buf->end, "MEMLOG %uz %V:%ui%N", size, &cf->conf_file->file.name, cf->conf_file->line); ngx_memset(buf->pos, ' ', buf->end - buf->pos); cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NGX_CONF_ERROR; } cln->data = new_log; cln->handler = ngx_log_memory_cleanup; new_log->writer = ngx_log_memory_writer; new_log->wdata = buf; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "nginx was built without debug support"); return NGX_CONF_ERROR; #endif } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t)); if (peer == NULL) { return NGX_CONF_ERROR; } if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) { return NGX_CONF_ERROR; } new_log->writer = ngx_syslog_writer; new_log->wdata = peer; } else { new_log->file = ngx_conf_open_file(cf->cycle, &value[1]); if (new_log->file == NULL) { return NGX_CONF_ERROR; } } if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) { return NGX_CONF_ERROR; } if (*head != new_log) { ngx_log_insert(*head, new_log); } return NGX_CONF_OK; }
/* check whether the client user name should be allowed to proceed, or whether the connection should be throttled */ void ngx_mail_throttle_user (ngx_str_t user, throttle_callback_t *callback) { ngx_pool_t *pool; ngx_log_t *log; ngx_connection_t *c; ngx_str_t *cusr; ngx_mail_session_t *s; mc_work_t w; ngx_str_t proxyip; ngx_str_t *dummy_value; pool = callback->pool; log = callback->log; c = callback->connection; s = callback->session; ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, log, 0, "user throttle: lookup alias, user:%V", &user); /* save a copy of the user name */ cusr = ngx_pstrcpy(pool, &user); if (cusr == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (deep copy user for incr)", &user); callback->on_allow(callback); return; } if (s->vlogin) { /* user alias has already been looked up */ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, log, 0, "user throttle: skip alias lookup, user:%V", &user); ngx_mail_throttle_quser(cusr, callback); return; } w.ctx = callback; w.request_code = mcreq_get; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_user_success_handler; w.on_failure = ngx_mail_throttle_user_failure_handler; /* GSSAPI workaround: don't lookup aliases for GSSAPI */ if (s->auth_method == NGX_MAIL_AUTH_GSSAPI) { ngx_log_error(NGX_LOG_INFO, log, 0, "not looking up cached aliases for auth=gssapi"); ngx_mail_throttle_quser(cusr, callback); return; } /* first stringify the proxy-ip address */ proxyip = ngx_mail_get_socket_local_addr_str (pool, c->fd); s->key_alias = ngx_zm_lookup_get_mail_alias_key( pool, log, *cusr, proxyip ); if (s->key_alias.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (create alias key)", &user); callback->on_allow(callback); return; } dummy_value = ngx_palloc (pool, sizeof (ngx_str_t)); ngx_str_null (dummy_value); callback->key = &s->key_alias; callback->value = dummy_value; callback->user = cusr; ngx_memcache_post(&w, s->key_alias, *dummy_value,/* pool */ NULL, log); }
static void ngx_mail_proxy_imap_handler(ngx_event_t *rev) { u_char *p; ngx_int_t rc; ngx_str_t line; ngx_connection_t *c; ngx_mail_session_t *s; ngx_mail_proxy_conf_t *pcf; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy imap auth handler"); c = rev->data; s = c->data; if (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "upstream timed out"); c->timedout = 1; ngx_mail_proxy_internal_server_error(s); return; } rc = ngx_mail_proxy_read_response(s, s->mail_state); if (rc == NGX_AGAIN) { return; } if (rc == NGX_ERROR) { ngx_mail_proxy_upstream_error(s); return; } switch (s->mail_state) { case ngx_imap_start: ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send login"); s->connection->log->action = "sending LOGIN command to upstream"; line.len = s->tag.len + sizeof("LOGIN ") - 1 + 1 + NGX_SIZE_T_LEN + 1 + 2; line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } line.len = ngx_sprintf(line.data, "%VLOGIN {%uz}" CRLF, &s->tag, s->login.len) - line.data; s->mail_state = ngx_imap_login; break; case ngx_imap_login: ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user"); s->connection->log->action = "sending user name to upstream"; line.len = s->login.len + 1 + 1 + NGX_SIZE_T_LEN + 1 + 2; line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } line.len = ngx_sprintf(line.data, "%V {%uz}" CRLF, &s->login, s->passwd.len) - line.data; s->mail_state = ngx_imap_user; break; case ngx_imap_user: ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send passwd"); s->connection->log->action = "sending password to upstream"; line.len = s->passwd.len + 2; line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } p = ngx_cpymem(line.data, s->passwd.data, s->passwd.len); *p++ = CR; *p = LF; s->mail_state = ngx_imap_passwd; break; case ngx_imap_passwd: s->connection->read->handler = ngx_mail_proxy_handler; s->connection->write->handler = ngx_mail_proxy_handler; rev->handler = ngx_mail_proxy_handler; c->write->handler = ngx_mail_proxy_handler; pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); ngx_add_timer(s->connection->read, pcf->timeout); ngx_del_timer(c->read); c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); ngx_mail_proxy_handler(s->connection->write); return; default: #if (NGX_SUPPRESS_WARN) ngx_str_null(&line); #endif break; } if (c->send(c, line.data, line.len) < (ssize_t) line.len) { /* * we treat the incomplete sending as NGX_ERROR * because it is very strange here */ ngx_mail_proxy_internal_server_error(s); return; } s->proxy->buffer->pos = s->proxy->buffer->start; s->proxy->buffer->last = s->proxy->buffer->start; }
static ngx_int_t ngx_rtmp_control_handler(ngx_http_request_t *r) { u_char *p; ngx_str_t section, method; ngx_uint_t n; ngx_rtmp_control_ctx_t *ctx; ngx_rtmp_control_loc_conf_t *llcf; llcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_control_module); if (llcf->control == 0) { return NGX_DECLINED; } /* uri format: .../section/method?args */ ngx_str_null(§ion); ngx_str_null(&method); for (n = r->uri.len; n; --n) { p = &r->uri.data[n - 1]; if (*p != '/') { continue; } if (method.data) { section.data = p + 1; section.len = method.data - section.data - 1; break; } method.data = p + 1; method.len = r->uri.data + r->uri.len - method.data; } ngx_log_debug2(NGX_LOG_DEBUG_RTMP, r->connection->log, 0, "rtmp_control: section='%V' method='%V'", §ion, &method); ctx = ngx_pcalloc(r->pool, sizeof(ngx_rtmp_control_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ngx_http_set_ctx(r, ctx, ngx_rtmp_control_module); if (ngx_array_init(&ctx->sessions, r->pool, 1, sizeof(void *)) != NGX_OK) { return NGX_ERROR; } ctx->method = method; #define NGX_RTMP_CONTROL_SECTION(flag, secname) \ if (llcf->control & NGX_RTMP_CONTROL_##flag && \ section.len == sizeof(#secname) - 1 && \ ngx_strncmp(section.data, #secname, sizeof(#secname) - 1) == 0) \ { \ return ngx_rtmp_control_##secname(r, &method); \ } NGX_RTMP_CONTROL_SECTION(RECORD, record); NGX_RTMP_CONTROL_SECTION(DROP, drop); NGX_RTMP_CONTROL_SECTION(REDIRECT, redirect); NGX_RTMP_CONTROL_SECTION(RELAY, relay); #undef NGX_RTMP_CONTROL_SECTION return NGX_DECLINED; }
static int ngx_http_lua_ngx_exec(lua_State *L) { int n; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_str_t uri; ngx_str_t args, user_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; const char *msg; n = lua_gettop(L); if (n != 1 && n != 2) { return luaL_error(L, "expecting one or two arguments, but got %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_str_null(&args); /* read the 1st argument (uri) */ p = (u_char *) luaL_checklstring(L, 1, &len); if (len == 0) { return luaL_error(L, "The uri argument is empty"); } uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(uri.data, p, len); uri.len = len; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); ngx_http_lua_check_if_abortable(L, ctx); if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (n == 2) { /* read the 2nd argument (args) */ dd("args type: %s", luaL_typename(L, 2)); switch (lua_type(L, 2)) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) lua_tolstring(L, 2, &len); user_args.data = ngx_palloc(r->pool, len); if (user_args.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(user_args.data, p, len); user_args.len = len; break; case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, 2, &user_args); dd("user_args: %.*s", (int) user_args.len, user_args.data); break; case LUA_TNIL: ngx_str_null(&user_args); break; default: msg = lua_pushfstring(L, "string, number, or table expected, " "but got %s", luaL_typename(L, 2)); return luaL_argerror(L, 2, msg); } } else { user_args.data = NULL; user_args.len = 0; } if (user_args.len) { if (args.len == 0) { args = user_args; } else { p = ngx_palloc(r->pool, args.len + user_args.len + 1); if (p == NULL) { return luaL_error(L, "no memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, user_args.data, user_args.len); args.data = p; args.len += user_args.len + 1; } } if (r->header_sent || ctx->header_sent) { return luaL_error(L, "attempt to call ngx.exec after " "sending out response headers"); } ctx->exec_uri = uri; ctx->exec_args = args; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exec \"%V?%V\"", &ctx->exec_uri, &ctx->exec_args); return lua_yield(L, 0); }
ngx_int_t ngx_dynamic_upstream_build_op(ngx_http_request_t *r, ngx_dynamic_upstream_op_t *op) { ngx_uint_t i; size_t args_size; u_char *low; ngx_uint_t key; ngx_str_t *args; ngx_http_variable_value_t *var; ngx_memzero(op, sizeof(ngx_dynamic_upstream_op_t)); /* default setting for op */ op->op = NGX_DYNAMIC_UPSTEAM_OP_LIST; op->status = NGX_HTTP_OK; ngx_str_null(&op->upstream); op->weight = 1; op->max_fails = 1; op->fail_timeout = 10; args = (ngx_str_t *)&ngx_dynamic_upstream_params; args_size = sizeof(ngx_dynamic_upstream_params) / sizeof(ngx_str_t); for (i=0;i<args_size;i++) { low = ngx_pnalloc(r->pool, args[i].len); if (low == NULL) { op->status = NGX_HTTP_INTERNAL_SERVER_ERROR; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to allocate memory from r->pool %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } key = ngx_hash_strlow(low, args[i].data, args[i].len); var = ngx_http_get_variable(r, &args[i], key); if (!var->not_found) { if (ngx_strcmp("arg_upstream", args[i].data) == 0) { op->upstream.data = var->data; op->upstream.len = var->len; } else if (ngx_strcmp("arg_verbose", args[i].data) == 0) { op->verbose = 1; } else if (ngx_strcmp("arg_add", args[i].data) == 0) { op->op |= NGX_DYNAMIC_UPSTEAM_OP_ADD; } else if (ngx_strcmp("arg_remove", args[i].data) == 0) { op->op |= NGX_DYNAMIC_UPSTEAM_OP_REMOVE; } else if (ngx_strcmp("arg_backup", args[i].data) == 0) { op->backup = 1; } else if (ngx_strcmp("arg_server", args[i].data) == 0) { op->server.data = var->data; op->server.len = var->len; } else if (ngx_strcmp("arg_weight", args[i].data) == 0) { op->weight = ngx_atoi(var->data, var->len); if (op->weight == NGX_ERROR) { op->status = NGX_HTTP_BAD_REQUEST; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "weight is not number. %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } op->op |= NGX_DYNAMIC_UPSTEAM_OP_PARAM; op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_WEIGHT; op->verbose = 1; } else if (ngx_strcmp("arg_max_fails", args[i].data) == 0) { op->max_fails = ngx_atoi(var->data, var->len); if (op->max_fails == NGX_ERROR) { op->status = NGX_HTTP_BAD_REQUEST; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "max_fails is not number. %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } op->op |= NGX_DYNAMIC_UPSTEAM_OP_PARAM; op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_MAX_FAILS; op->verbose = 1; } else if (ngx_strcmp("arg_fail_timeout", args[i].data) == 0) { op->fail_timeout = ngx_atoi(var->data, var->len); if (op->fail_timeout == NGX_ERROR) { op->status = NGX_HTTP_BAD_REQUEST; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "fail_timeout is not number. %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } op->op |= NGX_DYNAMIC_UPSTEAM_OP_PARAM; op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_FAIL_TIMEOUT; op->verbose = 1; } else if (ngx_strcmp("arg_up", args[i].data) == 0) { op->up = 1; op->op |= NGX_DYNAMIC_UPSTEAM_OP_PARAM; op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_UP; op->verbose = 1; } else if (ngx_strcmp("arg_down", args[i].data) == 0) { op->down = 1; op->op |= NGX_DYNAMIC_UPSTEAM_OP_PARAM; op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_DOWN; op->verbose = 1; } } } /* can not add and remove at once */ if ((op->op & NGX_DYNAMIC_UPSTEAM_OP_ADD) && (op->op & NGX_DYNAMIC_UPSTEAM_OP_REMOVE)) { op->status = NGX_HTTP_BAD_REQUEST; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "add and remove at once are not allowed. %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } if (op->op & NGX_DYNAMIC_UPSTEAM_OP_ADD) { op->op = NGX_DYNAMIC_UPSTEAM_OP_ADD; } else if (op->op & NGX_DYNAMIC_UPSTEAM_OP_REMOVE) { op->op = NGX_DYNAMIC_UPSTEAM_OP_REMOVE; } /* can not up and down at once */ if (op->up && op->down) { op->status = NGX_HTTP_BAD_REQUEST; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "down and up at once are not allowed. %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } return NGX_OK; }
static char * ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_limit_req_conf_t *lrcf = conf; ngx_int_t burst, delay; ngx_str_t *value, s; ngx_uint_t i; ngx_shm_zone_t *shm_zone; ngx_http_limit_req_limit_t *limit, *limits; #if (T_LIMIT_REQ) ngx_str_t forbid_action; #endif value = cf->args->elts; #if (T_LIMIT_REQ) if (cf->args->nelts == 2) { if (ngx_strncmp(value[1].data, "off", 3) == 0) { lrcf->enable = 0; return NGX_CONF_OK; } } lrcf->enable = 1; ngx_str_null(&forbid_action); #endif shm_zone = NULL; burst = 0; delay = 0; for (i = 1; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { s.len = value[i].len - 5; s.data = value[i].data + 5; shm_zone = ngx_shared_memory_add(cf, &s, 0, &ngx_http_limit_req_module); if (shm_zone == NULL) { return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "burst=", 6) == 0) { burst = ngx_atoi(value[i].data + 6, value[i].len - 6); if (burst <= 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid burst value \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "delay=", 6) == 0) { delay = ngx_atoi(value[i].data + 6, value[i].len - 6); if (delay <= 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid delay value \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (ngx_strcmp(value[i].data, "nodelay") == 0) { delay = NGX_MAX_INT_T_VALUE / 1000; continue; } #if (T_LIMIT_REQ) if (ngx_strncmp(value[i].data, "forbid_action=", 14) == 0) { s.len = value[i].len - 14; s.data = value[i].data + 14; if (s.len < 2 || (s.data[0] != '@' && s.data[0] != '/')) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid forbid_action \"%V\"", &value[i]); return NGX_CONF_ERROR; } forbid_action = s; continue; } #endif ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (shm_zone == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%V\" must have \"zone\" parameter", &cmd->name); return NGX_CONF_ERROR; } limits = lrcf->limits.elts; if (limits == NULL) { if (ngx_array_init(&lrcf->limits, cf->pool, 1, sizeof(ngx_http_limit_req_limit_t)) != NGX_OK) { return NGX_CONF_ERROR; } } for (i = 0; i < lrcf->limits.nelts; i++) { if (shm_zone == limits[i].shm_zone) { return "is duplicate"; } } limit = ngx_array_push(&lrcf->limits); if (limit == NULL) { return NGX_CONF_ERROR; } limit->shm_zone = shm_zone; limit->burst = burst * 1000; limit->delay = delay * 1000; #if (T_LIMIT_REQ) limit->forbid_action = forbid_action; #endif return NGX_CONF_OK; }
/* 与POP3邮件服务器认证交互的过程 */ static void ngx_mail_proxy_pop3_handler(ngx_event_t *rev) { u_char *p; ngx_int_t rc; ngx_str_t line;//保存发往上游邮件服务器的消息 ngx_connection_t *c; ngx_mail_session_t *s; ngx_mail_proxy_conf_t *pcf; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy pop3 auth handler"); c = rev->data;//获取nginx与上游的连接 s = c->data;//获取ngx_mail_session_t结构体 /* 如果读取上游邮件服务器响应超时,则向客户端发送错误响应 */ if (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "upstream timed out"); c->timedout = 1; ngx_mail_proxy_internal_server_error(s); return; } rc = ngx_mail_proxy_read_response(s, 0);//读取上游邮件服务器发来的响应到buffer缓冲区中 /* 还需要继续接收邮件服务器的消息 */ if (rc == NGX_AGAIN) { return; } /* 消息不合法或者邮件服务器没有通过验证,则返回错误给客户端 */ if (rc == NGX_ERROR) { ngx_mail_proxy_upstream_error(s); return; } switch (s->mail_state) { case ngx_pop3_start://构造发送给邮件服务器的用户消息 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user"); s->connection->log->action = "sending user name to upstream"; line.len = sizeof("USER ") - 1 + s->login.len + 2; line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1); p = ngx_cpymem(p, s->login.data, s->login.len); *p++ = CR; *p = LF; s->mail_state = ngx_pop3_user; break; case ngx_pop3_user://构造发送给邮件服务器的密码信息 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send pass"); s->connection->log->action = "sending password to upstream"; line.len = sizeof("PASS ") - 1 + s->passwd.len + 2; line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1); p = ngx_cpymem(p, s->passwd.data, s->passwd.len); *p++ = CR; *p = LF; s->mail_state = ngx_pop3_passwd; break; /* 在收到服务器返回的密码验证通过信息后,将nginx与下游客户端间、nginx与上游邮件服务器间的TCP连接上读写事件 的回调方法都设置为ngx_main_proxy_handler方法*/ case ngx_pop3_passwd: s->connection->read->handler = ngx_mail_proxy_handler; s->connection->write->handler = ngx_mail_proxy_handler; rev->handler = ngx_mail_proxy_handler; c->write->handler = ngx_mail_proxy_handler; pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); ngx_add_timer(s->connection->read, pcf->timeout); ngx_del_timer(c->read); c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); ngx_mail_proxy_handler(s->connection->write);//进入透传上下游TCP阶段 return; default: #if (NGX_SUPPRESS_WARN) ngx_str_null(&line); #endif break; } /* 向上游的邮件服务器发送验证消息,注意,这里向邮件服务器发送TCP流与以前情况不同,它不再通过epoll检测到TCP连接上出现可写事件而触发。 事实上,它是由连接上出现的可读事件触发的,因为读取到了邮件服务器的消息,才向邮件服务器发送消息,之所以可以这么做的一个原因在于,当前 阶段发送的TCP消息包都非常短小*/ if (c->send(c, line.data, line.len) < (ssize_t) line.len) { /* * we treat the incomplete sending as NGX_ERROR * because it is very strange here */ ngx_mail_proxy_internal_server_error(s); return; } /* 清空buffer缓冲区 */ s->proxy->buffer->pos = s->proxy->buffer->start; s->proxy->buffer->last = s->proxy->buffer->start; }
/* 该函数用来在全局唯一的ngx_cycle_t对象cycle的open_files成员中挂载一个待打开的文件 */ ngx_open_file_t * ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name) { ngx_str_t full; ngx_uint_t i; ngx_list_part_t *part; ngx_open_file_t *file; #if (NGX_SUPPRESS_WARN) ngx_str_null(&full); #endif /*遍历Nginx内核需要打开的文件数组,看是否对应的文件已经存在*/ if (name->len) { full = *name; /*获取pidfile的绝对路径名*/ if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) { return NULL; } part = &cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (full.len != file[i].name.len) { continue; } /*找到打开的目标文件,返回目标文件对象*/ if (ngx_strcmp(full.data, file[i].name.data) == 0) { return &file[i]; } } } /*没有找到文件,申请文件对象存储节点*/ file = ngx_list_push(&cycle->open_files); if (file == NULL) { return NULL; } /*存在目标文件,下面需要重新打开*/ if (name->len) { file->fd = NGX_INVALID_FILE; file->name = full; } else { //没有配置目标文件,改为标准错误输出 file->fd = ngx_stderr; file->name = *name; } file->flush = NULL; file->data = NULL; return file; }
static ngx_chain_t * ngx_rtmp_notify_update_create(ngx_rtmp_session_t *s, void *arg, ngx_pool_t *pool) { ngx_chain_t *pl; ngx_buf_t *b; size_t name_len, args_len; ngx_rtmp_notify_ctx_t *ctx; ngx_str_t sfx; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module); pl = ngx_alloc_chain_link(pool); if (pl == NULL) { return NULL; } if (ctx->flags & NGX_RTMP_NOTIFY_PUBLISHING) { ngx_str_set(&sfx, "_publish"); } else if (ctx->flags & NGX_RTMP_NOTIFY_PLAYING) { ngx_str_set(&sfx, "_play"); } else { ngx_str_null(&sfx); } name_len = ctx ? ngx_strlen(ctx->name) : 0; args_len = ctx ? ngx_strlen(ctx->args) : 0; b = ngx_create_temp_buf(pool, sizeof("&call=update") + sfx.len + sizeof("&time=") + NGX_TIME_T_LEN + sizeof("×tamp=") + NGX_INT32_LEN + sizeof("&app=") + s->app.len * 3 + sizeof("&name=") + name_len * 3 + 1 + args_len); if (b == NULL) { return NULL; } pl->buf = b; pl->next = NULL; b->last = ngx_cpymem(b->last, (u_char*) "&call=update", sizeof("&call=update") - 1); b->last = ngx_cpymem(b->last, sfx.data, sfx.len); b->last = ngx_cpymem(b->last, (u_char *) "&time=", sizeof("&time=") - 1); b->last = ngx_sprintf(b->last, "%T", ngx_cached_time->sec - ctx->start); b->last = ngx_cpymem(b->last, (u_char *) "×tamp=", sizeof("×tamp=") - 1); b->last = ngx_sprintf(b->last, "%D", s->current_time); b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1); b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len, NGX_ESCAPE_ARGS); if (name_len) { b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1); b->last = (u_char*) ngx_escape_uri(b->last, ctx->name, name_len, NGX_ESCAPE_ARGS); } if (args_len) { *b->last++ = '&'; b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len); } return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_UPDATE, pl); }
static char * ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_limit_req_conf_t *lrcf = conf; ngx_int_t burst; ngx_str_t *value, s, forbid_action; ngx_uint_t i, nodelay; ngx_shm_zone_t *shm_zone; ngx_http_limit_req_limit_t *limit, *limits; ngx_http_limit_req_variable_t condition; value = cf->args->elts; shm_zone = NULL; burst = 0; nodelay = 0; condition.index = -1; ngx_str_null(&condition.var); ngx_str_null(&forbid_action); for (i = 1; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { s.len = value[i].len - 5; s.data = value[i].data + 5; shm_zone = ngx_shared_memory_add(cf, &s, 0, &ngx_http_limit_req_module); if (shm_zone == NULL) { return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "burst=", 6) == 0) { burst = ngx_atoi(value[i].data + 6, value[i].len - 6); if (burst <= 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid burst rate \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (ngx_strcmp(value[i].data, "nodelay") == 0) { nodelay = 1; continue; } if (ngx_strncmp(value[i].data, "forbid_action=", 14) == 0) { s.len = value[i].len - 14; s.data = value[i].data + 14; if (s.len < 2 || (s.data[0] != '@' && s.data[0] != '/')) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid forbid_action \"%V\"", &value[i]); return NGX_CONF_ERROR; } forbid_action = s; continue; } if (ngx_strncmp(value[i].data, "condition=", 10) == 0) { s.len = value[i].len - 10; s.data = value[i].data + 10; if (s.len < 2 || s.data[0] != '$') { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid condition \"%V\"", &value[i]); return NGX_CONF_ERROR; } s.len--; s.data++; condition.index = ngx_http_get_variable_index(cf, &s); if (condition.index == NGX_ERROR) { return NGX_CONF_ERROR; } condition.var = s; continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (shm_zone == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%V\" must have \"zone\" parameter", &cmd->name); return NGX_CONF_ERROR; } if (shm_zone->data == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unknown limit_req_zone \"%V\"", &shm_zone->shm.name); return NGX_CONF_ERROR; } limits = lrcf->limits.elts; if (limits == NULL) { if (ngx_array_init(&lrcf->limits, cf->pool, 1, sizeof(ngx_http_limit_req_limit_t)) != NGX_OK) { return NGX_CONF_ERROR; } } for (i = 0; i < lrcf->limits.nelts; i++) { if (shm_zone == limits[i].shm_zone) { return "is duplicate"; } } limit = ngx_array_push(&lrcf->limits); if (limit == NULL) { return NGX_CONF_ERROR; } limit->shm_zone = shm_zone; limit->burst = burst * 1000; limit->nodelay = nodelay; limit->forbid_action = forbid_action; limit->condition = condition; return NGX_CONF_OK; }
static int ngx_http_lua_ngx_req_header_set_helper(lua_State *L) { ngx_http_request_t *r; u_char *p; ngx_str_t key; ngx_str_t value; ngx_uint_t i; size_t len; ngx_int_t rc; ngx_uint_t n; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_http_lua_check_fake_request(L, r); if (r->http_version < NGX_HTTP_VERSION_10) { return 0; } p = (u_char *) luaL_checklstring(L, 1, &len); dd("key: %.*s, len %d", (int) len, p, (int) len); #if 0 /* replace "_" with "-" */ for (i = 0; i < len; i++) { if (p[i] == '_') { p[i] = '-'; } } #endif key.data = ngx_palloc(r->pool, len + 1); if (key.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(key.data, p, len); key.data[len] = '\0'; key.len = len; if (lua_type(L, 2) == LUA_TNIL) { ngx_str_null(&value); } else if (lua_type(L, 2) == LUA_TTABLE) { n = luaL_getn(L, 2); if (n == 0) { ngx_str_null(&value); } else { for (i = 1; i <= n; i++) { dd("header value table index %d, top: %d", (int) i, lua_gettop(L)); lua_rawgeti(L, 2, i); p = (u_char *) luaL_checklstring(L, -1, &len); /* * we also copy the trailling '\0' char here because nginx * header values must be null-terminated * */ value.data = ngx_palloc(r->pool, len + 1); if (value.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(value.data, p, len + 1); value.len = len; rc = ngx_http_lua_set_input_header(r, key, value, i == 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", key.data, (int) rc); } } return 0; } } else { /* * we also copy the trailling '\0' char here because nginx * header values must be null-terminated * */ p = (u_char *) luaL_checklstring(L, 2, &len); value.data = ngx_palloc(r->pool, len + 1); if (value.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(value.data, p, len + 1); value.len = len; } dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", key.data, (int) rc); } return 0; }
ngx_int_t ngx_lua_content_by_file_handler(ngx_http_request_t* r) { ngx_lua_main_conf_t* pmainconf; ngx_lua_loc_conf_t* plocconf; ngx_int_t rc; int top; ngx_str_t src_path; u_char new_path[PATH_MAX]; dbg("ngx_lua_content_by_file_handler\n"); pmainconf = ngx_http_get_module_main_conf(r, ngx_lua_module); plocconf = ngx_http_get_module_loc_conf(r, ngx_lua_module); // complex path if (ngx_http_complex_value(r, &plocconf->lua_content_file, &src_path) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "ngx_lua_content_handler: ngx_http_complex_value error"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } // new path with\0 memcpy(new_path, src_path.data, src_path.len); new_path[src_path.len] = 0; src_path.data = new_path; // register ngx.req.args top = lua_gettop(pmainconf->lua); ngx_lua_module_set_req_obj(pmainconf->lua, r); ngx_lua_module_parse_args(r->pool, r->args.data, r->args.len, pmainconf->lua); if (src_path.len) { code_cache_node_t* ptr; char path[PATH_MAX]; ngx_str_t strPath; ngx_str_t code; ngx_str_null(&strPath); // file exists if (access((const char*)src_path.data, 0) == -1) { lua_pushfstring(pmainconf->lua, "%s doesn't exist", src_path.data); faild(NGX_HTTP_NOT_FOUND); } // get realpath if (realpath((const char*)src_path.data, path) == NULL) { lua_pushfstring(pmainconf->lua, "can't get realpath with %s", src_path.data); faild(NGX_HTTP_INTERNAL_SERVER_ERROR); } ngx_pfree(r->pool, src_path.data); // register ngx.scp.path ngx_lua_module_get_scp(pmainconf->lua); lua_pushstring(pmainconf->lua, "path"); lua_pushstring(pmainconf->lua, path); lua_settable(pmainconf->lua, -3); lua_pop(pmainconf->lua, 2); // lookup cache strPath.data = (u_char*)path; strPath.len = strlen(path); ptr = ngx_lua_code_cache_key_exists(pmainconf->cache_table, strPath); ngx_lua_module_replace_global(pmainconf->lua); if (ptr == NULL) // doesn't exist { code = ngx_lua_code_cache_load(strPath); if (code.data == NULL) { lua_pushstring(pmainconf->lua, "out of memory"); faild(NGX_HTTP_INTERNAL_SERVER_ERROR); } if (pmainconf->enable_code_cache) { ngx_str_t cache; dbg("code uncached\n"); if (ngx_lua_module_code_to_chunk(pmainconf->lua, code.data, code.len, &cache)) { faild(NGX_HTTP_INTERNAL_SERVER_ERROR); } ptr = ngx_lua_code_cache_node_new(strPath, cache); if (ptr == NULL) { lua_pushstring(pmainconf->lua, "out of memory"); faild(NGX_HTTP_INTERNAL_SERVER_ERROR); } ngx_pfree(ngx_cycle->pool, code.data); code = ptr->code; ngx_lua_core_hash_table_insert_notfind(pmainconf->cache_table, ptr); rc = ngx_lua_content_call_chunk(r, pmainconf->lua, &code); } else rc = ngx_lua_content_call_code(r, pmainconf->lua, code.data, code.len); } else { dbg("code cached\n"); code = ptr->code; rc = ngx_lua_content_call_chunk(r, pmainconf->lua, &code); } ngx_pfree(ngx_cycle->pool, code.data); if (rc != NGX_OK) return rc; rc = ngx_lua_content_send(r, pmainconf->lua); if (rc != NGX_OK) return rc; } if (top != lua_gettop(pmainconf->lua)) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "ngx_lua_content_by_file_handler: error lua stack"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } return NGX_OK; }
static char * ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_referer_conf_t *rlcf = conf; u_char *p; ngx_str_t *value, uri; ngx_uint_t i; if (rlcf->keys == NULL) { rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t)); if (rlcf->keys == NULL) { return NGX_CONF_ERROR; } rlcf->keys->pool = cf->pool; rlcf->keys->temp_pool = cf->pool; if (ngx_hash_keys_array_init(rlcf->keys, NGX_HASH_SMALL) != NGX_OK) { return NGX_CONF_ERROR; } } value = cf->args->elts; for (i = 1; i < cf->args->nelts; i++) { if (value[i].len == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid referer \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (ngx_strcmp(value[i].data, "none") == 0) { rlcf->no_referer = 1; continue; } if (ngx_strcmp(value[i].data, "blocked") == 0) { rlcf->blocked_referer = 1; continue; } if (ngx_strcmp(value[i].data, "server_names") == 0) { rlcf->server_names = 1; continue; } if (value[i].data[0] == '~') { if (ngx_http_add_regex_referer(cf, rlcf, &value[i]) != NGX_OK) { return NGX_CONF_ERROR; } continue; } ngx_str_null(&uri); p = (u_char *) ngx_strchr(value[i].data, '/'); if (p) { uri.len = (value[i].data + value[i].len) - p; uri.data = p; value[i].len = p - value[i].data; } if (ngx_http_add_referer(cf, rlcf->keys, &value[i], &uri) != NGX_OK) { return NGX_CONF_ERROR; } } return NGX_CONF_OK; }
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; } h->value.data = h->key.data + h->key.len + 1; h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1; 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; } }
static char * ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_limit_req_conf_t *lrcf = conf; ngx_int_t burst; ngx_str_t *value, s, forbid_action; ngx_uint_t i, nodelay; ngx_shm_zone_t *shm_zone; ngx_http_limit_req_limit_t *limit_req; value = cf->args->elts; if (cf->args->nelts == 2) { if (ngx_strncmp(value[1].data, "off", 3) == 0) { lrcf->enable = 0; return NGX_CONF_OK; } } lrcf->enable = 1; shm_zone = NULL; burst = 0; nodelay = 0; ngx_str_null(&forbid_action); for (i = 1; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { s.len = value[i].len - 5; s.data = value[i].data + 5; shm_zone = ngx_shared_memory_add(cf, &s, 0, &ngx_http_limit_req_module); if (shm_zone == NULL) { return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "burst=", 6) == 0) { burst = ngx_atoi(value[i].data + 6, value[i].len - 6); if (burst == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid burst rate \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "forbid_action=", 14) == 0) { s.len = value[i].len - 14; s.data = value[i].data + 14; if (s.len < 2 || (s.data[0] != '@' && s.data[0] != '/')) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid forbid_action \"%V\"", &value[i]); return NGX_CONF_ERROR; } forbid_action = s; continue; } if (ngx_strcmp(value[i].data, "nodelay") == 0) { nodelay = 1; continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (shm_zone == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%V\" must have \"zone\" parameter", &cmd->name); return NGX_CONF_ERROR; } /* if (shm_zone->data == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unknown limit_req_zone \"%V\"", &shm_zone->shm.name); return NGX_CONF_ERROR; } */ if (lrcf->rules == NULL) { lrcf->rules = ngx_array_create(cf->pool, 5, sizeof(ngx_http_limit_req_limit_t)); if (lrcf->rules == NULL) { return NGX_CONF_ERROR; } } limit_req = lrcf->rules->elts; for (i = 0; i < lrcf->rules->nelts; i++) { if (shm_zone == limit_req[i].shm_zone) { return "is duplicate"; } } limit_req = ngx_array_push(lrcf->rules); if (limit_req == NULL) { return NGX_CONF_ERROR; } ngx_memzero(limit_req, sizeof(ngx_http_limit_req_limit_t)); limit_req->shm_zone = shm_zone; limit_req->burst = burst * 1000; limit_req->nodelay = nodelay; limit_req->forbid_action = forbid_action; return NGX_CONF_OK; }
static ngx_int_t ngx_http_tfs_update_info_node(ngx_http_tfs_t *t, ngx_http_tfs_rc_ctx_t *rc_ctx, ngx_http_tfs_rcs_info_t *rc_info_node, u_char *base_info) { u_char *p; ngx_int_t rc; ngx_uint_t i, j; ngx_http_tfs_group_info_t *group_info; ngx_http_tfs_logical_cluster_t *logical_cluster; ngx_http_tfs_physical_cluster_t *physical_cluster; ngx_http_tfs_cluster_group_info_t *cluster_group_info; ngx_http_tfs_tair_server_addr_info_t *dup_server_info; p = base_info; /* free old rc servers */ if (rc_info_node->rc_servers != NULL) { ngx_slab_free_locked(rc_ctx->shpool, rc_info_node->rc_servers); } rc_info_node->rc_servers_count = 0; /* free old cluster data */ logical_cluster = rc_info_node->logical_clusters; for (i = 0; i < rc_info_node->logical_cluster_count; i++) { /* free old duplicate server info */ if (logical_cluster->need_duplicate) { dup_server_info = &logical_cluster->dup_server_info; for (j = 0; j < NGX_HTTP_TFS_TAIR_SERVER_ADDR_PART_COUNT; j++) { if (dup_server_info->server[j].data == NULL) { break; } ngx_slab_free_locked(rc_ctx->shpool, dup_server_info->server[j].data); ngx_str_null(&dup_server_info->server[j]); } logical_cluster->dup_server_addr_hash = -1; logical_cluster->need_duplicate = 0; } physical_cluster = logical_cluster->rw_clusters; for (j = 0; j < logical_cluster->rw_cluster_count; i++) { if (physical_cluster->cluster_id_text.len <= 0 || physical_cluster->cluster_id_text.data == NULL) { break; } ngx_slab_free_locked(rc_ctx->shpool, physical_cluster->cluster_id_text.data); ngx_str_null(&physical_cluster->cluster_id_text); physical_cluster->cluster_id = 0; if (physical_cluster->ns_vip_text.len <= 0 || physical_cluster->ns_vip_text.data == NULL) { break; } ngx_slab_free_locked(rc_ctx->shpool, physical_cluster->ns_vip_text.data); ngx_str_null(&physical_cluster->ns_vip_text); physical_cluster++; } logical_cluster->rw_cluster_count = 0; logical_cluster++; } rc_info_node->logical_cluster_count = 0; /* reset need duplicate flag */ rc_info_node->need_duplicate = 0; /* free old remote block cache info */ if (rc_info_node->remote_block_cache_info.len > 0 && rc_info_node->remote_block_cache_info.data != NULL) { ngx_slab_free_locked(rc_ctx->shpool, rc_info_node->remote_block_cache_info.data); ngx_str_null(&rc_info_node->remote_block_cache_info); } rc_info_node->remote_block_cache_info.len = 0; /* free old unlink cluster */ cluster_group_info = rc_info_node->unlink_clusters; for (i = 0; i < rc_info_node->unlink_cluster_count; i++) { for (j = 0; j < cluster_group_info[i].info_count; j++) { group_info = &cluster_group_info[i].group_info[j]; if (group_info->ns_vip_text.len <= 0 || group_info->ns_vip_text.data == NULL) { break; } ngx_slab_free_locked(rc_ctx->shpool, group_info->ns_vip_text.data); ngx_str_null(&group_info->ns_vip_text); } } rc_info_node->unlink_cluster_count = 0; /* parse rc info */ rc = ngx_http_tfs_parse_rc_info(rc_info_node, rc_ctx, p); if (rc == NGX_ERROR) { return NGX_ERROR; } t->rc_info_node = rc_info_node; return NGX_OK; }
void ngx_http_tfs_rc_server_destroy_node(ngx_http_tfs_rc_ctx_t *rc_ctx, ngx_http_tfs_rcs_info_t *rc_info_node) { ngx_str_t *block_cache_info; ngx_uint_t i, j; ngx_rbtree_node_t *node; ngx_http_tfs_group_info_t *group_info; ngx_http_tfs_logical_cluster_t *logical_cluster; ngx_http_tfs_physical_cluster_t *physical_cluster; ngx_http_tfs_cluster_group_info_t *cluster_group_info; ngx_http_tfs_tair_server_addr_info_t *dup_server_info; if (rc_info_node == NULL) { return; } if (rc_info_node->session_id.len <= 0 || rc_info_node->session_id.data == NULL) { goto last_free; } ngx_slab_free_locked(rc_ctx->shpool, rc_info_node->session_id.data); ngx_str_null(&rc_info_node->session_id); if (rc_info_node->rc_servers_count <= 0 || rc_info_node->rc_servers == NULL) { goto last_free; } ngx_slab_free_locked(rc_ctx->shpool, rc_info_node->rc_servers); block_cache_info = &rc_info_node->remote_block_cache_info; rc_info_node->rc_servers = NULL; logical_cluster = rc_info_node->logical_clusters; for (i = 0; i < rc_info_node->logical_cluster_count; i++) { if (logical_cluster->need_duplicate) { dup_server_info = &logical_cluster->dup_server_info; for (i = 0; i < NGX_HTTP_TFS_TAIR_SERVER_ADDR_PART_COUNT; i++) { if (dup_server_info->server[i].data == NULL) { goto last_free; } ngx_slab_free_locked(rc_ctx->shpool, dup_server_info->server[i].data); ngx_str_null(&dup_server_info->server[i]); } } physical_cluster = logical_cluster->rw_clusters; for (j = 0; j < logical_cluster->rw_cluster_count; j++) { if (physical_cluster[j].cluster_id_text.len <= 0 || physical_cluster[j].cluster_id_text.data == NULL) { goto last_free; } ngx_slab_free_locked(rc_ctx->shpool, physical_cluster[j].cluster_id_text.data); ngx_str_null(&physical_cluster[j].cluster_id_text); physical_cluster[j].cluster_id = 0; if (physical_cluster[j].ns_vip_text.len <= 0 || physical_cluster[j].ns_vip_text.data == NULL) { goto last_free; } ngx_slab_free_locked(rc_ctx->shpool, physical_cluster[j].ns_vip_text.data); ngx_str_null(&physical_cluster[j].ns_vip_text); physical_cluster++; } logical_cluster++; } if (block_cache_info->len <= 0 || block_cache_info->data == NULL) { goto last_free; } ngx_slab_free_locked(rc_ctx->shpool, block_cache_info->data); ngx_str_null(&rc_info_node->remote_block_cache_info); cluster_group_info = rc_info_node->unlink_cluster_groups; for (i = 0; i < rc_info_node->unlink_cluster_group_count; i++) { for (j = 0; j < cluster_group_info[i].info_count; j++) { group_info = &cluster_group_info[i].group_info[j]; if (group_info->ns_vip_text.len <= 0 || group_info->ns_vip_text.data == NULL) { break; } ngx_slab_free_locked(rc_ctx->shpool, group_info->ns_vip_text.data); ngx_str_null(&group_info->ns_vip_text); } } last_free: node = (ngx_rbtree_node_t *) ((u_char *) rc_info_node - offsetof(ngx_rbtree_node_t, color)); ngx_slab_free_locked(rc_ctx->shpool, node); }
ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree) { void *data, *prev; u_char *p, *name; size_t len; ngx_int_t rc; ngx_err_t err; ngx_str_t file, buf; ngx_dir_t dir; ngx_str_null(&buf); ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "walk tree \"%V\"", tree); if (ngx_open_dir(tree, &dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_open_dir_n " \"%s\" failed", tree->data); return NGX_ERROR; } prev = ctx->data; if (ctx->alloc) { data = ngx_alloc(ctx->alloc, ctx->log); if (data == NULL) { goto failed; } if (ctx->init_handler(data, prev) == NGX_ABORT) { goto failed; } ctx->data = data; } else { data = NULL; } for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOMOREFILES) { rc = NGX_OK; } else { ngx_log_error(NGX_LOG_CRIT, ctx->log, err, ngx_read_dir_n " \"%s\" failed", tree->data); rc = NGX_ERROR; } goto done; } len = ngx_de_namelen(&dir); name = ngx_de_name(&dir); ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree name %uz:\"%s\"", len, name); if (len == 1 && name[0] == '.') { continue; } if (len == 2 && name[0] == '.' && name[1] == '.') { continue; } file.len = tree->len + 1 + len; if (file.len + NGX_DIR_MASK_LEN > buf.len) { if (buf.len) { ngx_free(buf.data); } buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN; buf.data = ngx_alloc(buf.len + 1, ctx->log); if (buf.data == NULL) { goto failed; } } p = ngx_cpymem(buf.data, tree->data, tree->len); *p++ = '/'; ngx_memcpy(p, name, len + 1); file.data = buf.data; ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree path \"%s\"", file.data); if (!dir.valid_info) { if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_de_info_n " \"%s\" failed", file.data); continue; } } if (ngx_de_is_file(&dir)) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree file \"%s\"", file.data); ctx->size = ngx_de_size(&dir); ctx->fs_size = ngx_de_fs_size(&dir); ctx->access = ngx_de_access(&dir); ctx->mtime = ngx_de_mtime(&dir); if (ctx->file_handler(ctx, &file) == NGX_ABORT) { goto failed; } } else if (ngx_de_is_dir(&dir)) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree enter dir \"%s\"", file.data); ctx->access = ngx_de_access(&dir); ctx->mtime = ngx_de_mtime(&dir); rc = ctx->pre_tree_handler(ctx, &file); if (rc == NGX_ABORT) { goto failed; } if (rc == NGX_DECLINED) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree skip dir \"%s\"", file.data); continue; } if (ngx_walk_tree(ctx, &file) == NGX_ABORT) { goto failed; } ctx->access = ngx_de_access(&dir); ctx->mtime = ngx_de_mtime(&dir); if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) { goto failed; } } else { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree special \"%s\"", file.data); if (ctx->spec_handler(ctx, &file) == NGX_ABORT) { goto failed; } } } failed: rc = NGX_ABORT; done: if (buf.len) { ngx_free(buf.data); } if (data) { ngx_free(data); ctx->data = prev; } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", tree->data); } return rc; }
static ngx_int_t ngx_http_header_filter(ngx_http_request_t *r) { u_char *p; size_t len; ngx_str_t host, *status_line; ngx_buf_t *b; ngx_uint_t status, i, port; ngx_chain_t out; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif u_char addr[NGX_SOCKADDR_STRLEN]; if (r->header_sent) { return NGX_OK; } r->header_sent = 1; if (r != r->main) { return NGX_OK; } if (r->http_version < NGX_HTTP_VERSION_10) { return NGX_OK; } if (r->method == NGX_HTTP_HEAD) { r->header_only = 1; } if (r->headers_out.last_modified_time != -1) { if (r->headers_out.status != NGX_HTTP_OK && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) { r->headers_out.last_modified_time = -1; r->headers_out.last_modified = NULL; } } len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 /* the end of the header */ + sizeof(CRLF) - 1; /* status line */ if (r->headers_out.status_line.len) { len += r->headers_out.status_line.len; status_line = &r->headers_out.status_line; #if (NGX_SUPPRESS_WARN) status = 0; #endif } else { status = r->headers_out.status; if (status >= NGX_HTTP_OK && status < NGX_HTTP_LAST_2XX) { /* 2XX */ if (status == NGX_HTTP_NO_CONTENT) { r->header_only = 1; ngx_str_null(&r->headers_out.content_type); r->headers_out.last_modified_time = -1; r->headers_out.last_modified = NULL; r->headers_out.content_length = NULL; r->headers_out.content_length_n = -1; } status -= NGX_HTTP_OK; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_MOVED_PERMANENTLY && status < NGX_HTTP_LAST_3XX) { /* 3XX */ if (status == NGX_HTTP_NOT_MODIFIED) { r->header_only = 1; } status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_BAD_REQUEST && status < NGX_HTTP_LAST_4XX) { /* 4XX */ status = status - NGX_HTTP_BAD_REQUEST + NGX_HTTP_OFF_4XX; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR && status < NGX_HTTP_LAST_5XX) { /* 5XX */ status = status - NGX_HTTP_INTERNAL_SERVER_ERROR + NGX_HTTP_OFF_5XX; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else { len += NGX_INT_T_LEN; status_line = NULL; } } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->headers_out.server == NULL) { len += clcf->server_tokens ? sizeof(ngx_http_server_full_string) - 1: sizeof(ngx_http_server_string) - 1; } if (r->headers_out.date == NULL) { len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; } if (r->headers_out.content_type.len) { len += sizeof("Content-Type: ") - 1 + r->headers_out.content_type.len + 2; if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { len += sizeof("; charset=") - 1 + r->headers_out.charset.len; } } if (r->headers_out.content_length == NULL && r->headers_out.content_length_n >= 0) { len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2; } if (r->headers_out.last_modified == NULL && r->headers_out.last_modified_time != -1) { len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; } c = r->connection; if (r->headers_out.location && r->headers_out.location->value.len && r->headers_out.location->value.data[0] == '/') { r->headers_out.location->hash = 0; if (clcf->server_name_in_redirect) { cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); host = cscf->server_name; } else if (r->headers_in.server.len) { host = r->headers_in.server; } else { host.len = NGX_SOCKADDR_STRLEN; host.data = addr; if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) { return NGX_ERROR; } } switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) c->local_sockaddr; port = ntohs(sin6->sin6_port); break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: port = 0; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) c->local_sockaddr; port = ntohs(sin->sin_port); break; } len += sizeof("Location: https://") - 1 + host.len + r->headers_out.location->value.len + 2; if (clcf->port_in_redirect) { #if (NGX_HTTP_SSL) if (c->ssl) port = (port == 443) ? 0 : port; else #endif port = (port == 80) ? 0 : port; } else { port = 0; } if (port) { len += sizeof(":65535") - 1; } } else { ngx_str_null(&host); port = 0; } if (r->chunked) { len += sizeof("Transfer-Encoding: chunked" CRLF) - 1; } if (r->keepalive) { len += sizeof("Connection: keep-alive" CRLF) - 1; /* * MSIE and Opera ignore the "Keep-Alive: timeout=<N>" header. * MSIE keeps the connection alive for about 60-65 seconds. * Opera keeps the connection alive very long. * Mozilla keeps the connection alive for N plus about 1-10 seconds. * Konqueror keeps the connection alive for about N seconds. */ if (clcf->keepalive_header) { len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2; } } else { len += sizeof("Connection: closed" CRLF) - 1; } #if (NGX_HTTP_GZIP) if (r->gzip_vary) { if (clcf->gzip_vary) { len += sizeof("Vary: Accept-Encoding" CRLF) - 1; } else { r->gzip_vary = 0; } } #endif part = &r->headers_out.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header[i].hash == 0) { continue; } len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len + sizeof(CRLF) - 1; } b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return NGX_ERROR; } /* "HTTP/1.x " */ b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1); /* status line */ if (status_line) { b->last = ngx_copy(b->last, status_line->data, status_line->len); } else { b->last = ngx_sprintf(b->last, "%ui", status); } *b->last++ = CR; *b->last++ = LF; if (r->headers_out.server == NULL) { if (clcf->server_tokens) { p = (u_char *) ngx_http_server_full_string; len = sizeof(ngx_http_server_full_string) - 1; } else { p = (u_char *) ngx_http_server_string; len = sizeof(ngx_http_server_string) - 1; } b->last = ngx_cpymem(b->last, p, len); } if (r->headers_out.date == NULL) { b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1); b->last = ngx_cpymem(b->last, ngx_cached_http_time.data, ngx_cached_http_time.len); *b->last++ = CR; *b->last++ = LF; } if (r->headers_out.content_type.len) { b->last = ngx_cpymem(b->last, "Content-Type: ", sizeof("Content-Type: ") - 1); p = b->last; b->last = ngx_copy(b->last, r->headers_out.content_type.data, r->headers_out.content_type.len); if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { b->last = ngx_cpymem(b->last, "; charset=", sizeof("; charset=") - 1); b->last = ngx_copy(b->last, r->headers_out.charset.data, r->headers_out.charset.len); /* update r->headers_out.content_type for possible logging */ r->headers_out.content_type.len = b->last - p; r->headers_out.content_type.data = p; } *b->last++ = CR; *b->last++ = LF; } if (r->headers_out.content_length == NULL && r->headers_out.content_length_n >= 0) { b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF, r->headers_out.content_length_n); } if (r->headers_out.last_modified == NULL && r->headers_out.last_modified_time != -1) { b->last = ngx_cpymem(b->last, "Last-Modified: ", sizeof("Last-Modified: ") - 1); b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); *b->last++ = CR; *b->last++ = LF; } if (host.data) { p = b->last + sizeof("Location: ") - 1; b->last = ngx_cpymem(b->last, "Location: http", sizeof("Location: http") - 1); #if (NGX_HTTP_SSL) if (c->ssl) { *b->last++ ='s'; } #endif *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/'; b->last = ngx_copy(b->last, host.data, host.len); if (port) { b->last = ngx_sprintf(b->last, ":%ui", port); } b->last = ngx_copy(b->last, r->headers_out.location->value.data, r->headers_out.location->value.len); /* update r->headers_out.location->value for possible logging */ r->headers_out.location->value.len = b->last - p; r->headers_out.location->value.data = p; ngx_str_set(&r->headers_out.location->key, "Location"); *b->last++ = CR; *b->last++ = LF; } if (r->chunked) { b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF, sizeof("Transfer-Encoding: chunked" CRLF) - 1); } if (r->keepalive) { b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF, sizeof("Connection: keep-alive" CRLF) - 1); if (clcf->keepalive_header) { b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF, clcf->keepalive_header); } } else { b->last = ngx_cpymem(b->last, "Connection: close" CRLF, sizeof("Connection: close" CRLF) - 1); } #if (NGX_HTTP_GZIP) if (r->gzip_vary) { b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF, sizeof("Vary: Accept-Encoding" CRLF) - 1); } #endif part = &r->headers_out.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header[i].hash == 0) { continue; } b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); *b->last++ = ':'; *b->last++ = ' '; b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); *b->last++ = CR; *b->last++ = LF; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "%*s", (size_t) (b->last - b->pos), b->pos); /* the end of HTTP header */ *b->last++ = CR; *b->last++ = LF; r->header_size = b->last - b->pos; if (r->header_only) { b->last_buf = 1; } out.buf = b; out.next = NULL; return ngx_http_write_filter(r, &out); }
/* same as ngx_mail_throttle_user, but works on a fully qualified user name */ static void ngx_mail_throttle_quser (ngx_str_t * quser, throttle_callback_t *callback) { ngx_log_t *log; ngx_pool_t *pool; mc_work_t w; ngx_str_t k; ngx_str_t *value, *key; ngx_flag_t check_only; pool = callback->pool; log = callback->log; check_only = callback->check_only; k = ngx_mail_throttle_get_user_throttle_key(pool, log, *quser); if (k.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (generate key for get)", quser); callback->on_allow(callback); return; } key = ngx_pstrcpy (pool, &k); if (key == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (deep copy check user key)", quser); callback->on_allow(callback); } if (check_only == 0) { // try to increment the counter for this user ngx_log_error (NGX_LOG_INFO, log, 0, "check user throttle:%V", quser); w.ctx = callback; w.request_code = mcreq_incr; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_quser_success_handler; w.on_failure = ngx_mail_throttle_quser_failure_handler; value = ngx_palloc (pool, sizeof(ngx_str_t)); if (value == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error" "in ip throttle control (alloc mem for incr value)", quser); callback->on_allow(callback); return; } ngx_str_set(value, "1"); } else { // just check the counter ngx_log_error (NGX_LOG_INFO, log, 0, "check user throttle:%V, check only", quser); w.ctx = callback; w.request_code = mcreq_get; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_quser_success_handler; w.on_failure = ngx_mail_throttle_quser_failure_handler; value = ngx_palloc (pool, sizeof(ngx_str_t)); if (value == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in user throttle control (alloc mem for get value)", quser); callback->on_allow(callback); return; } ngx_str_null (value); } callback->key = key; callback->value = value; callback->user = quser; ngx_memcache_post(&w, *key, *value,/* pool */ NULL, log); }
static ngx_int_t ngx_rtmp_control_record(ngx_http_request_t *r, ngx_str_t *method) { ngx_rtmp_record_app_conf_t *racf; ngx_rtmp_core_main_conf_t *cmcf; ngx_rtmp_core_srv_conf_t **pcscf, *cscf; ngx_rtmp_core_app_conf_t **pcacf, *cacf; ngx_rtmp_live_app_conf_t *lacf; ngx_rtmp_live_stream_t *ls; ngx_rtmp_live_ctx_t *lctx; ngx_rtmp_session_t *s; ngx_chain_t cl; ngx_uint_t sn, rn, n; ngx_str_t srv, app, rec, name, path; ngx_str_t msg; ngx_buf_t *b; ngx_int_t rc; size_t len; sn = 0; if (ngx_http_arg(r, (u_char *) "srv", sizeof("srv") - 1, &srv) == NGX_OK) { sn = ngx_atoi(srv.data, srv.len); } if (ngx_http_arg(r, (u_char *) "app", sizeof("app") - 1, &app) != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "rtmp_control: app not specified"); ngx_str_set(&msg, "Application not specified"); goto error; } ngx_memzero(&rec, sizeof(rec)); ngx_http_arg(r, (u_char *) "rec", sizeof("rec") - 1, &rec); ngx_memzero(&name, sizeof(name)); ngx_http_arg(r, (u_char *) "name", sizeof("name") - 1, &name); cmcf = ngx_rtmp_core_main_conf; if (cmcf == NULL) { ngx_str_set(&msg, "Missing main RTMP conf"); goto error; } /* find server */ if (sn >= cmcf->servers.nelts) { ngx_str_set(&msg, "Server index out of range"); goto error; } pcscf = cmcf->servers.elts; pcscf += sn; cscf = *pcscf; /* find application */ pcacf = cscf->applications.elts; cacf = NULL; for (n = 0; n < cscf->applications.nelts; ++n, ++pcacf) { if ((*pcacf)->name.len == app.len && ngx_strncmp((*pcacf)->name.data, app.data, app.len) == 0) { cacf = *pcacf; break; } } if (cacf == NULL) { ngx_str_set(&msg, "Application not found"); goto error; } lacf = cacf->app_conf[ngx_rtmp_live_module.ctx_index]; racf = cacf->app_conf[ngx_rtmp_record_module.ctx_index]; /* find live stream by name */ for (ls = lacf->streams[ngx_hash_key(name.data, name.len) % lacf->nbuckets]; ls; ls = ls->next) { len = ngx_strlen(ls->name); if (name.len == len && ngx_strncmp(name.data, ls->name, name.len) == 0) { break; } } if (ls == NULL) { ngx_str_set(&msg, "Live stream not found"); goto error; } /* find publisher context */ for (lctx = ls->ctx; lctx; lctx = lctx->next) { if (lctx->flags & NGX_RTMP_LIVE_PUBLISHING) { break; } } if (lctx == NULL) { ngx_str_set(&msg, "No publisher"); goto error; } s = lctx->session; /* find recorder */ rn = ngx_rtmp_record_find(racf, &rec); if (rn == NGX_CONF_UNSET_UINT) { ngx_str_set(&msg, "Recorder not found"); goto error; } ngx_memzero(&path, sizeof(path)); if (method->len == sizeof("start") - 1 && ngx_strncmp(method->data, "start", method->len) == 0) { rc = ngx_rtmp_record_open(s, rn, &path); } else if (method->len == sizeof("stop") - 1 && ngx_strncmp(method->data, "stop", method->len) == 0) { rc = ngx_rtmp_record_close(s, rn, &path); } else { ngx_str_set(&msg, "Undefined method"); goto error; } if (rc == NGX_ERROR) { ngx_str_set(&msg, "Recorder error"); goto error; } if (rc == NGX_AGAIN) { /* already opened/closed */ ngx_str_null(&path); r->header_only = 1; } r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = path.len; b = ngx_create_temp_buf(r->pool, path.len); if (b == NULL) { return NGX_ERROR; } ngx_memzero(&cl, sizeof(cl)); cl.buf = b; b->last = ngx_cpymem(b->pos, path.data, path.len); b->last_buf = 1; ngx_http_send_header(r); return ngx_http_output_filter(r, &cl); error: r->headers_out.status = NGX_HTTP_BAD_REQUEST; r->headers_out.content_length_n = msg.len; b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } ngx_memzero(&cl, sizeof(cl)); cl.buf = b; b->start = b->pos = msg.data; b->end = b->last = msg.data + msg.len; b->memory = 1; b->last_buf = 1; ngx_http_send_header(r); return ngx_http_output_filter(r, &cl); }
static void ngx_mail_proxy_smtp_handler(ngx_event_t *rev) { u_char *p; ngx_int_t rc; ngx_str_t line; ngx_buf_t *b; ngx_connection_t *c; ngx_mail_session_t *s; ngx_mail_proxy_conf_t *pcf; ngx_mail_core_srv_conf_t *cscf; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy smtp auth handler"); c = rev->data; s = c->data; if (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "upstream timed out"); c->timedout = 1; ngx_mail_proxy_internal_server_error(s); return; } rc = ngx_mail_proxy_read_response(s, s->mail_state); if (rc == NGX_AGAIN) { return; } if (rc == NGX_ERROR) { ngx_mail_proxy_upstream_error(s); return; } switch (s->mail_state) { case ngx_smtp_start: ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send ehlo"); s->connection->log->action = "sending HELO/EHLO to upstream"; cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); line.len = sizeof("HELO ") - 1 + cscf->server_name.len + 2; line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); p = ngx_cpymem(line.data, ((s->esmtp || pcf->xclient) ? "EHLO " : "HELO "), sizeof("HELO ") - 1); p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len); *p++ = CR; *p = LF; if (pcf->xclient) { s->mail_state = ngx_smtp_helo_xclient; } else if (s->auth_method == NGX_MAIL_AUTH_NONE) { s->mail_state = ngx_smtp_helo_from; } else { s->mail_state = ngx_smtp_helo; } break; case ngx_smtp_helo_xclient: ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send xclient"); s->connection->log->action = "sending XCLIENT to upstream"; line.len = sizeof("XCLIENT ADDR= LOGIN= NAME=" CRLF) - 1 + s->connection->addr_text.len + s->login.len + s->host.len; line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } line.len = ngx_sprintf(line.data, "XCLIENT ADDR=%V%s%V NAME=%V" CRLF, &s->connection->addr_text, (s->login.len ? " LOGIN="******""), &s->login, &s->host) - line.data; if (s->smtp_helo.len) { s->mail_state = ngx_smtp_xclient_helo; } else if (s->auth_method == NGX_MAIL_AUTH_NONE) { s->mail_state = ngx_smtp_xclient_from; } else { s->mail_state = ngx_smtp_xclient; } break; case ngx_smtp_xclient_helo: ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send client ehlo"); s->connection->log->action = "sending client HELO/EHLO to upstream"; line.len = sizeof("HELO " CRLF) - 1 + s->smtp_helo.len; line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } line.len = ngx_sprintf(line.data, ((s->esmtp) ? "EHLO %V" CRLF : "HELO %V" CRLF), &s->smtp_helo) - line.data; s->mail_state = (s->auth_method == NGX_MAIL_AUTH_NONE) ? ngx_smtp_helo_from : ngx_smtp_helo; break; case ngx_smtp_helo_from: case ngx_smtp_xclient_from: ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send mail from"); s->connection->log->action = "sending MAIL FROM to upstream"; line.len = s->smtp_from.len + sizeof(CRLF) - 1; line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } p = ngx_cpymem(line.data, s->smtp_from.data, s->smtp_from.len); *p++ = CR; *p = LF; s->mail_state = ngx_smtp_from; break; case ngx_smtp_from: ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send rcpt to"); s->connection->log->action = "sending RCPT TO to upstream"; line.len = s->smtp_to.len + sizeof(CRLF) - 1; line.data = ngx_pnalloc(c->pool, line.len); if (line.data == NULL) { ngx_mail_proxy_internal_server_error(s); return; } p = ngx_cpymem(line.data, s->smtp_to.data, s->smtp_to.len); *p++ = CR; *p = LF; s->mail_state = ngx_smtp_to; break; case ngx_smtp_helo: case ngx_smtp_xclient: case ngx_smtp_to: b = s->proxy->buffer; if (s->auth_method == NGX_MAIL_AUTH_NONE) { b->pos = b->start; } else { ngx_memcpy(b->start, smtp_auth_ok, sizeof(smtp_auth_ok) - 1); b->last = b->start + sizeof(smtp_auth_ok) - 1; } s->connection->read->handler = ngx_mail_proxy_handler; s->connection->write->handler = ngx_mail_proxy_handler; rev->handler = ngx_mail_proxy_handler; c->write->handler = ngx_mail_proxy_handler; pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); ngx_add_timer(s->connection->read, pcf->timeout); ngx_del_timer(c->read); c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); ngx_mail_proxy_handler(s->connection->write); return; default: #if (NGX_SUPPRESS_WARN) ngx_str_null(&line); #endif break; } if (c->send(c, line.data, line.len) < (ssize_t) line.len) { /* * we treat the incomplete sending as NGX_ERROR * because it is very strange here */ ngx_mail_proxy_internal_server_error(s); return; } s->proxy->buffer->pos = s->proxy->buffer->start; s->proxy->buffer->last = s->proxy->buffer->start; }
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; umcf = ngx_http_get_module_main_conf(r,ngx_http_upstream_module); for(;;){ rc = ngx_http_parse_header_line(r,&r->upstream->buffer,1); if(rc == NGX_OK){ h = ngx_list_push(&r->upstream->headers_in.headers); if(h == NULL){ return NGX_ERROR; } h->hash = r->header_hash; h->key.len = r->header_name_end - r->header_name_start; 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; } h->value.data = h->key.data + h->key.len + 1; h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1; 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); } 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; } if(rc == NGX_HTTP_PARSE_HEADER_DONE){ 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; } 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; } }
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; int always_forward_body = 0; ngx_uint_t method; ngx_http_request_body_t *body; int type; ngx_buf_t *b; unsigned vars_action; ngx_uint_t nsubreqs; ngx_uint_t index; size_t sr_statuses_len; size_t sr_headers_len; size_t sr_bodies_len; size_t sr_flags_len; unsigned custom_ctx; ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_post_subrequest_data_t *psr_data; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "only one argument is expected, but got %d", n); } luaL_checktype(L, 1, LUA_TTABLE); nsubreqs = lua_objlen(L, 1); if (nsubreqs == 0) { return luaL_error(L, "at least one subrequest should be specified"); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); coctx = ctx->cur_co_ctx; if (coctx == NULL) { return luaL_error(L, "no co ctx found"); } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua location capture, uri:\"%V\" c:%ud", &r->uri, r->main->count); sr_statuses_len = nsubreqs * sizeof(ngx_int_t); sr_headers_len = nsubreqs * sizeof(ngx_http_headers_out_t *); sr_bodies_len = nsubreqs * sizeof(ngx_str_t); sr_flags_len = nsubreqs * sizeof(uint8_t); p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len + sr_bodies_len + sr_flags_len); if (p == NULL) { return luaL_error(L, "no memory"); } coctx->sr_statuses = (void *) p; p += sr_statuses_len; coctx->sr_headers = (void *) p; p += sr_headers_len; coctx->sr_bodies = (void *) p; p += sr_bodies_len; coctx->sr_flags = (void *) p; coctx->nsubreqs = nsubreqs; coctx->pending_subreqs = 0; extra_vars = NULL; for (index = 0; index < nsubreqs; index++) { coctx->pending_subreqs++; lua_rawgeti(L, 1, index + 1); if (lua_isnil(L, -1)) { return luaL_error(L, "only array-like tables are allowed"); } dd("queries query: top %d", lua_gettop(L)); if (lua_type(L, -1) != LUA_TTABLE) { return luaL_error(L, "the query argument %d is not a table, " "but a %s", index, lua_typename(L, lua_type(L, -1))); } nargs = lua_objlen(L, -1); if (nargs != 1 && nargs != 2) { return luaL_error(L, "query argument %d expecting one or " "two arguments", index); } lua_rawgeti(L, 2, 1); /* queries query uri */ dd("queries query uri: %d", lua_gettop(L)); dd("first arg in first query: %s", lua_typename(L, lua_type(L, -1))); body = NULL; ngx_str_null(&extra_args); 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 "forward_body" option */ lua_getfield(L, 4, "always_forward_body"); always_forward_body = lua_toboolean(L, -1); lua_pop(L, 1); dd("always foward body: %d", always_forward_body); /* 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, "no 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, "no 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, "no 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; ngx_str_null(&args); flags = 0; rc = ngx_http_parse_unsafe_uri(r, &uri, &args, &flags); if (rc != NGX_OK) { dd("rc = %d", (int) rc); return luaL_error(L, "unsafe uri in argument #1: %s", p); } if (args.len == 0) { if (extra_args.len) { p = ngx_palloc(r->pool, extra_args.len); if (p == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(p, extra_args.data, extra_args.len); args.data = p; args.len = extra_args.len; } } else if (extra_args.len) { /* concatenate the two parts of args together */ len = args.len + (sizeof("&") - 1) + extra_args.len; p = ngx_palloc(r->pool, len); if (p == NULL) { return luaL_error(L, "no 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, "no memory"); } psr = (ngx_http_post_subrequest_t *) p; p += sizeof(ngx_http_post_subrequest_t); sr_ctx = (ngx_http_lua_ctx_t *) p; p += sizeof(ngx_http_lua_ctx_t); psr_data = (ngx_http_lua_post_subrequest_data_t *) p; ngx_memzero(sr_ctx, sizeof(ngx_http_lua_ctx_t)); /* set by ngx_memzero: * sr_ctx->run_post_subrequest = 0 * sr_ctx->free = NULL * sr_ctx->body = NULL */ 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_lua_init_ctx(sr, sr_ctx); sr_ctx->capture = 1; sr_ctx->index = index; sr_ctx->last_body = &sr_ctx->body; sr_ctx->vm_state = ctx->vm_state; ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module); rc = ngx_http_lua_adjust_subrequest(sr, method, always_forward_body, body, vars_action, extra_vars); if (rc != NGX_OK) { ngx_http_lua_cancel_subreq(sr); return luaL_error(L, "failed to adjust the subrequest: %d", (int) rc); } dd("queries query uri opts ctx? %d", lua_gettop(L)); /* stack: queries query uri ctx? */ if (custom_ctx) { ngx_http_lua_ngx_set_ctx_helper(L, sr, sr_ctx, -1); lua_pop(L, 3); } else { lua_pop(L, 2); } /* stack: queries */ } if (extra_vars) { ngx_array_destroy(extra_vars); } ctx->no_abort = 1; return lua_yield(L, 0); }
/* 打开配置文件 */ ngx_open_file_t * ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name) { ngx_str_t full; ngx_uint_t i; ngx_list_part_t *part; ngx_open_file_t *file; #if (NGX_SUPPRESS_WARN) ngx_str_null(&full); #endif if (name->len) { full = *name; if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) { return NULL; } part = &cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (full.len != file[i].name.len) { continue; } if (ngx_strcmp(full.data, file[i].name.data) == 0) { return &file[i]; } } } file = ngx_list_push(&cycle->open_files); if (file == NULL) { return NULL; } if (name->len) { file->fd = NGX_INVALID_FILE; file->name = full; } else { file->fd = ngx_stderr; file->name = *name; } file->flush = NULL; file->data = NULL; return file; }
//mytest_upstream_process_header方法可以解析HTTP响应头部,而这里只是简单的 //把上游服务器发送的HTTP头部添加到了请求r->upstream->headers_in.headers链表 //中。 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取出来,对将要转发给 //下游客户端的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; } h->value.data = h->key.data + h->key.len + 1; h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1; ngx_memcpy(h->key.data, r->header_name_start, h->key.len); h->value.data[h->value.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; //当mytest_upstream_process_header返回NGX_OK后 //upstream模块开始把上游的包体直接转发到下游客户端 } }
static ngx_int_t ngx_http_spdy_serverpush_header_filter(ngx_http_request_t *r) { int rc; size_t len; u_char *p, *buf, *last; ngx_buf_t *b; ngx_str_t host; ngx_uint_t i, j, count, port; ngx_chain_t *cl; ngx_list_part_t *part, *pt; ngx_table_elt_t *header, *h; ngx_connection_t *c; ngx_http_cleanup_t *cln; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; ngx_http_spdy_stream_t *stream; ngx_http_spdy_out_frame_t *frame; ngx_http_spdy_connection_t *sc; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif u_char addr[NGX_SOCKADDR_STRLEN]; ngx_int_t index=-1; if (!r->spdy_stream) { return ngx_http_next_header_filter(r); } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "spdy serverpush module header filter"); if (r->header_sent) { return NGX_OK; } r->header_sent = 1; if (r != r->main) { return NGX_OK; } c = r->connection; part = &r->headers_out.headers.part; header = part->elts; int isSet = 0; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header[i].hash == 0) { continue; } ngx_str_t xac = ngx_string("X-Associated-Content"); if(ngx_strncmp(&header[i].key, &xac, 20) == 0 ) { isSet=1; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "KEY-Value Pair: \"%V\" and \"%V\"", &header[i].key,&header[i].value); index=i; value=ngx_pstrdup(r->pool,&header[i].value); /*int count1=17; while(count1) { value++; count1--; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Value is : \"%s\" ", value); valueLen=header[i].value.len - 17;*/ ngx_int_t countSlash=0; ngx_int_t countLen=0; while(*value!='\0' && countSlash!=3) { if(*value=='/') countSlash++; if(countSlash!=3) value++; countLen++; } countLen--; valueLen=header[i].value.len - countLen; if(index!=-1) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "key-value : %d and %d", countLen,valueLen); } } } if(!isSet) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "spdy serverpush module header filter !isSet cond"); return ngx_http_next_header_filter(r); } if (r->method == NGX_HTTP_HEAD) { r->header_only = 1; } switch (r->headers_out.status) { case NGX_HTTP_OK: case NGX_HTTP_PARTIAL_CONTENT: break; case NGX_HTTP_NOT_MODIFIED: r->header_only = 1; break; case NGX_HTTP_NO_CONTENT: r->header_only = 1; ngx_str_null(&r->headers_out.content_type); r->headers_out.content_length = NULL; r->headers_out.content_length_n = -1; /* fall through */ default: r->headers_out.last_modified_time = -1; r->headers_out.last_modified = NULL; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "spdy serverpush module header filter 2"); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "From header spdy body filter \"%V?%V\"", &r->uri, &r->args); len = NGX_SPDY_NV_NUM_SIZE + ngx_http_spdy_nv_nsize("version") + ngx_http_spdy_nv_vsize("HTTP/1.1") + ngx_http_spdy_nv_nsize("status") + ngx_http_spdy_nv_vsize("418"); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); /*len += ngx_http_spdy_nv_nsize("url") +ngx_http_spdy_nv_vsize("https://localhost/test1.js");*/ len += ngx_http_spdy_nv_nsize("url") +ngx_http_spdy_nv_vsize(&header[index].value); if (r->headers_out.server == NULL) { len += ngx_http_spdy_nv_nsize("server"); len += clcf->server_tokens ? ngx_http_spdy_nv_vsize(NGINX_VER) : ngx_http_spdy_nv_vsize("nginx"); } if (r->headers_out.date == NULL) { len += ngx_http_spdy_nv_nsize("date") + ngx_http_spdy_nv_vsize("Wed, 31 Dec 1986 10:00:00 GMT"); } if (r->headers_out.content_type.len) { len += ngx_http_spdy_nv_nsize("content-type") + NGX_SPDY_NV_VLEN_SIZE + r->headers_out.content_type.len; if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { len += sizeof("; charset=") - 1 + r->headers_out.charset.len; } } if (r->headers_out.content_length == NULL && r->headers_out.content_length_n >= 0) { len += ngx_http_spdy_nv_nsize("content-length") + NGX_SPDY_NV_VLEN_SIZE + NGX_OFF_T_LEN; } if (r->headers_out.last_modified == NULL && r->headers_out.last_modified_time != -1) { len += ngx_http_spdy_nv_nsize("last-modified") + ngx_http_spdy_nv_vsize("Wed, 31 Dec 1986 10:00:00 GMT"); } if (r->headers_out.location && r->headers_out.location->value.len && r->headers_out.location->value.data[0] == '/') { r->headers_out.location->hash = 0; if (clcf->server_name_in_redirect) { cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); host = cscf->server_name; } else if (r->headers_in.server.len) { host = r->headers_in.server; } else { host.len = NGX_SOCKADDR_STRLEN; host.data = addr; if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) { return NGX_ERROR; } } switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) c->local_sockaddr; port = ntohs(sin6->sin6_port); break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: port = 0; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) c->local_sockaddr; port = ntohs(sin->sin_port); break; } len += ngx_http_spdy_nv_nsize("location") + ngx_http_spdy_nv_vsize("https://") + host.len + r->headers_out.location->value.len; if (clcf->port_in_redirect) { #if (NGX_HTTP_SSL) if (c->ssl) port = (port == 443) ? 0 : port; else #endif port = (port == 80) ? 0 : port; } else { port = 0; } if (port) { len += sizeof(":65535") - 1; } } else { ngx_str_null(&host); port = 0; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "spdy serverpush module header filter 3"); part = &r->headers_out.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header[i].hash == 0) { continue; } len += NGX_SPDY_NV_NLEN_SIZE + header[i].key.len + NGX_SPDY_NV_VLEN_SIZE + header[i].value.len; } buf = ngx_alloc(len, r->pool->log); if (buf == NULL) { return NGX_ERROR; } last = buf + NGX_SPDY_NV_NUM_SIZE; last = ngx_http_spdy_nv_write_name(last, "version"); last = ngx_http_spdy_nv_write_val(last, "HTTP/1.1"); last = ngx_http_spdy_nv_write_name(last, "status"); last = ngx_spdy_frame_write_uint16(last, 3); last = ngx_sprintf(last, "%03ui", r->headers_out.status); count = 2; last = ngx_http_spdy_nv_write_name(last, "url"); //last = ngx_http_spdy_nv_write_val(last, "https://localhost/test1.js"); #if 1 last = ngx_http_spdy_nv_write_vlen(last, header[index].value.len); last = ngx_cpymem(last, header[index].value.data, header[index].value.len); #endif count++; if (r->headers_out.server == NULL) { last = ngx_http_spdy_nv_write_name(last, "server"); last = clcf->server_tokens ? ngx_http_spdy_nv_write_val(last, NGINX_VER) : ngx_http_spdy_nv_write_val(last, "nginx"); count++; } if (r->headers_out.date == NULL) { last = ngx_http_spdy_nv_write_name(last, "date"); last = ngx_http_spdy_nv_write_vlen(last, ngx_cached_http_time.len); last = ngx_cpymem(last, ngx_cached_http_time.data, ngx_cached_http_time.len); count++; } if (r->headers_out.content_type.len) { last = ngx_http_spdy_nv_write_name(last, "content-type"); p = last + NGX_SPDY_NV_VLEN_SIZE; last = ngx_cpymem(p, r->headers_out.content_type.data, r->headers_out.content_type.len); if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { last = ngx_cpymem(last, "; charset=", sizeof("; charset=") - 1); last = ngx_cpymem(last, r->headers_out.charset.data, r->headers_out.charset.len); /* update r->headers_out.content_type for possible logging */ r->headers_out.content_type.len = last - p; r->headers_out.content_type.data = p; } (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE, r->headers_out.content_type.len); count++; } if (r->headers_out.content_length == NULL && r->headers_out.content_length_n >= 0) { last = ngx_http_spdy_nv_write_name(last, "content-length"); p = last + NGX_SPDY_NV_VLEN_SIZE; last = ngx_sprintf(p, "%O", r->headers_out.content_length_n); (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE, last - p); count++; } if (r->headers_out.last_modified == NULL && r->headers_out.last_modified_time != -1) { last = ngx_http_spdy_nv_write_name(last, "last-modified"); p = last + NGX_SPDY_NV_VLEN_SIZE; last = ngx_http_time(p, r->headers_out.last_modified_time); (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE, last - p); count++; } if (host.data) { last = ngx_http_spdy_nv_write_name(last, "location"); p = last + NGX_SPDY_NV_VLEN_SIZE; last = ngx_cpymem(p, "http", sizeof("http") - 1); #if (NGX_HTTP_SSL) if (c->ssl) { *last++ ='s'; } #endif *last++ = ':'; *last++ = '/'; *last++ = '/'; last = ngx_cpymem(last, host.data, host.len); if (port) { last = ngx_sprintf(last, ":%ui", port); } last = ngx_cpymem(last, r->headers_out.location->value.data, r->headers_out.location->value.len); /* update r->headers_out.location->value for possible logging */ r->headers_out.location->value.len = last - p; r->headers_out.location->value.data = p; ngx_str_set(&r->headers_out.location->key, "location"); (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE, r->headers_out.location->value.len); count++; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "spdy serverpush module header filter 4"); part = &r->headers_out.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header[i].hash == 0 || header[i].hash == 2) { continue; } if ((header[i].key.len == 6 && ngx_strncasecmp(header[i].key.data, (u_char *) "status", 6) == 0) || (header[i].key.len == 7 && ngx_strncasecmp(header[i].key.data, (u_char *) "version", 7) == 0)) { header[i].hash = 0; continue; } last = ngx_http_spdy_nv_write_nlen(last, header[i].key.len); ngx_strlow(last, header[i].key.data, header[i].key.len); last += header[i].key.len; p = last + NGX_SPDY_NV_VLEN_SIZE; last = ngx_cpymem(p, header[i].value.data, header[i].value.len); pt = part; h = header; for (j = i + 1; /* void */; j++) { if (j >= pt->nelts) { if (pt->next == NULL) { break; } pt = pt->next; h = pt->elts; j = 0; } if (h[j].hash == 0 || h[j].hash == 2 || h[j].key.len != header[i].key.len || ngx_strncasecmp(header[i].key.data, h[j].key.data, header[i].key.len)) { continue; } *last++ = '\0'; last = ngx_cpymem(last, h[j].value.data, h[j].value.len); h[j].hash = 2; } (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE, last - p); count++; } (void) ngx_spdy_frame_write_uint16(buf, count); stream = r->spdy_stream; sc = stream->connection; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "spdy serverpush module header filter 5"); myStream = ngx_http_spdy_create_stream(sc, get_next_even_stream_id(), 0); len = last - buf; b = ngx_create_temp_buf(r->pool, NGX_SPDY_FRAME_HEADER_SIZE + NGX_SPDY_SYN_STREAM_SIZE + deflateBound(&sc->zstream_out, len)); if (b == NULL) { ngx_free(buf); return NGX_ERROR; } b->last += NGX_SPDY_FRAME_HEADER_SIZE + NGX_SPDY_SYN_STREAM_SIZE; sc->zstream_out.next_in = buf; sc->zstream_out.avail_in = len; sc->zstream_out.next_out = b->last; sc->zstream_out.avail_out = b->end - b->last; rc = deflate(&sc->zstream_out, Z_SYNC_FLUSH); ngx_free(buf); if (rc != Z_OK) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "spdy deflate() failed: %d", rc); return NGX_ERROR; } ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", sc->zstream_out.next_in, sc->zstream_out.next_out, sc->zstream_out.avail_in, sc->zstream_out.avail_out, rc); b->last = sc->zstream_out.next_out; p = b->pos; p = ngx_spdy_frame_write_head(p, NGX_SPDY_SYN_STREAM); len = b->last - b->pos; r->header_size = len; if (r->header_only) { b->last_buf = 1; p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_FIN, len - NGX_SPDY_FRAME_HEADER_SIZE); } else { p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_UNIDIRECTIONAL, len - NGX_SPDY_FRAME_HEADER_SIZE); } p= ngx_spdy_frame_write_sid(p, myStream->id); (void) ngx_spdy_frame_write_associated_sid(p, stream->id); cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; frame = ngx_palloc(r->pool, sizeof(ngx_http_spdy_out_frame_t)); if (frame == NULL) { return NGX_ERROR; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "spdy serverpush module header filter 6"); frame->first = cl; frame->last = cl; frame->handler = ngx_http_spdy_syn_frame_handler; frame->free = NULL; frame->stream = myStream; frame->size = len; frame->priority = myStream->priority; frame->blocked = 1; frame->fin = r->header_only; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0, "spdy:%ui create SYN_STREAM frame %p: size:%uz", myStream->id, frame, frame->size); ngx_http_spdy_queue_blocked_frame(sc, frame); r->blocked++; cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_ERROR; } cln->handler = ngx_http_spdy_filter_cleanup; cln->data = myStream; myStream->waiting = 1; ngx_http_spdy_serverpush_filter_send(c, myStream); return ngx_http_next_header_filter(r); }