[mod_auth] require digest uri= match original URI
[lighttpd.git] / src / mod_flv_streaming.c
blob427f877eb4293ef2315c2c60546ba54e2987fa71
1 #include "first.h"
3 #include "base.h"
4 #include "log.h"
5 #include "buffer.h"
6 #include "http_chunk.h"
7 #include "http_header.h"
9 #include "plugin.h"
11 #include <stdlib.h>
12 #include <string.h>
14 /* plugin config for all request/connections */
16 typedef struct {
17 array *extensions;
18 } plugin_config;
20 typedef struct {
21 PLUGIN_DATA;
22 plugin_config **config_storage;
23 plugin_config conf;
24 } plugin_data;
26 /* init the plugin data */
27 INIT_FUNC(mod_flv_streaming_init) {
28 return calloc(1, sizeof(plugin_data));
31 /* detroy the plugin data */
32 FREE_FUNC(mod_flv_streaming_free) {
33 plugin_data *p = p_d;
34 if (!p) return HANDLER_GO_ON;
36 if (p->config_storage) {
37 for (size_t i = 0; i < srv->config_context->used; ++i) {
38 plugin_config *s = p->config_storage[i];
39 if (NULL == s) continue;
40 array_free(s->extensions);
41 free(s);
43 free(p->config_storage);
45 free(p);
46 UNUSED(srv);
47 return HANDLER_GO_ON;
50 /* handle plugin config and check values */
52 SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
53 plugin_data *p = p_d;
54 size_t i = 0;
56 config_values_t cv[] = {
57 { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
58 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
61 if (!p) return HANDLER_ERROR;
63 p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
65 for (i = 0; i < srv->config_context->used; i++) {
66 data_config const* config = (data_config const*)srv->config_context->data[i];
67 plugin_config *s;
69 s = calloc(1, sizeof(plugin_config));
70 s->extensions = array_init();
72 cv[0].destination = s->extensions;
74 p->config_storage[i] = s;
76 if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
77 return HANDLER_ERROR;
80 if (!array_is_vlist(s->extensions)) {
81 log_error_write(srv, __FILE__, __LINE__, "s",
82 "unexpected value for flv-streaming.extensions; expected list of \"ext\"");
83 return HANDLER_ERROR;
87 return HANDLER_GO_ON;
90 #define PATCH(x) \
91 p->conf.x = s->x;
92 static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
93 size_t i, j;
94 plugin_config *s = p->config_storage[0];
96 PATCH(extensions);
98 /* skip the first, the global context */
99 for (i = 1; i < srv->config_context->used; i++) {
100 data_config *dc = (data_config *)srv->config_context->data[i];
101 s = p->config_storage[i];
103 /* condition didn't match */
104 if (!config_check_cond(srv, con, dc)) continue;
106 /* merge config */
107 for (j = 0; j < dc->value->used; j++) {
108 data_unset *du = dc->value->data[j];
110 if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
111 PATCH(extensions);
116 return 0;
118 #undef PATCH
120 static int split_get_params(array *get_params, buffer *qrystr) {
121 size_t is_key = 1, klen = 0;
122 char *key = qrystr->ptr, *val = NULL;
124 if (buffer_string_is_empty(qrystr)) return 0;
125 for (size_t i = 0, len = buffer_string_length(qrystr); i <= len; ++i) {
126 switch(qrystr->ptr[i]) {
127 case '=':
128 if (is_key) {
129 val = qrystr->ptr + i + 1;
130 klen = (size_t)(qrystr->ptr + i - key);
131 is_key = 0;
134 break;
135 case '&':
136 case '\0': /* fin symbol */
137 if (!is_key) {
138 /* we need at least a = since the last & */
139 array_insert_key_value(get_params, key, klen, val, qrystr->ptr + i - val);
142 key = qrystr->ptr + i + 1;
143 val = NULL;
144 is_key = 1;
145 break;
149 return 0;
152 URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
153 plugin_data *p = p_d;
155 if (con->mode != DIRECT) return HANDLER_GO_ON;
156 if (buffer_string_is_empty(con->physical.path)) return HANDLER_GO_ON;
158 mod_flv_streaming_patch_connection(srv, con, p);
160 if (!array_match_value_suffix(p->conf.extensions, con->physical.path)) {
161 /* not found */
162 return HANDLER_GO_ON;
166 data_string *get_param;
167 off_t start = 0, len = -1;
168 char *err = NULL;
169 /* if there is a start=[0-9]+ in the header use it as start,
170 * otherwise set start to beginning of file */
171 /* if there is a end=[0-9]+ in the header use it as end pos,
172 * otherwise send rest of file, starting from start */
174 array_reset_data_strings(srv->split_vals);
175 split_get_params(srv->split_vals, con->uri.query);
177 if (NULL != (get_param = (data_string *)array_get_element_klen(srv->split_vals, CONST_STR_LEN("start")))) {
178 if (buffer_string_is_empty(get_param->value)) return HANDLER_GO_ON;
179 start = strtoll(get_param->value->ptr, &err, 10);
180 if (*err != '\0') return HANDLER_GO_ON;
181 if (start < 0) return HANDLER_GO_ON;
184 if (NULL != (get_param = (data_string *)array_get_element_klen(srv->split_vals, CONST_STR_LEN("end")))) {
185 off_t end;
186 if (buffer_string_is_empty(get_param->value)) return HANDLER_GO_ON;
187 end = strtoll(get_param->value->ptr, &err, 10);
188 if (*err != '\0') return HANDLER_GO_ON;
189 if (end < 0) return HANDLER_GO_ON;
190 len = (start < end ? end - start : start - end) + 1;
192 else if (0 == start) {
193 return HANDLER_GO_ON;
196 /* let's build a flv header */
197 http_chunk_append_mem(srv, con, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9"));
198 if (0 != http_chunk_append_file_range(srv, con, con->physical.path, start, len)) {
199 chunkqueue_reset(con->write_queue);
200 return HANDLER_GO_ON;
203 http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv"));
204 con->file_finished = 1;
205 return HANDLER_FINISHED;
209 /* this function is called at dlopen() time and inits the callbacks */
211 int mod_flv_streaming_plugin_init(plugin *p);
212 int mod_flv_streaming_plugin_init(plugin *p) {
213 p->version = LIGHTTPD_VERSION_ID;
214 p->name = buffer_init_string("flv_streaming");
216 p->init = mod_flv_streaming_init;
217 p->handle_physical = mod_flv_streaming_path_handler;
218 p->set_defaults = mod_flv_streaming_set_defaults;
219 p->cleanup = mod_flv_streaming_free;
221 p->data = NULL;
223 return 0;