summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjakabosky <jakabosky@152afb58-edef-0310-8abb-c4023f1b3aa9>2007-01-12 06:21:05 +0000
committerjakabosky <jakabosky@152afb58-edef-0310-8abb-c4023f1b3aa9>2007-01-12 06:21:05 +0000
commitf4420102cb00522201cc41999a226c76863e82e2 (patch)
tree1a24281bdf13e6acd5aabf805b9a3b4e54ca9d02
parent4cd4fd4ad5c9578428d4ef148b73226bbc8cda7e (diff)
downloadlighttpd-f4420102cb00522201cc41999a226c76863e82e2.tar.gz
Added support for X-Rewrite-Backend to support creation of proxy-core backends dynamicly.
git-svn-id: svn://svn.lighttpd.net/lighttpd/trunk@1512 152afb58-edef-0310-8abb-c4023f1b3aa9
-rw-r--r--src/mod_proxy_core.c152
-rw-r--r--src/mod_proxy_core.h7
-rw-r--r--src/mod_proxy_core_address.c2
-rw-r--r--src/mod_proxy_core_backend.c2
4 files changed, 120 insertions, 43 deletions
diff --git a/src/mod_proxy_core.c b/src/mod_proxy_core.c
index ad103dd4..aeaa8350 100644
--- a/src/mod_proxy_core.c
+++ b/src/mod_proxy_core.c
@@ -347,7 +347,9 @@ proxy_session *proxy_session_init(void) {
sess->is_chunked = 0;
sess->send_response_content = 1;
- sess->do_session_clear = 0;
+ sess->do_new_session = 0;
+ sess->do_x_rewrite_backend = 0;
+ sess->x_rewrite_backend = NULL;
return sess;
}
@@ -378,7 +380,11 @@ void proxy_session_reset(proxy_session *sess) {
sess->internal_redirect_count = 0;
sess->do_internal_redirect = 0;
sess->is_closing = 0;
- sess->send_response_content = 0;
+
+ sess->do_new_session = 0;
+ sess->do_x_rewrite_backend = 0;
+ buffer_free(sess->x_rewrite_backend);
+ sess->x_rewrite_backend = NULL;
sess->remote_con = NULL;
sess->proxy_con = NULL;
@@ -400,6 +406,7 @@ void proxy_session_free(proxy_session *sess) {
chunkqueue_free(sess->recv_raw);
chunkqueue_free(sess->send_raw);
+ buffer_free(sess->x_rewrite_backend);
free(sess);
}
@@ -538,6 +545,7 @@ parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_
proxy_session *sess, chunkqueue *in, chunkqueue *out) {
proxy_protocol *protocol = (sess->proxy_backend) ? sess->proxy_backend->protocol : NULL;
int have_content_length = 0;
+ int do_x_rewrite = 0;
size_t i;
if(!protocol || !(protocol->proxy_parse_response_header)) {
@@ -642,27 +650,24 @@ parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_
continue;
} else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Rewrite-URI"))) {
if (p->conf.allow_x_rewrite) {
- sess->send_response_content = 0;
- sess->do_internal_redirect = 1;
- sess->do_session_clear = 1;
-
+ do_x_rewrite = 1;
buffer_copy_string_buffer(con->request.uri, header->value);
- buffer_reset(con->physical.path);
-
- config_cond_cache_reset(srv, con);
}
continue;
} else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Rewrite-Host"))) {
if (p->conf.allow_x_rewrite) {
- sess->send_response_content = 0;
- sess->do_internal_redirect = 1;
- sess->do_session_clear = 1;
-
+ do_x_rewrite = 1;
buffer_copy_string_buffer(con->request.http_host, header->value);
- buffer_reset(con->physical.path);
+ }
- config_cond_cache_reset(srv, con);
+ continue;
+ } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Rewrite-Backend"))) {
+ if (p->conf.allow_x_rewrite) {
+ do_x_rewrite = 1;
+ if (!sess->x_rewrite_backend) sess->x_rewrite_backend = buffer_init();
+ buffer_copy_string_buffer(sess->x_rewrite_backend, header->value);
+ sess->do_x_rewrite_backend = 1;
}
continue;
@@ -723,6 +728,16 @@ parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_
array_insert_unique(con->response.headers, (data_unset *)ds);
}
+ if (do_x_rewrite) {
+ sess->send_response_content = 0;
+ sess->do_internal_redirect = 1;
+ sess->do_new_session = 1;
+
+ buffer_reset(con->physical.path);
+
+ config_cond_cache_reset(srv, con);
+ }
+
/* we are finished decoding the response headers. */
if(!out->is_closed) {
/* We don't have all the response content try to enable chunked encoding. */
@@ -1059,6 +1074,9 @@ int proxy_get_request_header(server *srv, connection *con, plugin_data *p, proxy
handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
/* do we have a connection ? */
+ if (p->conf.debug > 0)
+ TRACE("proxy_state_engine: state=%d", sess->state);
+
switch (sess->state) {
case PROXY_STATE_UNSET:
/* we are not started yet */
@@ -1218,6 +1236,7 @@ handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy
if (sess->do_internal_redirect) {
/* no more response data to process. do redirect now. */
if (sess->recv->is_closed) {
+ sess->state = PROXY_STATE_FINISHED;
/* now it becomes tricky
*
* mod_staticfile should handle this file for us
@@ -1339,6 +1358,8 @@ handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy
/* recycle proxy connection. */
proxy_recycle_backend_connection(srv, p, sess);
+ sess->state = PROXY_STATE_FINISHED;
+
if (sess->do_internal_redirect) {
/* now it becomes tricky
*
@@ -1378,13 +1399,31 @@ proxy_backend *proxy_get_backend(server *srv, connection *con, plugin_data *p) {
return NULL;
}
+proxy_backend *proxy_find_backend(server *srv, connection *con, plugin_data *p, buffer *url) {
+ size_t i;
+
+ UNUSED(srv);
+ UNUSED(con);
+
+ for (i = 0; i < p->conf.backends->used; i++) {
+ proxy_backend *backend = p->conf.backends->ptr[i];
+
+ if (buffer_is_equal(backend->url, url)) {
+ return backend;
+ }
+ }
+
+ return NULL;
+}
+
/**
* choose a available address from the address-pool
*
* the backend has different balancers
*/
-proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_backend *backend) {
+proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_session *sess) {
size_t i;
+ proxy_backend *backend = sess->proxy_backend;
proxy_address_pool *address_pool = backend->address_pool;
unsigned long last_max; /* for the HASH balancer */
proxy_address *address = NULL, *cur_address = NULL;
@@ -1492,6 +1531,7 @@ static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_
PATCH_OPTION(response_rewrites);
PATCH_OPTION(allow_x_sendfile);
PATCH_OPTION(allow_x_rewrite);
+ PATCH_OPTION(max_pool_size);
PATCH_OPTION(check_local);
/* skip the first, the global context */
@@ -1523,6 +1563,8 @@ static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_
PATCH_OPTION(allow_x_sendfile);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_ALLOW_X_REWRITE))) {
PATCH_OPTION(allow_x_rewrite);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_MAX_POOL_SIZE))) {
+ PATCH_OPTION(max_pool_size);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_CHECK_LOCAL))) {
PATCH_OPTION(check_local);
}
@@ -1536,8 +1578,10 @@ static int mod_proxy_core_check_match(server *srv, connection *con, plugin_data
proxy_session *sess = con->plugin_ctx[p->id];
buffer *path;
- /* if this is the second round, sess is already prepared */
- if (sess) return HANDLER_GO_ON;
+ if (sess && !sess->do_new_session) {
+ /* if this is the second round, sess is already prepared */
+ return HANDLER_GO_ON;
+ }
path = file_match ? con->physical.path : con->uri.path;
if (buffer_is_empty(path)) return HANDLER_GO_ON;
@@ -1545,26 +1589,55 @@ static int mod_proxy_core_check_match(server *srv, connection *con, plugin_data
/* check if we have a matching conditional for this request */
mod_proxy_core_patch_connection(srv, con, p);
- /* no proxy backends to handle this request. */
- if (p->conf.backends->used == 0) return HANDLER_GO_ON;
+ /* make sure we have a protocol. */
+ if (NULL == p->conf.protocol) return HANDLER_GO_ON;
/* if check_local is enabled, then wait for file match. */
if (file_match != p->conf.check_local) return HANDLER_GO_ON;
+ if (sess && sess->do_x_rewrite_backend) {
+ proxy_backend *backend;
+
+ backend = proxy_find_backend(srv, con, p, sess->x_rewrite_backend);
+ if (backend == NULL) {
+ backend = proxy_backend_init();
+
+ buffer_copy_string_buffer(backend->url, sess->x_rewrite_backend);
+ /* check if the new backend has a valid backend-address */
+ if (0 == proxy_address_pool_add_string(backend->address_pool, backend->url)) {
+ if (p->conf.max_pool_size) {
+ backend->pool->max_size = p->conf.max_pool_size;
+ }
+
+ proxy_backends_add(p->conf.backends, backend);
+ } else {
+ proxy_backend_free(backend);
+ backend = NULL;
+ }
+ }
+ /* clear old session */
+ proxy_session_reset(sess);
+ if (NULL == backend) return HANDLER_GO_ON;
+ sess->proxy_backend = backend;
+ }
+
+ /* no proxy backends to handle this request. */
+ if (p->conf.backends->used == 0) return HANDLER_GO_ON;
+
if (!sess) {
/* a session lives for a single request */
sess = proxy_session_init();
- sess->p = p;
+ }
- con->plugin_ctx[p->id] = sess;
- con->mode = p->id;
+ con->plugin_ctx[p->id] = sess;
+ con->mode = p->id;
- if (con->conf.log_request_handling) {
- TRACE("handling it in mod_proxy_core: %s.path=%s",
- file_match ? "physical" : "uri", BUF_STR(path));
- }
- sess->remote_con = con;
+ if (con->conf.log_request_handling) {
+ TRACE("handling it in mod_proxy_core: %s.path=%s",
+ file_match ? "physical" : "uri", BUF_STR(path));
}
+ sess->p = p;
+ sess->remote_con = con;
return HANDLER_GO_ON;
}
@@ -1631,6 +1704,8 @@ CONNECTION_FUNC(mod_proxy_core_start_backend) {
}
switch (sess->state) {
+ case PROXY_STATE_FINISHED:
+ return HANDLER_GO_ON;
case PROXY_STATE_CONNECTING:
/* this connections is waited 10 seconds to connect to the backend
* and didn't got a successful connection yet, sending timeout */
@@ -1664,10 +1739,12 @@ CONNECTION_FUNC(mod_proxy_core_start_backend) {
proxy_address *address = NULL;
int woken_up;
- if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p))) {
- /* no connection pool for this location */
- ERROR("%s", "Couldn't find a backend for this location.");
- return HANDLER_ERROR;
+ if (NULL == sess->proxy_backend) {
+ if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p))) {
+ /* no connection pool for this location */
+ ERROR("%s", "Couldn't find a backend for this location.");
+ return HANDLER_ERROR;
+ }
}
sess->proxy_backend->balancer = p->conf.balancer;
@@ -1678,7 +1755,7 @@ CONNECTION_FUNC(mod_proxy_core_start_backend) {
* check the connection pool if we have a connection open
* for that address
*/
- if (NULL == (address = proxy_backend_balance(srv, con, sess->proxy_backend))) {
+ if (NULL == (address = proxy_backend_balance(srv, con, sess))) {
/* we don't have any backends to connect to */
proxy_request *req;
@@ -1756,13 +1833,8 @@ CONNECTION_FUNC(mod_proxy_core_start_backend) {
case HANDLER_COMEBACK:
/* request finished do redirect. */
if (sess->do_internal_redirect) {
- if (sess->do_session_clear) {
- /* clear proxy session. */
- mod_proxy_connection_reset(srv, con, p);
- } else {
- /* recycle proxy connection. */
- proxy_recycle_backend_connection(srv, p, sess);
- }
+ /* recycle proxy connection. */
+ proxy_recycle_backend_connection(srv, p, sess);
return HANDLER_COMEBACK;
}
/* restart the connection to the backend */
diff --git a/src/mod_proxy_core.h b/src/mod_proxy_core.h
index 31399f10..c24ea588 100644
--- a/src/mod_proxy_core.h
+++ b/src/mod_proxy_core.h
@@ -63,7 +63,8 @@ typedef enum {
PROXY_STATE_WRITE_REQUEST_HEADER,
PROXY_STATE_WRITE_REQUEST_BODY,
PROXY_STATE_READ_RESPONSE_HEADER,
- PROXY_STATE_READ_RESPONSE_BODY
+ PROXY_STATE_READ_RESPONSE_BODY,
+ PROXY_STATE_FINISHED
} proxy_state_t;
typedef struct proxy_session {
@@ -86,8 +87,10 @@ typedef struct proxy_session {
int is_closing; /** our connection will close when we are done */
int send_response_content; /** 0 if we have to ignore the content-body */
int do_internal_redirect; /** 1 if we do a internal redirect to the ->mode = DIRECT */
- int do_session_clear; /** clear out this proxy session, so a new session can be created. */
int internal_redirect_count; /** protection against infinite loops */
+ int do_new_session; /** 1 if we want a new proxy session can be created. */
+ int do_x_rewrite_backend; /** 1 if we want to do custom backend balancing */
+ buffer *x_rewrite_backend; /** holds name of new backend for custom balancing */
/**
* chunkqueues
diff --git a/src/mod_proxy_core_address.c b/src/mod_proxy_core_address.c
index a6af73da..23b7e877 100644
--- a/src/mod_proxy_core_address.c
+++ b/src/mod_proxy_core_address.c
@@ -52,7 +52,7 @@ void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *add
proxy_address *pool_address = address_pool->ptr[i];
if (buffer_is_equal(address->name, pool_address->name)) {
- TRACE("%s is already in the address-pool", BUF_STR(address->name));
+ /* TRACE("%s is already in the address-pool", BUF_STR(address->name)); */
proxy_address_free(address);
diff --git a/src/mod_proxy_core_backend.c b/src/mod_proxy_core_backend.c
index 753c95a7..7d2999fa 100644
--- a/src/mod_proxy_core_backend.c
+++ b/src/mod_proxy_core_backend.c
@@ -11,6 +11,7 @@ proxy_backend *proxy_backend_init(void) {
backend->pool = proxy_connection_pool_init();
backend->address_pool = proxy_address_pool_init();
backend->balancer = PROXY_BALANCE_RR;
+ backend->url = buffer_init();
return backend;
}
@@ -20,6 +21,7 @@ void proxy_backend_free(proxy_backend *backend) {
proxy_connection_pool_free(backend->pool);
proxy_address_pool_free(backend->address_pool);
+ buffer_free(backend->url);
free(backend);
}