blob: 88591986e1aa1859253c39bd624da90196ba2929 [file] [log] [blame] [raw]
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_echo_util.h"
#include "ngx_http_echo_sleep.h"
ngx_uint_t ngx_http_echo_content_length_hash = 0;
ngx_http_echo_ctx_t *
ngx_http_echo_create_ctx(ngx_http_request_t *r)
{
ngx_http_echo_ctx_t *ctx;
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_echo_ctx_t));
if (ctx == NULL) {
return NULL;
}
ctx->sleep.handler = ngx_http_echo_sleep_event_handler;
ctx->sleep.data = r;
ctx->sleep.log = r->connection->log;
return ctx;
}
ngx_int_t
ngx_http_echo_eval_cmd_args(ngx_http_request_t *r,
ngx_http_echo_cmd_t *cmd, ngx_array_t *computed_args,
ngx_array_t *opts)
{
ngx_uint_t i;
ngx_array_t *args = cmd->args;
ngx_str_t *arg, *raw, *opt;
ngx_http_echo_arg_template_t *value;
ngx_flag_t expecting_opts = 1;
value = args->elts;
for (i = 0; i < args->nelts; i++) {
raw = &value[i].raw_value;
if (value[i].lengths == NULL && raw->len > 0) {
if (expecting_opts) {
if (raw->len == 1 || raw->data[0] != '-') {
expecting_opts = 0;
} else if (raw->data[1] == '-') {
expecting_opts = 0;
continue;
} else {
opt = ngx_array_push(opts);
if (opt == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
opt->len = raw->len - 1;
opt->data = raw->data + 1;
continue;
}
}
}
arg = ngx_array_push(computed_args);
if (arg == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (value[i].lengths == NULL) { /* does not contain vars */
dd("Using raw value \"%.*s\"", (int) raw->len, raw->data);
*arg = *raw;
} else {
if (ngx_http_script_run(r, arg, value[i].lengths->elts,
0, value[i].values->elts) == NULL)
{
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
}
}
return NGX_OK;
}
ngx_int_t
ngx_http_echo_send_chain_link(ngx_http_request_t* r,
ngx_http_echo_ctx_t *ctx, ngx_chain_t *in)
{
ngx_int_t rc;
rc = ngx_http_echo_send_header_if_needed(r, ctx);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
if (in == NULL) {
#if defined(nginx_version) && nginx_version <= 8004
/* earlier versions of nginx does not allow subrequests
to send last_buf themselves */
if (r != r->main) {
return NGX_OK;
}
#endif
rc = ngx_http_send_special(r, NGX_HTTP_LAST);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
return rc;
}
return NGX_OK;
}
return ngx_http_output_filter(r, in);
}
ngx_int_t
ngx_http_echo_send_header_if_needed(ngx_http_request_t* r,
ngx_http_echo_ctx_t *ctx)
{
ngx_http_echo_loc_conf_t *elcf;
if (!r->header_sent) {
elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
r->headers_out.status = (ngx_uint_t) elcf->status;
if (ngx_http_set_content_type(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
return ngx_http_send_header(r);
}
return NGX_OK;
}
ssize_t
ngx_http_echo_atosz(u_char *line, size_t n)
{
ssize_t value;
if (n == 0) {
return NGX_ERROR;
}
for (value = 0; n--; line++) {
if (*line == '_') { /* we ignore undercores */
continue;
}
if (*line < '0' || *line > '9') {
return NGX_ERROR;
}
value = value * 10 + (*line - '0');
}
if (value < 0) {
return NGX_ERROR;
}
return value;
}
/* Modified from the ngx_strlcasestrn function in ngx_string.h
* Copyright (C) by Igor Sysoev */
u_char *
ngx_http_echo_strlstrn(u_char *s1, u_char *last, u_char *s2, size_t n)
{
ngx_uint_t c1, c2;
c2 = (ngx_uint_t) *s2++;
last -= n;
do {
do {
if (s1 >= last) {
return NULL;
}
c1 = (ngx_uint_t) *s1++;
} while (c1 != c2);
} while (ngx_strncmp(s1, s2, n) != 0);
return --s1;
}
ngx_int_t
ngx_http_echo_post_request_at_head(ngx_http_request_t *r,
ngx_http_posted_request_t *pr)
{
dd_enter();
if (pr == NULL) {
pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t));
if (pr == NULL) {
return NGX_ERROR;
}
}
pr->request = r;
pr->next = r->main->posted_requests;
r->main->posted_requests = pr;
return NGX_OK;
}
u_char *
ngx_http_echo_rebase_path(ngx_pool_t *pool, u_char *src, size_t osize,
size_t *nsize)
{
u_char *p, *dst;
if (osize == 0) {
return NULL;
}
if (src[0] == '/') {
/* being an absolute path already, just add a trailing '\0' */
*nsize = osize;
dst = ngx_palloc(pool, *nsize + 1);
if (dst == NULL) {
*nsize = 0;
return NULL;
}
p = ngx_copy(dst, src, osize);
*p = '\0';
return dst;
}
*nsize = ngx_cycle->prefix.len + osize;
dst = ngx_palloc(pool, *nsize + 1);
if (dst == NULL) {
*nsize = 0;
return NULL;
}
p = ngx_copy(dst, ngx_cycle->prefix.data, ngx_cycle->prefix.len);
p = ngx_copy(p, src, osize);
*p = '\0';
return dst;
}
ngx_int_t
ngx_http_echo_flush_postponed_outputs(ngx_http_request_t *r)
{
if (r == r->connection->data && r->postponed) {
/* notify the downstream postpone filter to flush the postponed
* outputs of the current request */
return ngx_http_output_filter(r, NULL);
}
/* do nothing */
return NGX_OK;
}