Apache HTTPD
mod_proxy_hcheck.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "mod_proxy.h"
17#include "mod_watchdog.h"
18#include "ap_slotmem.h"
19#include "ap_expr.h"
20#if APR_HAS_THREADS
21#include "apr_thread_pool.h"
22#endif
23#include "http_ssl.h"
24
25module AP_MODULE_DECLARE_DATA proxy_hcheck_module;
26
27#define HCHECK_WATHCHDOG_NAME ("_proxy_hcheck_")
28#define HC_THREADPOOL_SIZE (16)
29
30/* Why? So we can easily set/clear HC_USE_THREADS during dev testing */
31#if APR_HAS_THREADS
32#ifndef HC_USE_THREADS
33#define HC_USE_THREADS 1
34#endif
35#else
36#define HC_USE_THREADS 0
37#endif
38
48
49typedef struct {
50 char *expr;
51 ap_expr_info_t *pexpr; /* parsed expression */
53
61
62/* Used in the HC worker via the context field */
63typedef struct {
64 const char *path; /* The path of the original worker URL */
65 const char *method; /* Method string for the HTTP/AJP request */
66 const char *req; /* pre-formatted HTTP/AJP request */
67 proxy_worker *w; /* Pointer to the actual worker */
68 const char *protocol; /* HTTP 1.0 or 1.1? */
69} wctx_t;
70
79
81
83{
84 sctx_t *ctx = apr_pcalloc(p, sizeof(sctx_t));
85 ctx->s = s;
86 apr_pool_create(&ctx->p, p);
87 apr_pool_tag(ctx->p, "proxy_hcheck");
88 ctx->templates = apr_array_make(p, 10, sizeof(hc_template_t));
89 ctx->conditions = apr_table_make(p, 10);
90 ctx->hcworkers = apr_hash_make(p);
91 return ctx;
92}
93
95#if HC_USE_THREADS
97static int tpsize;
98#endif
99
100/*
101 * This serves double duty by not only validating (and creating)
102 * the health-check template, but also ties into set_worker_param()
103 * which does the actual setting of worker params in shm.
104 */
105static const char *set_worker_hc_param(apr_pool_t *p,
106 server_rec *s,
107 proxy_worker *worker,
108 const char *key,
109 const char *val,
110 void *v)
111{
112 int ival;
114 sctx_t *ctx = (sctx_t *) ap_get_module_config(s->module_config,
115 &proxy_hcheck_module);
116 if (!worker && !v) {
117 return "Bad call to set_worker_hc_param()";
118 }
119 if (!ctx) {
121 ap_set_module_config(s->module_config, &proxy_hcheck_module, ctx);
122 }
123 temp = (hc_template_t *)v;
124 if (!strcasecmp(key, "hctemplate")) {
125 hc_template_t *template;
126 template = (hc_template_t *)ctx->templates->elts;
127 for (ival = 0; ival < ctx->templates->nelts; ival++, template++) {
128 if (!ap_cstr_casecmp(template->name, val)) {
129 if (worker) {
130 worker->s->method = template->method;
131 worker->s->interval = template->interval;
132 worker->s->passes = template->passes;
133 worker->s->fails = template->fails;
134 PROXY_STRNCPY(worker->s->hcuri, template->hurl);
135 PROXY_STRNCPY(worker->s->hcexpr, template->hcexpr);
136 } else {
137 temp->method = template->method;
138 temp->interval = template->interval;
139 temp->passes = template->passes;
140 temp->fails = template->fails;
141 temp->hurl = apr_pstrdup(p, template->hurl);
142 temp->hcexpr = apr_pstrdup(p, template->hcexpr);
143 }
144 return NULL;
145 }
146 }
147 return apr_psprintf(p, "Unknown ProxyHCTemplate name: %s", val);
148 }
149 else if (!strcasecmp(key, "hcmethod")) {
151 for (; method->name; method++) {
152 if (!ap_cstr_casecmp(val, method->name)) {
153 if (!method->implemented) {
154 return apr_psprintf(p, "Health check method %s not (yet) implemented",
155 val);
156 }
157 if (worker) {
158 worker->s->method = method->method;
159 } else {
160 temp->method = method->method;
161 }
162 return NULL;
163 }
164 }
165 return "Unknown method";
166 }
167 else if (!strcasecmp(key, "hcinterval")) {
169 apr_status_t rv;
171 if (rv != APR_SUCCESS)
172 return "Unparse-able hcinterval setting";
173 if (hci < AP_WD_TM_SLICE)
174 return apr_psprintf(p, "Interval must be a positive value greater than %"
176 if (worker) {
177 worker->s->interval = hci;
178 } else {
179 temp->interval = hci;
180 }
181 }
182 else if (!strcasecmp(key, "hcpasses")) {
183 ival = atoi(val);
184 if (ival < 0)
185 return "Passes must be a positive value";
186 if (worker) {
187 worker->s->passes = ival;
188 } else {
189 temp->passes = ival;
190 }
191 }
192 else if (!strcasecmp(key, "hcfails")) {
193 ival = atoi(val);
194 if (ival < 0)
195 return "Fails must be a positive value";
196 if (worker) {
197 worker->s->fails = ival;
198 } else {
199 temp->fails = ival;
200 }
201 }
202 else if (!strcasecmp(key, "hcuri")) {
203 if (strlen(val) >= sizeof(worker->s->hcuri))
204 return apr_psprintf(p, "Health check uri length must be < %d characters",
205 (int)sizeof(worker->s->hcuri));
206 if (worker) {
207 PROXY_STRNCPY(worker->s->hcuri, val);
208 } else {
209 temp->hurl = apr_pstrdup(p, val);
210 }
211 }
212 else if (!strcasecmp(key, "hcexpr")) {
213 hc_condition_t *cond;
214 cond = (hc_condition_t *)apr_table_get(ctx->conditions, val);
215 if (!cond) {
216 return apr_psprintf(p, "Unknown health check condition expr: %s", val);
217 }
218 /* This check is wonky... a known expr can't be this big. Check anyway */
219 if (strlen(val) >= sizeof(worker->s->hcexpr))
220 return apr_psprintf(p, "Health check uri length must be < %d characters",
221 (int)sizeof(worker->s->hcexpr));
222 if (worker) {
223 PROXY_STRNCPY(worker->s->hcexpr, val);
224 } else {
225 temp->hcexpr = apr_pstrdup(p, val);
226 }
227 }
228 else {
229 return "unknown Worker hcheck parameter";
230 }
231 return NULL;
232}
233
234static const char *set_hc_condition(cmd_parms *cmd, void *dummy, const char *arg)
235{
236 char *name = NULL;
237 char *expr;
238 sctx_t *ctx;
239 hc_condition_t *cond;
240
242 if (err)
243 return err;
244 ctx = (sctx_t *) ap_get_module_config(cmd->server->module_config,
245 &proxy_hcheck_module);
246
247 name = ap_getword_conf(cmd->pool, &arg);
248 if (!*name) {
249 return apr_pstrcat(cmd->temp_pool, "Missing expression name for ",
250 cmd->cmd->name, NULL);
251 }
252 if (strlen(name) > (PROXY_WORKER_MAX_SCHEME_SIZE - 1)) {
253 return apr_psprintf(cmd->temp_pool, "Expression name limited to %d characters",
255 }
256 /* get expr. Allow fancy new {...} quoting style */
257 expr = ap_getword_conf2(cmd->temp_pool, &arg);
258 if (!*expr) {
259 return apr_pstrcat(cmd->temp_pool, "Missing expression for ",
260 cmd->cmd->name, NULL);
261 }
262 cond = apr_palloc(cmd->pool, sizeof(hc_condition_t));
263 cond->pexpr = ap_expr_parse_cmd(cmd, expr, 0, &err, NULL);
264 if (err) {
265 return apr_psprintf(cmd->temp_pool, "Could not parse expression \"%s\": %s",
266 expr, err);
267 }
268 cond->expr = apr_pstrdup(cmd->pool, expr);
269 apr_table_setn(ctx->conditions, name, (void *)cond);
270 expr = ap_getword_conf(cmd->temp_pool, &arg);
271 if (*expr) {
272 return "error: extra parameter(s)";
273 }
274 return NULL;
275}
276
277static const char *set_hc_template(cmd_parms *cmd, void *dummy, const char *arg)
278{
279 char *name = NULL;
280 char *word, *val;
281 hc_template_t *template;
282 sctx_t *ctx;
283
285 if (err)
286 return err;
287 ctx = (sctx_t *) ap_get_module_config(cmd->server->module_config,
288 &proxy_hcheck_module);
289
290 name = ap_getword_conf(cmd->temp_pool, &arg);
291 if (!*name) {
292 return apr_pstrcat(cmd->temp_pool, "Missing template name for ",
293 cmd->cmd->name, NULL);
294 }
295
296 template = (hc_template_t *)apr_array_push(ctx->templates);
297
298 template->name = apr_pstrdup(cmd->pool, name);
299 template->method = template->passes = template->fails = 1;
301 template->hurl = NULL;
302 template->hcexpr = NULL;
303 while (*arg) {
304 word = ap_getword_conf(cmd->pool, &arg);
305 val = strchr(word, '=');
306 if (!val) {
307 return "Invalid ProxyHCTemplate parameter. Parameter must be "
308 "in the form 'key=value'";
309 }
310 else
311 *val++ = '\0';
312 err = set_worker_hc_param(cmd->pool, ctx->s, NULL, word, val, template);
313
314 if (err) {
315 /* get rid of recently pushed (bad) template */
316 apr_array_pop(ctx->templates);
317 return apr_pstrcat(cmd->temp_pool, "ProxyHCTemplate: ", err, " ", word, "=", val, "; ", name, NULL);
318 }
319 /* No error means we have a valid template */
320 }
321 return NULL;
322}
323
324#if HC_USE_THREADS
325static const char *set_hc_tpsize (cmd_parms *cmd, void *dummy, const char *arg)
326{
327 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
328 if (err)
329 return err;
330
331 tpsize = atoi(arg);
332 if (tpsize < 0)
333 return "Invalid ProxyHCTPsize parameter. Parameter must be "
334 ">= 0";
335 return NULL;
336}
337#endif
338
339/*
340 * Create a dummy request rec, simply so we can use ap_expr.
341 * Use our short-lived pool for bucket_alloc so that we can simply move
342 * buckets and use them after the backend connection is released.
343 */
345 proxy_balancer *balancer,
346 const char *method,
347 const char *protocol)
348{
349 request_rec *r;
350
351 r = apr_pcalloc(p, sizeof(request_rec));
352 r->pool = p;
353 r->server = s;
354
356 if (balancer->section_config) {
359 balancer->section_config);
360 }
361
363
364 r->user = NULL;
366
368
375 r->notes = apr_table_make(r->pool, 5);
376
378 /* Must be set before we run create request hook */
379
380 r->sent_bodyct = 0; /* bytect isn't for body */
381
382 r->read_length = 0;
384
385 r->status = HTTP_OK; /* Until further notice */
386 r->the_request = NULL;
387
388 /* Begin by presuming any module can make its own path_info assumptions,
389 * until some module interjects and changes the value.
390 */
392
393
394 /* Time to populate r with the data we have. */
395 r->method = method;
396 /* Provide quick information about the request method as soon as known */
399 || (r->method_number == M_GET && r->method[0] == 'H')) {
400 r->header_only = 1;
401 }
402 else {
403 r->header_only = 0;
404 }
405 r->protocol = "HTTP/1.0";
406 r->proto_num = HTTP_VERSION(1, 0);
407 if ( protocol && (protocol[7] == '1') ) {
408 r->protocol = "HTTP/1.1";
409 r->proto_num = HTTP_VERSION(1, 1);
410 }
411 r->hostname = NULL;
412
413 return r;
414}
415
428
430 apr_pool_t *p)
431{
432 char *req = NULL;
433 const char *method = NULL;
434 const char *protocol = NULL;
435
436 /* TODO: Fold into switch/case below? This seems more obvious */
437 if ( (hc->s->method == OPTIONS11) || (hc->s->method == HEAD11) || (hc->s->method == GET11) ) {
438 protocol = "HTTP/1.1";
439 } else {
440 protocol = "HTTP/1.0";
441 }
442 switch (hc->s->method) {
443 case OPTIONS:
444 case OPTIONS11:
445 method = "OPTIONS";
446 req = apr_psprintf(p,
447 "OPTIONS * %s\r\n"
448 "Host: %s:%d\r\n"
449 "\r\n", protocol,
450 hc->s->hostname_ex, (int)hc->s->port);
451 break;
452
453 case HEAD:
454 case HEAD11:
455 method = "HEAD";
456 /* fallthru */
457 case GET:
458 case GET11:
459 if (!method) { /* did we fall thru? If not, we are GET */
460 method = "GET";
461 }
462 req = apr_psprintf(p,
463 "%s %s%s%s %s\r\n"
464 "Host: %s:%d\r\n"
465 "\r\n",
466 method,
467 (wctx->path ? wctx->path : ""),
468 (wctx->path && *hc->s->hcuri ? "/" : "" ),
469 (*hc->s->hcuri ? hc->s->hcuri : ""),
470 protocol,
471 hc->s->hostname_ex, (int)hc->s->port);
472 break;
473
474 default:
475 break;
476 }
477 wctx->req = req;
478 wctx->method = method;
479 wctx->protocol = protocol;
480}
481
483 apr_pool_t *p)
484{
485 proxy_worker *hc = NULL;
487
488 hc = (proxy_worker *)apr_hash_get(ctx->hcworkers, &worker, sizeof worker);
489 if (!hc) {
491 apr_status_t rv;
492 const char *url = worker->s->name_ex;
493 wctx_t *wctx = apr_pcalloc(ctx->p, sizeof(wctx_t));
494
495 port = (worker->s->port ? worker->s->port
496 : ap_proxy_port_of_scheme(worker->s->scheme));
498 "Creating hc worker %pp for %s://%s:%d",
499 worker, worker->s->scheme, worker->s->hostname_ex,
500 (int)port);
501
502 ap_proxy_define_worker(ctx->p, &hc, NULL, NULL, worker->s->name_ex, 0);
503 apr_snprintf(hc->s->name, sizeof hc->s->name, "%pp", worker);
504 apr_snprintf(hc->s->name_ex, sizeof hc->s->name_ex, "%pp", worker);
505 PROXY_STRNCPY(hc->s->hostname, worker->s->hostname); /* for compatibility */
506 PROXY_STRNCPY(hc->s->hostname_ex, worker->s->hostname_ex);
507 PROXY_STRNCPY(hc->s->scheme, worker->s->scheme);
508 PROXY_STRNCPY(hc->s->hcuri, worker->s->hcuri);
509 PROXY_STRNCPY(hc->s->hcexpr, worker->s->hcexpr);
510 hc->hash.def = hc->s->hash.def = ap_proxy_hashfunc(hc->s->name_ex,
512 hc->hash.fnv = hc->s->hash.fnv = ap_proxy_hashfunc(hc->s->name_ex,
514 hc->s->port = port;
515 hc->s->conn_timeout_set = worker->s->conn_timeout_set;
516 hc->s->conn_timeout = worker->s->conn_timeout;
517 hc->s->ping_timeout_set = worker->s->ping_timeout_set;
518 hc->s->ping_timeout = worker->s->ping_timeout;
519 hc->s->timeout_set = worker->s->timeout_set;
520 hc->s->timeout = worker->s->timeout;
521 /* Do not disable worker in case of errors */
523 /* Mark as the "generic" worker */
527 hc->s->disablereuse = worker->s->disablereuse;
528 hc->s->method = worker->s->method;
529 rv = apr_uri_parse(p, url, &uri);
530 if (rv == APR_SUCCESS) {
531 wctx->path = apr_pstrdup(ctx->p, uri.path);
532 }
533 wctx->w = worker;
534 create_hcheck_req(wctx, hc, ctx->p);
535 hc->context = wctx;
536 apr_hash_set(ctx->hcworkers, &worker, sizeof worker, hc);
537 }
538 /* This *could* have changed via the Balancer Manager */
539 /* TODO */
540 if (hc->s->method != worker->s->method) {
541 wctx_t *wctx = hc->context;
542 port = (worker->s->port ? worker->s->port
543 : ap_proxy_port_of_scheme(worker->s->scheme));
545 "Updating hc worker %pp for %s://%s:%d",
546 worker, worker->s->scheme, worker->s->hostname_ex,
547 (int)port);
548 hc->s->method = worker->s->method;
549 create_hcheck_req(wctx, hc, ctx->p);
550 }
551 return hc;
552}
553
555 proxy_conn_rec *backend,
556 server_rec *s)
557{
558 proxy_worker *worker = backend->worker;
559 apr_status_t rv;
560
561 /*
562 * normally, this is done in ap_proxy_determine_connection().
563 * TODO: Look at using ap_proxy_determine_connection() with a
564 * fake request_rec
565 */
567 worker->s->hostname_ex, worker->s->port,
568 0, NULL, s);
569 if (rv != APR_SUCCESS) {
571 "DNS lookup failure for: %s:%hu",
572 worker->s->hostname_ex, worker->s->port);
573 return !OK;
574 }
575
576 return OK;
577}
578
580 server_rec *s, int status)
581{
582 if (backend) {
583 backend->close = 1;
586 "Health check %s Status (%d) for %s.",
588 status,
589 backend->worker->s->name_ex);
590 }
591 if (status != OK) {
592 return APR_EGENERAL;
593 }
594 return APR_SUCCESS;
595}
596
597static int hc_get_backend(const char *proxy_function, proxy_conn_rec **backend,
598 proxy_worker *hc, sctx_t *ctx)
599{
600 int status;
601
603 if (status != OK) {
604 return status;
605 }
606
607 if (strcmp(hc->s->scheme, "https") == 0 || strcmp(hc->s->scheme, "wss") == 0 ) {
610 "mod_ssl not configured?");
611 return !OK;
612 }
613 (*backend)->is_ssl = 1;
614 }
615
616 return hc_determine_connection(proxy_function, *backend, ctx->s);
617}
618
620{
621 sctx_t *ctx = baton->ctx;
622 proxy_worker *worker = baton->worker, *hc;
624 int once = 0;
625
626 /*
627 * Since this is the watchdog, workers never actually handle a
628 * request here, and so the local data isn't initialized (of
629 * course, the shared memory is). So we need to bootstrap
630 * worker->cp. Note, we only need do this once.
631 */
632 if (!worker->cp) {
633 rv = ap_proxy_initialize_worker(worker, ctx->s, ctx->p);
634 if (rv != APR_SUCCESS) {
635 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ctx->s, APLOGNO(03250) "Cannot init worker");
636 return rv;
637 }
638 once = 1;
639 }
640
641 baton->hc = hc = hc_get_hcworker(ctx, worker, baton->ptemp);
642
643 /* Try to resolve the worker address once if it's reusable */
644 if (once && worker->s->is_address_reusable) {
645 proxy_conn_rec *backend = NULL;
646 if (hc_get_backend("HCHECK", &backend, hc, ctx)) {
647 rv = APR_EGENERAL;
648 }
649 if (backend) {
650 backend->close = 1;
651 ap_proxy_release_connection("HCHECK", backend, ctx->s);
652 }
653 }
654
655 return rv;
656}
657
659{
660 int status;
661 sctx_t *ctx = baton->ctx;
662 proxy_worker *hc = baton->hc;
663 proxy_conn_rec *backend = NULL;
664 apr_pool_t *ptemp = baton->ptemp;
665 request_rec *r;
667
669 return APR_ENOTIMPL;
670 }
671
672 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, baton->ctx->s, "HCCPING starting");
673 if ((status = hc_get_backend("HCCPING", &backend, hc, ctx)) != OK) {
674 return backend_cleanup("HCCPING", backend, ctx->s, status);
675 }
676 if ((status = ap_proxy_connect_backend("HCCPING", backend, hc, ctx->s)) != OK) {
677 return backend_cleanup("HCCPING", backend, ctx->s, status);
678 }
679 r = create_request_rec(ptemp, ctx->s, baton->balancer, "CPING", NULL);
680 if ((status = ap_proxy_connection_create_ex("HCCPING", backend, r)) != OK) {
681 return backend_cleanup("HCCPING", backend, ctx->s, status);
682 }
684 backend->connection->current_thread = thread;
685
686 if (hc->s->ping_timeout_set) {
687 timeout = hc->s->ping_timeout;
688 } else if ( hc->s->conn_timeout_set) {
689 timeout = hc->s->conn_timeout;
690 } else if ( hc->s->timeout_set) {
691 timeout = hc->s->timeout;
692 } else {
693 /* default to socket timeout */
695 }
697 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, baton->ctx->s, "HCCPING done %d", status);
698 return backend_cleanup("HCCPING", backend, ctx->s, status);
699}
700
702{
703 int status;
704 sctx_t *ctx = baton->ctx;
705 proxy_worker *hc = baton->hc;
706 proxy_conn_rec *backend = NULL;
707
708 status = hc_get_backend("HCTCP", &backend, hc, ctx);
709 if (status == OK) {
710 status = ap_proxy_connect_backend("HCTCP", backend, hc, ctx->s);
711 /* does an unconditional ap_proxy_is_socket_connected() */
712 }
713 return backend_cleanup("HCTCP", backend, ctx->s, status);
714}
715
716static int hc_send(request_rec *r, const char *out, apr_bucket_brigade *bb)
717{
718 apr_status_t rv;
720 apr_bucket_alloc_t *ba = c->bucket_alloc;
723 r->pool, ba));
725 rv = ap_pass_brigade(c->output_filters, bb);
727 return (rv) ? !OK : OK;
728}
729
731{
733 int len;
734 const char *ct;
735
736 len = ap_getline(buffer, sizeof(buffer), r, 1);
737 if (len <= 0) {
738 return !OK;
739 }
741 "%.*s", len, buffer);
742 /* for the below, see ap_proxy_http_process_response() */
743 if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
744 int major;
745 char keepchar;
746 int proxy_status = OK;
747 const char *proxy_status_line = NULL;
748
749 major = buffer[5] - '0';
750 if ((major != 1) || (len >= sizeof(buffer)-1)) {
751 return !OK;
752 }
753
754 keepchar = buffer[12];
755 buffer[12] = '\0';
756 proxy_status = atoi(&buffer[9]);
757 if (keepchar != '\0') {
758 buffer[12] = keepchar;
759 } else {
760 buffer[12] = ' ';
761 buffer[13] = '\0';
762 }
764 r->status = proxy_status;
766 } else {
767 return !OK;
768 }
769
770 /* OK, 1st line is OK... scarf in the headers */
771 while ((len = ap_getline(buffer, sizeof(buffer), r, 1)) > 0) {
772 char *value, *end;
774 len, buffer);
775 if (!(value = strchr(buffer, ':'))) {
776 return !OK;
777 }
778 *value = '\0';
779 ++value;
780 while (apr_isspace(*value))
781 ++value; /* Skip to start of value */
782 for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end)
783 *end = '\0';
785 }
786
787 /* Set the Content-Type for the request if set */
788 if ((ct = apr_table_get(r->headers_out, "Content-Type")) != NULL)
790
791 return OK;
792}
793
795{
797 int seen_eos = 0;
798
799 do {
801
805
806 if (rv != APR_SUCCESS) {
807 if (APR_STATUS_IS_EOF(rv)) {
808 rv = APR_SUCCESS;
809 break;
810 }
812 "Error reading response body");
813 break;
814 }
815
816 while (!APR_BRIGADE_EMPTY(bb)) {
817 apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
818 if (APR_BUCKET_IS_EOS(bucket)) {
819 seen_eos = 1;
820 break;
821 }
822 if (APR_BUCKET_IS_FLUSH(bucket)) {
823 apr_bucket_delete(bucket);
824 continue;
825 }
826 APR_BUCKET_REMOVE(bucket);
828 }
829 }
830 while (!seen_eos);
832 return (rv == APR_SUCCESS ? OK : !OK);
833}
834
835/*
836 * Send the HTTP OPTIONS, HEAD or GET request to the backend
837 * server associated w/ worker. If we have Conditions,
838 * then apply those to the resulting response, otherwise
839 * any status code 2xx or 3xx is considered "passing"
840 */
842{
843 int status;
844 proxy_conn_rec *backend = NULL;
845 sctx_t *ctx = baton->ctx;
846 proxy_worker *hc = baton->hc;
847 proxy_worker *worker = baton->worker;
848 apr_pool_t *ptemp = baton->ptemp;
849 request_rec *r;
850 wctx_t *wctx;
851 hc_condition_t *cond;
853
854 wctx = (wctx_t *)hc->context;
855 if (!wctx->req || !wctx->method) {
856 return APR_ENOTIMPL;
857 }
858
859 if ((status = hc_get_backend("HCOH", &backend, hc, ctx)) != OK) {
860 return backend_cleanup("HCOH", backend, ctx->s, status);
861 }
862 if ((status = ap_proxy_connect_backend("HCOH", backend, hc, ctx->s)) != OK) {
863 return backend_cleanup("HCOH", backend, ctx->s, status);
864 }
865
866 r = create_request_rec(ptemp, ctx->s, baton->balancer, wctx->method, wctx->protocol);
867 if ((status = ap_proxy_connection_create_ex("HCOH", backend, r)) != OK) {
868 return backend_cleanup("HCOH", backend, ctx->s, status);
869 }
871 backend->connection->current_thread = thread;
872
874
875 if ((status = hc_send(r, wctx->req, bb)) != OK) {
876 return backend_cleanup("HCOH", backend, ctx->s, status);
877 }
878 if ((status = hc_read_headers(r)) != OK) {
879 return backend_cleanup("HCOH", backend, ctx->s, status);
880 }
881 if (!r->header_only) {
885 status = hc_read_body(r, bb);
887 if (status != OK) {
888 return backend_cleanup("HCOH", backend, ctx->s, status);
889 }
891 }
892
893 if (*worker->s->hcexpr &&
894 (cond = (hc_condition_t *)apr_table_get(ctx->conditions, worker->s->hcexpr)) != NULL) {
895 const char *err;
896 int ok = ap_expr_exec(r, cond->pexpr, &err);
897 if (ok > 0) {
899 "Condition %s for %s (%s): passed", worker->s->hcexpr,
900 hc->s->name_ex, worker->s->name_ex);
901 } else if (ok < 0 || err) {
903 "Error on checking condition %s for %s (%s): %s", worker->s->hcexpr,
904 hc->s->name_ex, worker->s->name_ex, err);
905 status = !OK;
906 } else {
908 "Condition %s for %s (%s) : failed", worker->s->hcexpr,
909 hc->s->name_ex, worker->s->name_ex);
910 status = !OK;
911 }
912 } else if (r->status < 200 || r->status > 399) {
914 "Response status %i for %s (%s): failed", r->status,
915 hc->s->name_ex, worker->s->name_ex);
916 status = !OK;
917 }
918 return backend_cleanup("HCOH", backend, ctx->s, status);
919}
920
921static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b)
922{
923 baton_t *baton = (baton_t *)b;
924 server_rec *s = baton->ctx->s;
925 proxy_worker *worker = baton->worker;
926 proxy_worker *hc = baton->hc;
928 apr_status_t rv;
929
931 "%sHealth checking %s", (thread ? "Threaded " : ""),
932 worker->s->name_ex);
933
934 if (hc->s->method == TCP) {
935 rv = hc_check_tcp(baton);
936 }
937 else if (hc->s->method == CPING) {
938 rv = hc_check_cping(baton, thread);
939 }
940 else {
941 rv = hc_check_http(baton, thread);
942 }
943
944 now = apr_time_now();
945 if (rv == APR_ENOTIMPL) {
947 "Somehow tried to use unimplemented hcheck method: %d",
948 (int)hc->s->method);
949 }
950 /* what state are we in ? */
951 else if (PROXY_WORKER_IS_HCFAILED(worker) || PROXY_WORKER_IS_ERROR(worker)) {
952 if (rv == APR_SUCCESS) {
953 worker->s->pcount += 1;
954 if (worker->s->pcount >= worker->s->passes) {
957 worker->s->pcount = 0;
959 "%sHealth check ENABLING %s", (thread ? "Threaded " : ""),
960 worker->s->name_ex);
961
962 }
963 }
964 }
965 else {
966 if (rv != APR_SUCCESS) {
967 worker->s->error_time = now;
968 worker->s->fcount += 1;
969 if (worker->s->fcount >= worker->s->fails) {
971 worker->s->fcount = 0;
973 "%sHealth check DISABLING %s", (thread ? "Threaded " : ""),
974 worker->s->name_ex);
975 }
976 }
977 }
978 if (baton->now) {
979 *baton->now = now;
980 }
981 apr_pool_destroy(baton->ptemp);
982 worker->s->updated = now;
983
984 return NULL;
985}
986
987static apr_status_t hc_watchdog_callback(int state, void *data,
989{
991 proxy_balancer *balancer;
992 sctx_t *ctx = (sctx_t *)data;
993 server_rec *s = ctx->s;
994 proxy_server_conf *conf;
995
996 switch (state) {
999 "%s watchdog started.",
1001#if HC_USE_THREADS
1002 if (tpsize && hctp == NULL) {
1004 tpsize, ctx->p);
1005 if (rv != APR_SUCCESS) {
1007 "apr_thread_pool_create() with %d threads failed",
1008 tpsize);
1009 /* we can continue on without the threadpools */
1010 hctp = NULL;
1011 } else {
1013 "apr_thread_pool_create() with %d threads succeeded",
1014 tpsize);
1015 }
1016 } else {
1018 "Skipping apr_thread_pool_create()");
1019 hctp = NULL;
1020 }
1021#endif
1022 break;
1023
1025 /* loop thru all workers */
1026 if (s) {
1027 int i;
1028 conf = (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
1029 balancer = (proxy_balancer *)conf->balancers->elts;
1030 ctx->s = s;
1031 for (i = 0; i < conf->balancers->nelts; i++, balancer++) {
1032 int n;
1035 proxy_worker *worker;
1036 /* Have any new balancers or workers been added dynamically? */
1037 ap_proxy_sync_balancer(balancer, s, conf);
1038 workers = (proxy_worker **)balancer->workers->elts;
1039 now = apr_time_now();
1040 for (n = 0; n < balancer->workers->nelts; n++) {
1041 worker = *workers;
1042 if (!PROXY_WORKER_IS(worker, PROXY_WORKER_STOPPED) &&
1043 (worker->s->method != NONE) &&
1044 (worker->s->updated != 0) &&
1045 (now > worker->s->updated + worker->s->interval)) {
1046 baton_t *baton;
1047 apr_pool_t *ptemp;
1048
1050 "Checking %s worker: %s [%d] (%pp)", balancer->s->name,
1051 worker->s->name_ex, worker->s->method, worker);
1052
1053 /* This pool has the lifetime of the check */
1054 apr_pool_create(&ptemp, ctx->p);
1055 apr_pool_tag(ptemp, "hc_request");
1056 baton = apr_pcalloc(ptemp, sizeof(baton_t));
1057 baton->ctx = ctx;
1058 baton->balancer = balancer;
1059 baton->worker = worker;
1060 baton->ptemp = ptemp;
1061 if ((rv = hc_init_baton(baton))) {
1062 worker->s->updated = now;
1063 apr_pool_destroy(ptemp);
1064 return rv;
1065 }
1066 worker->s->updated = 0;
1067#if HC_USE_THREADS
1068 if (hctp) {
1071 NULL);
1072 }
1073 else
1074#endif
1075 {
1076 baton->now = &now;
1078 }
1079 }
1080 workers++;
1081 }
1082 }
1083 }
1084 break;
1085
1088 "stopping %s watchdog.",
1090#if HC_USE_THREADS
1091 if (hctp) {
1093 if (rv != APR_SUCCESS) {
1095 "apr_thread_pool_destroy() failed");
1096 }
1097 hctp = NULL;
1098 }
1099#endif
1100 break;
1101 }
1102 return rv;
1103}
1105 apr_pool_t *ptemp)
1106{
1107#if HC_USE_THREADS
1108 hctp = NULL;
1110#endif
1111
1115 for (; method->name; method++) {
1116 if (method->method == CPING) {
1117 method->implemented = 1;
1118 break;
1119 }
1120 }
1121 }
1122
1123 return OK;
1124}
1126 apr_pool_t *ptemp, server_rec *main_s)
1127{
1128 apr_status_t rv;
1129 server_rec *s = main_s;
1130
1133
1135 return OK;
1136 }
1141 "mod_watchdog is required");
1142 return !OK;
1143 }
1146 0, 1, p);
1147 if (rv) {
1149 "Failed to create watchdog instance (%s)",
1151 return !OK;
1152 }
1153 while (s) {
1154 sctx_t *ctx = ap_get_module_config(s->module_config,
1155 &proxy_hcheck_module);
1156
1157 if (s != ctx->s) {
1159 "Missing unique per-server context: %s (%pp:%pp) (no hchecks)",
1160 s->server_hostname, s, ctx->s);
1161 s = s->next;
1162 continue;
1163 }
1166 ctx,
1168 if (rv) {
1170 "Failed to register watchdog callback (%s)",
1172 return !OK;
1173 }
1175 "watchdog callback registered (%s for %s)", HCHECK_WATHCHDOG_NAME, s->server_hostname);
1176 s = s->next;
1177 }
1178
1179 return OK;
1180}
1181
1183{
1184 const apr_table_entry_t *elts;
1185 const apr_array_header_t *hdr;
1186 int i;
1188 &proxy_hcheck_module);
1189 if (!ctx)
1190 return;
1191 if (apr_is_empty_table(ctx->conditions))
1192 return;
1193
1194 ap_rputs("\n\n<table>"
1195 "<tr><th colspan='2'>Health check cond. expressions:</th></tr>\n"
1196 "<tr><th>Expr name</th><th>Expression</th></tr>\n", r);
1197
1198 hdr = apr_table_elts(ctx->conditions);
1199 elts = (const apr_table_entry_t *) hdr->elts;
1200 for (i = 0; i < hdr->nelts; ++i) {
1201 hc_condition_t *cond;
1202 if (!elts[i].key) {
1203 continue;
1204 }
1205 cond = (hc_condition_t *)elts[i].val;
1206 ap_rprintf(r, "<tr><td>%s</td><td>%s</td></tr>\n",
1207 ap_escape_html(r->pool, elts[i].key),
1208 ap_escape_html(r->pool, cond->expr));
1209 }
1210 ap_rputs("</table><hr/>\n", r);
1211}
1212
1213static void hc_select_exprs(request_rec *r, const char *expr)
1214{
1215 const apr_table_entry_t *elts;
1216 const apr_array_header_t *hdr;
1217 int i;
1219 &proxy_hcheck_module);
1220 if (!ctx)
1221 return;
1222 if (apr_is_empty_table(ctx->conditions))
1223 return;
1224
1225 hdr = apr_table_elts(ctx->conditions);
1226 elts = (const apr_table_entry_t *) hdr->elts;
1227 for (i = 0; i < hdr->nelts; ++i) {
1228 if (!elts[i].key) {
1229 continue;
1230 }
1231 ap_rprintf(r, "<option value='%s' %s >%s</option>\n",
1232 ap_escape_html(r->pool, elts[i].key),
1233 (!strcmp(elts[i].key, expr)) ? "selected" : "",
1234 ap_escape_html(r->pool, elts[i].key));
1235 }
1236}
1237
1238static int hc_valid_expr(request_rec *r, const char *expr)
1239{
1240 const apr_table_entry_t *elts;
1241 const apr_array_header_t *hdr;
1242 int i;
1244 &proxy_hcheck_module);
1245 if (!ctx)
1246 return 0;
1247 if (apr_is_empty_table(ctx->conditions))
1248 return 0;
1249
1250 hdr = apr_table_elts(ctx->conditions);
1251 elts = (const apr_table_entry_t *) hdr->elts;
1252 for (i = 0; i < hdr->nelts; ++i) {
1253 if (!elts[i].key) {
1254 continue;
1255 }
1256 if (!strcmp(elts[i].key, expr))
1257 return 1;
1258 }
1259 return 0;
1260}
1261
1262static const char *hc_get_body(request_rec *r)
1263{
1266 apr_status_t rv;
1267 char *buf;
1268
1269 if (!r || !r->kept_body)
1270 return "";
1271
1274 if (rv != APR_SUCCESS || len == 0)
1275 return "";
1276
1277 buf = apr_palloc(r->pool, len + 1);
1279 if (rv != APR_SUCCESS)
1280 return "";
1281 buf[len] = '\0'; /* ensure */
1282 return (const char*)buf;
1283}
1284
1285static const char *hc_expr_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1286{
1287 char *var = (char *)data;
1288
1289 if (var && *var && ctx->r && ap_cstr_casecmp(var, "BODY") == 0) {
1290 return hc_get_body(ctx->r);
1291 }
1292 return NULL;
1293}
1294
1295static const char *hc_expr_func_fn(ap_expr_eval_ctx_t *ctx, const void *data,
1296 const char *arg)
1297{
1298 char *var = (char *)arg;
1299
1300 if (var && *var && ctx->r && ap_cstr_casecmp(var, "BODY") == 0) {
1301 return hc_get_body(ctx->r);
1302 }
1303 return NULL;
1304}
1305
1307{
1308 switch (parms->type) {
1309 case AP_EXPR_FUNC_VAR:
1310 /* for now, we just handle everything that starts with HC_.
1311 */
1312 if (strncasecmp(parms->name, "HC_", 3) == 0) {
1313 *parms->func = hc_expr_var_fn;
1314 *parms->data = parms->name + 3;
1315 return OK;
1316 }
1317 break;
1319 /* Function HC() is implemented by us.
1320 */
1321 if (strcasecmp(parms->name, "HC") == 0) {
1322 *parms->func = hc_expr_func_fn;
1323 *parms->data = parms->arg;
1324 return OK;
1325 }
1326 break;
1327 }
1328 return DECLINED;
1329}
1330
1331static const command_rec command_table[] = {
1332 AP_INIT_RAW_ARGS("ProxyHCTemplate", set_hc_template, NULL, OR_FILEINFO,
1333 "Health check template"),
1335 "Define a health check condition ruleset expression"),
1336#if HC_USE_THREADS
1337 AP_INIT_TAKE1("ProxyHCTPsize", set_hc_tpsize, NULL, RSRC_CONF,
1338 "Set size of health check thread pool"),
1339#endif
1340 { NULL }
1341};
1342
1355
1356/* the main config structure */
1357
1359{
1361 NULL, /* create per-dir config structures */
1362 NULL, /* merge per-dir config structures */
1363 hc_create_config, /* create per-server config structures */
1364 NULL, /* merge per-server config structures */
1365 command_table, /* table of config file commands */
1366 hc_register_hooks /* register hooks */
1367};
Expression parser.
#define AP_EXPR_FUNC_STRING
Definition ap_expr.h:259
#define AP_EXPR_FUNC_VAR
Definition ap_expr.h:258
int n
Definition ap_regex.h:278
const char apr_size_t len
Definition ap_regex.h:187
Memory Slot Extension Storage Module for Apache.
APR Thread Pool Library.
ap_conf_vector_t * ap_merge_per_dir_configs(apr_pool_t *p, ap_conf_vector_t *base, ap_conf_vector_t *new_conf)
Definition config.c:285
static apr_pool_t * pconf
Definition event.c:441
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
ap_conf_vector_t * ap_create_request_config(apr_pool_t *p)
Definition config.c:356
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
#define AP_INIT_RAW_ARGS(directive, func, mconfig, where, help)
#define ap_set_module_config(v, m, val)
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
request_rec * r
#define HUGE_STRING_LEN
Definition httpd.h:303
#define DECLINED
Definition httpd.h:457
#define HTTP_VERSION(major, minor)
Definition httpd.h:269
#define OK
Definition httpd.h:456
apr_status_t ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket)
apr_status_t ap_get_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
#define AP_SQ_MS_CREATE_PRE_CONFIG
Definition http_core.h:1047
int ap_state_query(int query_code)
Definition core.c:5378
#define AP_SQ_MAIN_STATE
Definition http_core.h:1030
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_TRACE4
Definition http_log.h:75
#define APLOG_INFO
Definition http_log.h:70
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_TRACE3
Definition http_log.h:74
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
#define APLOG_TRACE7
Definition http_log.h:78
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_EMERG
Definition http_log.h:64
#define APLOG_TRACE2
Definition http_log.h:73
#define APLOG_DEBUG
Definition http_log.h:71
const unsigned char * buf
Definition util_md5.h:50
int ap_method_number_of(const char *method)
ap_method_list_t * ap_make_method_list(apr_pool_t *p, int nelts)
int ap_rprintf(request_rec *r, const char *fmt,...) __attribute__((format(printf
static APR_INLINE int ap_rputs(const char *str, request_rec *r)
void ap_set_content_type(request_rec *r, const char *ct)
int ap_getline(char *s, int n, request_rec *r, int flags)
Definition protocol.c:545
int ap_ssl_has_outgoing_handlers(void)
Definition ssl.c:164
const char apr_port_t port
Definition http_vhost.h:125
ap_vhost_iterate_conn_cb void * baton
Definition http_vhost.h:87
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_STATUS_IS_EOF(s)
Definition apr_errno.h:567
#define APR_BUCKET_IS_FLUSH(e)
#define APR_BUCKET_REMOVE(e)
#define APR_BRIGADE_INSERT_TAIL(b, e)
#define APR_BRIGADE_EMPTY(b)
#define apr_bucket_delete(e)
#define APR_BUCKET_IS_EOS(e)
apr_brigade_flush void * ctx
#define APR_BRIGADE_FIRST(b)
int apr_off_t * length
@ APR_BLOCK_READ
Definition apr_buckets.h:58
const char * url
Definition apr_escape.h:120
const char *const const char *const * aszSucc
Definition apr_hooks.h:346
const char *const * aszPre
Definition apr_hooks.h:345
#define APR_HOOK_LAST
Definition apr_hooks.h:305
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define APR_RETRIEVE_OPTIONAL_FN(name)
#define APR_OPTIONAL_FN_TYPE(name)
#define APR_REGISTER_OPTIONAL_FN(name)
const char * uri
Definition apr_uri.h:159
apr_text_header * hdr
Definition apr_xml.h:77
#define ap_expr_parse_cmd(cmd, expr, flags, err, lookup_fn)
Definition ap_expr.h:340
int ap_expr_exec(request_rec *r, const ap_expr_info_t *expr, const char **err)
void ap_hook_expr_lookup(ap_HOOK_expr_lookup_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
#define RSRC_CONF
#define OR_FILEINFO
#define HTTP_OK
Definition httpd.h:490
int ap_proxy_connect_backend(const char *proxy_function, proxy_conn_rec *conn, proxy_worker *worker, server_rec *s)
#define PROXY_WORKER_IS_HCFAILED(f)
Definition mod_proxy.h:365
apr_status_t ap_proxy_set_wstatus(char c, int set, proxy_worker *w)
#define PROXY_WORKER_STOPPED
Definition mod_proxy.h:326
#define PROXY_STRNCPY(dst, src)
Definition mod_proxy.h:395
int ap_proxy_release_connection(const char *proxy_function, proxy_conn_rec *conn, server_rec *s)
int ap_proxy_acquire_connection(const char *proxy_function, proxy_conn_rec **conn, proxy_worker *worker, server_rec *s)
apr_status_t ap_proxy_determine_address(const char *proxy_function, proxy_conn_rec *conn, const char *hostname, apr_port_t hostport, unsigned int flags, request_rec *r, server_rec *s)
#define PROXY_WORKER_IGNORE_ERRORS
Definition mod_proxy.h:321
char * ap_proxy_define_worker(apr_pool_t *p, proxy_worker **worker, proxy_balancer *balancer, proxy_server_conf *conf, const char *url, int do_malloc)
hcmethod_t
Definition mod_proxy.h:83
#define PROXY_WORKER_MAX_SCHEME_SIZE
Definition mod_proxy.h:375
int ap_proxy_pre_http_request(conn_rec *c, request_rec *r)
Definition proxy_util.c:876
#define PROXY_WORKER_GENERIC
Definition mod_proxy.h:323
#define PROXY_WORKER_IS(f, b)
Definition mod_proxy.h:369
#define PROXY_WORKER_IS_ERROR(f)
Definition mod_proxy.h:367
apr_status_t ap_proxy_sync_balancer(proxy_balancer *b, server_rec *s, proxy_server_conf *conf)
int ap_proxy_connection_create_ex(const char *proxy_function, proxy_conn_rec *conn, request_rec *r)
unsigned int ap_proxy_hashfunc(const char *str, proxy_hash_t method)
const char * ap_proxy_show_hcmethod(hcmethod_t method)
apr_status_t ap_proxy_initialize_worker(proxy_worker *worker, server_rec *s, apr_pool_t *p)
#define HCHECK_WATHCHDOG_DEFAULT_INTERVAL
Definition mod_proxy.h:516
apr_port_t ap_proxy_port_of_scheme(const char *scheme)
#define PROXY_WORKER_HC_FAIL_FLAG
Definition mod_proxy.h:344
#define PROXY_WORKER_IN_ERROR_FLAG
Definition mod_proxy.h:341
proxy_hcmethods_t proxy_hcmethods[]
Definition mod_proxy.c:47
@ HEAD
Definition mod_proxy.h:84
@ HEAD11
Definition mod_proxy.h:84
@ GET
Definition mod_proxy.h:84
@ OPTIONS
Definition mod_proxy.h:84
@ GET11
Definition mod_proxy.h:84
@ OPTIONS11
Definition mod_proxy.h:84
@ TCP
Definition mod_proxy.h:84
@ CPING
Definition mod_proxy.h:84
@ NONE
Definition mod_proxy.h:84
@ PROXY_HASHFUNC_DEFAULT
Definition mod_proxy.h:1234
@ PROXY_HASHFUNC_FNV
Definition mod_proxy.h:1234
#define AP_WATCHDOG_STATE_STARTING
#define AP_WATCHDOG_STATE_STOPPING
#define AP_WATCHDOG_STATE_RUNNING
#define AP_WD_TM_SLICE
#define M_OPTIONS
Definition httpd.h:597
#define M_GET
Definition httpd.h:592
#define STANDARD20_MODULE_STUFF
char * ap_getword_conf2(apr_pool_t *p, const char **line)
Definition util.c:882
int ap_cstr_casecmp(const char *s1, const char *s2)
Definition util.c:3542
#define ap_escape_html(p, s)
Definition httpd.h:1860
#define PROXYREQ_RESPONSE
Definition httpd.h:1136
apr_status_t ap_timeout_parameter_parse(const char *timeout_parameter, apr_interval_time_t *timeout, const char *default_time_unit)
Definition util.c:2622
char * ap_getword_conf(apr_pool_t *p, const char **line)
Definition util.c:833
#define NOT_IN_HTACCESS
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define apr_isspace(c)
Definition apr_lib.h:225
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
void * data
char * buffer
int strcasecmp(const char *a, const char *b)
int strncasecmp(const char *a, const char *b, size_t n)
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_uint16_t apr_port_t
int int int protocol
apr_uint32_t apr_pool_t apr_uint32_t apr_pollset_method_e method
Definition apr_poll.h:195
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char char ** end
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
apr_cmdtype_e cmd
int int status
#define apr_time_as_msec(time)
Definition apr_time.h:72
#define APR_TIME_T_FMT
Definition apr_time.h:52
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
apr_int64_t apr_time_t
Definition apr_time.h:45
#define apr_time_from_sec(sec)
Definition apr_time.h:78
#define REQUEST_NO_BODY
Definition httpd.h:746
#define AP_REQ_DEFAULT_PATH_INFO
Definition httpd.h:765
static struct h2_workers * workers
Definition h2_c1.c:48
SSL protocol handling.
apr_pool_t * p
Definition md_event.c:32
static apr_file_t * out
Definition mod_info.c:85
Proxy Extension Module for Apache.
static const char * hc_expr_func_fn(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
static apr_status_t hc_check_http(baton_t *baton, apr_thread_t *thread)
#define HC_THREADPOOL_SIZE
static void hc_show_exprs(request_rec *r)
static const command_rec command_table[]
static const char * set_hc_template(cmd_parms *cmd, void *dummy, const char *arg)
static int hc_valid_expr(request_rec *r, const char *expr)
static int hc_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_s)
static apr_status_t hc_watchdog_callback(int state, void *data, apr_pool_t *pool)
static const char * hc_get_body(request_rec *r)
static void create_hcheck_req(wctx_t *wctx, proxy_worker *hc, apr_pool_t *p)
static int hc_expr_lookup(ap_expr_lookup_parms *parms)
static ap_watchdog_t * watchdog
static void set_request_connection(request_rec *r, conn_rec *conn)
static int hc_read_headers(request_rec *r)
static int hc_send(request_rec *r, const char *out, apr_bucket_brigade *bb)
static apr_OFN_ajp_handle_cping_cpong_t * ajp_handle_cping_cpong
static const char * hc_expr_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
static apr_status_t hc_init_baton(baton_t *baton)
static const char * set_worker_hc_param(apr_pool_t *p, server_rec *s, proxy_worker *worker, const char *key, const char *val, void *v)
static void *APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b)
static void * hc_create_config(apr_pool_t *p, server_rec *s)
static proxy_worker * hc_get_hcworker(sctx_t *ctx, proxy_worker *worker, apr_pool_t *p)
static int hc_get_backend(const char *proxy_function, proxy_conn_rec **backend, proxy_worker *hc, sctx_t *ctx)
static void hc_register_hooks(apr_pool_t *p)
static apr_status_t hc_check_tcp(baton_t *baton)
static request_rec * create_request_rec(apr_pool_t *p, server_rec *s, proxy_balancer *balancer, const char *method, const char *protocol)
static int hc_determine_connection(const char *proxy_function, proxy_conn_rec *backend, server_rec *s)
static apr_status_t backend_cleanup(const char *proxy_function, proxy_conn_rec *backend, server_rec *s, int status)
static int hc_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
#define HCHECK_WATHCHDOG_NAME
static int hc_read_body(request_rec *r, apr_bucket_brigade *bb)
static void hc_select_exprs(request_rec *r, const char *expr)
static apr_status_t hc_check_cping(baton_t *baton, apr_thread_t *thread)
static const char * set_hc_condition(cmd_parms *cmd, void *dummy, const char *arg)
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
static apr_status_t ap_watchdog_register_callback(ap_watchdog_t *w, apr_interval_time_t interval, const void *data, ap_watchdog_callback_fn_t *callback)
static apr_status_t ap_watchdog_get_instance(ap_watchdog_t **watchdog, const char *name, int parent, int singleton, apr_pool_t *p)
Watchdog module for Apache.
char * name
Definition apr_tables.h:81
char * key
Definition apr_tables.h:83
proxy_worker * worker
proxy_balancer * balancer
apr_time_t * now
proxy_worker * hc
apr_pool_t * ptemp
sctx_t * ctx
Structure to store things which are per connection.
Definition httpd.h:1152
apr_sockaddr_t * client_addr
Definition httpd.h:1166
struct ap_filter_t * input_filters
Definition httpd.h:1195
struct ap_filter_t * output_filters
Definition httpd.h:1197
struct apr_bucket_alloc_t * bucket_alloc
Definition httpd.h:1201
char * client_ip
Definition httpd.h:1171
ap_expr_info_t * pexpr
hcmethod_t method
apr_interval_time_t interval
ap_conf_vector_t * section_config
Definition mod_proxy.h:579
proxy_balancer_shared * s
Definition mod_proxy.h:574
apr_array_header_t * workers
Definition mod_proxy.h:559
apr_socket_t * sock
Definition mod_proxy.h:278
proxy_worker * worker
Definition mod_proxy.h:273
unsigned int close
Definition mod_proxy.h:284
conn_rec * connection
Definition mod_proxy.h:270
unsigned int fnv
Definition mod_proxy.h:419
unsigned int def
Definition mod_proxy.h:418
apr_array_header_t * balancers
Definition mod_proxy.h:161
unsigned int conn_timeout_set
Definition mod_proxy.h:472
unsigned int timeout_set
Definition mod_proxy.h:469
apr_interval_time_t timeout
Definition mod_proxy.h:453
char hostname_ex[256]
Definition mod_proxy.h:488
apr_time_t updated
Definition mod_proxy.h:448
hcmethod_t method
Definition mod_proxy.h:485
apr_time_t error_time
Definition mod_proxy.h:449
unsigned int ping_timeout_set
Definition mod_proxy.h:471
unsigned int status
Definition mod_proxy.h:442
apr_interval_time_t interval
Definition mod_proxy.h:486
apr_interval_time_t conn_timeout
Definition mod_proxy.h:456
proxy_hashes hash
Definition mod_proxy.h:441
apr_interval_time_t ping_timeout
Definition mod_proxy.h:455
unsigned int is_address_reusable
Definition mod_proxy.h:467
unsigned int disablereuse
Definition mod_proxy.h:466
proxy_conn_pool * cp
Definition mod_proxy.h:504
proxy_worker_shared * s
Definition mod_proxy.h:505
void * context
Definition mod_proxy.h:510
proxy_hashes hash
Definition mod_proxy.h:502
A structure that represents the current request.
Definition httpd.h:845
char * user
Definition httpd.h:1005
int status
Definition httpd.h:891
apr_table_t * trailers_in
Definition httpd.h:1104
struct ap_filter_t * output_filters
Definition httpd.h:1070
char * useragent_ip
Definition httpd.h:1101
int read_body
Definition httpd.h:947
int header_only
Definition httpd.h:875
struct ap_filter_t * proto_input_filters
Definition httpd.h:1079
apr_table_t * notes
Definition httpd.h:985
const char * hostname
Definition httpd.h:883
int used_path_info
Definition httpd.h:1036
char * the_request
Definition httpd.h:866
int method_number
Definition httpd.h:898
apr_pool_t * pool
Definition httpd.h:847
apr_sockaddr_t * useragent_addr
Definition httpd.h:1100
int proxyreq
Definition httpd.h:873
conn_rec * connection
Definition httpd.h:849
apr_bucket_brigade * kept_body
Definition httpd.h:953
ap_method_list_t * allowed_methods
Definition httpd.h:926
apr_table_t * err_headers_out
Definition httpd.h:981
struct ap_filter_t * proto_output_filters
Definition httpd.h:1076
int proto_num
Definition httpd.h:877
struct ap_filter_t * input_filters
Definition httpd.h:1072
struct ap_conf_vector_t * request_config
Definition httpd.h:1049
apr_table_t * headers_in
Definition httpd.h:976
char * protocol
Definition httpd.h:879
apr_off_t read_length
Definition httpd.h:961
apr_table_t * subprocess_env
Definition httpd.h:983
apr_off_t sent_bodyct
Definition httpd.h:929
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
const char * status_line
Definition httpd.h:889
const char * method
Definition httpd.h:900
apr_table_t * trailers_out
Definition httpd.h:1106
char * ap_auth_type
Definition httpd.h:1007
apr_table_t * headers_out
Definition httpd.h:978
server_rec * s
apr_table_t * conditions
apr_hash_t * hcworkers
apr_array_header_t * templates
apr_pool_t * p
A structure to store information for each virtual server.
Definition httpd.h:1322
struct ap_conf_vector_t * lookup_defaults
Definition httpd.h:1343
struct ap_conf_vector_t * module_config
Definition httpd.h:1341
const char * path
const char * method
const char * req
proxy_worker * w
const char * protocol
static apr_time_t now
Definition testtime.c:33
apr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
Definition sockopt.c:355
#define var
@ AP_MODE_READBYTES
Definition util_filter.h:43
IN ULONG IN INT timeout