File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / mod_flv_streaming.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:20:06 2014 UTC (10 years ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_35p0, v1_4_35, HEAD
lighttpd 1.4.35

    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(plugin_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>