Return to mod_flv_streaming.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src |
1.1 misho 1: #include "base.h"
2: #include "log.h"
3: #include "buffer.h"
4: #include "response.h"
5: #include "http_chunk.h"
6: #include "stat_cache.h"
7:
8: #include "plugin.h"
9:
10: #include <ctype.h>
11: #include <stdlib.h>
12: #include <string.h>
13:
14: /* plugin config for all request/connections */
15:
16: typedef struct {
17: array *extensions;
18: } plugin_config;
19:
20: typedef struct {
21: PLUGIN_DATA;
22:
23: buffer *query_str;
24: array *get_params;
25:
26: plugin_config **config_storage;
27:
28: plugin_config conf;
29: } plugin_data;
30:
31: /* init the plugin data */
32: INIT_FUNC(mod_flv_streaming_init) {
33: plugin_data *p;
34:
35: p = calloc(1, sizeof(*p));
36:
37: p->query_str = buffer_init();
38: p->get_params = array_init();
39:
40: return p;
41: }
42:
43: /* detroy the plugin data */
44: FREE_FUNC(mod_flv_streaming_free) {
45: plugin_data *p = p_d;
46:
47: UNUSED(srv);
48:
49: if (!p) return HANDLER_GO_ON;
50:
51: if (p->config_storage) {
52: size_t i;
53:
54: for (i = 0; i < srv->config_context->used; i++) {
55: plugin_config *s = p->config_storage[i];
56:
57: if (!s) continue;
58:
59: array_free(s->extensions);
60:
61: free(s);
62: }
63: free(p->config_storage);
64: }
65:
66: buffer_free(p->query_str);
67: array_free(p->get_params);
68:
69: free(p);
70:
71: return HANDLER_GO_ON;
72: }
73:
74: /* handle plugin config and check values */
75:
76: SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
77: plugin_data *p = p_d;
78: size_t i = 0;
79:
80: config_values_t cv[] = {
81: { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
82: { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
83: };
84:
85: if (!p) return HANDLER_ERROR;
86:
1.1.1.2 ! misho 87: p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
1.1 misho 88:
89: for (i = 0; i < srv->config_context->used; i++) {
90: plugin_config *s;
91:
92: s = calloc(1, sizeof(plugin_config));
93: s->extensions = array_init();
94:
95: cv[0].destination = s->extensions;
96:
97: p->config_storage[i] = s;
98:
99: if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
100: return HANDLER_ERROR;
101: }
102: }
103:
104: return HANDLER_GO_ON;
105: }
106:
107: #define PATCH(x) \
108: p->conf.x = s->x;
109: static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
110: size_t i, j;
111: plugin_config *s = p->config_storage[0];
112:
113: PATCH(extensions);
114:
115: /* skip the first, the global context */
116: for (i = 1; i < srv->config_context->used; i++) {
117: data_config *dc = (data_config *)srv->config_context->data[i];
118: s = p->config_storage[i];
119:
120: /* condition didn't match */
121: if (!config_check_cond(srv, con, dc)) continue;
122:
123: /* merge config */
124: for (j = 0; j < dc->value->used; j++) {
125: data_unset *du = dc->value->data[j];
126:
127: if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
128: PATCH(extensions);
129: }
130: }
131: }
132:
133: return 0;
134: }
135: #undef PATCH
136:
137: static int split_get_params(array *get_params, buffer *qrystr) {
138: size_t is_key = 1;
139: size_t i;
140: char *key = NULL, *val = NULL;
141:
142: key = qrystr->ptr;
143:
144: /* we need the \0 */
145: for (i = 0; i < qrystr->used; i++) {
146: switch(qrystr->ptr[i]) {
147: case '=':
148: if (is_key) {
149: val = qrystr->ptr + i + 1;
150:
151: qrystr->ptr[i] = '\0';
152:
153: is_key = 0;
154: }
155:
156: break;
157: case '&':
158: case '\0': /* fin symbol */
159: if (!is_key) {
160: data_string *ds;
161: /* we need at least a = since the last & */
162:
163: /* terminate the value */
164: qrystr->ptr[i] = '\0';
165:
166: if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
167: ds = data_string_init();
168: }
169: buffer_copy_string_len(ds->key, key, strlen(key));
170: buffer_copy_string_len(ds->value, val, strlen(val));
171:
172: array_insert_unique(get_params, (data_unset *)ds);
173: }
174:
175: key = qrystr->ptr + i + 1;
176: val = NULL;
177: is_key = 1;
178: break;
179: }
180: }
181:
182: return 0;
183: }
184:
185: URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
186: plugin_data *p = p_d;
187: int s_len;
188: size_t k;
189:
190: UNUSED(srv);
191:
192: if (con->mode != DIRECT) return HANDLER_GO_ON;
193:
194: if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
195:
196: mod_flv_streaming_patch_connection(srv, con, p);
197:
198: s_len = con->physical.path->used - 1;
199:
200: for (k = 0; k < p->conf.extensions->used; k++) {
201: data_string *ds = (data_string *)p->conf.extensions->data[k];
202: int ct_len = ds->value->used - 1;
203:
204: if (ct_len > s_len) continue;
205: if (ds->value->used == 0) continue;
206:
207: if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
208: data_string *get_param;
209: stat_cache_entry *sce = NULL;
210: buffer *b;
211: int start;
212: char *err = NULL;
213: /* if there is a start=[0-9]+ in the header use it as start,
214: * otherwise send the full file */
215:
216: array_reset(p->get_params);
217: buffer_copy_string_buffer(p->query_str, con->uri.query);
218: split_get_params(p->get_params, p->query_str);
219:
220: if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
221: return HANDLER_GO_ON;
222: }
223:
224: /* too short */
225: if (get_param->value->used < 2) return HANDLER_GO_ON;
226:
227: /* check if it is a number */
228: start = strtol(get_param->value->ptr, &err, 10);
229: if (*err != '\0') {
230: return HANDLER_GO_ON;
231: }
232:
233: if (start <= 0) return HANDLER_GO_ON;
234:
235: /* check if start is > filesize */
236: if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
237: return HANDLER_GO_ON;
238: }
239:
240: if (start > sce->st.st_size) {
241: return HANDLER_GO_ON;
242: }
243:
244: /* we are safe now, let's build a flv header */
245: b = chunkqueue_get_append_buffer(con->write_queue);
246: buffer_copy_string_len(b, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9"));
247:
248: http_chunk_append_file(srv, con, con->physical.path, start, sce->st.st_size - start);
249:
250: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv"));
251:
252: con->file_finished = 1;
253:
254: return HANDLER_FINISHED;
255: }
256: }
257:
258: /* not found */
259: return HANDLER_GO_ON;
260: }
261:
262: /* this function is called at dlopen() time and inits the callbacks */
263:
264: int mod_flv_streaming_plugin_init(plugin *p);
265: int mod_flv_streaming_plugin_init(plugin *p) {
266: p->version = LIGHTTPD_VERSION_ID;
267: p->name = buffer_init_string("flv_streaming");
268:
269: p->init = mod_flv_streaming_init;
270: p->handle_physical = mod_flv_streaming_path_handler;
271: p->set_defaults = mod_flv_streaming_set_defaults;
272: p->cleanup = mod_flv_streaming_free;
273:
274: p->data = NULL;
275:
276: return 0;
277: }