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