1
/* Copyright (C) agentzh */
6
#include <ngx_config.h>
8
#include "ngx_http_chunkin_util.h"
9
#include "ngx_http_chunkin_filter_module.h"
10
#include "ngx_http_chunkin_request_body.h"
13
DEFAULT_MAX_CHUNKS_PER_BUF = 512
16
static ngx_int_t ngx_http_chunkin_resume_handler(ngx_http_request_t *r);
18
static char* ngx_http_chunkin_resume(ngx_conf_t *cf, ngx_command_t *cmd,
21
static void *ngx_http_chunkin_create_conf(ngx_conf_t *cf);
22
static char *ngx_http_chunkin_merge_conf(ngx_conf_t *cf, void *parent,
25
static ngx_int_t ngx_http_chunkin_handler(ngx_http_request_t *r);
27
static ngx_int_t ngx_http_chunkin_init(ngx_conf_t *cf);
29
static void ngx_http_chunkin_post_read(ngx_http_request_t *r);
32
static ngx_command_t ngx_http_chunkin_commands[] = {
34
{ ngx_string("chunkin"),
35
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
36
ngx_conf_set_flag_slot,
37
NGX_HTTP_LOC_CONF_OFFSET,
38
offsetof(ngx_http_chunkin_conf_t, enabled),
41
{ ngx_string("chunkin_max_chunks_per_buf"),
42
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
43
ngx_conf_set_num_slot,
44
NGX_HTTP_LOC_CONF_OFFSET,
45
offsetof(ngx_http_chunkin_conf_t, max_chunks_per_buf),
48
{ ngx_string("chunkin_resume"),
49
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
50
ngx_http_chunkin_resume,
51
NGX_HTTP_LOC_CONF_OFFSET,
55
{ ngx_string("chunkin_keepalive"),
56
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
57
|NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
58
ngx_conf_set_flag_slot,
59
NGX_HTTP_LOC_CONF_OFFSET,
60
offsetof(ngx_http_chunkin_conf_t, keepalive),
67
static ngx_http_module_t ngx_http_chunkin_filter_module_ctx = {
68
NULL, /* preconfiguration */
69
ngx_http_chunkin_init, /* postconfiguration */
71
NULL, /* create main configuration */
72
NULL, /* init main configuration */
74
NULL, /* create server configuration */
75
NULL, /* merge server configuration */
77
ngx_http_chunkin_create_conf, /* create location configuration */
78
ngx_http_chunkin_merge_conf /* merge location configuration */
82
ngx_module_t ngx_http_chunkin_filter_module = {
84
&ngx_http_chunkin_filter_module_ctx, /* module context */
85
ngx_http_chunkin_commands, /* module directives */
86
NGX_HTTP_MODULE, /* module type */
87
NULL, /* init master */
88
NULL, /* init module */
89
NULL, /* init process */
90
NULL, /* init thread */
91
NULL, /* exit thread */
92
NULL, /* exit process */
93
NULL, /* exit master */
99
ngx_http_chunkin_create_conf(ngx_conf_t *cf)
101
ngx_http_chunkin_conf_t *conf;
103
conf = ngx_palloc(cf->pool, sizeof(ngx_http_chunkin_conf_t));
108
conf->enabled = NGX_CONF_UNSET;
109
conf->keepalive = NGX_CONF_UNSET;
110
conf->max_chunks_per_buf = NGX_CONF_UNSET_UINT;
117
ngx_http_chunkin_merge_conf(ngx_conf_t *cf, void *parent, void *child)
119
ngx_http_chunkin_conf_t *prev = parent;
120
ngx_http_chunkin_conf_t *conf = child;
122
ngx_conf_merge_value(conf->enabled, prev->enabled, 0);
123
ngx_conf_merge_value(conf->keepalive, prev->keepalive, 0);
124
ngx_conf_merge_uint_value(conf->max_chunks_per_buf,
125
prev->max_chunks_per_buf,
126
DEFAULT_MAX_CHUNKS_PER_BUF);
133
ngx_http_chunkin_is_chunked_encoding(ngx_http_request_t *r)
135
dd("is chunked encoding...");
137
return r->headers_in.transfer_encoding &&
138
r->headers_in.transfer_encoding->value.len >= 7 &&
139
ngx_strcasestrn(r->headers_in.transfer_encoding->value.data,
145
ngx_http_chunkin_init(ngx_conf_t *cf)
147
ngx_http_handler_pt *h;
148
ngx_http_core_main_conf_t *cmcf;
150
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
152
h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
157
*h = ngx_http_chunkin_handler;
164
ngx_http_chunkin_handler(ngx_http_request_t *r)
166
ngx_http_chunkin_ctx_t *ctx;
167
ngx_http_chunkin_conf_t *conf;
170
dd("entered chunkin handler...");
172
conf = ngx_http_get_module_loc_conf(r, ngx_http_chunkin_filter_module);
174
if (!conf->enabled || r != r->main) {
175
dd("conf not enabled: %d", (int) conf->enabled);
180
ctx = ngx_http_get_module_ctx(r, ngx_http_chunkin_filter_module);
192
if (ctx->waiting_more_body) {
196
dd("reading chunked input eagerly...");
198
/* XXX this is a hack for now */
201
&& r->headers_in.connection_type ==
202
NGX_HTTP_CONNECTION_KEEP_ALIVE) {
203
dd("re-enable r->keepalive...");
209
dd_check_read_event_handler(r);
210
dd_check_write_event_handler(r);
213
rc = ngx_http_read_client_request_body(r,
214
ngx_http_chunkin_post_read);
217
ngx_http_chunkin_clear_transfer_encoding(r);
219
r->header_in->pos = r->header_end + sizeof(CRLF) - 1;
221
if (r->header_in->pos > r->header_in->last) {
222
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
223
"chunkin: r->header_in->pos overflown");
225
return NGX_HTTP_INTERNAL_SERVER_ERROR;
228
if (*(r->header_in->pos - 2) != CR || *(r->header_in->pos - 1) != LF) {
229
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
230
"chunkin: r->header_in->pos not lead by CRLF");
232
return NGX_HTTP_INTERNAL_SERVER_ERROR;
235
dd("chunkin handler: header_in->pos: %d", (int)(r->header_in->pos - r->header_in->start));
237
rc = ngx_http_chunkin_read_chunked_request_body(r,
238
ngx_http_chunkin_post_read);
240
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
241
dd("read client request body returned special response %d", (int) rc);
245
dd("read client request body returned %d", (int) rc);
247
if (rc == NGX_AGAIN) {
248
ctx->waiting_more_body = 1;
260
ngx_http_chunkin_post_read(ngx_http_request_t *r)
262
ngx_http_chunkin_ctx_t *ctx;
266
dd_check_read_event_handler(r);
267
dd_check_write_event_handler(r);
269
r->read_event_handler = ngx_http_block_reading;
271
ctx = ngx_http_get_module_ctx(r, ngx_http_chunkin_filter_module);
275
if (ctx->waiting_more_body) {
276
ctx->waiting_more_body = 0;
277
ngx_http_core_run_phases(r);
282
static char* ngx_http_chunkin_resume(ngx_conf_t *cf, ngx_command_t *cmd,
285
ngx_http_core_loc_conf_t *clcf;
287
clcf = ngx_http_conf_get_module_loc_conf(cf,
288
ngx_http_core_module);
290
clcf->handler = ngx_http_chunkin_resume_handler;
297
ngx_http_chunkin_resume_handler(ngx_http_request_t *r) {
299
ngx_http_chunkin_conf_t *conf;
300
ngx_http_chunkin_ctx_t *ctx;
302
conf = ngx_http_get_module_loc_conf(r, ngx_http_chunkin_filter_module);
304
dd("method: %.*s (%d)", (int) r->method_name.len, r->method_name.data, (int) r->method);
306
if (!conf->enabled || r != r->main
307
|| (r->method != NGX_HTTP_PUT && r->method != NGX_HTTP_POST &&
308
r->method != NGX_HTTP_DELETE))
310
dd("conf not enabled or in subrequest or not POST nor PUT requests");
312
return NGX_HTTP_LENGTH_REQUIRED;
315
if (r->method == NGX_HTTP_POST &&
316
! ngx_http_chunkin_is_chunked_encoding(r->main))
318
dd("found POST request, but not chunked");
319
return NGX_HTTP_LENGTH_REQUIRED;
322
dd("chunked request test passed");
324
/* XXX just to fool the nginx core */
325
r->headers_in.content_length_n = 1;
327
ngx_http_chunkin_clear_transfer_encoding(r);
329
ctx = ngx_http_get_module_ctx(r, ngx_http_chunkin_filter_module);
332
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_chunkin_ctx_t));
337
/* ctx->ignore_body is set to 0 */
345
r->method = NGX_HTTP_PUT;
346
r->headers_in.content_length = NULL;
347
r->headers_in.content_length_n = -1;
350
rc = ngx_http_chunkin_process_request_header(r);
359
rc = ngx_http_chunkin_process_request(r);
364
return ngx_http_chunkin_internal_redirect(r, &r->main->uri, &r->main->args,