#ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" #include "ngx_http_echo_echo.h" #include "ngx_http_echo_util.h" #include "ngx_http_echo_filter.h" #include static ngx_buf_t ngx_http_echo_space_buf; static ngx_buf_t ngx_http_echo_newline_buf; ngx_int_t ngx_http_echo_echo_init(ngx_conf_t *cf) { static u_char space_str[] = " "; static u_char newline_str[] = "\n"; dd("global init..."); ngx_memzero(&ngx_http_echo_space_buf, sizeof(ngx_buf_t)); ngx_http_echo_space_buf.memory = 1; ngx_http_echo_space_buf.start = ngx_http_echo_space_buf.pos = space_str; ngx_http_echo_space_buf.end = ngx_http_echo_space_buf.last = space_str + sizeof(space_str) - 1; ngx_memzero(&ngx_http_echo_newline_buf, sizeof(ngx_buf_t)); ngx_http_echo_newline_buf.memory = 1; ngx_http_echo_newline_buf.start = ngx_http_echo_newline_buf.pos = newline_str; ngx_http_echo_newline_buf.end = ngx_http_echo_newline_buf.last = newline_str + sizeof(newline_str) - 1; return NGX_OK; } ngx_int_t ngx_http_echo_exec_echo_sync(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx) { ngx_buf_t *buf; ngx_chain_t *cl = NULL; /* the head of the chain link */ buf = ngx_calloc_buf(r->pool); if (buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } buf->sync = 1; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = buf; cl->next = NULL; return ngx_http_echo_send_chain_link(r, ctx, cl); } ngx_int_t ngx_http_echo_exec_echo(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args, ngx_flag_t in_filter, ngx_array_t *opts) { ngx_uint_t i; ngx_buf_t *space_buf; ngx_buf_t *newline_buf; ngx_buf_t *buf; ngx_str_t *computed_arg; ngx_str_t *computed_arg_elts; ngx_str_t *opt; ngx_chain_t *cl = NULL; /* the head of the chain link */ ngx_chain_t **ll = &cl; /* always point to the address of the last link */ dd_enter(); if (computed_args == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } computed_arg_elts = computed_args->elts; for (i = 0; i < computed_args->nelts; i++) { computed_arg = &computed_arg_elts[i]; if (computed_arg->len == 0) { buf = NULL; } else { buf = ngx_calloc_buf(r->pool); if (buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } buf->start = buf->pos = computed_arg->data; buf->last = buf->end = computed_arg->data + computed_arg->len; buf->memory = 1; } if (cl == NULL) { cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = buf; cl->next = NULL; ll = &cl->next; } else { /* append a space first */ *ll = ngx_alloc_chain_link(r->pool); if (*ll == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } space_buf = ngx_calloc_buf(r->pool); if (space_buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* nginx clears buf flags at the end of each request handling, * so we have to make a clone here. */ *space_buf = ngx_http_echo_space_buf; (*ll)->buf = space_buf; (*ll)->next = NULL; ll = &(*ll)->next; /* then append the buf only if it's non-empty */ if (buf) { *ll = ngx_alloc_chain_link(r->pool); if (*ll == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } (*ll)->buf = buf; (*ll)->next = NULL; ll = &(*ll)->next; } } } /* end for */ if (cl && cl->buf == NULL) { cl = cl->next; } if (opts && opts->nelts > 0) { opt = opts->elts; /* FIXME handle other unrecognized options here */ if (opt[0].len == 1 && opt[0].data[0] == 'n') { goto done; } } /* append the newline character */ newline_buf = ngx_calloc_buf(r->pool); if (newline_buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } *newline_buf = ngx_http_echo_newline_buf; if (cl == NULL) { cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = newline_buf; cl->next = NULL; /* ll = &cl->next; */ } else { *ll = ngx_alloc_chain_link(r->pool); if (*ll == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } (*ll)->buf = newline_buf; (*ll)->next = NULL; /* ll = &(*ll)->next; */ } done: if (cl == NULL || cl->buf == NULL) { return NGX_OK; } if (in_filter) { return ngx_http_echo_next_body_filter(r, cl); } return ngx_http_echo_send_chain_link(r, ctx, cl); } ngx_int_t ngx_http_echo_exec_echo_flush(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx) { return ngx_http_send_special(r, NGX_HTTP_FLUSH); } ngx_int_t ngx_http_echo_exec_echo_request_body(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx) { ngx_buf_t *b; ngx_chain_t *out, *cl, **ll; if (r->request_body == NULL || r->request_body->bufs == NULL) { return NGX_OK; } out = NULL; ll = &out; for (cl = r->request_body->bufs; cl; cl = cl->next) { if (ngx_buf_special(cl->buf)) { /* we do not want to create zero-size bufs */ continue; } *ll = ngx_alloc_chain_link(r->pool); if (*ll == NULL) { return NGX_ERROR; } b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } (*ll)->buf = b; (*ll)->next = NULL; ngx_memcpy(b, cl->buf, sizeof(ngx_buf_t)); b->tag = (ngx_buf_tag_t) &ngx_http_echo_exec_echo_request_body; b->last_buf = 0; b->last_in_chain = 0; ll = &(*ll)->next; } if (out == NULL) { return NGX_OK; } return ngx_http_echo_send_chain_link(r, ctx, out); } ngx_int_t ngx_http_echo_exec_echo_duplicate(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_str_t *computed_arg; ngx_str_t *computed_arg_elts; ssize_t i, count; ngx_str_t *str; u_char *p; ngx_int_t rc; ngx_buf_t *buf; ngx_chain_t *cl; dd_enter(); computed_arg_elts = computed_args->elts; computed_arg = &computed_arg_elts[0]; count = ngx_http_echo_atosz(computed_arg->data, computed_arg->len); if (count == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid size specified: \"%V\"", computed_arg); return NGX_HTTP_INTERNAL_SERVER_ERROR; } str = &computed_arg_elts[1]; if (count == 0 || str->len == 0) { rc = ngx_http_echo_send_header_if_needed(r, ctx); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } return NGX_OK; } buf = ngx_create_temp_buf(r->pool, count * str->len); if (buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } p = buf->pos; for (i = 0; i < count; i++) { p = ngx_copy(p, str->data, str->len); } buf->last = p; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->next = NULL; cl->buf = buf; return ngx_http_echo_send_chain_link(r, ctx, cl); }