Mercurial > hg > ngx_http_delay_body_filter_module
comparison 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 |
comparison
equal
deleted
inserted
replaced
0:a386f95c5ae9 | 1:7c2d64d9c656 |
---|---|
7 #include <ngx_core.h> | 7 #include <ngx_core.h> |
8 #include <ngx_http.h> | 8 #include <ngx_http.h> |
9 | 9 |
10 | 10 |
11 typedef struct { | 11 typedef struct { |
12 ngx_msec_t delay; | 12 ngx_msec_t delay; |
13 } ngx_http_delay_body_conf_t; | 13 } ngx_http_delay_body_conf_t; |
14 | 14 |
15 | 15 |
16 typedef struct { | |
17 ngx_event_t event; | |
18 ngx_chain_t *out; | |
19 ngx_uint_t buffered; | |
20 } ngx_http_delay_body_ctx_t; | |
21 | |
22 | |
23 static ngx_int_t ngx_http_delay_body_filter(ngx_http_request_t *r, | |
24 ngx_chain_t *in); | |
25 static void ngx_http_delay_body_cleanup(void *data); | |
26 static void ngx_http_delay_body_event_handler(ngx_event_t *ev); | |
16 static void *ngx_http_delay_body_create_conf(ngx_conf_t *cf); | 27 static void *ngx_http_delay_body_create_conf(ngx_conf_t *cf); |
17 static char *ngx_http_delay_body_merge_conf(ngx_conf_t *cf, void *parent, | 28 static char *ngx_http_delay_body_merge_conf(ngx_conf_t *cf, void *parent, |
18 void *child); | 29 void *child); |
19 static ngx_int_t ngx_http_delay_body_init(ngx_conf_t *cf); | 30 static ngx_int_t ngx_http_delay_body_init(ngx_conf_t *cf); |
20 | 31 |
67 | 78 |
68 | 79 |
69 static ngx_int_t | 80 static ngx_int_t |
70 ngx_http_delay_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | 81 ngx_http_delay_body_filter(ngx_http_request_t *r, ngx_chain_t *in) |
71 { | 82 { |
72 ngx_chain_t *cl; | 83 ngx_int_t rc; |
84 ngx_chain_t *cl, *ln; | |
85 ngx_http_cleanup_t *cln; | |
86 ngx_http_delay_body_ctx_t *ctx; | |
73 ngx_http_delay_body_conf_t *conf; | 87 ngx_http_delay_body_conf_t *conf; |
74 | 88 |
75 conf = ngx_http_get_module_loc_conf(r, ngx_http_delay_body_filter_module); | 89 conf = ngx_http_get_module_loc_conf(r, ngx_http_delay_body_filter_module); |
76 | 90 |
77 if (!conf->delay) { | 91 if (!conf->delay) { |
79 } | 93 } |
80 | 94 |
81 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 95 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
82 "delay request body filter"); | 96 "delay request body filter"); |
83 | 97 |
84 /* TODO: delay */ | 98 ctx = ngx_http_get_module_ctx(r, ngx_http_delay_body_filter_module); |
85 | 99 |
86 for (cl = in; cl; cl = cl->next) { | 100 if (ctx == NULL) { |
87 | 101 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_delay_body_ctx_t)); |
88 if (cl->buf->last_buf) { | 102 if (ctx == NULL) { |
89 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 103 return NGX_ERROR; |
90 "delay body: last buf"); | |
91 } | 104 } |
92 | 105 |
93 } | 106 ngx_http_set_ctx(r, ctx, ngx_http_delay_body_filter_module); |
94 | 107 |
95 return ngx_http_next_request_body_filter(r, in); | 108 #if 1 /* XXX */ |
109 r->request_body->filter_need_buffering = 1; | |
110 #endif | |
111 } | |
112 | |
113 if (ngx_chain_add_copy(r->pool, &ctx->out, in) != NGX_OK) { | |
114 return NGX_ERROR; | |
115 } | |
116 | |
117 if (!ctx->event.timedout) { | |
118 if (!ctx->event.timer_set) { | |
119 | |
120 /* cleanup to remove the timer in case of abnormal termination */ | |
121 | |
122 cln = ngx_http_cleanup_add(r, 0); | |
123 if (cln == NULL) { | |
124 return NGX_ERROR; | |
125 } | |
126 | |
127 cln->handler = ngx_http_delay_body_cleanup; | |
128 cln->data = ctx; | |
129 | |
130 /* add timer */ | |
131 | |
132 ctx->event.handler = ngx_http_delay_body_event_handler; | |
133 ctx->event.data = r; | |
134 ctx->event.log = r->connection->log; | |
135 | |
136 ngx_add_timer(&ctx->event, conf->delay); | |
137 | |
138 ctx->buffered = 1; | |
139 #if 1 /* XXX */ | |
140 r->request_body->buffered++; | |
141 #endif | |
142 } | |
143 | |
144 return ngx_http_next_request_body_filter(r, NULL); | |
145 } | |
146 | |
147 if (ctx->buffered) { | |
148 ctx->buffered = 0; | |
149 #if 1 /* XXX */ | |
150 r->request_body->buffered--; | |
151 #endif | |
152 } | |
153 | |
154 rc = ngx_http_next_request_body_filter(r, ctx->out); | |
155 | |
156 for (cl = ctx->out; cl; /* void */) { | |
157 ln = cl; | |
158 cl = cl->next; | |
159 ngx_free_chain(r->pool, ln); | |
160 } | |
161 | |
162 ctx->out = NULL; | |
163 | |
164 return rc; | |
165 } | |
166 | |
167 | |
168 static void | |
169 ngx_http_delay_body_cleanup(void *data) | |
170 { | |
171 ngx_http_delay_body_ctx_t *ctx = data; | |
172 | |
173 if (ctx->event.timer_set) { | |
174 ngx_del_timer(&ctx->event); | |
175 } | |
176 } | |
177 | |
178 | |
179 static void | |
180 ngx_http_delay_body_event_handler(ngx_event_t *ev) | |
181 { | |
182 ngx_connection_t *c; | |
183 ngx_http_request_t *r; | |
184 | |
185 r = ev->data; | |
186 c = r->connection; | |
187 | |
188 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
189 "delay request body event"); | |
190 | |
191 ngx_post_event(c->read, &ngx_posted_events); | |
96 } | 192 } |
97 | 193 |
98 | 194 |
99 static void * | 195 static void * |
100 ngx_http_delay_body_create_conf(ngx_conf_t *cf) | 196 ngx_http_delay_body_create_conf(ngx_conf_t *cf) |