Mercurial > hg > nginx-ranges
comparison src/http/ngx_http.c @ 0:f0b350454894 NGINX_0_1_0
nginx 0.1.0
*) The first public version.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 04 Oct 2004 00:00:00 +0400 |
parents | |
children | 4b2dafa26fe2 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0b350454894 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); | |
14 static char *ngx_http_merge_locations(ngx_conf_t *cf, | |
15 ngx_array_t *locations, | |
16 void **loc_conf, | |
17 ngx_http_module_t *module, | |
18 ngx_uint_t ctx_index); | |
19 | |
20 int ngx_http_max_module; | |
21 | |
22 ngx_uint_t ngx_http_total_requests; | |
23 uint64_t ngx_http_total_sent; | |
24 | |
25 | |
26 ngx_int_t (*ngx_http_top_header_filter) (ngx_http_request_t *r); | |
27 ngx_int_t (*ngx_http_top_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch); | |
28 | |
29 | |
30 static ngx_command_t ngx_http_commands[] = { | |
31 | |
32 {ngx_string("http"), | |
33 NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, | |
34 ngx_http_block, | |
35 0, | |
36 0, | |
37 NULL}, | |
38 | |
39 ngx_null_command | |
40 }; | |
41 | |
42 | |
43 static ngx_core_module_t ngx_http_module_ctx = { | |
44 ngx_string("http"), | |
45 NULL, | |
46 NULL | |
47 }; | |
48 | |
49 | |
50 ngx_module_t ngx_http_module = { | |
51 NGX_MODULE, | |
52 &ngx_http_module_ctx, /* module context */ | |
53 ngx_http_commands, /* module directives */ | |
54 NGX_CORE_MODULE, /* module type */ | |
55 NULL, /* init module */ | |
56 NULL /* init child */ | |
57 }; | |
58 | |
59 | |
60 static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
61 { | |
62 char *rv; | |
63 ngx_uint_t mi, m, s, l, p, a, n; | |
64 ngx_uint_t port_found, addr_found, virtual_names; | |
65 ngx_conf_t pcf; | |
66 ngx_array_t in_ports; | |
67 ngx_listening_t *ls; | |
68 ngx_http_listen_t *lscf; | |
69 ngx_http_module_t *module; | |
70 ngx_http_handler_pt *h; | |
71 ngx_http_conf_ctx_t *ctx; | |
72 ngx_http_in_port_t *in_port, *inport; | |
73 ngx_http_in_addr_t *in_addr, *inaddr; | |
74 ngx_http_server_name_t *s_name, *name; | |
75 ngx_http_core_srv_conf_t **cscfp, *cscf; | |
76 ngx_http_core_loc_conf_t *clcf; | |
77 ngx_http_core_main_conf_t *cmcf; | |
78 #if (WIN32) | |
79 ngx_iocp_conf_t *iocpcf; | |
80 #endif | |
81 | |
82 /* the main http context */ | |
83 ngx_test_null(ctx, | |
84 ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)), | |
85 NGX_CONF_ERROR); | |
86 | |
87 *(ngx_http_conf_ctx_t **) conf = ctx; | |
88 | |
89 /* count the number of the http modules and set up their indices */ | |
90 | |
91 ngx_http_max_module = 0; | |
92 for (m = 0; ngx_modules[m]; m++) { | |
93 if (ngx_modules[m]->type != NGX_HTTP_MODULE) { | |
94 continue; | |
95 } | |
96 | |
97 ngx_modules[m]->ctx_index = ngx_http_max_module++; | |
98 } | |
99 | |
100 /* the main http main_conf, it's the same in the all http contexts */ | |
101 ngx_test_null(ctx->main_conf, | |
102 ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module), | |
103 NGX_CONF_ERROR); | |
104 | |
105 /* the http null srv_conf, it's used to merge the server{}s' srv_conf's */ | |
106 ngx_test_null(ctx->srv_conf, | |
107 ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module), | |
108 NGX_CONF_ERROR); | |
109 | |
110 /* the http null loc_conf, it's used to merge the server{}s' loc_conf's */ | |
111 ngx_test_null(ctx->loc_conf, | |
112 ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module), | |
113 NGX_CONF_ERROR); | |
114 | |
115 | |
116 /* create the main_conf, srv_conf and loc_conf in all http modules */ | |
117 | |
118 for (m = 0; ngx_modules[m]; m++) { | |
119 if (ngx_modules[m]->type != NGX_HTTP_MODULE) { | |
120 continue; | |
121 } | |
122 | |
123 module = ngx_modules[m]->ctx; | |
124 mi = ngx_modules[m]->ctx_index; | |
125 | |
126 if (module->pre_conf) { | |
127 if (module->pre_conf(cf) != NGX_OK) { | |
128 return NGX_CONF_ERROR; | |
129 } | |
130 } | |
131 | |
132 if (module->create_main_conf) { | |
133 ngx_test_null(ctx->main_conf[mi], module->create_main_conf(cf), | |
134 NGX_CONF_ERROR); | |
135 } | |
136 | |
137 if (module->create_srv_conf) { | |
138 ngx_test_null(ctx->srv_conf[mi], module->create_srv_conf(cf), | |
139 NGX_CONF_ERROR); | |
140 } | |
141 | |
142 if (module->create_loc_conf) { | |
143 ngx_test_null(ctx->loc_conf[mi], module->create_loc_conf(cf), | |
144 NGX_CONF_ERROR); | |
145 } | |
146 } | |
147 | |
148 /* parse inside the http{} block */ | |
149 | |
150 pcf = *cf; | |
151 cf->ctx = ctx; | |
152 cf->module_type = NGX_HTTP_MODULE; | |
153 cf->cmd_type = NGX_HTTP_MAIN_CONF; | |
154 rv = ngx_conf_parse(cf, NULL); | |
155 | |
156 if (rv != NGX_CONF_OK) { | |
157 *cf = pcf; | |
158 return rv; | |
159 } | |
160 | |
161 /* | |
162 * init http{} main_conf's, merge the server{}s' srv_conf's | |
163 * and its location{}s' loc_conf's | |
164 */ | |
165 | |
166 cmcf = ctx->main_conf[ngx_http_core_module.ctx_index]; | |
167 cscfp = cmcf->servers.elts; | |
168 | |
169 for (m = 0; ngx_modules[m]; m++) { | |
170 if (ngx_modules[m]->type != NGX_HTTP_MODULE) { | |
171 continue; | |
172 } | |
173 | |
174 module = ngx_modules[m]->ctx; | |
175 mi = ngx_modules[m]->ctx_index; | |
176 | |
177 /* init http{} main_conf's */ | |
178 | |
179 if (module->init_main_conf) { | |
180 rv = module->init_main_conf(cf, ctx->main_conf[mi]); | |
181 if (rv != NGX_CONF_OK) { | |
182 *cf = pcf; | |
183 return rv; | |
184 } | |
185 } | |
186 | |
187 for (s = 0; s < cmcf->servers.nelts; s++) { | |
188 | |
189 /* merge the server{}s' srv_conf's */ | |
190 | |
191 if (module->merge_srv_conf) { | |
192 rv = module->merge_srv_conf(cf, | |
193 ctx->srv_conf[mi], | |
194 cscfp[s]->ctx->srv_conf[mi]); | |
195 if (rv != NGX_CONF_OK) { | |
196 *cf = pcf; | |
197 return rv; | |
198 } | |
199 } | |
200 | |
201 if (module->merge_loc_conf) { | |
202 | |
203 /* merge the server{}'s loc_conf */ | |
204 | |
205 rv = module->merge_loc_conf(cf, | |
206 ctx->loc_conf[mi], | |
207 cscfp[s]->ctx->loc_conf[mi]); | |
208 if (rv != NGX_CONF_OK) { | |
209 *cf = pcf; | |
210 return rv; | |
211 } | |
212 | |
213 /* merge the locations{}' loc_conf's */ | |
214 | |
215 rv = ngx_http_merge_locations(cf, &cscfp[s]->locations, | |
216 cscfp[s]->ctx->loc_conf, | |
217 module, mi); | |
218 if (rv != NGX_CONF_OK) { | |
219 *cf = pcf; | |
220 return rv; | |
221 } | |
222 | |
223 #if 0 | |
224 clcfp = (ngx_http_core_loc_conf_t **) cscfp[s]->locations.elts; | |
225 | |
226 for (l = 0; l < cscfp[s]->locations.nelts; l++) { | |
227 rv = module->merge_loc_conf(cf, | |
228 cscfp[s]->ctx->loc_conf[mi], | |
229 clcfp[l]->loc_conf[mi]); | |
230 if (rv != NGX_CONF_OK) { | |
231 *cf = pcf; | |
232 return rv; | |
233 } | |
234 } | |
235 #endif | |
236 } | |
237 } | |
238 } | |
239 | |
240 /* we needed "http"'s cf->ctx while merging configuration */ | |
241 *cf = pcf; | |
242 | |
243 /* init lists of the handlers */ | |
244 | |
245 ngx_init_array(cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers, | |
246 cf->cycle->pool, 10, sizeof(ngx_http_handler_pt), | |
247 NGX_CONF_ERROR); | |
248 cmcf->phases[NGX_HTTP_REWRITE_PHASE].type = NGX_OK; | |
249 | |
250 | |
251 /* the special find config phase for single handler */ | |
252 | |
253 ngx_init_array(cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers, | |
254 cf->cycle->pool, 1, sizeof(ngx_http_handler_pt), | |
255 NGX_CONF_ERROR); | |
256 cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].type = NGX_OK; | |
257 | |
258 ngx_test_null(h, ngx_push_array( | |
259 &cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers), | |
260 NGX_CONF_ERROR); | |
261 *h = ngx_http_find_location_config; | |
262 | |
263 | |
264 ngx_init_array(cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers, | |
265 cf->cycle->pool, 10, sizeof(ngx_http_handler_pt), | |
266 NGX_CONF_ERROR); | |
267 cmcf->phases[NGX_HTTP_ACCESS_PHASE].type = NGX_DECLINED; | |
268 | |
269 | |
270 ngx_init_array(cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, | |
271 cf->cycle->pool, 10, sizeof(ngx_http_handler_pt), | |
272 NGX_CONF_ERROR); | |
273 cmcf->phases[NGX_HTTP_CONTENT_PHASE].type = NGX_OK; | |
274 | |
275 | |
276 /* | |
277 * create the lists of the ports, the addresses and the server names | |
278 * to allow quickly find the server core module configuration at run-time | |
279 */ | |
280 | |
281 ngx_init_array(in_ports, cf->pool, 10, sizeof(ngx_http_in_port_t), | |
282 NGX_CONF_ERROR); | |
283 | |
284 /* "server" directives */ | |
285 cscfp = cmcf->servers.elts; | |
286 for (s = 0; s < cmcf->servers.nelts; s++) { | |
287 | |
288 /* "listen" directives */ | |
289 lscf = cscfp[s]->listen.elts; | |
290 for (l = 0; l < cscfp[s]->listen.nelts; l++) { | |
291 | |
292 port_found = 0; | |
293 | |
294 /* AF_INET only */ | |
295 | |
296 in_port = in_ports.elts; | |
297 for (p = 0; p < in_ports.nelts; p++) { | |
298 | |
299 if (lscf[l].port == in_port[p].port) { | |
300 | |
301 /* the port is already in the port list */ | |
302 | |
303 port_found = 1; | |
304 addr_found = 0; | |
305 | |
306 in_addr = in_port[p].addrs.elts; | |
307 for (a = 0; a < in_port[p].addrs.nelts; a++) { | |
308 | |
309 if (lscf[l].addr == in_addr[a].addr) { | |
310 | |
311 /* the address is already bound to this port */ | |
312 | |
313 /* "server_name" directives */ | |
314 s_name = cscfp[s]->server_names.elts; | |
315 for (n = 0; n < cscfp[s]->server_names.nelts; n++) { | |
316 | |
317 /* | |
318 * add the server name and server core module | |
319 * configuration to the address:port | |
320 */ | |
321 | |
322 /* TODO: duplicate names can be checked here */ | |
323 | |
324 ngx_test_null(name, | |
325 ngx_push_array(&in_addr[a].names), | |
326 NGX_CONF_ERROR); | |
327 | |
328 name->name = s_name[n].name; | |
329 name->core_srv_conf = s_name[n].core_srv_conf; | |
330 } | |
331 | |
332 /* | |
333 * check duplicate "default" server that | |
334 * serves this address:port | |
335 */ | |
336 | |
337 if (lscf[l].default_server) { | |
338 if (in_addr[a].default_server) { | |
339 ngx_log_error(NGX_LOG_ERR, cf->log, 0, | |
340 "duplicate default server in %s:%d", | |
341 lscf[l].file_name.data, | |
342 lscf[l].line); | |
343 | |
344 return NGX_CONF_ERROR; | |
345 } | |
346 | |
347 in_addr[a].core_srv_conf = cscfp[s]; | |
348 in_addr[a].default_server = 1; | |
349 } | |
350 | |
351 addr_found = 1; | |
352 | |
353 break; | |
354 | |
355 } else if (in_addr[a].addr == INADDR_ANY) { | |
356 | |
357 /* | |
358 * "*:port" must be the last resort so move it | |
359 * to the end of the address list and add | |
360 * the new address at its place | |
361 */ | |
362 | |
363 ngx_test_null(inaddr, | |
364 ngx_push_array(&in_port[p].addrs), | |
365 NGX_CONF_ERROR); | |
366 | |
367 ngx_memcpy(inaddr, &in_addr[a], | |
368 sizeof(ngx_http_in_addr_t)); | |
369 | |
370 in_addr[a].addr = lscf[l].addr; | |
371 in_addr[a].default_server = lscf[l].default_server; | |
372 in_addr[a].core_srv_conf = cscfp[s]; | |
373 | |
374 /* | |
375 * create the empty list of the server names that | |
376 * can be served on this address:port | |
377 */ | |
378 | |
379 ngx_init_array(inaddr->names, cf->pool, 10, | |
380 sizeof(ngx_http_server_name_t), | |
381 NGX_CONF_ERROR); | |
382 | |
383 addr_found = 1; | |
384 | |
385 break; | |
386 } | |
387 } | |
388 | |
389 if (!addr_found) { | |
390 | |
391 /* | |
392 * add the address to the addresses list that | |
393 * bound to this port | |
394 */ | |
395 | |
396 ngx_test_null(inaddr, | |
397 ngx_push_array(&in_port[p].addrs), | |
398 NGX_CONF_ERROR); | |
399 | |
400 inaddr->addr = lscf[l].addr; | |
401 inaddr->default_server = lscf[l].default_server; | |
402 inaddr->core_srv_conf = cscfp[s]; | |
403 | |
404 /* | |
405 * create the empty list of the server names that | |
406 * can be served on this address:port | |
407 */ | |
408 | |
409 ngx_init_array(inaddr->names, cf->pool, 10, | |
410 sizeof(ngx_http_server_name_t), | |
411 NGX_CONF_ERROR); | |
412 } | |
413 } | |
414 } | |
415 | |
416 if (!port_found) { | |
417 | |
418 /* add the port to the in_port list */ | |
419 | |
420 ngx_test_null(in_port, | |
421 ngx_push_array(&in_ports), | |
422 NGX_CONF_ERROR); | |
423 | |
424 in_port->port = lscf[l].port; | |
425 | |
426 ngx_test_null(in_port->port_text.data, ngx_palloc(cf->pool, 7), | |
427 NGX_CONF_ERROR); | |
428 in_port->port_text.len = ngx_snprintf((char *) | |
429 in_port->port_text.data, | |
430 7, ":%d", | |
431 in_port->port); | |
432 | |
433 /* create list of the addresses that bound to this port ... */ | |
434 | |
435 ngx_init_array(in_port->addrs, cf->pool, 10, | |
436 sizeof(ngx_http_in_addr_t), | |
437 NGX_CONF_ERROR); | |
438 | |
439 ngx_test_null(inaddr, ngx_push_array(&in_port->addrs), | |
440 NGX_CONF_ERROR); | |
441 | |
442 /* ... and add the address to this list */ | |
443 | |
444 inaddr->addr = lscf[l].addr; | |
445 inaddr->default_server = lscf[l].default_server; | |
446 inaddr->core_srv_conf = cscfp[s]; | |
447 | |
448 /* | |
449 * create the empty list of the server names that | |
450 * can be served on this address:port | |
451 */ | |
452 | |
453 ngx_init_array(inaddr->names, cf->pool, 10, | |
454 sizeof(ngx_http_server_name_t), | |
455 NGX_CONF_ERROR); | |
456 } | |
457 } | |
458 } | |
459 | |
460 /* optimize the lists of the ports, the addresses and the server names */ | |
461 | |
462 /* AF_INET only */ | |
463 | |
464 in_port = in_ports.elts; | |
465 for (p = 0; p < in_ports.nelts; p++) { | |
466 | |
467 /* check whether the all server names point to the same server */ | |
468 | |
469 in_addr = in_port[p].addrs.elts; | |
470 for (a = 0; a < in_port[p].addrs.nelts; a++) { | |
471 | |
472 virtual_names = 0; | |
473 | |
474 name = in_addr[a].names.elts; | |
475 for (n = 0; n < in_addr[a].names.nelts; n++) { | |
476 if (in_addr[a].core_srv_conf != name[n].core_srv_conf) { | |
477 virtual_names = 1; | |
478 break; | |
479 } | |
480 } | |
481 | |
482 /* | |
483 * if the all server names point to the same server | |
484 * then we do not need to check them at run-time | |
485 */ | |
486 | |
487 if (!virtual_names) { | |
488 in_addr[a].names.nelts = 0; | |
489 } | |
490 } | |
491 | |
492 /* | |
493 * if there's the binding to "*:port" then we need to bind() | |
494 * to "*:port" only and ignore the other bindings | |
495 */ | |
496 | |
497 if (in_addr[a - 1].addr == INADDR_ANY) { | |
498 a--; | |
499 | |
500 } else { | |
501 a = 0; | |
502 } | |
503 | |
504 in_addr = in_port[p].addrs.elts; | |
505 while (a < in_port[p].addrs.nelts) { | |
506 | |
507 ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr, | |
508 in_port[p].port); | |
509 if (ls == NULL) { | |
510 return NGX_CONF_ERROR; | |
511 } | |
512 | |
513 ls->backlog = -1; | |
514 #if 0 | |
515 #if 0 | |
516 ls->nonblocking = 1; | |
517 #else | |
518 ls->nonblocking = 0; | |
519 #endif | |
520 #endif | |
521 ls->addr_ntop = 1; | |
522 | |
523 ls->handler = ngx_http_init_connection; | |
524 | |
525 cscf = in_addr[a].core_srv_conf; | |
526 ls->pool_size = cscf->connection_pool_size; | |
527 ls->post_accept_timeout = cscf->post_accept_timeout; | |
528 | |
529 clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; | |
530 ls->log = clcf->err_log; | |
531 | |
532 #if (WIN32) | |
533 iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); | |
534 if (iocpcf->acceptex_read) { | |
535 ls->post_accept_buffer_size = cscf->client_header_buffer_size; | |
536 } | |
537 #endif | |
538 | |
539 ls->ctx = ctx; | |
540 | |
541 if (in_port[p].addrs.nelts > 1) { | |
542 | |
543 in_addr = in_port[p].addrs.elts; | |
544 if (in_addr[in_port[p].addrs.nelts - 1].addr != INADDR_ANY) { | |
545 | |
546 /* | |
547 * if this port has not the "*:port" binding then create | |
548 * the separate ngx_http_in_port_t for the all bindings | |
549 */ | |
550 | |
551 ngx_test_null(inport, | |
552 ngx_palloc(cf->pool, | |
553 sizeof(ngx_http_in_port_t)), | |
554 NGX_CONF_ERROR); | |
555 | |
556 inport->port = in_port[p].port; | |
557 inport->port_text = in_port[p].port_text; | |
558 | |
559 /* init list of the addresses ... */ | |
560 | |
561 ngx_init_array(inport->addrs, cf->pool, 1, | |
562 sizeof(ngx_http_in_addr_t), | |
563 NGX_CONF_ERROR); | |
564 | |
565 /* ... and set up it with the first address */ | |
566 | |
567 inport->addrs.nelts = 1; | |
568 inport->addrs.elts = in_port[p].addrs.elts; | |
569 | |
570 ls->servers = inport; | |
571 | |
572 /* prepare for the next cycle */ | |
573 | |
574 in_port[p].addrs.elts = (char *) in_port[p].addrs.elts | |
575 + in_port[p].addrs.size; | |
576 in_port[p].addrs.nelts--; | |
577 | |
578 in_addr = (ngx_http_in_addr_t *) in_port[p].addrs.elts; | |
579 a = 0; | |
580 | |
581 continue; | |
582 } | |
583 } | |
584 | |
585 ls->servers = &in_port[p]; | |
586 a++; | |
587 } | |
588 } | |
589 | |
590 #if (NGX_DEBUG) | |
591 in_port = in_ports.elts; | |
592 for (p = 0; p < in_ports.nelts; p++) { | |
593 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, | |
594 "port: %d %08x", in_port[p].port, &in_port[p]); | |
595 in_addr = in_port[p].addrs.elts; | |
596 for (a = 0; a < in_port[p].addrs.nelts; a++) { | |
597 u_char ip[20]; | |
598 ngx_inet_ntop(AF_INET, &in_addr[a].addr, ip, 20); | |
599 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, | |
600 "%s %08x", ip, in_addr[a].core_srv_conf); | |
601 s_name = in_addr[a].names.elts; | |
602 for (n = 0; n < in_addr[a].names.nelts; n++) { | |
603 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, | |
604 "%s %08x", s_name[n].name.data, | |
605 s_name[n].core_srv_conf); | |
606 } | |
607 } | |
608 } | |
609 #endif | |
610 | |
611 return NGX_CONF_OK; | |
612 } | |
613 | |
614 | |
615 static char *ngx_http_merge_locations(ngx_conf_t *cf, | |
616 ngx_array_t *locations, | |
617 void **loc_conf, | |
618 ngx_http_module_t *module, | |
619 ngx_uint_t ctx_index) | |
620 { | |
621 char *rv; | |
622 ngx_uint_t i; | |
623 ngx_http_core_loc_conf_t **clcfp; | |
624 | |
625 clcfp = /* (ngx_http_core_loc_conf_t **) */ locations->elts; | |
626 | |
627 for (i = 0; i < locations->nelts; i++) { | |
628 rv = module->merge_loc_conf(cf, loc_conf[ctx_index], | |
629 clcfp[i]->loc_conf[ctx_index]); | |
630 if (rv != NGX_CONF_OK) { | |
631 return rv; | |
632 } | |
633 | |
634 rv = ngx_http_merge_locations(cf, &clcfp[i]->locations, | |
635 clcfp[i]->loc_conf, module, ctx_index); | |
636 if (rv != NGX_CONF_OK) { | |
637 return rv; | |
638 } | |
639 } | |
640 | |
641 return NGX_CONF_OK; | |
642 } |