Annotation of embedaddon/lighttpd/src/mod_flv_streaming.c, revision 1.1
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:
! 87: p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
! 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>