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>