File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / mod_flv_streaming.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:35:00 2016 UTC (7 years, 7 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_41p8, HEAD
lighttpd 1.4.41

    1: #include "first.h"
    2: 
    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: 
   59: 			if (NULL == s) continue;
   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: 
   89: 	p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
   90: 
   91: 	for (i = 0; i < srv->config_context->used; i++) {
   92: 		data_config const* config = (data_config const*)srv->config_context->data[i];
   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: 
  102: 		if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
  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;
  142: 	size_t i, len;
  143: 	char *key = NULL, *val = NULL;
  144: 
  145: 	key = qrystr->ptr;
  146: 
  147: 	/* we need the \0 */
  148: 	len = buffer_string_length(qrystr);
  149: 	for (i = 0; i <= len; i++) {
  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: 
  198: 	if (buffer_string_is_empty(con->physical.path)) return HANDLER_GO_ON;
  199: 
  200: 	mod_flv_streaming_patch_connection(srv, con, p);
  201: 
  202: 	s_len = buffer_string_length(con->physical.path);
  203: 
  204: 	for (k = 0; k < p->conf.extensions->used; k++) {
  205: 		data_string *ds = (data_string *)p->conf.extensions->data[k];
  206: 		int ct_len = buffer_string_length(ds->value);
  207: 
  208: 		if (ct_len > s_len) continue;
  209: 		if (buffer_is_empty(ds->value)) continue;
  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);
  219: 			buffer_copy_buffer(p->query_str, con->uri.query);
  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 */
  227: 			if (buffer_string_is_empty(get_param->value)) return HANDLER_GO_ON;
  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: 
  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);
  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>