1 /*
2 * Copyright (c) 2010, FRiCKLE Piotr Sikora <info@frickle.com>
3 * Copyright (c) 2009-2010, Yichun Zhang <agentzh@gmail.com>
4 * Copyright (C) 2002-2010, Igor Sysoev
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #ifndef DDEBUG
29 #define DDEBUG 0
30 #endif
31
32 #include <nginx.h>
33
34 #include "ngx_postgres_ddebug.h"
35 #include "ngx_postgres_util.h"
36
37
38 /*
39 * All functions in this file are copied directly from ngx_http_upstream.c,
40 * beacuse they are declared as static there.
41 */
42
43
44 void
ngx_postgres_upstream_finalize_request(ngx_http_request_t * r,ngx_http_upstream_t * u,ngx_int_t rc)45 ngx_postgres_upstream_finalize_request(ngx_http_request_t *r,
46 ngx_http_upstream_t *u, ngx_int_t rc)
47 {
48 #if defined(nginx_version) && (nginx_version < 1009001)
49 ngx_time_t *tp;
50 #endif
51
52 dd("entering");
53
54 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
55 "finalize http upstream request: %i", rc);
56
57 if (u->cleanup) {
58 *u->cleanup = NULL;
59 }
60
61 if (u->resolved && u->resolved->ctx) {
62 ngx_resolve_name_done(u->resolved->ctx);
63 u->resolved->ctx = NULL;
64 }
65
66 #if defined(nginx_version) && (nginx_version >= 1009001)
67 if (u->state && u->state->response_time) {
68 u->state->response_time = ngx_current_msec - u->state->response_time;
69 #else
70 if (u->state && u->state->response_sec) {
71 tp = ngx_timeofday();
72 u->state->response_sec = tp->sec - u->state->response_sec;
73 u->state->response_msec = tp->msec - u->state->response_msec;
74 #endif
75
76 if (u->pipe) {
77 u->state->response_length = u->pipe->read_length;
78 }
79 }
80
81 if (u->finalize_request) {
82 u->finalize_request(r, rc);
83 }
84
85 if (u->peer.free) {
86 u->peer.free(&u->peer, u->peer.data, 0);
87 }
88
89 if (u->peer.connection) {
90
91 #if 0 /* we don't support SSL at this time, was: (NGX_HTTP_SSL) */
92
93 /* TODO: do not shutdown persistent connection */
94
95 if (u->peer.connection->ssl) {
96
97 /*
98 * We send the "close notify" shutdown alert to the upstream only
99 * and do not wait its "close notify" shutdown alert.
100 * It is acceptable according to the TLS standard.
101 */
102
103 u->peer.connection->ssl->no_wait_shutdown = 1;
104
105 (void) ngx_ssl_shutdown(u->peer.connection);
106 }
107 #endif
108
109 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
110 "close http upstream connection: %d",
111 u->peer.connection->fd);
112
113 #if defined(nginx_version) && (nginx_version >= 1001004)
114 if (u->peer.connection->pool) {
115 ngx_destroy_pool(u->peer.connection->pool);
116 }
117 #endif
118
119 ngx_close_connection(u->peer.connection);
120 }
121
122 u->peer.connection = NULL;
123
124 if (u->pipe && u->pipe->temp_file) {
125 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
126 "http upstream temp fd: %d",
127 u->pipe->temp_file->file.fd);
128 }
129
130 if (u->header_sent
131 && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
132 {
133 rc = 0;
134 }
135
136 if (rc == NGX_DECLINED) {
137 dd("returning");
138 return;
139 }
140
141 r->connection->log->action = "sending to client";
142
143 if (rc == 0) {
144 rc = ngx_http_send_special(r, NGX_HTTP_LAST);
145 }
146
147 ngx_http_finalize_request(r, rc);
148
149 dd("returning");
150 }
151
152 void
153 ngx_postgres_upstream_next(ngx_http_request_t *r,
154 ngx_http_upstream_t *u, ngx_int_t ft_type)
155 {
156 ngx_uint_t status, state;
157
158 dd("entering");
159
160 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
161 "http next upstream, %xi", ft_type);
162
163 #if 0
164 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
165 #endif
166
167 if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) {
168 state = NGX_PEER_NEXT;
169 } else {
170 state = NGX_PEER_FAILED;
171 }
172
173 if (ft_type != NGX_HTTP_UPSTREAM_FT_NOLIVE) {
174 u->peer.free(&u->peer, u->peer.data, state);
175 }
176
177 if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
178 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
179 "upstream timed out");
180 }
181
182 if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
183 status = 0;
184
185 } else {
186 switch(ft_type) {
187
188 case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
189 status = NGX_HTTP_GATEWAY_TIME_OUT;
190 break;
191
192 case NGX_HTTP_UPSTREAM_FT_HTTP_500:
193 status = NGX_HTTP_INTERNAL_SERVER_ERROR;
194 break;
195
196 case NGX_HTTP_UPSTREAM_FT_HTTP_404:
197 status = NGX_HTTP_NOT_FOUND;
198 break;
199
200 /*
201 * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
202 * never reach here
203 */
204
205 default:
206 status = NGX_HTTP_BAD_GATEWAY;
207 }
208 }
209
210 if (r->connection->error) {
211 ngx_postgres_upstream_finalize_request(r, u,
212 NGX_HTTP_CLIENT_CLOSED_REQUEST);
213
214 dd("returning");
215 return;
216 }
217
218 if (status) {
219 u->state->status = status;
220
221 if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) {
222 ngx_postgres_upstream_finalize_request(r, u, status);
223
224 dd("returning");
225 return;
226 }
227 }
228
229 if (u->peer.connection) {
230 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
231 "close http upstream connection: %d",
232 u->peer.connection->fd);
233
234 #if 0 /* we don't support SSL at this time, was: (NGX_HTTP_SSL) */
235
236 if (u->peer.connection->ssl) {
237 u->peer.connection->ssl->no_wait_shutdown = 1;
238 u->peer.connection->ssl->no_send_shutdown = 1;
239
240 (void) ngx_ssl_shutdown(u->peer.connection);
241 }
242 #endif
243
244 #if defined(nginx_version) && (nginx_version >= 1001004)
245 if (u->peer.connection->pool) {
246 ngx_destroy_pool(u->peer.connection->pool);
247 }
248 #endif
249
250 ngx_close_connection(u->peer.connection);
251 }
252
253 #if 0
254 if (u->conf->busy_lock && !u->busy_locked) {
255 ngx_http_upstream_busy_lock(p);
256 return;
257 }
258 #endif
259
260 /* TODO: ngx_http_upstream_connect(r, u); */
261 if (status == 0) {
262 status = NGX_HTTP_INTERNAL_SERVER_ERROR;
263 }
264
265 dd("returning");
266 return ngx_postgres_upstream_finalize_request(r, u, status);
267 }
268
269 ngx_int_t
270 ngx_postgres_upstream_test_connect(ngx_connection_t *c)
271 {
272 int err;
273 socklen_t len;
274
275 dd("entering");
276
277 #if (NGX_HAVE_KQUEUE)
278
279 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
280 if (c->write->pending_eof) {
281 c->log->action = "connecting to upstream";
282 (void) ngx_connection_error(c, c->write->kq_errno,
283 "kevent() reported that connect() failed");
284
285 dd("returning NGX_ERROR");
286 return NGX_ERROR;
287 }
288
289 } else
290 #endif
291 {
292 err = 0;
293 len = sizeof(int);
294
295 /*
296 * BSDs and Linux return 0 and set a pending error in err
297 * Solaris returns -1 and sets errno
298 */
299
300 if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == -1)
301 {
302 err = ngx_errno;
303 }
304
305 if (err) {
306 c->log->action = "connecting to upstream";
307 (void) ngx_connection_error(c, err, "connect() failed");
308
309 dd("returning NGX_ERROR");
310 return NGX_ERROR;
311 }
312 }
313
314 dd("returning NGX_OK");
315 return NGX_OK;
316 }
317
318 ngx_int_t
319 ngx_postgres_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v,
320 uintptr_t data)
321 {
322 ngx_http_variable_t *var;
323 ngx_http_core_main_conf_t *cmcf;
324 ngx_postgres_rewrite_loc_conf_t *rlcf;
325
326 rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
327
328 if (rlcf->uninitialized_variable_warn == 0) {
329 *v = ngx_http_variable_null_value;
330 return NGX_OK;
331 }
332
333 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
334
335 var = cmcf->variables.elts;
336
337 /*
338 * the ngx_http_rewrite_module sets variables directly in r->variables,
339 * and they should be handled by ngx_http_get_indexed_variable(),
340 * so the handler is called only if the variable is not initialized
341 */
342
343 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
344 "using uninitialized \"%V\" variable", &var[data].name);
345
346 *v = ngx_http_variable_null_value;
347
348 return NGX_OK;
349 }
350
351 char *
352 ngx_postgres_rewrite_value(ngx_conf_t *cf, ngx_postgres_rewrite_loc_conf_t *lcf,
353 ngx_str_t *value)
354 {
355 ngx_int_t n;
356 ngx_http_script_compile_t sc;
357 ngx_http_script_value_code_t *val;
358 ngx_http_script_complex_value_code_t *complex;
359
360 n = ngx_http_script_variables_count(value);
361
362 if (n == 0) {
363 val = ngx_http_script_start_code(cf->pool, &lcf->codes,
364 sizeof(ngx_http_script_value_code_t));
365 if (val == NULL) {
366 return NGX_CONF_ERROR;
367 }
368
369 n = ngx_atoi(value->data, value->len);
370
371 if (n == NGX_ERROR) {
372 n = 0;
373 }
374
375 val->code = ngx_http_script_value_code;
376 val->value = (uintptr_t) n;
377 val->text_len = (uintptr_t) value->len;
378 val->text_data = (uintptr_t) value->data;
379
380 return NGX_CONF_OK;
381 }
382
383 complex = ngx_http_script_start_code(cf->pool, &lcf->codes,
384 sizeof(ngx_http_script_complex_value_code_t));
385 if (complex == NULL) {
386 return NGX_CONF_ERROR;
387 }
388
389 complex->code = ngx_http_script_complex_value_code;
390 complex->lengths = NULL;
391
392 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
393
394 sc.cf = cf;
395 sc.source = value;
396 sc.lengths = &complex->lengths;
397 sc.values = &lcf->codes;
398 sc.variables = n;
399 sc.complete_lengths = 1;
400
401 if (ngx_http_script_compile(&sc) != NGX_OK) {
402 return NGX_CONF_ERROR;
403 }
404
405 return NGX_CONF_OK;
406 }
407