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 (r->header_only || rc >= NGX_HTTP_SPECIAL_RESPONSE) { 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); }
ngx_int_t ngx_http_echo_exec_echo_request_body(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx) { if (r->request_body && r->request_body->bufs) { return ngx_http_echo_send_chain_link(r, ctx, r->request_body->bufs); } return NGX_OK; }
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_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_run_cmds(ngx_http_request_t *r) { ngx_http_echo_loc_conf_t *elcf; ngx_http_echo_ctx_t *ctx; ngx_int_t rc; ngx_array_t *cmds; ngx_array_t *computed_args = NULL; ngx_http_echo_cmd_t *cmd; ngx_http_echo_cmd_t *cmd_elts; ngx_array_t *opts = NULL; elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); cmds = elcf->handler_cmds; if (cmds == NULL) { return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); if (ctx == NULL) { ctx = ngx_http_echo_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_echo_module); } dd("exec handler: %.*s: %i", (int) r->uri.len, r->uri.data, (int) ctx->next_handler_cmd); cmd_elts = cmds->elts; for (; ctx->next_handler_cmd < cmds->nelts; ctx->next_handler_cmd++) { cmd = &cmd_elts[ctx->next_handler_cmd]; /* evaluate arguments for the current cmd (if any) */ if (cmd->args) { computed_args = ngx_array_create(r->pool, cmd->args->nelts, sizeof(ngx_str_t)); if (computed_args == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } opts = ngx_array_create(r->pool, 1, sizeof(ngx_str_t)); if (opts == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_echo_eval_cmd_args(r, cmd, computed_args, opts); if (rc != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to evaluate arguments for " "the directive."); return rc; } } /* do command dispatch based on the opcode */ switch (cmd->opcode) { case echo_opcode_echo: /* XXX moved the following code to a separate * function */ dd("found echo opcode"); rc = ngx_http_echo_exec_echo(r, ctx, computed_args, 0 /* in filter */, opts); break; case echo_opcode_echo_request_body: rc = ngx_http_echo_exec_echo_request_body(r, ctx); break; case echo_opcode_echo_location_async: dd("found opcode echo location async..."); rc = ngx_http_echo_exec_echo_location_async(r, ctx, computed_args); break; case echo_opcode_echo_location: return ngx_http_echo_exec_echo_location(r, ctx, computed_args); break; case echo_opcode_echo_subrequest_async: dd("found opcode echo subrequest async..."); rc = ngx_http_echo_exec_echo_subrequest_async(r, ctx, computed_args); break; case echo_opcode_echo_subrequest: return ngx_http_echo_exec_echo_subrequest(r, ctx, computed_args); break; case echo_opcode_echo_sleep: return ngx_http_echo_exec_echo_sleep(r, ctx, computed_args); break; case echo_opcode_echo_flush: rc = ngx_http_echo_exec_echo_flush(r, ctx); break; case echo_opcode_echo_blocking_sleep: rc = ngx_http_echo_exec_echo_blocking_sleep(r, ctx, computed_args); break; case echo_opcode_echo_reset_timer: rc = ngx_http_echo_exec_echo_reset_timer(r, ctx); break; case echo_opcode_echo_duplicate: rc = ngx_http_echo_exec_echo_duplicate(r, ctx, computed_args); break; case echo_opcode_echo_read_request_body: ctx->wait_read_request_body = 0; rc = ngx_http_echo_exec_echo_read_request_body(r, ctx); #if defined(nginx_version) && nginx_version >= 8011 /* XXX read_client_request_body always increments the counter */ r->main->count--; #endif dd("read request body: %d", (int) rc); if (rc == NGX_OK) { continue; } ctx->wait_read_request_body = 1; /* r->write_event_handler = ngx_http_request_empty_handler; */ return rc; break; case echo_opcode_echo_foreach_split: rc = ngx_http_echo_exec_echo_foreach_split(r, ctx, computed_args); break; case echo_opcode_echo_end: rc = ngx_http_echo_exec_echo_end(r, ctx); break; case echo_opcode_echo_exec: dd("echo_exec"); return ngx_http_echo_exec_exec(r, ctx, computed_args); break; default: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Unknown opcode: %d", cmd->opcode); return NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } } rc = ngx_http_echo_send_chain_link(r, ctx, NULL /* indicate LAST */); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } return NGX_OK; }
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); }
/* XXX extermely evil and not working yet */ ngx_int_t ngx_http_echo_exec_abort_parent(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx) { #if 0 ngx_http_postponed_request_t *pr, *ppr; ngx_http_request_t *saved_data = NULL; ngx_chain_t *out = NULL; /* ngx_int_t rc; */ dd("aborting parent..."); if (r == r->main || r->parent == NULL) { return NGX_OK; } if (r->parent->postponed) { dd("Found parent->postponed..."); saved_data = r->connection->data; ppr = NULL; for (pr = r->parent->postponed; pr->next; pr = pr->next) { if (pr->request == NULL) { continue; } if (pr->request == r) { /* r->parent->postponed->next = pr; */ dd("found the current subrequest"); out = pr->out; continue; } /* r->connection->data = pr->request; */ dd("finalizing the subrequest..."); ngx_http_upstream_create(pr->request); pr->request->upstream = NULL; if (ppr == NULL) { r->parent->postponed = pr->next; ppr = pr->next; } else { ppr->next = pr->next; ppr = pr->next; } } } r->parent->postponed->next = NULL; /* r->connection->data = r->parent; r->connection->buffered = 0; if (out != NULL) { dd("trying to send more stuffs for the parent"); ngx_http_output_filter(r->parent, out); } */ /* ngx_http_send_special(r->parent, NGX_HTTP_LAST); */ if (saved_data) { r->connection->data = saved_data; } dd("terminating the parent request"); return ngx_http_echo_send_chain_link(r, ctx, NULL /* indicate LAST */); /* ngx_http_upstream_create(r); */ /* ngx_http_finalize_request(r->parent, NGX_ERROR); */ #endif return NGX_OK; }