Project

General

Profile

Feature #2060 ยป mod-connect.patch

jmberg, 2009-09-01 09:46

View differences:

lighttpd-1.4.x/src/Makefile.am 2009-09-01 11:22:58.000000000 +0200
mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_proxy_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_connect.la
mod_connect_la_SOURCES = mod_connect.c
mod_connect_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_connect_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_ssi.la
mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-- lighttpd-1.4.x.orig/src/base.h 2009-09-01 11:22:55.000000000 +0200
++ lighttpd-1.4.x/src/base.h 2009-09-01 11:22:58.000000000 +0200
......
CON_STATE_WRITE,
CON_STATE_RESPONSE_END,
CON_STATE_ERROR,
CON_STATE_CLOSE
CON_STATE_CLOSE,
CON_STATE_READ_CONTINUOUS,
} connection_state_t;
typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
-- lighttpd-1.4.x.orig/src/connections-glue.c 2009-09-01 11:22:55.000000000 +0200
++ lighttpd-1.4.x/src/connections-glue.c 2009-09-01 11:22:58.000000000 +0200
......
case CON_STATE_REQUEST_END: return "req-end";
case CON_STATE_RESPONSE_START: return "resp-start";
case CON_STATE_RESPONSE_END: return "resp-end";
case CON_STATE_READ_CONTINUOUS: return "read-continuous";
default: return "(unknown)";
}
}
......
case CON_STATE_REQUEST_END: return "Q";
case CON_STATE_RESPONSE_START: return "s";
case CON_STATE_RESPONSE_END: return "S";
case CON_STATE_READ_CONTINUOUS: return "F";
default: return "x";
}
}
-- lighttpd-1.4.x.orig/src/connections.c 2009-09-01 11:22:55.000000000 +0200
++ lighttpd-1.4.x/src/connections.c 2009-09-01 11:22:58.000000000 +0200
......
}
break;
case CON_STATE_READ_CONTINUOUS:
break;
default: break;
}
......
}
if (con->state == CON_STATE_READ ||
con->state == CON_STATE_READ_POST) {
con->state == CON_STATE_READ_POST ||
con->state == CON_STATE_READ_CONTINUOUS) {
connection_handle_read_state(srv, con);
}
......
break;
case CON_STATE_READ_POST:
case CON_STATE_READ:
case CON_STATE_READ_CONTINUOUS:
if (srv->srvconf.log_state_handling) {
log_error_write(srv, __FILE__, __LINE__, "sds",
"state for fd", con->fd, connection_get_state(con->state));
}
connection_handle_read_state(srv, con);
if (con->state == CON_STATE_READ_CONTINUOUS) {
plugins_call_read_continuous(srv, con);
}
break;
case CON_STATE_WRITE:
if (srv->srvconf.log_state_handling) {
......
fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
}
break;
case CON_STATE_READ_CONTINUOUS:
/* leave up to plugins */
break;
default:
fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
break;
-- /dev/null 1970-01-01 00:00:00.000000000 +0000
++ lighttpd-1.4.x/src/mod_connect.c 2009-09-01 11:35:04.000000000 +0200
......
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include "buffer.h"
#include "server.h"
#include "keyvalue.h"
#include "log.h"
#include "http_chunk.h"
#include "fdevent.h"
#include "connections.h"
#include "response.h"
#include "joblist.h"
#include "network.h"
#include "plugin.h"
#include "inet_ntop_cache.h"
#include "crc32.h"
#include <fnmatch.h>
#include <stdio.h>
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
#include "sys-socket.h"
#define data_connect data_fastcgi
#define data_connect_init data_fastcgi_init
#define CONNECT_RETRY_TIMEOUT 60
/**
*
* The connect module is based on the proxy module,
* which in turn is based on the fastcgi module.
*/
typedef struct {
array *extensions;
unsigned int debug;
} plugin_config;
typedef struct {
PLUGIN_DATA;
buffer *parse_response;
plugin_config **config_storage;
plugin_config conf;
} plugin_data;
typedef enum {
CONNECT_STATE_INIT,
CONNECT_STATE_CONNECT,
CONNECT_STATE_CONNECTED,
} connect_connection_state_t;
typedef struct {
connect_connection_state_t state;
time_t state_timestamp;
buffer *host;
unsigned short port;
chunkqueue *toclient;
buffer *response;
int fd; /* fd to the connect process */
int fd_server_ndx; /* index into the fd-event buffer */
int client_closed, server_closed;
int noresp;
int path; /* handle as /path based CONNECT */
size_t path_info_offset; /* start of path_info in uri.path */
connection *remote_conn; /* dump pointer */
plugin_data *plugin_data; /* dump pointer */
} handler_ctx;
/* ok, we need a prototype */
static handler_t connect_handle_fdevent(void *s, void *ctx, int revents);
static handler_ctx *handler_ctx_init(void)
{
handler_ctx *hctx = calloc(1, sizeof(*hctx));
hctx->state = CONNECT_STATE_INIT;
hctx->host = buffer_init();
hctx->response = buffer_init();
hctx->toclient = chunkqueue_init();
hctx->fd = -1;
hctx->fd_server_ndx = -1;
hctx->path = 0;
return hctx;
}
static void handler_ctx_free(handler_ctx *hctx)
{
buffer_free(hctx->host);
buffer_free(hctx->response);
chunkqueue_free(hctx->toclient);
free(hctx);
}
INIT_FUNC(mod_connect_init)
{
plugin_data *p;
p = calloc(1, sizeof(*p));
p->parse_response = buffer_init();
return p;
}
FREE_FUNC(mod_connect_free)
{
plugin_data *p = p_d;
UNUSED(srv);
buffer_free(p->parse_response);
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (s) {
array_free(s->extensions);
free(s);
}
}
free(p->config_storage);
}
free(p);
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(mod_connect_set_defaults)
{
plugin_data *p = p_d;
data_unset *du;
size_t i = 0;
config_values_t cv[] = {
{ "connect.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },
{ "connect.debug", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
array *ca;
s = malloc(sizeof(plugin_config));
s->extensions = array_init();
s->debug = 0;
cv[0].destination = s->extensions;
cv[1].destination = &(s->debug);
p->config_storage[i] = s;
ca = ((data_config *)srv->config_context->data[i])->value;
if (config_insert_values_global(srv, ca, cv))
return HANDLER_ERROR;
du = array_get_element(ca, "connect.server");
if (du) {
size_t j;
data_array *da = (data_array *)du;
if (du->type != TYPE_ARRAY) {
log_error_write(srv, __FILE__, __LINE__, "sss",
"unexpected type for key: ", "connect.server", "array of strings");
return HANDLER_ERROR;
}
/*
* connect.server = ( "<regex>" => "<host>", ...)
*/
for (j = 0; j < da->value->used; j++) {
data_array *da_ext = (data_array *)da->value->data[j];
data_array *dca;
data_connect *dc;
if (da_ext->type != TYPE_ARRAY) {
log_error_write(srv, __FILE__, __LINE__, "sssbs",
"unexpected type for key: ", "connect.server",
"[", da->value->data[j]->key, "](string)");
return HANDLER_ERROR;
}
config_values_t pcv[] = {
{ "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "port", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
{ "noresponse", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
dc = data_connect_init();
buffer_copy_string_buffer(dc->key, da_ext->key);
pcv[0].destination = dc->host;
pcv[1].destination = &(dc->port);
pcv[2].destination = &(dc->usage); // hack
if (config_insert_values_internal(srv, da_ext->value, pcv))
return HANDLER_ERROR;
dca = (data_array *)array_get_element(s->extensions, da_ext->key->ptr);
if (!dca) {
dca = data_array_init();
buffer_copy_string_buffer(dca->key, da_ext->key);
array_insert_unique(s->extensions, (data_unset *)dca);
}
if (s->debug)
log_error_write(srv, __FILE__, __LINE__, "ssssd",
da_ext->key->ptr, "=>", dc->host->ptr, ":", dc->port);
array_insert_unique(dca->value, (data_unset *)dc);
}
}
}
return HANDLER_GO_ON;
}
static void connect_connection_close(server *srv, handler_ctx *hctx)
{
plugin_data *p;
connection *con;
if (!hctx)
return;
p = hctx->plugin_data;
con = hctx->remote_conn;
if (hctx->fd != -1) {
fdevent_event_del(srv->ev, &(hctx->fd_server_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
close(hctx->fd);
srv->cur_fds--;
}
handler_ctx_free(hctx);
con->plugin_ctx[p->id] = NULL;
}
static int connect_establish_connection(server *srv, handler_ctx *hctx)
{
struct sockaddr *connect_addr;
struct sockaddr_in connect_addr_in;
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
struct sockaddr_in6 connect_addr_in6;
#endif
socklen_t servlen;
plugin_data *p = hctx->plugin_data;
int connect_fd = hctx->fd;
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
if (strstr(hctx->host->ptr, ":")) {
memset(&connect_addr_in6, 0, sizeof(connect_addr_in6));
connect_addr_in6.sin6_family = AF_INET6;
inet_pton(AF_INET6, hctx->host->ptr, (char *) &connect_addr_in6.sin6_addr);
connect_addr_in6.sin6_port = htons(hctx->port);
servlen = sizeof(connect_addr_in6);
connect_addr = (struct sockaddr *) &connect_addr_in6;
} else
#endif
{
memset(&connect_addr_in, 0, sizeof(connect_addr_in));
connect_addr_in.sin_family = AF_INET;
connect_addr_in.sin_addr.s_addr = inet_addr(hctx->host->ptr);
connect_addr_in.sin_port = htons(hctx->port);
servlen = sizeof(connect_addr_in);
connect_addr = (struct sockaddr *) &connect_addr_in;
}
if (-1 == connect(connect_fd, connect_addr, servlen)) {
if (errno == EINPROGRESS || errno == EALREADY) {
if (p->conf.debug)
log_error_write(srv, __FILE__, __LINE__, "sd",
"connect delayed:", connect_fd);
return 1;
} else {
log_error_write(srv, __FILE__, __LINE__, "sdsd",
"connect failed:", connect_fd, strerror(errno), errno);
return -1;
}
}
if (p->conf.debug)
log_error_write(srv, __FILE__, __LINE__, "sd",
"connect succeeded: ", connect_fd);
return 0;
}
static int connect_set_state(server *srv, handler_ctx *hctx, connect_connection_state_t state)
{
hctx->state = state;
hctx->state_timestamp = srv->cur_ts;
return 0;
}
static handler_t connect_write_request(server *srv, handler_ctx *hctx)
{
plugin_data *p = hctx->plugin_data;
connection *con = hctx->remote_conn;
int ret;
switch(hctx->state) {
case CONNECT_STATE_INIT:
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
if (strstr(hctx->host->ptr,":")) {
if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
return HANDLER_ERROR;
}
} else
#endif
{
if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
return HANDLER_ERROR;
}
}
hctx->fd_server_ndx = -1;
srv->cur_fds++;
fdevent_register(srv->ev, hctx->fd, connect_handle_fdevent, hctx);
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
return HANDLER_ERROR;
}
/* fall through */
case CONNECT_STATE_CONNECT:
/* try to finish the connect() */
if (hctx->state == CONNECT_STATE_INIT) {
/* first round */
switch (connect_establish_connection(srv, hctx)) {
case 1:
connect_set_state(srv, hctx, CONNECT_STATE_CONNECT);
/* connection is in progress, wait for an event and call getsockopt() below */
fdevent_event_add(srv->ev, &(hctx->fd_server_ndx), hctx->fd, FDEVENT_OUT);
return HANDLER_WAIT_FOR_EVENT;
case -1:
hctx->fd_server_ndx = -1;
return HANDLER_ERROR;
default:
/* everything is ok, go on */
break;
}
} else {
int socket_error;
socklen_t socket_error_len = sizeof(socket_error);
/* we don't need it anymore */
fdevent_event_del(srv->ev, &(hctx->fd_server_ndx), hctx->fd);
/* try to finish the connect() */
if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"getsockopt failed:", strerror(errno));
return HANDLER_ERROR;
}
if (socket_error != 0) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"establishing connection failed:", strerror(socket_error),
"port:", hctx->port);
con->http_status = 503;
con->mode = DIRECT;
return HANDLER_FINISHED;
}
if (p->conf.debug)
log_error_write(srv, __FILE__, __LINE__, "s", "connect - connect - delayed success");
}
connect_set_state(srv, hctx, CONNECT_STATE_CONNECTED);
if (!hctx->noresp) {
struct {
const char *b; size_t l;
} strs[] = {
{ CONST_STR_LEN("HTTP/1.0 200 Connection established\r\n") },
{ CONST_STR_LEN("\r\n") },
};
int i;
buffer *b = chunkqueue_get_append_buffer(hctx->toclient);
for (i = 0; i < (int)(sizeof(strs)/sizeof(strs[0])); i++)
buffer_append_string_len(b, strs[i].b, strs[i].l);
}
connection_set_state(srv, con, CON_STATE_READ_CONTINUOUS);
/* fall through */
case CONNECT_STATE_CONNECTED:
if (!hctx->server_closed) {
ret = srv->network_backend_write(srv, con, hctx->fd, con->read_queue);
chunkqueue_remove_finished_chunks(con->read_queue);
if (-1 == ret) { /* error on our side */
log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
} else if (-2 == ret) { /* remote close */
log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed, remote connection close:", strerror(errno), errno);
hctx->server_closed = 1;
}
}
if (!hctx->client_closed) {
con->keep_alive = 1;
ret = network_write_chunkqueue(srv, con, hctx->toclient);
con->keep_alive = 0;
chunkqueue_remove_finished_chunks(hctx->toclient);
if (-1 == ret) { /* error on our side */
log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
} else if (-2 == ret) { /* remote close */
log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed, remote connection close:", strerror(errno), errno);
hctx->client_closed = 1;
}
}
if (!chunkqueue_is_empty(con->read_queue)) {
fdevent_event_del(srv->ev, &(hctx->fd_server_ndx), hctx->fd);
fdevent_event_add(srv->ev, &(hctx->fd_server_ndx), hctx->fd, FDEVENT_OUT);
} else {
fdevent_event_del(srv->ev, &(hctx->fd_server_ndx), hctx->fd);
if (hctx->client_closed)
connect_connection_close(srv, hctx);
else if (chunkqueue_is_empty(hctx->toclient))
fdevent_event_add(srv->ev, &(hctx->fd_server_ndx), hctx->fd, FDEVENT_IN);
}
if (!chunkqueue_is_empty(hctx->toclient)) {
fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
} else {
fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
if (hctx->server_closed) {
if (!hctx->client_closed) {
connection_set_state(srv, con, CON_STATE_RESPONSE_END);
hctx->client_closed = 1;
}
} else if (chunkqueue_is_empty(con->read_queue))
fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
}
return HANDLER_WAIT_FOR_EVENT;
default:
log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
return HANDLER_ERROR;
}
}
static int mod_connect_patch_connection(server *srv, connection *con, plugin_data *p)
{
size_t i, j;
plugin_config *s = p->config_storage[0];
#define PATCH(x) do { p->conf.x = s->x; } while (0)
PATCH(extensions);
PATCH(debug);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
/* condition didn't match */
if (!config_check_cond(srv, con, dc))
continue;
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
if (buffer_is_equal_string(du->key, CONST_STR_LEN("connect.server")))
PATCH(extensions);
else if (buffer_is_equal_string(du->key, CONST_STR_LEN("connect.debug")))
PATCH(debug);
}
}
#undef PATCH
return 0;
}
SUBREQUEST_FUNC(mod_connect_handle_subrequest)
{
plugin_data *p = p_d;
handler_ctx *hctx = con->plugin_ctx[p->id];
handler_t h;
if (!hctx)
return HANDLER_GO_ON;
mod_connect_patch_connection(srv, con, p);
/* not my job */
if (con->mode != p->id)
return HANDLER_GO_ON;
/* ok, create the request */
h = connect_write_request(srv, hctx);
switch (h) {
case HANDLER_ERROR:
log_error_write(srv, __FILE__, __LINE__, "sbdd", "connect-server disabled:",
hctx->host, hctx->port, hctx->fd);
connect_connection_close(srv, hctx);
/* reset the enviroment and restart the sub-request */
buffer_reset(con->physical.path);
con->mode = DIRECT;
joblist_append(srv, con);
return HANDLER_ERROR;
default:
return h;
}
}
static handler_t connect_handle_fdevent(void *s, void *ctx, int revents)
{
server *srv = (server *)s;
handler_ctx *hctx = ctx;
connection *con = hctx->remote_conn;
plugin_data *p = hctx->plugin_data;
int b;
ssize_t r;
buffer *buf;
int fd = hctx->fd;
char readbuf[4096];
if ((revents & FDEVENT_IN) &&
hctx->state == CONNECT_STATE_CONNECTED &&
chunkqueue_is_empty(hctx->toclient)) {
/* check how much we have to read */
if (ioctl(fd, FIONREAD, &b)) {
log_error_write(srv, __FILE__, __LINE__, "sd",
"ioctl failed: ", fd);
goto disconnect;
}
if (!b || b > (int)sizeof(readbuf))
b = sizeof(readbuf);
errno = 0;
r = read(fd, readbuf, b);
if (r > 0) {
buf = chunkqueue_get_append_buffer(hctx->toclient);
buffer_append_memory(buf, readbuf, r + 1); // XX ???
} else if (errno != EAGAIN)
goto disconnect;
}
if (revents & FDEVENT_OUT) {
if (p->conf.debug)
log_error_write(srv, __FILE__, __LINE__, "sd",
"connect: fdevent-out", hctx->state);
if (hctx->state == CONNECT_STATE_CONNECT ||
hctx->state == CONNECT_STATE_CONNECTED) {
/* unfinished connect call or data to send */
return mod_connect_handle_subrequest(srv, con, p);
} else {
log_error_write(srv, __FILE__, __LINE__, "sd",
"connect: out", hctx->state);
}
}
/* perhaps this issue is already handled */
if (revents & FDEVENT_HUP) {
if (p->conf.debug)
log_error_write(srv, __FILE__, __LINE__, "sd",
"connect: fdevent-hup", hctx->state);
if (hctx->state == CONNECT_STATE_CONNECT) {
/* connect() -> EINPROGRESS -> HUP */
goto disconnect;
}
con->file_finished = 1;
goto disconnect;
} else if (revents & FDEVENT_ERR) {
/* kill all connections to the connect process */
log_error_write(srv, __FILE__, __LINE__, "sd", "connect-FDEVENT_ERR, but no HUP", revents);
goto disconnect;
}
joblist_append(srv, con);
return HANDLER_FINISHED;
disconnect:
hctx->server_closed = 1;
joblist_append(srv, con);
connect_write_request(srv, hctx);
return HANDLER_FINISHED;
}
static handler_t mod_connect_check(server *srv, connection *con, void *p_d)
{
plugin_data *p = p_d;
size_t s_len;
size_t k;
buffer *fn;
data_array *extension = NULL;
size_t path_info_offset;
data_connect *host;
handler_ctx *hctx;
char *colon;
int path = 0;
if (con->request.http_method != HTTP_METHOD_CONNECT)
return HANDLER_GO_ON;
if (con->mode != DIRECT)
return HANDLER_GO_ON;
/* Have we processed this request already? */
if (con->file_started == 1)
return HANDLER_GO_ON;
mod_connect_patch_connection(srv, con, p);
fn = con->uri.path;
if (fn->used == 0)
return HANDLER_ERROR;
s_len = fn->used - 1;
path_info_offset = 0;
if (p->conf.debug)
log_error_write(srv, __FILE__, __LINE__, "s", "connect - start");
/* check if prefix or host matches */
for (k = 0; k < p->conf.extensions->used; k++) {
data_array *ext = NULL;
size_t ct_len;
ext = (data_array *)p->conf.extensions->data[k];
if (ext->key->used == 0)
continue;
ct_len = ext->key->used - 1;
if (s_len < ct_len)
continue;
/* check host/prefix in the form "/path" */
if (*(ext->key->ptr) == '/') {
if (strncmp(fn->ptr, ext->key->ptr, ct_len) == 0) {
if (s_len > ct_len + 1) {
char *pi_offset;
pi_offset = strchr(fn->ptr + ct_len + 1, '/');
if (pi_offset)
path_info_offset = pi_offset - fn->ptr;
}
extension = ext;
path = 1;
break;
}
} else if (fnmatch(ext->key->ptr, fn->ptr + 1, FNM_NOESCAPE|FNM_CASEFOLD) == 0) {
/* check extension in the form ".fcg" */
extension = ext;
break;
}
}
if (!extension)
return HANDLER_GO_ON;
if (p->conf.debug)
log_error_write(srv, __FILE__, __LINE__, "s", "connect - ext found");
host = (data_connect *)extension->value->data[0];
/*
* if check-local is disabled, use the uri.path handler
*
*/
/* init handler-context */
hctx = handler_ctx_init();
hctx->path_info_offset = path_info_offset;
hctx->remote_conn = con;
hctx->plugin_data = p;
if (!host->host) {
colon = strrchr(fn->ptr + 1, ':');
if (!colon) {
buffer_append_string(hctx->host, fn->ptr + 1);
hctx->port = host->port ? host->port : 443;
} else {
hctx->port = atoi(colon + 1);
buffer_append_string_len(hctx->host, fn->ptr + 1, colon - fn->ptr - 1);
}
} else {
buffer_append_string(hctx->host, host->host->ptr);
hctx->port = host->port;
}
hctx->noresp = host->usage; // XXX
hctx->path = path;
con->plugin_ctx[p->id] = hctx;
con->mode = p->id;
if (p->conf.debug)
log_error_write(srv, __FILE__, __LINE__, "sbd",
"connect - found a host",
hctx->host, hctx->port);
return HANDLER_GO_ON;
}
static handler_t mod_connect_connection_close(server *srv, connection *con, void *p_d)
{
plugin_data *p = p_d;
connect_connection_close(srv, con->plugin_ctx[p->id]);
return HANDLER_GO_ON;
}
/**
*
* the trigger re-enables the disabled connections after the timeout is over
*
*/
TRIGGER_FUNC(mod_connect_trigger)
{
plugin_data *p = p_d;
if (p->config_storage) {
size_t i, n, k;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (!s)
continue;
/* get the extensions for all configs */
for (k = 0; k < s->extensions->used; k++) {
data_array *extension = (data_array *)s->extensions->data[k];
/* get all hosts */
for (n = 0; n < extension->value->used; n++) {
data_connect *host = (data_connect *)extension->value->data[n];
if (!host->is_disabled ||
srv->cur_ts - host->disable_ts < 5)
continue;
log_error_write(srv, __FILE__, __LINE__, "sbd",
"connect - re-enabled:",
host->host, host->port);
host->is_disabled = 0;
}
}
}
}
return HANDLER_GO_ON;
}
int mod_connect_plugin_init(plugin *p)
{
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("connect");
p->init = mod_connect_init;
p->cleanup = mod_connect_free;
p->set_defaults = mod_connect_set_defaults;
p->connection_reset = mod_connect_connection_close;
p->handle_connection_close = mod_connect_connection_close;
p->handle_uri_clean = mod_connect_check;
p->handle_subrequest = mod_connect_handle_subrequest;
p->handle_trigger = mod_connect_trigger;
p->read_continuous = mod_connect_handle_subrequest;
p->data = NULL;
return 0;
}
......
-- lighttpd-1.4.x.orig/src/plugin.c 2009-09-01 11:22:55.000000000 +0200
++ lighttpd-1.4.x/src/plugin.c 2009-09-01 11:22:58.000000000 +0200
......
PLUGIN_FUNC_INIT,
PLUGIN_FUNC_CLEANUP,
PLUGIN_FUNC_SET_DEFAULTS,
PLUGIN_FUNC_READ_CONTINUOUS,
PLUGIN_FUNC_SIZEOF
} plugin_t;
......
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
PLUGIN_TO_SLOT(PLUGIN_FUNC_READ_CONTINUOUS, read_continuous)
#undef PLUGIN_TO_SLOT
......
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
PLUGIN_TO_SLOT(PLUGIN_FUNC_READ_CONTINUOUS, read_continuous)
PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
#undef PLUGIN_TO_SLOT
-- lighttpd-1.4.x.orig/src/plugin.h 2009-09-01 11:22:55.000000000 +0200
++ lighttpd-1.4.x/src/plugin.h 2009-09-01 11:22:58.000000000 +0200
......
#define PHYSICALPATH_FUNC CONNECTION_FUNC
#define REQUESTDONE_FUNC CONNECTION_FUNC
#define URIHANDLER_FUNC CONNECTION_FUNC
#define READ_CONT_FUNC CONNECTION_FUNC
#define PLUGIN_DATA size_t id
......
*/
handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */
handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */
handler_t (* read_continuous) (server *srv, connection *con, void *p_d); /* */
void *data;
/* dlopen handle */
......
handler_t plugins_call_handle_connection_close(server *srv, connection *con);
handler_t plugins_call_handle_joblist(server *srv, connection *con);
handler_t plugins_call_connection_reset(server *srv, connection *con);
handler_t plugins_call_read_continuous(server *srv, connection *con);
handler_t plugins_call_handle_trigger(server *srv);
handler_t plugins_call_handle_sighup(server *srv);
    (1-1/1)