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