typedef struct {
apr_pool_t *p;
+ apr_bucket_alloc_t *ba;
apr_array_header_t *templates;
apr_array_header_t *conditions;
ap_watchdog_t *watchdog;
{
sctx_t *ctx = (sctx_t *) apr_palloc(p, sizeof(sctx_t));
apr_pool_create(&ctx->p, p);
+ ctx->ba = apr_bucket_alloc_create(p);
ctx->templates = apr_array_make(ctx->p, 10, sizeof(hc_template_t));
ctx->conditions = apr_array_make(ctx->p, 10, sizeof(hc_condition_t));
ctx->hcworkers = apr_hash_make(ctx->p);
return ctx;
}
-static proxy_worker *hc_get_hcworker(sctx_t *ctx, proxy_worker *worker)
-{
- proxy_worker *hc = NULL;
- const char* wptr;
-
- wptr = apr_psprintf(ctx->p, "%pp", worker);
- hc = (proxy_worker *)apr_hash_get(ctx->hcworkers, wptr, APR_HASH_KEY_STRING);
- if (!hc) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
- "Creating hc worker %s for %s://%s:%d",
- wptr, worker->s->scheme, worker->s->hostname,
- (int)worker->s->port);
-
- ap_proxy_define_worker(ctx->p, &hc, NULL, NULL, worker->s->name, 0);
- PROXY_STRNCPY(hc->s->name, wptr);
- PROXY_STRNCPY(hc->s->hostname, worker->s->hostname);
- PROXY_STRNCPY(hc->s->scheme, worker->s->scheme);
- hc->hash.def = hc->s->hash.def = ap_proxy_hashfunc(hc->s->name, PROXY_HASHFUNC_DEFAULT);
- hc->hash.fnv = hc->s->hash.fnv = ap_proxy_hashfunc(hc->s->name, PROXY_HASHFUNC_FNV);
- hc->s->port = worker->s->port;
- /* Do not disable worker in case of errors */
- hc->s->status |= PROXY_WORKER_IGNORE_ERRORS;
- /* Mark as the "generic" worker */
- hc->s->status |= PROXY_WORKER_GENERIC;
- ap_proxy_initialize_worker(hc, ctx->s, ctx->p);
- /* Enable address cache for generic reverse worker */
- hc->s->is_address_reusable = 1;
- /* tuck away since we need the preparsed address */
- hc->cp->addr = worker->cp->addr;
- hc->s->method = worker->s->method;
- apr_hash_set(ctx->hcworkers, wptr, APR_HASH_KEY_STRING, hc);
- }
- return hc;
-}
-
-static apr_status_t hc_init_worker(sctx_t *ctx, proxy_worker *worker) {
- /*
- * Since this is the watchdog, workers never actually handle a
- * request here, and so the local data isn't initialized (of
- * course, the shared memory is). So we need to bootstrap
- * worker->cp. Note, we only need do this once.
- */
- if (!worker->cp) {
- apr_status_t rv;
- apr_status_t err = APR_SUCCESS;
- rv = ap_proxy_initialize_worker(worker, ctx->s, ctx->p);
- if (rv != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ctx->s, APLOGNO() "Cannot init worker");
- return rv;
- }
- /*
- * normally, this is done in ap_proxy_determine_connection().
- * TODO: Look at using ap_proxy_determine_connection() with a
- * fake request_rec
- */
- err = apr_sockaddr_info_get(&(worker->cp->addr), worker->s->hostname, APR_UNSPEC,
- worker->s->port, 0, ctx->p);
-
- if (err != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
- "DNS lookup failure for: %s:%d",
- worker->s->hostname, (int)worker->s->port);
- return err;
- }
- }
- return APR_SUCCESS;
-}
-
-
/*
* This serves double duty by not only validating (and creating)
* the health-check template, but also ties into set_worker_param()
return NULL;
}
+
+static request_rec *create_request_rec(conn_rec *conn)
+{
+ request_rec *r;
+ apr_pool_t *p;
+
+ apr_pool_create(&p, conn->pool);
+ apr_pool_tag(p, "request");
+ r = apr_pcalloc(p, sizeof(request_rec));
+ r->pool = p;
+ r->connection = conn;
+ r->server = conn->base_server;
+
+ r->user = NULL;
+ r->ap_auth_type = NULL;
+
+ r->allowed_methods = ap_make_method_list(p, 2);
+
+ r->headers_in = apr_table_make(r->pool, 25);
+ r->trailers_in = apr_table_make(r->pool, 5);
+ r->subprocess_env = apr_table_make(r->pool, 25);
+ r->headers_out = apr_table_make(r->pool, 12);
+ r->err_headers_out = apr_table_make(r->pool, 5);
+ r->trailers_out = apr_table_make(r->pool, 5);
+ r->notes = apr_table_make(r->pool, 5);
+
+ r->request_config = ap_create_request_config(r->pool);
+ /* Must be set before we run create request hook */
+
+ r->proto_output_filters = conn->output_filters;
+ r->output_filters = r->proto_output_filters;
+ r->proto_input_filters = conn->input_filters;
+ r->input_filters = r->proto_input_filters;
+ r->per_dir_config = r->server->lookup_defaults;
+
+ r->sent_bodyct = 0; /* bytect isn't for body */
+
+ r->read_length = 0;
+ r->read_body = REQUEST_NO_BODY;
+
+ r->status = HTTP_OK; /* Until further notice */
+ r->header_only = 0;
+ r->the_request = NULL;
+
+ /* Begin by presuming any module can make its own path_info assumptions,
+ * until some module interjects and changes the value.
+ */
+ r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
+
+ r->useragent_addr = conn->client_addr;
+ r->useragent_ip = conn->client_ip;
+
+
+ /* Time to populate r with the data we have. */
+ r->method = "OPTIONS";
+ /* Provide quick information about the request method as soon as known */
+ r->method_number = ap_method_number_of(r->method);
+ if (r->method_number == M_GET && r->method[0] == 'H') {
+ r->header_only = 1;
+ }
+
+ r->protocol = (char*)"HTTP/1.1";
+ r->proto_num = HTTP_VERSION(1, 1);
+
+ r->hostname = NULL;
+
+ return r;
+}
+
+static proxy_worker *hc_get_hcworker(sctx_t *ctx, proxy_worker *worker)
+{
+ proxy_worker *hc = NULL;
+ const char* wptr;
+
+ wptr = apr_psprintf(ctx->p, "%pp", worker);
+ hc = (proxy_worker *)apr_hash_get(ctx->hcworkers, wptr, APR_HASH_KEY_STRING);
+ if (!hc) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
+ "Creating hc worker %s for %s://%s:%d",
+ wptr, worker->s->scheme, worker->s->hostname,
+ (int)worker->s->port);
+
+ ap_proxy_define_worker(ctx->p, &hc, NULL, NULL, worker->s->name, 0);
+ PROXY_STRNCPY(hc->s->name, wptr);
+ PROXY_STRNCPY(hc->s->hostname, worker->s->hostname);
+ PROXY_STRNCPY(hc->s->scheme, worker->s->scheme);
+ hc->hash.def = hc->s->hash.def = ap_proxy_hashfunc(hc->s->name, PROXY_HASHFUNC_DEFAULT);
+ hc->hash.fnv = hc->s->hash.fnv = ap_proxy_hashfunc(hc->s->name, PROXY_HASHFUNC_FNV);
+ hc->s->port = worker->s->port;
+ /* Do not disable worker in case of errors */
+ hc->s->status |= PROXY_WORKER_IGNORE_ERRORS;
+ /* Mark as the "generic" worker */
+ hc->s->status |= PROXY_WORKER_GENERIC;
+ ap_proxy_initialize_worker(hc, ctx->s, ctx->p);
+ /* Enable address cache for generic reverse worker */
+ hc->s->is_address_reusable = 1;
+ /* tuck away since we need the preparsed address */
+ hc->cp->addr = worker->cp->addr;
+ hc->s->method = worker->s->method;
+ apr_hash_set(ctx->hcworkers, wptr, APR_HASH_KEY_STRING, hc);
+ }
+ return hc;
+}
+
+static apr_status_t hc_init_worker(sctx_t *ctx, proxy_worker *worker) {
+ /*
+ * Since this is the watchdog, workers never actually handle a
+ * request here, and so the local data isn't initialized (of
+ * course, the shared memory is). So we need to bootstrap
+ * worker->cp. Note, we only need do this once.
+ */
+ if (!worker->cp) {
+ apr_status_t rv;
+ apr_status_t err = APR_SUCCESS;
+ rv = ap_proxy_initialize_worker(worker, ctx->s, ctx->p);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ctx->s, APLOGNO() "Cannot init worker");
+ return rv;
+ }
+ /*
+ * normally, this is done in ap_proxy_determine_connection().
+ * TODO: Look at using ap_proxy_determine_connection() with a
+ * fake request_rec
+ */
+ err = apr_sockaddr_info_get(&(worker->cp->addr), worker->s->hostname, APR_UNSPEC,
+ worker->s->port, 0, ctx->p);
+
+ if (err != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
+ "DNS lookup failure for: %s:%d",
+ worker->s->hostname, (int)worker->s->port);
+ return err;
+ }
+ }
+ return APR_SUCCESS;
+}
+
static apr_status_t backend_cleanup(const char *proxy_function, proxy_conn_rec *backend,
server_rec *s, int status)
{
}
+static int hc_get_backend(const char *proxy_function, proxy_conn_rec **backend,
+ proxy_worker *hc, sctx_t *ctx)
+{
+ int status;
+ status = ap_proxy_acquire_connection("HCTCP", backend, hc, ctx->s);
+ if (status == OK) {
+ (*backend)->addr = hc->cp->addr;
+ (*backend)->pool = ctx->p;
+ (*backend)->hostname = hc->s->hostname;
+ if (strcmp(hc->s->scheme, "https") == 0) {
+ if (!ap_proxy_ssl_enable(NULL)) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
+ "mod_ssl not configured?");
+ return !OK;
+ }
+ (*backend)->is_ssl = 1;
+ }
+
+ }
+ return status;
+}
+
static apr_status_t hc_check_tcp(sctx_t *ctx, apr_pool_t *p, proxy_worker *worker)
{
int status;
hc = hc_get_hcworker(ctx, worker);
- status = ap_proxy_acquire_connection("HCTCP", &backend, hc, ctx->s);
+ status = hc_get_backend("HCTCP", &backend, hc, ctx);
if (status == OK) {
backend->addr = hc->cp->addr;
status = ap_proxy_connect_backend("HCTCP", backend, hc, ctx->s);
return backend_cleanup("HCTCP", backend, ctx->s, status);
}
-#if 0
+static void hc_send(sctx_t *ctx, apr_pool_t *p, const char *out, proxy_conn_rec *backend)
+{
+ apr_bucket_brigade *tmp_bb = apr_brigade_create(p, ctx->ba);
+ APR_BRIGADE_INSERT_TAIL(tmp_bb, apr_bucket_pool_create(out, strlen(out), p,
+ ctx->ba));
+ APR_BRIGADE_INSERT_TAIL(tmp_bb, apr_bucket_flush_create(ctx->ba));
+ ap_pass_brigade(backend->connection->output_filters, tmp_bb);
+ apr_brigade_destroy(tmp_bb);
+}
+
+static int hc_read_headers(sctx_t *ctx, request_rec *r)
+{
+ char buffer[HUGE_STRING_LEN];
+ int len;
+
+ len = ap_getline(buffer, sizeof(buffer), r, 1);
+ if (len <= 0) {
+ return !OK;
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
+ "%s", buffer);
+ /* for the below, see ap_proxy_http_process_response() */
+ if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
+ int major, minor;
+ char keepchar;
+ int proxy_status = OK;
+ const char *proxy_status_line = NULL;
+
+ major = buffer[5] - '0';
+ minor = buffer[7] - '0';
+ if ((major != 1) || (len >= sizeof(buffer)-1)) {
+ return !OK;
+ }
+
+ keepchar = buffer[12];
+ buffer[12] = '\0';
+ proxy_status = atoi(&buffer[9]);
+ if (keepchar != '\0') {
+ buffer[12] = keepchar;
+ } else {
+ buffer[12] = ' ';
+ buffer[13] = '\0';
+ }
+ proxy_status_line = apr_pstrdup(r->pool, &buffer[9]);
+ r->status = proxy_status;
+ r->status_line = proxy_status_line;
+ } else {
+ return !OK;
+ }
+ /* OK, 1st line is OK... scarf in the headers */
+ while ((len = ap_getline(buffer, sizeof(buffer), r, 1)) > 0) {
+ char *value, *end;
+ if (!(value = strchr(buffer, ':'))) {
+ return !OK;
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
+ "%s", buffer);
+ *value = '\0';
+ ++value;
+ while (apr_isspace(*value))
+ ++value; /* Skip to start of value */
+ for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end)
+ *end = '\0';
+ apr_table_add(r->headers_out, buffer, value);
+ }
+ return OK;
+}
+
static apr_status_t hc_check_options(sctx_t *ctx, apr_pool_t *p, proxy_worker *worker)
{
int status;
proxy_worker *hc;
conn_rec c;
request_rec *r;
-
- proxy_server_conf *conf = (proxy_server_conf *)ap_get_module_config(ctx->s->module_config,
- &proxy_module);
+ const char *req;
hc = hc_get_hcworker(ctx, worker);
- if ((status = ap_proxy_acquire_connection("HCTCP", &backend, hc, ctx->s)) != OK) {
- return backend_cleanup("HCTCP", backend, ctx->s, status);
- }
-/*
- if ((status = ap_proxy_determine_connection(p, r, conf, hc,
- backend, uri, &newurl, proxyname, proxyport,
- server_portstr, sizeof(server_portstr))) != OK) {
+ if ((status = hc_get_backend("HCTCP", &backend, hc, ctx)) != OK) {
return backend_cleanup("HCTCP", backend, ctx->s, status);
}
-*/
if ((status = ap_proxy_connect_backend("HCTCP", backend, hc, ctx->s)) != OK) {
return backend_cleanup("HCTCP", backend, ctx->s, status);
}
if (!backend->connection) {
- status = ap_proxy_connection_create("HCTCP", backend, &c, ctx->s);
- if (status != OK) {
+ if ((status = ap_proxy_connection_create("HCTCP", backend, &c, ctx->s)) != OK) {
return backend_cleanup("HCTCP", backend, ctx->s, status);
}
}
+ req = apr_psprintf(p, "OPTIONS * HTTP/1.1\r\nHost: %s://%s:%d\r\n\r\n",
+ hc->s->scheme, hc->s->hostname, (int)hc->s->port);
+ hc_send(ctx, p, req, backend);
- return APR_SUCCESS;
-}
+ r = create_request_rec(backend->connection);
+ r->pool = p;
+ status = hc_read_headers(ctx, r);
+
+ return backend_cleanup("HCTCP", backend, ctx->s, status);}
-#endif
static void hc_check(sctx_t *ctx, apr_pool_t *p, apr_time_t now,
proxy_worker *worker)
rv = hc_check_tcp(ctx, p, worker);
break;
+ case OPTIONS:
+ rv = hc_check_options(ctx, p, worker);
+ break;
+
default:
rv = APR_ENOTIMPL;
break;
worker = *workers;
/* TODO: REMOVE ap_log_error call */
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO()
- "Checking %s worker: %s [%d] (%lu %lu %lu)", balancer->s->name,
- worker->s->name, worker->s->method, (unsigned long)now,
- (unsigned long)worker->s->updated, (unsigned long)worker->s->interval);
+ "Checking %s worker: %s [%d] (%pp)", balancer->s->name,
+ worker->s->name, worker->s->method, worker);
if ((worker->s->method != NONE) && (now > worker->s->updated + worker->s->interval)) {
if ((rv = hc_init_worker(ctx, worker)) != APR_SUCCESS) {
return rv;