Mercurial > hg > ngx_http_delay_body_filter_module
annotate ngx_http_delay_body_filter_module.c @ 1:7c2d64d9c656
Working delay body and tests.
Depends on rb->filter_need_buffering and rb->buffered, as well as
corresponding changes in the request body reading code to work.
Might not be the best solution, as current body reading code relies
on rb->buffered to be properly set at various stages. Notably,
rb->buffered must be cleared when calling the next filter, since
the save body filter relies on it. Possible future improvements:
implement last buffer checking in the save body filter instead of
checking for (rb->rest == 0 && !rb->buffered).
The code uses its own event to implement delay timer. To remove the timer
in case of abnormal request termination a cleanup handler is added. While
in theory it is possible to use a timer on c->read instead, this implies
additional changes to the request body reading code. Custom event was chosen
to reduce complexity of changes needed.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Fri, 20 Aug 2021 22:35:05 +0300 |
parents | a386f95c5ae9 |
children | b049c3a0543e |
rev | line source |
---|---|
0 | 1 |
2 /* | |
3 * Copyright (C) Maxim Dounin | |
4 */ | |
5 | |
6 #include <ngx_config.h> | |
7 #include <ngx_core.h> | |
8 #include <ngx_http.h> | |
9 | |
10 | |
11 typedef struct { | |
1
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
12 ngx_msec_t delay; |
0 | 13 } ngx_http_delay_body_conf_t; |
14 | |
15 | |
1
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
16 typedef struct { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
17 ngx_event_t event; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
18 ngx_chain_t *out; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
19 ngx_uint_t buffered; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
20 } ngx_http_delay_body_ctx_t; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
21 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
22 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
23 static ngx_int_t ngx_http_delay_body_filter(ngx_http_request_t *r, |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
24 ngx_chain_t *in); |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
25 static void ngx_http_delay_body_cleanup(void *data); |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
26 static void ngx_http_delay_body_event_handler(ngx_event_t *ev); |
0 | 27 static void *ngx_http_delay_body_create_conf(ngx_conf_t *cf); |
28 static char *ngx_http_delay_body_merge_conf(ngx_conf_t *cf, void *parent, | |
29 void *child); | |
30 static ngx_int_t ngx_http_delay_body_init(ngx_conf_t *cf); | |
31 | |
32 | |
33 static ngx_command_t ngx_http_delay_body_commands[] = { | |
34 | |
35 { ngx_string("delay_body"), | |
36 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
37 ngx_conf_set_msec_slot, | |
38 NGX_HTTP_LOC_CONF_OFFSET, | |
39 offsetof(ngx_http_delay_body_conf_t, delay), | |
40 NULL }, | |
41 | |
42 ngx_null_command | |
43 }; | |
44 | |
45 | |
46 static ngx_http_module_t ngx_http_delay_body_module_ctx = { | |
47 NULL, /* preconfiguration */ | |
48 ngx_http_delay_body_init, /* postconfiguration */ | |
49 | |
50 NULL, /* create main configuration */ | |
51 NULL, /* init main configuration */ | |
52 | |
53 NULL, /* create server configuration */ | |
54 NULL, /* merge server configuration */ | |
55 | |
56 ngx_http_delay_body_create_conf, /* create location configuration */ | |
57 ngx_http_delay_body_merge_conf /* merge location configuration */ | |
58 }; | |
59 | |
60 | |
61 ngx_module_t ngx_http_delay_body_filter_module = { | |
62 NGX_MODULE_V1, | |
63 &ngx_http_delay_body_module_ctx, /* module context */ | |
64 ngx_http_delay_body_commands, /* module directives */ | |
65 NGX_HTTP_MODULE, /* module type */ | |
66 NULL, /* init master */ | |
67 NULL, /* init module */ | |
68 NULL, /* init process */ | |
69 NULL, /* init thread */ | |
70 NULL, /* exit thread */ | |
71 NULL, /* exit process */ | |
72 NULL, /* exit master */ | |
73 NGX_MODULE_V1_PADDING | |
74 }; | |
75 | |
76 | |
77 static ngx_http_request_body_filter_pt ngx_http_next_request_body_filter; | |
78 | |
79 | |
80 static ngx_int_t | |
81 ngx_http_delay_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | |
82 { | |
1
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
83 ngx_int_t rc; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
84 ngx_chain_t *cl, *ln; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
85 ngx_http_cleanup_t *cln; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
86 ngx_http_delay_body_ctx_t *ctx; |
0 | 87 ngx_http_delay_body_conf_t *conf; |
88 | |
89 conf = ngx_http_get_module_loc_conf(r, ngx_http_delay_body_filter_module); | |
90 | |
91 if (!conf->delay) { | |
92 return ngx_http_next_request_body_filter(r, in); | |
93 } | |
94 | |
95 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
96 "delay request body filter"); | |
97 | |
1
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
98 ctx = ngx_http_get_module_ctx(r, ngx_http_delay_body_filter_module); |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
99 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
100 if (ctx == NULL) { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
101 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_delay_body_ctx_t)); |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
102 if (ctx == NULL) { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
103 return NGX_ERROR; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
104 } |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
105 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
106 ngx_http_set_ctx(r, ctx, ngx_http_delay_body_filter_module); |
0 | 107 |
1
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
108 #if 1 /* XXX */ |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
109 r->request_body->filter_need_buffering = 1; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
110 #endif |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
111 } |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
112 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
113 if (ngx_chain_add_copy(r->pool, &ctx->out, in) != NGX_OK) { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
114 return NGX_ERROR; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
115 } |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
116 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
117 if (!ctx->event.timedout) { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
118 if (!ctx->event.timer_set) { |
0 | 119 |
1
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
120 /* cleanup to remove the timer in case of abnormal termination */ |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
121 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
122 cln = ngx_http_cleanup_add(r, 0); |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
123 if (cln == NULL) { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
124 return NGX_ERROR; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
125 } |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
126 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
127 cln->handler = ngx_http_delay_body_cleanup; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
128 cln->data = ctx; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
129 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
130 /* add timer */ |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
131 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
132 ctx->event.handler = ngx_http_delay_body_event_handler; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
133 ctx->event.data = r; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
134 ctx->event.log = r->connection->log; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
135 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
136 ngx_add_timer(&ctx->event, conf->delay); |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
137 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
138 ctx->buffered = 1; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
139 #if 1 /* XXX */ |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
140 r->request_body->buffered++; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
141 #endif |
0 | 142 } |
143 | |
1
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
144 return ngx_http_next_request_body_filter(r, NULL); |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
145 } |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
146 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
147 if (ctx->buffered) { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
148 ctx->buffered = 0; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
149 #if 1 /* XXX */ |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
150 r->request_body->buffered--; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
151 #endif |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
152 } |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
153 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
154 rc = ngx_http_next_request_body_filter(r, ctx->out); |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
155 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
156 for (cl = ctx->out; cl; /* void */) { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
157 ln = cl; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
158 cl = cl->next; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
159 ngx_free_chain(r->pool, ln); |
0 | 160 } |
161 | |
1
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
162 ctx->out = NULL; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
163 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
164 return rc; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
165 } |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
166 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
167 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
168 static void |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
169 ngx_http_delay_body_cleanup(void *data) |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
170 { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
171 ngx_http_delay_body_ctx_t *ctx = data; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
172 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
173 if (ctx->event.timer_set) { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
174 ngx_del_timer(&ctx->event); |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
175 } |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
176 } |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
177 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
178 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
179 static void |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
180 ngx_http_delay_body_event_handler(ngx_event_t *ev) |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
181 { |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
182 ngx_connection_t *c; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
183 ngx_http_request_t *r; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
184 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
185 r = ev->data; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
186 c = r->connection; |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
187 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
188 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
189 "delay request body event"); |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
190 |
7c2d64d9c656
Working delay body and tests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
0
diff
changeset
|
191 ngx_post_event(c->read, &ngx_posted_events); |
0 | 192 } |
193 | |
194 | |
195 static void * | |
196 ngx_http_delay_body_create_conf(ngx_conf_t *cf) | |
197 { | |
198 ngx_http_delay_body_conf_t *conf; | |
199 | |
200 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_delay_body_conf_t)); | |
201 if (conf == NULL) { | |
202 return NULL; | |
203 } | |
204 | |
205 conf->delay = NGX_CONF_UNSET_MSEC; | |
206 | |
207 return conf; | |
208 } | |
209 | |
210 | |
211 static char * | |
212 ngx_http_delay_body_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
213 { | |
214 ngx_http_delay_body_conf_t *prev = parent; | |
215 ngx_http_delay_body_conf_t *conf = child; | |
216 | |
217 ngx_conf_merge_msec_value(conf->delay, prev->delay, 0); | |
218 | |
219 return NGX_CONF_OK; | |
220 } | |
221 | |
222 | |
223 static ngx_int_t | |
224 ngx_http_delay_body_init(ngx_conf_t *cf) | |
225 { | |
226 ngx_http_next_request_body_filter = ngx_http_top_request_body_filter; | |
227 ngx_http_top_request_body_filter = ngx_http_delay_body_filter; | |
228 | |
229 return NGX_OK; | |
230 } |