/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_echo_util.h"
#include "ngx_http_echo_subrequest.h"
#include "ngx_http_echo_handler.h"
#include <nginx.h>
#define ngx_http_echo_method_name(m) { sizeof(m) - 1, (u_char *) m " " }
ngx_str_t ngx_http_echo_content_length_header_key =
ngx_string("Content-Length");
ngx_str_t ngx_http_echo_get_method = ngx_http_echo_method_name("GET");
ngx_str_t ngx_http_echo_put_method = ngx_http_echo_method_name("PUT");
ngx_str_t ngx_http_echo_post_method = ngx_http_echo_method_name("POST");
ngx_str_t ngx_http_echo_head_method = ngx_http_echo_method_name("HEAD");
ngx_str_t ngx_http_echo_copy_method = ngx_http_echo_method_name("COPY");
ngx_str_t ngx_http_echo_move_method = ngx_http_echo_method_name("MOVE");
ngx_str_t ngx_http_echo_lock_method = ngx_http_echo_method_name("LOCK");
ngx_str_t ngx_http_echo_mkcol_method = ngx_http_echo_method_name("MKCOL");
ngx_str_t ngx_http_echo_trace_method = ngx_http_echo_method_name("TRACE");
ngx_str_t ngx_http_echo_delete_method = ngx_http_echo_method_name("DELETE");
ngx_str_t ngx_http_echo_unlock_method = ngx_http_echo_method_name("UNLOCK");
ngx_str_t ngx_http_echo_options_method = ngx_http_echo_method_name("OPTIONS");
ngx_str_t ngx_http_echo_propfind_method =
ngx_http_echo_method_name("PROPFIND");
ngx_str_t ngx_http_echo_proppatch_method =
ngx_http_echo_method_name("PROPPATCH");
typedef struct ngx_http_echo_subrequest_s {
ngx_uint_t method;
ngx_str_t *method_name;
ngx_str_t *location;
ngx_str_t *query_string;
ssize_t content_length_n;
ngx_http_request_body_t *request_body;
} ngx_http_echo_subrequest_t;
static ngx_int_t ngx_http_echo_parse_method_name(ngx_str_t **method_name_ptr);
static ngx_int_t ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr,
ngx_http_echo_subrequest_t *parsed_sr);
static ngx_int_t ngx_http_echo_parse_subrequest_spec(ngx_http_request_t *r,
ngx_array_t *computed_args, ngx_http_echo_subrequest_t **parsed_sr_ptr);
static ngx_int_t ngx_http_echo_set_content_length_header(ngx_http_request_t *r,
off_t len);
ngx_int_t
ngx_http_echo_exec_echo_subrequest_async(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args)
{
ngx_int_t rc;
ngx_http_echo_subrequest_t *parsed_sr;
ngx_http_request_t *sr; /* subrequest object */
ngx_str_t args;
ngx_uint_t flags = 0;
dd_enter();
rc = ngx_http_echo_parse_subrequest_spec(r, computed_args, &parsed_sr);
if (rc != NGX_OK) {
return rc;
}
dd("location: %.*s",
(int) parsed_sr->location->len,
parsed_sr->location->data);
args.data = NULL;
args.len = 0;
if (ngx_http_parse_unsafe_uri(r, parsed_sr->location, &args, &flags)
!= NGX_OK)
{
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"echo_subrequest_async sees unsafe uri: \"%V\"",
parsed_sr->location);
return NGX_ERROR;
}
if (args.len > 0 && parsed_sr->query_string == NULL) {
parsed_sr->query_string = &args;
}
rc = ngx_http_echo_send_header_if_needed(r, ctx);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
rc = ngx_http_subrequest(r, parsed_sr->location, parsed_sr->query_string,
&sr, NULL, 0);
if (rc != NGX_OK) {
return NGX_ERROR;
}
rc = ngx_http_echo_adjust_subrequest(sr, parsed_sr);
if (rc != NGX_OK) {
return rc;
}
return NGX_OK;
}
ngx_int_t
ngx_http_echo_exec_echo_subrequest(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args)
{
ngx_int_t rc;
ngx_http_request_t *sr; /* subrequest object */
ngx_http_post_subrequest_t *psr;
ngx_http_echo_subrequest_t *parsed_sr;
ngx_str_t args;
ngx_uint_t flags = 0;
ngx_http_echo_ctx_t *sr_ctx;
dd_enter();
rc = ngx_http_echo_parse_subrequest_spec(r, computed_args, &parsed_sr);
if (rc != NGX_OK) {
return rc;
}
args.data = NULL;
args.len = 0;
if (ngx_http_parse_unsafe_uri(r, parsed_sr->location, &args, &flags)
!= NGX_OK)
{
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"echo_subrequest sees unsafe uri: \"%V\"",
parsed_sr->location);
return NGX_ERROR;
}
if (args.len > 0 && parsed_sr->query_string == NULL) {
parsed_sr->query_string = &args;
}
rc = ngx_http_echo_send_header_if_needed(r, ctx);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
sr_ctx = ngx_http_echo_create_ctx(r);
/* set by ngx_http_echo_create_ctx
* sr_ctx->run_post_subrequest = 0
*/
dd("creating sr ctx for %.*s: %p", (int) parsed_sr->location->len,
parsed_sr->location->data, sr_ctx);
psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
if (psr == NULL) {
return NGX_ERROR;
}
psr->handler = ngx_http_echo_post_subrequest;
psr->data = sr_ctx;
rc = ngx_http_subrequest(r, parsed_sr->location, parsed_sr->query_string,
&sr, psr, 0);
if (rc != NGX_OK) {
return NGX_ERROR;
}
sr_ctx->sleep.data = sr;
ngx_http_set_ctx(sr, sr_ctx, ngx_http_echo_module);
rc = ngx_http_echo_adjust_subrequest(sr, parsed_sr);
if (rc != NGX_OK) {
return NGX_ERROR;
}
return NGX_AGAIN;
}
static ngx_int_t
ngx_http_echo_parse_subrequest_spec(ngx_http_request_t *r,
ngx_array_t *computed_args, ngx_http_echo_subrequest_t **parsed_sr_ptr)
{
ngx_str_t *computed_arg_elts, *arg;
ngx_str_t **to_write = NULL;
ngx_str_t *method_name;
ngx_str_t *body_str = NULL;
ngx_str_t *body_file = NULL;
ngx_uint_t i;
ngx_flag_t expecting_opt;
ngx_http_request_body_t *rb = NULL;
ngx_buf_t *b;
ngx_http_echo_subrequest_t *parsed_sr;
ngx_open_file_info_t of;
ngx_http_core_loc_conf_t *clcf;
size_t len;
*parsed_sr_ptr = ngx_pcalloc(r->pool, sizeof(ngx_http_echo_subrequest_t));
if (*parsed_sr_ptr == NULL) {
return NGX_ERROR;
}
parsed_sr = *parsed_sr_ptr;
computed_arg_elts = computed_args->elts;
method_name = &computed_arg_elts[0];
parsed_sr->location = &computed_arg_elts[1];
if (parsed_sr->location->len == 0) {
return NGX_ERROR;
}
expecting_opt = 1;
for (i = 2; i < computed_args->nelts; i++) {
arg = &computed_arg_elts[i];
if (!expecting_opt) {
if (to_write == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"echo_subrequest_async: to_write should NOT be NULL");
return NGX_ERROR;
}
*to_write = arg;
to_write = NULL;
expecting_opt = 1;
continue;
}
if (arg->len == 2) {
if (ngx_strncmp("-q", arg->data, arg->len) == 0) {
to_write = &parsed_sr->query_string;
expecting_opt = 0;
continue;
}
if (ngx_strncmp("-b", arg->data, arg->len) == 0) {
to_write = &body_str;
expecting_opt = 0;
continue;
}
if (ngx_strncmp("-f", arg->data, arg->len) == 0) {
dd(