Mercurial > hg > nginx
annotate src/http/modules/ngx_http_random_index_module.c @ 3440:88741ec7731a stable-0.7
merge r3294, r3305:
Fix a bug introduced in r2032: After a child process has read a terminate
message from a channel, the process tries to read the channel again.
The kernel (at least FreeBSD) may preempt the process and sends a SIGIO
signal to a master process. The master process sends a new terminate message,
the kernel switches again to the the child process, and the child process
reads the messages instead of an EAGAIN error. And this may repeat over
and over. Being that the child process can not exit the cycle and test
the termination flag set by the message handler.
The fix disallow the master process to send a new terminate message on
SIGIO signal reception. It may send the message only on SIGALARM signal.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 01 Feb 2010 15:49:36 +0000 |
parents | 6b8284fc958d |
children | 8152369f7037 |
rev | line source |
---|---|
2235 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_http.h> | |
10 | |
11 | |
12 typedef struct { | |
13 ngx_flag_t enable; | |
14 } ngx_http_random_index_loc_conf_t; | |
15 | |
16 | |
17 #define NGX_HTTP_RANDOM_INDEX_PREALLOCATE 50 | |
18 | |
19 | |
20 static ngx_int_t ngx_http_random_index_error(ngx_http_request_t *r, | |
21 ngx_dir_t *dir, ngx_str_t *name); | |
2266
6223d5a9e87f
back out $random_index variable
Igor Sysoev <igor@sysoev.ru>
parents:
2258
diff
changeset
|
22 static ngx_int_t ngx_http_random_index_init(ngx_conf_t *cf); |
2235 | 23 static void *ngx_http_random_index_create_loc_conf(ngx_conf_t *cf); |
24 static char *ngx_http_random_index_merge_loc_conf(ngx_conf_t *cf, | |
25 void *parent, void *child); | |
26 | |
27 | |
28 static ngx_command_t ngx_http_random_index_commands[] = { | |
29 | |
30 { ngx_string("random_index"), | |
31 NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
32 ngx_conf_set_flag_slot, | |
33 NGX_HTTP_LOC_CONF_OFFSET, | |
34 offsetof(ngx_http_random_index_loc_conf_t, enable), | |
35 NULL }, | |
36 | |
37 ngx_null_command | |
38 }; | |
39 | |
40 | |
41 static ngx_http_module_t ngx_http_random_index_module_ctx = { | |
2266
6223d5a9e87f
back out $random_index variable
Igor Sysoev <igor@sysoev.ru>
parents:
2258
diff
changeset
|
42 NULL, /* preconfiguration */ |
2235 | 43 ngx_http_random_index_init, /* postconfiguration */ |
44 | |
45 NULL, /* create main configuration */ | |
46 NULL, /* init main configuration */ | |
47 | |
48 NULL, /* create server configuration */ | |
49 NULL, /* merge server configuration */ | |
50 | |
51 ngx_http_random_index_create_loc_conf, /* create location configration */ | |
52 ngx_http_random_index_merge_loc_conf /* merge location configration */ | |
53 }; | |
54 | |
55 | |
56 ngx_module_t ngx_http_random_index_module = { | |
57 NGX_MODULE_V1, | |
58 &ngx_http_random_index_module_ctx, /* module context */ | |
59 ngx_http_random_index_commands, /* module directives */ | |
60 NGX_HTTP_MODULE, /* module type */ | |
61 NULL, /* init master */ | |
62 NULL, /* init module */ | |
63 NULL, /* init process */ | |
64 NULL, /* init thread */ | |
65 NULL, /* exit thread */ | |
66 NULL, /* exit process */ | |
67 NULL, /* exit master */ | |
68 NGX_MODULE_V1_PADDING | |
69 }; | |
70 | |
71 | |
72 static ngx_int_t | |
73 ngx_http_random_index_handler(ngx_http_request_t *r) | |
74 { | |
75 u_char *last, *filename; | |
76 size_t len, allocated, root; | |
77 ngx_err_t err; | |
78 ngx_int_t rc; | |
79 ngx_str_t path, uri, *name; | |
80 ngx_dir_t dir; | |
81 ngx_uint_t n, level; | |
82 ngx_array_t names; | |
83 ngx_http_random_index_loc_conf_t *rlcf; | |
84 | |
85 if (r->uri.data[r->uri.len - 1] != '/') { | |
86 return NGX_DECLINED; | |
87 } | |
88 | |
89 if (r->zero_in_uri) { | |
90 return NGX_DECLINED; | |
91 } | |
92 | |
93 if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { | |
94 return NGX_DECLINED; | |
95 } | |
96 | |
97 rlcf = ngx_http_get_module_loc_conf(r, ngx_http_random_index_module); | |
98 | |
99 if (!rlcf->enable) { | |
100 return NGX_DECLINED; | |
101 } | |
102 | |
103 #if (NGX_HAVE_D_TYPE) | |
104 len = NGX_DIR_MASK_LEN; | |
105 #else | |
106 len = NGX_HTTP_RANDOM_INDEX_PREALLOCATE; | |
107 #endif | |
108 | |
109 last = ngx_http_map_uri_to_path(r, &path, &root, len); | |
110 if (last == NULL) { | |
111 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
112 } | |
113 | |
114 allocated = path.len; | |
115 | |
116 path.len = last - path.data - 1; | |
117 path.data[path.len] = '\0'; | |
118 | |
119 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
120 "http random index: \"%s\"", path.data); | |
121 | |
122 if (ngx_open_dir(&path, &dir) == NGX_ERROR) { | |
123 err = ngx_errno; | |
124 | |
125 if (err == NGX_ENOENT | |
126 || err == NGX_ENOTDIR | |
127 || err == NGX_ENAMETOOLONG) | |
128 { | |
129 level = NGX_LOG_ERR; | |
130 rc = NGX_HTTP_NOT_FOUND; | |
131 | |
132 } else if (err == NGX_EACCES) { | |
133 level = NGX_LOG_ERR; | |
134 rc = NGX_HTTP_FORBIDDEN; | |
135 | |
136 } else { | |
137 level = NGX_LOG_CRIT; | |
138 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
139 } | |
140 | |
141 ngx_log_error(level, r->connection->log, err, | |
142 ngx_open_dir_n " \"%s\" failed", path.data); | |
143 | |
144 return rc; | |
145 } | |
146 | |
147 if (ngx_array_init(&names, r->pool, 32, sizeof(ngx_str_t)) != NGX_OK) { | |
148 return ngx_http_random_index_error(r, &dir, &path); | |
149 } | |
150 | |
151 filename = path.data; | |
152 filename[path.len] = '/'; | |
153 | |
154 for ( ;; ) { | |
155 ngx_set_errno(0); | |
156 | |
157 if (ngx_read_dir(&dir) == NGX_ERROR) { | |
158 err = ngx_errno; | |
159 | |
160 if (err != NGX_ENOMOREFILES) { | |
161 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, | |
162 ngx_read_dir_n " \"%V\" failed", &path); | |
163 return ngx_http_random_index_error(r, &dir, &path); | |
164 } | |
165 | |
166 break; | |
167 } | |
168 | |
169 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
170 "http random index file: \"%s\"", ngx_de_name(&dir)); | |
171 | |
172 if (ngx_de_name(&dir)[0] == '.') { | |
173 continue; | |
174 } | |
175 | |
176 len = ngx_de_namelen(&dir); | |
177 | |
3433 | 178 if (dir.type == 0 || ngx_de_is_link(&dir)) { |
2235 | 179 |
180 /* 1 byte for '/' and 1 byte for terminating '\0' */ | |
181 | |
182 if (path.len + 1 + len + 1 > allocated) { | |
183 allocated = path.len + 1 + len + 1 | |
184 + NGX_HTTP_RANDOM_INDEX_PREALLOCATE; | |
185 | |
186 filename = ngx_pnalloc(r->pool, allocated); | |
187 if (filename == NULL) { | |
188 return ngx_http_random_index_error(r, &dir, &path); | |
189 } | |
190 | |
191 last = ngx_cpystrn(filename, path.data, path.len + 1); | |
192 *last++ = '/'; | |
193 } | |
194 | |
195 ngx_cpystrn(last, ngx_de_name(&dir), len + 1); | |
196 | |
197 if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { | |
198 err = ngx_errno; | |
199 | |
200 if (err != NGX_ENOENT) { | |
201 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, | |
202 ngx_de_info_n " \"%s\" failed", filename); | |
203 return ngx_http_random_index_error(r, &dir, &path); | |
204 } | |
205 | |
206 if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { | |
207 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, | |
208 ngx_de_link_info_n " \"%s\" failed", | |
209 filename); | |
210 return ngx_http_random_index_error(r, &dir, &path); | |
211 } | |
212 } | |
213 } | |
214 | |
215 if (!ngx_de_is_file(&dir)) { | |
216 continue; | |
217 } | |
218 | |
219 name = ngx_array_push(&names); | |
220 if (name == NULL) { | |
221 return ngx_http_random_index_error(r, &dir, &path); | |
222 } | |
223 | |
224 name->len = len; | |
225 | |
226 name->data = ngx_pnalloc(r->pool, len); | |
227 if (name->data == NULL) { | |
228 return ngx_http_random_index_error(r, &dir, &path); | |
229 } | |
230 | |
231 ngx_memcpy(name->data, ngx_de_name(&dir), len); | |
232 } | |
233 | |
234 if (ngx_close_dir(&dir) == NGX_ERROR) { | |
235 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, | |
236 ngx_close_dir_n " \"%s\" failed", &path); | |
237 } | |
238 | |
239 n = names.nelts; | |
240 | |
241 if (n == 0) { | |
242 return NGX_DECLINED; | |
243 } | |
244 | |
245 name = names.elts; | |
246 | |
247 n = (ngx_uint_t) (((uint64_t) ngx_random() * n) / 0x80000000); | |
248 | |
249 uri.len = r->uri.len + name[n].len; | |
250 | |
251 uri.data = ngx_pnalloc(r->pool, uri.len); | |
252 if (uri.data == NULL) { | |
253 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
254 } | |
255 | |
256 last = ngx_copy(uri.data, r->uri.data, r->uri.len); | |
257 ngx_memcpy(last, name[n].data, name[n].len); | |
258 | |
259 return ngx_http_internal_redirect(r, &uri, &r->args); | |
260 } | |
261 | |
262 | |
263 static ngx_int_t | |
264 ngx_http_random_index_error(ngx_http_request_t *r, ngx_dir_t *dir, | |
265 ngx_str_t *name) | |
266 { | |
267 if (ngx_close_dir(dir) == NGX_ERROR) { | |
268 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, | |
269 ngx_close_dir_n " \"%V\" failed", name); | |
270 } | |
271 | |
272 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
273 } | |
274 | |
275 | |
276 static void * | |
277 ngx_http_random_index_create_loc_conf(ngx_conf_t *cf) | |
278 { | |
279 ngx_http_random_index_loc_conf_t *conf; | |
280 | |
281 conf = ngx_palloc(cf->pool, sizeof(ngx_http_random_index_loc_conf_t)); | |
282 if (conf == NULL) { | |
3237
2efa8d2fcde1
merge r2903, r2911, r2912, r3002:
Igor Sysoev <igor@sysoev.ru>
parents:
2721
diff
changeset
|
283 return NULL; |
2235 | 284 } |
285 | |
286 conf->enable = NGX_CONF_UNSET; | |
287 | |
288 return conf; | |
289 } | |
290 | |
291 | |
292 static char * | |
293 ngx_http_random_index_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
294 { | |
295 ngx_http_random_index_loc_conf_t *prev = parent; | |
296 ngx_http_random_index_loc_conf_t *conf = child; | |
297 | |
298 ngx_conf_merge_value(conf->enable, prev->enable, 0); | |
299 | |
300 return NGX_CONF_OK; | |
301 } | |
302 | |
303 | |
304 static ngx_int_t | |
305 ngx_http_random_index_init(ngx_conf_t *cf) | |
306 { | |
307 ngx_http_handler_pt *h; | |
308 ngx_http_core_main_conf_t *cmcf; | |
309 | |
310 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); | |
311 | |
312 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); | |
313 if (h == NULL) { | |
314 return NGX_ERROR; | |
315 } | |
316 | |
317 *h = ngx_http_random_index_handler; | |
318 | |
319 return NGX_OK; | |
320 } |