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_srcache_filter_module.h"
14 #include "ngx_http_srcache_util.h"
15 #include "ngx_http_srcache_var.h"
16 #include "ngx_http_srcache_fetch.h"
17 #include "ngx_http_srcache_store.h"
18 #include "ngx_http_srcache_headers.h"
19
20
21 static void *ngx_http_srcache_create_loc_conf(ngx_conf_t *cf);
22 static char *ngx_http_srcache_merge_loc_conf(ngx_conf_t *cf, void *parent,
23 void *child);
24 static ngx_int_t ngx_http_srcache_post_config(ngx_conf_t *cf);
25 static char *ngx_http_srcache_conf_set_request(ngx_conf_t *cf,
26 ngx_command_t *cmd, void *conf);
27 static void *ngx_http_srcache_create_main_conf(ngx_conf_t *cf);
28 static char *ngx_http_srcache_init_main_conf(ngx_conf_t *cf, void *conf);
29 static char *ngx_http_srcache_store_statuses(ngx_conf_t *cf,
30 ngx_command_t *cmd, void *conf);
31
32
33 static volatile ngx_cycle_t *ngx_http_srcache_prev_cycle = NULL;
34
35
36 static ngx_str_t ngx_http_srcache_hide_headers[] = {
37 ngx_string("Connection"),
38 ngx_string("Keep-Alive"),
39 ngx_string("Proxy-Authenticate"),
40 ngx_string("Proxy-Authorization"),
41 ngx_string("TE"),
42 ngx_string("Trailers"),
43 ngx_string("Transfer-Encoding"),
44 ngx_string("Upgrade"),
45 ngx_string("Set-Cookie"),
46 ngx_null_string
47 };
48
49
50 static ngx_conf_bitmask_t ngx_http_srcache_cache_method_mask[] = {
51 { ngx_string("GET"), NGX_HTTP_GET},
52 { ngx_string("HEAD"), NGX_HTTP_HEAD },
53 { ngx_string("POST"), NGX_HTTP_POST },
54 { ngx_string("PUT"), NGX_HTTP_PUT },
55 { ngx_string("DELETE"), NGX_HTTP_DELETE },
56 { ngx_null_string, 0 }
57 };
58
59
60 static ngx_command_t ngx_http_srcache_commands[] = {
61
62 { ngx_string("srcache_buffer"),
63 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
64 |NGX_CONF_TAKE1,
65 ngx_conf_set_size_slot,
66 NGX_HTTP_LOC_CONF_OFFSET,
67 offsetof(ngx_http_srcache_loc_conf_t, buf_size),
68 NULL },
69
70 { ngx_string("srcache_fetch"),
71 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
72 |NGX_CONF_TAKE23,
73 ngx_http_srcache_conf_set_request,
74 NGX_HTTP_LOC_CONF_OFFSET,
75 offsetof(ngx_http_srcache_loc_conf_t, fetch),
76 NULL },
77
78 { ngx_string("srcache_store"),
79 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
80 |NGX_CONF_TAKE23,
81 ngx_http_srcache_conf_set_request,
82 NGX_HTTP_LOC_CONF_OFFSET,
83 offsetof(ngx_http_srcache_loc_conf_t, store),
84 NULL },
85
86 { ngx_string("srcache_store_max_size"),
87 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
88 |NGX_CONF_TAKE1,
89 ngx_conf_set_size_slot,
90 NGX_HTTP_LOC_CONF_OFFSET,
91 offsetof(ngx_http_srcache_loc_conf_t, store_max_size),
92 NULL },
93
94 { ngx_string("srcache_fetch_skip"),
95 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
96 |NGX_CONF_TAKE1,
97 ngx_http_set_complex_value_slot,
98 NGX_HTTP_LOC_CONF_OFFSET,
99 offsetof(ngx_http_srcache_loc_conf_t, fetch_skip),
100 NULL },
101
102 { ngx_string("srcache_store_skip"),
103 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
104 |NGX_CONF_TAKE1,
105 ngx_http_set_complex_value_slot,
106 NGX_HTTP_LOC_CONF_OFFSET,
107 offsetof(ngx_http_srcache_loc_conf_t, store_skip),
108 NULL },
109
110 { ngx_string("srcache_store_statuses"),
111 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
112 |NGX_CONF_1MORE,
113 ngx_http_srcache_store_statuses,
114 NGX_HTTP_LOC_CONF_OFFSET,
115 0,
116 NULL },
117
118 { ngx_string("srcache_methods"),
119 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
120 ngx_conf_set_bitmask_slot,
121 NGX_HTTP_LOC_CONF_OFFSET,
122 offsetof(ngx_http_srcache_loc_conf_t, cache_methods),
123 &ngx_http_srcache_cache_method_mask },
124
125 { ngx_string("srcache_request_cache_control"),
126 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
127 ngx_conf_set_flag_slot,
128 NGX_HTTP_LOC_CONF_OFFSET,
129 offsetof(ngx_http_srcache_loc_conf_t, req_cache_control),
130 NULL },
131
132 { ngx_string("srcache_store_private"),
133 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
134 ngx_conf_set_flag_slot,
135 NGX_HTTP_LOC_CONF_OFFSET,
136 offsetof(ngx_http_srcache_loc_conf_t, store_private),
137 NULL },
138
139 { ngx_string("srcache_store_no_store"),
140 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
141 ngx_conf_set_flag_slot,
142 NGX_HTTP_LOC_CONF_OFFSET,
143 offsetof(ngx_http_srcache_loc_conf_t, store_no_store),
144 NULL },
145
146 { ngx_string("srcache_store_no_cache"),
147 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
148 ngx_conf_set_flag_slot,
149 NGX_HTTP_LOC_CONF_OFFSET,
150 offsetof(ngx_http_srcache_loc_conf_t, store_no_cache),
151 NULL },
152
153 { ngx_string("srcache_response_cache_control"),
154 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
155 ngx_conf_set_flag_slot,
156 NGX_HTTP_LOC_CONF_OFFSET,
157 offsetof(ngx_http_srcache_loc_conf_t, resp_cache_control),
158 NULL },
159
160 { ngx_string("srcache_store_hide_header"),
161 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
162 ngx_conf_set_str_array_slot,
163 NGX_HTTP_LOC_CONF_OFFSET,
164 offsetof(ngx_http_srcache_loc_conf_t, hide_headers),
165 NULL },
166
167 { ngx_string("srcache_store_pass_header"),
168 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
169 ngx_conf_set_str_array_slot,
170 NGX_HTTP_LOC_CONF_OFFSET,
171 offsetof(ngx_http_srcache_loc_conf_t, pass_headers),
172 NULL },
173
174 { ngx_string("srcache_store_ranges"),
175 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
176 ngx_conf_set_flag_slot,
177 NGX_HTTP_LOC_CONF_OFFSET,
178 offsetof(ngx_http_srcache_loc_conf_t, store_ranges),
179 NULL },
180
181 { ngx_string("srcache_ignore_content_encoding"),
182 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
183 ngx_conf_set_flag_slot,
184 NGX_HTTP_LOC_CONF_OFFSET,
185 offsetof(ngx_http_srcache_loc_conf_t, ignore_content_encoding),
186 NULL },
187
188 { ngx_string("srcache_header_buffer_size"),
189 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
190 |NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
191 ngx_conf_set_size_slot,
192 NGX_HTTP_LOC_CONF_OFFSET,
193 offsetof(ngx_http_srcache_loc_conf_t, header_buf_size),
194 NULL },
195
196 { ngx_string("srcache_max_expire"),
197 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
198 |NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
199 ngx_conf_set_sec_slot,
200 NGX_HTTP_LOC_CONF_OFFSET,
201 offsetof(ngx_http_srcache_loc_conf_t, max_expire),
202 NULL },
203
204 { ngx_string("srcache_default_expire"),
205 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
206 |NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
207 ngx_conf_set_sec_slot,
208 NGX_HTTP_LOC_CONF_OFFSET,
209 offsetof(ngx_http_srcache_loc_conf_t, default_expire),
210 NULL },
211
212 ngx_null_command
213 };
214
215
216 static ngx_http_module_t ngx_http_srcache_filter_module_ctx = {
217 NULL, /* preconfiguration */
218 ngx_http_srcache_post_config, /* postconfiguration */
219
220 ngx_http_srcache_create_main_conf, /* create main configuration */
221 ngx_http_srcache_init_main_conf, /* init main configuration */
222
223 NULL, /* create server configuration */
224 NULL, /* merge server configuration */
225
226 ngx_http_srcache_create_loc_conf, /* create location configuration */
227 ngx_http_srcache_merge_loc_conf /* merge location configuration */
228 };
229
230
231 ngx_module_t ngx_http_srcache_filter_module = {
232 NGX_MODULE_V1,
233 &ngx_http_srcache_filter_module_ctx, /* module context */
234 ngx_http_srcache_commands, /* module directives */
235 NGX_HTTP_MODULE, /* module type */
236 NULL, /* init master */
237 NULL, /* init module */
238 NULL, /* init process */
239 NULL, /* init thread */
240 NULL, /* exit thread */
241 NULL, /* exit process */
242 NULL, /* exit master */
243 NGX_MODULE_V1_PADDING
244 };
245
246
247 static void *
ngx_http_srcache_create_loc_conf(ngx_conf_t * cf)248 ngx_http_srcache_create_loc_conf(ngx_conf_t *cf)
249 {
250 ngx_http_srcache_loc_conf_t *conf;
251
252 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_srcache_loc_conf_t));
253 if (conf == NULL) {
254 return NULL;
255 }
256
257 /*
258 * set by ngx_pcalloc():
259 *
260 * conf->fetch_skip = NULL;
261 * conf->store_skip = NULL;
262 * conf->cache_methods = 0;
263 * conf->hide_headers_hash = { NULL, 0 };
264 * conf->skip_content_type = 0;
265 * conf->store_statuses = NULL;
266 */
267
268 conf->fetch = NGX_CONF_UNSET_PTR;
269 conf->store = NGX_CONF_UNSET_PTR;
270
271 conf->buf_size = NGX_CONF_UNSET_SIZE;
272 conf->store_max_size = NGX_CONF_UNSET_SIZE;
273 conf->header_buf_size = NGX_CONF_UNSET_SIZE;
274
275 conf->req_cache_control = NGX_CONF_UNSET;
276 conf->resp_cache_control = NGX_CONF_UNSET;
277
278 conf->store_private = NGX_CONF_UNSET;
279 conf->store_no_store = NGX_CONF_UNSET;
280 conf->store_no_cache = NGX_CONF_UNSET;
281 conf->store_ranges = NGX_CONF_UNSET;
282
283 conf->max_expire = NGX_CONF_UNSET;
284 conf->default_expire = NGX_CONF_UNSET;
285
286 conf->ignore_content_encoding = NGX_CONF_UNSET;
287
288 conf->hide_headers = NGX_CONF_UNSET_PTR;
289 conf->pass_headers = NGX_CONF_UNSET_PTR;
290
291 return conf;
292 }
293
294
295 static char *
ngx_http_srcache_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)296 ngx_http_srcache_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
297 {
298 ngx_http_srcache_loc_conf_t *prev = parent;
299 ngx_http_srcache_loc_conf_t *conf = child;
300 ngx_hash_init_t hash;
301
302 ngx_conf_merge_ptr_value(conf->fetch, prev->fetch, NULL);
303 ngx_conf_merge_ptr_value(conf->store, prev->store, NULL);
304
305 ngx_conf_merge_size_value(conf->buf_size, prev->buf_size,
306 (size_t) ngx_pagesize);
307
308 ngx_conf_merge_size_value(conf->store_max_size, prev->store_max_size, 0);
309
310 ngx_conf_merge_size_value(conf->header_buf_size, prev->header_buf_size,
311 (size_t) ngx_pagesize);
312
313 if (conf->fetch_skip == NULL) {
314 conf->fetch_skip = prev->fetch_skip;
315 }
316
317 if (conf->store_skip == NULL) {
318 conf->store_skip = prev->store_skip;
319 }
320
321 if (conf->store_statuses == NULL) {
322 conf->store_statuses = prev->store_statuses;
323 }
324
325 if (conf->cache_methods == 0) {
326 conf->cache_methods = prev->cache_methods;
327 }
328
329 conf->cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
330
331 ngx_conf_merge_value(conf->req_cache_control, prev->req_cache_control, 0);
332 ngx_conf_merge_value(conf->resp_cache_control, prev->resp_cache_control, 1);
333
334 ngx_conf_merge_value(conf->store_private, prev->store_private, 0);
335 ngx_conf_merge_value(conf->store_no_store, prev->store_no_store, 0);
336 ngx_conf_merge_value(conf->store_no_cache, prev->store_no_cache, 0);
337 ngx_conf_merge_value(conf->store_ranges, prev->store_ranges, 0);
338
339 ngx_conf_merge_value(conf->max_expire, prev->max_expire, 0);
340 ngx_conf_merge_value(conf->default_expire, prev->default_expire, 60);
341
342 ngx_conf_merge_value(conf->ignore_content_encoding,
343 prev->ignore_content_encoding, 0);
344
345 hash.max_size = 512;
346 hash.bucket_size = ngx_align(64, ngx_cacheline_size);
347 hash.name = "srcache_store_hide_headers_hash";
348
349 if (ngx_http_srcache_hide_headers_hash(cf, conf,
350 prev, ngx_http_srcache_hide_headers, &hash)
351 != NGX_OK)
352 {
353 return NGX_CONF_ERROR;
354 }
355
356 return NGX_CONF_OK;
357 }
358
359
360 static char *
ngx_http_srcache_conf_set_request(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)361 ngx_http_srcache_conf_set_request(ngx_conf_t *cf, ngx_command_t *cmd,
362 void *conf)
363 {
364 char *p = conf;
365
366 ngx_http_srcache_request_t **rpp;
367 ngx_http_srcache_request_t *rp;
368 ngx_str_t *value;
369 ngx_str_t *method_name;
370 ngx_http_compile_complex_value_t ccv;
371 ngx_http_srcache_main_conf_t *smcf;
372
373 rpp = (ngx_http_srcache_request_t **) (p + cmd->offset);
374
375 if (*rpp != NGX_CONF_UNSET_PTR) {
376 return "is duplicate";
377 }
378
379 smcf = ngx_http_conf_get_module_main_conf(cf,
380 ngx_http_srcache_filter_module);
381
382 smcf->module_used = 1;
383
384 value = cf->args->elts;
385
386 *rpp = ngx_pcalloc(cf->pool, sizeof(ngx_http_srcache_request_t));
387 if (*rpp == NULL) {
388 return NGX_CONF_ERROR;
389 }
390
391 rp = *rpp;
392
393 method_name = &value[1];
394
395 rp->method = ngx_http_srcache_parse_method_name(&method_name);
396
397 if (rp->method == NGX_HTTP_UNKNOWN) {
398 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
399 "%V specifies bad HTTP method %V",
400 &cmd->name, method_name);
401
402 return NGX_CONF_ERROR;
403 }
404
405 rp->method_name = *method_name;
406
407 /* compile the location arg */
408
409 if (value[2].len == 0) {
410 ngx_memzero(&rp->location, sizeof(ngx_http_complex_value_t));
411
412 } else {
413 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
414
415 ccv.cf = cf;
416 ccv.value = &value[2];
417 ccv.complex_value = &rp->location;
418
419 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
420 return NGX_CONF_ERROR;
421 }
422 }
423
424 if (cf->args->nelts == 2 + 1) {
425 return NGX_CONF_OK;
426 }
427
428 /* compile the args arg */
429
430 if (value[3].len == 0) {
431 ngx_memzero(&rp->location, sizeof(ngx_http_complex_value_t));
432 return NGX_CONF_OK;
433 }
434
435 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
436
437 ccv.cf = cf;
438 ccv.value = &value[3];
439 ccv.complex_value = &rp->args;
440
441 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
442 return NGX_CONF_ERROR;
443 }
444
445 return NGX_CONF_OK;
446 }
447
448
449 static void *
ngx_http_srcache_create_main_conf(ngx_conf_t * cf)450 ngx_http_srcache_create_main_conf(ngx_conf_t *cf)
451 {
452 ngx_http_srcache_main_conf_t *smcf;
453
454 smcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_srcache_main_conf_t));
455 if (smcf == NULL) {
456 return NULL;
457 }
458
459 /* set by ngx_pcalloc:
460 * smcf->postponed_to_access_phase_end = 0;
461 * smcf->module_used = 0;
462 * smcf->headers_in_hash = { NULL, 0 };
463 */
464
465 return smcf;
466 }
467
468
469 static char *
ngx_http_srcache_init_main_conf(ngx_conf_t * cf,void * conf)470 ngx_http_srcache_init_main_conf(ngx_conf_t *cf, void *conf)
471 {
472 ngx_http_srcache_main_conf_t *smcf = conf;
473
474 ngx_array_t headers_in;
475 ngx_hash_key_t *hk;
476 ngx_hash_init_t hash;
477 ngx_http_srcache_header_t *header;
478
479 /* srcache_headers_in_hash */
480
481 if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
482 != NGX_OK)
483 {
484 return NGX_CONF_ERROR;
485 }
486
487 for (header = ngx_http_srcache_headers_in; header->name.len; header++) {
488 hk = ngx_array_push(&headers_in);
489 if (hk == NULL) {
490 return NGX_CONF_ERROR;
491 }
492
493 hk->key = header->name;
494 hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
495 hk->value = header;
496 }
497
498 hash.hash = &smcf->headers_in_hash;
499 hash.key = ngx_hash_key_lc;
500 hash.max_size = 512;
501 hash.bucket_size = ngx_align(64, ngx_cacheline_size);
502 hash.name = "srcache_headers_in_hash";
503 hash.pool = cf->pool;
504 hash.temp_pool = NULL;
505
506 if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
507 return NGX_CONF_ERROR;
508 }
509
510 return NGX_CONF_OK;
511 }
512
513
514 static ngx_int_t
ngx_http_srcache_post_config(ngx_conf_t * cf)515 ngx_http_srcache_post_config(ngx_conf_t *cf)
516 {
517 int multi_http_blocks;
518 ngx_int_t rc;
519 ngx_http_handler_pt *h;
520 ngx_http_core_main_conf_t *cmcf;
521 ngx_http_srcache_main_conf_t *smcf;
522
523 rc = ngx_http_srcache_add_variables(cf);
524 if (rc != NGX_OK) {
525 return rc;
526 }
527
528 smcf = ngx_http_conf_get_module_main_conf(cf,
529 ngx_http_srcache_filter_module);
530
531 if (ngx_http_srcache_prev_cycle != ngx_cycle) {
532 ngx_http_srcache_prev_cycle = ngx_cycle;
533 multi_http_blocks = 0;
534
535 } else {
536 multi_http_blocks = 1;
537 }
538
539 if (multi_http_blocks || smcf->module_used) {
540
541 dd("using ngx-srcache");
542
543 /* register our output filters */
544 rc = ngx_http_srcache_filter_init(cf);
545 if (rc != NGX_OK) {
546 return rc;
547 }
548
549 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
550
551 /* register our access phase handler */
552
553 h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
554 if (h == NULL) {
555 return NGX_ERROR;
556 }
557
558 *h = ngx_http_srcache_access_handler;
559 }
560
561 return NGX_OK;
562 }
563
564
565 static char *
ngx_http_srcache_store_statuses(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)566 ngx_http_srcache_store_statuses(ngx_conf_t *cf, ngx_command_t *cmd,
567 void *conf)
568 {
569 ngx_http_srcache_loc_conf_t *slcf = conf;
570
571 ngx_uint_t i, n;
572 ngx_int_t status;
573 ngx_str_t *value;
574
575 value = cf->args->elts;
576
577 if (slcf->store_statuses) {
578 return "is duplicate";
579 }
580
581 n = cf->args->nelts - 1;
582
583 slcf->store_statuses = ngx_pnalloc(cf->pool, (n + 1) * sizeof(ngx_int_t));
584 if (slcf->store_statuses == NULL) {
585 return NGX_CONF_ERROR;
586 }
587
588 for (i = 1; i <= n; i++) {
589 status = ngx_atoi(value[i].data, value[i].len);
590 if (status == NGX_ERROR) {
591 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
592 "status code \"%V\" is an invalid number",
593 &value[i]);
594
595 return NGX_CONF_ERROR;
596 }
597
598 if (status < 0) {
599 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
600 "status code \"%V\" is not a positive number",
601 &value[i]);
602
603 return NGX_CONF_ERROR;
604 }
605
606 slcf->store_statuses[i - 1] = status;
607 }
608
609 slcf->store_statuses[i - 1] = 0;
610
611 ngx_sort(slcf->store_statuses, n, sizeof(ngx_int_t),
612 ngx_http_srcache_cmp_int);
613
614 #if 0
615 for (i = 0; i < n; i++) {
616 dd("status: %d", (int) slcf->store_statuses[i]);
617 }
618 #endif
619
620 return NGX_CONF_OK;
621 }
622
623 /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
624