Exemple #1
0
/* The old shoutcast procotol. Don't look at this, it's really nasty */
int httpp_parse_icy(http_parser_t *parser, char *http_data, unsigned long len)
{
    char *data;
    char *line[MAX_HEADERS];
    int lines;

    if(http_data == NULL)
        return 0;

    data = malloc(len + 1);
    memcpy(data, http_data, len);
    data[len] = 0;

    lines = split_headers(data, len, line);

    /* Now, this protocol looks like:
     * sourcepassword\n
     * headers: as normal\n"
     * \n
     */

    parser->req_type = httpp_req_source;
    httpp_setvar(parser, HTTPP_VAR_URI, "/");
    httpp_setvar(parser, HTTPP_VAR_ICYPASSWORD, line[0]);
    httpp_setvar(parser, HTTPP_VAR_PROTOCOL, "ICY");
    httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE");
    /* This protocol is evil */
    httpp_setvar(parser, HTTPP_VAR_VERSION, "666");

    parse_headers(parser, line, lines);

    free(data);
    
    return 1;
}
Exemple #2
0
int httpp_parse_response(http_parser_t *parser, char *http_data, unsigned long len, char *uri)
{
    char *data;
    char *line[MAX_HEADERS];
    int lines, slen,i, whitespace=0, where=0,code;
    char *version=NULL, *resp_code=NULL, *message=NULL;
    
    if(http_data == NULL)
        return 0;

    /* make a local copy of the data, including 0 terminator */
    data = (char *)malloc(len+1);
    if (data == NULL) return 0;
    memcpy(data, http_data, len);
    data[len] = 0;

    lines = split_headers(data, len, line);

    /* In this case, the first line contains:
     * VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK
     */
    slen = strlen(line[0]);
    version = line[0];
    for(i=0; i < slen; i++) {
        if(line[0][i] == ' ') {
            line[0][i] = 0;
            whitespace = 1;
        } else if(whitespace) {
            whitespace = 0;
            where++;
            if(where == 1)
                resp_code = &line[0][i];
            else {
                message = &line[0][i];
                break;
            }
        }
    }

    if(version == NULL || resp_code == NULL || message == NULL) {
        free(data);
        return 0;
    }

    httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code);
    code = atoi(resp_code);
    if(code < 200 || code >= 300) {
        httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message);
    }

    httpp_setvar(parser, HTTPP_VAR_URI, uri);
    httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE");

    parse_headers(parser, line, lines);

    free(data);

    return 1;
}
int format_ogg_get_plugin (format_plugin_t *plugin, client_t *client)
{
    ogg_state_t *state = calloc (1, sizeof (ogg_state_t));

    plugin->get_buffer = ogg_get_buffer;
    plugin->write_buf_to_client = write_buf_to_client;
    plugin->write_buf_to_file = write_ogg_to_file;
    plugin->create_client_data = create_ogg_client_data;
    plugin->free_plugin = format_ogg_free_plugin;
    plugin->get_image = get_image;
    plugin->set_tag = NULL;
    plugin->apply_settings = apply_ogg_settings;
    if (plugin->parser)
    {
        const char *s = httpp_getvar (plugin->parser, "content-type");;
        if (s==NULL || strcmp (s, "application/x-ogg") == 0)
            httpp_setvar (plugin->parser, "content-type", "application/ogg");
        plugin->contenttype = strdup (httpp_getvar (plugin->parser, "content-type"));
    }
    else
        plugin->contenttype = strdup ("application/ogg");

    ogg_sync_init (&state->oy);

    plugin->_state = state;
    state->mount = plugin->mount;
    state->bos_end = &state->header_pages;

    return 0;
}
Exemple #4
0
int format_ogg_get_plugin (source_t *source)
{
    format_plugin_t *plugin;
    ogg_state_t *state = calloc (1, sizeof (ogg_state_t));

    plugin = (format_plugin_t *)calloc(1, sizeof(format_plugin_t));

    plugin->type = FORMAT_TYPE_OGG;
    plugin->get_buffer = ogg_get_buffer;
    plugin->write_buf_to_client = write_buf_to_client;
    plugin->write_buf_to_file = write_ogg_to_file;
    plugin->create_client_data = create_ogg_client_data;
    plugin->free_plugin = format_ogg_free_plugin;
    plugin->set_tag = NULL;
    if (strcmp (httpp_getvar (source->parser, "content-type"), "application/x-ogg") == 0)
        httpp_setvar (source->parser, "content-type", "application/ogg");
    plugin->contenttype = httpp_getvar (source->parser, "content-type");

    ogg_sync_init (&state->oy);

    plugin->_state = state;
    source->format = plugin;
    state->mount = source->mount;
    state->bos_end = &state->header_pages;

    return 0;
}
Exemple #5
0
static void ogg_apply_client (format_plugin_t *plugin, client_t *client)
{
    ogg_state_t *state = plugin->_state;

    state->mount = NULL;
    ogg_sync_clear (&state->oy);

    if (client == NULL)
        return;
    plugin->parser = client->parser;
    if (plugin->parser)
    {
        const char *s = httpp_getvar (plugin->parser, "content-type");
        if (s==NULL || strcmp (s, "application/x-ogg") == 0)
            httpp_setvar (plugin->parser, "content-type", "application/ogg");
        s = httpp_getvar (plugin->parser, "content-type");
        if (s)
            plugin->contenttype = strdup (s);
    }

    ogg_sync_init (&state->oy);

    state->mount = plugin->mount;
    state->bos_end = &state->header_pages;
}
Exemple #6
0
void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults)
{
    http_varlist_t *list;

    parser->req_type = httpp_req_none;
    parser->uri = NULL;
    parser->vars = avl_tree_new(_compare_vars, NULL);
    parser->queryvars = avl_tree_new(_compare_vars, NULL);

    /* now insert the default variables */
    list = defaults;
    while (list != NULL) {
        httpp_setvar(parser, list->var.name, list->var.value);
        list = list->next;
    }
}
Exemple #7
0
static void parse_headers(http_parser_t *parser, char **line, int lines)
{
    int i,l;
    int whitespace, where, slen;
    char *name = NULL;
    char *value = NULL;

    /* parse the name: value lines. */
    for (l = 1; l < lines; l++) {
        where = 0;
        whitespace = 0;
        name = line[l];
        value = NULL;
        slen = strlen(line[l]);
        for (i = 0; i < slen; i++) {
            if (line[l][i] == ':') {
                whitespace = 1;
                line[l][i] = '\0';
            } else {
                if (whitespace) {
                    whitespace = 0;
                    while (i < slen && line[l][i] == ' ')
                        i++;

                    if (i < slen)
                        value = &line[l][i];
                    
                    break;
                }
            }
        }
        
        if (name != NULL && value != NULL) {
            httpp_setvar(parser, _lowercase(name), value);
            name = NULL; 
            value = NULL;
        }
    }
}
Exemple #8
0
int httpp_parse(http_parser_t *parser, const char *http_data, unsigned long len)
{
    char *data, *tmp;
    char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */
    int i;
    int lines;
    char *req_type = NULL;
    char *uri = NULL;
    char *version = NULL;
    int whitespace, where, slen;

    if (http_data == NULL)
        return 0;

    /* make a local copy of the data, including 0 terminator */
    data = (char *)amalloc(len+1);
    memcpy(data, http_data, len);
    data[len] = 0;

    lines = split_headers(data, len, line);

    /* parse the first line special
    ** the format is:
    ** REQ_TYPE URI VERSION
    ** eg:
    ** GET /index.html HTTP/1.0
    */
    where = 0;
    whitespace = 0;
    slen = strlen(line[0]);
    req_type = line[0];
    for (i = 0; i < slen; i++) {
        if (line[0][i] == ' ') {
            whitespace = 1;
            line[0][i] = '\0';
        } else {
            /* we're just past the whitespace boundry */
            if (whitespace) {
                whitespace = 0;
                where++;
                switch (where) {
                case 1:
                    uri = &line[0][i];
                    break;
                case 2:
                    version = &line[0][i];
                    break;
                }
            }
        }
    }

    if (strcasecmp("GET", req_type) == 0) {
        parser->req_type = httpp_req_get;
    } else if (strcasecmp("POST", req_type) == 0) {
        parser->req_type = httpp_req_post;
    } else if (strcasecmp("HEAD", req_type) == 0) {
        parser->req_type = httpp_req_head;
    } else if (strcasecmp("SOURCE", req_type) == 0) {
        parser->req_type = httpp_req_source;
    } else if (strcasecmp("PLAY", req_type) == 0) {
        parser->req_type = httpp_req_play;
    } else if (strcasecmp("STATS", req_type) == 0) {
        parser->req_type = httpp_req_stats;
    } else {
        parser->req_type = httpp_req_unknown;
    }

    if (uri != NULL && strlen(uri) > 0) {
        char *query;
        if((query = strchr(uri, '?')) != NULL) {
            httpp_setvar(parser, HTTPP_VAR_RAWURI, uri);
            httpp_setvar(parser, HTTPP_VAR_QUERYARGS, query);
            *query = 0;
            query++;
            parse_query(parser, query);
        }

        parser->uri = strdup(uri);
    } else {
        free(data);
        return 0;
    }

    if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) {
        tmp[0] = '\0';
        if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) {
            httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version);
            httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]);
        } else {
            free(data);
            return 0;
        }
    } else {
        free(data);
        return 0;
    }

    if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) {
        switch (parser->req_type) {
        case httpp_req_get:
            httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET");
            break;
        case httpp_req_post:
            httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST");
            break;
        case httpp_req_head:
            httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD");
            break;
        case httpp_req_source:
            httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE");
            break;
        case httpp_req_play:
            httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY");
            break;
        case httpp_req_stats:
            httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS");
            break;
        default:
            break;
        }
    } else {
        free(data);
        return 0;
    }

    if (parser->uri != NULL) {
        httpp_setvar(parser, HTTPP_VAR_URI, parser->uri);
    } else {
        free(data);
        return 0;
    }

    parse_headers(parser, line, lines);

    free(data);

    return 1;
}
Exemple #9
0
/* client has requested a file, so check for it and send the file.  Do not
 * refer to the client_t afterwards.  return 0 for success, -1 on error.
 */
int fserve_client_create (client_t *httpclient, const char *path)
{
    struct stat file_buf;
    char *fullpath;
    int m3u_requested = 0, m3u_file_available = 1;
    int xspf_requested = 0, xspf_file_available = 1;
    int ret = -1;
    ice_config_t *config;
    fbinfo finfo;
    char fsize[20];

    fullpath = util_get_path_from_normalised_uri (path, 0);
    DEBUG2 ("checking for file %s (%s)", path, fullpath);

    if (strcmp (util_get_extension (fullpath), "m3u") == 0)
        m3u_requested = 1;

    if (strcmp (util_get_extension (fullpath), "xspf") == 0)
        xspf_requested = 1;

    /* check for the actual file */
    if (stat (fullpath, &file_buf) != 0)
    {
        /* the m3u can be generated, but send an m3u file if available */
        if (m3u_requested == 0 && xspf_requested == 0)
        {
            if (redirect_client (path, httpclient) == 0)
            {
                if ((httpclient->flags & CLIENT_SKIP_ACCESSLOG) == 0)
                    WARN2 ("req for file \"%s\" %s", fullpath, strerror (errno));
                ret = client_send_404 (httpclient, "The file you requested could not be found");
            }
            free (fullpath);
            return ret;
        }
        m3u_file_available = 0;
        xspf_file_available = 0;
    }

    client_set_queue (httpclient, NULL);
    httpclient->refbuf = refbuf_new (4096);

    if (m3u_requested && m3u_file_available == 0)
    {
        const char  *host = httpp_getvar (httpclient->parser, "host"),
                    *args = httpp_getvar (httpclient->parser, HTTPP_VAR_QUERYARGS),
                    *at = "", *user = "", *pass ="";
        char *sourceuri = strdup (path);
        char *dot = strrchr (sourceuri, '.');
        char *protocol = "http";
        const char *agent = httpp_getvar (httpclient->parser, "user-agent");
        int x;
        char scratch[1000];

        if (agent)
        {
            if (strstr (agent, "QTS") || strstr (agent, "QuickTime"))
                protocol = "icy";
        }
        /* at least a couple of players (fb2k/winamp) are reported to send a 
         * host header but without the port number. So if we are missing the
         * port then lets treat it as if no host line was sent */
        if (host && strchr (host, ':') == NULL)
            host = NULL;

        *dot = 0;
        if (httpclient->username && httpclient->password)
        {
            at = "@";
            user = httpclient->username;
            pass = httpclient->password;
        }
        httpclient->respcode = 200;
        if (host == NULL)
        {
            config = config_get_config();
            x = snprintf (scratch, sizeof scratch,
                    "%s://%s%s%s%s%s:%d%s%s\r\n",
                    protocol,
                    user, at[0]?":":"", pass, at,
                    config->hostname, config->port,
                    sourceuri,
                    args?args:"");
            config_release_config();
        }
        else
        {
            x = snprintf (scratch, sizeof scratch,
                    "%s://%s%s%s%s%s%s%s\r\n",
                    protocol,
                    user, at[0]?":":"", pass, at,
                    host,
                    sourceuri,
                    args?args:"");
        }
        snprintf (httpclient->refbuf->data, BUFSIZE,
                "HTTP/1.0 200 OK\r\n"
                "Content-Length: %d\r\n"
                "%s\r\n"
                "Content-Type: audio/x-mpegurl\r\n\r\n%s",
                x, client_keepalive_header (httpclient), scratch);
        httpclient->refbuf->len = strlen (httpclient->refbuf->data);
        free (sourceuri);
        free (fullpath);
        return fserve_setup_client_fb (httpclient, NULL);
    }
    if (xspf_requested && xspf_file_available == 0)
    {
        xmlDocPtr doc;
        char *reference = strdup (path);
        char *eol = strrchr (reference, '.');
        if (eol)
            *eol = '\0';
        doc = stats_get_xml (0, reference);
        free (reference);
        free (fullpath);
        return admin_send_response (doc, httpclient, XSLT, "xspf.xsl");
    }

    /* on demand file serving check */
    config = config_get_config();
    if (config->fileserve == 0)
    {
        config_release_config();
        DEBUG1 ("on demand file \"%s\" refused", fullpath);
        free (fullpath);
        return client_send_404 (httpclient, "The file you requested could not be found");
    }
    config_release_config();

    if (S_ISREG (file_buf.st_mode) == 0)
    {
        WARN1 ("found requested file but there is no handler for it: %s", fullpath);
        free (fullpath);
        return client_send_404 (httpclient, "The file you requested could not be found");
    }

    free (fullpath);
    finfo.flags = 0;
    finfo.mount = (char *)path;
    finfo.fallback = NULL;
    finfo.limit = 0;
    finfo.type = FORMAT_TYPE_UNDEFINED;
    snprintf (fsize, 20, "%" PRId64, (int64_t)file_buf.st_size);
    httpp_setvar (httpclient->parser, "__FILESIZE", fsize);
    stats_event_inc (NULL, "file_connections");

    return fserve_setup_client_fb (httpclient, &finfo);
}
Exemple #10
0
void admin_handle_request(client_t *client, const char *uri)
{
    const char *mount, *command_string;
    int command;

    DEBUG1("Admin request (%s)", uri);
    if (!((strcmp(uri, "/admin.cgi") == 0) ||
         (strncmp("/admin/", uri, 7) == 0))) {
        ERROR0("Internal error: admin request isn't");
        client_send_401(client);
        return;
    }

    if (strcmp(uri, "/admin.cgi") == 0) {
        command_string = uri + 1;
    }
    else {
        command_string = uri + 7;
    }

    DEBUG1("Got command (%s)", command_string);
    command = admin_get_command(command_string);

    if(command < 0) {
        ERROR1("Error parsing command string or unrecognised command: %s",
                command_string);
        client_send_400(client, "Unrecognised command");
        return;
    }

    if (command == COMMAND_SHOUTCAST_METADATA_UPDATE) {

        ice_config_t *config;
        const char *sc_mount;
        const char *pass = httpp_get_query_param (client->parser, "pass");
        listener_t *listener;

        if (pass == NULL)
        {
            client_send_400 (client, "missing pass parameter");
            return;
        }
        config = config_get_config ();
        sc_mount = config->shoutcast_mount;
        listener = config_get_listen_sock (config, client->con);
        if (listener && listener->shoutcast_mount)
            sc_mount = listener->shoutcast_mount;

        httpp_set_query_param (client->parser, "mount", sc_mount);
        httpp_setvar (client->parser, HTTPP_VAR_PROTOCOL, "ICY");
        httpp_setvar (client->parser, HTTPP_VAR_ICYPASSWORD, pass);
        config_release_config ();
    }

    mount = httpp_get_query_param(client->parser, "mount");

    if(mount != NULL) {
        source_t *source;

        /* this request does not require auth but can apply to files on webroot */
        if (command == COMMAND_BUILDM3U)
        {
            command_buildm3u (client, mount);
            return;
        }
        /* This is a mount request, handle it as such */
        if (!connection_check_admin_pass(client->parser))
        {
            if (!connection_check_source_pass(client->parser, mount))
            {
                INFO1("Bad or missing password on mount modification admin "
                        "request (command: %s)", command_string);
                client_send_401(client);
                return;
            }
        }
        
        avl_tree_rlock(global.source_tree);
        source = source_find_mount_raw(mount);

        if (source == NULL)
        {
            WARN2("Admin command %s on non-existent source %s", 
                    command_string, mount);
            avl_tree_unlock(global.source_tree);
            client_send_400(client, "Source does not exist");
        }
        else
        {
            if (source->running == 0 && source->on_demand == 0)
            {
                avl_tree_unlock (global.source_tree);
                INFO2("Received admin command %s on unavailable mount \"%s\"",
                        command_string, mount);
                client_send_400 (client, "Source is not available");
                return;
            }
            if (command == COMMAND_SHOUTCAST_METADATA_UPDATE &&
                    source->shoutcast_compat == 0)
            {
                avl_tree_unlock (global.source_tree);
                ERROR0 ("illegal change of metadata on non-shoutcast "
                        "compatible stream");
                client_send_400 (client, "illegal metadata call");
                return;
            }
            INFO2("Received admin command %s on mount \"%s\"", 
                    command_string, mount);
            admin_handle_mount_request(client, source, command);
            avl_tree_unlock(global.source_tree);
        }
    }
    else {

        if (command == COMMAND_PLAINTEXT_LISTSTREAM) {
        /* this request is used by a slave relay to retrieve
           mounts from the master, so handle this request
           validating against the relay password */
            if(!connection_check_relay_pass(client->parser)) {
                INFO1("Bad or missing password on admin command "
                      "request (command: %s)", command_string);
                client_send_401(client);
                return;
            }
        }
        else {
            if(!connection_check_admin_pass(client->parser)) {
                INFO1("Bad or missing password on admin command "
                      "request (command: %s)", command_string);
                client_send_401(client);
                return;
            }
        }
        
        admin_handle_general_request(client, command);
    }
}
Exemple #11
0
int format_general_headers (format_plugin_t *plugin, client_t *client)
{
    unsigned remaining = 4096 - client->refbuf->len;
    char *ptr = client->refbuf->data + client->refbuf->len;
    int bytes = 0;
    int bitrate_filtered = 0;
    avl_node *node;
    ice_config_t *config;
    uint64_t length = 0; 

    /* hack for flash player, it wants a length. */
    if (httpp_getvar (client->parser, "x-flash-version"))
        length = 221183499;
    else
    {
        // flash may not send above header, so check for swf in referer
        const char *referer = httpp_getvar (client->parser, "referer");
        if (referer)
        {
            int len = strcspn (referer, "?");
            if (len >= 4 && strncmp (referer+len-4, ".swf", 4) == 0)
                length = 221183499;
        }
    }

    if (client->respcode == 0)
    {
        const char *useragent = httpp_getvar (client->parser, "user-agent");
        const char *protocol = "HTTP/1.0";
        const char *contenttypehdr = "Content-Type";
        const char *contenttype = plugin->contenttype;
        const char *range = httpp_getvar (client->parser, "range");
        const char *fs = httpp_getvar (client->parser, "__FILESIZE");

        if (useragent)
        {
            const char *resp = httpp_get_query_param (client->parser, "_hdr");
            int fmtcode = 0;
#define FMT_RETURN_ICY          1
#define FMT_LOWERCASE_TYPE      2
#define FMT_FORCE_AAC           4

            do
            {
                if (resp)
                {
                    fmtcode = atoi (resp);
                    break;
                }
                if (fs) break;  // ignore following settings for files.
                if (strstr (useragent, "shoutcastsource")) /* hack for mpc */
                    fmtcode = FMT_RETURN_ICY;
                if (strstr (useragent, "Windows-Media-Player") || strstr (useragent, "WMFSDK")) /* hack for wmp*/
                    fmtcode = FMT_RETURN_ICY;
                if (strstr (useragent, "RealMedia")) /* hack for rp (mainly mobile) */
                    fmtcode = FMT_RETURN_ICY;
                if (strstr (useragent, "Shoutcast Server")) /* hack for sc_serv */
                    fmtcode = FMT_LOWERCASE_TYPE;
                // if (strstr (useragent, "Sonos"))
                //    contenttypehdr = "content-type";
                if (plugin->type == FORMAT_TYPE_AAC && strstr (useragent, "AppleWebKit"))
                    fmtcode |= FMT_FORCE_AAC;
                if (strstr (useragent, "BlackBerry"))
                {
                    fmtcode |= FMT_RETURN_ICY;
                    if (plugin->type == FORMAT_TYPE_AAC)
                        fmtcode |= FMT_FORCE_AAC;
                }
            } while (0);
            if (fmtcode & FMT_RETURN_ICY)
                protocol = "ICY";
            if (fmtcode & FMT_LOWERCASE_TYPE)
                contenttypehdr = "content-type";
            if (fmtcode & FMT_FORCE_AAC) // ie for avoiding audio/aacp
                contenttype = "audio/aac";
        }
        if (fs)
        {
            uint64_t pos1 = 0, pos2 = length ? length : 50000000, max = pos2;
            char buf[30];

            sscanf (fs, "%" SCNuMAX, &max);
            if (range)
            {
                if (strncmp (range, "bytes=-", 7) == 0)
                {
                    sscanf (range, "bytes=-%" SCNuMAX, &pos2);
                    pos1 = max-pos2;
                    pos2 = max-1;
                }
                else
                {
                    if (sscanf (range, "bytes=%" SCNuMAX "-%" SCNuMAX, &pos1, &pos2) < 2)
                        pos2 = max-1;
                }
                if (pos2 >= max || pos1 >= pos2)
                {
                    DEBUG2 ("client range invalid (%" PRIu64 ", %" PRIu64 ")", pos1, pos2);
                    return -1;
                }
                length = pos2 - pos1 + 1;
                snprintf (buf, 30, "%" PRIu64, length);
                httpp_setvar (client->parser, "__LENGTH", buf);
                client->respcode = 206;
                client->intro_offset = pos1;
                bytes = snprintf (ptr, remaining, "%s 206 Partial Content\r\n"
                        "%s: %s\r\n"
                        "Content-Length: %" PRIu64 "\r\n"
                        "Content-Range: bytes %" PRIu64 "-%" PRIu64 "/%" PRIu64 "\r\n",
                        protocol, contenttypehdr,
                        contenttype ? contenttype : "application/octet-stream",
                        length,
                        pos1, pos2, max);
            }
            else
            {
                client->respcode = 200;
                bytes = snprintf (ptr, remaining, "%s 200 OK\r\n"
                        "Content-Length: %" PRIu64 "\r\n"
                        "%s: %s\r\n", protocol, max, contenttypehdr, contenttype);
            }
        }
        else
        {
            client->respcode = 200;
            bytes = snprintf (ptr, remaining, "%s 200 OK\r\n"
                    "%s: %s\r\n", protocol, contenttypehdr, contenttype);
        }
        remaining -= bytes;
        ptr += bytes;
    }

    if (plugin && plugin->parser)
    {
        /* iterate through source http headers and send to client */
        avl_tree_rlock (plugin->parser->vars);
        node = avl_get_first (plugin->parser->vars);
        while (node)
        {
            int next = 1;
            http_var_t *var = (http_var_t *)node->key;
            bytes = 0;
            if (!strcasecmp (var->name, "ice-audio-info"))
            {
                /* convert ice-audio-info to icy-br */
                char *brfield = NULL;
                unsigned int bitrate;

                if (bitrate_filtered == 0)
                    brfield = strstr (var->value, "bitrate=");
                if (brfield && sscanf (brfield, "bitrate=%u", &bitrate))
                {
                    bytes = snprintf (ptr, remaining, "icy-br:%u\r\n", bitrate);
                    next = 0;
                    bitrate_filtered = 1;
                }
                else
                    /* show ice-audio_info header as well because of relays */
                    bytes = snprintf (ptr, remaining, "%s: %s\r\n", var->name, var->value);
            }
            else
            {
                if (strcasecmp (var->name, "ice-password") &&
                        strcasecmp (var->name, "icy-metaint"))
                {
                    if (!strncasecmp ("ice-", var->name, 4))
                    {
                        if (!strcasecmp ("ice-public", var->name))
                            bytes = snprintf (ptr, remaining, "icy-pub:%s\r\n", var->value);
                        else
                            if (!strcasecmp ("ice-bitrate", var->name))
                                bytes = snprintf (ptr, remaining, "icy-br:%s\r\n", var->value);
                            else
                                bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
                                        var->name + 3, var->value);
                    }
                    else 
                        if (!strncasecmp ("icy-", var->name, 4))
                        {
                            bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
                                    var->name + 3, var->value);
                        }
                }
            }

            remaining -= bytes;
            ptr += bytes;
            if (next)
                node = avl_get_next (node);
        }
        avl_tree_unlock (plugin->parser->vars);
    }

    config = config_get_config();
    bytes = snprintf (ptr, remaining, "Server: %s\r\n", config->server_id);
    config_release_config();
    remaining -= bytes;
    ptr += bytes;

    /* prevent proxy servers from caching */
    bytes = snprintf (ptr, remaining, "Cache-Control: no-cache\r\nPragma: no-cache\r\n"
            "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n");
    remaining -= bytes;
    ptr += bytes;

    bytes = snprintf (ptr, remaining, "\r\n");
    remaining -= bytes;
    ptr += bytes;

    client->refbuf->len = 4096 - remaining;
    client->refbuf->flags |= WRITE_BLOCK_GENERIC;
    return 0;
}
Exemple #12
0
int admin_handle_request (client_t *client, const char *uri)
{
    const char *mount = httpp_get_query_param(client->parser, "mount");

    if (strcmp (uri, "/admin.cgi") == 0)
    {
        const char *pass = httpp_get_query_param (client->parser, "pass");
        if (pass == NULL)
            return client_send_400 (client, "missing pass parameter");
        uri++;
        if (mount == NULL)
        {
            if (client->server_conn && client->server_conn->shoutcast_mount)
                httpp_set_query_param (client->parser, "mount",
                        client->server_conn->shoutcast_mount);
            mount = httpp_get_query_param (client->parser, "mount");
        }
        httpp_setvar (client->parser, HTTPP_VAR_PROTOCOL, "ICY");
        httpp_setvar (client->parser, HTTPP_VAR_ICYPASSWORD, pass);
        client->username = strdup ("source");
        client->password = strdup (pass);
    }
    else
        uri += 7;

    if (connection_check_admin_pass (client->parser))
        client->flags |= CLIENT_AUTHENTICATED;
    else
    {
        /* special case for slaves requesting a streamlist for authenticated relaying */
        if (strcmp (uri, "streams") == 0 || strcmp (uri, "streamlist.txt") == 0)
        {
            if (connection_check_relay_pass (client->parser))
                client->flags |= CLIENT_AUTHENTICATED;
        }
    }

    if (mount)
    {
        /* no auth/stream required for this */
        if (strcmp (uri, "buildm3u") == 0)
            return command_buildm3u (client, mount);
        if (strcmp (uri, "showimage") == 0)
            return command_show_image (client, mount);

        /* This is a mount request, but admin user is allowed */
        if ((client->flags & CLIENT_AUTHENTICATED) == 0)
        {
            switch (auth_check_source (client, mount))
            {
                case 0:
                    break;
                default:
                    INFO1("Bad or missing password on mount modification "
                            "admin request (%s)", uri);
                    return client_send_401 (client, NULL);
                    /* fall through */
                case 1:
                    return 0;
            }
        }
        if (strcmp (uri, "streams") == 0)
            return auth_add_listener ("/admin/streams", client);
        return admin_mount_request (client, uri);
    }

    return admin_handle_general_request (client, uri);
}
Exemple #13
0
static void *source_fallback_file (void *arg)
{
    char *mount = arg;
    char *type;
    char *path;
    unsigned int len;
    FILE *file = NULL;
    source_t *source = NULL;
    ice_config_t *config;
    http_parser_t *parser;

    do
    {
        if (mount == NULL || mount[0] != '/')
            break;
        config = config_get_config();
        len  = strlen (config->webroot_dir) + strlen (mount) + 1;
        path = malloc (len);
        if (path)
            snprintf (path, len, "%s%s", config->webroot_dir, mount);
        
        config_release_config ();
        if (path == NULL)
            break;

        file = fopen (path, "rb");
        if (file == NULL)
        {
            WARN1 ("unable to open file \"%s\"", path);
            free (path);
            break;
        }
        free (path);
        source = source_reserve (mount);
        if (source == NULL)
        {
            WARN1 ("mountpoint \"%s\" already reserved", mount);
            break;
        }
        INFO1 ("mountpoint %s is reserved", mount);
        type = fserve_content_type (mount);
        parser = httpp_create_parser();
        httpp_initialize (parser, NULL);
        httpp_setvar (parser, "content-type", type);
        free (type);

        source->hidden = 1;
        source->yp_public = 0;
        source->intro_file = file;
        source->parser = parser;
        file = NULL;

        if (connection_complete_source (source, 0) < 0)
            break;
        source_client_thread (source);
        httpp_destroy (parser);
    } while (0);
    if (file)
        fclose (file);
    free (mount);
    return NULL;
}
static int command_metadata (client_t *client, source_t *source, int response)
{
    const char *song, *title, *artist, *artwork, *charset, *url;
    format_plugin_t *plugin;
    xmlDocPtr doc;
    xmlNodePtr node;
    int same_ip = 1;

    doc = xmlNewDoc(XMLSTR("1.0"));
    node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
    xmlDocSetRootElement(doc, node);

    DEBUG0("Got metadata update request");

    COMMAND_OPTIONAL(client, "song", song);
    COMMAND_OPTIONAL(client, "title", title);
    COMMAND_OPTIONAL(client, "artist", artist);
    COMMAND_OPTIONAL(client, "url", url);
    COMMAND_OPTIONAL(client, "artwork", artwork);
    COMMAND_OPTIONAL(client, "charset", charset);

    plugin = source->format;
    if (source_running (source))
        if (strcmp (client->connection.ip, source->client->connection.ip) != 0)
            if (response == RAW && connection_check_admin_pass (client->parser) == 0)
                same_ip = 0;

	/* Update stream metadata if needed */
	if (same_ip) {
		static const struct {
			const char		*param;
			const char		*stat_name;
			const char		*hdr[3];
		} fwd[] = {
			{"xstreamname",			"server_name", 			{"ice-name",		"icy-name",			"x-audiocast-name"}},
			{"xstreamdesc",			"server_description",	{"ice-description",	"icy-description",	"x-audiocast-description"}},
			{"xstreamurl",			"server_url",			{"ice-url",			"icy-url",			"x-audiocast-url"}},
			{"xstreamgenre",		"genre",				{"ice-genre",		"icy-genre",		"x-audiocast-genre"}}
		};
		unsigned i;
		for (i = 0; i < sizeof(fwd) / sizeof(*fwd); i++) {
			const char *value;
			unsigned j;
			COMMAND_OPTIONAL(client, fwd[i].param, value);
			if (value && *value) {
				value = auto_recode(value);
				if (source->format->charset)
					stats_set_conv (source->stats, fwd[i].stat_name, value, source->format->charset);
				else
					stats_set (source->stats, fwd[i].stat_name, value);
			} else if (value) {
				stats_set (source->stats, fwd[i].stat_name, NULL);
			}
			for (j = 0; j < 3; j++) {
				if (j == 0 && value && *value) {
					httpp_setvar(source->format->parser, fwd[i].hdr[j], value);
				} else if (value && !*value) {
					httpp_deletevar(source->format->parser, fwd[i].hdr[j]);
				}
			}
		}

	}

    do
    {
        if (same_ip == 0 || plugin == NULL)
            break;
		/* Charset detection (if none specified) */
		if (!charset) {
			const char *r;
			int len;
			charset = "UTF8";
#define CCONV(s) \
			if (s && (r = auto_recode(s))) { \
				len = strlen(r); \
				s = alloca(len + 1); \
				memcpy((char*)s, r, len + 1); \
			}
			CCONV(title);
			CCONV(song);
			CCONV(artist);
		}
		/* Now send prepared metadata */
        if (artwork)
            stats_event (source->mount, "artwork", artwork);
        if (plugin->set_tag)
        {
            if (url)
            {
                plugin->set_tag (plugin, "url", url, charset);
                INFO2 ("Metadata url on %s set to \"%s\"", source->mount, url);
            }
            if (song)
            {
                plugin->set_tag (plugin, "artist", NULL, NULL);
                plugin->set_tag (plugin, "title", song, charset);
                INFO2("Metadata song on %s set to \"%s\"", source->mount, song);
            }
            if (artist)
            {
                plugin->set_tag (plugin, "artist", artist, charset);
                INFO2 ("Metadata artist on %s changed to \"%s\"", source->mount, artist);
            }
            if (title)
            {
                plugin->set_tag (plugin, "title", title, charset);
                INFO2 ("Metadata title on %s changed to \"%s\"", source->mount, title);
            }
            /* updates are now done, let them be pushed into the stream */
            plugin->set_tag (plugin, NULL, NULL, NULL);
        }
        else
        {
            break;
        }
        thread_mutex_unlock (&source->lock);
        xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR("Metadata update successful"));
        xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
        return admin_send_response(doc, client, response, "response.xsl");

    } while (0);
    thread_mutex_unlock (&source->lock);
    xmlNewChild(node, NULL, XMLSTR("message"), 
            XMLSTR("Mountpoint will not accept this URL update"));
    xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
    return admin_send_response(doc, client, response, "response.xsl");
}