| 1 | /* |
|---|
| 2 | * Author: Kirill S. Vlasov (kirakuna@yahoo.com) |
|---|
| 3 | * Date: 7 May 2008 |
|---|
| 4 | */ |
|---|
| 5 | |
|---|
| 6 | #include <ctype.h> |
|---|
| 7 | #include <stdlib.h> |
|---|
| 8 | #include <string.h> |
|---|
| 9 | |
|---|
| 10 | #include "base.h" |
|---|
| 11 | #include "log.h" |
|---|
| 12 | #include "buffer.h" |
|---|
| 13 | |
|---|
| 14 | #include "plugin.h" |
|---|
| 15 | |
|---|
| 16 | #ifdef HAVE_CONFIG_H |
|---|
| 17 | #include "config.h" |
|---|
| 18 | #endif |
|---|
| 19 | |
|---|
| 20 | typedef struct { |
|---|
| 21 | buffer *prefix; // one symbol prefix for fcgi |
|---|
| 22 | buffer *keyword; |
|---|
| 23 | int count; // must be power of two |
|---|
| 24 | } plugin_config; |
|---|
| 25 | |
|---|
| 26 | typedef struct { |
|---|
| 27 | size_t foo; |
|---|
| 28 | } handler_ctx; |
|---|
| 29 | |
|---|
| 30 | typedef struct { |
|---|
| 31 | PLUGIN_DATA; |
|---|
| 32 | buffer *match_buf; |
|---|
| 33 | plugin_config **config_storage; |
|---|
| 34 | plugin_config conf; |
|---|
| 35 | } plugin_data; |
|---|
| 36 | |
|---|
| 37 | static handler_ctx * handler_ctx_init() { |
|---|
| 38 | handler_ctx * hctx; |
|---|
| 39 | hctx = calloc(1, sizeof(*hctx)); |
|---|
| 40 | return hctx; |
|---|
| 41 | } |
|---|
| 42 | |
|---|
| 43 | static void handler_ctx_free(handler_ctx *hctx) { |
|---|
| 44 | free(hctx); |
|---|
| 45 | } |
|---|
| 46 | |
|---|
| 47 | INIT_FUNC(mod_cookie_balancer_init) { |
|---|
| 48 | plugin_data *p; |
|---|
| 49 | |
|---|
| 50 | p = calloc(1, sizeof(*p)); |
|---|
| 51 | |
|---|
| 52 | p->match_buf = buffer_init(); |
|---|
| 53 | |
|---|
| 54 | return p; |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | FREE_FUNC(mod_cookie_balancer_free) { |
|---|
| 58 | plugin_data *p = p_d; |
|---|
| 59 | |
|---|
| 60 | UNUSED(srv); |
|---|
| 61 | |
|---|
| 62 | if (!p) return HANDLER_GO_ON; |
|---|
| 63 | |
|---|
| 64 | buffer_free(p->match_buf); |
|---|
| 65 | if (p->config_storage) { |
|---|
| 66 | size_t i; |
|---|
| 67 | for (i = 0; i < srv->config_context->used; i++) { |
|---|
| 68 | plugin_config *s = p->config_storage[i]; |
|---|
| 69 | free(s); |
|---|
| 70 | } |
|---|
| 71 | free(p->config_storage); |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | free(p); |
|---|
| 75 | |
|---|
| 76 | return HANDLER_GO_ON; |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | SETDEFAULTS_FUNC(mod_cookie_balancer_set_defaults) { |
|---|
| 81 | plugin_data *p = p_d; |
|---|
| 82 | size_t i = 0; |
|---|
| 83 | |
|---|
| 84 | config_values_t cv[] = { |
|---|
| 85 | { "cb.count",NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, |
|---|
| 86 | { "cb.prefix",NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, |
|---|
| 87 | { "cb.keyword",NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, |
|---|
| 88 | { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } |
|---|
| 89 | }; |
|---|
| 90 | |
|---|
| 91 | if (!p) return HANDLER_ERROR; |
|---|
| 92 | |
|---|
| 93 | p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); |
|---|
| 94 | |
|---|
| 95 | for (i = 0; i < srv->config_context->used; i++) { |
|---|
| 96 | plugin_config *s; |
|---|
| 97 | |
|---|
| 98 | s = calloc(1, sizeof(plugin_config)); |
|---|
| 99 | s->prefix = buffer_init(); |
|---|
| 100 | s->keyword = buffer_init(); |
|---|
| 101 | s->count = 0; |
|---|
| 102 | |
|---|
| 103 | cv[0].destination = &(s->count); |
|---|
| 104 | cv[1].destination = s->prefix; |
|---|
| 105 | cv[2].destination = s->keyword; |
|---|
| 106 | |
|---|
| 107 | p->config_storage[i] = s; |
|---|
| 108 | |
|---|
| 109 | if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { |
|---|
| 110 | return HANDLER_ERROR; |
|---|
| 111 | } |
|---|
| 112 | } |
|---|
| 113 | return HANDLER_GO_ON; |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | #define PATCH(x) \ |
|---|
| 117 | p->conf.x = s->x; |
|---|
| 118 | static int mod_cookie_balancer_patch_connection(server *srv, connection *con, plugin_data *p) { |
|---|
| 119 | size_t i, j; |
|---|
| 120 | plugin_config *s = p->config_storage[0]; |
|---|
| 121 | |
|---|
| 122 | PATCH(count); |
|---|
| 123 | PATCH(prefix); |
|---|
| 124 | |
|---|
| 125 | |
|---|
| 126 | /* skip the first, the global context */ |
|---|
| 127 | for (i = 0; i < srv->config_context->used; i++) { |
|---|
| 128 | data_config *dc = (data_config *)srv->config_context->data[i]; |
|---|
| 129 | s = p->config_storage[i]; |
|---|
| 130 | |
|---|
| 131 | for (j = 0; j < dc->value->used; j++) { |
|---|
| 132 | data_unset *du = dc->value->data[j]; |
|---|
| 133 | if (buffer_is_equal_string(du->key, CONST_STR_LEN("cb.count"))) { |
|---|
| 134 | PATCH(count); |
|---|
| 135 | } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cb.prefix"))) { |
|---|
| 136 | PATCH(prefix); |
|---|
| 137 | } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cb.keyword"))) { |
|---|
| 138 | PATCH(keyword); |
|---|
| 139 | } |
|---|
| 140 | } |
|---|
| 141 | } |
|---|
| 142 | char *h = p->conf.prefix->ptr; |
|---|
| 143 | |
|---|
| 144 | return 0; |
|---|
| 145 | } |
|---|
| 146 | |
|---|
| 147 | URIHANDLER_FUNC(mod_cookie_balancer_con_reset) { |
|---|
| 148 | plugin_data *p = p_d; |
|---|
| 149 | |
|---|
| 150 | UNUSED(srv); |
|---|
| 151 | |
|---|
| 152 | if (con->plugin_ctx[p->id]) { |
|---|
| 153 | handler_ctx_free(con->plugin_ctx[p->id]); |
|---|
| 154 | con->plugin_ctx[p->id] = NULL; |
|---|
| 155 | } |
|---|
| 156 | |
|---|
| 157 | return HANDLER_GO_ON; |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | URIHANDLER_FUNC(mod_cookie_balancer_uri_handler) { |
|---|
| 161 | plugin_data *p = p_d; |
|---|
| 162 | data_string *ds; |
|---|
| 163 | |
|---|
| 164 | mod_cookie_balancer_patch_connection(srv, con, p); |
|---|
| 165 | |
|---|
| 166 | char *ch = con->request.uri->ptr; |
|---|
| 167 | if (*ch == '/') { |
|---|
| 168 | ch++; |
|---|
| 169 | char *substr = strstr(ch, p->conf.prefix->ptr); |
|---|
| 170 | if (substr && strcmp(substr, ch) == 0) |
|---|
| 171 | return HANDLER_GO_ON; |
|---|
| 172 | } |
|---|
| 173 | ds = (data_string *)array_get_element(con->request.headers, "Cookie"); |
|---|
| 174 | if (NULL != ds) { |
|---|
| 175 | char *g; |
|---|
| 176 | if (NULL != (g = strstr(ds->value->ptr, p->conf.keyword->ptr))) { |
|---|
| 177 | char *nc = g; |
|---|
| 178 | while (*nc != '=' && *nc != '\t') nc++; |
|---|
| 179 | if (*nc == '=') { |
|---|
| 180 | nc++; |
|---|
| 181 | buffer *tmp = buffer_init(); |
|---|
| 182 | buffer_append_string_buffer(tmp, con->request.uri); |
|---|
| 183 | buffer_reset(con->request.uri); |
|---|
| 184 | buffer_copy_string(con->request.uri, "/"); |
|---|
| 185 | buffer_append_string(con->request.uri, p->conf.prefix->ptr); |
|---|
| 186 | char num[1]; |
|---|
| 187 | sprintf(&num,"%d",(*nc & p->conf.count)); |
|---|
| 188 | buffer_append_string(con->request.uri, &num); |
|---|
| 189 | buffer_append_string_buffer(con->request.uri, tmp); |
|---|
| 190 | return HANDLER_COMEBACK; |
|---|
| 191 | } |
|---|
| 192 | } |
|---|
| 193 | } |
|---|
| 194 | /* |
|---|
| 195 | else { |
|---|
| 196 | if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) |
|---|
| 197 | ds = data_response_init(); |
|---|
| 198 | buffer_copy_string(ds->key, "Set-Cookie"); |
|---|
| 199 | buffer_append_string(ds->value, "cookiename=12345671"); |
|---|
| 200 | array_insert_unique(con->response.headers, (data_unset *)ds); |
|---|
| 201 | } |
|---|
| 202 | */ |
|---|
| 203 | return HANDLER_GO_ON; |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | int mod_cookie_balancer_plugin_init(plugin *p) { |
|---|
| 207 | p->version = LIGHTTPD_VERSION_ID; |
|---|
| 208 | p->name = buffer_init_string("cookie_balancer"); |
|---|
| 209 | |
|---|
| 210 | p->init = mod_cookie_balancer_init; |
|---|
| 211 | |
|---|
| 212 | p->handle_uri_raw = mod_cookie_balancer_uri_handler; |
|---|
| 213 | p->set_defaults = mod_cookie_balancer_set_defaults; |
|---|
| 214 | p->cleanup = mod_cookie_balancer_free; |
|---|
| 215 | p->connection_reset = mod_cookie_balancer_con_reset; |
|---|
| 216 | |
|---|
| 217 | p->data = NULL; |
|---|
| 218 | |
|---|
| 219 | return 0; |
|---|
| 220 | } |
|---|