diff options
author | kaiwu <kaiwu2004@gmail.com> | 2025-03-01 12:42:23 +0800 |
---|---|---|
committer | kaiwu <kaiwu2004@gmail.com> | 2025-03-01 12:42:23 +0800 |
commit | 3f33461e4948bf05e60bdff35ec6c57a649c7860 (patch) | |
tree | 284c2ba95a41536ae1bff6bea710db0709a64739 /form-input-nginx-module-0.12/src | |
download | openresty-3f33461e4948bf05e60bdff35ec6c57a649c7860.tar.gz openresty-3f33461e4948bf05e60bdff35ec6c57a649c7860.zip |
openresty bundle
Diffstat (limited to 'form-input-nginx-module-0.12/src')
-rwxr-xr-x | form-input-nginx-module-0.12/src/ddebug.h | 118 | ||||
-rw-r--r-- | form-input-nginx-module-0.12/src/ngx_http_form_input_module.c | 523 |
2 files changed, 641 insertions, 0 deletions
diff --git a/form-input-nginx-module-0.12/src/ddebug.h b/form-input-nginx-module-0.12/src/ddebug.h new file mode 100755 index 0000000..3b14190 --- /dev/null +++ b/form-input-nginx-module-0.12/src/ddebug.h @@ -0,0 +1,118 @@ +#ifndef DDEBUG_H +#define DDEBUG_H + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> +#include <nginx.h> + +#if defined(DDEBUG) && (DDEBUG) + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) fprintf(stderr, "form-input *** %s: ", __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__) + +# else + +#include <stdarg.h> +#include <stdio.h> + +#include <stdarg.h> + +static void dd(const char * fmt, ...) { +} + +# endif + +# if DDEBUG > 1 + +# define dd_enter() dd_enter_helper(r, __func__) + + +# if defined(nginx_version) && nginx_version >= 8011 +# define dd_main_req_count r->main->count +# else +# define dd_main_req_count 0 +# endif + +static void dd_enter_helper(ngx_http_request_t *r, const char *func) { + ngx_http_posted_request_t *pr; + + fprintf(stderr, ">enter %s %.*s %.*s?%.*s c:%d m:%p r:%p ar:%p pr:%p", + func, + (int) r->method_name.len, r->method_name.data, + (int) r->uri.len, r->uri.data, + (int) r->args.len, r->args.data, + (int) dd_main_req_count, r->main, + r, r->connection->data, r->parent); + + if (r->posted_requests) { + fprintf(stderr, " posted:"); + + for (pr = r->posted_requests; pr; pr = pr->next) { + fprintf(stderr, "%p,", pr); + } + } + + fprintf(stderr, "\n"); +} + +# else + +# define dd_enter() + +# endif + +#else + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) + +# define dd_enter() + +# else + +#include <stdarg.h> + +static void dd(const char * fmt, ...) { +} + +static void dd_enter() { +} + +# endif + +#endif + +#if defined(DDEBUG) && (DDEBUG) + +#define dd_check_read_event_handler(r) \ + dd("r->read_event_handler = %s", \ + r->read_event_handler == ngx_http_block_reading ? \ + "ngx_http_block_reading" : \ + r->read_event_handler == ngx_http_test_reading ? \ + "ngx_http_test_reading" : \ + r->read_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#define dd_check_write_event_handler(r) \ + dd("r->write_event_handler = %s", \ + r->write_event_handler == ngx_http_handler ? \ + "ngx_http_handler" : \ + r->write_event_handler == ngx_http_core_run_phases ? \ + "ngx_http_core_run_phases" : \ + r->write_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#else + +#define dd_check_read_event_handler(r) +#define dd_check_write_event_handler(r) + +#endif + +#endif /* DDEBUG_H */ + diff --git a/form-input-nginx-module-0.12/src/ngx_http_form_input_module.c b/form-input-nginx-module-0.12/src/ngx_http_form_input_module.c new file mode 100644 index 0000000..9aff693 --- /dev/null +++ b/form-input-nginx-module-0.12/src/ngx_http_form_input_module.c @@ -0,0 +1,523 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include <ndk.h> +#include <nginx.h> +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> + + +#define form_urlencoded_type "application/x-www-form-urlencoded" +#define form_urlencoded_type_len (sizeof(form_urlencoded_type) - 1) + + +typedef struct { + unsigned used; /* :1 */ +} ngx_http_form_input_main_conf_t; + + +typedef struct { + unsigned done:1; + unsigned waiting_more_body:1; +} ngx_http_form_input_ctx_t; + + +static ngx_int_t ngx_http_set_form_input(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v); +static char *ngx_http_set_form_input_conf_handler(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static void *ngx_http_form_input_create_main_conf(ngx_conf_t *cf); +static ngx_int_t ngx_http_form_input_init(ngx_conf_t *cf); +static ngx_int_t ngx_http_form_input_handler(ngx_http_request_t *r); +static void ngx_http_form_input_post_read(ngx_http_request_t *r); +static ngx_int_t ngx_http_form_input_arg(ngx_http_request_t *r, u_char *name, + size_t len, ngx_str_t *value, ngx_flag_t multi); + + +static ngx_command_t ngx_http_form_input_commands[] = { + + { ngx_string("set_form_input"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_set_form_input_conf_handler, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("set_form_input_multi"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_set_form_input_conf_handler, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_form_input_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_form_input_init, /* postconfiguration */ + + ngx_http_form_input_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_form_input_module = { + NGX_MODULE_V1, + &ngx_http_form_input_module_ctx, /* module context */ + ngx_http_form_input_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit precess */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_set_form_input(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + ngx_http_form_input_ctx_t *ctx; + ngx_int_t rc; + + dd_enter(); + + dd("set default return value"); + ngx_str_set(res, ""); + + if (r->done) { + dd("request done"); + return NGX_OK; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_form_input_module); + + if (ctx == NULL) { + dd("ndk handler:null ctx"); + return NGX_OK; + } + + if (!ctx->done) { + dd("ctx not done"); + return NGX_OK; + } + + rc = ngx_http_form_input_arg(r, v->data, v->len, res, 0); + + return rc; +} + + +static ngx_int_t +ngx_http_set_form_input_multi(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v) +{ + ngx_http_form_input_ctx_t *ctx; + ngx_int_t rc; + + dd_enter(); + + dd("set default return value"); + ngx_str_set(res, ""); + + /* dd("set default return value"); */ + + if (r->done) { + return NGX_OK; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_form_input_module); + + if (ctx == NULL) { + dd("ndk handler:null ctx"); + return NGX_OK; + } + + if (!ctx->done) { + dd("ctx not done"); + return NGX_OK; + } + + rc = ngx_http_form_input_arg(r, v->data, v->len, res, 1); + + return rc; +} + + +/* fork from ngx_http_arg. + * read argument(s) with name arg_name and length arg_len into value variable, + * if multi flag is set, multi arguments with name arg_name will be read and + * stored in an ngx_array_t struct, this can be operated by directives in + * array-var-nginx-module */ +static ngx_int_t +ngx_http_form_input_arg(ngx_http_request_t *r, u_char *arg_name, size_t arg_len, + ngx_str_t *value, ngx_flag_t multi) +{ + u_char *p, *v, *last, *buf; + ngx_chain_t *cl; + size_t len = 0; + ngx_array_t *array = NULL; + ngx_str_t *s; + ngx_buf_t *b; + + if (multi) { + array = ngx_array_create(r->pool, 1, sizeof(ngx_str_t)); + if (array == NULL) { + return NGX_ERROR; + } + value->data = (u_char *)array; + value->len = sizeof(ngx_array_t); + + } else { + ngx_str_set(value, ""); + } + + /* we read data from r->request_body->bufs */ + if (r->request_body == NULL || r->request_body->bufs == NULL) { + dd("empty rb or empty rb bufs"); + return NGX_OK; + } + + if (r->request_body->bufs->next != NULL) { + /* more than one buffer...we should copy the data out... */ + len = 0; + for (cl = r->request_body->bufs; cl; cl = cl->next) { + b = cl->buf; + + if (b->in_file) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "form-input: in-file buffer found. aborted. " + "consider increasing your " + "client_body_buffer_size setting"); + + return NGX_OK; + } + + len += b->last - b->pos; + } + + dd("len=%d", (int) len); + + if (len == 0) { + return NGX_OK; + } + + buf = ngx_palloc(r->pool, len); + if (buf == NULL) { + return NGX_ERROR; + } + + p = buf; + last = p + len; + + for (cl = r->request_body->bufs; cl; cl = cl->next) { + p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos); + } + + dd("p - buf = %d, last - buf = %d", (int) (p - buf), + (int) (last - buf)); + + dd("copied buf (len %d): %.*s", (int) len, (int) len, + buf); + + } else { + dd("XXX one buffer only"); + + b = r->request_body->bufs->buf; + if (ngx_buf_size(b) == 0) { + return NGX_OK; + } + + buf = b->pos; + last = b->last; + } + + for (p = buf; p < last; p++) { + /* we need '=' after name, so drop one char from last */ + + p = ngx_strlcasestrn(p, last - 1, arg_name, arg_len - 1); + if (p == NULL) { + return NGX_OK; + } + + dd("found argument name, offset: %d", (int) (p - buf)); + + if ((p == buf || *(p - 1) == '&') && *(p + arg_len) == '=') { + v = p + arg_len + 1; + dd("v = %d...", (int) (v - buf)); + + dd("buf now (len %d): %.*s", + (int) (last - v), (int) (last - v), v); + + p = ngx_strlchr(v, last, '&'); + if (p == NULL) { + dd("& not found, pointing it to last..."); + p = last; + + } else { + dd("found &, pointing it to %d...", (int) (p - buf)); + } + + if (multi) { + s = ngx_array_push(array); + if (s == NULL) { + return NGX_ERROR; + } + s->data = v; + s->len = p - v; + dd("array var:%.*s", (int) s->len, s->data); + + } else { + value->data = v; + value->len = p - v; + dd("value: [%.*s]", (int) value->len, value->data); + return NGX_OK; + } + } + } + +#if 0 + if (multi) { + value->data = (u_char *) array; + value->len = sizeof(ngx_array_t); + } +#endif + + return NGX_OK; +} + + +static char * +ngx_http_set_form_input_conf_handler(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ndk_set_var_t filter; + ngx_str_t *value, s; + u_char *p; + ngx_http_form_input_main_conf_t *fmcf; + +#if defined(nginx_version) && nginx_version >= 8042 && nginx_version <= 8053 + return "does not work with " NGINX_VER; +#endif + + fmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_form_input_module); + + fmcf->used = 1; + + filter.type = NDK_SET_VAR_MULTI_VALUE; + filter.size = 1; + + value = cf->args->elts; + + if ((value->len == sizeof("set_form_input_multi") - 1) && + ngx_strncmp(value->data, "set_form_input_multi", value->len) == 0) + { + dd("use ngx_http_form_input_multi"); + filter.func = (void *) ngx_http_set_form_input_multi; + + } else { + filter.func = (void *) ngx_http_set_form_input; + } + + value++; + + if (cf->args->nelts == 2) { + p = value->data; + p++; + s.len = value->len - 1; + s.data = p; + + } else if (cf->args->nelts == 3) { + s.len = (value + 1)->len; + s.data = (value + 1)->data; + } + + return ndk_set_var_multi_value_core (cf, value, &s, &filter); +} + + +/* register a new rewrite phase handler */ +static ngx_int_t +ngx_http_form_input_init(ngx_conf_t *cf) +{ + + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + ngx_http_form_input_main_conf_t *fmcf; + + fmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_form_input_module); + + if (!fmcf->used) { + return NGX_OK; + } + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); + + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_form_input_handler; + + return NGX_OK; +} + + +/* an rewrite phase handler */ +static ngx_int_t +ngx_http_form_input_handler(ngx_http_request_t *r) +{ + ngx_http_form_input_ctx_t *ctx; + ngx_str_t value; + ngx_int_t rc; + + dd_enter(); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http form_input rewrite phase handler"); + + ctx = ngx_http_get_module_ctx(r, ngx_http_form_input_module); + + if (ctx != NULL) { + if (ctx->done) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http form_input rewrite phase handler done"); + + return NGX_DECLINED; + } + + return NGX_DONE; + } + + if (r->method != NGX_HTTP_POST && r->method != NGX_HTTP_PUT) { + return NGX_DECLINED; + } + + if (r->headers_in.content_type == NULL + || r->headers_in.content_type->value.data == NULL) + { + dd("content_type is %p", r->headers_in.content_type); + + return NGX_DECLINED; + } + + value = r->headers_in.content_type->value; + + dd("r->headers_in.content_length_n:%d", + (int) r->headers_in.content_length_n); + + /* just focus on x-www-form-urlencoded */ + + if (value.len < form_urlencoded_type_len + || ngx_strncasecmp(value.data, (u_char *) form_urlencoded_type, + form_urlencoded_type_len) != 0) + { + dd("not application/x-www-form-urlencoded"); + return NGX_DECLINED; + } + + dd("content type is application/x-www-form-urlencoded"); + + dd("create new ctx"); + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_form_input_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + /* set by ngx_pcalloc: + * ctx->done = 0; + * ctx->waiting_more_body = 0; + */ + + ngx_http_set_ctx(r, ctx, ngx_http_form_input_module); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http form_input start to read client request body"); + + rc = ngx_http_read_client_request_body(r, ngx_http_form_input_post_read); + + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { +#if (nginx_version < 1002006) || \ + (nginx_version >= 1003000 && nginx_version < 1003009) + r->main->count--; +#endif + + return rc; + } + + if (rc == NGX_AGAIN) { + ctx->waiting_more_body = 1; + + return NGX_DONE; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http form_input has read the request body in one run"); + + return NGX_DECLINED; +} + + +static void +ngx_http_form_input_post_read(ngx_http_request_t *r) +{ + ngx_http_form_input_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http form_input post read request body"); + + ctx = ngx_http_get_module_ctx(r, ngx_http_form_input_module); + + ctx->done = 1; + +#if defined(nginx_version) && nginx_version >= 8011 + dd("count--"); + r->main->count--; +#endif + + dd("waiting more body: %d", (int) ctx->waiting_more_body); + + /* waiting_more_body my rewrite phase handler */ + if (ctx->waiting_more_body) { + ctx->waiting_more_body = 0; + + ngx_http_core_run_phases(r); + } +} + + +static void * +ngx_http_form_input_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_form_input_main_conf_t *fmcf; + + fmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_form_input_main_conf_t)); + if (fmcf == NULL) { + return NULL; + } + + /* set by ngx_pcalloc: + * fmcf->used = 0; + */ + + return fmcf; +} |