mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
Added support for <http-headers> within <mount>. Also support merging of headers (normal mount + default mount). See #1885
svn path=/icecast/trunk/icecast/; revision=19269
This commit is contained in:
parent
aa869033e2
commit
9597e2eadd
@ -279,7 +279,7 @@ void admin_send_response (xmlDocPtr doc, client_t *client,
|
|||||||
len = util_http_build_header(client->refbuf->data, buf_len, 0,
|
len = util_http_build_header(client->refbuf->data, buf_len, 0,
|
||||||
0, 200, NULL,
|
0, 200, NULL,
|
||||||
"text/xml", "utf-8",
|
"text/xml", "utf-8",
|
||||||
NULL);
|
NULL, NULL);
|
||||||
len += snprintf (client->refbuf->data + len, buf_len - len, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff);
|
len += snprintf (client->refbuf->data + len, buf_len - len, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff);
|
||||||
|
|
||||||
client->refbuf->len = len;
|
client->refbuf->len = len;
|
||||||
@ -573,7 +573,7 @@ static void html_success(client_t *client, char *message)
|
|||||||
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
|
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
|
||||||
0, 200, NULL,
|
0, 200, NULL,
|
||||||
"text/html", "utf-8",
|
"text/html", "utf-8",
|
||||||
"");
|
"", NULL);
|
||||||
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
|
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
|
||||||
"<html><head><title>Admin request successful</title></head>"
|
"<html><head><title>Admin request successful</title></head>"
|
||||||
"<body><p>%s</p></body></html>", message);
|
"<body><p>%s</p></body></html>", message);
|
||||||
@ -712,7 +712,7 @@ static void command_buildm3u(client_t *client, const char *mount)
|
|||||||
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
|
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
|
||||||
0, 200, NULL,
|
0, 200, NULL,
|
||||||
"audio/x-mpegurl", NULL,
|
"audio/x-mpegurl", NULL,
|
||||||
NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
config = config_get_config();
|
config = config_get_config();
|
||||||
snprintf (client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
|
snprintf (client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
|
||||||
@ -1032,7 +1032,7 @@ static void command_list_mounts(client_t *client, int response)
|
|||||||
util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
|
util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
|
||||||
0, 200, NULL,
|
0, 200, NULL,
|
||||||
"text/plain", "utf-8",
|
"text/plain", "utf-8",
|
||||||
"");
|
"", NULL);
|
||||||
client->refbuf->len = strlen (client->refbuf->data);
|
client->refbuf->len = strlen (client->refbuf->data);
|
||||||
client->respcode = 200;
|
client->respcode = 200;
|
||||||
|
|
||||||
|
@ -87,7 +87,8 @@ static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
|
|||||||
static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
|
static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
|
||||||
static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
|
static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
|
||||||
ice_config_t *c);
|
ice_config_t *c);
|
||||||
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
|
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node,
|
||||||
|
ice_config_http_header_t **http_headers);
|
||||||
static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
|
static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
|
||||||
static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
|
static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
|
||||||
static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
|
static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
|
||||||
@ -136,6 +137,45 @@ static void config_clear_http_header(ice_config_http_header_t *header) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ice_config_http_header_t * config_copy_http_header(ice_config_http_header_t *header) {
|
||||||
|
ice_config_http_header_t *ret = NULL;
|
||||||
|
ice_config_http_header_t *cur = NULL;
|
||||||
|
ice_config_http_header_t *old = NULL;
|
||||||
|
|
||||||
|
while (header) {
|
||||||
|
if (cur) {
|
||||||
|
cur->next = calloc(1, sizeof(ice_config_http_header_t));
|
||||||
|
old = cur;
|
||||||
|
cur = cur->next;
|
||||||
|
} else {
|
||||||
|
ret = calloc(1, sizeof(ice_config_http_header_t));
|
||||||
|
cur = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cur) return ret; /* TODO: do better error handling */
|
||||||
|
|
||||||
|
cur->type = header->type;
|
||||||
|
cur->name = (char *)xmlCharStrdup(header->name);
|
||||||
|
cur->value = (char *)xmlCharStrdup(header->value);
|
||||||
|
|
||||||
|
if (!cur->name || !cur->value) {
|
||||||
|
if (cur->name) xmlFree(cur->name);
|
||||||
|
if (cur->value) xmlFree(cur->value);
|
||||||
|
if (old) {
|
||||||
|
old->next = NULL;
|
||||||
|
} else {
|
||||||
|
ret = NULL;
|
||||||
|
}
|
||||||
|
free(cur);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
header = header->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void config_clear_mount (mount_proxy *mount)
|
static void config_clear_mount (mount_proxy *mount)
|
||||||
{
|
{
|
||||||
config_options_t *option;
|
config_options_t *option;
|
||||||
@ -168,6 +208,7 @@ static void config_clear_mount (mount_proxy *mount)
|
|||||||
option = nextopt;
|
option = nextopt;
|
||||||
}
|
}
|
||||||
auth_release (mount->auth);
|
auth_release (mount->auth);
|
||||||
|
config_clear_http_header(mount->http_headers);
|
||||||
free (mount);
|
free (mount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,7 +532,7 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
|
|||||||
} else if (xmlStrcmp (node->name, XMLSTR("limits")) == 0) {
|
} else if (xmlStrcmp (node->name, XMLSTR("limits")) == 0) {
|
||||||
_parse_limits(doc, node->xmlChildrenNode, configuration);
|
_parse_limits(doc, node->xmlChildrenNode, configuration);
|
||||||
} else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
|
} else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
|
||||||
_parse_http_headers(doc, node->xmlChildrenNode, configuration);
|
_parse_http_headers(doc, node->xmlChildrenNode, &(configuration->http_headers));
|
||||||
} else if (xmlStrcmp (node->name, XMLSTR("relay")) == 0) {
|
} else if (xmlStrcmp (node->name, XMLSTR("relay")) == 0) {
|
||||||
_parse_relay(doc, node->xmlChildrenNode, configuration);
|
_parse_relay(doc, node->xmlChildrenNode, configuration);
|
||||||
} else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
|
} else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
|
||||||
@ -728,6 +769,8 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
|
|||||||
} else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) {
|
} else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) {
|
||||||
mount->subtype = (char *)xmlNodeListGetString(
|
mount->subtype = (char *)xmlNodeListGetString(
|
||||||
doc, node->xmlChildrenNode, 1);
|
doc, node->xmlChildrenNode, 1);
|
||||||
|
} else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
|
||||||
|
_parse_http_headers(doc, node->xmlChildrenNode, &(mount->http_headers));
|
||||||
}
|
}
|
||||||
} while ((node = node->next));
|
} while ((node = node->next));
|
||||||
|
|
||||||
@ -762,7 +805,7 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
|
|||||||
configuration->mounts = mount;
|
configuration->mounts = mount;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c) {
|
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_http_header_t **http_headers) {
|
||||||
ice_config_http_header_t *header;
|
ice_config_http_header_t *header;
|
||||||
ice_config_http_header_t *next;
|
ice_config_http_header_t *next;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
@ -783,11 +826,11 @@ static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c)
|
|||||||
name = NULL;
|
name = NULL;
|
||||||
value = NULL;
|
value = NULL;
|
||||||
|
|
||||||
if (!c->http_headers) {
|
if (!*http_headers) {
|
||||||
c->http_headers = header;
|
*http_headers = header;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
next = c->http_headers;
|
next = *http_headers;
|
||||||
while (next->next) next = next->next;
|
while (next->next) next = next->next;
|
||||||
next->next = header;
|
next->next = header;
|
||||||
} while ((node = node->next));
|
} while ((node = node->next));
|
||||||
@ -1244,6 +1287,9 @@ static void _add_server(xmlDocPtr doc, xmlNodePtr node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void merge_mounts(mount_proxy * dst, mount_proxy * src) {
|
static void merge_mounts(mount_proxy * dst, mount_proxy * src) {
|
||||||
|
ice_config_http_header_t *http_header_next;
|
||||||
|
ice_config_http_header_t **http_header_tail;
|
||||||
|
|
||||||
if (!dst || !src)
|
if (!dst || !src)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1305,6 +1351,15 @@ static void merge_mounts(mount_proxy * dst, mount_proxy * src) {
|
|||||||
dst->subtype = (char*)xmlStrdup((xmlChar*)src->subtype);
|
dst->subtype = (char*)xmlStrdup((xmlChar*)src->subtype);
|
||||||
if (dst->yp_public == -1)
|
if (dst->yp_public == -1)
|
||||||
dst->yp_public = src->yp_public;
|
dst->yp_public = src->yp_public;
|
||||||
|
|
||||||
|
if (dst->http_headers) {
|
||||||
|
http_header_next = dst->http_headers;
|
||||||
|
while (http_header_next->next) http_header_next = http_header_next->next;
|
||||||
|
http_header_tail = &(http_header_next->next);
|
||||||
|
} else {
|
||||||
|
http_header_tail = &(dst->http_headers);
|
||||||
|
}
|
||||||
|
*http_header_tail = config_copy_http_header(src->http_headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _merge_mounts_all(ice_config_t *c) {
|
static inline void _merge_mounts_all(ice_config_t *c) {
|
||||||
|
@ -88,6 +88,8 @@ typedef struct _mount_proxy {
|
|||||||
char *charset; /* character set if not utf8 */
|
char *charset; /* character set if not utf8 */
|
||||||
int mp3_meta_interval; /* outgoing per-stream metadata interval */
|
int mp3_meta_interval; /* outgoing per-stream metadata interval */
|
||||||
|
|
||||||
|
ice_config_http_header_t *http_headers; /* additional HTTP headers */
|
||||||
|
|
||||||
char *auth_type; /* Authentication type */
|
char *auth_type; /* Authentication type */
|
||||||
struct auth_tag *auth;
|
struct auth_tag *auth;
|
||||||
char *cluster_password;
|
char *cluster_password;
|
||||||
|
@ -190,7 +190,7 @@ static void client_send_error(client_t *client, int status, int plain, const cha
|
|||||||
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
|
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
|
||||||
0, status, NULL,
|
0, status, NULL,
|
||||||
plain ? "text/plain" : "text/html", "utf-8",
|
plain ? "text/plain" : "text/html", "utf-8",
|
||||||
plain ? message : "");
|
plain ? message : "", NULL);
|
||||||
|
|
||||||
if (!plain)
|
if (!plain)
|
||||||
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
|
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
|
||||||
|
@ -299,7 +299,7 @@ static int format_prepare_headers (source_t *source, client_t *client)
|
|||||||
ptr = client->refbuf->data;
|
ptr = client->refbuf->data;
|
||||||
client->respcode = 200;
|
client->respcode = 200;
|
||||||
|
|
||||||
bytes = util_http_build_header (ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL);
|
bytes = util_http_build_header (ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source);
|
||||||
|
|
||||||
remaining -= bytes;
|
remaining -= bytes;
|
||||||
ptr += bytes;
|
ptr += bytes;
|
||||||
|
@ -458,7 +458,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
|||||||
httpclient->respcode = 200;
|
httpclient->respcode = 200;
|
||||||
ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
|
ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
|
||||||
0, 200, NULL,
|
0, 200, NULL,
|
||||||
"audio/x-mpegurl", NULL, "");
|
"audio/x-mpegurl", NULL, "", NULL);
|
||||||
if (host == NULL)
|
if (host == NULL)
|
||||||
{
|
{
|
||||||
config = config_get_config();
|
config = config_get_config();
|
||||||
@ -567,7 +567,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
|||||||
bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
|
bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
|
||||||
0, 206, NULL,
|
0, 206, NULL,
|
||||||
type, NULL,
|
type, NULL,
|
||||||
NULL);
|
NULL, NULL);
|
||||||
bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes,
|
bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes,
|
||||||
"Accept-Ranges: bytes\r\n"
|
"Accept-Ranges: bytes\r\n"
|
||||||
"Content-Length: %" PRI_OFF_T "\r\n"
|
"Content-Length: %" PRI_OFF_T "\r\n"
|
||||||
@ -593,7 +593,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
|||||||
bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
|
bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
|
||||||
0, 200, NULL,
|
0, 200, NULL,
|
||||||
type, NULL,
|
type, NULL,
|
||||||
NULL);
|
NULL, NULL);
|
||||||
bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes,
|
bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes,
|
||||||
"Accept-Ranges: bytes\r\n"
|
"Accept-Ranges: bytes\r\n"
|
||||||
"Content-Length: %" PRI_OFF_T "\r\n\r\n",
|
"Content-Length: %" PRI_OFF_T "\r\n\r\n",
|
||||||
|
47
src/util.c
47
src/util.c
@ -45,6 +45,7 @@
|
|||||||
#include "refbuf.h"
|
#include "refbuf.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
#include "source.h"
|
||||||
|
|
||||||
#define CATMODULE "util"
|
#define CATMODULE "util"
|
||||||
|
|
||||||
@ -487,20 +488,12 @@ char *util_base64_decode(const char *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TODO, FIXME: handle memory allocation errors better. */
|
/* TODO, FIXME: handle memory allocation errors better. */
|
||||||
static inline char * _build_headers(ice_config_t *config) {
|
static inline void _build_headers_loop(char **ret, size_t *len, ice_config_http_header_t *header) {
|
||||||
char *ret = NULL;
|
|
||||||
size_t len = 1;
|
|
||||||
size_t headerlen;
|
size_t headerlen;
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *value;
|
const char *value;
|
||||||
ice_config_http_header_t *header = config->http_headers;
|
char * r = *ret;
|
||||||
|
|
||||||
if (!header) {
|
|
||||||
return strdup("");
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = calloc(1, 1);
|
|
||||||
*ret = 0;
|
|
||||||
while (header) {
|
while (header) {
|
||||||
name = header->name;
|
name = header->name;
|
||||||
switch (header->type) {
|
switch (header->type) {
|
||||||
@ -509,14 +502,31 @@ static inline char * _build_headers(ice_config_t *config) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
headerlen = strlen(name) + strlen(value) + 4;
|
headerlen = strlen(name) + strlen(value) + 4;
|
||||||
len += headerlen;
|
*len += headerlen;
|
||||||
ret = realloc(ret, len);
|
r = realloc(r, *len);
|
||||||
strcat(ret, name);
|
strcat(r, name);
|
||||||
strcat(ret, ": ");
|
strcat(r, ": ");
|
||||||
strcat(ret, value);
|
strcat(r, value);
|
||||||
strcat(ret, "\r\n");
|
strcat(r, "\r\n");
|
||||||
header = header->next;
|
header = header->next;
|
||||||
}
|
}
|
||||||
|
*ret = r;
|
||||||
|
}
|
||||||
|
static inline char * _build_headers(int status, ice_config_t *config, source_t *source) {
|
||||||
|
mount_proxy *mountproxy = NULL;
|
||||||
|
char *ret = NULL;
|
||||||
|
size_t len = 1;
|
||||||
|
|
||||||
|
if (source)
|
||||||
|
mountproxy = config_find_mount(config, source->mount, MOUNT_TYPE_NORMAL);
|
||||||
|
|
||||||
|
ret = calloc(1, 1);
|
||||||
|
*ret = 0;
|
||||||
|
|
||||||
|
_build_headers_loop(&ret, &len, config->http_headers);
|
||||||
|
if (mountproxy && mountproxy->http_headers)
|
||||||
|
_build_headers_loop(&ret, &len, mountproxy->http_headers);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,7 +534,8 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
|
|||||||
int cache,
|
int cache,
|
||||||
int status, const char * statusmsg,
|
int status, const char * statusmsg,
|
||||||
const char * contenttype, const char * charset,
|
const char * contenttype, const char * charset,
|
||||||
const char * datablock) {
|
const char * datablock,
|
||||||
|
struct source_tag * source) {
|
||||||
const char * http_version = "1.0";
|
const char * http_version = "1.0";
|
||||||
ice_config_t *config;
|
ice_config_t *config;
|
||||||
time_t now;
|
time_t now;
|
||||||
@ -598,7 +609,7 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
|
|||||||
currenttime_buffer[0] = '\0';
|
currenttime_buffer[0] = '\0';
|
||||||
|
|
||||||
config = config_get_config();
|
config = config_get_config();
|
||||||
extra_headers = _build_headers(config);
|
extra_headers = _build_headers(status, config, source);
|
||||||
ret = snprintf (out, len, "%sServer: %s\r\n%s%s%s%s%s%s%s",
|
ret = snprintf (out, len, "%sServer: %s\r\n%s%s%s%s%s%s%s",
|
||||||
status_buffer,
|
status_buffer,
|
||||||
config->server_id,
|
config->server_id,
|
||||||
|
@ -56,11 +56,14 @@ char *util_url_escape(const char *src);
|
|||||||
* If datablock is NULL no end-of-header nor any data is appended.
|
* If datablock is NULL no end-of-header nor any data is appended.
|
||||||
* Returns the number of bytes written or -1 on error.
|
* Returns the number of bytes written or -1 on error.
|
||||||
*/
|
*/
|
||||||
|
struct source_tag; /* use forward decleration so we do not need to
|
||||||
|
* include <source.h> that would cause other conflicts. */
|
||||||
ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
|
ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
|
||||||
int cache,
|
int cache,
|
||||||
int status, const char * statusmsg,
|
int status, const char * statusmsg,
|
||||||
const char * contenttype, const char * charset,
|
const char * contenttype, const char * charset,
|
||||||
const char * datablock);
|
const char * datablock,
|
||||||
|
struct source_tag * source);
|
||||||
|
|
||||||
/* String dictionary type, without support for NULL keys, or multiple
|
/* String dictionary type, without support for NULL keys, or multiple
|
||||||
* instances of the same key */
|
* instances of the same key */
|
||||||
|
@ -238,7 +238,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
|
|||||||
|
|
||||||
if (string == NULL)
|
if (string == NULL)
|
||||||
string = xmlCharStrdup ("");
|
string = xmlCharStrdup ("");
|
||||||
ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL);
|
ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL);
|
||||||
snprintf (refbuf->data + ret, full_len - ret,
|
snprintf (refbuf->data + ret, full_len - ret,
|
||||||
"Content-Length: %d\r\n\r\n%s",
|
"Content-Length: %d\r\n\r\n%s",
|
||||||
len, string);
|
len, string);
|
||||||
|
Loading…
Reference in New Issue
Block a user