Add "Cross-origin resource sharing" (CORS) support
[privoxy.git] / cgi.c
diff --git a/cgi.c b/cgi.c
index 759517d..c67aed4 100644 (file)
--- a/cgi.c
+++ b/cgi.c
@@ -1,4 +1,3 @@
-const char cgi_rcs[] = "$Id: cgi.c,v 1.162 2016/03/17 10:40:53 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
@@ -8,8 +7,8 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.162 2016/03/17 10:40:53 fabiankeil Exp $"
  *                This only contains the framework functions, the
  *                actual handler functions are declared elsewhere.
  *
- * Copyright   :  Written by and Copyright (C) 2001-2004, 2006-2008
- *                the SourceForge Privoxy team. http://www.privoxy.org/
+ * Copyright   :  Written by and Copyright (C) 2001-2017
+ *                members of the Privoxy team. http://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
  *                by and Copyright (C) 1997 Anonymous Coders and
@@ -69,8 +68,6 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.162 2016/03/17 10:40:53 fabiankeil Exp $"
 /* jcc.h is for mutex semaphore globals only */
 #include "jcc.h"
 
-const char cgi_h_rcs[] = CGI_H_VERSION;
-
 /*
  * List of CGI functions: name, handler, description
  * Note: Do NOT use single quotes in the description;
@@ -96,15 +93,16 @@ static const struct cgi_dispatcher cgi_dispatchers[] = {
         "View the current configuration",
 #endif
          TRUE },
-   { "show-version",
-         cgi_show_version,
-         "View the source code version numbers",
-          TRUE },
 #ifdef FEATURE_CLIENT_TAGS
-   { "show-client-tags",
+   /*
+    * This is marked as harmless because despite the description
+    * used in the menu the actual toggling is done through another
+    * path ("/toggle-client-tag").
+    */
+   { "client-tags",
          cgi_show_client_tags,
          "View or toggle the tags that can be set based on the clients address",
-          FALSE },
+         TRUE },
 #endif
    { "show-request",
          cgi_show_request,
@@ -120,6 +118,12 @@ static const struct cgi_dispatcher cgi_dispatchers[] = {
          "Toggle Privoxy on or off",
          FALSE },
 #endif /* def FEATURE_TOGGLE */
+#ifdef FEATURE_CLIENT_TAGS
+   { "toggle-client-tag",
+         cgi_toggle_client_tag,
+         NULL,
+         FALSE },
+#endif
 #ifdef FEATURE_CGI_EDIT_ACTIONS
    { "edit-actions", /* Edit the actions list */
          cgi_edit_actions,
@@ -430,6 +434,7 @@ static int referrer_is_safe(const struct client_state *csp)
 {
    char *referrer;
    static const char alternative_prefix[] = "http://" CGI_SITE_1_HOST "/";
+   const char *trusted_cgi_referrer = csp->config->trusted_cgi_referrer;
 
    referrer = grep_cgi_referrer(csp);
 
@@ -448,6 +453,18 @@ static int referrer_is_safe(const struct client_state *csp)
 
       return TRUE;
    }
+   else if ((trusted_cgi_referrer != NULL) && (0 == strncmp(referrer,
+            trusted_cgi_referrer, strlen(trusted_cgi_referrer))))
+   {
+      /*
+       * After some more testing this block should be merged with
+       * the previous one or the log level should bedowngraded.
+       */
+      log_error(LOG_LEVEL_INFO, "Granting access to %s based on trusted referrer %s",
+         csp->http->url, referrer);
+
+      return TRUE;
+   }
    else
    {
       /* Untrustworthy referrer */
@@ -1040,6 +1057,8 @@ jb_err cgi_error_disabled(const struct client_state *csp,
    assert(csp);
    assert(rsp);
 
+   rsp->status = strdup_or_die("403 Request not trusted or feature disabled");
+
    if (NULL == (exports = default_exports(csp, "cgi-error-disabled")))
    {
       return JB_ERR_MEMORY;
@@ -1566,6 +1585,18 @@ struct http_response *finish_http_response(struct client_state *csp, struct http
       return rsp;
    }
 
+   /*
+    * Add "Cross-origin resource sharing" (CORS) headers if enabled
+    */
+   if (NULL != csp->config->cors_allowed_origin)
+   {
+      enlist_unique_header(rsp->headers, "Access-Control-Allow-Origin",
+         strdup_or_die(csp->config->cors_allowed_origin));
+      enlist_unique_header(rsp->headers, "Access-Control-Allow-Methods", "GET,POST");
+      enlist_unique_header(rsp->headers, "Access-Control-Allow-Headers", "X-Requested-With");
+      enlist_unique_header(rsp->headers, "Access-Control-Max-Age", "86400");
+   }
+
    /*
     * Fill in the HTTP Status, using HTTP/1.1
     * unless the client asked for HTTP/1.0.
@@ -2100,15 +2131,12 @@ jb_err template_fill_for_cgi(const struct client_state *csp,
    err = template_load(csp, &rsp->body, templatename, 0);
    if (err == JB_ERR_FILE)
    {
-      free_map(exports);
-      return cgi_error_no_template(csp, rsp, templatename);
+      err = cgi_error_no_template(csp, rsp, templatename);
    }
-   else if (err)
+   else if (err == JB_ERR_OK)
    {
-      free_map(exports);
-      return err; /* JB_ERR_MEMORY */
+      err = template_fill(&rsp->body, exports);
    }
-   err = template_fill(&rsp->body, exports);
    free_map(exports);
    return err;
 }