/* 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); }
int move_listener (client_t *client, struct _fbinfo *finfo) { source_t *source; mount_proxy *minfo; int rate = finfo->limit, loop = 20, ret = -1; ice_config_t *config = config_get_config(); struct _fbinfo where; unsigned int len = 4096; char buffer [len]; memcpy (&where, finfo, sizeof (where)); if (finfo->fallback) where.fallback = strdup (finfo->fallback); avl_tree_rlock (global.source_tree); do { len = sizeof buffer; util_expand_pattern (where.fallback, where.mount, buffer, &len); where.mount = buffer; minfo = config_find_mount (config, where.mount); if (rate == 0 && minfo && minfo->limit_rate) rate = minfo->limit_rate; source = source_find_mount_raw (where.mount); if (source == NULL && minfo == NULL) break; if (source) { thread_rwlock_wlock (&source->lock); if (source_available (source)) { // an unused on-demand relay will still have an unitialised type if (source->format->type == finfo->type || source->format->type == FORMAT_TYPE_UNDEFINED) { config_release_config(); avl_tree_unlock (global.source_tree); source_setup_listener (source, client); source->listeners++; client->flags |= CLIENT_HAS_MOVED; thread_rwlock_unlock (&source->lock); free (where.fallback); return 0; } } thread_rwlock_unlock (&source->lock); } if (minfo && minfo->fallback_mount) { free (where.fallback); where.fallback = strdup (where.mount); where.mount = minfo->fallback_mount; } else break; } while (loop--); avl_tree_unlock (global.source_tree); config_release_config(); if (where.mount && ((client->flags & CLIENT_IS_SLAVE) == 0)) { if (where.limit == 0) { if (rate == 0) if (sscanf (where.mount, "%*[^[][%d]", &rate) == 1) rate = rate * 1000/8; where.limit = rate; } client->intro_offset = 0; ret = fserve_setup_client_fb (client, &where); } free (where.fallback); return ret; }
int fserve_setup_client (client_t *client) { client->check_buffer = format_generic_write_to_client; return fserve_setup_client_fb (client, NULL); }
static int http_client_request (client_t *client) { refbuf_t *refbuf = client->shared_data; int remaining = PER_CLIENT_REFBUF_SIZE - 1 - refbuf->len, ret = -1; if (remaining && client->connection.discon_time > client->worker->current_time.tv_sec) { char *buf = refbuf->data + refbuf->len; ret = client_read_bytes (client, buf, remaining); if (ret > 0) { char *ptr; buf [ret] = '\0'; refbuf->len += ret; if (memcmp (refbuf->data, "<policy-file-request/>", 23) == 0) { fbinfo fb; memset (&fb, 0, sizeof(fb)); fb.mount = "/flashpolicy"; fb.flags = FS_USE_ADMIN; fb.type = FORMAT_TYPE_UNDEFINED; client->respcode = 200; refbuf_release (refbuf); client->shared_data = NULL; client->check_buffer = format_generic_write_to_client; return fserve_setup_client_fb (client, &fb); } /* find a blank line */ do { buf = refbuf->data; ptr = strstr (buf, "\r\n\r\n"); if (ptr) { ptr += 4; break; } ptr = strstr (buf, "\n\n"); if (ptr) { ptr += 2; break; } ptr = strstr (buf, "\r\r\n\r\r\n"); if (ptr) { ptr += 6; break; } client->schedule_ms = client->worker->time_ms + 100; return 0; } while (0); client->refbuf = client->shared_data; client->shared_data = NULL; client->connection.discon_time = 0; client->parser = httpp_create_parser(); httpp_initialize (client->parser, NULL); if (httpp_parse (client->parser, refbuf->data, refbuf->len)) { if (useragents.filename) { const char *agent = httpp_getvar (client->parser, "user-agent"); if (agent && search_cached_pattern (&useragents, agent) > 0) { INFO2 ("dropping client at %s because useragent is %s", client->connection.ip, agent); return -1; } } /* headers now parsed, make sure any sent content is next */ if (strcmp("ICE", httpp_getvar (client->parser, HTTPP_VAR_PROTOCOL)) && strcmp("HTTP", httpp_getvar (client->parser, HTTPP_VAR_PROTOCOL))) { ERROR0("Bad HTTP protocol detected"); return -1; } auth_check_http (client); switch (client->parser->req_type) { case httpp_req_get: refbuf->len = PER_CLIENT_REFBUF_SIZE; client->ops = &http_req_get_ops; break; case httpp_req_source: client->pos = ptr - refbuf->data; client->ops = &http_req_source_ops; break; case httpp_req_stats: refbuf->len = PER_CLIENT_REFBUF_SIZE; client->ops = &http_req_stats_ops; break; case httpp_req_options: return client_send_options (client); default: WARN1("unhandled request type from %s", client->connection.ip); return client_send_501 (client); } client->counter = 0; return client->ops->process(client); } /* invalid http request */ return -1; } if (ret && client->connection.error == 0) { /* scale up the retry time, very short initially, usual case */ uint64_t diff = client->worker->time_ms - client->counter; diff >>= 1; if (diff > 200) diff = 200; client->schedule_ms = client->worker->time_ms + 6 + diff; return 0; }