static int command_list_log (client_t *client, int response) { refbuf_t *content; const char *logname = httpp_get_query_param (client->parser, "log"); int log = -1; ice_config_t *config; if (logname == NULL) return client_send_400 (client, "No log specified"); config = config_get_config (); if (strcmp (logname, "errorlog") == 0) log = config->error_log.logid; else if (strcmp (logname, "accesslog") == 0) log = config->access_log.logid; else if (strcmp (logname, "playlistlog") == 0) log = config->playlist_log.logid; if (log < 0) { config_release_config(); WARN1 ("request to show unknown log \"%s\"", logname); return client_send_400 (client, "unknown"); } content = refbuf_new (0); log_contents (log, &content->data, &content->len); config_release_config(); if (response == XSLT) { xmlNodePtr xmlnode; xmlDocPtr doc; doc = xmlNewDoc(XMLSTR("1.0")); xmlnode = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL); xmlDocSetRootElement(doc, xmlnode); xmlNewTextChild (xmlnode, NULL, XMLSTR("log"), XMLSTR(content->data)); refbuf_release (content); return admin_send_response (doc, client, XSLT, "showlog.xsl"); } else { refbuf_t *http = refbuf_new (100); int len = snprintf (http->data, 100, "%s", "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n"); http->len = len; http->next = content; client->respcode = 200; client_set_queue (client, http); return fserve_setup_client (client); } }
refbuf_t *refbuf_copy(refbuf_t *orig) { refbuf_t *ret = refbuf_new (orig->len), *ref = ret; memcpy (ref->data, orig->data, orig->len); orig = orig->associated; while (orig) { ref->associated = refbuf_new (orig->len); ref = ref->associated; memcpy (ref->data, orig->data, orig->len); orig = orig->associated; } return ret; }
int command_list_mounts(client_t *client, int response) { DEBUG0("List mounts request"); client_set_queue (client, NULL); client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); if (response == TEXT) { redirector_update (client); snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"); client->refbuf->len = strlen (client->refbuf->data); client->respcode = 200; if (strcmp (httpp_getvar (client->parser, HTTPP_VAR_URI), "/admin/streams") == 0) client->refbuf->next = stats_get_streams (1); else client->refbuf->next = stats_get_streams (0); return fserve_setup_client (client); } else { xmlDocPtr doc; avl_tree_rlock (global.source_tree); doc = admin_build_sourcelist(NULL); avl_tree_unlock (global.source_tree); return admin_send_response (doc, client, response, "listmounts.xsl"); } }
static int ebml_create_client_data (format_plugin_t *format, client_t *client) { ebml_client_data_t *ebml_client_data = calloc(1, sizeof(ebml_client_data_t)); ebml_source_state_t *ebml_source_state = format->_state; int ret = 0; if ((ebml_client_data) && (ebml_source_state->header)) { ebml_client_data->header = ebml_source_state->header; refbuf_addref (ebml_client_data->header); // broken, assumes too much currently } client->format_data = ebml_client_data; client->free_client_data = ebml_free_client_data; if (client->refbuf == NULL) client->refbuf = refbuf_new (4096); client->refbuf->len = 0; if (format_general_headers (format, client) < 0) return -1; return ret; }
static void _add_stats_to_stats_client (client_t *client, const char *fmt, va_list ap) { event_listener_t *listener = client->shared_data; refbuf_t *r = listener->recent_block; if (r && (r->flags & STATS_BLOCK_CONNECTION) == 0) { /* lets see if we can append to an existing block */ if (r->len < 1390) { int written = _append_to_bufferv (r, 1400, fmt, ap); if (written > 0) { listener->content_len += written; return; } } } r = refbuf_new (1400); r->len = 0; if (_append_to_bufferv (r, 1400, fmt, ap) < 0) { WARN1 ("stat details are too large \"%s\"", fmt); refbuf_release (r); return; } _add_node_to_stats_client (client, r); client->schedule_ms = 0; }
int client_send_404 (client_t *client, const char *message) { int ret = -1; if (client->worker == NULL) /* client is not on any worker now */ { client_destroy (client); return 0; } client_set_queue (client, NULL); if (client->respcode) { worker_t *worker = client->worker; if (client->respcode >= 300) client->flags = client->flags & ~CLIENT_AUTHENTICATED; client->flags |= CLIENT_ACTIVE; worker_wakeup (worker); } else { if (client->parser->req_type == httpp_req_head || message == NULL) message = "Not Available"; ret = strlen (message); client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 404 Not Available\r\n" "%s\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n" "%s", client_keepalive_header (client), ret, message ? message: ""); client->respcode = 404; client->refbuf->len = strlen (client->refbuf->data); ret = fserve_setup_client (client); } return ret; }
int client_send_404 (client_t *client, const char *message) { int ret = -1; if (client->worker == NULL) /* client is not on any worker now */ { client_destroy (client); return 0; } client_set_queue (client, NULL); if (client->respcode) { worker_t *worker = client->worker; if (client->respcode >= 300) client->flags = client->flags & ~CLIENT_AUTHENTICATED; client->flags |= CLIENT_ACTIVE; worker_wakeup (worker); } else { if (message == NULL) message = "Not Available"; client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 404 Not Available\r\n" "Content-Type: text/html\r\n\r\n" "<b>%s</b>\r\n", message); client->respcode = 404; client->refbuf->len = strlen (client->refbuf->data); ret = fserve_setup_client (client); } return ret; }
/* create a client_t with the provided connection and parser details. Return * 0 on success, -1 if server limit has been reached. In either case a * client_t is returned just in case a message needs to be returned. Should * be called with global lock held. */ int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser) { ice_config_t *config; client_t *client = (client_t *)calloc(1, sizeof(client_t)); int ret = -1; if (client == NULL) abort(); config = config_get_config (); global.clients++; if (config->client_limit < global.clients) WARN2 ("server client limit reached (%d/%d)", config->client_limit, global.clients); else ret = 0; config_release_config (); stats_event_args (NULL, "clients", "%d", global.clients); client->con = con; client->parser = parser; client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); client->refbuf->len = 0; /* force reader code to ignore buffer contents */ client->pos = 0; client->write_to_client = format_generic_write_to_client; *c_ptr = client; return ret; }
static int xslt_write_callback (void *ctxt, const char *data, int len) { struct bufs *x = ctxt; refbuf_t *r; int loop = 10; if (len == 0) return 0; if (len < 0 || len > 2000000) { ERROR1 ("%d length requested", len); return -1; } while (loop) { r = *x->tail; if (r) { x->tail = &r->next; loop--; continue; } *x->tail = r = refbuf_new (len); memcpy (r->data, data, len); x->len += len; break; } return len; }
static int xslt_write_callback (void *ctxt, const char *data, int len) { struct bufs *x = ctxt; refbuf_t *r; int loop = 10; if (len == 0) return 0; if (len < 0 || len > 2000000) { ERROR1 ("%d length requested", len); return -1; } while (loop) { int size = len > 4096 ? len : 4096; if (*x->tail == NULL) { *x->tail = refbuf_new (size); (*x->tail)->len = 0; } r = *x->tail; if (r->len + len > size) { x->tail = &r->next; loop--; continue; } memcpy (r->data + r->len, data, len); r->len += len; x->len += len; break; } return len; }
refbuf_t *make_refbuf_with_page (ogg_page *page) { refbuf_t *refbuf = refbuf_new (page->header_len + page->body_len); memcpy (refbuf->data, page->header, page->header_len); memcpy (refbuf->data+page->header_len, page->body, page->body_len); return refbuf; }
int format_file_read (client_t *client, format_plugin_t *plugin, FILE *fp) { refbuf_t *refbuf = client->refbuf; size_t bytes = -1; int unprocessed = 0; do { if (refbuf == NULL) { if (fp == NULL) return -2; refbuf = client->refbuf = refbuf_new (4096); client->pos = refbuf->len; client->intro_offset = 0; client->queue_pos = 0; } if (client->pos < refbuf->len) break; if (fp == NULL || client->flags & CLIENT_HAS_INTRO_CONTENT) { if (refbuf->next) { //DEBUG1 ("next intro block is %d", refbuf->next->len); client->refbuf = refbuf->next; refbuf->next = NULL; refbuf_release (refbuf); client->pos = 0; return 0; } //DEBUG0 ("No more intro data "); client_set_queue (client, NULL); client->flags &= ~CLIENT_HAS_INTRO_CONTENT; client->intro_offset = client->connection.sent_bytes; refbuf = NULL; continue; } if (fseek (fp, client->intro_offset, SEEK_SET) < 0 || (bytes = fread (refbuf->data, 1, 4096, fp)) <= 0) { return bytes < 0 ? -2 : -1; } refbuf->len = bytes; client->pos = 0; if (plugin->align_buffer) { /* here the buffer may require truncating to keep the buffers aligned on * certain boundaries */ unprocessed = plugin->align_buffer (client, plugin); if (unprocessed < 0 || unprocessed >= bytes) unprocessed = 0; } client->intro_offset += (bytes - unprocessed); } while (1); return 0; }
static void _handle_source_request (client_t *client, char *uri, int auth_style) { source_t *source; INFO1("Source logging in at mountpoint \"%s\"", uri); if (uri[0] != '/') { WARN0 ("source mountpoint not starting with /"); client_send_401 (client); return; } if (auth_style == ICECAST_SOURCE_AUTH) { if (connection_check_source_pass (client->parser, uri) == 0) { /* We commonly get this if the source client is using the wrong * protocol: attempt to diagnose this and return an error */ /* TODO: Do what the above comment says */ INFO1("Source (%s) attempted to login with invalid or missing password", uri); client_send_401(client); return; } } source = source_reserve (uri); if (source) { if (auth_style == SHOUTCAST_SOURCE_AUTH) { source->shoutcast_compat = 1; } source->client = client; source->parser = client->parser; source->con = client->con; if (connection_complete_source (source, 1) < 0) { source_clear_source (source); source_free_source (source); } else { refbuf_t *ok = refbuf_new (PER_CLIENT_REFBUF_SIZE); client->respcode = 200; snprintf (ok->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 200 OK\r\n\r\n"); ok->len = strlen (ok->data); /* we may have unprocessed data read in, so don't overwrite it */ ok->associated = client->refbuf; client->refbuf = ok; fserve_add_client_callback (client, source_client_callback, source); } } else { client_send_404 (client, "Mountpoint in use"); WARN1 ("Mountpoint %s in use", uri); } }
/* return a list of blocks which contain lines of text. Each line is a mountpoint * reference that a slave will use for relaying. The prepend setting is to indicate * if some something else needs to be added to each line. */ refbuf_t *stats_get_streams (int prepend) { #define STREAMLIST_BLKSIZE 4096 avl_node *node; unsigned int remaining = STREAMLIST_BLKSIZE, prelen; refbuf_t *start = refbuf_new (remaining), *cur = start; const char *pre = ""; char *buffer = cur->data; if (prepend) pre = "/admin/streams?mount="; prelen = strlen (pre); /* now the stats for each source */ avl_tree_rlock (_stats.source_tree); node = avl_get_first(_stats.source_tree); while (node) { int ret; stats_source_t *source = (stats_source_t *)node->key; if ((source->flags & STATS_HIDDEN) == 0) { if (remaining <= strlen (source->source) + prelen + 3) { cur->len = STREAMLIST_BLKSIZE - remaining; cur->next = refbuf_new (STREAMLIST_BLKSIZE); remaining = STREAMLIST_BLKSIZE; cur = cur->next; buffer = cur->data; } ret = snprintf (buffer, remaining, "%s%s\r\n", pre, source->source); if (ret > 0) { buffer += ret; remaining -= ret; } } node = avl_get_next(node); } avl_tree_unlock (_stats.source_tree); cur->len = STREAMLIST_BLKSIZE - remaining; return start; }
int client_send_501(client_t *client) { client_set_queue (client, NULL); client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 501 Not Implemented\r\n\r\n"); client->respcode = 501; client->refbuf->len = strlen (client->refbuf->data); return fserve_setup_client (client); }
int client_send_416(client_t *client) { client_set_queue (client, NULL); client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n"); client->respcode = 416; client->refbuf->len = strlen (client->refbuf->data); return fserve_setup_client (client); }
int format_file_read (client_t *client, format_plugin_t *plugin, icefile_handle f) { refbuf_t *refbuf = client->refbuf; ssize_t bytes = -1; int unprocessed = 0; do { if (refbuf == NULL) { if (file_in_use (f) == 0) return -2; refbuf = client->refbuf = refbuf_new (8192); client->flags |= CLIENT_HAS_INTRO_CONTENT; client->pos = refbuf->len; client->queue_pos = 0; } if (client->pos < refbuf->len) break; if (refbuf->next) { //DEBUG1 ("next intro block is %d", refbuf->next->len); client->refbuf = refbuf->next; refbuf->next = NULL; refbuf_release (refbuf); client->pos = 0; return 0; } if (file_in_use (f) == 0) return -2; bytes = pread (f, refbuf->data, 8192, client->intro_offset); if (bytes <= 0) return bytes < 0 ? -2 : -1; refbuf->len = bytes; client->pos = 0; if (plugin && plugin->align_buffer) { /* here the buffer may require truncating to keep the buffers aligned on * certain boundaries */ unprocessed = plugin->align_buffer (client, plugin); if (unprocessed == bytes) return -1; if (unprocessed < 0 || unprocessed > bytes) { unprocessed = 0; client->connection.error = 1; } } client->intro_offset += (bytes - unprocessed); } while (1); return refbuf->len - client->pos; }
static refbuf_t *ebml_get_buffer (source_t *source) { ebml_source_state_t *ebml_source_state = source->format->_state; format_plugin_t *format = source->format; char *data = NULL; int bytes = 0; refbuf_t *refbuf; int ret; while (1) { if ((bytes = ebml_read_space(ebml_source_state->ebml)) > 0) { refbuf = refbuf_new(bytes); ebml_read(ebml_source_state->ebml, refbuf->data, bytes); if (ebml_source_state->header == NULL) { ebml_source_state->header = refbuf; continue; } if (ebml_last_was_sync(ebml_source_state->ebml)) { refbuf->flags |= SOURCE_BLOCK_SYNC; } if (refbuf->len > 0) { source->client->queue_pos += refbuf->len; } return refbuf; } else { data = ebml_write_buffer(ebml_source_state->ebml, EBML_SLICE_SIZE); bytes = client_read_bytes (source->client, data, EBML_SLICE_SIZE); if (bytes <= 0) { ebml_wrote (ebml_source_state->ebml, 0); return NULL; } format->read_bytes += bytes; ret = ebml_wrote (ebml_source_state->ebml, bytes); if (ret != bytes) { ERROR0 ("Problem processing stream"); source->flags &= ~SOURCE_RUNNING; return NULL; } } } }
static size_t handle_returned_data (void *ptr, size_t size, size_t nmemb, void *stream) { auth_client *auth_user = stream; unsigned bytes = size * nmemb; client_t *client = auth_user->client; refbuf_t *r = client->refbuf; if (client && client->respcode == 0 && r && client->flags & CLIENT_HAS_INTRO_CONTENT) { refbuf_t *n; struct build_intro_contents *x = (void*)r->data; n = refbuf_new (bytes); memcpy (n->data, ptr, bytes); if (x->type) { int unprocessed = mpeg_complete_frames (&x->sync, n, 0); if (unprocessed < 0) { mpeg_data_insert (&x->sync, n); /* maybe short read, less than frame */ return (int)(bytes); } if (unprocessed > 0) { refbuf_t *next = refbuf_new (unprocessed); memcpy (next->data, n->data + n->len, unprocessed); next->len = unprocessed; mpeg_data_insert (&x->sync, next); } } if (n->len == 0) refbuf_release (n); else { *x->tailp = n; x->tailp = &n->next; x->intro_len += n->len; } } return (int)(bytes); }
int client_send_400(client_t *client, const char *message) { client_set_queue (client, NULL); client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 400 Bad Request\r\n" "Content-Type: text/html\r\n\r\n" "<b>%s</b>\r\n", message?message:""); client->respcode = 400; client->refbuf->len = strlen (client->refbuf->data); return fserve_setup_client (client); }
refbuf_t *make_refbuf_with_page (ogg_codec_t *codec, ogg_page *page) { refbuf_t *refbuf; if (codec && codec->filtered) return NULL; refbuf = refbuf_new (page->header_len + page->body_len); memcpy (refbuf->data, page->header, page->header_len); memcpy (refbuf->data+page->header_len, page->body, page->body_len); return refbuf; }
int client_send_302(client_t *client, const char *location) { client_set_queue (client, NULL); client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 302 Temporarily Moved\r\n" "Content-Type: text/html\r\n" "Location: %s\r\n\r\n" "Moved <a href=\"%s\">here</a>\r\n", location, location); client->respcode = 302; client->refbuf->len = strlen (client->refbuf->data); return fserve_setup_client (client); }
int client_send_options(client_t *client) { client_set_queue (client, NULL); client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.1 200 OK\r\n" "Access-Control-Allow-Origin: *\r\n" "Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type\r\n" "Access-Control-Allow-Methods: GET, OPTIONS, STATS\r\n\r\n"); client->respcode = 200; client->refbuf->len = strlen (client->refbuf->data); return fserve_setup_client (client); }
int client_send_403(client_t *client, const char *reason) { if (reason == NULL) reason = "Forbidden"; client_set_queue (client, NULL); client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 403 %s\r\n" "Content-Type: text/html\r\n\r\n", reason); client->respcode = 403; client->refbuf->len = strlen (client->refbuf->data); return fserve_setup_client (client); }
refbuf_t *stats_get_streams (void) { #define STREAMLIST_BLKSIZE 4096 avl_node *node; unsigned int remaining = STREAMLIST_BLKSIZE; refbuf_t *start = refbuf_new (remaining), *cur = start; char *buffer = cur->data; /* now the stats for each source */ thread_mutex_lock (&_stats_mutex); node = avl_get_first(_stats.source_tree); while (node) { int ret; stats_source_t *source = (stats_source_t *)node->key; if (source->hidden == 0) { if (remaining <= strlen (source->source) + 3) { cur->len = STREAMLIST_BLKSIZE - remaining; cur->next = refbuf_new (STREAMLIST_BLKSIZE); remaining = STREAMLIST_BLKSIZE; cur = cur->next; buffer = cur->data; } ret = snprintf (buffer, remaining, "%s\r\n", source->source); if (ret > 0) { buffer += ret; remaining -= ret; } } node = avl_get_next(node); } thread_mutex_unlock(&_stats_mutex); cur->len = STREAMLIST_BLKSIZE - remaining; return start; }
static refbuf_t *ebml_get_buffer(source_t *source) { ebml_source_state_t *ebml_source_state = source->format->_state; format_plugin_t *format = source->format; char *data = NULL; int bytes = 0; refbuf_t *refbuf; int ret; while (1) { if ((bytes = ebml_read_space(ebml_source_state->ebml)) > 0) { refbuf = refbuf_new(bytes); ebml_read(ebml_source_state->ebml, refbuf->data, bytes); if (ebml_source_state->header == NULL) { ebml_source_state->header = refbuf; continue; } if (ebml_last_was_sync(ebml_source_state->ebml)) { refbuf->sync_point = 1; } return refbuf; } else { data = ebml_write_buffer(ebml_source_state->ebml, EBML_SLICE_SIZE); bytes = client_read_bytes (source->client, data, EBML_SLICE_SIZE); if (bytes <= 0) { ebml_wrote (ebml_source_state->ebml, 0); return NULL; } format->read_bytes += bytes; ret = ebml_wrote (ebml_source_state->ebml, bytes); if (ret != bytes) { ICECAST_LOG_ERROR("Problem processing stream"); source->running = 0; return NULL; } } } }
/* called from the source thread when the metadata has been updated. * The artist title are checked and made ready for clients to send */ static void mp3_set_title (source_t *source) { const char meta[] = "StreamTitle='"; int size; unsigned char len_byte; refbuf_t *p; unsigned int len = sizeof(meta) + 2; /* the StreamTitle, quotes, ; and null */ mp3_state *source_mp3 = source->format->_state; /* make sure the url data does not disappear from under us */ thread_mutex_lock (&source_mp3->url_lock); /* work out message length */ if (source_mp3->url_artist) len += strlen (source_mp3->url_artist); if (source_mp3->url_title) len += strlen (source_mp3->url_title); if (source_mp3->url_artist && source_mp3->url_title) len += 3; #define MAX_META_LEN 255*16 if (len > MAX_META_LEN) { thread_mutex_unlock (&source_mp3->url_lock); WARN1 ("Metadata too long at %d chars", len); return; } /* work out the metadata len byte */ len_byte = (len-1) / 16 + 1; /* now we know how much space to allocate, +1 for the len byte */ size = len_byte * 16 + 1; p = refbuf_new (size); if (p) { mp3_state *source_mp3 = source->format->_state; memset (p->data, '\0', size); if (source_mp3->url_artist && source_mp3->url_title) snprintf (p->data, size, "%c%s%s - %s';", len_byte, meta, source_mp3->url_artist, source_mp3->url_title); else snprintf (p->data, size, "%c%s%s';", len_byte, meta, source_mp3->url_title); filter_shoutcast_metadata (source, p->data, size); refbuf_release (source_mp3->metadata); source_mp3->metadata = p; } thread_mutex_unlock (&source_mp3->url_lock); }
int format_mp3_get_plugin (source_t *source) { const char *metadata; format_plugin_t *plugin; mp3_state *state = calloc(1, sizeof(mp3_state)); refbuf_t *meta; plugin = (format_plugin_t *)calloc(1, sizeof(format_plugin_t)); plugin->type = FORMAT_TYPE_GENERIC; plugin->get_buffer = mp3_get_no_meta; plugin->write_buf_to_client = format_mp3_write_buf_to_client; plugin->write_buf_to_file = write_mp3_to_file; plugin->create_client_data = format_mp3_create_client_data; plugin->free_plugin = format_mp3_free_plugin; plugin->set_tag = mp3_set_tag; plugin->apply_settings = format_mp3_apply_settings; plugin->contenttype = httpp_getvar (source->parser, "content-type"); if (plugin->contenttype == NULL) { /* We default to MP3 audio for old clients without content types */ plugin->contenttype = "audio/mpeg"; } plugin->_state = state; /* initial metadata needs to be blank for sending to clients and for comparing with new metadata */ meta = refbuf_new (17); memcpy (meta->data, "\001StreamTitle='';", 17); state->metadata = meta; state->interval = -1; metadata = httpp_getvar (source->parser, "icy-metaint"); if (metadata) { state->inline_metadata_interval = atoi (metadata); if (state->inline_metadata_interval > 0) { state->offset = 0; plugin->get_buffer = mp3_get_filter_meta; state->interval = state->inline_metadata_interval; } } source->format = plugin; thread_mutex_create (&state->url_lock); return 0; }
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client) { xmlDocPtr res; xsltStylesheetPtr cur; xmlChar *string; int len, problem = 0; xmlSetGenericErrorFunc ("", log_parse_failure); xsltSetGenericErrorFunc ("", log_parse_failure); thread_mutex_lock(&xsltlock); cur = xslt_get_stylesheet(xslfilename); if (cur == NULL) { thread_mutex_unlock(&xsltlock); ERROR1 ("problem reading stylesheet \"%s\"", xslfilename); client_send_404 (client, "Could not parse XSLT file"); return; } res = xsltApplyStylesheet(cur, doc, NULL); if (xsltSaveResultToString (&string, &len, res, cur) < 0) problem = 1; thread_mutex_unlock(&xsltlock); if (problem == 0) { const char *http = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: "; int buf_len = strlen (http) + 20 + len; if (string == NULL) string = xmlStrdup (""); client->respcode = 200; client_set_queue (client, NULL); client->refbuf = refbuf_new (buf_len); len = snprintf (client->refbuf->data, buf_len, "%s%d\r\n\r\n%s", http, len, string); client->refbuf->len = len; fserve_add_client (client, NULL); xmlFree (string); } else { WARN1 ("problem applying stylesheet \"%s\"", xslfilename); client_send_404 (client, "XSLT problem"); } xmlFreeDoc(res); }
refbuf_t *refbuf_realloc (refbuf_t *refbuf, size_t newsize) { char *newdata; dprintf("reallocing to %d\n", newsize); if (!refbuf) return refbuf_new (newsize); newdata = realloc(refbuf->data, newsize); if (!newdata) return NULL; refbuf->len = newsize; refbuf->data = newdata; return refbuf; }