Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Icecast-Server
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Marvin Scholz
Icecast-Server
Commits
293b7db0
Commit
293b7db0
authored
Nov 12, 2017
by
Marvin Scholz
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'CORS' of
https://github.com/jucrouzet/Icecast-Server
into jucrouzet-CORS
parents
c1b4e755
a0bb2556
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
609 additions
and
10 deletions
+609
-10
src/Makefile.am
src/Makefile.am
+2
-2
src/cfgfile.c
src/cfgfile.c
+263
-1
src/cfgfile.h
src/cfgfile.h
+18
-2
src/client.c
src/client.c
+38
-0
src/client.h
src/client.h
+1
-0
src/connection.c
src/connection.c
+12
-2
src/cors.c
src/cors.c
+243
-0
src/cors.h
src/cors.h
+22
-0
src/util.c
src/util.c
+10
-3
No files found.
src/Makefile.am
View file @
293b7db0
...
...
@@ -13,14 +13,14 @@ noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \
acl.h auth.h
\
format.h format_ogg.h format_mp3.h format_ebml.h
\
format_vorbis.h format_theora.h format_flac.h format_speex.h format_midi.h
\
format_kate.h format_skeleton.h format_opus.h
format_kate.h format_skeleton.h format_opus.h
cors.h
icecast_SOURCES
=
cfgfile.c main.c logging.c sighandler.c connection.c global.c
\
util.c slave.c source.c stats.c refbuf.c client.c playlist.c
\
xslt.c fserve.c admin.c md5.c matchfile.c tls.c
\
format.c format_ogg.c format_mp3.c format_midi.c format_flac.c format_ebml.c
\
format_kate.c format_skeleton.c format_opus.c
\
event.c event_log.c event_exec.c
\
acl.c auth.c auth_htpasswd.c auth_anonymous.c auth_static.c
acl.c auth.c auth_htpasswd.c auth_anonymous.c auth_static.c
cors.c
EXTRA_icecast_SOURCES
=
curl.c yp.c
\
auth_url.c event_url.c
\
format_vorbis.c format_theora.c format_speex.c
...
...
src/cfgfile.c
View file @
293b7db0
...
...
@@ -148,6 +148,17 @@ static void _parse_events(event_registration_t **events, xmlNodePtr node);
static
void
merge_mounts
(
mount_proxy
*
dst
,
mount_proxy
*
src
);
static
inline
void
_merge_mounts_all
(
ice_config_t
*
c
);
static
void
_parse_cors
(
xmlDocPtr
doc
,
xmlNodePtr
node
,
ice_config_cors_path_t
**
cors_paths
);
static
int
_parse_cors_path
(
xmlDocPtr
doc
,
xmlNodePtr
node
,
ice_config_cors_path_t
*
cors_path
);
static
void
config_clear_cors
(
ice_config_cors_path_t
*
cors_paths
);
operation_mode
config_str_to_omode
(
const
char
*
str
)
{
if
(
!
str
||
!*
str
)
...
...
@@ -219,7 +230,7 @@ static inline void __read_unsigned_int(xmlDocPtr doc, xmlNodePtr node, unsigned
}
if
(
str
)
xmlFree
(
str
);
}
}
static
inline
int
__parse_public
(
const
char
*
str
)
{
...
...
@@ -657,6 +668,7 @@ void config_clear(ice_config_t *c)
#endif
config_clear_http_header
(
c
->
http_headers
);
config_clear_cors
(
c
->
cors_paths
);
memset
(
c
,
0
,
sizeof
(
ice_config_t
));
}
...
...
@@ -1028,6 +1040,8 @@ static void _parse_root(xmlDocPtr doc,
}
else
if
(
xmlStrcmp
(
node
->
name
,
XMLSTR
(
"event-bindings"
))
==
0
||
xmlStrcmp
(
node
->
name
,
XMLSTR
(
"kartoffelsalat"
))
==
0
)
{
_parse_events
(
&
configuration
->
event
,
node
->
xmlChildrenNode
);
}
else
if
(
xmlStrcmp
(
node
->
name
,
XMLSTR
(
"cors"
))
==
0
)
{
_parse_cors
(
doc
,
node
->
xmlChildrenNode
,
&
(
configuration
->
cors_paths
));
}
}
while
((
node
=
node
->
next
));
...
...
@@ -2220,6 +2234,254 @@ static void _parse_events(event_registration_t **events, xmlNodePtr node)
}
}
static
ice_config_cors_path_t
*
_cors_sort_paths_by_base_length_desc
(
ice_config_cors_path_t
*
cors_paths
)
{
ice_config_cors_path_t
*
curr
=
cors_paths
;
ice_config_cors_path_t
*
prev
=
cors_paths
;
ice_config_cors_path_t
*
largest
=
cors_paths
;
ice_config_cors_path_t
*
largestPrev
=
cors_paths
;
ice_config_cors_path_t
*
tmp
;
// End of sorting or only one path or no path
if
(
!
cors_paths
||
!
cors_paths
->
next
)
{
return
cors_paths
;
}
// Find the largest base and set it first.
while
(
curr
!=
NULL
)
{
if
(
strlen
(
curr
->
base
)
>
strlen
(
largest
->
base
))
{
largestPrev
=
prev
;
largest
=
curr
;
}
prev
=
curr
;
curr
=
curr
->
next
;
}
if
(
largest
!=
cors_paths
)
{
largestPrev
->
next
=
cors_paths
;
tmp
=
cors_paths
->
next
;
cors_paths
->
next
=
largest
->
next
;
largest
->
next
=
tmp
;
}
// Recurse to the rest of the list
largest
->
next
=
_cors_sort_paths_by_base_length_desc
(
largest
->
next
);
return
largest
;
}
static
void
_parse_cors
(
xmlDocPtr
doc
,
xmlNodePtr
node
,
ice_config_cors_path_t
**
cors_paths
)
{
ice_config_cors_path_t
*
path
=
NULL
;
ice_config_cors_path_t
*
next
=
NULL
;
char
*
base
=
NULL
;
do
{
if
(
node
==
NULL
)
break
;
if
(
xmlIsBlankNode
(
node
))
continue
;
if
(
!
node
->
name
)
continue
;
if
(
xmlStrcmp
(
node
->
name
,
XMLSTR
(
"path"
))
!=
0
)
{
continue
;
}
if
(
!
(
base
=
(
char
*
)
xmlGetProp
(
node
,
XMLSTR
(
"base"
)))
||
!
strlen
(
base
)
)
{
ICECAST_LOG_WARN
(
"Ignoring <cors><path> tag without base attribute or empty"
);
xmlFree
(
xmlGetProp
(
node
,
XMLSTR
(
"base"
)));
continue
;
}
path
=
calloc
(
1
,
sizeof
(
ice_config_cors_path_t
));
if
(
!
path
)
{
ICECAST_LOG_ERROR
(
"Out of memory while parsing config file"
);
break
;
}
path
->
base
=
base
;
if
(
!
_parse_cors_path
(
doc
,
node
,
path
))
{
base
=
NULL
;
if
(
!*
cors_paths
)
{
*
cors_paths
=
path
;
continue
;
}
next
=
*
cors_paths
;
while
(
next
->
next
)
{
next
=
next
->
next
;
}
next
->
next
=
path
;
}
else
{
free
(
path
);
}
}
while
((
node
=
node
->
next
));
/* in case we used break we may need to clean those up */
if
(
base
)
xmlFree
(
base
);
*
cors_paths
=
_cors_sort_paths_by_base_length_desc
(
*
cors_paths
);
}
static
void
_cors_sort_origins_by_length_desc
(
char
**
origins
)
{
uint
length
;
char
*
temp
;
// If there are no origins or only one, no sort.
if
(
!
origins
||
!
origins
[
1
])
{
return
;
}
// Count origins.
for
(
length
=
0
;
origins
[
length
];
length
++
);
// Sort origin by length, descending.
for
(
int
step
=
0
;
step
<
length
;
step
++
)
{
for
(
int
i
=
0
;
i
<
length
-
step
-
1
;
i
++
)
{
if
(
strlen
(
origins
[
i
])
<
strlen
(
origins
[
i
+
1
]))
{
temp
=
origins
[
i
];
origins
[
i
]
=
origins
[
i
+
1
];
origins
[
i
+
1
]
=
temp
;
}
}
}
}
static
int
_parse_cors_path
(
xmlDocPtr
doc
,
xmlNodePtr
node
,
ice_config_cors_path_t
*
cors_path
)
{
int
allowed_count
=
0
;
int
forbidden_count
=
0
;
int
exposed_headers_count
=
0
;
xmlNodePtr
tmpNode
=
node
->
xmlChildrenNode
;
while
((
tmpNode
=
tmpNode
->
next
))
{
if
(
tmpNode
==
NULL
)
break
;
if
(
!
tmpNode
->
name
)
continue
;
if
(
xmlStrcmp
(
tmpNode
->
name
,
XMLSTR
(
"no-cors"
))
==
0
)
{
cors_path
->
no_cors
=
1
;
return
0
;
}
if
(
xmlIsBlankNode
(
tmpNode
))
continue
;
if
(
xmlStrcmp
(
tmpNode
->
name
,
XMLSTR
(
"allowed-origin"
))
==
0
)
{
allowed_count
++
;
continue
;
}
if
(
xmlStrcmp
(
tmpNode
->
name
,
XMLSTR
(
"forbidden-origin"
))
==
0
)
{
forbidden_count
++
;
continue
;
}
if
(
xmlStrcmp
(
tmpNode
->
name
,
XMLSTR
(
"exposed-header"
))
==
0
)
{
exposed_headers_count
++
;
continue
;
}
}
if
(
!
allowed_count
&&
!
forbidden_count
&&
!
exposed_headers_count
)
{
return
1
;
}
if
(
allowed_count
)
{
cors_path
->
allowed
=
calloc
(
allowed_count
+
1
,
sizeof
(
char
*
));
if
(
!
cors_path
->
allowed
)
{
ICECAST_LOG_ERROR
(
"Out of memory while parsing config file"
);
return
1
;
}
cors_path
->
allowed
[
allowed_count
]
=
NULL
;
}
if
(
forbidden_count
)
{
cors_path
->
forbidden
=
calloc
(
forbidden_count
+
1
,
sizeof
(
char
*
));
if
(
!
cors_path
->
forbidden
)
{
ICECAST_LOG_ERROR
(
"Out of memory while parsing config file"
);
if
(
cors_path
->
allowed
)
free
(
cors_path
->
allowed
);
return
1
;
}
cors_path
->
forbidden
[
forbidden_count
]
=
NULL
;
}
tmpNode
=
node
->
xmlChildrenNode
;
allowed_count
=
forbidden_count
=
exposed_headers_count
=
0
;
while
((
tmpNode
=
tmpNode
->
next
))
{
if
(
tmpNode
==
NULL
)
break
;
if
(
!
tmpNode
->
name
)
continue
;
if
(
xmlIsBlankNode
(
tmpNode
))
continue
;
if
(
xmlStrcmp
(
tmpNode
->
name
,
XMLSTR
(
"allowed-origin"
))
==
0
)
{
cors_path
->
allowed
[
allowed_count
++
]
=
(
char
*
)
xmlNodeListGetString
(
doc
,
tmpNode
->
xmlChildrenNode
,
1
);
continue
;
}
if
(
xmlStrcmp
(
tmpNode
->
name
,
XMLSTR
(
"forbidden-origin"
))
==
0
)
{
cors_path
->
forbidden
[
forbidden_count
++
]
=
(
char
*
)
xmlNodeListGetString
(
doc
,
tmpNode
->
xmlChildrenNode
,
1
);
continue
;
}
if
(
xmlStrcmp
(
tmpNode
->
name
,
XMLSTR
(
"exposed-header"
))
==
0
)
{
char
*
orig_value
=
(
char
*
)
xmlNodeListGetString
(
doc
,
tmpNode
->
xmlChildrenNode
,
1
);
int
first_value
=
1
;
if
(
!
cors_path
->
exposed_headers
)
{
cors_path
->
exposed_headers
=
calloc
(
strlen
(
orig_value
)
+
1
,
sizeof
(
char
));
}
else
{
cors_path
->
exposed_headers
=
realloc
(
cors_path
->
exposed_headers
,
(
strlen
(
cors_path
->
exposed_headers
)
+
strlen
(
orig_value
)
+
3
)
);
first_value
=
0
;
}
if
(
!
cors_path
->
exposed_headers
)
{
ICECAST_LOG_ERROR
(
"Out of memory while parsing config file"
);
if
(
cors_path
->
allowed
)
free
(
cors_path
->
allowed
);
if
(
cors_path
->
forbidden
)
free
(
cors_path
->
forbidden
);
return
1
;
}
if
(
!
first_value
)
cors_path
->
exposed_headers
=
strcat
(
cors_path
->
exposed_headers
,
", "
);
cors_path
->
exposed_headers
=
strcat
(
cors_path
->
exposed_headers
,
orig_value
);
xmlFree
(
orig_value
);
continue
;
}
}
_cors_sort_origins_by_length_desc
(
cors_path
->
allowed
);
_cors_sort_origins_by_length_desc
(
cors_path
->
forbidden
);
return
0
;
}
void
config_clear_cors
(
ice_config_cors_path_t
*
cors_paths
)
{
while
(
cors_paths
)
{
ice_config_cors_path_t
*
path
=
cors_paths
;
cors_paths
=
path
->
next
;
if
(
path
->
allowed
)
{
for
(
int
i
=
0
;
path
->
allowed
[
i
];
i
++
)
{
xmlFree
(
path
->
allowed
[
i
]);
}
free
(
path
->
allowed
);
}
if
(
path
->
forbidden
)
{
for
(
int
i
=
0
;
path
->
forbidden
[
i
];
i
++
)
{
xmlFree
(
path
->
forbidden
[
i
]);
}
free
(
path
->
forbidden
);
}
if
(
path
->
exposed_headers
)
{
free
(
path
->
exposed_headers
);
}
xmlFree
(
path
->
base
);
free
(
path
);
}
}
config_options_t
*
config_parse_options
(
xmlNodePtr
node
)
{
config_options_t
*
ret
=
NULL
;
...
...
src/cfgfile.h
View file @
293b7db0
...
...
@@ -3,7 +3,7 @@
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2000-2004, Jack Moffitt <jack@xiph.org>,
* Copyright 2000-2004, Jack Moffitt <jack@xiph.org>,
* Michael Smith <msmith@xiph.org>,
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
...
...
@@ -30,7 +30,7 @@ struct _mount_proxy;
#include "global.h"
#include "connection.h"
#define XMLSTR(str) ((xmlChar *)(str))
#define XMLSTR(str) ((xmlChar *)(str))
typedef
enum
_operation_mode
{
/* Default operation mode. may depend on context */
...
...
@@ -175,6 +175,21 @@ typedef struct _listener_t {
tlsmode_t
tls
;
}
listener_t
;
typedef
struct
ice_config_cors_path
{
/* base path */
char
*
base
;
/* no-cors path */
int
no_cors
;
/* allowed origins */
char
**
allowed
;
/* forbidden origins */
char
**
forbidden
;
/* exposed headers */
char
*
exposed_headers
;
/* link to the next list element */
struct
ice_config_cors_path
*
next
;
}
ice_config_cors_path_t
;
typedef
struct
_config_tls_context
{
char
*
cert_file
;
char
*
key_file
;
...
...
@@ -220,6 +235,7 @@ typedef struct ice_config_tag {
char
*
master_password
;
ice_config_http_header_t
*
http_headers
;
ice_config_cors_path_t
*
cors_paths
;
/* is TLS supported by the server? */
int
tls_ok
;
...
...
src/client.c
View file @
293b7db0
...
...
@@ -44,6 +44,8 @@
/* for ADMIN_COMMAND_ERROR */
#include "admin.h"
#include "cors.h"
#ifdef _WIN32
#define snprintf _snprintf
#endif
...
...
@@ -292,6 +294,42 @@ void client_send_101(client_t *client, reuse_t reuse)
fserve_add_client
(
client
,
NULL
);
}
/* Sends an empty 204 response (for OPTIONS) */
void
client_send_204
(
client_t
*
client
)
{
ssize_t
ret
;
char
*
message
;
message
=
calloc
(
PER_CLIENT_REFBUF_SIZE
,
sizeof
(
char
));
if
(
!
message
)
{
client_send_500
(
client
,
"Unable to allocate memory for response"
);
return
;
}
ret
=
util_http_build_header
(
message
,
// Response buffer
PER_CLIENT_REFBUF_SIZE
,
// Buffer size
0
,
// Offset
0
,
// Prevent cache
204
,
// Status code
"No Content"
,
// Status message
NULL
,
// Content-Type
NULL
,
// Charset
NULL
,
// Data
NULL
,
// Source
client
);
if
(
ret
==
-
1
||
ret
>=
PER_CLIENT_REFBUF_SIZE
)
{
free
(
message
);
ICECAST_LOG_ERROR
(
"Dropping client as we can not build response headers."
);
client_send_500
(
client
,
"Header generation failed."
);
return
;
}
client_send_bytes
(
client
,
message
,
strlen
(
message
));
client_destroy
(
client
);
free
(
message
);
}
void
client_send_426
(
client_t
*
client
,
reuse_t
reuse
)
{
ssize_t
ret
;
...
...
src/client.h
View file @
293b7db0
...
...
@@ -111,6 +111,7 @@ int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser);
void
client_destroy
(
client_t
*
client
);
void
client_send_error
(
client_t
*
client
,
int
status
,
int
plain
,
const
char
*
message
);
void
client_send_101
(
client_t
*
client
,
reuse_t
reuse
);
void
client_send_204
(
client_t
*
client
);
void
client_send_426
(
client_t
*
client
,
reuse_t
reuse
);
int
client_send_bytes
(
client_t
*
client
,
const
void
*
buf
,
unsigned
len
);
int
client_read_bytes
(
client_t
*
client
,
void
*
buf
,
unsigned
len
);
...
...
src/connection.c
View file @
293b7db0
...
...
@@ -134,7 +134,7 @@ void connection_shutdown(void)
tls_ctx_unref
(
tls_ctx
);
matchfile_release
(
banned_ip
);
matchfile_release
(
allowed_ip
);
thread_cond_destroy
(
&
global
.
shutdown_cond
);
thread_rwlock_destroy
(
&
_source_shutdown_rwlock
);
thread_spin_destroy
(
&
_connection_lock
);
...
...
@@ -1130,6 +1130,7 @@ static int _handle_aliases(client_t *client, char **uri)
*/
static
void
_handle_authed_client
(
client_t
*
client
,
void
*
uri
,
auth_result
result
)
{
httpp_request_type_e
req_type
;
auth_stack_release
(
client
->
authstack
);
client
->
authstack
=
NULL
;
...
...
@@ -1139,7 +1140,13 @@ static void _handle_authed_client(client_t *client, void *uri, auth_result resul
return
;
}
if
(
acl_test_method
(
client
->
acl
,
client
->
parser
->
req_type
)
!=
ACL_POLICY_ALLOW
)
{
// If path is not /admin/ OPTIONS should respect the same acl as GET
// for preflighted request
req_type
=
client
->
parser
->
req_type
;
if
(
strstr
(
client
->
parser
->
uri
,
"/admin/"
)
!=
client
->
parser
->
uri
)
{
req_type
=
httpp_req_get
;
}
if
(
acl_test_method
(
client
->
acl
,
req_type
)
!=
ACL_POLICY_ALLOW
)
{
ICECAST_LOG_ERROR
(
"Client (role=%s, username=%s) not allowed to use this request method on %H"
,
client
->
role
,
client
->
username
,
uri
);
client_send_error
(
client
,
401
,
1
,
"You need to authenticate
\r\n
"
);
free
(
uri
);
...
...
@@ -1157,6 +1164,9 @@ static void _handle_authed_client(client_t *client, void *uri, auth_result resul
case
httpp_req_get
:
_handle_get_request
(
client
,
uri
);
break
;
case
httpp_req_options
:
client_send_204
(
client
);
break
;
default:
ICECAST_LOG_ERROR
(
"Wrong request type from client"
);
client_send_error
(
client
,
400
,
0
,
"unknown request"
);
...
...
src/cors.c
0 → 100644
View file @
293b7db0
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2017, Julien CROUZET <contact@juliencrouzet.fr>
*/
/**
* Cors handling functions
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <ctype.h>
#include "cfgfile.h"
#include "client.h"
#include "logging.h"
#define CATMODULE "CORS"
static
const
char
*
cors_header_names
[
7
]
=
{
"access-control-allow-origin"
,
"access-control-expose-headers"
,
"access-control-max-age"
,
"access-control-allow-credentials"
,
"access-control-allow-methods"
,
"access-control-allow-headers"
,
NULL
};
static
const
char
*
icy_headers
=
"icy-br, icy-caps, icy-description, icy-genre, icy-metaint, icy-metadata-interval, icy-name, icy-pub, icy-public, icy-url"
;
static
ice_config_cors_path_t
*
_find_matching_path
(
ice_config_cors_path_t
*
paths
,
char
*
path
)
{
ice_config_cors_path_t
*
matching_path
=
paths
;
while
(
matching_path
)
{
if
(
strncmp
(
matching_path
->
base
,
path
,
strlen
(
matching_path
->
base
))
==
0
)
{
return
matching_path
;
}
matching_path
=
matching_path
->
next
;
}
return
NULL
;
}
static
int
_cors_valid_origin
(
ice_config_cors_path_t
*
path
,
const
char
*
origin
)
{
if
(
path
->
forbidden
)
{
for
(
int
i
=
0
;
path
->
forbidden
[
i
];
i
++
)
{
if
(
strstr
(
origin
,
path
->
forbidden
[
i
])
==
origin
)
{
ICECAST_LOG_DEBUG
(
"Declared origin
\"
%s
\"
matches forbidden origin
\"
%s
\"
, not sending CORS"
,
origin
,
path
->
forbidden
[
i
]
);
return
0
;
}
}
}
if
(
path
->
allowed
)
{
for
(
int
i
=
0
;
path
->
allowed
[
i
];
i
++
)
{
if
((
strlen
(
path
->
allowed
[
i
])
==
1
)
&&
path
->
allowed
[
i
][
0
]
==
'*'
)
{
ICECAST_LOG_DEBUG
(
"All (
\"
*
\"
) allowed origin for
\"
%s
\"
, sending CORS"
,
origin
);
return
1
;
}
if
(
strstr
(
origin
,
path
->
allowed
[
i
])
==
origin
)
{
ICECAST_LOG_DEBUG
(
"Declared origin
\"
%s
\"
matches allowed origin
\"
%s
\"
, sending CORS"
,
origin
,
path
->
allowed
[
i
]
);
return
1
;
}
}
}
ICECAST_LOG_DEBUG
(
"Declared origin
\"
%s
\"
does not matches any declared origin, not sending CORS"
,
origin
);
return
0
;
}
static
void
_add_header
(
char
**
out
,
size_t
*
len
,
const
char
*
header_name
,
const
char
*
header_value
)
{
int
new_length
;
char
*
new_out
;
if
(
!
header_name
||
!
header_value
||
!
strlen
(
header_name
))
{
return
;
}
new_length
=
strlen
(
header_name
)
+
strlen
(
header_value
)
+
4
;
new_out
=
calloc
(
*
len
+
new_length
,
sizeof
(
char
));
if
(
!
new_out
)
{
ICECAST_LOG_ERROR
(
"Out of memory while setting CORS header."
);
return
;
}
snprintf
(
new_out
,
*
len
+
new_length
,
"%s%s: %s
\r\n
"
,
*
out
,
header_name
,
header_value
);
free
(
*
out
);
*
len
+=
new_length
;
*
out
=
new_out
;
}
/**
* Removes an header by its name in current headers list.
* Header removal is needed to remove any manually added headers
* added while a forbidden rule is active.
*/
static
void
_remove_header
(
char
**
out
,
size_t
*
len
,
const
char
*
header_name
)
{
int
header_start
[
100
];
int
header_end
[
100
];
int
current_position
=
0
;
int
found_count
=
0
;
char
*
new_out
;
if
(
!*
len
)
return
;
while
((
current_position
<
(
*
len
-
1
))
&&
found_count
<
100
)
{
char
*
substr
=
strcasestr
((
*
out
+
current_position
),
header_name
);
char
*
substr_end
;
if
(
!
substr
)
{
break
;
}
substr_end
=
strstr
(
substr
,
"
\r\n
"
);
if
(
!
substr_end
)
{
return
;
}
header_start
[
found_count
]
=
substr
-
*
out
;
header_end
[
found_count
]
=
substr_end
-
*
out
+
2
;
current_position
=
header_end
[
found_count
];
found_count
++
;
}
if
(
!
found_count
)
{
return
;
}
current_position
=
0
;
new_out
=
calloc
(
*
len
+
1
,
sizeof
(
char
));
if
(
!
new_out
)
{
return
;
}
free
(
*
out
);
for
(
int
i
=
0
;
i
<
found_count
;
i
++
)
{
while
(
current_position
<
header_start
[
i
])
{
new_out
[
current_position
]
=
*
out
[
current_position
];
}
current_position
=
header_end
[
i
];
}
while
(
current_position
<
*
len
)
{
new_out
[
current_position
]
=
0
;
current_position
++
;
}
*
out
=
new_out
;
for
(
int
i
=
0
;
i
<
found_count
;
i
++
)
{
*
len
-=
header_end
[
i
]
-
header_start
[
i
];
}
return
;
}
static
void
_add_cors
(
char
**
out
,
size_t
*
len
,
ice_config_cors_path_t
*
path
,
char
*
origin
)
{