From ca83e6b44b6ff3b770fbb1ea7cf299227c4fcb1c Mon Sep 17 00:00:00 2001
From: Philipp Schafft <lion@lion.leolix.org>
Date: Sun, 4 Nov 2018 09:39:45 +0000
Subject: [PATCH] Feature: Added type="cors" to <header>.

---
 src/cfgfile.c |  9 ++++++---
 src/cfgfile.h |  4 +++-
 src/util.c    | 28 ++++++++++++++++++++++------
 3 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/src/cfgfile.c b/src/cfgfile.c
index 8f306e1c..539568a7 100644
--- a/src/cfgfile.c
+++ b/src/cfgfile.c
@@ -518,7 +518,8 @@ static void config_clear_http_header(ice_config_http_header_t *header)
 
     while (header) {
         xmlFree(header->name);
-        xmlFree(header->value);
+        if (header->value)
+            xmlFree(header->value);
         old = header;
         header = header->next;
         free(old);
@@ -1664,13 +1665,15 @@ static void _parse_http_headers(xmlDocPtr                   doc,
             continue;
         if (!(name = (char *)xmlGetProp(node, XMLSTR("name"))))
             break;
-        if (!(value = (char *)xmlGetProp(node, XMLSTR("value"))))
-            break;
+
+        value = (char *)xmlGetProp(node, XMLSTR("value"));
 
         type = HTTP_HEADER_TYPE_STATIC; /* default */
         if ((tmp = (char *)xmlGetProp(node, XMLSTR("type")))) {
             if (strcmp(tmp, "static") == 0) {
                 type = HTTP_HEADER_TYPE_STATIC;
+            } else if (strcmp(tmp, "cors") == 0 || strcmp(tmp, "corpse") == 0) {
+                type = HTTP_HEADER_TYPE_CORS;
             } else {
                 ICECAST_LOG_WARN("Unknown type %s for "
                     "HTTP Header %s", tmp, name);
diff --git a/src/cfgfile.h b/src/cfgfile.h
index af7f0e6b..83f01314 100644
--- a/src/cfgfile.h
+++ b/src/cfgfile.h
@@ -32,7 +32,9 @@
 
 typedef enum _http_header_type {
     /* static: headers are passed as is to the client. */
-    HTTP_HEADER_TYPE_STATIC
+    HTTP_HEADER_TYPE_STATIC,
+    /* CORS: headers are only sent to the client if it's a CORS request. */
+    HTTP_HEADER_TYPE_CORS
 } http_header_type;
 
 typedef struct ice_config_http_header_tag {
diff --git a/src/util.c b/src/util.c
index 891717ef..f89afb32 100644
--- a/src/util.c
+++ b/src/util.c
@@ -598,7 +598,7 @@ unsigned int util_str_to_unsigned_int(const char *str, const unsigned int defaul
 }
 
 /* TODO, FIXME: handle memory allocation errors better. */
-static inline void   _build_headers_loop(char **ret, size_t *len, ice_config_http_header_t *header, int status) {
+static inline void   _build_headers_loop(char **ret, size_t *len, ice_config_http_header_t *header, int status, const char *allow, client_t *client) {
     size_t headerlen;
     const char *name;
     const char *value;
@@ -620,7 +620,23 @@ static inline void   _build_headers_loop(char **ret, size_t *len, ice_config_htt
         switch (header->type) {
             case HTTP_HEADER_TYPE_STATIC:
                 value = header->value;
-                break;
+            break;
+            case HTTP_HEADER_TYPE_CORS:
+                if (name && client && client->parser) {
+                    const char *origin = httpp_getvar(client->parser, "origin");
+                    if (origin) {
+                        value = header->value;
+                        if (!value) {
+                            ICECAST_LOG_ERROR("value='%s', name='%s', origin='%s', allow='%s'", value, name, origin, allow);
+                            if (strcasecmp(name, "Access-Control-Allow-Origin") == 0) {
+                                value = origin;
+                            } else if (strcasecmp(name, "Access-Control-Allow-Methods") == 0) {
+                                value = allow;
+                            }
+                        }
+                    }
+                }
+            break;
         }
 
         /* check data */
@@ -644,7 +660,7 @@ static inline void   _build_headers_loop(char **ret, size_t *len, ice_config_htt
     } while ((header = header->next));
     *ret = r;
 }
-static inline char * _build_headers(int status, ice_config_t *config, source_t *source) {
+static inline char * _build_headers(int status, const char *allow, ice_config_t *config, source_t *source, client_t *client) {
     mount_proxy *mountproxy = NULL;
     char *ret = NULL;
     size_t len = 1;
@@ -655,9 +671,9 @@ static inline char * _build_headers(int status, ice_config_t *config, source_t *
     ret = calloc(1, 1);
     *ret = 0;
 
-    _build_headers_loop(&ret, &len, config->http_headers, status);
+    _build_headers_loop(&ret, &len, config->http_headers, status, allow, client);
     if (mountproxy && mountproxy->http_headers)
-        _build_headers_loop(&ret, &len, mountproxy->http_headers, status);
+        _build_headers_loop(&ret, &len, mountproxy->http_headers, status, allow, client);
 
     return ret;
 }
@@ -785,7 +801,7 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
     }
 
     config = config_get_config();
-    extra_headers = _build_headers(status, config, source);
+    extra_headers = _build_headers(status, allow_header, config, source, client);
     ret = snprintf (out, len, "%sServer: %s\r\nConnection: %s\r\nAccept-Encoding: identity\r\nAllow: %s\r\n%s%s%s%s%s%s%s%s",
                               status_buffer,
                               config->server_id,