Ticket #1658: mod_cookie_balancer.c

File mod_cookie_balancer.c, 5.0 kB (added by kirakuna, 5 months ago)
Line 
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
20typedef struct {
21        buffer *prefix; // one symbol prefix for fcgi
22        buffer *keyword;
23        int count;      // must be power of two
24} plugin_config;
25
26typedef struct {
27        size_t foo;
28} handler_ctx;
29
30typedef struct {
31        PLUGIN_DATA;
32        buffer *match_buf;
33        plugin_config **config_storage;
34        plugin_config conf;
35} plugin_data;
36
37static handler_ctx * handler_ctx_init() {
38        handler_ctx * hctx;
39        hctx = calloc(1, sizeof(*hctx));
40        return hctx;
41}
42
43static void handler_ctx_free(handler_ctx *hctx) {
44        free(hctx);
45}
46
47INIT_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
57FREE_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
80SETDEFAULTS_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;
118static 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
147URIHANDLER_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
160URIHANDLER_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
206int 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}