static ngx_int_t
ngx_http_data_dome_auth_handler(ngx_http_request_t *r)
{
    ngx_buf_t                       *b;
    ngx_int_t                        rc;
    ngx_str_t                        val;
    ngx_str_t                        x_datadome_response;
    ngx_uint_t                       i;
    ngx_chain_t                      out;
    ngx_list_part_t                 *part;
    ngx_table_elt_t                 *header;
    ngx_table_elt_t                 *location;
    ngx_http_data_dome_auth_ctx_t   *ctx;
    ngx_http_data_dome_auth_conf_t  *acf;

    // you can dissable this module in location or if level
    acf = ngx_http_get_module_loc_conf(r, ngx_http_data_dome_auth_module);

    if (acf->uri_lengths == NULL) {
  return NGX_DECLINED;
    }

    if (r->internal && acf->pass_internal_redirect) {
  return NGX_DECLINED;
    }

    // but module use main request context to keep the status
    // to prevent duplicated query to API server
    ctx = ngx_http_get_module_ctx(r->main, ngx_http_data_dome_auth_module);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0,
		   "Data Dome auth request handler, ctx: %p", ctx);

    if (ctx != NULL) {
    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0,
		   "Data Dome auth request handler ctx: declined %d, processing: %d, done: %d",
		    ctx->declined, ctx->processing, ctx->done);

	if (ctx->declined) {
	    return NGX_DECLINED;
	}

	if (ctx->processing) {
	    return NGX_OK;
	}

	if (!ctx->done) {
	    return NGX_AGAIN;
	}

    if (ngx_http_data_dome_auth_set_variables(r, acf, ctx) != NGX_OK) {
        return NGX_ERROR;
    }

	if (acf->learning) {
	    return NGX_OK;
	}

    if (ctx->subrequest_rc < NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    x_datadome_response.len = 0;

    part = &ctx->subrequest->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 (header[i].key.len != sizeof("X-DataDomeResponse") - 1) {
            continue;
        }

        if (ngx_strncmp(header[i].key.data, "X-DataDomeResponse", header[i].key.len) != 0) {
            continue;
        }

        x_datadome_response = header[i].value;

        break;
    }

    if (x_datadome_response.len == 0) {
	    ngx_log_error(NGX_LOG_ERR, r->main->connection->log, 0, "API server response hasn't got X-DataDomeResponse");
	    return NGX_DECLINED;
    }

    if ((ngx_uint_t)ngx_atoi(x_datadome_response.data, x_datadome_response.len) != ctx->subrequest->headers_out.status) {
	    ngx_log_error(NGX_LOG_ERR, r->main->connection->log, 0, "API server response's X-DataDomeResponse (%V) != status (%d)",
	        &x_datadome_response, ctx->subrequest->headers_out.status);
	    return NGX_DECLINED;
    }

	if (ngx_http_data_dome_auth_execute_x_datadome_headers(r->main->pool, "X-DataDome-headers",
	                                                       &ctx->subrequest->headers_out.headers,
	                                                       &r->main->headers_out.headers) == NGX_ERROR) {
	    return NGX_ERROR;
	}

	if (ngx_http_data_dome_auth_execute_x_datadome_headers(r->main->pool, "X-DataDome-request-headers",
	                                                       &ctx->subrequest->headers_out.headers,
	                                                       &r->main->headers_in.headers) == NGX_ERROR) {
	    return NGX_ERROR;
	}

	switch (ctx->subrequest->headers_out.status) {
	case NGX_HTTP_MOVED_PERMANENTLY:
	case NGX_HTTP_MOVED_TEMPORARILY:
	case NGX_HTTP_UNAUTHORIZED:
	case NGX_HTTP_FORBIDDEN:

        part = &ctx->subrequest->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 (header[i].key.len != sizeof("Location") - 1) {
                continue;
            }

            if (ngx_strncmp(header[i].key.data, "Location", header[i].key.len) != 0) {
                continue;
            }

            location = ngx_list_push(&r->main->headers_out.headers);
            if (location == NULL) {
              return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            location->hash = 1;
            location->key = header[i].key;
            location->lowcase_key = header[i].lowcase_key;
            location->value = header[i].value;

            break;
        }

	    // nginx reset upstream buffer length, so, use body lenght from header ;)
	    val.len = ctx->subrequest->headers_out.content_length_n;
	    val.data = ctx->subrequest->upstream->buffer.pos;

	    // if response hasn't Content-Length and body the length was -1, fix it
	    if (ctx->subrequest->headers_out.content_length_n < 0) {
	      val.len = 0;
	    }

	    if (val.len == 0) {
    	    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
	    		   "Data Dome auth send response without body: s: %d",
		    	   ctx->subrequest->headers_out.status);
            return ctx->subrequest->headers_out.status;
	    }

	    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
			   "Data Dome auth send response: s: %d, c: %V, b: %V",
			   ctx->subrequest->headers_out.status, &ctx->subrequest->headers_out.content_type, &val);

        r->headers_out.status = ctx->subrequest->headers_out.status;

        r->headers_out.content_length_n = val.len;

        if (ctx->subrequest->headers_out.content_type.len) {
            r->headers_out.content_type_len = ctx->subrequest->headers_out.content_type.len;
            r->headers_out.content_type = ctx->subrequest->headers_out.content_type;
        } else {
            if (ngx_http_set_content_type(r) != NGX_OK) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }
        }

        if (r->method == NGX_HTTP_HEAD || val.len == 0) {
            rc = ngx_http_send_header(r);
            if (rc != NGX_OK) {
                return rc;
            }

            return NGX_DONE;
        }

        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
        b->pos = val.data;
        b->last = val.data + val.len;
        b->memory = val.len ? 1 : 0;
        b->last_buf = (r == r->main) ? 1 : 0;
        b->last_in_chain = 1;

        out.buf = b;
        out.next = NULL;

        rc = ngx_http_send_header(r);

        if (rc == NGX_ERROR || rc > NGX_OK) {
            return rc;
        }

        if (r->header_only) {
            ngx_http_finalize_request(r, NGX_DONE);
            return NGX_DONE;
        }

        rc = ngx_http_output_filter(r, &out);
	    if (rc != NGX_OK) {
	      return rc;
	    }

        ngx_http_finalize_request(r, NGX_DONE);
	    return NGX_DONE;

	case NGX_HTTP_OK:

	    return NGX_OK;

	default:

	    ngx_log_error(NGX_LOG_ERR, r->main->connection->log, 0,
			  "Data Dome auth request unexpected status: %d, pass", ctx->subrequest->headers_out.status);

	    return NGX_OK;
	}
    }

    ctx = ngx_pcalloc(r->main->pool, sizeof(ngx_http_data_dome_auth_ctx_t));
    if (ctx == NULL) {
	return NGX_ERROR;
    }

    if (ngx_http_script_run(r, &ctx->uri, acf->uri_lengths->elts, 0, acf->uri_values->elts)
        == NULL)
    {
        return NGX_ERROR;
    }

    if (ngx_strncmp(ctx->uri.data, "off", ctx->uri.len) == 0) {
	    return NGX_DECLINED;
    }

    ngx_http_set_ctx(r->main, ctx, ngx_http_data_dome_auth_module);

#if (NGX_PCRE)

    if (acf->uri_regex_exclusion) {
        if (ngx_regex_exec(acf->uri_regex_exclusion, &r->main->uri, NULL, 0) != NGX_REGEX_NO_MATCHED) {

            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0,
                  "Data Dome auth URI regex exclusion: \"%V\" match with URI: %V",
                   &acf->uri_regex_exclusion_raw, &r->main->uri);

            ctx->declined = 1;
            return NGX_DECLINED;
        }
    }

    if (acf->uri_regex) {

	if (ngx_regex_exec(acf->uri_regex, &r->main->uri, NULL, 0) != NGX_REGEX_NO_MATCHED) {

	    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0,
			  "Data Dome auth URI regex: \"%V\" match with URI: %V",
			   &acf->uri_regex_raw, &r->main->uri);

	    goto validate;
	}

	ctx->declined = 1;
	return NGX_DECLINED;
    }

 validate:

#endif

    ctx->processing = 1;

    // keep original read and write event handler because read client body may override it
    ctx->read_event_handler = r->main->read_event_handler;
    ctx->write_event_handler = r->main->write_event_handler;

    return ngx_http_data_dome_subrequest(r);
}
static ngx_int_t
ngx_http_auth_request_handler(ngx_http_request_t *r)
{
    ngx_table_elt_t               *h, *ho;
    ngx_http_request_t            *sr;
    ngx_http_post_subrequest_t    *ps;
    ngx_http_auth_request_ctx_t   *ctx;
    ngx_http_auth_request_conf_t  *arcf;

    arcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_request_module);

    if (arcf->uri.len == 0) {
        return NGX_DECLINED;
    }

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "auth request handler");

    ctx = ngx_http_get_module_ctx(r, ngx_http_auth_request_module);

    if (ctx != NULL) {
        if (!ctx->done) {
            return NGX_AGAIN;
        }

        /*
         * as soon as we are done - explicitly set variables to make
         * sure they will be available after internal redirects
         */

        if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) {
            return NGX_ERROR;
        }

        /* return appropriate status */

        if (ctx->status == NGX_HTTP_FORBIDDEN) {
            return ctx->status;
        }

        if (ctx->status == NGX_HTTP_UNAUTHORIZED) {
            sr = ctx->subrequest;

            h = sr->headers_out.www_authenticate;

            if (!h && sr->upstream) {
                h = sr->upstream->headers_in.www_authenticate;
            }

            if (h) {
                ho = ngx_list_push(&r->headers_out.headers);
                if (ho == NULL) {
                    return NGX_ERROR;
                }

                *ho = *h;

                r->headers_out.www_authenticate = ho;
            }

            return ctx->status;
        }

        if (ctx->status >= NGX_HTTP_OK
            && ctx->status < NGX_HTTP_SPECIAL_RESPONSE)
        {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "auth request unexpected status: %ui", ctx->status);

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t));
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
    if (ps == NULL) {
        return NGX_ERROR;
    }

    ps->handler = ngx_http_auth_request_done;
    ps->data = ctx;

    if (ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps,
                            NGX_HTTP_SUBREQUEST_WAITED)
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    /*
     * allocate fake request body to avoid attempts to read it and to make
     * sure real body file (if already read) won't be closed by upstream
     */

    sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
    if (sr->request_body == NULL) {
        return NGX_ERROR;
    }

    sr->header_only = 1;

    ctx->subrequest = sr;

    ngx_http_set_ctx(r, ctx, ngx_http_auth_request_module);

    return NGX_AGAIN;
}
ngx_int_t
ngx_http_lua_rewrite_handler(ngx_http_request_t *r)
{
    ngx_http_lua_loc_conf_t     *llcf;
    ngx_http_lua_ctx_t          *ctx;
    ngx_int_t                    rc;
    ngx_http_lua_main_conf_t    *lmcf;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
            "lua rewrite handler, uri \"%V\"", &r->uri);

    lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);

    if (! lmcf->postponed_to_rewrite_phase_end) {
        ngx_http_core_main_conf_t       *cmcf;
        ngx_http_phase_handler_t        tmp;
        ngx_http_phase_handler_t        *ph;
        ngx_http_phase_handler_t        *cur_ph;
        ngx_http_phase_handler_t        *last_ph;

        lmcf->postponed_to_rewrite_phase_end = 1;

        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

        ph = cmcf->phase_engine.handlers;
        cur_ph = &ph[r->phase_handler];
        last_ph = &ph[cur_ph->next - 1];

#if 0
        if (cur_ph == last_ph) {
            dd("XXX our handler is already the last rewrite phase handler");
        }
#endif

        if (cur_ph < last_ph) {
            dd("swaping the contents of cur_ph and last_ph...");

            tmp      = *cur_ph;

            memmove(cur_ph, cur_ph + 1,
                (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t));

            *last_ph = tmp;

            r->phase_handler--; /* redo the current ph */

            return NGX_DECLINED;
        }
    }

    llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);

    if (llcf->rewrite_handler == NULL) {
        dd("no rewrite handler found");
        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    dd("ctx = %p", ctx);

    if (ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        dd("setting new ctx: ctx = %p", ctx);

        ctx->cc_ref = LUA_NOREF;
        ctx->ctx_ref = LUA_NOREF;

        ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
    }

    dd("entered? %d", (int) ctx->entered_rewrite_phase);

    if (ctx->waiting_more_body) {
        return NGX_DONE;
    }

    if (ctx->entered_rewrite_phase) {
        dd("rewriteby: calling wev handler");
        rc = ngx_http_lua_wev_handler(r);
        dd("rewriteby: wev handler returns %d", (int) rc);
        return rc;
    }

    if (llcf->force_read_body &&
            ! ctx->read_body_done &&
            ((r->method & NGX_HTTP_POST) || (r->method & NGX_HTTP_PUT)))
    {
        rc = ngx_http_read_client_request_body(r, 
                ngx_http_lua_generic_phase_post_read);

        if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
            return rc;
        }

        if (rc == NGX_AGAIN) {
            ctx->waiting_more_body = 1;
            return NGX_DONE;
        }
    }

    dd("calling rewrite handler");
    return llcf->rewrite_handler(r);
}
ngx_int_t
ngx_http_lua_content_handler(ngx_http_request_t *r)
{
    ngx_http_lua_loc_conf_t     *llcf;
    ngx_http_lua_ctx_t          *ctx;
    ngx_int_t                    rc;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "lua content handler, uri \"%V\"", &r->uri);

    llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);

    if (llcf->content_handler == NULL) {
        dd("no content handler found");
        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    dd("ctx = %p", ctx);

    if (ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        dd("setting new ctx: ctx = %p, size: %d", ctx, (int) sizeof(*ctx));

        ctx->entry_ref = LUA_NOREF;
        ctx->ctx_ref = LUA_NOREF;

        ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
    }

    dd("entered? %d", (int) ctx->entered_content_phase);

    if (ctx->waiting_more_body) {
        return NGX_DONE;
    }

    if (ctx->entered_content_phase) {
        dd("calling wev handler");
        rc = ngx_http_lua_wev_handler(r);
        dd("wev handler returns %d", (int) rc);
        return rc;
    }

    if (llcf->force_read_body && !ctx->read_body_done) {
        r->request_body_in_single_buf = 1;
        r->request_body_in_persistent_file = 1;
        r->request_body_in_clean_file = 1;

        rc = ngx_http_read_client_request_body(r,
                ngx_http_lua_content_phase_post_read);

        if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
            return rc;
        }

        if (rc == NGX_AGAIN) {
            ctx->waiting_more_body = 1;

            return NGX_DONE;
        }
    }

    dd("setting entered");

    ctx->entered_content_phase = 1;

    dd("calling content handler");
    return llcf->content_handler(r);
}
static ngx_int_t
ngx_http_memcached_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_memcached_ctx_t       *ctx;
    ngx_http_memcached_loc_conf_t  *mlcf;

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    if (ngx_http_set_content_type(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);

    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
    if (u == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    u->schema.len = sizeof("memcached://") - 1;
    u->schema.data = (u_char *) "memcached://";

    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#if (NGX_THREADS)
    u->peer.lock = &r->connection->lock;
#endif

    u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;

    u->conf = &mlcf->upstream;

    u->create_request = ngx_http_memcached_create_request;
    u->reinit_request = ngx_http_memcached_reinit_request;
    u->process_header = ngx_http_memcached_process_header;
    u->abort_request = ngx_http_memcached_abort_request;
    u->finalize_request = ngx_http_memcached_finalize_request;

    r->upstream = u;

    ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
    if (ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ctx->rest = NGX_HTTP_MEMCACHED_END;
    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);

    u->input_filter_init = ngx_http_memcached_filter_init;
    u->input_filter = ngx_http_memcached_filter;
    u->input_filter_ctx = ctx;

    ngx_http_upstream_init(r);

    return NGX_DONE;
}
Esempio n. 6
0
ngx_int_t
ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val,
        ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *script)
{
    size_t           i;
    ngx_int_t        rc;
    u_char          *err_msg;
    size_t           rlen;
    u_char          *rdata;
#if (NGX_PCRE)
    ngx_pool_t      *old_pool;
#endif

    ngx_http_lua_ctx_t          *ctx;
    ngx_http_cleanup_t          *cln;

    dd("nargs: %d", (int) nargs);

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    if (ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t));
        if (ctx == NULL) {
            return NGX_ERROR;
        }

        dd("setting new ctx: ctx = %p", ctx);

        ctx->cc_ref = LUA_NOREF;
        ctx->ctx_ref = LUA_NOREF;

        ngx_http_set_ctx(r, ctx, ngx_http_lua_module);

    } else {
        ngx_http_lua_reset_ctx(r, L, ctx);
    }

    if (ctx->cleanup == NULL) {
        cln = ngx_http_cleanup_add(r, 0);
        if (cln == NULL) {
            return NGX_ERROR;
        }

        cln->handler = ngx_http_lua_request_cleanup;
        cln->data = r;
        ctx->cleanup = &cln->handler;
    }

    /*  set Lua VM panic handler */
    lua_atpanic(L, ngx_http_lua_atpanic);

    /*  initialize nginx context in Lua VM, code chunk at stack top    sp = 1 */
    ngx_http_lua_set_by_lua_env(L, r, nargs, args);

    /*  passing directive arguments to the user code */
    for (i = 0; i < nargs; i++) {
        lua_pushlstring(L, (const char *) args[i].data, args[i].len);
    }

#if (NGX_PCRE)
    /* XXX: work-around to nginx regex subsystem */
    old_pool = ngx_http_lua_pcre_malloc_init(r->pool);
#endif

    /*  protected call user code */
    rc = lua_pcall(L, nargs, 1, 0);

#if (NGX_PCRE)
    /* XXX: work-around to nginx regex subsystem */
    ngx_http_lua_pcre_malloc_done(old_pool);
#endif

    if (rc != 0) {
        /*  error occured when running loaded code */
        err_msg = (u_char *) lua_tostring(L, -1);

        if (err_msg != NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "(lua-error) %s",
                    err_msg);

            lua_settop(L, 0);    /*  clear remaining elems on stack */
        }

        return NGX_ERROR;
    }

    NGX_LUA_EXCEPTION_TRY {
        rdata = (u_char *) lua_tolstring(L, -1, &rlen);

        if (rdata) {
            val->data = ngx_pcalloc(r->pool, rlen);
            if (val->data == NULL) {
                return NGX_ERROR;
            }

            ngx_memcpy(val->data, rdata, rlen);
            val->len = rlen;

        } else {
            val->data = NULL;
            val->len = 0;
        }

    } NGX_LUA_EXCEPTION_CATCH {
        dd("nginx execution restored");
    }

    /*  clear Lua stack */
    lua_settop(L, 0);

    return NGX_OK;
}
Esempio n. 7
0
/*
** [ENTRY POINT] does : this function called by nginx from the request handler
*/
static ngx_int_t
ngx_http_modsecurity_handler(ngx_http_request_t *r)
{
    ngx_http_modsecurity_loc_conf_t *cf;
    ngx_http_modsecurity_ctx_t      *ctx;
    ngx_int_t                        rc;

    cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity);

    /* Process only main request */
    if (r != r->main || !cf->enable) {
        return NGX_DECLINED;
    }

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "modSecurity: handler");

    /* create / retrive request ctx */
    if (r->internal) {
        
        ctx = ngx_http_get_module_pool_ctx(r, ngx_http_modsecurity);

        if (ctx) {
            /* we have already processed the request headers */
            ngx_http_set_ctx(r, ctx, ngx_http_modsecurity);
            return NGX_DECLINED;
        }

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "modSecurity: request pool ctx empty");
    }

    ctx = ngx_http_modsecurity_create_ctx(r);
    if (ctx == NULL) {

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_http_set_ctx(r, ctx, ngx_http_modsecurity);

    if (ngx_http_set_pool_ctx(r, ctx, ngx_http_modsecurity) != NGX_OK) {
        return NGX_ERROR;
    }

    /* load request to request rec */
    if (ngx_http_modsecurity_load_request(r) != NGX_OK
        || ngx_http_modsecurity_load_headers_in(r) != NGX_OK) {

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /* processing request headers */
    rc = ngx_http_modsecurity_status(r, modsecProcessRequestHeaders(ctx->req));

    if (rc != NGX_DECLINED) {
        return rc;
    }

    if (modsecContextState(ctx->req) == MODSEC_DISABLED) {
        return NGX_DECLINED;
    }

    if (r->method == NGX_HTTP_POST 
            && modsecIsRequestBodyAccessEnabled(ctx->req) ) {

        /* read POST request body, should we process PUT? */
        rc = ngx_http_read_client_request_body(r, ngx_http_modsecurity_body_handler);
        if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
            return rc;
        }

        return NGX_DONE;
    }
    
    /* other method */
    return ngx_http_modsecurity_status(r, modsecProcessRequestBody(ctx->req));
}
static ngx_int_t
ngx_http_addition_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_int_t                  rc;
    ngx_uint_t                 last;
    ngx_chain_t               *cl;
    ngx_http_request_t        *sr;
    ngx_http_addition_ctx_t   *ctx;
    ngx_http_addition_conf_t  *conf;

    if (in == NULL || r->header_only) {
        return ngx_http_next_body_filter(r, in);
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_addition_filter_module);

    if (ctx == NULL) {
        return ngx_http_next_body_filter(r, in);
    }

    conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);

    if (!ctx->before_body_sent) {
        ctx->before_body_sent = 1;

        if (conf->before_body.len) {
            if (ngx_http_subrequest(r, &conf->before_body, NULL, &sr, NULL, 0) != NGX_OK) {
                return NGX_ERROR;
            }
        }
    }

    if (conf->after_body.len == 0) {
        ngx_http_set_ctx(r, NULL, ngx_http_addition_filter_module);
        return ngx_http_next_body_filter(r, in);
    }

    last = 0;

    for (cl = in; cl; cl = cl->next) {
        if (cl->buf->last_buf) {
            cl->buf->last_buf = 0;
            cl->buf->sync = 1;
            last = 1;
        }
    }

    rc = ngx_http_next_body_filter(r, in);

    if (rc == NGX_ERROR || !last || conf->after_body.len == 0) {
        return rc;
    }

    if (ngx_http_subrequest(r, &conf->after_body, NULL, &sr, NULL, 0) != NGX_OK) {
        return NGX_ERROR;
    }

    ngx_http_set_ctx(r, NULL, ngx_http_addition_filter_module);

    return ngx_http_send_special(r, NGX_HTTP_LAST);
}
static void
ngx_http_dav_ext_propfind_handler(ngx_http_request_t *r)
{
	ngx_chain_t             *c;
	ngx_buf_t               *b;
	XML_Parser              parser;
	ngx_uint_t              status;
	ngx_http_dav_ext_ctx_t *ctx;

	ctx = ngx_http_get_module_ctx(r, ngx_http_dav_ext_module);

	if (ctx == NULL) {
		ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_dav_ext_ctx_t));
		ngx_http_set_ctx(r, ctx, ngx_http_dav_ext_module);
	}

	c = r->request_body->bufs;

	status = NGX_OK;

	parser = XML_ParserCreate(NULL);

	XML_SetUserData(parser, ctx);

	XML_SetElementHandler(parser, 
			ngx_http_dav_ext_start_xml_elt,
			ngx_http_dav_ext_end_xml_elt);

	for(; c != NULL && c->buf != NULL && !c->buf->last_buf; c = c->next) {

		b = c ->buf;

		if (!XML_Parse(parser, (const char*)b->pos, b->last - b->pos, b->last_buf)) {

			ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
					"dav_ext propfind XML error");

			status = NGX_ERROR;

			break;
		}

	}

	XML_ParserFree(parser);

	if (status == NGX_OK) {

		r->headers_out.status = 207;

		ngx_str_set(&r->headers_out.status_line, "207 Multi-Status");

		ngx_http_send_header(r);

		ngx_http_finalize_request(r, ngx_http_dav_ext_send_propfind(r));

	} else {

		r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR;

		r->header_only = 1;

		r->headers_out.content_length_n = 0;

		ngx_http_finalize_request(r, ngx_http_send_header(r));

	}

}
ngx_int_t
ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r)
{
    int                      cc_ref;
    lua_State               *cc;
    ngx_http_lua_ctx_t      *ctx;
    ngx_http_cleanup_t      *cln;

    /*  {{{ new coroutine to handle request */
    cc = ngx_http_lua_new_thread(r, L, &cc_ref);
    if (cc == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "(lua-content-by-chunk) failed to create new coroutine to handle request!");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /*  move code closure to new coroutine */
    lua_xmove(L, cc, 1);

    /*  set closure's env table to new coroutine's globals table */
    lua_pushvalue(cc, LUA_GLOBALSINDEX);
    lua_setfenv(cc, -2);

    /*  save reference of code to ease forcing stopping */
    lua_pushvalue(cc, -1);
    lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE);

    /*  save nginx request in coroutine globals table */
    lua_pushlightuserdata(cc, r);
    lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST);
    /*  }}} */

    /*  {{{ initialize request context */
    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    if (ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
    }

    ctx->cc = cc;
    ctx->cc_ref = cc_ref;

    /*  }}} */

    /*  {{{ register request cleanup hooks */
    cln = ngx_http_cleanup_add(r, 0);
    if (cln == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    cln->handler = ngx_http_lua_request_cleanup;
    cln->data = r;
    ctx->cleanup = &cln->handler;
    /*  }}} */

    return ngx_http_lua_run_thread(L, r, ctx, 0);
}
static ngx_int_t ngx_http_small_light_header_filter(ngx_http_request_t *r)
{
    ngx_http_small_light_conf_t *srv_conf;
    ngx_http_small_light_conf_t *loc_conf;
    ngx_http_small_light_ctx_t  *ctx;
    ngx_hash_init_t              hash_init;
    ngx_str_t                    define_pattern;
    char                        *converter;

    if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED ||
        r->headers_out.content_length_n == 0)
    {
        return ngx_http_next_header_filter(r);
    }

    srv_conf = ngx_http_get_module_srv_conf(r, ngx_http_small_light_module);
    loc_conf = ngx_http_get_module_loc_conf(r, ngx_http_small_light_module);

    if (!loc_conf->enable) {
        return ngx_http_next_header_filter(r);
    }

    if (!loc_conf->enable_getparam_mode) {
        if(ngx_http_small_light_parse_define_pattern(r, &r->unparsed_uri, &define_pattern) != NGX_OK) {
            return ngx_http_next_header_filter(r);
        }
    }
    
    ctx = ngx_http_get_module_ctx(r, ngx_http_small_light_module);
    if (ctx) {
        ngx_http_set_ctx(r, NULL, ngx_http_small_light_module);
        return ngx_http_next_header_filter(r);
    }

    if ((ctx = ngx_pcalloc(r->pool, sizeof(*ctx))) == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to allocate memory from r->pool %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    ctx->params.keys.pool = r->pool;
    ctx->params.temp_pool = r->pool;
    if (ngx_hash_keys_array_init(&ctx->params, NGX_HASH_SMALL) != NGX_OK) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to init hash keys for parameters %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    if (loc_conf->enable_getparam_mode) {
        if (ngx_http_small_light_init_getparams(r, ctx, srv_conf) != NGX_OK) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "failed to analyze parameters:%V %s:%d",
                          &define_pattern,
                          __FUNCTION__,
                          __LINE__);
            return NGX_ERROR;
        }
    } else {
        if (ngx_http_small_light_init_params(r, ctx, &define_pattern, srv_conf) != NGX_OK) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "failed to analyze parameters:%V %s:%d",
                          &define_pattern,
                          __FUNCTION__,
                          __LINE__);
            return NGX_ERROR;
        }
    }

    hash_init.hash        = &ctx->hash;
    hash_init.key         = ngx_hash_key_lc;
    hash_init.max_size    = 128;
    hash_init.bucket_size = ngx_cacheline_size;
    hash_init.name        = "small_light_init_params";
    hash_init.pool        = ctx->params.keys.pool;
    hash_init.temp_pool   = NULL;

    if (ngx_hash_init(&hash_init, ctx->params.keys.elts, ctx->params.keys.nelts) != NGX_OK) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to init hash table for parameters %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    ctx->inf             = (char *)r->headers_out.content_type.data;
    ctx->material_dir    = &srv_conf->material_dir;
    ctx->imlib2_temp_dir = loc_conf->imlib2_temp_dir;
    ctx->radius_max      = loc_conf->radius_max;
    ctx->sigma_max       = loc_conf->sigma_max;

    if (r->headers_out.content_length_n < 0) {
        ctx->content_length = loc_conf->buffer_size;
    } else {
        ctx->content_length = r->headers_out.content_length_n;
    }

    converter = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "e");
    if (ngx_strcmp(converter, NGX_HTTP_SMALL_LIGHT_CONVERTER_IMAGEMAGICK) == 0) {
        ctx->converter.init    = ngx_http_small_light_imagemagick_init;
        ctx->converter.term    = ngx_http_small_light_imagemagick_term;
        ctx->converter.process = ngx_http_small_light_imagemagick_process;
        ctx->ictx = ngx_pcalloc(r->pool, sizeof(ngx_http_small_light_imagemagick_ctx_t));
#ifdef NGX_HTTP_SMALL_LIGHT_IMLIB2_ENABLED
    } else if (ngx_strcmp(converter, NGX_HTTP_SMALL_LIGHT_CONVERTER_IMLIB2) == 0) {
        ctx->converter.init    = ngx_http_small_light_imlib2_init;
        ctx->converter.term    = ngx_http_small_light_imlib2_term;
        ctx->converter.process = ngx_http_small_light_imlib2_process;
        ctx->ictx = ngx_pcalloc(r->pool, sizeof(ngx_http_small_light_imlib2_ctx_t));
#endif
#ifdef NGX_HTTP_SMALL_LIGHT_GD_ENABLED
    } else if (ngx_strcmp(converter, NGX_HTTP_SMALL_LIGHT_CONVERTER_GD) == 0) {
        ctx->converter.init    = ngx_http_small_light_gd_init;
        ctx->converter.term    = ngx_http_small_light_gd_term;
        ctx->converter.process = ngx_http_small_light_gd_process;
        ctx->ictx = ngx_pcalloc(r->pool, sizeof(ngx_http_small_light_gd_ctx_t));
#endif
    } else {
        ctx->converter.init    = ngx_http_small_light_imagemagick_init;
        ctx->converter.term    = ngx_http_small_light_imagemagick_term;
        ctx->converter.process = ngx_http_small_light_imagemagick_process;
        ctx->ictx = ngx_pcalloc(r->pool, sizeof(ngx_http_small_light_imagemagick_ctx_t));
    }

    if (ctx->ictx == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to allocate memory from r->pool %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    ngx_http_set_ctx(r, ctx, ngx_http_small_light_module);

    if (r->headers_out.refresh) {
        r->headers_out.refresh->hash = 0;
    }

    r->main_filter_need_in_memory = 1;
    r->allow_ranges               = 0;

    return NGX_OK;
}
static ngx_int_t
ngx_http_spdy_serverpush_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
   
    off_t                       size;
    ngx_buf_t                  *b;
    ngx_chain_t                *cl, *ll, *out, **ln;
    ngx_http_spdy_stream_t     *stream;
    ngx_http_spdy_out_frame_t  *frame;
    //ngx_int_t                   static_handler_return_value;
    ngx_output_chain_ctx_t       *ctx;

    ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
    ngx_http_set_ctx(r, ctx, ngx_http_spdy_serverpush_filter_module);    
    ngx_int_t ret_SH = ngx_http_static_handler(r);
    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "static_handler return : %d", ret_SH);

    stream = myStream;
    if (stream == NULL) {
        return ngx_http_next_body_filter(r, in);
    }

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "spdy body filter \"%V?%V\"", &r->uri, &r->args);

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "Data in server Push ");

    if (myChain == NULL || r->header_only) {

	ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "Ending");
        if (stream->waiting) {
            return NGX_AGAIN;
        }

        r->connection->buffered &= ~NGX_SPDY_WRITE_BUFFERED;

        return NGX_OK;
    }

    size = 0;
    ln = &out;
    ll = myChain;
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "into for ");
    for ( ;; ) {
        b = ll->buf;
//#if 1
	if(b->file)
	{	
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "file detected push : %d",(b->file_last-b->file_pos));
		ngx_int_t my_size = b->file_last-b->file_pos;
		u_char* my_buf = ngx_pcalloc(r->pool,sizeof(u_char)*my_size);
		ngx_read_file(b->file, my_buf, my_size, 0);
		b->start = my_buf;
		b->pos = my_buf;
		b->last = my_buf+my_size;//+NGX_SPDY_FRAME_HEADER_SIZE;

	}
        if (ngx_buf_size(b) == 0 && !ngx_buf_special(b)) {
            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                          "zero size buf in spdy body filter "
                          "t:%d r:%d f:%d %p %p-%p %p %O-%O",
                          b->temporary,
                          b->recycled,
                          b->in_file,
                          b->start,
                          b->pos,
                          b->last,
                          b->file,
                          b->file_pos,
                          b->file_last);

            ngx_debug_point();
            return NGX_ERROR;
        }
//#endif
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "out of for");
        cl = ngx_alloc_chain_link(r->pool);
        if (cl == NULL) {
            return NGX_ERROR;
        }
	
        size += ngx_buf_size(b);
	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "Size %d ",size);
        
        cl->buf = b;

        *ln = cl;
        ln = &cl->next;

        if (ll->next == NULL) {
            break;
        }

        ll = ll->next;
    }

    if (size > NGX_SPDY_MAX_FRAME_SIZE) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                      "FIXME: chain too big in spdy filter: %O", size);
        return NGX_ERROR;
    }
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "ONE ");
    frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t) size,
                                                b->last_buf, out, cl);

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "FOUR ");
    if (frame == NULL) {
        return NGX_ERROR;
    }

    ngx_http_spdy_queue_frame(stream->connection, frame);

    stream->waiting++;

    r->main->blocked++;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "Data in server Push end");
    ngx_http_spdy_serverpush_filter_send(r->connection, stream);
    return ngx_http_next_body_filter(r,in);
}
static ngx_int_t
ngx_http_eval_handler(ngx_http_request_t *r)
{
    /* size_t                      loc_len; */
    ngx_str_t                   args;
    ngx_str_t                   subrequest_uri;
    ngx_uint_t                  flags;
    /* ngx_http_core_loc_conf_t   *clcf; */
    ngx_http_eval_loc_conf_t   *ecf;
    ngx_http_eval_ctx_t        *ctx;
    ngx_http_eval_ctx_t        *sr_ctx;
    ngx_http_request_t         *sr;
    ngx_int_t                   rc;
    ngx_http_post_subrequest_t *psr;
    u_char                     *p;

    /*
    if(r != r->main) {
        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

        loc_len = r->valid_location ? clcf->name.len : 0;

        if(r->uri.len != loc_len) {
            r->uri.data += loc_len;
            r->uri.len -= loc_len;
        }
        else {
            r->uri.len = 1;
        }
    }
    */

    ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module);

    if(ecf->variables == NULL || !ecf->variables->nelts) {
        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module);

    if(ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ctx->base_conf = ecf;

        ngx_http_set_ctx(r, ctx, ngx_http_eval_module);
    }

    if (ctx->done) {
        dd("subrequest done");
        if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) {
            return NGX_DECLINED;
        }

        dd("status: %d", (int) ctx->status);

        return ctx->status;
    }

    if (ctx->in_progress) {
        dd("still in progress");
        return NGX_DONE;
    }

    psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
    if (psr == NULL) {
        return NGX_ERROR;
    }

    if(ngx_http_eval_init_variables(r, ctx, ecf) != NGX_OK) {
        return NGX_ERROR;
    }

    args = r->args;
    flags = 0;

    subrequest_uri.len = ecf->eval_location.len + r->uri.len;

    p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len);

    if(p == NULL) {
        return NGX_ERROR;
    }

    p = ngx_copy(p, ecf->eval_location.data, ecf->eval_location.len);
    p = ngx_copy(p, r->uri.data, r->uri.len);

    if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) {
        return NGX_ERROR;
    }

    psr->handler = ngx_http_eval_post_subrequest_handler;
    psr->data = ctx;

    flags |= NGX_HTTP_SUBREQUEST_WAITED;

    dd("subrequest in memory : %d", (int) ecf->subrequest_in_memory);

    if (ecf->subrequest_in_memory) {
        flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY;
    } else {
    }

    dd("issue subrequest");

    rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags);

    if (rc == NGX_ERROR || rc == NGX_DONE) {
        return rc;
    }

    sr->discard_body = 1;

    ctx->in_progress = 1;

    /* XXX we don't allow eval in subrequests, i think? */
    sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t));
    if (sr_ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_http_set_ctx(sr, sr_ctx, ngx_http_eval_module);

    dd("wait for subrequest to complete");

    return NGX_DONE;
}
Esempio n. 14
0
void 
ngx_php_error_cb(int type, 
    const char *error_filename, const uint error_lineno, const char *format, va_list args)
{
    TSRMLS_FETCH();
    char *buffer;
    int buffer_len, display;

    buffer_len = vspprintf(&buffer, PG(log_errors_max_len), format, args);
    
    /* check for repeated errors to be ignored */
    if (PG(ignore_repeated_errors) && PG(last_error_message)) {
        /* no check for PG(last_error_file) is needed since it cannot
         * be NULL if PG(last_error_message) is not NULL */
        if (strcmp(PG(last_error_message), buffer)
            || (!PG(ignore_repeated_source)
                && ((PG(last_error_lineno) != (int)error_lineno)
                    || strcmp(PG(last_error_file), error_filename)))) {
            display = 1;
        } else {
            display = 0;
        }
    } else {
        display = 1;
    }

    /* store the error if it has changed */
    if (display) {
        if (PG(last_error_message)) {
            free(PG(last_error_message));
            PG(last_error_message) = NULL;
        }
        if (PG(last_error_file)) {
            free(PG(last_error_file));
            PG(last_error_file) = NULL;
        }
        if (!error_filename) {
            error_filename = "Unknown";
        }
        PG(last_error_type) = type;
        PG(last_error_message) = strdup(buffer);
        PG(last_error_file) = strdup(error_filename);
        PG(last_error_lineno) = error_lineno;
    }

    /* according to error handling mode, suppress error, throw exception or show it */
    if (EG(error_handling) != EH_NORMAL) {
        switch (type) {
            case E_ERROR:
            case E_CORE_ERROR:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
            case E_PARSE:
                /* fatal errors are real errors and cannot be made exceptions */
                break;
            case E_STRICT:
            case E_DEPRECATED:
            case E_USER_DEPRECATED:
                /* for the sake of BC to old damaged code */
                break;
            case E_NOTICE:
            case E_USER_NOTICE:
                /* notices are no errors and are not treated as such like E_WARNINGS */
                break;
            default:
                /* throw an exception if we are in EH_THROW mode
                 * but DO NOT overwrite a pending exception
                 */
                if (EG(error_handling) == EH_THROW && !EG(exception)) {
                    zend_throw_error_exception(EG(exception_class), buffer, 0, type TSRMLS_CC);
                }
                efree(buffer);
                return;
        }
    }

    /* display/log the error if necessary */
    if (display && (EG(error_reporting) & type || (type & E_CORE))
        && (PG(log_errors) || PG(display_errors) ) ) {

        char *error_type_str;

        switch (type) {
            case E_ERROR:
            case E_CORE_ERROR:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
                error_type_str = "Fatal error";
                break;
            case E_RECOVERABLE_ERROR:
                error_type_str = "Catchable fatal error";
                break;
            case E_WARNING:
            case E_CORE_WARNING:
            case E_COMPILE_WARNING:
            case E_USER_WARNING:
                error_type_str = "Warning";
                break;
            case E_PARSE:
                error_type_str = "Parse error";
                break;
            case E_NOTICE:
            case E_USER_NOTICE:
                error_type_str = "Notice";
                break;
            case E_STRICT:
                error_type_str = "Strict Standards";
                break;
            case E_DEPRECATED:
            case E_USER_DEPRECATED:
                error_type_str = "Deprecated";
                break;
            default:
                error_type_str = "Unknown error";
                break;
        }
        buffer_len = spprintf(&buffer, 0, "%s: %s in %s on line %d", error_type_str, buffer, error_filename, error_lineno);

        ngx_buf_t *b;
        ngx_http_php_rputs_chain_list_t *chain;
        ngx_http_php_ctx_t *ctx;
        ngx_http_request_t *r;
        u_char *u_str;
        ngx_str_t ns;

        r = ngx_php_request;
        ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

        if ( ctx == NULL ) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s", buffer);

            ngx_php_debug("ngx_php error handler, ctx is nil.");

            efree(buffer);
            zend_bailout();

            ngx_http_php_zend_uthread_exit(r);
            return ;
        }

        ns.data = (u_char *)buffer;
        ns.len = buffer_len;

        if (ctx->rputs_chain == NULL){
            chain = ngx_pcalloc(r->pool, sizeof(ngx_http_php_rputs_chain_list_t));
            chain->out = ngx_alloc_chain_link(r->pool);
            chain->last = &chain->out;
        }else {
            chain = ctx->rputs_chain;
            (*chain->last)->next = ngx_alloc_chain_link(r->pool);
            chain->last = &(*chain->last)->next;
        }

        b = ngx_calloc_buf(r->pool);
        (*chain->last)->buf = b;
        (*chain->last)->next = NULL;

        u_str = ngx_pstrdup(r->pool, &ns);
        //u_str[ns.len] = '\0';
        (*chain->last)->buf->pos = u_str;
        (*chain->last)->buf->last = u_str + ns.len;
        (*chain->last)->buf->memory = 1;
        ctx->rputs_chain = chain;
        ngx_http_set_ctx(r, ctx, ngx_http_php_module);

        if (r->headers_out.content_length_n == -1){
            r->headers_out.content_length_n += ns.len + 1;
        }else {
            r->headers_out.content_length_n += ns.len;
        }

        if (!r->headers_out.status) {
            r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s", buffer);

        ngx_php_debug("ngx_php error handler.");

        efree(buffer);
        zend_bailout();

        ngx_http_php_zend_uthread_exit(r);
        return ;
    }

    /* Log if necessary */
    if (!display) {
        efree(buffer);
        return;
    }

    efree(buffer);
}
static ngx_int_t
ngx_http_srcache_fetch_subrequest(ngx_http_request_t *r,
    ngx_http_srcache_loc_conf_t *conf, ngx_http_srcache_ctx_t *ctx)
{
    ngx_http_srcache_ctx_t         *sr_ctx;
    ngx_http_post_subrequest_t     *psr;
    ngx_str_t                       args;
    ngx_uint_t                      flags = 0;
    ngx_http_request_t             *sr;
    ngx_int_t                       rc;

    ngx_http_srcache_parsed_request_t  *parsed_sr;

    dd_enter();

    parsed_sr = ngx_palloc(r->pool, sizeof(ngx_http_srcache_parsed_request_t));
    if (parsed_sr == NULL) {
        return NGX_ERROR;
    }

    parsed_sr->method      = conf->fetch->method;
    parsed_sr->method_name = conf->fetch->method_name;

    parsed_sr->request_body = NULL;
    parsed_sr->content_length_n = -1;

    if (ngx_http_complex_value(r, &conf->fetch->location,
                               &parsed_sr->location) != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (parsed_sr->location.len == 0) {
        return NGX_ERROR;
    }

    if (ngx_http_complex_value(r, &conf->fetch->args, &parsed_sr->args)
            != NGX_OK)
    {
        return NGX_ERROR;
    }

    args.data = NULL;
    args.len = 0;

    if (ngx_http_parse_unsafe_uri(r, &parsed_sr->location, &args, &flags)
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (args.len > 0 && parsed_sr->args.len == 0) {
        parsed_sr->args = args;
    }

    sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_ctx_t));
    if (sr_ctx == NULL) {
        return NGX_ERROR;
    }

    sr_ctx->in_fetch_subrequest = 1;

    psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
    if (psr == NULL) {
        return NGX_ERROR;
    }

    psr->handler = ngx_http_srcache_fetch_post_subrequest;
    psr->data = sr_ctx;

    dd("firing the fetch subrequest");

    dd("fetch location: %.*s", (int) parsed_sr->location.len,
       parsed_sr->location.data);

    dd("fetch args: %.*s", (int) parsed_sr->args.len,
            parsed_sr->args.data);

    rc = ngx_http_subrequest(r, &parsed_sr->location, &parsed_sr->args,
                             &sr, psr, flags);

    if (rc != NGX_OK) {
        return NGX_ERROR;
    }

    rc = ngx_http_srcache_adjust_subrequest(sr, parsed_sr);

    if (rc != NGX_OK) {
        return NGX_ERROR;
    }

    ngx_http_set_ctx(sr, sr_ctx, ngx_http_srcache_filter_module);

    ctx->issued_fetch_subrequest = 1;

    return NGX_OK;
}
static int
ngx_http_lua_ngx_location_capture_multi(lua_State *L)
{
    ngx_http_request_t              *r;
    ngx_http_request_t              *sr = NULL; /* subrequest object */
    ngx_http_post_subrequest_t      *psr;
    ngx_http_lua_ctx_t              *sr_ctx;
    ngx_http_lua_ctx_t              *ctx;
    ngx_array_t                     *extra_vars;
    ngx_str_t                        uri;
    ngx_str_t                        args;
    ngx_str_t                        extra_args;
    ngx_uint_t                       flags;
    u_char                          *p;
    u_char                          *q;
    size_t                           len;
    size_t                           nargs;
    int                              rc;
    int                              n;
    int                              always_forward_body = 0;
    ngx_uint_t                       method;
    ngx_http_request_body_t         *body;
    int                              type;
    ngx_buf_t                       *b;
    unsigned                         vars_action;
    ngx_uint_t                       nsubreqs;
    ngx_uint_t                       index;
    size_t                           sr_statuses_len;
    size_t                           sr_headers_len;
    size_t                           sr_bodies_len;
    size_t                           sr_flags_len;
    size_t                           ofs1, ofs2;
    unsigned                         custom_ctx;
    ngx_http_lua_co_ctx_t           *coctx;

    ngx_http_lua_post_subrequest_data_t      *psr_data;

    n = lua_gettop(L);
    if (n != 1) {
        return luaL_error(L, "only one argument is expected, but got %d", n);
    }

    luaL_checktype(L, 1, LUA_TTABLE);

    nsubreqs = lua_objlen(L, 1);
    if (nsubreqs == 0) {
        return luaL_error(L, "at least one subrequest should be specified");
    }

    r = ngx_http_lua_get_req(L);
    if (r == NULL) {
        return luaL_error(L, "no request object found");
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    if (ctx == NULL) {
        return luaL_error(L, "no ctx found");
    }

    ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
                               | NGX_HTTP_LUA_CONTEXT_ACCESS
                               | NGX_HTTP_LUA_CONTEXT_CONTENT);

    coctx = ctx->cur_co_ctx;
    if (coctx == NULL) {
        return luaL_error(L, "no co ctx found");
    }

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "lua location capture, uri:\"%V\" c:%ud", &r->uri,
                   r->main->count);

    sr_statuses_len = nsubreqs * sizeof(ngx_int_t);
    sr_headers_len  = nsubreqs * sizeof(ngx_http_headers_out_t *);
    sr_bodies_len   = nsubreqs * sizeof(ngx_str_t);
    sr_flags_len    = nsubreqs * sizeof(uint8_t);

    p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len +
                    sr_bodies_len + sr_flags_len);

    if (p == NULL) {
        return luaL_error(L, "no memory");
    }

    coctx->sr_statuses = (void *) p;
    p += sr_statuses_len;

    coctx->sr_headers = (void *) p;
    p += sr_headers_len;

    coctx->sr_bodies = (void *) p;
    p += sr_bodies_len;

    coctx->sr_flags = (void *) p;

    coctx->nsubreqs = nsubreqs;

    coctx->pending_subreqs = 0;

    extra_vars = NULL;

    for (index = 0; index < nsubreqs; index++) {
        coctx->pending_subreqs++;

        lua_rawgeti(L, 1, index + 1);
        if (lua_isnil(L, -1)) {
            return luaL_error(L, "only array-like tables are allowed");
        }

        dd("queries query: top %d", lua_gettop(L));

        if (lua_type(L, -1) != LUA_TTABLE) {
            return luaL_error(L, "the query argument %d is not a table, "
                              "but a %s",
                              index, lua_typename(L, lua_type(L, -1)));
        }

        nargs = lua_objlen(L, -1);

        if (nargs != 1 && nargs != 2) {
            return luaL_error(L, "query argument %d expecting one or "
                              "two arguments", index);
        }

        lua_rawgeti(L, 2, 1); /* queries query uri */

        dd("queries query uri: %d", lua_gettop(L));

        dd("first arg in first query: %s", lua_typename(L, lua_type(L, -1)));

        body = NULL;

        ngx_str_null(&extra_args);

        if (extra_vars != NULL) {
            /* flush out existing elements in the array */
            extra_vars->nelts = 0;
        }

        vars_action = 0;

        custom_ctx = 0;

        if (nargs == 2) {
            /* check out the options table */

            lua_rawgeti(L, 2, 2); /* queries query uri opts */

            dd("queries query uri opts: %d", lua_gettop(L));

            if (lua_type(L, 4) != LUA_TTABLE) {
                return luaL_error(L, "expecting table as the 2nd argument for "
                                  "subrequest %d, but got %s", index,
                                  luaL_typename(L, 4));
            }

            dd("queries query uri opts: %d", lua_gettop(L));

            /* check the args option */

            lua_getfield(L, 4, "args");

            type = lua_type(L, -1);

            switch (type) {
            case LUA_TTABLE:
                ngx_http_lua_process_args_option(r, L, -1, &extra_args);
                break;

            case LUA_TNIL:
                /* do nothing */
                break;

            case LUA_TNUMBER:
            case LUA_TSTRING:
                extra_args.data = (u_char *) lua_tolstring(L, -1, &len);
                extra_args.len = len;

                break;

            default:
                return luaL_error(L, "Bad args option value");
            }

            lua_pop(L, 1);

            dd("queries query uri opts: %d", lua_gettop(L));

            /* check the vars option */

            lua_getfield(L, 4, "vars");

            switch (lua_type(L, -1)) {
            case LUA_TTABLE:
                ngx_http_lua_process_vars_option(r, L, -1, &extra_vars);

                dd("post process vars top: %d", lua_gettop(L));
                break;

            case LUA_TNIL:
                /* do nothing */
                break;

            default:
                return luaL_error(L, "Bad vars option value");
            }

            lua_pop(L, 1);

            dd("queries query uri opts: %d", lua_gettop(L));

            /* check the share_all_vars option */

            lua_getfield(L, 4, "share_all_vars");

            switch (lua_type(L, -1)) {
            case LUA_TNIL:
                /* do nothing */
                break;

            case LUA_TBOOLEAN:
                if (lua_toboolean(L, -1)) {
                    vars_action |= NGX_HTTP_LUA_SHARE_ALL_VARS;
                }
                break;

            default:
                return luaL_error(L, "Bad share_all_vars option value");
            }

            lua_pop(L, 1);

            dd("queries query uri opts: %d", lua_gettop(L));

            /* check the copy_all_vars option */

            lua_getfield(L, 4, "copy_all_vars");

            switch (lua_type(L, -1)) {
            case LUA_TNIL:
                /* do nothing */
                break;

            case LUA_TBOOLEAN:
                if (lua_toboolean(L, -1)) {
                    vars_action |= NGX_HTTP_LUA_COPY_ALL_VARS;
                }
                break;

            default:
                return luaL_error(L, "Bad copy_all_vars option value");
            }

            lua_pop(L, 1);

            dd("queries query uri opts: %d", lua_gettop(L));

            /* check the "forward_body" option */

            lua_getfield(L, 4, "always_forward_body");
            always_forward_body = lua_toboolean(L, -1);
            lua_pop(L, 1);

            dd("always foward body: %d", always_forward_body);

            /* check the "method" option */

            lua_getfield(L, 4, "method");

            type = lua_type(L, -1);

            if (type == LUA_TNIL) {
                method = NGX_HTTP_GET;

            } else {
                if (type != LUA_TNUMBER) {
                    return luaL_error(L, "Bad http request method");
                }

                method = (ngx_uint_t) lua_tonumber(L, -1);
            }

            lua_pop(L, 1);

            dd("queries query uri opts: %d", lua_gettop(L));

            /* check the "ctx" option */

            lua_getfield(L, 4, "ctx");

            type = lua_type(L, -1);

            if (type != LUA_TNIL) {
                if (type != LUA_TTABLE) {
                    return luaL_error(L, "Bad ctx option value type %s, "
                                      "expected a Lua table",
                                      lua_typename(L, type));
                }

                custom_ctx = 1;

            } else {
                lua_pop(L, 1);
            }

            dd("queries query uri opts ctx?: %d", lua_gettop(L));

            /* check the "body" option */

            lua_getfield(L, 4, "body");

            type = lua_type(L, -1);

            if (type != LUA_TNIL) {
                if (type != LUA_TSTRING && type != LUA_TNUMBER) {
                    return luaL_error(L, "Bad http request body");
                }

                body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));

                if (body == NULL) {
                    return luaL_error(L, "no memory");
                }

                q = (u_char *) lua_tolstring(L, -1, &len);

                dd("request body: [%.*s]", (int) len, q);

                if (len) {
                    b = ngx_create_temp_buf(r->pool, len);
                    if (b == NULL) {
                        return luaL_error(L, "no memory");
                    }

                    b->last = ngx_copy(b->last, q, len);

                    body->bufs = ngx_alloc_chain_link(r->pool);
                    if (body->bufs == NULL) {
                        return luaL_error(L, "no memory");
                    }

                    body->bufs->buf = b;
                    body->bufs->next = NULL;

                    body->buf = b;
                }
            }

            lua_pop(L, 1); /* pop the body */

            /* stack: queries query uri opts ctx? */

            lua_remove(L, 4);

            /* stack: queries query uri ctx? */

            dd("queries query uri ctx?: %d", lua_gettop(L));

        } else {
            method = NGX_HTTP_GET;
        }

        /* stack: queries query uri ctx? */

        p = (u_char *) luaL_checklstring(L, 3, &len);

        uri.data = ngx_palloc(r->pool, len);
        if (uri.data == NULL) {
            return luaL_error(L, "memory allocation error");
        }

        ngx_memcpy(uri.data, p, len);

        uri.len = len;

        ngx_str_null(&args);

        flags = 0;

        rc = ngx_http_parse_unsafe_uri(r, &uri, &args, &flags);
        if (rc != NGX_OK) {
            dd("rc = %d", (int) rc);

            return luaL_error(L, "unsafe uri in argument #1: %s", p);
        }

        if (args.len == 0) {
            if (extra_args.len) {
                p = ngx_palloc(r->pool, extra_args.len);
                if (p == NULL) {
                    return luaL_error(L, "no memory");
                }

                ngx_memcpy(p, extra_args.data, extra_args.len);

                args.data = p;
                args.len = extra_args.len;
            }

        } else if (extra_args.len) {
            /* concatenate the two parts of args together */
            len = args.len + (sizeof("&") - 1) + extra_args.len;

            p = ngx_palloc(r->pool, len);
            if (p == NULL) {
                return luaL_error(L, "no memory");
            }

            q = ngx_copy(p, args.data, args.len);
            *q++ = '&';
            ngx_memcpy(q, extra_args.data, extra_args.len);

            args.data = p;
            args.len = len;
        }

        ofs1 = ngx_align(sizeof(ngx_http_post_subrequest_t), sizeof(void *));
        ofs2 = ngx_align(sizeof(ngx_http_lua_ctx_t), sizeof(void *));

        p = ngx_palloc(r->pool, ofs1 + ofs2
                       + sizeof(ngx_http_lua_post_subrequest_data_t));
        if (p == NULL) {
            return luaL_error(L, "no memory");
        }

        psr = (ngx_http_post_subrequest_t *) p;

        p += ofs1;

        sr_ctx = (ngx_http_lua_ctx_t *) p;

        ngx_http_lua_assert((void *) sr_ctx == ngx_align_ptr(sr_ctx,
                                                             sizeof(void *)));

        p += ofs2;

        psr_data = (ngx_http_lua_post_subrequest_data_t *) p;

        ngx_http_lua_assert((void *) psr_data == ngx_align_ptr(psr_data,
                                                               sizeof(void *)));

        ngx_memzero(sr_ctx, sizeof(ngx_http_lua_ctx_t));

        /* set by ngx_memzero:
         *      sr_ctx->run_post_subrequest = 0
         *      sr_ctx->free = NULL
         *      sr_ctx->body = NULL
         */

        psr_data->ctx = sr_ctx;
        psr_data->pr_co_ctx = coctx;

        psr->handler = ngx_http_lua_post_subrequest;
        psr->data = psr_data;

        rc = ngx_http_lua_subrequest(r, &uri, &args, &sr, psr, 0);

        if (rc != NGX_OK) {
            return luaL_error(L, "failed to issue subrequest: %d", (int) rc);
        }

        ngx_http_lua_init_ctx(sr, sr_ctx);

        sr_ctx->capture = 1;
        sr_ctx->index = index;
        sr_ctx->last_body = &sr_ctx->body;
        sr_ctx->vm_state = ctx->vm_state;

        ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module);

        rc = ngx_http_lua_adjust_subrequest(sr, method, always_forward_body,
                                            body, vars_action, extra_vars);

        if (rc != NGX_OK) {
            ngx_http_lua_cancel_subreq(sr);
            return luaL_error(L, "failed to adjust the subrequest: %d",
                              (int) rc);
        }

        dd("queries query uri opts ctx? %d", lua_gettop(L));

        /* stack: queries query uri ctx? */

        if (custom_ctx) {
            ngx_http_lua_ngx_set_ctx_helper(L, sr, sr_ctx, -1);
            lua_pop(L, 3);

        } else {
            lua_pop(L, 2);
        }

        /* stack: queries */
    }

    if (extra_vars) {
        ngx_array_destroy(extra_vars);
    }

    ctx->no_abort = 1;

    return lua_yield(L, 0);
}
static ngx_int_t
ngx_http_upstreamTest_handler(ngx_http_request_t *r)
{

    static ngx_int_t visited_times = 0;
    ngx_http_upstreamTest_ctx_t *upstreamctx = ngx_http_get_module_ctx(r,ngx_http_upstreamTest_module);
    if(upstreamctx == NULL)
    {
        upstreamctx = ngx_pcalloc(r->pool,sizeof(ngx_http_upstreamTest_ctx_t));
        if(upstreamctx == NULL)
        {
            return NGX_ERROR;
        }
        ngx_http_set_ctx(r,upstreamctx,ngx_http_upstream_module);
    }

    if(ngx_http_upstream_create(r) != NGX_OK)
    {
        ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"ngx_http_upstream_create() failed");
        return NGX_ERROR;
    }
    ngx_http_upstreamTest_conf_t *upstreamconf = (ngx_http_upstreamTest_conf_t *)ngx_http_get_module_loc_conf(r,ngx_http_upstreamTest_module);
    ngx_http_upstream_t *u = r->upstream;
    u->conf = &upstreamconf->upstream;
    u->buffering = upstreamconf->upstream.buffering;
    u->resolved = (ngx_http_upstream_resolved_t*)ngx_pcalloc(r->pool,sizeof(ngx_http_upstream_resolved_t));
    if(u->resolved == NULL)
    {
        ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"ngx_pcalloc resolved error. %s",strerror(errno));
        return NGX_ERROR;
    }

//    static struct sockaddr_in  backendSockAddr;
//    backendSockAddr.sin_family = AF_INET;
//    backendSockAddr.sin_port = htons((in_port_t)7777);
//    backendSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

//    u->resolved->sockaddr = (struct sockaddr *)&backendSockAddr;
//    u->resolved->socklen = sizeof(struct sockaddr_in);
//    u->resolved->naddrs = 1;

    u->create_request = ngx_http_upstreamTest_create_request;
    u->process_header = ngx_http_upstreamTest_process_status_line;
    u->finalize_request = ngx_http_upstreamTest_finalize_request;
    
  //  r->main->count++;
 //   ngx_http_upstream_init(r);
    if(!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD)))
        return NGX_HTTP_NOT_ALLOWED;

    u_char ngx_upstream_string[1024];
    ngx_sprintf(ngx_upstream_string,"Visited times: %d",++visited_times);
    ngx_log_error(NGX_LOG_EMERG,r->connection->log,0,"ngx_upstream_string: %s",ngx_upstream_string); 
    ngx_uint_t content_length = ngx_strlen(ngx_upstream_string);
    ngx_int_t rc;
    
    if(!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD)))
        return NGX_HTTP_NOT_ALLOWED;

    rc = ngx_http_discard_request_body(r);
    if(rc != NGX_OK)
    {
        ngx_log_error(NGX_LOG_EMERG,r->connection->log,0,"discard requst_body failed!");
        return rc;
    }
    
    ngx_str_set(&r->headers_out.content_type,"text/html");

    if(r->method == NGX_HTTP_HEAD)
    {
        r->headers_out.status = NGX_HTTP_OK;
        r->headers_out.content_length_n = content_length;
        ngx_log_error(NGX_LOG_EMERG,r->connection->log,0,"send respond head!");
        return ngx_http_send_header(r);
    }

    ngx_buf_t *b;
    b =  ngx_pcalloc(r->pool,sizeof(ngx_buf_t));
    if(b == NULL)
        return NGX_HTTP_INTERNAL_SERVER_ERROR;

    ngx_chain_t out;
    out.buf = b;
    out.next = NULL;

    b->pos = ngx_upstream_string;
    b->last = ngx_upstream_string + content_length;
    b->memory = 1;
    b->last_buf = 1;

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n  = content_length;

    rc = ngx_http_send_header(r);

    if(rc == NGX_ERROR || rc > NGX_OK || r->header_only)
        return rc;

    ngx_http_output_filter(r,&out);
    r->main->count++;
    ngx_http_upstream_init(r);
    return NGX_OK;
}
Esempio n. 18
0
//#define mechanics_debug
//naxsi_modifiers_debug
static ngx_int_t ngx_http_dummy_access_handler(ngx_http_request_t *r)
{
  ngx_http_request_ctx_t	*ctx;
  ngx_int_t			rc;
  ngx_http_dummy_loc_conf_t	*cf;
  ngx_http_core_loc_conf_t  *clcf;
  struct tms		 tmsstart, tmsend;
  clock_t		 start, end;
  ngx_http_variable_value_t *lookup;


  static ngx_str_t learning_flag = ngx_string(RT_LEARNING);
  static ngx_str_t enable_flag = ngx_string(RT_ENABLE);
  static ngx_str_t post_action_flag = ngx_string(RT_POST_ACTION);
  
  
  ctx = ngx_http_get_module_ctx(r, ngx_http_naxsi_module);
  cf = ngx_http_get_module_loc_conf(r, ngx_http_naxsi_module);

  clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
  /* ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, */
  /* 		"naxsi_entry_point"); */
  
  if (ctx && ctx->over)
    return (NGX_DECLINED);
  if (ctx && ctx->wait_for_body) {
#ifdef mechanics_debug
    ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		  "naxsi:NGX_AGAIN");
#endif
    return (NGX_DONE);
  }
  if (!cf) 
    return (NGX_ERROR);
  /* the module is not enabled here */
  if (!cf->enabled || cf->force_disabled)
    return (NGX_DECLINED);
  /* don't process internal requests. */
  if (r->internal) {
#ifdef mechanics_debug
    ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		  "XX-DON'T PROCESS (%V)|CTX:%p|ARGS:%V|METHOD=%s|INTERNAL:%d", &(r->uri), ctx, &(r->args),
		  r->method == NGX_HTTP_POST ? "POST" : r->method == NGX_HTTP_PUT ? "PUT" : r->method == NGX_HTTP_GET ? "GET" : "UNKNOWN!!",
		  r->internal);
#endif
    return (NGX_DECLINED);
  }
#ifdef mechanics_debug
  ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  		"XX-processing (%V)|CTX:%p|ARGS:%V|METHOD=%s|INTERNAL:%d", &(r->uri), ctx, &(r->args),
		r->method == NGX_HTTP_POST ? "POST" : r->method == NGX_HTTP_PUT ? "PUT" : r->method == NGX_HTTP_GET ? "GET" : "UNKNOWN!!",
		r->internal);
#endif
  if (!ctx) {
    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_request_ctx_t));
    /* might have been set by a previous trigger */
    if (ctx->learning)	{
      clcf->post_action.data = 0; //cf->denied_url->data;
      clcf->post_action.len = 0; //cf->denied_url->len;
    }
      
    if (ctx == NULL)
      return NGX_ERROR;
    ngx_http_set_ctx(r, ctx, ngx_http_naxsi_module);
    
#ifdef naxsi_modifiers_debug
    ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		  "XX-dummy : orig learning : %d", cf->learning ? 1 : 0);
#endif
    ctx->learning = cf->learning;
    lookup = ngx_http_get_variable(r, &learning_flag, cf->flag_learning_h);
    if (lookup && !lookup->not_found) {
      ctx->learning = lookup->data[0] - '0';
#ifdef naxsi_modifiers_debug
      ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		    "XX-dummy : override learning : %d", ctx->learning ? 1 : 0);
#endif
    }
#ifdef naxsi_modifiers_debug
    ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		  "XX-dummy : [final] learning : %d", ctx->learning ? 1 : 0);
#endif

    ctx->enabled = cf->enabled;
#ifdef naxsi_modifiers_debug
    ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		  "XX-dummy : orig enabled : %d", ctx->enabled ? 1 : 0);
#endif
    lookup = ngx_http_get_variable(r, &enable_flag, cf->flag_enable_h);
    if (lookup && !lookup->not_found) {
      ctx->enabled = lookup->data[0] - '0';
#ifdef naxsi_modifiers_debug
      ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		    "XX-dummy : override enable : %d", ctx->enabled ? 1 : 0);
#endif

    }
#ifdef naxsi_modifiers_debug
    ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		  "XX-dummy : [final] enabled : %d", ctx->enabled ? 1 : 0);
#endif
    
    if (cf->learning)
      ctx->post_action = 1;
    else
      ctx->post_action = 0;
#ifdef naxsi_modifiers_debug    
    ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		  "XX-dummy : orig post_action : %d", ctx->post_action ? 1 : 0);
#endif
    lookup = ngx_http_get_variable(r, &post_action_flag, cf->flag_post_action_h);
    if (lookup && !lookup->not_found) {
      ctx->post_action = lookup->data[0] - '0';
#ifdef naxsi_modifier_debug
      ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		    "XX-dummy : override post_action : %d", ctx->post_action ? 1 : 0);
#endif
    }
#ifdef naxsi_modifiers_debug
    ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		  "XX-dummy : [final] post_action : %d", ctx->post_action ? 1 : 0);
#endif
    //---

    /* the module is not enabled here */
    if (!ctx->enabled)
      return (NGX_DECLINED);
    

    if  ((r->method == NGX_HTTP_POST || r->method == NGX_HTTP_PUT) 
	 && !ctx->ready) {
#ifdef mechanics_debug
      ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		    "XX-dummy : body_request : before !");
#endif
      rc = ngx_http_read_client_request_body(r, ngx_http_dummy_payload_handler);
      /* this might happen quite often, especially with big files / 
      ** low network speed. our handler is called when headers are read, 
      ** but, often, the full body request hasn't yet, so 
      ** read client request body will return ngx_again. Then we need
      ** to return ngx_done, wait for our handler to be called once 
      ** body request arrived, and let him call core_run_phases
      ** to be able to process the request.
      */
      if (rc == NGX_AGAIN) {
	ctx->wait_for_body = 1;
#ifdef mechanics_debug
	ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		      "XX-dummy : body_request : NGX_AGAIN !");
#endif
	return (NGX_DONE);
      }
      else
	if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
	  /* this debug print should be commented, but the thing is that
	  ** according to what I read into nginx src code, it may happen
	  ** and I haven't been abble to trigger this, so I just let it 
	  ** here to know when this special case will be triggered
	  */
	  ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
			"XX-dummy : SPECIAL RESPONSE !!!!");
	  return rc;
	}
    }
    else
      ctx->ready = 1;
  }
  if (ctx && ctx->ready && !ctx->over) {
    
    if ((start = times(&tmsstart)) == (clock_t)-1)
      ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		    "XX-dummy : Failed to get time");
    ngx_http_dummy_data_parse(ctx, r);
    cf->request_processed++;
    if ((end = times(&tmsend)) == (clock_t)-1)
      ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		    "XX-dummy : Failed to get time");
    if (end - start > 0)
      ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
		    "[MORE THAN 1MS] times : start:%l end:%l diff:%l",
		    start, end, (end-start));
    ctx->over = 1;
    if (ctx->block) {
      cf->request_blocked++;
      rc = ngx_http_output_forbidden_page(ctx, r);
      //nothing:      return (NGX_OK);
      //redirect : return (NGX_HTTP_OK);
      return (rc);
    }
    else if (ctx->log)
      rc = ngx_http_output_forbidden_page(ctx, r);
  }
#ifdef mechanics_debug
  ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		"NGX_FINISHED !");
#endif

  return (NGX_DECLINED);
}
ngx_int_t
ngx_http_drizzle_handler(ngx_http_request_t *r)
{
    ngx_http_upstream_t            *u;
    ngx_http_drizzle_loc_conf_t    *dlcf;
#if defined(nginx_version) && nginx_version < 8017
    ngx_http_drizzle_ctx_t         *dctx;
#endif
    ngx_http_core_loc_conf_t       *clcf;
    ngx_str_t                       target;
    ngx_url_t                       url;
    ngx_connection_t               *c;

    dd("request: %p", r);
    dd("subrequest in memory: %d", (int) r->subrequest_in_memory);
    dd("connection: %p", r->connection);
    dd("connection log: %p", r->connection->log);

    if (r->subrequest_in_memory) {
        /* TODO: add support for subrequest in memory by
         * emitting output into u->buffer instead */

        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                      "ngx_http_drizzle_module does not support "
                      "subrequest in memory");

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    dlcf = ngx_http_get_module_loc_conf(r, ngx_http_drizzle_module);

    if ((dlcf->default_query == NULL) && !(dlcf->methods_set & r->method)) {
        if (dlcf->methods_set != 0) {
            return NGX_HTTP_NOT_ALLOWED;
        }

        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "drizzle: missing \"drizzle_query\" in location \"%V\"",
                      &clcf->name);

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    dd("XXX upstream already exists? %p", r->upstream);

#if defined(nginx_version) &&                                                \
    ((nginx_version >= 7063 && nginx_version < 8000)                         \
     || nginx_version >= 8007)

    dd("creating upstream.......");
    if (ngx_http_upstream_create(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    u = r->upstream;

#else /* 0.7.x < 0.7.63, 0.8.x < 0.8.7 */

    dd("XXX create upstream");
    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
    if (u == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#  if (NGX_THREADS)
    u->peer.lock = &r->connection->lock;
#  endif

    r->upstream = u;

#endif

    if (dlcf->complex_target) {
        /* variables used in the drizzle_pass directive */
        if (ngx_http_complex_value(r, dlcf->complex_target, &target)
            != NGX_OK)
        {
            dd("failed to compile");
            return NGX_ERROR;
        }

        if (target.len == 0) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "drizzle: handler: empty \"drizzle_pass\" target");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        url.host = target;
        url.port = 0;
        url.no_resolve = 1;

        dlcf->upstream.upstream = ngx_http_upstream_drizzle_add(r, &url);

        if (dlcf->upstream.upstream == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "drizzle: upstream \"%V\" not found", &target);

            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

#if defined(nginx_version) && nginx_version < 8017
    dctx = ngx_pcalloc(r->pool, sizeof(ngx_http_drizzle_ctx_t));
    if (dctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_http_set_ctx(r, dctx, ngx_http_drizzle_module);
#endif

    u->schema.len = sizeof("drizzle://") - 1;
    u->schema.data = (u_char *) "drizzle://";

    u->output.tag = (ngx_buf_tag_t) &ngx_http_drizzle_module;

    dd("drizzle tag: %p", (void *) u->output.tag);

    u->conf = &dlcf->upstream;

    u->create_request = ngx_http_drizzle_create_request;
    u->reinit_request = ngx_http_drizzle_reinit_request;
    u->process_header = ngx_http_drizzle_process_header;
    u->abort_request = ngx_http_drizzle_abort_request;
    u->finalize_request = ngx_http_drizzle_finalize_request;

    /* we bypass the upstream input filter mechanism in
     * ngx_http_upstream_process_headers */

    u->input_filter_init = ngx_http_drizzle_input_filter_init;
    u->input_filter = ngx_http_drizzle_input_filter;
    u->input_filter_ctx = NULL;

#if defined(nginx_version) && nginx_version >= 8011
    r->main->count++;
#endif

    dd("XXX connect timeout: %d", (int) dlcf->upstream.connect_timeout);

    ngx_http_upstream_dbd_init(r);

    /* override the read/write event handler to our own */
    u->write_event_handler = ngx_http_drizzle_wev_handler;
    u->read_event_handler  = ngx_http_drizzle_rev_handler;

    /* a bit hack-ish way to return error response (clean-up part) */
    if ((u->peer.connection) && (u->peer.connection->fd == 0)) {
        c = u->peer.connection;
        u->peer.connection = NULL;

        if (c->write->timer_set) {
            ngx_del_timer(c->write);
        }

        ngx_free_connection(c);

        ngx_http_upstream_drizzle_finalize_request(r, u,
#if defined(nginx_version) && (nginx_version >= 8017)
            NGX_HTTP_SERVICE_UNAVAILABLE);
#else
            dctx->status ? dctx->status : NGX_HTTP_INTERNAL_SERVER_ERROR);
#endif
    }
static mrb_value ngx_mrb_echo(mrb_state *mrb, mrb_value self)
{
  mrb_value argv;
  ngx_buf_t *b;
  ngx_mrb_rputs_chain_list_t *chain;
  u_char *str;
  ngx_str_t ns;

  ngx_http_request_t *r = ngx_mrb_get_request();
  ngx_http_mruby_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module);

  mrb_get_args(mrb, "o", &argv);

  if (mrb_type(argv) != MRB_TT_STRING) {
    argv = mrb_funcall(mrb, argv, "to_s", 0, NULL);
  }

  ns.data = (u_char *)RSTRING_PTR(
      mrb_str_plus(mrb, argv, mrb_str_new_lit(mrb, "\n")));
  ns.len = RSTRING_LEN(argv) + sizeof("\n") - 1;
  if (ns.len == 0) {
    return self;
  }

  if (ctx->rputs_chain == NULL) {
    chain = ngx_pcalloc(r->pool, sizeof(ngx_mrb_rputs_chain_list_t));
    if (chain == NULL) {
      mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory");
    }
    chain->out = ngx_alloc_chain_link(r->pool);
    if (chain->out == NULL) {
      mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory");
    }
    chain->last = &chain->out;
  } else {
    chain = ctx->rputs_chain;
    (*chain->last)->next = ngx_alloc_chain_link(r->pool);
    if ((*chain->last)->next == NULL) {
      mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory");
    }
    chain->last = &(*chain->last)->next;
  }
  b = ngx_calloc_buf(r->pool);
  if (b == NULL) {
    mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory");
  }
  (*chain->last)->buf = b;
  (*chain->last)->next = NULL;

  str = ngx_pstrdup(r->pool, &ns);
  if (str == NULL) {
    mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory");
  }
  str[ns.len] = '\0';
  (*chain->last)->buf->pos = str;
  (*chain->last)->buf->last = str + ns.len;
  (*chain->last)->buf->memory = 1;
  ctx->rputs_chain = chain;
  ngx_http_set_ctx(r, ctx, ngx_http_mruby_module);

  if (r->headers_out.content_length_n == -1) {
    r->headers_out.content_length_n += ns.len + 1;
  } else {
    r->headers_out.content_length_n += ns.len;
  }

  return self;
}
Esempio n. 21
0
static ngx_int_t
ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_int_t                     rc;
    ngx_connection_t             *c;
    ngx_output_chain_ctx_t       *ctx;
    ngx_http_core_loc_conf_t     *clcf;
    ngx_http_copy_filter_conf_t  *conf;

    c = r->connection;

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
                   "http copy filter: \"%V?%V\"", &r->uri, &r->args);

    ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module);

    if (ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
        if (ctx == NULL) {
            return NGX_ERROR;
        }

        ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module);

        conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module);
        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

        ctx->sendfile = c->sendfile;
        ctx->need_in_memory = r->main_filter_need_in_memory
                              || r->filter_need_in_memory;
        ctx->need_in_temp = r->filter_need_temporary;

        ctx->alignment = clcf->directio_alignment;

        ctx->pool = r->pool;
        ctx->bufs = conf->bufs;
        ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module;

        ctx->output_filter = (ngx_output_chain_filter_pt)
                                  ngx_http_next_body_filter;
        ctx->filter_ctx = r;

#if (NGX_HAVE_FILE_AIO)
        if (ngx_file_aio) {
            if (clcf->aio) {
                ctx->aio_handler = ngx_http_copy_aio_handler;
            }
#if (NGX_HAVE_AIO_SENDFILE)
            c->aio_sendfile = (clcf->aio == NGX_HTTP_AIO_SENDFILE);
#endif
        }
#endif

        if (in && in->buf && ngx_buf_size(in->buf)) {
            r->request_output = 1;
        }
    }

#if (NGX_HAVE_FILE_AIO)
    ctx->aio = r->aio;
#endif

    for ( ;; ) {
        rc = ngx_output_chain(ctx, in);

        if (ctx->in == NULL) {
            r->buffered &= ~NGX_HTTP_COPY_BUFFERED;

        } else {
            r->buffered |= NGX_HTTP_COPY_BUFFERED;
        }

        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
                       "http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);

#if (NGX_HAVE_FILE_AIO && NGX_HAVE_AIO_SENDFILE)

        if (c->busy_sendfile) {
            ssize_t                n;
            off_t                  offset;
            ngx_file_t            *file;
            ngx_http_ephemeral_t  *e;

            if (r->aio) {
                c->busy_sendfile = NULL;
                return rc;
            }

            file = c->busy_sendfile->file;
            offset = c->busy_sendfile->file_pos;

            if (file->aio) {
                c->busy_count = (offset == file->aio->last_offset) ?
                                c->busy_count + 1 : 0;
                file->aio->last_offset = offset;

                if (c->busy_count > 2) {
                    ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                                  "sendfile(%V) returned busy again",
                                  &file->name);
                    c->aio_sendfile = 0;
                }
            }

            c->busy_sendfile = NULL;
            e = (ngx_http_ephemeral_t *) &r->uri_start;

            n = ngx_file_aio_read(file, &e->aio_preload, 1, offset, r->pool);

            if (n > 0) {
                in = NULL;
                continue;
            }

            rc = n;

            if (rc == NGX_AGAIN) {
                file->aio->data = r;
                file->aio->handler = ngx_http_copy_aio_sendfile_event_handler;

                r->main->blocked++;
                r->aio = 1;
            }
        }
#endif

        return rc;
    }
}
static ngx_int_t
ngx_http_memcached_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_memcached_ctx_t       *ctx;
    ngx_http_memcached_loc_conf_t  *mlcf;

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    if (ngx_http_set_content_type(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (ngx_http_upstream_create(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    u = r->upstream;

    ngx_str_set(&u->schema, "memcached://");
    u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;

    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);

    u->conf = &mlcf->upstream;

    u->create_request = ngx_http_memcached_create_request;
    u->reinit_request = ngx_http_memcached_reinit_request;
    u->process_header = ngx_http_memcached_process_header;
    u->abort_request = ngx_http_memcached_abort_request;
    u->finalize_request = ngx_http_memcached_finalize_request;

    ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
    if (ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ctx->rest = NGX_HTTP_MEMCACHED_END;
    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);

    u->input_filter_init = ngx_http_memcached_filter_init;
    u->input_filter = ngx_http_memcached_filter;
    u->input_filter_ctx = ctx;

    r->main->count++;

    ngx_http_upstream_init(r);

    return NGX_DONE;
}
Esempio n. 23
0
ngx_int_t
passenger_content_handler(ngx_http_request_t *r)
{
    ngx_int_t              rc;
    ngx_http_upstream_t   *u;
    passenger_loc_conf_t  *slcf;
    ngx_str_t              path, base_uri;
    u_char                *path_last, *end;
    u_char                 root_path_str[NGX_MAX_PATH + 1];
    ngx_str_t              root_path;
    size_t                 root, len;
    u_char                 page_cache_file_str[NGX_MAX_PATH + 1];
    ngx_str_t              page_cache_file;
    passenger_context_t   *context;
    PP_Error               error;

    if (passenger_main_conf.root_dir.len == 0) {
        return NGX_DECLINED;
    } else if (r->subrequest_in_memory) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                      "ngx_http_passenger_module does not support "
                      "subrequest in memory");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module);

    /* Let the next content handler take care of this request if Phusion
     * Passenger is disabled for this URL.
     */
    if (!slcf->enabled) {
        return NGX_DECLINED;
    }
    
    /* Let the next content handler take care of this request if this URL
     * maps to an existing file.
     */
    path_last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    if (path_last != NULL && file_exists(path.data, 0)) {
        return NGX_DECLINED;
    }
    
    /* Create a string containing the root path. This path already
     * contains a trailing slash.
     */
    end = ngx_copy(root_path_str, path.data, root);
    *end = '\0';
    root_path.data = root_path_str;
    root_path.len  = root;
    
    
    context = ngx_pcalloc(r->pool, sizeof(passenger_context_t));
    if (context == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    ngx_http_set_ctx(r, context, ngx_http_passenger_module);
    
    
    /* Find the base URI for this web application, if any. */
    if (find_base_uri(r, slcf, &base_uri)) {
        /* Store the found base URI into context->public_dir. We infer that the 'public'
         * directory of the web application is document root + base URI.
         */
        len = root_path.len + base_uri.len + 1;
        context->public_dir.data = ngx_palloc(r->pool, sizeof(u_char) * len);
        end = ngx_copy(context->public_dir.data, root_path.data, root_path.len);
        end = ngx_copy(end, base_uri.data, base_uri.len);
        *end = '\0';
        context->public_dir.len = len - 1;
        context->base_uri = base_uri;
    } else {
        /* No base URI directives are applicable for this request. So assume that
         * the web application's public directory is the document root.
         * context->base_uri is now a NULL string.
         */
        len = sizeof(u_char *) * (root_path.len + 1);
        context->public_dir.data = ngx_palloc(r->pool, len);
        end = ngx_copy(context->public_dir.data, root_path.data,
                       root_path.len);
        *end = '\0';
        context->public_dir.len  = root_path.len;
    }
    
    /* If there's a corresponding page cache file for this URL, then serve that
     * file instead.
     */
    page_cache_file.data = page_cache_file_str;
    page_cache_file.len  = sizeof(page_cache_file_str);
    if (map_uri_to_page_cache_file(r, &context->public_dir, path.data,
                                   path_last - path.data, &page_cache_file)) {
        return passenger_static_content_handler(r, &page_cache_file);
    }
    
    if (slcf->app_type.data == NULL) {
        pp_error_init(&error);
        if (slcf->app_root.data == NULL) {
            context->app_type = pp_app_type_detector_check_document_root(
                pp_app_type_detector,
                (const char *) context->public_dir.data, context->public_dir.len,
                context->base_uri.len != 0,
                &error);
        } else {
            context->app_type = pp_app_type_detector_check_app_root(
                pp_app_type_detector,
                (const char *) slcf->app_root.data, slcf->app_root.len,
                &error);
        }
        if (context->app_type == PAT_NONE) {
            return NGX_DECLINED;
        } else if (context->app_type == PAT_ERROR) {
            if (error.errnoCode == EACCES) {
                ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                              "%s; This error means that the Nginx worker process (PID %d, "
                              "running as UID %d) does not have permission to access this file. "
                              "Please read the manual to learn how to fix this problem: "
                              "section 'Troubleshooting' -> 'Upon accessing the web app, Nginx "
                              "reports a \"Permission denied\" error'; Extra info",
                              error.message,
                              (int) getpid(),
                              (int) getuid());
            } else {
                ngx_log_error(NGX_LOG_ALERT, r->connection->log,
                              (error.errnoCode == PP_NO_ERRNO) ? 0 : error.errnoCode,
                              "%s",
                              error.message);
            }
            pp_error_destroy(&error);
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    } else {
        context->app_type = pp_get_app_type2((const char *) slcf->app_type.data,
            slcf->app_type.len);
        if (context->app_type == PAT_NONE) {
            return NGX_DECLINED;
        }
    }
    
    
    /* Setup upstream stuff and prepare sending the request to the backend. */
    
    if (ngx_http_upstream_create(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    u = r->upstream;
    
    u->schema = pp_schema_string;
    u->output.tag = (ngx_buf_tag_t) &ngx_http_passenger_module;
    set_upstream_server_address(u, &slcf->upstream_config);
    u->conf = &slcf->upstream_config;

#if (NGX_HTTP_CACHE)
    u->create_key       = create_key;
#endif
    u->create_request   = create_request;
    u->reinit_request   = reinit_request;
    u->process_header   = process_status_line;
    u->abort_request    = abort_request;
    u->finalize_request = finalize_request;
    r->state = 0;

    u->buffering = slcf->upstream_config.buffering;
    
    u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
    if (u->pipe == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
    u->pipe->input_ctx = r;

    rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

    fix_peer_address(r);

    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        return rc;
    }

    return NGX_DONE;
}
static ngx_int_t
ngx_http_charset_header_filter(ngx_http_request_t *r)
{
    ngx_int_t                      charset, source_charset;
    ngx_str_t                     *mc, *from, *to, s;
    ngx_uint_t                     n;
    ngx_http_charset_t            *charsets;
    ngx_http_charset_ctx_t        *ctx;
    ngx_http_variable_value_t     *vv;
    ngx_http_charset_loc_conf_t   *lcf, *mlcf;
    ngx_http_charset_main_conf_t  *mcf;

    mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);

    charsets = mcf->charsets.elts;
    n = mcf->charsets.nelts;

    /* destination charset */

    if (r == r->main) {

        if (!r->ignore_content_encoding
            && r->headers_out.content_encoding
            && r->headers_out.content_encoding->value.len)
        {
            return ngx_http_next_header_filter(r);
        }

        if (r->headers_out.content_type.len == 0) {
            return ngx_http_next_header_filter(r);
        }

        if (r->headers_out.override_charset
            && r->headers_out.override_charset->len)
        {
            charset = ngx_http_charset_get_charset(charsets, n,
                                              r->headers_out.override_charset);

            if (charset == NGX_HTTP_NO_CHARSET) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "unknown charset \"%V\" to override",
                              r->headers_out.override_charset);

                return ngx_http_next_header_filter(r);
            }

        } else {
            mlcf = ngx_http_get_module_loc_conf(r,
                                                ngx_http_charset_filter_module);
            charset = mlcf->charset;

            if (charset == NGX_HTTP_NO_CHARSET) {
                return ngx_http_next_header_filter(r);
            }

            if (r->headers_out.charset.len) {
                if (mlcf->override_charset == 0) {
                    return ngx_http_next_header_filter(r);
                }

            } else {
                if (ngx_http_test_content_type(r, &mlcf->types) == NULL) {
                    return ngx_http_next_header_filter(r);
                }
            }

            if (charset >= NGX_HTTP_CHARSET_VAR) {
                vv = ngx_http_get_indexed_variable(r,
                                               charset - NGX_HTTP_CHARSET_VAR);

                if (vv == NULL || vv->not_found) {
                    return NGX_ERROR;
                }

                s.len = vv->len;
                s.data = vv->data;

                charset = ngx_http_charset_get_charset(charsets, n, &s);
            }
        }

    } else {
        ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module);

        if (ctx == NULL) {

            mc = &r->main->headers_out.charset;

            if (mc->len == 0) {
                return ngx_http_next_header_filter(r);
            }

            ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
            if (ctx == NULL) {
                return NGX_ERROR;
            }

            ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module);

            charset = ngx_http_charset_get_charset(charsets, n, mc);

            ctx->charset = charset;

        } else {
            charset = ctx->charset;
        }
    }

    /* source charset */

    if (r->headers_out.charset.len == 0) {
        lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);

        source_charset = lcf->source_charset;

        if (source_charset >= NGX_HTTP_CHARSET_VAR) {
            vv = ngx_http_get_indexed_variable(r,
                                        source_charset - NGX_HTTP_CHARSET_VAR);

            if (vv == NULL || vv->not_found) {
                return NGX_ERROR;
            }

            s.len = vv->len;
            s.data = vv->data;

            source_charset = ngx_http_charset_get_charset(charsets, n, &s);
        }

        if (charset != NGX_HTTP_NO_CHARSET) {
            return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset,
                                                source_charset);
        }

        if (source_charset == NGX_CONF_UNSET) {
            return ngx_http_next_header_filter(r);
        }

        from = &charsets[source_charset].name;
        to = &r->main->headers_out.charset;

        goto no_charset_map;
    }

    source_charset = ngx_http_charset_get_charset(charsets, n,
                                                  &r->headers_out.charset);

    if (charset == NGX_HTTP_NO_CHARSET
        || source_charset == NGX_HTTP_NO_CHARSET)
    {
        if (charset != source_charset
            || ngx_strcasecmp(r->main->headers_out.charset.data,
                              r->headers_out.charset.data)
                != 0)
        {
            from = &r->headers_out.charset;
            to = (charset == NGX_HTTP_NO_CHARSET) ?
                                           &r->main->headers_out.charset:
                                           &charsets[charset].name;

            goto no_charset_map;
        }

        return ngx_http_next_header_filter(r);
    }

    if (source_charset != charset
        && (charsets[source_charset].tables == NULL
            || charsets[source_charset].tables[charset] == NULL))
    {
        from = &charsets[source_charset].name;
        to = &charsets[charset].name;

        goto no_charset_map;
    }

    r->headers_out.content_type.len = r->headers_out.content_type_len;

    return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset,
                                        source_charset);

no_charset_map:

    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "no \"charset_map\" between the charsets \"%V\" and \"%V\"",
                  from, to);

    return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_redis_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_redis_ctx_t           *ctx;
    ngx_http_redis_loc_conf_t      *rlcf;

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    if (ngx_http_set_content_type(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

#if defined nginx_version && nginx_version >= 8011
    if (ngx_http_upstream_create(r) != NGX_OK) {
#else
    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);

    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
    if (u == NULL) {
#endif
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

#if defined nginx_version && nginx_version >= 8011
    u = r->upstream;
#endif

#if defined nginx_version && nginx_version >= 8037
    ngx_str_set(&u->schema, "redis://");
#else
    u->schema.len = sizeof("redis://") - 1;
    u->schema.data = (u_char *) "redis://";
#endif

#if defined nginx_version && nginx_version >= 8011
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module;
#else
    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#endif

#if defined nginx_version && nginx_version >= 8011
    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);
#else
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module;
#endif

    u->conf = &rlcf->upstream;

    u->create_request = ngx_http_redis_create_request;
    u->reinit_request = ngx_http_redis_reinit_request;
    u->process_header = ngx_http_redis_process_header;
    u->abort_request = ngx_http_redis_abort_request;
    u->finalize_request = ngx_http_redis_finalize_request;

#if defined nginx_version && nginx_version < 8011
    r->upstream = u;
#endif

    ctx = ngx_palloc(r->pool, sizeof(ngx_http_redis_ctx_t));
    if (ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ctx->rest = NGX_HTTP_REDIS_END;
    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_redis_module);

    u->input_filter_init = ngx_http_redis_filter_init;
    u->input_filter = ngx_http_redis_filter;
    u->input_filter_ctx = ctx;

#if defined nginx_version && nginx_version >= 8011
    r->main->count++;
#endif

    ngx_http_upstream_init(r);

    return NGX_DONE;
}


static ngx_int_t
ngx_http_redis_create_request(ngx_http_request_t *r)
{
    size_t                          len;
    uintptr_t                       escape;
    ngx_buf_t                      *b;
    ngx_chain_t                    *cl;
    ngx_http_redis_ctx_t           *ctx;
    ngx_http_variable_value_t      *vv[2];
    ngx_http_redis_loc_conf_t      *rlcf;

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);

    vv[0] = ngx_http_get_indexed_variable(r, ngx_http_redis_db_index);

    /*
     * If user do not select redis database in nginx.conf by redis_db
     * variable, just add size of "select 0" to request.  This is add
     * some overhead in talk with redis, but this way simplify parsing
     * the redis answer in ngx_http_redis_process_header().
     */
    if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select 0 redis database" );
        len = sizeof("select 0") - 1;
    } else {
        len = sizeof("select ") - 1 + vv[0]->len;
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select %s redis database", vv[0]->data);
    }
    len += sizeof(CRLF) - 1;

    vv[1] = ngx_http_get_indexed_variable(r, rlcf->index);

    /* If nginx.conf have no redis_key return error. */
    if (vv[1] == NULL || vv[1]->not_found || vv[1]->len == 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "the \"$redis_key\" variable is not set");
        return NGX_ERROR;
    }

    /* Count have space required escape symbols. */
    escape = 2 * ngx_escape_uri(NULL, vv[1]->data, vv[1]->len, NGX_ESCAPE_REDIS);

    len += sizeof("get ") - 1 + vv[1]->len + escape + sizeof(CRLF) - 1;

    /* Create temporary buffer for request with size len. */
    b = ngx_create_temp_buf(r->pool, len);
    if (b == NULL) {
        return NGX_ERROR;
    }

    cl = ngx_alloc_chain_link(r->pool);
    if (cl == NULL) {
        return NGX_ERROR;
    }

    cl->buf = b;
    cl->next = NULL;

    r->upstream->request_bufs = cl;

    /* Add "select " for request. */
    *b->last++ = 's'; *b->last++ = 'e'; *b->last++ = 'l'; *b->last++ = 'e';
    *b->last++ = 'c'; *b->last++ = 't'; *b->last++ = ' ';

    /* Get context redis_db from configuration file. */
    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    ctx->key.data = b->last;

    /*
     * Add "0" as redis number db to request if redis_db undefined,
     * othervise add real number from context.
     */
    if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select 0 redis database" );
        *b->last++ = '0';
    } else {
        b->last = ngx_copy(b->last, vv[0]->data, vv[0]->len);
        ctx->key.len = b->last - ctx->key.data;
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select %V redis database", &ctx->key);
    }

    /* Add "\r\n". */
    *b->last++ = CR; *b->last++ = LF;


    /* Add "get" command with space. */
    *b->last++ = 'g'; *b->last++ = 'e'; *b->last++ = 't'; *b->last++ = ' ';

    /* Get context redis_key from nginx.conf. */
    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    ctx->key.data = b->last;

    /*
     * If no escape symbols then copy data as is, othervise use
     * escape-copy function.
     */

    if (escape == 0) {
        b->last = ngx_copy(b->last, vv[1]->data, vv[1]->len);

    } else {
        b->last = (u_char *) ngx_escape_uri(b->last, vv[1]->data, vv[1]->len,
                                            NGX_ESCAPE_REDIS);
    }

    ctx->key.len = b->last - ctx->key.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http redis request: \"%V\"", &ctx->key);

    /* Add one more "\r\n". */
    *b->last++ = CR; *b->last++ = LF;

    /*
     * Summary, the request looks like this:
     * "select $redis_db\r\nget $redis_key\r\n", where
     * $redis_db and $redis_key are variable's values.
     */

    return NGX_OK;
}
static ngx_int_t
ngx_http_gzip_header_filter(ngx_http_request_t *r)
{
    ngx_table_elt_t       *h;
    ngx_http_gzip_ctx_t   *ctx;
    ngx_http_gzip_conf_t  *conf;
    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
    if (!conf->enable
            || (r->headers_out.status != NGX_HTTP_OK
                && r->headers_out.status != NGX_HTTP_FORBIDDEN
                && r->headers_out.status != NGX_HTTP_NOT_FOUND)
            || (r->headers_out.content_encoding
                && r->headers_out.content_encoding->value.len)
            || (r->headers_out.content_length_n != -1
                && r->headers_out.content_length_n < conf->min_length)
            || ngx_http_test_content_type(r, &conf->types) == NULL
            || r->header_only)
    {
        return ngx_http_next_header_filter(r);
    }
    r->gzip_vary = 1;
#if (NGX_HTTP_DEGRADATION)
    {
        ngx_http_core_loc_conf_t  *clcf;
        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
        if (clcf->gzip_disable_degradation && ngx_http_degraded(r))
        {
            return ngx_http_next_header_filter(r);
        }
    }
#endif
    if (!r->gzip_tested)
    {
        if (ngx_http_gzip_ok(r) != NGX_OK)
        {
            return ngx_http_next_header_filter(r);
        }
    }
    else if (!r->gzip_ok)
    {
        return ngx_http_next_header_filter(r);
    }
    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t));
    if (ctx == NULL)
    {
        return NGX_ERROR;
    }
    ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module);
    ctx->request = r;
    ctx->buffering = (conf->postpone_gzipping != 0);
    ngx_http_gzip_filter_memory(r, ctx);
    h = ngx_list_push(&r->headers_out.headers);
    if (h == NULL)
    {
        return NGX_ERROR;
    }
    h->hash = 1;
    ngx_str_set(&h->key, "Content-Encoding");
    ngx_str_set(&h->value, "gzip");
    r->headers_out.content_encoding = h;
    r->main_filter_need_in_memory = 1;
    ngx_http_clear_content_length(r);
    ngx_http_clear_accept_ranges(r);
    ngx_http_weak_etag(r);
    return ngx_http_next_header_filter(r);
}
Esempio n. 27
0
ngx_int_t
ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r)
{
    int                      co_ref;
    lua_State               *co;
    ngx_http_lua_ctx_t      *ctx;
    ngx_http_cleanup_t      *cln;

    dd("content by chunk");

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    if (ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        dd("setting new ctx, ctx = %p, size: %d", ctx, (int) sizeof(*ctx));

        ctx->entry_ref = LUA_NOREF;
        ctx->ctx_ref = LUA_NOREF;

        ngx_http_set_ctx(r, ctx, ngx_http_lua_module);

    } else {
        dd("reset ctx");
        ngx_http_lua_reset_ctx(r, L, ctx);
    }

    ctx->entered_content_phase = 1;

    /*  {{{ new coroutine to handle request */
    co = ngx_http_lua_new_thread(r, L, &co_ref);

    if (co == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                     "lua: failed to create new coroutine to handle request");

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /*  move code closure to new coroutine */
    lua_xmove(L, co, 1);

    /*  set closure's env table to new coroutine's globals table */
    lua_pushvalue(co, LUA_GLOBALSINDEX);
    lua_setfenv(co, -2);

    /*  save nginx request in coroutine globals table */
    lua_pushlightuserdata(co, &ngx_http_lua_request_key);
    lua_pushlightuserdata(co, r);
    lua_rawset(co, LUA_GLOBALSINDEX);
    /*  }}} */

    ctx->entry_co = co;
    ctx->cur_co = co;
    ctx->cur_co_ctx = &ctx->entry_co_ctx;
    ctx->cur_co_ctx->co = co;
    ctx->entry_ref = co_ref;

    /*  {{{ register request cleanup hooks */
    if (ctx->cleanup == NULL) {
        cln = ngx_http_cleanup_add(r, 0);
        if (cln == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        cln->handler = ngx_http_lua_request_cleanup;
        cln->data = r;
        ctx->cleanup = &cln->handler;
    }
    /*  }}} */

    ctx->context = NGX_HTTP_LUA_CONTEXT_CONTENT;

    return ngx_http_lua_run_thread(L, r, ctx, 0);
}
ngx_int_t
ngx_http_srcache_access_handler(ngx_http_request_t *r)
{
    ngx_str_t                       skip;
    ngx_int_t                       rc;
    ngx_http_srcache_loc_conf_t    *conf;
    ngx_http_srcache_main_conf_t   *smcf;
    ngx_http_srcache_ctx_t         *ctx;
    ngx_chain_t                    *cl;
    size_t                          len;
    unsigned                        no_store;

    /* access phase handlers are skipped in subrequests,
     * so the current request must be a main request */

    conf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module);

    if (conf->fetch == NULL && conf->store == NULL) {
        dd("bypass: %.*s", (int) r->uri.len, r->uri.data);
        return NGX_DECLINED;
    }

    dd("store defined? %p", conf->store);

    dd("req method: %lu", (unsigned long) r->method);
    dd("cache methods: %lu", (unsigned long) conf->cache_methods);

    if (!(r->method & conf->cache_methods)) {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "srcache_fetch and srcache_store skipped due to request "
                       "method %V", &r->method_name);

        return NGX_DECLINED;
    }

    if (conf->req_cache_control
        && ngx_http_srcache_request_no_cache(r, &no_store) == NGX_OK)
    {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "srcache_fetch skipped due to request headers "
                       "\"Cache-Control: no-cache\" or \"Pragma: no-cache\"");

        if (!no_store) {
            /* register a ctx to give a chance to srcache_store to run */

            ctx = ngx_pcalloc(r->pool,
                              sizeof(ngx_http_srcache_filter_module));

            if (ctx == NULL) {
                return NGX_ERROR;
            }

            ngx_http_set_ctx(r, ctx, ngx_http_srcache_filter_module);

        } else {
            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "srcache_store skipped due to request header "
                           "\"Cache-Control: no-store\"");
        }

        return NGX_DECLINED;
    }

    if (conf->fetch_skip != NULL
        && ngx_http_complex_value(r, conf->fetch_skip, &skip) == NGX_OK
        && skip.len
        && (skip.len != 1 || skip.data[0] != '0'))
    {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "srcache_fetch skipped due to the true value fed into "
                       "srcache_fetch_skip: \"%V\"", &skip);

        /* register a ctx to give a chance to srcache_store to run */

        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_filter_module));

        if (ctx == NULL) {
            return NGX_ERROR;
        }

        ngx_http_set_ctx(r, ctx, ngx_http_srcache_filter_module);

        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_srcache_filter_module);

    if (ctx != NULL) {
        /*
        if (ctx->fetch_error) {
            return NGX_DECLINED;
        }
        */

        if (ctx->waiting_subrequest) {
            dd("waiting subrequest");
            return NGX_AGAIN;
        }

        if (ctx->waiting_request_body) {
            return NGX_AGAIN;
        }

        if (ctx->request_body_done == 1) {
            ctx->request_body_done = 0;
            goto do_fetch_subrequest;
        }

        if (ctx->request_done) {
            dd("request done");

            if (ngx_http_post_request(r, NULL) != NGX_OK) {
                return NGX_ERROR;
            }

            if (!ctx->from_cache) {
                return NGX_DECLINED;
            }

            dd("sending header");

            if (ctx->body_from_cache) {
                len = 0;

                for (cl = ctx->body_from_cache; cl->next; cl = cl->next) {
                    len += ngx_buf_size(cl->buf);
                }

                len += ngx_buf_size(cl->buf);

                cl->buf->last_buf = 1;

                r->headers_out.content_length_n = len;

                rc = ngx_http_srcache_fetch_header_filter(r);

                dd("srcache fetch header returned %d", (int) rc);

                if (rc == NGX_ERROR || rc > NGX_OK) {
                    return rc;
                }

#if 1
                if (r->header_only) {
                    return NGX_HTTP_OK;
                }
#endif

                if (!r->filter_finalize) {
                    rc = ngx_http_srcache_next_body_filter(r,
                                                        ctx->body_from_cache);

                    if (rc == NGX_ERROR) {
                        r->connection->error = 1;
                        return NGX_ERROR;
                    }

                    if (rc > NGX_OK) {
                        return rc;
                    }
                }

                dd("sent body from cache: %d", (int) rc);
                dd("finalize from here...");

                ngx_http_finalize_request(r, rc);

                /* dd("r->main->count (post): %d", (int) r->main->count); */
                return NGX_DONE;
            }

            return NGX_DECLINED;
        }

    } else {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_filter_module));

        if (ctx == NULL) {
            return NGX_ERROR;
        }

        ngx_http_set_ctx(r, ctx, ngx_http_srcache_filter_module);
    }

    smcf = ngx_http_get_module_main_conf(r, ngx_http_srcache_filter_module);

    if (!smcf->postponed_to_access_phase_end) {
        ngx_http_core_main_conf_t       *cmcf;
        ngx_http_phase_handler_t         tmp;
        ngx_http_phase_handler_t        *ph;
        ngx_http_phase_handler_t        *cur_ph;
        ngx_http_phase_handler_t        *last_ph;

        smcf->postponed_to_access_phase_end = 1;

        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

        ph = cmcf->phase_engine.handlers;
        cur_ph = &ph[r->phase_handler];

        /* we should skip the post_access phase handler here too */
        last_ph = &ph[cur_ph->next - 2];

        if (cur_ph < last_ph) {
            dd("swaping the contents of cur_ph and last_ph...");

            tmp = *cur_ph;

            memmove(cur_ph, cur_ph + 1,
                    (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t));

            *last_ph = tmp;

            r->phase_handler--; /* redo the current ph */

            return NGX_DECLINED;
        }
    }

    if (conf->fetch == NULL) {
        dd("fetch is not defined");
        return NGX_DECLINED;
    }

    dd("running phase handler...");

    if (!r->request_body) {
        dd("reading request body: ctx = %p", ctx);

        rc = ngx_http_read_client_request_body(r,
                                               ngx_http_srcache_post_read_body);
        if (rc == NGX_ERROR || rc > NGX_OK) {
#if (nginx_version < 1002006)                                               \
    || (nginx_version >= 1003000 && nginx_version < 1003009)
            r->main->count--;
#endif
            return rc;
        }

        if (rc == NGX_AGAIN) {
            ctx->waiting_request_body = 1;
            return NGX_AGAIN;
        }

        /* rc == NGX_OK */
    }

do_fetch_subrequest:
    /* issue a subrequest to fetch cached stuff (if any) */

    rc = ngx_http_srcache_fetch_subrequest(r, conf, ctx);

    if (rc != NGX_OK) {
        return rc;
    }

    ctx->waiting_subrequest = 1;

    dd("quit");

    return NGX_AGAIN;
}
static ngx_int_t
ngx_http_req_status_handler(ngx_http_request_t *r)
{
    size_t                              len;
    uint32_t                            hash;
    ngx_str_t                           key;
    ngx_uint_t                          i;
    ngx_time_t                         *tp;
    ngx_shm_zone_t                    **pzone;
    ngx_pool_cleanup_t                 *cln;
    ngx_http_req_status_ctx_t          *r_ctx;
    ngx_http_req_status_zone_t         *ctx;
    ngx_http_req_status_node_t         *ssn;
    ngx_http_req_status_loc_conf_t     *rlcf;
    ngx_http_req_status_zone_node_t    *pzn;

    r_ctx = ngx_http_get_module_ctx(r, ngx_http_req_status_module);

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_req_status_module);

    do {
        pzone = rlcf->req_zones.elts;

        for (i = 0; i < rlcf->req_zones.nelts; i++) {
            ctx = pzone[i]->data;

            if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) {
                continue;
            }

            if (key.len == 0) {
                continue;
            }

            if (key.len > 65535) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                        "req-status, the value of the \"%V\" variable "
                        "is more than 65535 bytes: \"%v\"",
                        &ctx->key.value, &key);
                continue;
            }

            if (r_ctx == NULL) {

                r_ctx = ngx_palloc(r->pool, sizeof(ngx_http_req_status_ctx_t));
                if (r_ctx == NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                if (ngx_array_init(&r_ctx->req_zones, r->pool, 2,
                            sizeof(ngx_http_req_status_zone_node_t))
                        != NGX_OK)
                {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                cln = ngx_pool_cleanup_add(r->pool, 0);
                if (cln == NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                cln->handler = ngx_http_req_status_cleanup;
                cln->data = r_ctx;

                ngx_http_set_ctx(r, r_ctx, ngx_http_req_status_module);
            }

            hash = ngx_crc32_short(key.data, key.len);

            ngx_shmtx_lock(&ctx->shpool->mutex);

            ssn = ngx_http_req_status_lookup(ctx, hash, &key);

            if (ssn == NULL) {
                len  = sizeof(ngx_http_req_status_node_t) + key.len + 1;

                ssn = ngx_slab_alloc_locked(ctx->shpool, len);
                if (ssn == NULL) {
                    ngx_http_req_status_expire(ctx);

                    ssn = ngx_slab_alloc_locked(ctx->shpool, len);
                    if (ssn == NULL) {
                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                "req-status, slab alloc fail, zone = \"%V\", "
                                "key = \"%V\", size = %uz",
                                &ctx->shm_zone->shm.name, &key, len);

                        ngx_shmtx_unlock(&ctx->shpool->mutex);

                        continue;
                    }
                }

                ssn->node.key = hash;
                ssn->len = key.len;
                ssn->count = 1;

                ngx_memzero(&ssn->data, sizeof(ssn->data));
                ngx_memcpy(ssn->key, key.data, key.len);
                ssn->key[key.len] = '\0';
                ssn->last_traffic_update = 0;

                ngx_rbtree_insert(&ctx->sh->rbtree, &ssn->node);
            }

            tp = ngx_timeofday();

            ssn->data.requests ++;
            ssn->active ++;
            if (ssn->active > ssn->data.max_active) {
                ssn->data.max_active = ssn->active;
            }

            ngx_queue_insert_head(&ctx->sh->queue, &ssn->queue);

            ngx_shmtx_unlock(&ctx->shpool->mutex);

            pzn = ngx_array_push(&r_ctx->req_zones);
            if (pzn == NULL) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            pzn->node = ssn;
            pzn->zone = ctx;
        }

        rlcf = rlcf->parent;
    } while (rlcf);

    return NGX_DECLINED;
}
Esempio n. 30
0
static ngx_int_t
ngx_http_tfs_handler(ngx_http_request_t *r)
{
    ngx_int_t                  rc;
    ngx_http_tfs_t            *t;
    ngx_http_tfs_loc_conf_t   *tlcf;
    ngx_http_tfs_srv_conf_t   *tscf;
    ngx_http_tfs_main_conf_t  *tmcf;

    tlcf = ngx_http_get_module_loc_conf(r, ngx_http_tfs_module);
    tscf = ngx_http_get_module_srv_conf(r, ngx_http_tfs_module);
    tmcf = ngx_http_get_module_main_conf(r, ngx_http_tfs_module);

    t = ngx_pcalloc(r->pool, sizeof(ngx_http_tfs_t));

    if (t == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "alloc ngx_http_tfs_t failed");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    t->pool = r->pool;
    t->data = r;
    t->log = r->connection->log;
    t->loc_conf = tlcf;
    t->srv_conf = tscf;
    t->main_conf = tmcf;
    t->output.tag = (ngx_buf_tag_t) &ngx_http_tfs_module;
    if (tmcf->local_block_cache_ctx != NULL) {
        t->block_cache_ctx.use_cache |= NGX_HTTP_TFS_LOCAL_BLOCK_CACHE;
        t->block_cache_ctx.local_ctx = tmcf->local_block_cache_ctx;
    }
    if (tmcf->enable_remote_block_cache == NGX_HTTP_TFS_YES) {
        t->block_cache_ctx.use_cache |= NGX_HTTP_TFS_REMOTE_BLOCK_CACHE;
    }
    t->block_cache_ctx.remote_ctx.data = t;
    t->block_cache_ctx.remote_ctx.tair_instance =
                                             &tmcf->remote_block_cache_instance;
    t->block_cache_ctx.curr_lookup_cache = NGX_HTTP_TFS_LOCAL_BLOCK_CACHE;

    rc = ngx_http_restful_parse(r, &t->r_ctx);
    if (rc != NGX_OK) {
        return rc;
    }

    t->header_only = r->header_only;

    if (!t->loc_conf->upstream->enable_rcs && t->r_ctx.version == 2) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "custom file requires tfs_enable_rcs on,"
                      " and make sure you have MetaServer and RootServer!");
        return NGX_HTTP_BAD_REQUEST;
    }

    switch (t->r_ctx.action.code) {
    case NGX_HTTP_TFS_ACTION_CREATE_DIR:
    case NGX_HTTP_TFS_ACTION_CREATE_FILE:
    case NGX_HTTP_TFS_ACTION_REMOVE_DIR:
    case NGX_HTTP_TFS_ACTION_REMOVE_FILE:
    case NGX_HTTP_TFS_ACTION_MOVE_DIR:
    case NGX_HTTP_TFS_ACTION_MOVE_FILE:
    case NGX_HTTP_TFS_ACTION_LS_DIR:
    case NGX_HTTP_TFS_ACTION_LS_FILE:
    case NGX_HTTP_TFS_ACTION_STAT_FILE:
    case NGX_HTTP_TFS_ACTION_KEEPALIVE:
    case NGX_HTTP_TFS_ACTION_READ_FILE:
    case NGX_HTTP_TFS_ACTION_GET_APPID:
        rc = ngx_http_discard_request_body(r);

        if (rc != NGX_OK) {
            return rc;
        }

        r->headers_out.content_length_n = -1;
        ngx_http_set_ctx(r, t, ngx_http_tfs_module);
        r->main->count++;
        ngx_http_tfs_read_body_handler(r);
        break;
    case NGX_HTTP_TFS_ACTION_WRITE_FILE:
        r->headers_out.content_length_n = -1;
        ngx_http_set_ctx(r, t, ngx_http_tfs_module);
        rc = ngx_http_read_client_request_body(r,
                                               ngx_http_tfs_read_body_handler);
        if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
            return rc;
        }
        break;
    }

    return NGX_DONE;
}