mod_serf.c revision fa9496078a83e18311b90b33574fdeb9c115ed7d
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering/* Licensed to the Apache Software Foundation (ASF) under one or more
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * contributor license agreements. See the NOTICE file distributed with
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * this work for additional information regarding copyright ownership.
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * The ASF licenses this file to You under the Apache License, Version 2.0
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * (the "License"); you may not use this file except in compliance with
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * the License. You may obtain a copy of the License at
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * http://www.apache.org/licenses/LICENSE-2.0
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * Unless required by applicable law or agreed to in writing, software
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * distributed under the License is distributed on an "AS IS" BASIS,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * See the License for the specific language governing permissions and
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * limitations under the License.
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringmodule AP_MODULE_DECLARE_DATA serf_module;
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringtypedef struct {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringtypedef struct {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringtypedef struct {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* name -> serf_cluster_t* */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringtypedef struct {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringstatic void closed_connection(serf_connection_t *conn,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* justin says that error handling isn't done yet. hah. */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* XXXXXX: review */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ERR, why, ctx->r, "Closed Connection Error");
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ctx->rstatus = HTTP_INTERNAL_SERVER_ERROR;
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringstatic serf_bucket_t* conn_setup(apr_socket_t *sock,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering c = serf_bucket_socket_create(sock, ctx->bkt_alloc);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringstatic int copy_headers_in(void *vbaton, const char *key, const char *value)
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering serf_bucket_t *hdrs_bkt = (serf_bucket_t *)vbaton;
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* XXXXX: List of headers not to copy to serf. serf's serf_bucket_headers_setn,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * doesn't actually overwrite a header if we set it once, so we need to ignore anything
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * we might want to toggle or combine.
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering if (strcasecmp("Accept-Encoding", key) == 0) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering if (strcasecmp("Keep-Alive", key) == 0) {
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt serf_bucket_headers_setn(hdrs_bkt, key, value);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringstatic int copy_headers_out(void *vbaton, const char *key, const char *value)
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* XXXXX: Special Treatment required for MANY other headers. fixme.*/
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering if (strcasecmp("Content-Type", key) == 0) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering else if (strcasecmp("Connection", key) == 0) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering else if (strcasecmp("Content-Encoding", key) == 0) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering else if (strcasecmp("Content-Length", key) == 0) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering if (strcasecmp("Transfer-Encoding", key) == 0) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering apr_table_addn(ctx->r->headers_out, key, value);
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardtstatic serf_bucket_t* accept_response(serf_request_t *request,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* get the per-request bucket allocator */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering bkt_alloc = serf_request_get_alloc(request);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* Create a barrier so the response doesn't eat us! */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering c = serf_bucket_barrier_create(stream, bkt_alloc);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering return serf_bucket_response_create(c, bkt_alloc);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringstatic apr_status_t handle_response(serf_request_t *request,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* XXXXXXX: Create better error message. */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering rv = serf_bucket_response_status(response, &sl);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, ctx->r, "serf_bucket_response_status...");
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ctx->rstatus = HTTP_INTERNAL_SERVER_ERROR;
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * XXXXX: If I understood serf buckets better, it might be possible to not
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * copy all of the data here, and better stream it to the client.
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering rv = serf_bucket_read(response, AP_IOBUFSIZE, &data, &len);
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, ctx->r, "serf_bucket_read(response)");
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering hdrs = serf_bucket_response_get_headers(response);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering serf_bucket_headers_do(hdrs, copy_headers_out, ctx);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* XXXX: write to brigades and stuff. meh */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* XXXX: Should we send a flush now? */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringstatic apr_status_t setup_request(serf_request_t *request,
4f76ef0423a30ee672891056aeb5df2422947e1dThomas Hindoe Paaboel Andersen serf_bucket_t *body_bkt = NULL;
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* XXXXX: handle incoming request bodies */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering *req_bkt = serf_bucket_request_create(ctx->r->method, ctx->r->unparsed_uri, body_bkt,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering hdrs_bkt = serf_bucket_request_get_headers(*req_bkt);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering apr_table_do(copy_headers_in, hdrs_bkt, ctx->r->headers_in, NULL);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering serf_bucket_headers_setn(hdrs_bkt, "Host",
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering apr_table_get(ctx->r->headers_in, "Host"));
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering serf_bucket_headers_setn(hdrs_bkt, "Host", ctx->conf->url.hostname);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip");
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering *req_bkt = serf_bucket_ssl_encrypt_create(*req_bkt, NULL,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ctx->ssl_ctx = serf_bucket_ssl_encrypt_context_get(*req_bkt);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering *req_bkt = serf_bucket_ssl_encrypt_create(*req_bkt, ctx->ssl_ctx,
f6d6bad1461a8f545a80955fadd7ee0c10db15bbLennart Poettering/* TOOD: rewrite drive_serf to make it async */
f6d6bad1461a8f545a80955fadd7ee0c10db15bbLennart Poetteringstatic int drive_serf(request_rec *r, serf_config_t *conf)
f6d6bad1461a8f545a80955fadd7ee0c10db15bbLennart Poettering /* XXXXX: make persistent/per-process or something.*/
f6d6bad1461a8f545a80955fadd7ee0c10db15bbLennart Poettering (serf_server_config_t *)ap_get_module_config(r->server->module_config,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering if (strcmp(conf->url.scheme, "cluster") == 0) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* TODO: could this be optimized in post-config to pre-setup the
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering * pointers to the right cluster inside the conf structure?
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering "SerfCluster: unable to find cluster %s", conf->url.hostname);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering cp = ap_lookup_provider(AP_SERF_CLUSTER_PROVIDER, cluster->provider, "0");
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering "SerfCluster: unable to find provider %s", cluster->provider);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering "SerfCluster: %s is missing list servers provider.", cluster->provider);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering "SerfCluster: %s list servers returned failure", cluster->provider);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering if (servers == NULL || apr_is_empty_array(servers)) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering "SerfCluster: %s failed to provide a list of servers", cluster->provider);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* TOOD: restructure try all servers in the array !! */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering choice = APR_ARRAY_IDX(servers, 0, ap_serf_server_t *);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering rv = apr_sockaddr_info_get(&address, choice->ip,
pool);
return HTTP_INTERNAL_SERVER_ERROR;
baton.r = r;
pool);
&baton);
return HTTP_INTERNAL_SERVER_ERROR;
&serf_module);
return DECLINED;
static int is_true(const char *w)
const char *p = argv[i];
return NULL;
const char *rv;
&serf_module);
return err;
const char *p = argv[i];
if (rv) {
return rv;
return NULL;
return new;
return ctx;
return ctx;
{NULL}
typedef struct hb_table_baton_t {
apr_pool_t *p;
const char *msg;
key);
if (b.msg) {
return b.msg;
return NULL;
typedef struct hb_server_t {
const char *ip;
int busy;
int ready;
int seen;
} hb_server_t;
char *key;
char *value;
char *strtok_state;
while (key) {
if (value) {
if (!path) {
return APR_SUCCESS;
if (rv) {
return rv;
if (rv) {
return rv;
int lineno = 0;
const char *ip;
lineno++;
return APR_SUCCESS;
request_rec *r,
if (rv) {
return HTTP_INTERNAL_SERVER_ERROR;
ap_serf_server_t *x;
return OK;
NULL,
NULL,
NULL,