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;
}
Example #5
0
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);
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #10
0
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;
}
Example #11
0
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;
}
Example #12
0
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;
}
Example #13
0
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();
}
Example #16
0
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;
}
Example #20
0
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;
}
Example #21
0
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;
    }
}
Example #22
0
/**
 * 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);
}
Example #23
0
/*
   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;
}
Example #27
0
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;
    }
}