Docs/TrafficShaping: mod_speed.c

File mod_speed.c, 5.6 kB (added by Terminar, 1 year ago)

mod_speed.c for selective traffic shaping in lighttpd-1.5-svn

Line 
1 #include <ctype.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "base.h"
6 #include "log.h"
7 #include "buffer.h"
8
9 #include "plugin.h"
10 #include <unistd.h>
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 /**
17  * small lighttpd-plugin for selective speed
18  *
19  * Bjoern Kalkbrenner <terminar@cyberphoria.org> [20070204]
20  *
21  * Adds: X-LIGHTTPD-KBytes-per-second header, you now can use e.g.
22  * <?php
23  * header("X-LIGHTTPD-KBytes-per-second: 20");
24  * header("X-Sendfile: /path/to/file");
25  * ?>
26  * to set the max speed for the download/current connection. This can be also used with reproxy.
27  * Options:
28  * # use this on the frontend to just copy the header from the response to the request header (forward it to the backend)
29  * speed.just-copy-header = "enable"
30  * # use this on the backend to fetch the speed from the request. This is not useful on the frontend, i think :)
31  * speed.use-request = "enable"
32  *
33  */
34        
35        
36
37 /* plugin config for all request/connections */
38
39 typedef struct {
40         unsigned short just_copy_header;
41         unsigned short use_request;
42 } plugin_config;
43
44 typedef struct {
45         PLUGIN_DATA;
46
47         buffer *tmp_buf;
48
49         plugin_config **config_storage;
50
51         plugin_config conf;
52 } plugin_data;
53
54 /* init the plugin data */
55 INIT_FUNC(mod_speed_init) {
56         plugin_data *p;
57        
58         UNUSED(srv);
59
60         p = calloc(1, sizeof(*p));
61
62         return p;
63 }
64
65 /* detroy the plugin data */
66 FREE_FUNC(mod_speed_free) {
67         plugin_data *p = p_d;
68
69         UNUSED(srv);
70
71         if (!p) return HANDLER_GO_ON;
72
73         if (p->config_storage) {
74                 size_t i;
75                
76                 for (i = 0; i < srv->config_context->used; i++) {
77                         plugin_config *s = p->config_storage[i];
78
79                         if (!s) continue;
80
81                         free(s);
82                 }
83                 free(p->config_storage);
84         }
85
86         free(p);
87
88         return HANDLER_GO_ON;
89 }
90
91 /* handle plugin config and check values */
92 SETDEFAULTS_FUNC(mod_speed_set_defaults) {
93         plugin_data *p = p_d;
94         size_t i = 0;
95
96         config_values_t cv[] = {
97                 { "speed.just-copy-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
98                 { "speed.use-request", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
99                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
100         };
101
102         if (!p) return HANDLER_ERROR;
103
104         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
105
106         for (i = 0; i < srv->config_context->used; i++) {
107                 plugin_config *s;
108
109                 s = calloc(1, sizeof(plugin_config));
110                 s->just_copy_header = 0;
111                 s->use_request = 0;
112
113                 cv[0].destination = &(s->just_copy_header);
114                 cv[1].destination = &(s->use_request);
115                
116                 p->config_storage[i] = s;
117
118                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
119                     TRACE("%s","error inserting values config");
120                         return HANDLER_ERROR;
121                 }
122
123                                                
124         }
125
126
127         return HANDLER_GO_ON;
128 }
129
130 static int mod_speed_patch_connection(server *srv, connection *con, plugin_data *p) {
131         size_t i, j;
132         plugin_config *s = p->config_storage[0];
133
134         PATCH_OPTION(just_copy_header);
135         PATCH_OPTION(use_request);
136
137         /* skip the first, the global context */
138         for (i = 1; i < srv->config_context->used; i++) {
139        
140                 data_config *dc = (data_config *)srv->config_context->data[i];
141                 s = p->config_storage[i];
142
143                 /* condition didn't match */
144                 if (!config_check_cond(srv, con, dc)) continue;
145
146                 /* merge config */
147                 for (j = 0; j < dc->value->used; j++) {
148                         data_unset *du = dc->value->data[j];
149
150                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("speed.just-copy-header"))) {
151                         TRACE("%s","copy header set");
152                                 PATCH_OPTION(just_copy_header);
153                         }
154                        
155                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("speed.use-request"))) {
156                         TRACE("%s","use request header set");
157                                 PATCH_OPTION(use_request);
158                         }
159                        
160                 }
161         }
162
163         return 0;
164 }
165
166 URIHANDLER_FUNC(mod_speed_send_request_content) {
167         plugin_data *p = p_d;
168         buffer *b=NULL;
169         data_string *ds = NULL;
170         data_string *ds_request = NULL;
171         int found=0;
172
173         mod_speed_patch_connection(srv, con, p);
174
175         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, CONST_STR_LEN("X-LIGHTTPD-KBytes-per-second")))) {
176             if (p->conf.just_copy_header > 0) {
177
178                 if (NULL == (ds_request = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("X-LIGHTTPD-KBytes-per-second")))) {
179                
180                     if (NULL == (ds_request = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
181                         ds_request = data_string_init();
182                     }
183                    
184                 } else {
185                     found=1;
186                 }
187                                
188                 buffer_copy_string(ds_request->key, "X-LIGHTTPD-KBytes-per-second");
189                 buffer_copy_string(ds_request->value, ds->value->ptr);
190                 if (!found)
191                 {
192                     array_insert_unique(con->request.headers, (data_unset *)ds_request);
193                 }
194                
195             } else
196             {
197                 con->conf.kbytes_per_second = atol(ds->value->ptr);
198                 TRACE("===> Found my header for speed in send_request_content: %s",ds->value->ptr);
199             }
200            
201         }
202
203         /* not found */
204         return HANDLER_GO_ON;
205 }
206
207 URIHANDLER_FUNC(mod_speed_start_backend) {
208         plugin_data *p = p_d;
209         buffer *b=NULL;
210         data_string *ds = NULL;
211         data_string *ds_request = NULL;
212
213         mod_speed_patch_connection(srv, con, p);
214
215         if (p->conf.use_request > 0)
216         {
217                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("X-LIGHTTPD-KBytes-per-second")))) {
218        
219                     con->conf.kbytes_per_second = atol(ds->value->ptr);
220                 }
221         }
222        
223         /* not found */
224         return HANDLER_GO_ON;
225 }
226
227
228 /* this function is called at dlopen() time and inits the callbacks */
229
230 int mod_speed_plugin_init(plugin *p) {
231         p->version     = LIGHTTPD_VERSION_ID;
232         p->name        = buffer_init_string("speed");
233
234         p->init        = mod_speed_init;
235         p->set_defaults  = mod_speed_set_defaults;
236         p->cleanup     = mod_speed_free;
237
238         p->handle_start_backend = mod_speed_start_backend;
239         p->handle_send_request_content = mod_speed_send_request_content;
240
241         p->data        = NULL;
242
243         return 0;
244 }