static int ngx_http_modsecurity_save_headers_in_visitor(void *data, const char *key, const char *value) { ngx_http_request_t *r = data; ngx_table_elt_t *h; ngx_http_header_t *hh; ngx_http_core_main_conf_t *cmcf; h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { return 0; } h->key.data = (u_char *)key; h->key.len = ngx_strlen(key); h->value.data = (u_char *)value; h->value.len = ngx_strlen(value); h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { return 0; } ngx_strlow(h->lowcase_key, h->key.data, h->key.len); h->hash = ngx_hash_key(h->lowcase_key, h->key.len); cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, h->lowcase_key, h->key.len); if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { return 0; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: save headers in: \"%V: %V\"", &h->key, &h->value); return 1; }
// the following function updates the pointers in headers_in (e.g. range) // to point to the respective elements inside the headers_in->headers array static void ngx_http_parallel_update_headers( ngx_http_request_t* r, ngx_http_headers_in_t* headers_in) { ngx_http_core_main_conf_t *cmcf; ngx_http_header_t *hh; ngx_list_part_t *part; ngx_table_elt_t **ph; ngx_table_elt_t *h; ngx_uint_t i; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); part = &headers_in->headers.part; h = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; h = part->elts; i = 0; } hh = ngx_hash_find(&cmcf->headers_in_hash, h[i].hash, h[i].lowcase_key, h[i].key.len); if (!hh) { continue; } ph = (ngx_table_elt_t **)((char *)headers_in + hh->offset); *ph = &h[i]; } }
static int ngx_http_modsecurity_save_headers_out_visitor(void *data, const char *key, const char *value) { ngx_http_request_t *r = data; ngx_table_elt_t *h, he; 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); h = &he; h->key.data = (u_char *)key; h->key.len = ngx_strlen(key); h->value.data = (u_char *)value; h->value.len = ngx_strlen(value); h->lowcase_key = ngx_palloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { return 0; } ngx_strlow(h->lowcase_key, h->key.data, h->key.len); h->hash = ngx_hash_key(h->lowcase_key, h->key.len); hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, h->lowcase_key, h->key.len); if (hh) { /* copy all */ if (hh->copy_handler(r, h, hh->conf) != NGX_OK) { return 0; } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: save headers out: \"%V: %V\"", &h->key, &h->value); return 1; }
ngx_int_t ngx_http_secure_token_init_body_filter(ngx_http_request_t *r, ngx_str_t* token) { ngx_http_secure_token_loc_conf_t *conf; ngx_http_secure_token_ctx_t* ctx; body_processor_t* processor; conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_token_filter_module); // Note: content_type_lowcase is already initialized since we called ngx_http_test_content_type processor = ngx_hash_find(&conf->processors_hash, r->headers_out.content_type_hash, r->headers_out.content_type_lowcase, r->headers_out.content_type_len); if (processor == NULL) { return NGX_DONE; } // add the token to all the URLs in the response ctx = ngx_pcalloc(r->pool, sizeof(*ctx)); if (ctx == NULL) { return NGX_ERROR; } ctx->token = *token; ctx->process = processor->process; ctx->processor_context_offset = processor->processor_context_offset; ctx->processor_params = processor->processor_params; ngx_http_set_ctx(r, ctx, ngx_http_secure_token_filter_module); ctx->last_out = &ctx->out; r->filter_need_in_memory = 1; ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); ngx_http_clear_etag(r); return NGX_OK; }
void find_test(ngx_hash_t *hash, ngx_str_t addr[], int num) { ngx_uint_t key; int loop; char prefix[] = " "; for (loop = 0; loop < num; loop++) { key = ngx_hash_key_lc(addr[loop].data, addr[loop].len); void *value = ngx_hash_find(hash, key, addr[loop].data, addr[loop].len); if (value) { printf("(url = \"%s\"%.*s, key = %-10ld) found, (ip = \"%s\")\n", addr[loop].data, Max_Url_Len - addr[loop].len, prefix, key, (char*)value); } else { printf("(url = \"%s\"%.*s, key = %-10d) not found!\n", addr[loop].data, Max_Url_Len - addr[loop].len, prefix, key); } } }
void * ngx_http_proxy_connect_test_block_ports(ngx_http_request_t *r) { size_t len; ngx_uint_t i, hash; ngx_hash_t *ports_hash = NULL; ngx_http_proxy_connect_loc_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_connect_module); ports_hash = &conf->ports; len = r->port_end - r->port_start; if (ports_hash->size == 0 || len == 0) { return NULL; } hash = 0; for (i = 0; i < len; i++) { hash = ngx_hash(hash, r->port_start[i]); } return ngx_hash_find(ports_hash, hash, r->port_start, len); }
void * ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key, u_char *name, size_t len) { void *value; if (hash->hash.buckets) { value = ngx_hash_find(&hash->hash, key, name, len); if (value) { return value; } } if (len == 0) { return NULL; } if (hash->wc_head && hash->wc_head->hash.buckets) { value = ngx_hash_find_wc_head(hash->wc_head, name, len); if (value) { return value; } } if (hash->wc_tail && hash->wc_tail->hash.buckets) { value = ngx_hash_find_wc_tail(hash->wc_tail, name, len); if (value) { return value; } } return NULL; }
void * ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len) { void *value; ngx_uint_t i, key; #if 0 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wct:\"%*s\"", len, name); #endif key = 0; for (i = 0; i < len; i++) { if (name[i] == '.') { break; } key = ngx_hash(key, name[i]); } if (i == len) { return NULL; } #if 0 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key); #endif value = ngx_hash_find(&hwc->hash, key, name, i); #if 0 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value); #endif if (value) { /* * the 2 low bits of value have the special meaning: * 00 - value is data pointer; * 11 - value is pointer to wildcard hash allowing "example.*". */ if ((uintptr_t) value & 2) { i++; hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3); value = ngx_hash_find_wc_tail(hwc, &name[i], len - i); if (value) { return value; } return hwc->value; } return value; } return hwc->value; }
static ngx_int_t ngx_http_wd_handler(ngx_http_request_t *r) { ngx_http_wd_loc_conf_t *wdlcf; ngx_str_t file_path; u_char *p, *n; u_char *hash_value; u_char buf[1024] = {}; u_char md5_digest[16]; ngx_md5_t md5; int fd, uri_len; ngx_uint_t key; ssize_t rlen; ngx_http_wd_ctx_t *ctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "web defacement handler begin"); wdlcf = ngx_http_get_module_loc_conf(r, ngx_http_web_defacement_module); if (!wdlcf->enabled || wdlcf->file_name_hash.buckets == NULL) { return NGX_DECLINED; } #if (NGX_HTTP_NETEYE_SECURITY) ctx = ngx_http_ns_get_module_ctx(r, ngx_http_web_defacement_module); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } #else ctx = ngx_http_get_module_ctx(r, ngx_http_web_defacement_module); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "web defacement module: r=%p, ctx=%p, uri=%p", r, ctx, &r->uri); if(ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_wd_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_web_defacement_module); } #endif uri_len = r->uri.len; // Get dir if (r->uri.data[r->uri.len - 1] == '/') { uri_len += wdlcf->index_file.len; } n = ngx_pnalloc(r->pool, wdlcf->orig_path.len + uri_len + 1); if (n == NULL) { return NGX_ERROR; } p = ngx_cpymem(n, wdlcf->orig_path.data, wdlcf->orig_path.len); if (r->uri.data[r->uri.len - 1] == '/' && wdlcf->index_file.len > 0) { p = ngx_cpymem(p, r->uri.data, r->uri.len); ngx_cpystrn(p, wdlcf->index_file.data, wdlcf->index_file.len + 1); } else { ngx_cpystrn(p, r->uri.data, r->uri.len + 1); } file_path.len = wdlcf->orig_path.len + uri_len; file_path.data = n; key = ngx_hash_key_lc(file_path.data, file_path.len); hash_value = ngx_hash_find(&wdlcf->file_name_hash, key, file_path.data, file_path.len); if (hash_value == NULL) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "In hash, can't find file %V, pass", &file_path); return NGX_DECLINED; } else { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Find file %s", (char *)file_path.data); } fd = open((const char *)file_path.data, O_RDONLY); if (fd < 0) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Can't open file: %V", &file_path); do_action: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "The uri is defaced, set variables"); ctx->defaced = 1; ctx->file.data = r->uri.data; ctx->file.len = r->uri.len; if (wdlcf->log_enabled) { ngx_http_wd_write_attack_log(r); } return NGX_DECLINED; } ngx_md5_init(&md5); while (1) { rlen = read(fd, buf, sizeof(buf)); if (rlen < 0) { close(fd); goto do_action; } if (rlen == 0) { break; } ngx_md5_update(&md5, (void *)buf, rlen); } close(fd); ngx_md5_final(md5_digest, &md5); if (memcmp(hash_value, md5_digest, sizeof(md5_digest)) != 0) { goto do_action; } return NGX_DECLINED; }
ngx_http_variable_value_t * ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) { ngx_http_variable_t *v; ngx_http_variable_value_t *vv; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len); if (v) { if (v->flags & NGX_HTTP_VAR_INDEXED) { return ngx_http_get_flushed_variable(r, v->index); } else { vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); if (vv && v->get_handler(r, vv, v->data) == NGX_OK) { return vv; } return NULL; } } vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { return NULL; } if (ngx_strncmp(name->data, "http_", 5) == 0) { if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } if (ngx_strncmp(name->data, "sent_http_", 10) == 0) { if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } if (ngx_strncmp(name->data, "upstream_http_", 14) == 0) { if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } if (ngx_strncmp(name->data, "cookie_", 7) == 0) { if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } if (ngx_strncmp(name->data, "arg_", 4) == 0) { if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } vv->not_found = 1; return vv; }
int ngx_http_tcl_setv_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Tcl_Obj *varObj; Tcl_Obj *valObj; ngx_http_request_t *r = getrequest(clientData); ngx_http_core_main_conf_t *cmcf; ngx_http_variable_t *v; ngx_http_variable_value_t *vv; int len; int rc; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "key value"); return TCL_ERROR; } varObj = objv[1]; valObj = objv[2]; rc = SetVarFromAny(interp, varObj); if (rc != TCL_OK) { return rc; } cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); v = ngx_hash_find(&cmcf->variables_hash, vartype_get_hash(varObj), vartype_get_name(varObj), vartype_get_namelen(varObj)); if (v == NULL) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "variable \"", Tcl_GetString(varObj), "\" not found", NULL); return TCL_ERROR; } if (v->flags & NGX_HTTP_VAR_CHANGEABLE) { if (v->set_handler != NULL) { vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { return TCL_ERROR; } vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = (u_char*)Tcl_GetStringFromObj(valObj, &len); vv->len = len; v->set_handler(r, vv, v->data); return TCL_OK; } if (v->flags & NGX_HTTP_VAR_INDEXED) { vv = &r->variables[v->index]; vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = (u_char*)Tcl_GetStringFromObj(valObj, &len); vv->len = len; return TCL_OK; } } Tcl_ResetResult(interp); Tcl_AppendResult(interp, "variable \"", Tcl_GetString(varObj), "\" is not changeable", NULL); return TCL_ERROR; }
uint32_t dvt_cache_label_id_from_name(dvt_cache_t *cache, ngx_str_t *name) { ngx_uint_t key_hash = ngx_hash_key(name->data, name->len); int64_t r = (uint64_t)ngx_hash_find(cache->label_ids, key_hash, name->data, name->len); return (uint32_t) r - ARBITRARY_OFFSET_TO_AVOID_PTR_EQ_NULL; }
static ngx_uint_t construct_request_buffer(ngx_http_request_t *r, passenger_loc_conf_t *slcf, passenger_context_t *context, buffer_construction_state *state, ngx_buf_t *b) { #define PUSH_STATIC_STR(str) \ do { \ if (b != NULL) { \ b->last = ngx_copy(b->last, (const u_char *) str, \ sizeof(str) - 1); \ } \ total_size += sizeof(str) - 1; \ } while (0) ngx_uint_t total_size = 0; ngx_str_t *union_station_filters; ngx_uint_t i; ngx_list_part_t *part; ngx_table_elt_t *header; size_t len; ngx_http_script_len_code_pt lcode; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; if (b != NULL) { b->last = ngx_copy(b->last, state->method.data, state->method.len); } total_size += state->method.len; if (b != NULL) { b->last = ngx_copy(b->last, state->escaped_uri.data, state->escaped_uri.len); } total_size += state->escaped_uri.len; if (r->args.len > 0) { if (b != NULL) { b->last = ngx_copy(b->last, "?", 1); b->last = ngx_copy(b->last, r->args.data, r->args.len); } total_size += r->args.len + 1; } PUSH_STATIC_STR(" HTTP/1.1\r\nConnection: close\r\n"); part = &r->headers_in.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 (ngx_hash_find(&slcf->headers_set_hash, header[i].hash, header[i].lowcase_key, header[i].key.len) || header_is_transfer_encoding(&header[i].key)) { continue; } if (b != NULL) { b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); b->last = ngx_copy(b->last, ": ", 2); b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); b->last = ngx_copy(b->last, "\r\n", 2); } total_size += header[i].key.len + header[i].value.len + 4; } if (r->headers_in.chunked) { PUSH_STATIC_STR("Content-Length: "); if (b != NULL) { b->last = ngx_copy(b->last, state->content_length.data, state->content_length.len); } total_size += state->content_length.len; PUSH_STATIC_STR("\r\n"); } if (slcf->headers_set_len) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); ngx_http_script_flush_no_cacheable_variables(r, slcf->flushes); le.ip = slcf->headers_set_len->elts; le.request = r; le.flushed = 1; while (*(uintptr_t *) le.ip) { while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; total_size += lcode(&le); } le.ip += sizeof(uintptr_t); } if (b != NULL) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = slcf->headers_set->elts; e.pos = b->last; e.request = r; e.flushed = 1; le.ip = slcf->headers_set_len->elts; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; /* skip the header line name length */ (void) lcode(&le); if (*(ngx_http_script_len_code_pt *) le.ip) { for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; } e.skip = (len == sizeof("\r\n") - 1) ? 1 : 0; } else { e.skip = 0; } le.ip += sizeof(uintptr_t); while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } e.ip += sizeof(uintptr_t); } b->last = e.pos; } } if (b != NULL) { b->last = ngx_copy(b->last, "!~: ", sizeof("!~: ") - 1); b->last = ngx_copy(b->last, state->core_password.data, state->core_password.len); b->last = ngx_copy(b->last, "\r\n", sizeof("\r\n") - 1); } total_size += (sizeof("!~: \r\n") - 1) + state->core_password.len; PUSH_STATIC_STR("!~DOCUMENT_ROOT: "); if (b != NULL) { b->last = ngx_copy(b->last, context->public_dir.data, context->public_dir.len); } total_size += context->public_dir.len; PUSH_STATIC_STR("\r\n"); if (context->base_uri.len > 0) { PUSH_STATIC_STR("!~SCRIPT_NAME: "); if (b != NULL) { b->last = ngx_copy(b->last, context->base_uri.data, context->base_uri.len); } total_size += context->base_uri.len; PUSH_STATIC_STR("\r\n"); } PUSH_STATIC_STR("!~REMOTE_ADDR: "); if (b != NULL) { b->last = ngx_copy(b->last, r->connection->addr_text.data, r->connection->addr_text.len); } total_size += r->connection->addr_text.len; PUSH_STATIC_STR("\r\n"); PUSH_STATIC_STR("!~REMOTE_PORT: "); if (b != NULL) { b->last = ngx_copy(b->last, state->remote_port.data, state->remote_port.len); } total_size += state->remote_port.len; PUSH_STATIC_STR("\r\n"); if (r->headers_in.user.len > 0) { PUSH_STATIC_STR("!~REMOTE_USER: "******"\r\n"); } if (slcf->app_group_name.data == NULL) { PUSH_STATIC_STR("!~PASSENGER_APP_GROUP_NAME: "); if (b != NULL) { b->last = ngx_copy(b->last, context->public_dir.data, context->public_dir.len); } total_size += context->public_dir.len; if (slcf->environment.data != NULL) { if (b != NULL) { b->last = ngx_copy(b->last, " (", 2); b->last = ngx_copy(b->last, slcf->environment.data, slcf->environment.len); b->last = ngx_copy(b->last, ")", 1); } total_size += (sizeof(" (") - 1) + slcf->environment.len + (sizeof(")") - 1); } PUSH_STATIC_STR("\r\n"); } PUSH_STATIC_STR("!~PASSENGER_APP_TYPE: "); if (b != NULL) { b->last = ngx_copy(b->last, state->app_type.data, state->app_type.len); } total_size += state->app_type.len; PUSH_STATIC_STR("\r\n"); if (slcf->union_station_filters != NGX_CONF_UNSET_PTR && slcf->union_station_filters->nelts > 0) { union_station_filters = (ngx_str_t *) slcf->union_station_filters->elts; for (i = 0; i < slcf->union_station_filters->nelts; i++) { PUSH_STATIC_STR("!~UNION_STATION_FILTERS: "); if (b != NULL) { b->last = ngx_copy(b->last, union_station_filters[i].data, union_station_filters[i].len); } total_size += union_station_filters[i].len; PUSH_STATIC_STR("\r\n"); } } if (b != NULL) { b->last = ngx_copy(b->last, slcf->options_cache.data, slcf->options_cache.len); } total_size += slcf->options_cache.len; if (slcf->env_vars_cache.data != NULL) { PUSH_STATIC_STR("!~PASSENGER_ENV_VARS: "); if (b != NULL) { b->last = ngx_copy(b->last, slcf->env_vars_cache.data, slcf->env_vars_cache.len); } total_size += slcf->env_vars_cache.len; PUSH_STATIC_STR("\r\n"); } /* D = Dechunk response * Prevent Nginx from rechunking the response. * C = Strip 100 Continue header * S = SSL */ PUSH_STATIC_STR("!~FLAGS: DC"); #if (NGX_HTTP_SSL) if (r->http_connection->ssl) { PUSH_STATIC_STR("S"); } #endif PUSH_STATIC_STR("\r\n\r\n"); return total_size; #undef PUSH_STATIC_STR }
static ngx_int_t ngx_child_request_copy_headers( ngx_http_request_t* r, ngx_child_request_params_t* params, ngx_http_headers_in_t* dest, ngx_http_headers_in_t* src) { ngx_child_request_hide_header_t *hide_header; ngx_http_core_main_conf_t *cmcf; ngx_list_part_t *part; ngx_table_elt_t *output; ngx_table_elt_t *ch; ngx_table_elt_t *h; ngx_uint_t i = 0; ngx_http_header_t *hh; ngx_table_elt_t **ph; ngx_uint_t count; ngx_int_t rc; // get the total header count count = 0; for (part = &src->headers.part; part; part = part->next) { count += part->nelts; } // allocate dest array rc = ngx_list_init(&dest->headers, r->pool, count + 2, sizeof(ngx_table_elt_t)); if (rc != NGX_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_child_request_copy_headers: ngx_list_init failed"); return NGX_ERROR; } output = dest->headers.last->elts; // copy relevant headers cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); part = &src->headers.part; h = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; h = part->elts; i = 0; } ch = h + i; // remove range if needed if (ch->hash == range_hash && !params->proxy_range && params->range_start >= params->range_end && ch->key.len == range_key.len && ngx_memcmp(ch->lowcase_key, range_lowcase_key, range_key.len) == 0) { dest->range = NULL; continue; } if (!params->proxy_all_headers) { // remove headers from the hide list hide_header = ngx_hash_find(&hide_headers_hash, ch->hash, ch->lowcase_key, ch->key.len); if (hide_header != NULL) { if (hide_header->offset >= 0) { *(ngx_table_elt_t**)((u_char*)dest + hide_header->offset) = NULL; } continue; } } // add the header to the output list *output = *ch; // update the header pointer, if exists hh = ngx_hash_find(&cmcf->headers_in_hash, ch->hash, ch->lowcase_key, ch->key.len); if (hh) { if ((ch->key.len == sizeof("cookie") - 1 && ngx_memcmp(ch->lowcase_key, "cookie", sizeof("cookie") - 1) == 0) || (ch->key.len == sizeof("x-forwarded-for") - 1 && ngx_memcmp(ch->lowcase_key, "x-forwarded-for", sizeof("x-forwarded-for") - 1) == 0)) { // multi header ngx_child_request_update_multi_header( (ngx_array_t*)((char *)dest + hh->offset), ch, output); } else { // single header ph = (ngx_table_elt_t **)((char *)dest + hh->offset); *ph = output; } } output++; } // add the extra header if needed if (params->extra_header.key.len != 0) { *output++ = params->extra_header; } // set the range if needed if (params->range_start < params->range_end) { if (dest->range == NULL) { h = output++; h->hash = range_hash; h->key = range_key; h->lowcase_key = range_lowcase_key; dest->range = h; } else { h = dest->range; } h->value.data = ngx_pnalloc(r->pool, sizeof(RANGE_FORMAT) + 2 * NGX_OFF_T_LEN); if (h->value.data == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_child_request_copy_headers: ngx_pnalloc failed"); return NGX_ERROR; } h->value.len = ngx_sprintf( h->value.data, RANGE_FORMAT, params->range_start, params->range_end - 1) - h->value.data; h->value.data[h->value.len] = '\0'; } // update the element count dest->headers.last->nelts = output - (ngx_table_elt_t*)dest->headers.last->elts; return NGX_OK; }
static mrb_value ngx_http_mruby_variable_set_internal(mrb_state *mrb, mrb_value self, char *k, mrb_value o) { ngx_http_request_t *r; ngx_http_variable_t *v; ngx_http_variable_value_t *vv; ngx_http_core_main_conf_t *cmcf; ngx_str_t key; ngx_uint_t hash; u_char *val, *low; r = ngx_http_mruby_get_request(); val = (u_char *)RSTRING_PTR(o); key.data = (u_char *)k; key.len = ngx_strlen(k); if (key.len) { low = ngx_pnalloc(r->pool, key.len); if (low == NULL) { return mrb_nil_value(); } } else { return mrb_nil_value(); } hash = ngx_hash_strlow(low, key.data, key.len); cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); v = ngx_hash_find(&cmcf->variables_hash, hash, key.data, key.len); if (v) { if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) { ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s:%d: %s not changeable" , MODULE_NAME , __FUNCTION__ , __LINE__ , key.data ); return mrb_nil_value(); } if (v->set_handler) { vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s:%d: memory allocate failed" , MODULE_NAME , __FUNCTION__ , __LINE__ ); return mrb_nil_value(); } vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = RSTRING_LEN(o); v->set_handler(r, vv, v->data); return mrb_str_new_cstr(mrb, (char *)val); } if (v->flags & NGX_HTTP_VAR_INDEXED) { vv = &r->variables[v->index]; vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = RSTRING_LEN(o); return mrb_str_new_cstr(mrb, (char *)val); } ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s:%d: %s is not assinged" , MODULE_NAME , __FUNCTION__ , __LINE__ , key.data ); return mrb_nil_value(); } ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s:%d: %s is not found" , MODULE_NAME , __FUNCTION__ , __LINE__ , key.data ); return mrb_nil_value(); }
static ngx_int_t process_header(ngx_http_request_t *r) { ngx_int_t rc; ngx_uint_t i; 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 ( ;; ) { #if NGINX_VERSION_NUM >= 7000 rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1); #else rc = ngx_http_parse_header_line(r, &r->upstream->buffer); #endif if (rc == NGX_OK) { /* a header line has been parsed successfully */ h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } 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; h->key.data = ngx_palloc(r->pool, h->key.len + 1 + h->value.len + 1 + h->key.len); if (h->key.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_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_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); if (h->key.len == r->lowcase_index) { ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); } else { for (i = 0; i < h->key.len; i++) { h->lowcase_key[i] = ngx_tolower(h->key.data[i]); } } 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_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http scgi header: \"%V: %V\"", &h->key, &h->value); continue; } if (rc == NGX_HTTP_PARSE_HEADER_DONE) { /* a whole header has been parsed successfully */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http scgi header done"); /* * if no "Server" and "Date" in header line, * then add the default headers */ if (r->upstream->headers_in.server == NULL) { h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash( ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r'); h->key.len = sizeof("Server") - 1; h->key.data = (u_char *) "Server"; h->value.data = (u_char *) (NGINX_VER " + Phusion Passenger " PASSENGER_VERSION " (mod_rails/mod_rack)"); h->value.len = ngx_strlen(h->value.data); 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_HTTP_INTERNAL_SERVER_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e'); h->key.len = sizeof("Date") - 1; h->key.data = (u_char *) "Date"; h->value.len = 0; h->value.data = NULL; h->lowcase_key = (u_char *) "date"; } return NGX_OK; } if (rc == NGX_AGAIN) { return NGX_AGAIN; } /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid header"); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } }
//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_scgi_process_header(ngx_http_request_t *r) { ngx_str_t *status_line; ngx_int_t rc, status; ngx_table_elt_t *h; ngx_http_upstream_t *u; 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) { /* a header line has been parsed successfully */ 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->value.len = r->header_end - r->header_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_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); 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; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http scgi header: \"%V: %V\"", &h->key, &h->value); continue; } if (rc == NGX_HTTP_PARSE_HEADER_DONE) { /* a whole header has been parsed successfully */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http scgi header done"); if (r->http_version > NGX_HTTP_VERSION_9) { return NGX_OK; } u = r->upstream; if (u->headers_in.status) { status_line = &u->headers_in.status->value; status = ngx_atoi(status_line->data, 3); if (status == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid status \"%V\"", status_line); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } r->http_version = NGX_HTTP_VERSION_10; u->headers_in.status_n = status; u->headers_in.status_line = *status_line; } else if (u->headers_in.location) { r->http_version = NGX_HTTP_VERSION_10; u->headers_in.status_n = 302; ngx_str_set(&u->headers_in.status_line, "302 Moved Temporarily"); } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent neither valid HTTP/1.0 header " "nor \"Status\" header line"); u->headers_in.status_n = 200; ngx_str_set(&u->headers_in.status_line, "200 OK"); } if (u->state) { u->state->status = u->headers_in.status_n; } return NGX_OK; } if (rc == NGX_AGAIN) { return NGX_AGAIN; } /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid header"); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } }
static ngx_int_t ngx_http_scgi_create_request(ngx_http_request_t *r) { u_char ch, *key, *val, *lowcase_key; size_t len, allocated; ngx_buf_t *b; ngx_str_t *content_length; ngx_uint_t i, n, hash, header_params; ngx_chain_t *cl, *body; ngx_list_part_t *part; ngx_table_elt_t *header, **ignored; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; ngx_http_scgi_loc_conf_t *scf; ngx_http_script_len_code_pt lcode; static ngx_str_t zero = ngx_string("0"); content_length = r->headers_in.content_length ? &r->headers_in.content_length->value : &zero; len = sizeof("CONTENT_LENGTH") + content_length->len + 1; header_params = 0; ignored = NULL; scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); if (scf->params_len) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); ngx_http_script_flush_no_cacheable_variables(r, scf->flushes); le.flushed = 1; le.ip = scf->params_len->elts; le.request = r; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; len += lcode(&le); while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; len += lcode(&le) + 1; } le.ip += sizeof(uintptr_t); } } if (scf->upstream.pass_request_headers) { allocated = 0; lowcase_key = NULL; if (scf->header_params) { ignored = ngx_palloc(r->pool, scf->header_params * sizeof(void *)); if (ignored == NULL) { return NGX_ERROR; } } part = &r->headers_in.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 (scf->header_params) { if (allocated < header[i].key.len) { allocated = header[i].key.len + 16; lowcase_key = ngx_pnalloc(r->pool, allocated); if (lowcase_key == NULL) { return NGX_ERROR; } } hash = 0; for (n = 0; n < header[i].key.len; n++) { ch = header[i].key.data[n]; if (ch >= 'A' && ch <= 'Z') { ch |= 0x20; } else if (ch == '-') { ch = '_'; } hash = ngx_hash(hash, ch); lowcase_key[n] = ch; } if (ngx_hash_find(&scf->headers_hash, hash, lowcase_key, n)) { ignored[header_params++] = &header[i]; continue; } } len += sizeof("HTTP_") - 1 + header[i].key.len + 1 + header[i].value.len + 1; } } /* netstring: "length:" + packet + "," */ b = ngx_create_temp_buf(r->pool, NGX_SIZE_T_LEN + 1 + len + 1); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; b->last = ngx_snprintf(b->last, NGX_SIZE_T_LEN + 1 + sizeof("CONTENT_LENGTH") + NGX_OFF_T_LEN + 1, "%ui:CONTENT_LENGTH%Z%V%Z", len, content_length); if (scf->params_len) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = scf->params->elts; e.pos = b->last; e.request = r; e.flushed = 1; while (*(uintptr_t *) e.ip) { #if (NGX_DEBUG) key = e.pos; #endif code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) & e); #if (NGX_DEBUG) val = e.pos; #endif while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } *e.pos++ = '\0'; e.ip += sizeof(uintptr_t); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "scgi param: \"%s: %s\"", key, val); } b->last = e.pos; } if (scf->upstream.pass_request_headers) { part = &r->headers_in.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; } for (n = 0; n < header_params; n++) { if (&header[i] == ignored[n]) { goto next; } } key = b->last; b->last = ngx_cpymem(key, "HTTP_", sizeof("HTTP_") - 1); for (n = 0; n < header[i].key.len; n++) { ch = header[i].key.data[n]; if (ch >= 'a' && ch <= 'z') { ch &= ~0x20; } else if (ch == '-') { ch = '_'; } *b->last++ = ch; } *b->last++ = (u_char) 0; val = b->last; b->last = ngx_copy(val, header[i].value.data, header[i].value.len); *b->last++ = (u_char) 0; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "scgi param: \"%s: %s\"", key, val); next: continue; } } *b->last++ = (u_char) ','; if (scf->upstream.pass_request_body) { body = r->upstream->request_bufs; r->upstream->request_bufs = cl; while (body) { b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NGX_ERROR; } cl = cl->next; cl->buf = b; body = body->next; } } else { r->upstream->request_bufs = cl; } cl->next = NULL; return NGX_OK; }
void * ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len) { void *value; ngx_uint_t i, n, key; #if 0 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wch:\"%*s\"", len, name); #endif n = len; while (n) { if (name[n - 1] == '.') { break; } n--; } key = 0; for (i = n; i < len; i++) { key = ngx_hash(key, name[i]); } #if 0 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key); #endif value = ngx_hash_find(&hwc->hash, key, &name[n], len - n); #if 0 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value); #endif if (value) { /* * the 2 low bits of value have the special meaning: * 00 - value is data pointer for both "example.com" * and "*.example.com"; * 01 - value is data pointer for "*.example.com" only; * 10 - value is pointer to wildcard hash allowing * both "example.com" and "*.example.com"; * 11 - value is pointer to wildcard hash allowing * "*.example.com" only. */ if ((uintptr_t) value & 2) { if (n == 0) { /* "example.com" */ if ((uintptr_t) value & 1) { return NULL; } hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3); return hwc->value; } hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3); value = ngx_hash_find_wc_head(hwc, name, n - 1); if (value) { return value; } return hwc->value; } if ((uintptr_t) value & 1) { if (n == 0) { /* "example.com" */ return NULL; } return (void *) ((uintptr_t) value & (uintptr_t) ~3); } return value; } return hwc->value; }
static ngx_int_t process_header(ngx_http_request_t *r) { ngx_str_t *status_line; ngx_int_t rc, status; ngx_table_elt_t *h; ngx_http_upstream_t *u; ngx_http_upstream_header_t *hh; ngx_http_upstream_main_conf_t *umcf; ngx_http_core_loc_conf_t *clcf; umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); for ( ;; ) { rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1); if (rc == NGX_OK) { /* a header line has been parsed successfully */ 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->value.len = r->header_end - r->header_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; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http scgi header: \"%V: %V\"", &h->key, &h->value); continue; } if (rc == NGX_HTTP_PARSE_HEADER_DONE) { /* a whole header has been parsed successfully */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http scgi header done"); /* * if no "Server" and "Date" in header line, * then add the default headers */ if (r->upstream->headers_in.server == NULL) { h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash( ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r'); h->key.len = sizeof("Server") - 1; h->key.data = (u_char *) "Server"; if (!passenger_main_conf.show_version_in_header) { if (clcf->server_tokens) { h->value.data = (u_char *) (NGINX_VER " + " PROGRAM_NAME); } else { h->value.data = (u_char *) ("nginx + " PROGRAM_NAME); } } else { if (clcf->server_tokens) { h->value.data = (u_char *) (NGINX_VER " + " PROGRAM_NAME " " PASSENGER_VERSION); } else { h->value.data = (u_char *) ("nginx + " PROGRAM_NAME " " PASSENGER_VERSION); } } h->value.len = ngx_strlen(h->value.data); 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_HTTP_INTERNAL_SERVER_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e'); h->key.len = sizeof("Date") - 1; h->key.data = (u_char *) "Date"; h->value.len = 0; h->value.data = NULL; h->lowcase_key = (u_char *) "date"; } /* Process "Status" header. */ u = r->upstream; if (u->headers_in.status_n) { goto done; } if (u->headers_in.status) { status_line = &u->headers_in.status->value; status = ngx_atoi(status_line->data, 3); if (status == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid status \"%V\"", status_line); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } u->headers_in.status_n = status; u->headers_in.status_line = *status_line; } else if (u->headers_in.location) { u->headers_in.status_n = 302; ngx_str_set(&u->headers_in.status_line, "302 Moved Temporarily"); } else { u->headers_in.status_n = 200; ngx_str_set(&u->headers_in.status_line, "200 OK"); } if (u->state && u->state->status == 0) { u->state->status = u->headers_in.status_n; } done: /* Supported since Nginx 1.3.15. */ #ifdef NGX_HTTP_SWITCHING_PROTOCOLS if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS && r->headers_in.upgrade) { u->upgrade = 1; } #endif return NGX_OK; } if (rc == NGX_AGAIN) { return NGX_AGAIN; } /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid header"); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } }
/** * Set nginx internal variable content * * @retval Always return a boolean on Lua stack. Return true when variable * content was modified successfully, false otherwise. * @seealso ngx_http_lua_var_get * */ static int ngx_http_lua_var_set(lua_State *L) { ngx_http_variable_t *v; ngx_http_variable_value_t *vv; ngx_http_core_main_conf_t *cmcf; u_char *p, *lowcase, *val; size_t len; ngx_str_t name; ngx_uint_t hash; ngx_http_request_t *r; int value_type; const char *msg; 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); /* we skip the first argument that is the table */ /* we read the variable name */ if (lua_type(L, 2) != LUA_TSTRING) { return luaL_error(L, "bad variable name"); } p = (u_char *) lua_tolstring(L, 2, &len); lowcase = lua_newuserdata(L, len + 1); hash = ngx_hash_strlow(lowcase, p, len); lowcase[len] = '\0'; name.len = len; name.data = lowcase; /* we read the variable new value */ value_type = lua_type(L, 3); switch (value_type) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) luaL_checklstring(L, 3, &len); val = ngx_palloc(r->pool, len); if (val == NULL) { return luaL_error(L, "memory allocation erorr"); } ngx_memcpy(val, p, len); break; case LUA_TNIL: /* undef the variable */ val = NULL; len = 0; break; default: msg = lua_pushfstring(L, "string, number, or nil expected, " "but got %s", lua_typename(L, value_type)); return luaL_argerror(L, 1, msg); } /* we fetch the variable itself */ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); v = ngx_hash_find(&cmcf->variables_hash, hash, name.data, name.len); if (v) { if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) { return luaL_error(L, "variable \"%s\" not changeable", lowcase); } if (v->set_handler) { dd("set variables with set_handler"); vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { return luaL_error(L, "no memory"); } if (value_type == LUA_TNIL) { vv->valid = 0; vv->not_found = 1; vv->no_cacheable = 0; vv->data = NULL; vv->len = 0; } else { vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; } v->set_handler(r, vv, v->data); return 0; } if (v->flags & NGX_HTTP_VAR_INDEXED) { vv = &r->variables[v->index]; dd("set indexed variable"); if (value_type == LUA_TNIL) { vv->valid = 0; vv->not_found = 1; vv->no_cacheable = 0; vv->data = NULL; vv->len = 0; } else { vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; } return 0; } return luaL_error(L, "variable \"%s\" cannot be assigned a value", lowcase); } /* variable not found */ return luaL_error(L, "variable \"%s\" not found for writing; " "maybe it is a built-in variable that is not changeable " "or you forgot to use \"set $%s '';\" " "in the config file to define it first", lowcase, lowcase); }
/* AJPV13_RESPONSE/AJPV14_RESPONSE:= response_prefix (2) status (short) status_msg (short) num_headers (short) num_headers*(res_header_name header_value) *body_chunk terminator boolean <! -- recycle connection or not --> req_header_name := sc_req_header_name | (string) res_header_name := sc_res_header_name | (string) header_value := (string) body_chunk := length (short) body length*(var binary) */ ngx_int_t ajp_unmarshal_response(ajp_msg_t *msg, ngx_http_request_t *r, ngx_http_ajp_loc_conf_t *alcf) { int i; u_char line[1024], *last; uint16_t status; uint16_t name; uint16_t num_headers; ngx_int_t rc; ngx_str_t str; ngx_log_t *log; ngx_table_elt_t *h; ngx_http_upstream_t *u; ngx_http_upstream_header_t *hh; ngx_http_upstream_main_conf_t *umcf; log = r->connection->log; umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); u = r->upstream; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "ajp_unmarshal_response"); rc = ajp_msg_get_uint16(msg, &status); if (rc != NGX_OK) { return rc; } u->headers_in.status_n = status; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "ajp_unmarshal_response: status = %d", status); rc = ajp_msg_get_string(msg, &str); if (rc == NGX_OK) { if (str.len > 0) { last = ngx_snprintf(line, 1024, "%d %V", status, &str); str.data = line; str.len = last - line; u->headers_in.status_line.data = ngx_pstrdup(r->pool, &str); u->headers_in.status_line.len = str.len; } else { u->headers_in.status_line.data = NULL; u->headers_in.status_line.len = 0; } } else { return rc; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "ajp_unmarshal_response: status_line = \"%V\"", &u->headers_in.status_line); if (u->state) { u->state->status = u->headers_in.status_n; } num_headers = 0; rc = ajp_msg_get_uint16(msg, &num_headers); if (rc != NGX_OK) { return rc; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "ajp_unmarshal_response: Number of headers is = %d", num_headers); for(i = 0 ; i < (int) num_headers ; i++) { rc = ajp_msg_peek_uint16(msg, &name); if (rc != NGX_OK) { return rc; } /* a header line has been parsed successfully */ h = ngx_list_push(&u->headers_in.headers); if (h == NULL) { return NGX_ERROR; } if ((name & 0XFF00) == 0XA000) { ajp_msg_get_uint16(msg, &name); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http ajp known header: %08Xd", name); rc = get_res_header_for_sc(name, h); if (rc != NGX_OK) { ngx_log_error(NGX_LOG_ERR, log, 0, "ajp_unmarshal_response: No such sc (%08Xd)", name); return NGX_ERROR; } } else { name = 0; rc = ajp_msg_get_string(msg, &str); if (rc != NGX_OK) { if (rc != AJP_EOVERFLOW) { ngx_log_error(NGX_LOG_ERR, log, 0, "ajp_unmarshal_response: Null header name"); } return rc; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http ajp unknown header: %V", &str); rc = get_res_unknown_header_by_str(&str, h, r->pool); if (rc != NGX_OK) { return rc; } } rc = ajp_msg_get_string(msg, &h->value); if (rc != NGX_OK) { if (rc != AJP_EOVERFLOW) { ngx_log_error(NGX_LOG_ERR, log, 0, "ajp_unmarshal_response: Null header value"); } return rc; } 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) { ngx_log_error(NGX_LOG_ERR, log, 0, "ajp_unmarshal_response: hh->handler error: \"%V: %V\"", &h->key, &h->value); return NGX_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, "http ajp header: \"%V: %V\"", &h->key, &h->value); } return NGX_OK; }
static ngx_int_t zupstream_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->value.len = r->header_end - r->header_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; } }
ngx_int_t ngx_rtmp_amf_message_handler(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { ngx_rtmp_amf_ctx_t act; ngx_rtmp_core_main_conf_t *cmcf; ngx_array_t *ch; ngx_rtmp_handler_pt *ph; size_t len, n; static u_char func[128]; static ngx_rtmp_amf_elt_t elts[] = { { NGX_RTMP_AMF_STRING, ngx_null_string, func, sizeof(func) }, }; /* AMF command names come with string type, but shared object names * come without type */ if (h->type == NGX_RTMP_MSG_AMF_SHARED || h->type == NGX_RTMP_MSG_AMF3_SHARED) { elts[0].type |= NGX_RTMP_AMF_TYPELESS; } else { elts[0].type &= ~NGX_RTMP_AMF_TYPELESS; } if ((h->type == NGX_RTMP_MSG_AMF3_SHARED || h->type == NGX_RTMP_MSG_AMF3_META || h->type == NGX_RTMP_MSG_AMF3_CMD) && in->buf->last > in->buf->pos) { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "AMF3 prefix: %ui", (ngx_int_t)*in->buf->pos); ++in->buf->pos; } cmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_core_module); /* read AMF func name & transaction id */ ngx_memzero(&act, sizeof(act)); act.link = in; act.log = s->connection->log; memset(func, 0, sizeof(func)); if (ngx_rtmp_amf_read(&act, elts, sizeof(elts) / sizeof(elts[0])) != NGX_OK) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "AMF cmd failed"); return NGX_ERROR; } /* skip name */ in = act.link; in->buf->pos += act.offset; len = ngx_strlen(func); ch = ngx_hash_find(&cmcf->amf_hash, ngx_hash_strlow(func, func, len), func, len); if (ch && ch->nelts) { ph = ch->elts; for (n = 0; n < ch->nelts; ++n, ++ph) { ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "AMF func '%s' passed to handler %d/%d", func, n, ch->nelts); switch ((*ph)(s, h, in)) { case NGX_ERROR: return NGX_ERROR; case NGX_DONE: return NGX_OK; } } } else { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "AMF cmd '%s' no handler", func); } return NGX_OK; }
ngx_int_t ngx_http_srcache_store_response_header(ngx_http_request_t *r, ngx_http_srcache_ctx_t *ctx) { ngx_chain_t *cl; size_t len; ngx_buf_t *b; ngx_uint_t status; ngx_uint_t i; ngx_str_t *status_line; ngx_list_part_t *part; ngx_table_elt_t *header; u_char buf[sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1]; ngx_http_srcache_loc_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module); dd("request: %p, uri: %.*s", r, (int) r->uri.len, r->uri.data); len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 /* the end of the header */ + sizeof(CRLF) - 1; if (r->headers_out.status_line.len) { dd("status line defined"); len += r->headers_out.status_line.len; status_line = &r->headers_out.status_line; status = 0; } else { dd("status line not defined"); status = r->headers_out.status; if (status >= NGX_HTTP_OK && status < NGX_HTTP_LAST_LEVEL_200) { /* 2XX */ status -= NGX_HTTP_OK; dd("status: %d", (int) status); 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_LEVEL_300) { /* 3XX */ if (status == NGX_HTTP_NOT_MODIFIED) { r->header_only = 1; } status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200; 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_LEVEL_400) { /* 4XX */ status = status - NGX_HTTP_BAD_REQUEST + NGX_HTTP_LEVEL_200 + NGX_HTTP_LEVEL_300; 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_LEVEL_500) { /* 5XX */ status = status - NGX_HTTP_INTERNAL_SERVER_ERROR + NGX_HTTP_LEVEL_200 + NGX_HTTP_LEVEL_300 + NGX_HTTP_LEVEL_400; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else { len += NGX_INT_T_LEN; status_line = NULL; } } if (!conf->hide_content_type && 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 (!conf->hide_last_modified) { 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.status != NGX_HTTP_NO_CONTENT) { r->headers_out.last_modified_time = -1; r->headers_out.last_modified = NULL; } } dd("last modified time: %d", (int) r->headers_out.last_modified_time); if (r->headers_out.last_modified == NULL && r->headers_out.last_modified_time != -1) { (void) ngx_http_time(buf, r->headers_out.last_modified_time); len += sizeof("Last-Modified: ") - 1 + sizeof(buf) + 2; } } if (r->allow_ranges) { len += sizeof("X-SRCache-Allow-Ranges: 1") - 1 + 2; } 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; } if (ngx_hash_find(&conf->hide_headers_hash, header[i].hash, header[i].lowcase_key, header[i].key.len)) { 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 (!conf->hide_content_type && r->headers_out.content_type.len) { b->last = ngx_cpymem(b->last, "Content-Type: ", sizeof("Content-Type: ") - 1); 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); } *b->last++ = CR; *b->last++ = LF; } if (!conf->hide_last_modified && 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_cpymem(b->last, buf, sizeof(buf)); *b->last++ = CR; *b->last++ = LF; } if (r->allow_ranges) { b->last = ngx_cpymem(b->last, "X-SRCache-Allow-Ranges: 1\r\n", sizeof("X-SRCache-Allow-Ranges: 1\r\n") - 1); } 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; } dd("header hash: %lu, hash lc: %lu", (unsigned long) header[i].hash, (unsigned long) ngx_hash_key_lc(header[i].key.data, header[i].key.len)); if (ngx_hash_find(&conf->hide_headers_hash, header[i].hash, header[i].lowcase_key, header[i].key.len)) { dd("skipped header key: %.*s", (int) header[i].key.len, header[i].key.data); continue; } dd("header not skipped"); 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, r->connection->log, 0, "srcache store header %*s", (size_t) (b->last - b->pos), b->pos); /* the end of HTTP header */ *b->last++ = CR; *b->last++ = LF; if (b->last != b->end) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "srcache_fetch: buffer error when serializing the " "response header: %O left", (off_t) (b->last - b->end)); return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; ctx->body_to_cache = cl; ctx->response_length += len; return NGX_OK; }
int ngx_http_lua_ffi_var_set(ngx_http_request_t *r, u_char *name_data, size_t name_len, u_char *lowcase_buf, u_char *value, size_t value_len, u_char *errbuf, size_t errlen) { u_char *p; ngx_uint_t hash; ngx_http_variable_t *v; ngx_http_variable_value_t *vv; ngx_http_core_main_conf_t *cmcf; if (r == NULL) { ngx_snprintf(errbuf, errlen, "no request object found"); return NGX_ERROR; } if ((r)->connection->fd == -1) { ngx_snprintf(errbuf, errlen, "API disabled in the current context"); return NGX_ERROR; } hash = ngx_hash_strlow(lowcase_buf, name_data, name_len); dd("variable name: %.*s", (int) name_len, lowcase_buf); /* we fetch the variable itself */ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); v = ngx_hash_find(&cmcf->variables_hash, hash, lowcase_buf, name_len); if (v) { if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) { dd("variable not changeable"); ngx_snprintf(errbuf, errlen, "variable \"%*s\" not changeable", name_len, lowcase_buf); return NGX_ERROR; } if (v->set_handler) { dd("set variables with set_handler"); if (value != NULL && value_len) { vv = ngx_pnalloc(r->pool, sizeof(ngx_http_variable_value_t) + value_len); if (vv == NULL) { goto nomem; } p = (u_char *) vv + sizeof(ngx_http_variable_value_t); ngx_memcpy(p, value, value_len); value = p; } else { vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { goto nomem; } } if (value == NULL) { vv->valid = 0; vv->not_found = 1; vv->no_cacheable = 0; vv->data = NULL; vv->len = 0; } else { vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = value; vv->len = value_len; } v->set_handler(r, vv, v->data); return NGX_OK; } if (v->flags & NGX_HTTP_VAR_INDEXED) { vv = &r->variables[v->index]; dd("set indexed variable"); if (value == NULL) { vv->valid = 0; vv->not_found = 1; vv->no_cacheable = 0; vv->data = NULL; vv->len = 0; } else { p = ngx_palloc(r->pool, value_len); if (p == NULL) { goto nomem; } ngx_memcpy(p, value, value_len); value = p; vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = value; vv->len = value_len; } return NGX_OK; } ngx_snprintf(errbuf, errlen, "variable \"%*s\" cannot be assigned " "a value", name_len, lowcase_buf); return NGX_ERROR; } /* variable not found */ ngx_snprintf(errbuf, errlen, "variable \"%*s\" not found for writing; " "maybe it is a built-in variable that is not changeable " "or you forgot to use \"set $%*s '';\" " "in the config file to define it first", name_len, lowcase_buf, name_len, lowcase_buf); return NGX_ERROR; nomem: ngx_snprintf(errbuf, errlen, "no memory"); return NGX_ERROR; }
static ngx_int_t ngx_http_redis_create_request(ngx_http_request_t *r) { ngx_int_t rc = NGX_ERROR; ngx_http_redis_loc_conf_t *rlcf; ngx_http_redis_ctx_t *ctx; ngx_http_variable_value_t *vv; ngx_http_upstream_t *u = r->upstream; ngx_chain_t *cl = NULL; u_char *p, *last; ngx_str_t command; ngx_int_t command_hash = 0; ngx_http_redis_command_process_t *proc; if (r->args.len == 0) { return NGX_ERROR; } ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module); rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module); vv = ngx_http_get_indexed_variable(r, rlcf->index); if (vv == NULL || vv->not_found || vv->len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the \"$redis_key\" variable is not set"); return NGX_ERROR; } p = r->args.data; last = p + r->args.len; for (; p != last; p++) { if (*p == '&') { break; } } command.data = r->args.data; command.len = p - command.data; command_hash = ngx_hash_key_lc(command.data, command.len); proc = ngx_hash_find(&ctx->command_hash, command_hash, command.data, command.len); if (proc && proc->create_request_handler) { rc = proc->create_request_handler(r, p+1, last, vv, &cl); } /* switch (*p) { case 'g': case 'G': rc = ngx_http_redis_process_get(r, p, last, vv, &cl); break; case 'A': case 'a': rc = ngx_http_redis_process_append(r, p, last, vv, &cl); break; default: break; } */ if (rc != NGX_OK) { return rc; } u->request_bufs = cl; return NGX_OK; }
static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr, ngx_array_t *extra_vars) { ngx_http_core_main_conf_t *cmcf; ngx_http_variable_t *v; ngx_http_variable_value_t *vv; u_char *val; u_char *p; ngx_uint_t i, hash; ngx_str_t name; size_t len; ngx_hash_t *variables_hash; ngx_keyval_t *var; /* set any extra variables that were passed to the subrequest */ if (extra_vars == NULL || extra_vars->nelts == 0) { return NGX_OK; } cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module); variables_hash = &cmcf->variables_hash; var = extra_vars->elts; for (i = 0; i < extra_vars->nelts; i++, var++) { /* copy the variable's name and value because they are allocated * by the lua VM */ len = var->key.len + var->value.len; p = ngx_pnalloc(sr->pool, len); if (p == NULL) { return NGX_ERROR; } name.data = p; name.len = var->key.len; p = ngx_copy(p, var->key.data, var->key.len); hash = ngx_hash_strlow(name.data, name.data, name.len); val = p; len = var->value.len; ngx_memcpy(p, var->value.data, len); v = ngx_hash_find(variables_hash, hash, name.data, name.len); if (v) { if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) { ngx_log_error(NGX_LOG_ERR, sr->connection->log, 0, "variable \"%V\" not changeable", &name); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (v->set_handler) { vv = ngx_palloc(sr->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { return NGX_ERROR; } vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; v->set_handler(sr, vv, v->data); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sr->connection->log, 0, "variable \"%V\" set to value \"%v\"", &name, vv); continue; } if (v->flags & NGX_HTTP_VAR_INDEXED) { vv = &sr->variables[v->index]; vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sr->connection->log, 0, "variable \"%V\" set to value \"%v\"", &name, vv); continue; } } ngx_log_error(NGX_LOG_ERR, sr->connection->log, 0, "variable \"%V\" cannot be assigned a value (maybe you " "forgot to define it first?) ", &name); return NGX_ERROR; } return NGX_OK; }
ngx_int_t ngx_http_srcache_process_header(ngx_http_request_t *r, ngx_buf_t *b) { ngx_int_t rc; ngx_table_elt_t header; ngx_http_srcache_ctx_t *ctx; off_t len, rest; unsigned truncate; u_char *p; ngx_http_srcache_header_t *hh; ngx_http_srcache_main_conf_t *smcf; smcf = ngx_http_get_module_main_conf(r, ngx_http_srcache_filter_module); ctx = ngx_http_get_module_ctx(r, ngx_http_srcache_filter_module); for ( ;; ) { len = b->last - b->pos; rest = ctx->header_buf->end - ctx->header_buf->last; dd("len: %d, rest: %d", (int) len, (int) rest); if (len > rest) { len = rest; truncate = 1; } else { truncate = 0; } ctx->header_buf->last = ngx_copy(ctx->header_buf->last, b->pos, (size_t) len); p = ctx->header_buf->pos; rc = ngx_http_parse_header_line(r, ctx->header_buf, 1); b->pos += ctx->header_buf->pos - p; if (rc == NGX_OK) { /* a header line has been parsed successfully */ ngx_memzero(&header, sizeof(ngx_table_elt_t)); header.hash = r->header_hash; header.key.len = r->header_name_end - r->header_name_start; header.value.len = r->header_end - r->header_start; header.key.data = ngx_pnalloc(r->pool, header.key.len + 1 + header.value.len + 1 + header.key.len); if (header.key.data == NULL) { return NGX_ERROR; } header.value.data = header.key.data + header.key.len + 1; header.lowcase_key = header.key.data + header.key.len + 1 + header.value.len + 1; ngx_cpystrn(header.key.data, r->header_name_start, header.key.len + 1); ngx_cpystrn(header.value.data, r->header_start, header.value.len + 1); if (header.key.len == r->lowcase_index) { ngx_memcpy(header.lowcase_key, r->lowcase_header, header.key.len); } else { ngx_strlow(header.lowcase_key, header.key.data, header.key.len); } hh = ngx_hash_find(&smcf->headers_in_hash, header.hash, header.lowcase_key, header.key.len); if (hh) { if (hh->handler(r->parent, &header, hh->offset) != NGX_OK) { return NGX_ERROR; } } else { if (ngx_http_srcache_process_header_line(r->parent, &header, 0) != NGX_OK) { return NGX_ERROR; } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "srcache_fetch header: \"%V: %V\"", &header.key, &header.value); ctx->header_buf->pos = ctx->header_buf->start; ctx->header_buf->last = ctx->header_buf->start; continue; } if (rc == NGX_HTTP_PARSE_HEADER_DONE) { /* a whole header has been parsed successfully */ ctx->header_buf->pos = ctx->header_buf->start; ctx->header_buf->last = ctx->header_buf->start; ngx_pfree(r->pool, ctx->header_buf->start); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "srcache_fetch header done"); return NGX_OK; } if (rc == NGX_AGAIN) { if (truncate) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "srcache_fetch: header buffer overflown " "(maybe you should consider increasing " "srcache_header_buffer_size?)"); ctx->header_buf->pos = ctx->header_buf->start; ctx->header_buf->last = ctx->header_buf->start; ngx_pfree(r->pool, ctx->header_buf->start); return NGX_ERROR; } return NGX_AGAIN; } /* there was error while a header line parsing */ ctx->header_buf->pos = ctx->header_buf->start; ctx->header_buf->last = ctx->header_buf->start; ngx_pfree(r->pool, ctx->header_buf->start); ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "srcache_fetch: cache sent invalid header"); return NGX_ERROR; } }