Annotation of embedaddon/lighttpd/src/mod_flv_streaming.c, revision 1.1.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>