1
2 /*
3 * Copyright (C) Yichun Zhang (agentzh)
4 */
5
6
7 #ifndef DDEBUG
8 #define DDEBUG 0
9 #endif
10 #include "ddebug.h"
11
12
13 #include "ngx_http_echo_util.h"
14 #include "ngx_http_echo_sleep.h"
15
16
17 ngx_uint_t ngx_http_echo_content_length_hash = 0;
18
19
20 ngx_http_echo_ctx_t *
ngx_http_echo_create_ctx(ngx_http_request_t * r)21 ngx_http_echo_create_ctx(ngx_http_request_t *r)
22 {
23 ngx_http_echo_ctx_t *ctx;
24
25 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_echo_ctx_t));
26 if (ctx == NULL) {
27 return NULL;
28 }
29
30 ctx->sleep.handler = ngx_http_echo_sleep_event_handler;
31 ctx->sleep.data = r;
32 ctx->sleep.log = r->connection->log;
33
34 return ctx;
35 }
36
37
38 ngx_int_t
ngx_http_echo_eval_cmd_args(ngx_http_request_t * r,ngx_http_echo_cmd_t * cmd,ngx_array_t * computed_args,ngx_array_t * opts)39 ngx_http_echo_eval_cmd_args(ngx_http_request_t *r,
40 ngx_http_echo_cmd_t *cmd, ngx_array_t *computed_args,
41 ngx_array_t *opts)
42 {
43 unsigned expecting_opts = 1;
44 ngx_uint_t i;
45 ngx_array_t *args = cmd->args;
46 ngx_str_t *arg, *raw, *opt;
47 ngx_http_echo_arg_template_t *value;
48
49 value = args->elts;
50
51 for (i = 0; i < args->nelts; i++) {
52 raw = &value[i].raw_value;
53
54 if (value[i].lengths == NULL && raw->len > 0) {
55 if (expecting_opts) {
56 if (raw->len == 1 || raw->data[0] != '-') {
57 expecting_opts = 0;
58
59 } else if (raw->data[1] == '-') {
60 expecting_opts = 0;
61 continue;
62
63 } else {
64 opt = ngx_array_push(opts);
65 if (opt == NULL) {
66 return NGX_HTTP_INTERNAL_SERVER_ERROR;
67 }
68
69 opt->len = raw->len - 1;
70 opt->data = raw->data + 1;
71
72 dd("pushing opt: %.*s", (int) opt->len, opt->data);
73
74 continue;
75 }
76 }
77
78 } else {
79 expecting_opts = 0;
80 }
81
82 arg = ngx_array_push(computed_args);
83 if (arg == NULL) {
84 return NGX_HTTP_INTERNAL_SERVER_ERROR;
85 }
86
87 if (value[i].lengths == NULL) { /* does not contain vars */
88 dd("Using raw value \"%.*s\"", (int) raw->len, raw->data);
89 *arg = *raw;
90
91 } else {
92 if (ngx_http_script_run(r, arg, value[i].lengths->elts,
93 0, value[i].values->elts)
94 == NULL)
95 {
96 return NGX_HTTP_INTERNAL_SERVER_ERROR;
97 }
98 }
99
100 dd("pushed arg: %.*s", (int) arg->len, arg->data);
101 }
102
103 return NGX_OK;
104 }
105
106
107 ngx_int_t
ngx_http_echo_send_chain_link(ngx_http_request_t * r,ngx_http_echo_ctx_t * ctx,ngx_chain_t * in)108 ngx_http_echo_send_chain_link(ngx_http_request_t *r,
109 ngx_http_echo_ctx_t *ctx, ngx_chain_t *in)
110 {
111 ngx_int_t rc;
112
113 rc = ngx_http_echo_send_header_if_needed(r, ctx);
114
115 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
116 return rc;
117 }
118
119 if (in == NULL) {
120
121 #if defined(nginx_version) && nginx_version <= 8004
122
123 /* earlier versions of nginx does not allow subrequests
124 to send last_buf themselves */
125 if (r != r->main) {
126 return NGX_OK;
127 }
128
129 #endif
130
131 rc = ngx_http_send_special(r, NGX_HTTP_LAST);
132 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
133 return rc;
134 }
135
136 return NGX_OK;
137 }
138
139 /* FIXME we should udpate chains to recycle chain links and bufs */
140 return ngx_http_output_filter(r, in);
141 }
142
143
144 ngx_int_t
ngx_http_echo_send_header_if_needed(ngx_http_request_t * r,ngx_http_echo_ctx_t * ctx)145 ngx_http_echo_send_header_if_needed(ngx_http_request_t *r,
146 ngx_http_echo_ctx_t *ctx)
147 {
148 ngx_int_t rc;
149 ngx_http_echo_loc_conf_t *elcf;
150
151 if (!r->header_sent && !ctx->header_sent) {
152 elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
153
154 r->headers_out.status = (ngx_uint_t) elcf->status;
155
156 if (ngx_http_set_content_type(r) != NGX_OK) {
157 return NGX_HTTP_INTERNAL_SERVER_ERROR;
158 }
159
160 ngx_http_clear_content_length(r);
161 ngx_http_clear_accept_ranges(r);
162
163 rc = ngx_http_send_header(r);
164 ctx->header_sent = 1;
165 return rc;
166 }
167
168 return NGX_OK;
169 }
170
171
172 ssize_t
ngx_http_echo_atosz(u_char * line,size_t n)173 ngx_http_echo_atosz(u_char *line, size_t n)
174 {
175 ssize_t value;
176
177 if (n == 0) {
178 return NGX_ERROR;
179 }
180
181 for (value = 0; n--; line++) {
182 if (*line == '_') { /* we ignore undercores */
183 continue;
184 }
185
186 if (*line < '0' || *line > '9') {
187 return NGX_ERROR;
188 }
189
190 value = value * 10 + (*line - '0');
191 }
192
193 if (value < 0) {
194 return NGX_ERROR;
195 }
196
197 return value;
198 }
199
200
201 /* Modified from the ngx_strlcasestrn function in ngx_string.h
202 * Copyright (C) by Igor Sysoev */
203 u_char *
ngx_http_echo_strlstrn(u_char * s1,u_char * last,u_char * s2,size_t n)204 ngx_http_echo_strlstrn(u_char *s1, u_char *last, u_char *s2, size_t n)
205 {
206 ngx_uint_t c1, c2;
207
208 c2 = (ngx_uint_t) *s2++;
209 last -= n;
210
211 do {
212 do {
213 if (s1 >= last) {
214 return NULL;
215 }
216
217 c1 = (ngx_uint_t) *s1++;
218
219 } while (c1 != c2);
220
221 } while (ngx_strncmp(s1, s2, n) != 0);
222
223 return --s1;
224 }
225
226
227 ngx_int_t
ngx_http_echo_post_request_at_head(ngx_http_request_t * r,ngx_http_posted_request_t * pr)228 ngx_http_echo_post_request_at_head(ngx_http_request_t *r,
229 ngx_http_posted_request_t *pr)
230 {
231 dd_enter();
232
233 if (pr == NULL) {
234 pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t));
235 if (pr == NULL) {
236 return NGX_ERROR;
237 }
238 }
239
240 pr->request = r;
241 pr->next = r->main->posted_requests;
242 r->main->posted_requests = pr;
243
244 return NGX_OK;
245 }
246
247
248 u_char *
ngx_http_echo_rebase_path(ngx_pool_t * pool,u_char * src,size_t osize,size_t * nsize)249 ngx_http_echo_rebase_path(ngx_pool_t *pool, u_char *src, size_t osize,
250 size_t *nsize)
251 {
252 u_char *p, *dst;
253
254 if (osize == 0) {
255 return NULL;
256 }
257
258 if (src[0] == '/') {
259 /* being an absolute path already, just add a trailing '\0' */
260 *nsize = osize;
261
262 dst = ngx_palloc(pool, *nsize + 1);
263 if (dst == NULL) {
264 *nsize = 0;
265 return NULL;
266 }
267
268 p = ngx_copy(dst, src, osize);
269 *p = '\0';
270
271 return dst;
272 }
273
274 *nsize = ngx_cycle->prefix.len + osize;
275
276 dst = ngx_palloc(pool, *nsize + 1);
277 if (dst == NULL) {
278 *nsize = 0;
279 return NULL;
280 }
281
282 p = ngx_copy(dst, ngx_cycle->prefix.data, ngx_cycle->prefix.len);
283 p = ngx_copy(p, src, osize);
284
285 *p = '\0';
286
287 return dst;
288 }
289
290
291 ngx_int_t
ngx_http_echo_flush_postponed_outputs(ngx_http_request_t * r)292 ngx_http_echo_flush_postponed_outputs(ngx_http_request_t *r)
293 {
294 if (r == r->connection->data && r->postponed) {
295 /* notify the downstream postpone filter to flush the postponed
296 * outputs of the current request */
297 return ngx_http_output_filter(r, NULL);
298 }
299
300 /* do nothing */
301 return NGX_OK;
302 }
303