1 /*
2  * Copyright (c) 2010, FRiCKLE Piotr Sikora <info@frickle.com>
3  * Copyright (c) 2009-2010, Xiaozhe Wang <chaoslawful@gmail.com>
4  * Copyright (c) 2009-2010, Yichun Zhang <agentzh@gmail.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #ifndef DDEBUG
30 #define DDEBUG 0
31 #endif
32 
33 #include "ngx_postgres_ddebug.h"
34 #include "ngx_postgres_escape.h"
35 #include "ngx_postgres_handler.h"
36 #include "ngx_postgres_keepalive.h"
37 #include "ngx_postgres_module.h"
38 #include "ngx_postgres_output.h"
39 #include "ngx_postgres_upstream.h"
40 #include "ngx_postgres_util.h"
41 #include "ngx_postgres_variable.h"
42 #include "ngx_postgres_rewrite.h"
43 
44 
45 #define NGX_CONF_TAKE34  (NGX_CONF_TAKE3|NGX_CONF_TAKE4)
46 
47 
48 static ngx_command_t ngx_postgres_module_commands[] = {
49 
50     { ngx_string("postgres_server"),
51       NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
52       ngx_postgres_conf_server,
53       NGX_HTTP_SRV_CONF_OFFSET,
54       0,
55       NULL },
56 
57     { ngx_string("postgres_keepalive"),
58       NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
59       ngx_postgres_conf_keepalive,
60       NGX_HTTP_SRV_CONF_OFFSET,
61       0,
62       NULL },
63 
64     { ngx_string("postgres_pass"),
65       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
66       ngx_postgres_conf_pass,
67       NGX_HTTP_LOC_CONF_OFFSET,
68       0,
69       NULL },
70 
71     { ngx_string("postgres_query"),
72       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|
73           NGX_HTTP_LIF_CONF|NGX_CONF_1MORE,
74       ngx_postgres_conf_query,
75       NGX_HTTP_LOC_CONF_OFFSET,
76       0,
77       NULL },
78 
79     { ngx_string("postgres_rewrite"),
80       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|
81           NGX_HTTP_LIF_CONF|NGX_CONF_2MORE,
82       ngx_postgres_conf_rewrite,
83       NGX_HTTP_LOC_CONF_OFFSET,
84       0,
85       NULL },
86 
87     { ngx_string("postgres_output"),
88       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|
89           NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
90       ngx_postgres_conf_output,
91       NGX_HTTP_LOC_CONF_OFFSET,
92       0,
93       NULL },
94 
95     { ngx_string("postgres_set"),
96       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE34,
97       ngx_postgres_conf_set,
98       NGX_HTTP_LOC_CONF_OFFSET,
99       0,
100       NULL },
101 
102     { ngx_string("postgres_escape"),
103       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
104       ngx_postgres_conf_escape,
105       NGX_HTTP_LOC_CONF_OFFSET,
106       0,
107       NULL },
108 
109     { ngx_string("postgres_connect_timeout"),
110       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
111       ngx_conf_set_msec_slot,
112       NGX_HTTP_LOC_CONF_OFFSET,
113       offsetof(ngx_postgres_loc_conf_t, upstream.connect_timeout),
114       NULL },
115 
116     { ngx_string("postgres_result_timeout"),
117       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
118       ngx_conf_set_msec_slot,
119       NGX_HTTP_LOC_CONF_OFFSET,
120       offsetof(ngx_postgres_loc_conf_t, upstream.read_timeout),
121       NULL },
122 
123       ngx_null_command
124 };
125 
126 static ngx_http_variable_t ngx_postgres_module_variables[] = {
127 
128     { ngx_string("postgres_columns"), NULL,
129       ngx_postgres_variable_columns, 0,
130       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
131 
132     { ngx_string("postgres_rows"), NULL,
133       ngx_postgres_variable_rows, 0,
134       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
135 
136     { ngx_string("postgres_affected"), NULL,
137       ngx_postgres_variable_affected, 0,
138       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
139 
140     { ngx_string("postgres_query"), NULL,
141       ngx_postgres_variable_query, 0,
142       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
143 
144     { ngx_null_string, NULL, NULL, 0, 0, 0 }
145 };
146 
147 static ngx_http_module_t ngx_postgres_module_ctx = {
148     ngx_postgres_add_variables,             /* preconfiguration */
149     NULL,                                   /* postconfiguration */
150 
151     NULL,                                   /* create main configuration */
152     NULL,                                   /* init main configuration */
153 
154     ngx_postgres_create_upstream_srv_conf,  /* create server configuration */
155     NULL,                                   /* merge server configuration */
156 
157     ngx_postgres_create_loc_conf,           /* create location configuration */
158     ngx_postgres_merge_loc_conf             /* merge location configuration */
159 };
160 
161 ngx_module_t ngx_postgres_module = {
162     NGX_MODULE_V1,
163     &ngx_postgres_module_ctx,      /* module context */
164     ngx_postgres_module_commands,  /* module directives */
165     NGX_HTTP_MODULE,               /* module type */
166     NULL,                          /* init master */
167     NULL,                          /* init module */
168     NULL,                          /* init process */
169     NULL,                          /* init thread */
170     NULL,                          /* exit thread */
171     NULL,                          /* exit process */
172     NULL,                          /* exit master */
173     NGX_MODULE_V1_PADDING
174 };
175 
176 ngx_conf_bitmask_t ngx_postgres_http_methods[] = {
177    { ngx_string("GET"),       NGX_HTTP_GET },
178    { ngx_string("HEAD"),      NGX_HTTP_HEAD },
179    { ngx_string("POST"),      NGX_HTTP_POST },
180    { ngx_string("PUT"),       NGX_HTTP_PUT },
181    { ngx_string("DELETE"),    NGX_HTTP_DELETE },
182    { ngx_string("MKCOL"),     NGX_HTTP_MKCOL },
183    { ngx_string("COPY"),      NGX_HTTP_COPY },
184    { ngx_string("MOVE"),      NGX_HTTP_MOVE },
185    { ngx_string("OPTIONS"),   NGX_HTTP_OPTIONS },
186    { ngx_string("PROPFIND"),  NGX_HTTP_PROPFIND },
187    { ngx_string("PROPPATCH"), NGX_HTTP_PROPPATCH },
188    { ngx_string("LOCK"),      NGX_HTTP_LOCK },
189    { ngx_string("UNLOCK"),    NGX_HTTP_UNLOCK },
190 #if defined(nginx_version) && (nginx_version >= 8041)
191    { ngx_string("PATCH"),     NGX_HTTP_PATCH },
192 #endif
193     { ngx_null_string, 0 }
194 };
195 
196 ngx_conf_enum_t ngx_postgres_upstream_mode_options[] = {
197     { ngx_string("multi"),  0 },
198     { ngx_string("single"), 1 },
199     { ngx_null_string, 0 }
200 };
201 
202 ngx_conf_enum_t ngx_postgres_upstream_overflow_options[] = {
203     { ngx_string("ignore"), 0 },
204     { ngx_string("reject"), 1 },
205     { ngx_null_string, 0 }
206 };
207 
208 ngx_conf_enum_t ngx_postgres_requirement_options[] = {
209     { ngx_string("optional"), 0 },
210     { ngx_string("required"), 1 },
211     { ngx_null_string, 0 }
212 };
213 
214 ngx_postgres_rewrite_enum_t ngx_postgres_rewrite_handlers[] = {
215     { ngx_string("no_changes"), 0, ngx_postgres_rewrite_changes },
216     { ngx_string("changes"),    1, ngx_postgres_rewrite_changes },
217     { ngx_string("no_rows"),    2, ngx_postgres_rewrite_rows },
218     { ngx_string("rows"),       3, ngx_postgres_rewrite_rows },
219     { ngx_string("no_errors"),  4, ngx_postgres_rewrite_valid },
220     { ngx_string("errors"),     5, ngx_postgres_rewrite_valid },
221     { ngx_null_string, 0, NULL }
222 };
223 
224 ngx_postgres_output_enum_t ngx_postgres_output_handlers[] = {
225     { ngx_string("none"),         0, NULL },
226     { ngx_string("rds"),          0, ngx_postgres_output_rds },
227     { ngx_string("text") ,        0, ngx_postgres_output_text },
228     { ngx_string("value"),        0, ngx_postgres_output_value },
229     { ngx_string("binary_value"), 1, ngx_postgres_output_value },
230     { ngx_string("json"),         0, ngx_postgres_output_json },
231     { ngx_string("hex"),          0, ngx_postgres_output_hex },
232     { ngx_null_string, 0, NULL }
233 };
234 
235 
236 ngx_int_t
ngx_postgres_add_variables(ngx_conf_t * cf)237 ngx_postgres_add_variables(ngx_conf_t *cf)
238 {
239     ngx_http_variable_t  *var, *v;
240 
241     dd("entering");
242 
243     for (v = ngx_postgres_module_variables; v->name.len; v++) {
244         var = ngx_http_add_variable(cf, &v->name, v->flags);
245         if (var == NULL) {
246             dd("returning NGX_ERROR");
247             return NGX_ERROR;
248         }
249 
250         var->get_handler = v->get_handler;
251         var->data = v->data;
252     }
253 
254     dd("returning NGX_OK");
255     return NGX_OK;
256 }
257 
258 void *
ngx_postgres_create_upstream_srv_conf(ngx_conf_t * cf)259 ngx_postgres_create_upstream_srv_conf(ngx_conf_t *cf)
260 {
261     ngx_postgres_upstream_srv_conf_t  *conf;
262     ngx_pool_cleanup_t                *cln;
263 
264     dd("entering");
265 
266     conf = ngx_pcalloc(cf->pool, sizeof(ngx_postgres_upstream_srv_conf_t));
267     if (conf == NULL) {
268         dd("returning NULL");
269         return NULL;
270     }
271 
272     /*
273      * set by ngx_pcalloc():
274      *
275      *     conf->peers = NULL
276      *     conf->current = 0
277      *     conf->servers = NULL
278      *     conf->free = { NULL, NULL }
279      *     conf->cache = { NULL, NULL }
280      *     conf->active_conns = 0
281      *     conf->reject = 0
282      */
283 
284     conf->pool = cf->pool;
285 
286     /* enable keepalive (single) by default */
287     conf->max_cached = 10;
288     conf->single = 1;
289 
290     cln = ngx_pool_cleanup_add(cf->pool, 0);
291     cln->handler = ngx_postgres_keepalive_cleanup;
292     cln->data = conf;
293 
294     dd("returning");
295     return conf;
296 }
297 
298 void *
ngx_postgres_create_loc_conf(ngx_conf_t * cf)299 ngx_postgres_create_loc_conf(ngx_conf_t *cf)
300 {
301     ngx_postgres_loc_conf_t  *conf;
302 
303     dd("entering");
304 
305     conf = ngx_pcalloc(cf->pool, sizeof(ngx_postgres_loc_conf_t));
306     if (conf == NULL) {
307         dd("returning NULL");
308         return NULL;
309     }
310 
311     /*
312      * set by ngx_pcalloc():
313      *
314      *     conf->upstream.* = 0 / NULL
315      *     conf->upstream_cv = NULL
316      *     conf->query.methods_set = 0
317      *     conf->query.methods = NULL
318      *     conf->query.def = NULL
319      *     conf->output_binary = 0
320      */
321 
322     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
323     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
324 
325     conf->rewrites = NGX_CONF_UNSET_PTR;
326     conf->output_handler = NGX_CONF_UNSET_PTR;
327     conf->variables = NGX_CONF_UNSET_PTR;
328 
329     /* the hardcoded values */
330     conf->upstream.cyclic_temp_file = 0;
331     conf->upstream.buffering = 1;
332     conf->upstream.ignore_client_abort = 1;
333     conf->upstream.send_lowat = 0;
334     conf->upstream.bufs.num = 0;
335     conf->upstream.busy_buffers_size = 0;
336     conf->upstream.max_temp_file_size = 0;
337     conf->upstream.temp_file_write_size = 0;
338     conf->upstream.intercept_errors = 1;
339     conf->upstream.intercept_404 = 1;
340     conf->upstream.pass_request_headers = 0;
341     conf->upstream.pass_request_body = 0;
342 
343     dd("returning");
344     return conf;
345 }
346 
347 char *
ngx_postgres_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)348 ngx_postgres_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
349 {
350     ngx_postgres_loc_conf_t  *prev = parent;
351     ngx_postgres_loc_conf_t  *conf = child;
352 
353     dd("entering");
354 
355     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
356                               prev->upstream.connect_timeout, 10000);
357 
358     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
359                               prev->upstream.read_timeout, 30000);
360 
361     if ((conf->upstream.upstream == NULL) && (conf->upstream_cv == NULL)) {
362         conf->upstream.upstream = prev->upstream.upstream;
363         conf->upstream_cv = prev->upstream_cv;
364     }
365 
366     if ((conf->query.def == NULL) && (conf->query.methods == NULL)) {
367         conf->query.methods_set = prev->query.methods_set;
368         conf->query.methods = prev->query.methods;
369         conf->query.def = prev->query.def;
370     }
371 
372     ngx_conf_merge_ptr_value(conf->rewrites, prev->rewrites, NULL);
373 
374     if (conf->output_handler == NGX_CONF_UNSET_PTR) {
375         if (prev->output_handler == NGX_CONF_UNSET_PTR) {
376             /* default */
377             conf->output_handler = ngx_postgres_output_rds;
378             conf->output_binary = 0;
379         } else {
380             /* merge */
381             conf->output_handler = prev->output_handler;
382             conf->output_binary = prev->output_binary;
383         }
384     }
385 
386     ngx_conf_merge_ptr_value(conf->variables, prev->variables, NULL);
387 
388     dd("returning NGX_CONF_OK");
389     return NGX_CONF_OK;
390 }
391 
392 /*
393  * Based on: ngx_http_upstream.c/ngx_http_upstream_server
394  * Copyright (C) Igor Sysoev
395  */
396 char *
ngx_postgres_conf_server(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)397 ngx_postgres_conf_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
398 {
399     ngx_str_t                         *value = cf->args->elts;
400     ngx_postgres_upstream_srv_conf_t  *pgscf = conf;
401     ngx_postgres_upstream_server_t    *pgs;
402     ngx_http_upstream_srv_conf_t      *uscf;
403     ngx_url_t                          u;
404     ngx_uint_t                         i;
405 
406     dd("entering");
407 
408     uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
409 
410     if (pgscf->servers == NULL) {
411         pgscf->servers = ngx_array_create(cf->pool, 4,
412                              sizeof(ngx_postgres_upstream_server_t));
413         if (pgscf->servers == NULL) {
414             dd("returning NGX_CONF_ERROR");
415             return NGX_CONF_ERROR;
416         }
417 
418         uscf->servers = pgscf->servers;
419     }
420 
421     pgs = ngx_array_push(pgscf->servers);
422     if (pgs == NULL) {
423         dd("returning NGX_CONF_ERROR");
424         return NGX_CONF_ERROR;
425     }
426 
427     ngx_memzero(pgs, sizeof(ngx_postgres_upstream_server_t));
428 
429     /* parse the first name:port argument */
430 
431     ngx_memzero(&u, sizeof(ngx_url_t));
432 
433     u.url = value[1];
434     u.default_port = 5432; /* PostgreSQL default */
435 
436     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
437         if (u.err) {
438             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
439                                "postgres: %s in upstream \"%V\"",
440                                u.err, &u.url);
441         }
442 
443         dd("returning NGX_CONF_ERROR");
444         return NGX_CONF_ERROR;
445     }
446 
447     pgs->addrs = u.addrs;
448     pgs->naddrs = u.naddrs;
449     pgs->port = u.family == AF_UNIX ? u.default_port : u.port;
450     pgs->family = u.family;
451 
452     /* parse various options */
453     for (i = 2; i < cf->args->nelts; i++) {
454 
455         if (ngx_strncmp(value[i].data, "port=", sizeof("port=") - 1)
456                 == 0)
457         {
458             pgs->port = (in_port_t) ngx_atoi(&value[i].data[sizeof("port=") - 1], value[i].len - (sizeof("port=") - 1));
459             continue;
460         }
461 
462         if (ngx_strncmp(value[i].data, "dbname=", sizeof("dbname=") - 1)
463                 == 0)
464         {
465             pgs->dbname.len = value[i].len - (sizeof("dbname=") - 1);
466             pgs->dbname.data = &value[i].data[sizeof("dbname=") - 1];
467             continue;
468         }
469 
470         if (ngx_strncmp(value[i].data, "user=", sizeof("user=") - 1)
471                 == 0)
472         {
473             pgs->user.len = value[i].len - (sizeof("user=") - 1);
474             pgs->user.data = &value[i].data[sizeof("user=") - 1];
475             continue;
476         }
477 
478         if (ngx_strncmp(value[i].data, "password=", sizeof("password=") - 1)
479                 == 0)
480         {
481             pgs->password.len = value[i].len - (sizeof("password=") - 1);
482             pgs->password.data = &value[i].data[sizeof("password=") - 1];
483             continue;
484         }
485 
486         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
487                            "postgres: invalid parameter \"%V\" in"
488                            " \"postgres_server\"", &value[i]);
489 
490         dd("returning NGX_CONF_ERROR");
491         return NGX_CONF_ERROR;
492     }
493 
494     uscf->peer.init_upstream = ngx_postgres_upstream_init;
495 
496     dd("returning NGX_CONF_OK");
497     return NGX_CONF_OK;
498 }
499 
500 char *
ngx_postgres_conf_keepalive(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)501 ngx_postgres_conf_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
502 {
503     ngx_str_t                         *value = cf->args->elts;
504     ngx_postgres_upstream_srv_conf_t  *pgscf = conf;
505     ngx_conf_enum_t                   *e;
506     ngx_uint_t                         i, j;
507     ngx_int_t                          n;
508 
509     dd("entering");
510 
511     if (pgscf->max_cached != 10 /* default */) {
512         dd("returning");
513         return "is duplicate";
514     }
515 
516     if ((cf->args->nelts == 2) && (ngx_strcmp(value[1].data, "off") == 0)) {
517         pgscf->max_cached = 0;
518 
519         dd("returning NGX_CONF_OK");
520         return NGX_CONF_OK;
521     }
522 
523     for (i = 1; i < cf->args->nelts; i++) {
524 
525         if (ngx_strncmp(value[i].data, "max=", sizeof("max=") - 1)
526                 == 0)
527         {
528             value[i].len = value[i].len - (sizeof("max=") - 1);
529             value[i].data = &value[i].data[sizeof("max=") - 1];
530 
531             n = ngx_atoi(value[i].data, value[i].len);
532             if (n == NGX_ERROR) {
533                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
534                                    "postgres: invalid \"max\" value \"%V\""
535                                    " in \"%V\" directive",
536                                    &value[i], &cmd->name);
537 
538                 dd("returning NGX_CONF_ERROR");
539                 return NGX_CONF_ERROR;
540             }
541 
542             pgscf->max_cached = (ngx_uint_t) n;
543 
544             continue;
545         }
546 
547         if (ngx_strncmp(value[i].data, "mode=", sizeof("mode=") - 1)
548                 == 0)
549         {
550             value[i].len = value[i].len - (sizeof("mode=") - 1);
551             value[i].data = &value[i].data[sizeof("mode=") - 1];
552 
553             e = ngx_postgres_upstream_mode_options;
554             for (j = 0; e[j].name.len; j++) {
555                 if ((e[j].name.len == value[i].len)
556                     && (ngx_strcasecmp(e[j].name.data, value[i].data) == 0))
557                 {
558                     pgscf->single = e[j].value;
559                     break;
560                 }
561             }
562 
563             if (e[j].name.len == 0) {
564                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
565                                    "postgres: invalid \"mode\" value \"%V\""
566                                    " in \"%V\" directive",
567                                    &value[i], &cmd->name);
568 
569                 dd("returning NGX_CONF_ERROR");
570                 return NGX_CONF_ERROR;
571             }
572 
573             continue;
574         }
575 
576         if (ngx_strncmp(value[i].data, "overflow=", sizeof("overflow=") - 1)
577                 == 0)
578         {
579             value[i].len = value[i].len - (sizeof("overflow=") - 1);
580             value[i].data = &value[i].data[sizeof("overflow=") - 1];
581 
582             e = ngx_postgres_upstream_overflow_options;
583             for (j = 0; e[j].name.len; j++) {
584                 if ((e[j].name.len == value[i].len)
585                     && (ngx_strcasecmp(e[j].name.data, value[i].data) == 0))
586                 {
587                     pgscf->reject = e[j].value;
588                     break;
589                 }
590             }
591 
592             if (e[j].name.len == 0) {
593                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
594                                    "postgres: invalid \"overflow\" value \"%V\""
595                                    " in \"%V\" directive",
596                                    &value[i], &cmd->name);
597 
598                 dd("returning NGX_CONF_ERROR");
599                 return NGX_CONF_ERROR;
600             }
601 
602             continue;
603         }
604 
605         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
606                            "postgres: invalid parameter \"%V\" in"
607                            " \"%V\" directive",
608                            &value[i], &cmd->name);
609 
610         dd("returning NGX_CONF_ERROR");
611         return NGX_CONF_ERROR;
612     }
613 
614     dd("returning NGX_CONF_OK");
615     return NGX_CONF_OK;
616 }
617 
618 char *
ngx_postgres_conf_pass(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)619 ngx_postgres_conf_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
620 {
621     ngx_str_t                         *value = cf->args->elts;
622     ngx_postgres_loc_conf_t           *pglcf = conf;
623     ngx_http_core_loc_conf_t          *clcf;
624     ngx_http_compile_complex_value_t   ccv;
625     ngx_url_t                          url;
626 
627     dd("entering");
628 
629     if ((pglcf->upstream.upstream != NULL) || (pglcf->upstream_cv != NULL)) {
630         dd("returning");
631         return "is duplicate";
632     }
633 
634     if (value[1].len == 0) {
635         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
636                            "postgres: empty upstream in \"%V\" directive",
637                            &cmd->name);
638 
639         dd("returning NGX_CONF_ERROR");
640         return NGX_CONF_ERROR;
641     }
642 
643     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
644 
645     clcf->handler = ngx_postgres_handler;
646 
647     if (clcf->name.data[clcf->name.len - 1] == '/') {
648         clcf->auto_redirect = 1;
649     }
650 
651     if (ngx_http_script_variables_count(&value[1])) {
652         /* complex value */
653         dd("complex value");
654 
655         pglcf->upstream_cv = ngx_palloc(cf->pool,
656                                         sizeof(ngx_http_complex_value_t));
657         if (pglcf->upstream_cv == NULL) {
658             dd("returning NGX_CONF_ERROR");
659             return NGX_CONF_ERROR;
660         }
661 
662         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
663 
664         ccv.cf = cf;
665         ccv.value = &value[1];
666         ccv.complex_value = pglcf->upstream_cv;
667 
668         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
669             dd("returning NGX_CONF_ERROR");
670             return NGX_CONF_ERROR;
671         }
672 
673         dd("returning NGX_CONF_OK");
674         return NGX_CONF_OK;
675     } else {
676         /* simple value */
677         dd("simple value");
678 
679         ngx_memzero(&url, sizeof(ngx_url_t));
680 
681         url.url = value[1];
682         url.no_resolve = 1;
683 
684         pglcf->upstream.upstream = ngx_http_upstream_add(cf, &url, 0);
685         if (pglcf->upstream.upstream == NULL) {
686             dd("returning NGX_CONF_ERROR");
687             return NGX_CONF_ERROR;
688         }
689 
690         dd("returning NGX_CONF_OK");
691         return NGX_CONF_OK;
692     }
693 }
694 
695 char *
ngx_postgres_conf_query(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)696 ngx_postgres_conf_query(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
697 {
698     ngx_str_t                         *value = cf->args->elts;
699     ngx_str_t                          sql = value[cf->args->nelts - 1];
700     ngx_postgres_loc_conf_t           *pglcf = conf;
701     ngx_http_compile_complex_value_t   ccv;
702     ngx_postgres_mixed_t              *query;
703     ngx_conf_bitmask_t                *b;
704     ngx_uint_t                         methods, i, j;
705 
706     dd("entering");
707 
708     if (sql.len == 0) {
709         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
710                            "postgres: empty query in \"%V\" directive",
711                            &cmd->name);
712 
713         dd("returning NGX_CONF_ERROR");
714         return NGX_CONF_ERROR;
715     }
716 
717     if (cf->args->nelts == 2) {
718         /* default query */
719         dd("default query");
720 
721         if (pglcf->query.def != NULL) {
722             dd("returning");
723             return "is duplicate";
724         }
725 
726         pglcf->query.def = ngx_palloc(cf->pool, sizeof(ngx_postgres_mixed_t));
727         if (pglcf->query.def == NULL) {
728             dd("returning NGX_CONF_ERROR");
729             return NGX_CONF_ERROR;
730         }
731 
732         methods = 0xFFFF;
733         query = pglcf->query.def;
734     } else {
735         /* method-specific query */
736         dd("method-specific query");
737 
738         methods = 0;
739 
740         for (i = 1; i < cf->args->nelts - 1; i++) {
741             b = ngx_postgres_http_methods;
742             for (j = 0; b[j].name.len; j++) {
743                 if ((b[j].name.len == value[i].len)
744                     && (ngx_strcasecmp(b[j].name.data, value[i].data) == 0))
745                 {
746                     if (pglcf->query.methods_set & b[j].mask) {
747                         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
748                                            "postgres: method \"%V\" is"
749                                            " duplicate in \"%V\" directive",
750                                            &value[i], &cmd->name);
751 
752                         dd("returning NGX_CONF_ERROR");
753                         return NGX_CONF_ERROR;
754                     }
755 
756                     methods |= b[j].mask;
757                     break;
758                 }
759             }
760 
761             if (b[j].name.len == 0) {
762                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
763                                    "postgres: invalid method \"%V\""
764                                    " in \"%V\" directive",
765                                    &value[i], &cmd->name);
766 
767                 dd("returning NGX_CONF_ERROR");
768                 return NGX_CONF_ERROR;
769             }
770         }
771 
772         if (pglcf->query.methods == NULL) {
773             pglcf->query.methods = ngx_array_create(cf->pool, 4,
774                                        sizeof(ngx_postgres_mixed_t));
775             if (pglcf->query.methods == NULL) {
776                 dd("returning NGX_CONF_ERROR");
777                 return NGX_CONF_ERROR;
778             }
779         }
780 
781         query = ngx_array_push(pglcf->query.methods);
782         if (query == NULL) {
783             dd("returning NGX_CONF_ERROR");
784             return NGX_CONF_ERROR;
785         }
786 
787         pglcf->query.methods_set |= methods;
788     }
789 
790     if (ngx_http_script_variables_count(&sql)) {
791         /* complex value */
792         dd("complex value");
793 
794         query->key = methods;
795 
796         query->cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
797         if (query->cv == NULL) {
798             dd("returning NGX_CONF_ERROR");
799             return NGX_CONF_ERROR;
800         }
801 
802         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
803 
804         ccv.cf = cf;
805         ccv.value = &sql;
806         ccv.complex_value = query->cv;
807 
808         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
809             dd("returning NGX_CONF_ERROR");
810             return NGX_CONF_ERROR;
811         }
812     } else {
813         /* simple value */
814         dd("simple value");
815 
816         query->key = methods;
817         query->sv = sql;
818         query->cv = NULL;
819     }
820 
821     dd("returning NGX_CONF_OK");
822     return NGX_CONF_OK;
823 }
824 
825 char *
ngx_postgres_conf_rewrite(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)826 ngx_postgres_conf_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
827 {
828     ngx_str_t                    *value = cf->args->elts;
829     ngx_str_t                     what = value[cf->args->nelts - 2];
830     ngx_str_t                     to = value[cf->args->nelts - 1];
831     ngx_postgres_loc_conf_t      *pglcf = conf;
832     ngx_postgres_rewrite_conf_t  *pgrcf;
833     ngx_postgres_rewrite_t       *rewrite;
834     ngx_postgres_rewrite_enum_t  *e;
835     ngx_conf_bitmask_t           *b;
836     ngx_uint_t                    methods, keep_body, i, j;
837 
838     dd("entering");
839 
840     e = ngx_postgres_rewrite_handlers;
841     for (i = 0; e[i].name.len; i++) {
842         if ((e[i].name.len == what.len)
843             && (ngx_strcasecmp(e[i].name.data, what.data) == 0))
844         {
845             break;
846         }
847     }
848 
849     if (e[i].name.len == 0) {
850         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
851                            "postgres: invalid condition \"%V\""
852                            " in \"%V\" directive", &what, &cmd->name);
853 
854         dd("returning NGX_CONF_ERROR");
855         return NGX_CONF_ERROR;
856     }
857 
858     if (pglcf->rewrites == NGX_CONF_UNSET_PTR) {
859         pglcf->rewrites = ngx_array_create(cf->pool, 2,
860                                            sizeof(ngx_postgres_rewrite_conf_t));
861         if (pglcf->rewrites == NULL) {
862             dd("returning NGX_CONF_ERROR");
863             return NGX_CONF_ERROR;
864         }
865     } else {
866         pgrcf = pglcf->rewrites->elts;
867         for (j = 0; j < pglcf->rewrites->nelts; j++) {
868             if (pgrcf[j].key == e[i].key) {
869                 pgrcf = &pgrcf[j];
870                 goto found;
871             }
872         }
873     }
874 
875     pgrcf = ngx_array_push(pglcf->rewrites);
876     if (pgrcf == NULL) {
877         dd("returning NGX_CONF_ERROR");
878         return NGX_CONF_ERROR;
879     }
880 
881     ngx_memzero(pgrcf, sizeof(ngx_postgres_rewrite_conf_t));
882 
883     pgrcf->key = e[i].key;
884     pgrcf->handler = e[i].handler;
885 
886 found:
887 
888     if (cf->args->nelts == 3) {
889         /* default rewrite */
890         dd("default rewrite");
891 
892         if (pgrcf->def != NULL) {
893             dd("returning");
894             return "is duplicate";
895         }
896 
897         pgrcf->def = ngx_palloc(cf->pool, sizeof(ngx_postgres_rewrite_t));
898         if (pgrcf->def == NULL) {
899             dd("returning NGX_CONF_ERROR");
900             return NGX_CONF_ERROR;
901         }
902 
903         methods = 0xFFFF;
904         rewrite = pgrcf->def;
905     } else {
906         /* method-specific rewrite */
907         dd("method-specific rewrite");
908 
909         methods = 0;
910 
911         for (i = 1; i < cf->args->nelts - 2; i++) {
912             b = ngx_postgres_http_methods;
913             for (j = 0; b[j].name.len; j++) {
914                 if ((b[j].name.len == value[i].len)
915                     && (ngx_strcasecmp(b[j].name.data, value[i].data) == 0))
916                 {
917                     if (pgrcf->methods_set & b[j].mask) {
918                         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
919                                            "postgres: method \"%V\" for"
920                                            " condition \"%V\" is duplicate"
921                                            " in \"%V\" directive",
922                                            &value[i], &what, &cmd->name);
923 
924                         dd("returning NGX_CONF_ERROR");
925                         return NGX_CONF_ERROR;
926                     }
927 
928                     methods |= b[j].mask;
929                     break;
930                 }
931             }
932 
933             if (b[j].name.len == 0) {
934                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
935                                    "postgres: invalid method \"%V\" for"
936                                    " condition \"%V\" in \"%V\" directive",
937                                    &value[i], &what, &cmd->name);
938 
939                 dd("returning NGX_CONF_ERROR");
940                 return NGX_CONF_ERROR;
941             }
942         }
943 
944         if (pgrcf->methods == NULL) {
945             pgrcf->methods = ngx_array_create(cf->pool, 4,
946                                               sizeof(ngx_postgres_rewrite_t));
947             if (pgrcf->methods == NULL) {
948                 dd("returning NGX_CONF_ERROR");
949                 return NGX_CONF_ERROR;
950             }
951         }
952 
953         rewrite = ngx_array_push(pgrcf->methods);
954         if (rewrite == NULL) {
955             dd("returning NGX_CONF_ERROR");
956             return NGX_CONF_ERROR;
957         }
958 
959         pgrcf->methods_set |= methods;
960     }
961 
962     if (to.data[0] == '=') {
963         keep_body = 1;
964         to.len--;
965         to.data++;
966     } else {
967         keep_body = 0;
968     }
969 
970     rewrite->key = methods;
971     rewrite->status = ngx_atoi(to.data, to.len);
972     if ((rewrite->status == NGX_ERROR)
973         || (rewrite->status < NGX_HTTP_OK)
974         || (rewrite->status > NGX_HTTP_INSUFFICIENT_STORAGE)
975         || ((rewrite->status >= NGX_HTTP_SPECIAL_RESPONSE)
976             && (rewrite->status < NGX_HTTP_BAD_REQUEST)))
977     {
978           rewrite->location = to;
979         //dd("returning NGX_CONF_ERROR");
980 
981         //return NGX_CONF_ERROR;
982     }
983 
984     if (keep_body) {
985         rewrite->status = -rewrite->status;
986     }
987 
988     dd("returning NGX_CONF_OK");
989     return NGX_CONF_OK;
990 }
991 
992 char *
ngx_postgres_conf_output(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)993 ngx_postgres_conf_output(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
994 {
995     ngx_str_t                   *value = cf->args->elts;
996     ngx_postgres_loc_conf_t     *pglcf = conf;
997     ngx_postgres_output_enum_t  *e;
998     ngx_uint_t                   i;
999 
1000     dd("entering");
1001 
1002     if (pglcf->output_handler != NGX_CONF_UNSET_PTR) {
1003         dd("returning");
1004         return "is duplicate";
1005     }
1006 
1007     e = ngx_postgres_output_handlers;
1008     for (i = 0; e[i].name.len; i++) {
1009         if ((e[i].name.len == value[1].len)
1010             && (ngx_strcasecmp(e[i].name.data, value[1].data) == 0))
1011         {
1012             pglcf->output_handler = e[i].handler;
1013             break;
1014         }
1015     }
1016 
1017     if (e[i].name.len == 0) {
1018         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1019                            "postgres: invalid output format \"%V\""
1020                            " in \"%V\" directive", &value[1], &cmd->name);
1021 
1022         dd("returning NGX_CONF_ERROR");
1023         return NGX_CONF_ERROR;
1024     }
1025 
1026     pglcf->output_binary = e[i].binary;
1027 
1028     dd("returning NGX_CONF_OK");
1029     return NGX_CONF_OK;
1030 }
1031 
1032 char *
ngx_postgres_conf_set(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1033 ngx_postgres_conf_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1034 {
1035     ngx_str_t                *value = cf->args->elts;
1036     ngx_postgres_loc_conf_t  *pglcf = conf;
1037     ngx_postgres_variable_t  *pgvar;
1038     ngx_conf_enum_t          *e;
1039     ngx_int_t                 idx;
1040     ngx_uint_t                i;
1041 
1042     dd("entering");
1043 
1044     if (value[1].len < 2) {
1045         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1046                            "postgres: empty variable name in \"%V\" directive",
1047                            &cmd->name);
1048 
1049         dd("returning NGX_CONF_ERROR");
1050         return NGX_CONF_ERROR;
1051     }
1052 
1053     if (value[1].data[0] != '$') {
1054         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1055                            "postgres: invalid variable name \"%V\""
1056                            " in \"%V\" directive", &value[1], &cmd->name);
1057 
1058         dd("returning NGX_CONF_ERROR");
1059         return NGX_CONF_ERROR;
1060     }
1061 
1062     value[1].len--;
1063     value[1].data++;
1064 
1065     if (value[3].len == 0) {
1066         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1067                            "postgres: empty column in \"%V\" directive",
1068                            &cmd->name);
1069 
1070         dd("returning NGX_CONF_ERROR");
1071         return NGX_CONF_ERROR;
1072     }
1073 
1074     if (pglcf->variables == NGX_CONF_UNSET_PTR) {
1075         pglcf->variables = ngx_array_create(cf->pool, 4,
1076                                             sizeof(ngx_postgres_variable_t));
1077         if (pglcf->variables == NULL) {
1078             dd("returning NGX_CONF_ERROR");
1079             return NGX_CONF_ERROR;
1080         }
1081     }
1082 
1083     pgvar = ngx_array_push(pglcf->variables);
1084     if (pgvar == NULL) {
1085         dd("returning NGX_CONF_ERROR");
1086         return NGX_CONF_ERROR;
1087     }
1088 
1089     pgvar->idx = pglcf->variables->nelts - 1;
1090 
1091     pgvar->var = ngx_http_add_variable(cf, &value[1], 0);
1092     if (pgvar->var == NULL) {
1093         dd("returning NGX_CONF_ERROR");
1094         return NGX_CONF_ERROR;
1095     }
1096 
1097     idx = ngx_http_get_variable_index(cf, &value[1]);
1098     if (idx == NGX_ERROR) {
1099         dd("returning NGX_CONF_ERROR");
1100         return NGX_CONF_ERROR;
1101     }
1102 
1103     /*
1104      * Check if "$variable" was previously defined,
1105      * back-off even if it was marked as "CHANGEABLE".
1106      */
1107     if (pgvar->var->get_handler != NULL) {
1108         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1109                            "postgres: variable \"$%V\" is duplicate"
1110                            " in \"%V\" directive", &value[1], &cmd->name);
1111 
1112         dd("returning NGX_CONF_ERROR");
1113         return NGX_CONF_ERROR;
1114     }
1115 
1116     pgvar->var->get_handler = ngx_postgres_variable_get_custom;
1117     pgvar->var->data = (uintptr_t) pgvar;
1118 
1119     pgvar->value.row = ngx_atoi(value[2].data, value[2].len);
1120     if (pgvar->value.row == NGX_ERROR) {
1121         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1122                            "postgres: invalid row number \"%V\""
1123                            " in \"%V\" directive", &value[2], &cmd->name);
1124 
1125         dd("returning NGX_CONF_ERROR");
1126         return NGX_CONF_ERROR;
1127     }
1128 
1129     pgvar->value.column = ngx_atoi(value[3].data, value[3].len);
1130     if (pgvar->value.column == NGX_ERROR) {
1131         /* get column by name */
1132         pgvar->value.col_name = ngx_pnalloc(cf->pool, value[3].len + 1);
1133         if (pgvar->value.col_name == NULL) {
1134             dd("returning NGX_CONF_ERROR");
1135             return NGX_CONF_ERROR;
1136         }
1137 
1138         (void) ngx_cpystrn(pgvar->value.col_name,
1139                            value[3].data, value[3].len + 1);
1140     }
1141 
1142     if (cf->args->nelts == 4) {
1143         /* default value */
1144         pgvar->value.required = 0;
1145     } else {
1146         /* user-specified value */
1147         e = ngx_postgres_requirement_options;
1148         for (i = 0; e[i].name.len; i++) {
1149             if ((e[i].name.len == value[4].len)
1150                 && (ngx_strcasecmp(e[i].name.data, value[4].data) == 0))
1151             {
1152                 pgvar->value.required = e[i].value;
1153                 break;
1154             }
1155         }
1156 
1157         if (e[i].name.len == 0) {
1158             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1159                                "postgres: invalid requirement option \"%V\""
1160                                " in \"%V\" directive", &value[4], &cmd->name);
1161 
1162             dd("returning NGX_CONF_ERROR");
1163             return NGX_CONF_ERROR;
1164         }
1165     }
1166 
1167     dd("returning NGX_CONF_OK");
1168     return NGX_CONF_OK;
1169 }
1170 
1171 /*
1172  * Based on: ngx_http_rewrite_module.c/ngx_http_rewrite_set
1173  * Copyright (C) Igor Sysoev
1174  */
1175 char *
ngx_postgres_conf_escape(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1176 ngx_postgres_conf_escape(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1177 {
1178     ngx_str_t                           *value = cf->args->elts;
1179     ngx_str_t                            src = value[cf->args->nelts - 1];
1180     ngx_int_t                            index;
1181     ngx_http_variable_t                 *v;
1182     ngx_http_script_var_code_t          *vcode;
1183     ngx_http_script_var_handler_code_t  *vhcode;
1184     ngx_postgres_rewrite_loc_conf_t     *rlcf;
1185     ngx_postgres_escape_t               *pge;
1186     ngx_str_t                            dst;
1187     ngx_uint_t                           empty;
1188 
1189     dd("entering");
1190 
1191     if ((src.len != 0) && (src.data[0] == '=')) {
1192         empty = 1;
1193         src.len--;
1194         src.data++;
1195     } else {
1196         empty = 0;
1197     }
1198 
1199     if (src.len == 0) {
1200         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1201                            "postgres: empty value in \"%V\" directive",
1202                            &cmd->name);
1203 
1204         dd("returning NGX_CONF_ERROR");
1205         return NGX_CONF_ERROR;
1206     }
1207 
1208     if (cf->args->nelts == 2) {
1209         dst = src;
1210     } else {
1211         dst = value[1];
1212     }
1213 
1214     if (dst.len < 2) {
1215         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1216                            "postgres: empty variable name in \"%V\" directive",
1217                            &cmd->name);
1218 
1219         dd("returning NGX_CONF_ERROR");
1220         return NGX_CONF_ERROR;
1221     }
1222 
1223     if (dst.data[0] != '$') {
1224         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1225                            "postgres: invalid variable name \"%V\""
1226                            " in \"%V\" directive", &dst, &cmd->name);
1227 
1228         dd("returning NGX_CONF_ERROR");
1229         return NGX_CONF_ERROR;
1230     }
1231 
1232     dst.len--;
1233     dst.data++;
1234 
1235     v = ngx_http_add_variable(cf, &dst, NGX_HTTP_VAR_CHANGEABLE);
1236     if (v == NULL) {
1237         dd("returning NGX_CONF_ERROR");
1238         return NGX_CONF_ERROR;
1239     }
1240 
1241     index = ngx_http_get_variable_index(cf, &dst);
1242     if (index == NGX_ERROR) {
1243         dd("returning NGX_CONF_ERROR");
1244         return NGX_CONF_ERROR;
1245     }
1246 
1247     if (v->get_handler == NULL
1248         && ngx_strncasecmp(dst.data, (u_char *) "http_", 5) != 0
1249         && ngx_strncasecmp(dst.data, (u_char *) "sent_http_", 10) != 0
1250         && ngx_strncasecmp(dst.data, (u_char *) "upstream_http_", 14) != 0)
1251     {
1252         v->get_handler = ngx_postgres_rewrite_var;
1253         v->data = index;
1254     }
1255 
1256     rlcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_rewrite_module);
1257 
1258     if (ngx_postgres_rewrite_value(cf, rlcf, &src) != NGX_CONF_OK) {
1259         dd("returning NGX_CONF_ERROR");
1260         return NGX_CONF_ERROR;
1261     }
1262 
1263     pge = ngx_http_script_start_code(cf->pool, &rlcf->codes,
1264                                      sizeof(ngx_postgres_escape_t));
1265     if (pge == NULL) {
1266         dd("returning NGX_CONF_ERROR");
1267         return NGX_CONF_ERROR;
1268     }
1269 
1270     pge->code = ngx_postgres_escape_string;
1271     pge->empty = empty;
1272 
1273     if (v->set_handler) {
1274         vhcode = ngx_http_script_start_code(cf->pool, &rlcf->codes,
1275                                    sizeof(ngx_http_script_var_handler_code_t));
1276         if (vhcode == NULL) {
1277             dd("returning NGX_CONF_ERROR");
1278             return NGX_CONF_ERROR;
1279         }
1280 
1281         vhcode->code = ngx_http_script_var_set_handler_code;
1282         vhcode->handler = v->set_handler;
1283         vhcode->data = v->data;
1284 
1285         dd("returning NGX_CONF_OK");
1286         return NGX_CONF_OK;
1287     }
1288 
1289     vcode = ngx_http_script_start_code(cf->pool, &rlcf->codes,
1290                                        sizeof(ngx_http_script_var_code_t));
1291     if (vcode == NULL) {
1292         dd("returning NGX_CONF_ERROR");
1293         return NGX_CONF_ERROR;
1294     }
1295 
1296     vcode->code = ngx_http_script_set_var_code;
1297     vcode->index = (uintptr_t) index;
1298 
1299     dd("returning NGX_CONF_OK");
1300     return NGX_CONF_OK;
1301 }
1302 
1303 ngx_http_upstream_srv_conf_t *
ngx_postgres_find_upstream(ngx_http_request_t * r,ngx_url_t * url)1304 ngx_postgres_find_upstream(ngx_http_request_t *r, ngx_url_t *url)
1305 {
1306     ngx_http_upstream_main_conf_t   *umcf;
1307     ngx_http_upstream_srv_conf_t   **uscfp;
1308     ngx_uint_t                       i;
1309 
1310     dd("entering");
1311 
1312     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1313 
1314     uscfp = umcf->upstreams.elts;
1315 
1316     for (i = 0; i < umcf->upstreams.nelts; i++) {
1317 
1318         if ((uscfp[i]->host.len != url->host.len)
1319             || (ngx_strncasecmp(uscfp[i]->host.data, url->host.data,
1320                                 url->host.len) != 0))
1321         {
1322             dd("host doesn't match");
1323             continue;
1324         }
1325 
1326   #if (nginx_version < 1011006)
1327         if (uscfp[i]->port != url->port) {
1328             dd("port doesn't match: %d != %d",
1329                (int) uscfp[i]->port, (int) url->port);
1330             continue;
1331         }
1332 
1333         if (uscfp[i]->default_port && url->default_port
1334             && (uscfp[i]->default_port != url->default_port))
1335         {
1336             dd("default_port doesn't match");
1337             continue;
1338         }
1339 
1340   #endif
1341         dd("returning");
1342         return uscfp[i];
1343     }
1344 
1345     dd("returning NULL");
1346     return NULL;
1347 }
1348