Only show "Local support" on templates conditionally:
[privoxy.git] / cgi.c
diff --git a/cgi.c b/cgi.c
index d9d6f28..d5f8770 100644 (file)
--- a/cgi.c
+++ b/cgi.c
@@ -1,4 +1,4 @@
-const char cgi_rcs[] = "$Id: cgi.c,v 1.28 2001/09/19 18:00:37 oes Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.33 2001/10/14 22:28:41 jongfoster Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
@@ -38,6 +38,28 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.28 2001/09/19 18:00:37 oes Exp $";
  *
  * Revisions   :
  *    $Log: cgi.c,v $
+ *    Revision 1.33  2001/10/14 22:28:41  jongfoster
+ *    Fixing stupid typo.
+ *
+ *    Revision 1.32  2001/10/14 22:20:18  jongfoster
+ *    - Changes to CGI dispatching method to match CGI names exactly,
+ *      rather than doing a prefix match.
+ *    - No longer need to count the length of the CGI handler names by hand.
+ *    - Adding new handler for 404 error when disptching a CGI, if none of
+ *      the handlers match.
+ *    - Adding new handlers for CGI actionsfile editor.
+ *
+ *    Revision 1.31  2001/10/10 10:56:39  oes
+ *    Failiure to load template now fatal. Before, the user got a hard-to-understand assertion failure from cgi.c
+ *
+ *    Revision 1.30  2001/10/02 15:30:57  oes
+ *    Introduced show-request cgi
+ *
+ *    Revision 1.29  2001/09/20 15:47:44  steudten
+ *
+ *    Fix BUG: Modify int size to size_t size in fill_template()
+ *     - removes big trouble on machines where sizeof(int) != sizeof(size_t).
+ *
  *    Revision 1.28  2001/09/19 18:00:37  oes
  *     - Deletef time() FIXME (Can't fail under Linux either, if
  *       the argument is guaranteed to be in out address space,
@@ -226,44 +248,55 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.28 2001/09/19 18:00:37 oes Exp $";
 
 const char cgi_h_rcs[] = CGI_H_VERSION;
 
-const struct cgi_dispatcher cgi_dispatcher[] = {
-   { "robots.txt", 
-         10, cgi_robots_txt,  
-         "HIDE Sends a robots.txt file to tell robots to go away." }, 
+static const struct cgi_dispatcher cgi_dispatchers[] = {
+   { "",
+         cgi_default,
+         "Junkbuster main page" },
    { "show-status", 
-         11, cgi_show_status,  
+         cgi_show_status,  
          "Show information about the current configuration" }, 
-   { "show-url-info",
-         13, cgi_show_url_info, 
-         "Show which actions apply to a URL and why"  },
    { "show-version", 
-         12, cgi_show_version,  
+         cgi_show_version,  
          "Show the source code version numbers" }, 
-   { "send-banner",
-         11, cgi_send_banner, 
-         "HIDE Send the transparent or \"Junkbuster\" gif" },
+   { "show-request", 
+         cgi_show_request,  
+         "Show the client's request headers." }, 
+   { "show-url-info",
+         cgi_show_url_info, 
+         "Show which actions apply to a URL and why"  },
 #ifdef FEATURE_CGI_EDIT_ACTIONS
-   { "edit-actions-list",
-         17, cgi_edit_actions_list
+   { "edit-actions",
+         cgi_edit_actions
          "Edit the actions list" },
+#endif /* def FEATURE_CGI_EDIT_ACTIONS */
+
+#ifdef FEATURE_CGI_EDIT_ACTIONS
+   { "edit-actions-for-url",
+         cgi_edit_actions_for_url, 
+         NULL /* Edit the actions for (a) specified URL(s) */ },
+   { "edit-actions-list",
+         cgi_edit_actions_list, 
+         NULL /* Edit the actions list */ },
    { "edit-actions-submit",
-         19, cgi_edit_actions_submit, 
-         "HIDE Change the actions for (a) specified URL(s)" },
-   { "edit-actions",
-         12, cgi_edit_actions, 
-         "HIDE Edit the actions for (a) specified URL(s)" },
+         cgi_edit_actions_submit, 
+         NULL /* Change the actions for (a) specified URL(s) */ },
 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
-   { "",
-         0, cgi_default,
-         "Junkbuster main page" },
-   { NULL, 0, NULL, NULL }
+   { "robots.txt", 
+         cgi_robots_txt,  
+         NULL /* Sends a robots.txt file to tell robots to go away. */ }, 
+   { "send-banner",
+         cgi_send_banner, 
+         NULL /* Send the transparent or \"Junkbuster\" gif */ },
+   { NULL, /* NULL Indicates end of list and default page */
+         cgi_error_404,
+         NULL /* Unknown CGI page */ }
 };
 
 
 /*
  * Some images
  *
- * Hint: You can encode your own GIFs like that:
+ * Hint: You can encode your own GIFs like this:
  * perl -e 'while (read STDIN, $c, 1) { printf("\\%.3o,", unpack("C", $c)); }'
  */
 
@@ -288,16 +321,18 @@ const char image_blank_gif_data[] =
 const int image_blank_gif_length = sizeof(image_blank_gif_data) - 1;
 
 
+static struct http_response *dispatch_known_cgi(struct client_state * csp,
+                                                const char * path);
+
+
 /*********************************************************************
  * 
  * Function    :  dispatch_cgi
  *
  * Description :  Checks if a request URL has either the magical hostname
- *                i.j.b or matches HOME_PAGE_URL/config/. If so, it parses
- *                the (rest of the) path as a cgi name plus query string,
- *                prepares a map that maps CGI parameter names to their values,
- *                initializes the http_response struct, and calls the 
- *                relevant CGI handler function.
+ *                i.j.b or matches HOME_PAGE_URL/config/. If so, it passes
+ *                the (rest of the) path onto dispatch_known_cgi, which
+ *                calls the relevant CGI handler function.
  *
  * Parameters  :
  *          1  :  csp = Current client state (buffers, headers, etc...)
@@ -307,31 +342,40 @@ const int image_blank_gif_length = sizeof(image_blank_gif_data) - 1;
  *********************************************************************/
 struct http_response *dispatch_cgi(struct client_state *csp)
 {
-   char *argstring = NULL;
-   const struct cgi_dispatcher *d;
-   struct map *param_list;
-   struct http_response *rsp;
+   const char *host = csp->http->host;
+   const char *path = csp->http->path;
 
    /*
     * Should we intercept ?
     */
 
    /* Either the host matches CGI_PREFIX_HOST ..*/
-   if (0 == strcmpic(csp->http->host, CGI_PREFIX_HOST))
+   if (   (0 == strcmpic(host, CGI_PREFIX_HOST))
+       && (path[0] == '/') )
    {
-      /* ..then the path will all be for us */
-      argstring = csp->http->path;
+      /* ..then the path will all be for us.  Remove leading '/' */
+      path++;
    }
-   /* Or it's the host part HOME_PAGE_URL, and the path /config ? */
-   else if (   (0 == strcmpic(csp->http->host, HOME_PAGE_URL + 7 ))
-            && (0 == strncmpic(csp->http->path,"/config", 7))
-            && ((csp->http->path[7] == '/') || (csp->http->path[7] == '\0')))
+   /* Or it's the host part HOME_PAGE_URL, and the path /config/ */
+   else if (   (0 == strcmpic(host, HOME_PAGE_URL + 7 ))
+            && (0 == strncmpic(path,"/config", 7)) )
    {
-      /* then it's everything following "/config" */
-      argstring = csp->http->path + 7;
+      /* take everything following "/config" */
+      path += 7;
+      if (*path == '/')
+      {
+         /* skip the forward slash after "/config" */
+         path++;
+      }
+      else if (*path != '\0')
+      {
+         /* wierdness: URL is /configXXX, where XXX is some string */
+         return NULL;
+      }
    }
    else
    {
+      /* Not a CGI */
       return NULL;
    }
 
@@ -339,17 +383,74 @@ struct http_response *dispatch_cgi(struct client_state *csp)
     * This is a CGI call.
     */
 
-   /* Get mem for response or fail*/
-   if (NULL == (rsp = alloc_http_response()))
+   return dispatch_known_cgi(csp, path);
+}
+
+
+/*********************************************************************
+ * 
+ * Function    :  dispatch_known_cgi
+ *
+ * Description :  Processes a CGI once dispatch_cgi has determined that
+ *                it matches one of the magic prefixes. Parses the path
+ *                as a cgi name plus query string, prepares a map that
+ *                maps CGI parameter names to their values, initializes
+ *                the http_response struct, and calls the relevant CGI
+ *                handler function.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *          2  :  path = Path of CGI, with the CGI prefix removed.
+ *                       Should not have a leading "/".
+ *
+ * Returns     :  http_response, or NULL on handler failure or out of
+ *                memory.
+ *
+ *********************************************************************/
+static struct http_response *dispatch_known_cgi(struct client_state * csp,
+                                                const char * path)
+{
+   const struct cgi_dispatcher *d;
+   struct map *param_list;
+   struct http_response *rsp;
+   char *query_args_start;
+   char *path_copy;
+   int result;
+
+   if (NULL == (path_copy = strdup(path)))
    {
       return NULL;
    }
 
+   query_args_start = path_copy;
+   while (*query_args_start && *query_args_start != '?')
+   {
+      query_args_start++;
+   }
+   if (*query_args_start == '?')
+   {
+      *query_args_start++ = '\0';
+   }
+
+   if (NULL == (param_list = parse_cgi_parameters(query_args_start)))
+   {
+      free(path_copy);
+      return(NULL);
+   }
+
 
-   /* Remove leading slash */
-   if (*argstring == '/')
+   /*
+    * At this point:
+    * path_copy        = CGI call name
+    * param_list       = CGI params, as map
+    */
+
+   /* Get mem for response or fail*/
+   if (NULL == (rsp = alloc_http_response()))
    {
-      argstring++;
+      free(path_copy);
+      free_map(param_list);
+      return NULL;
    }
 
    log_error(LOG_LEVEL_GPC, "%s%s cgi call", csp->http->hostport, csp->http->path);
@@ -357,33 +458,26 @@ struct http_response *dispatch_cgi(struct client_state *csp)
                             csp->ip_addr_str, csp->http->cmd); 
 
    /* Find and start the right CGI function*/
-   for (d = cgi_dispatcher; d->handler; d++)
+   for (d = cgi_dispatchers; FOREVER; d++)
    {
-      if (strncmp(argstring, d->name, d->name_length) == 0)
+      if ((d->name == NULL) || (strcmp(path_copy, d->name) == 0))
       {
-         if (NULL == (param_list = 
-             parse_cgi_parameters(argstring + d->name_length)))
+         result = (d->handler)(csp, rsp, param_list);
+         free(path_copy);
+         free_map(param_list);
+         if (result)
          {
-            free_map(param_list);
+            /* Error in handler */
             free_http_response(rsp);
             return(NULL);
          }
-         if ((d->handler)(csp, rsp, param_list))
+         else
          {
-            free_map(param_list);
-            free_http_response(rsp);
-            return(NULL);
+            /* It worked */
+            return(finish_http_response(rsp));
          }
-
-         free_map(param_list);
-         return(finish_http_response(rsp));
       }
    }
-
-   /* Can't get here, since cgi_default will match all requests */
-   free_http_response(rsp);
-   return(NULL);
-
 }
 
 
@@ -395,14 +489,14 @@ struct http_response *dispatch_cgi(struct client_state *csp)
  *                pairs and store them in a struct map list.
  *
  * Parameters  :
- *          1  :  string = string to be parsed 
+ *          1  :  string = string to be parsed.  Will be trashed.
  *
  * Returns     :  pointer to param list, or NULL if out of memory.
  *
  *********************************************************************/
-struct map *parse_cgi_parameters(char *argstring)
+static struct map *parse_cgi_parameters(char *argstring)
 {
-   char *tmp, *p;
+   char *p;
    char *vector[BUFFER_SIZE];
    int pairs, i;
    struct map *cgi_params;
@@ -412,17 +506,7 @@ struct map *parse_cgi_parameters(char *argstring)
       return NULL;
    }
 
-   if(*argstring == '?')
-   {
-      argstring++;
-   }
-   if (NULL == (tmp = strdup(argstring)))
-   {
-      free_map(cgi_params);
-      return NULL;
-   }
-
-   pairs = ssplit(tmp, "&", vector, SZ(vector), 1, 1);
+   pairs = ssplit(argstring, "&", vector, SZ(vector), 1, 1);
 
    for (i = 0; i < pairs; i++)
    {
@@ -433,7 +517,6 @@ struct map *parse_cgi_parameters(char *argstring)
       }
    }
 
-   free(tmp);
    return(cgi_params);
 
 }
@@ -708,7 +791,7 @@ char *template_load(struct client_state *csp, const char *templatename)
 
    if(NULL == (fp = fopen(buf, "r")))
    {
-      log_error(LOG_LEVEL_ERROR, "error loading template %s: %E", buf);
+      log_error(LOG_LEVEL_FATAL, "error loading template %s: %E", buf);
       return NULL;
    }
    
@@ -850,12 +933,12 @@ void template_fill(char **template_ptr, struct map *exports)
 struct map *default_exports(const struct client_state *csp, const char *caller)
 {
    char buf[20];
+   int local_help_exists = 0;
    struct map * exports = new_map();
 
    map(exports, "version", 1, VERSION, 1);
    map(exports, "my-ip-address", 1, csp->my_ip_addr_str ? csp->my_ip_addr_str : "unknown", 1);
    map(exports, "my-hostname", 1, csp->my_hostname ? csp->my_hostname : "unknown", 1);
-   map(exports, "admin-address", 1, csp->config->admin_address ? csp->config->admin_address : "fill@me.in.please", 1);
    map(exports, "homepage", 1, HOME_PAGE_URL, 1);
    map(exports, "default-cgi", 1, HOME_PAGE_URL "/config", 1);
    map(exports, "menu", 1, make_menu(caller), 0);
@@ -869,14 +952,28 @@ struct map *default_exports(const struct client_state *csp, const char *caller)
       map_block_killer(exports, "unstable");
    }
 
+   if(csp->config->admin_address != NULL)
+   {
+      map(exports, "admin-address", 1, csp->config->admin_address, 1);
+      local_help_exists = 1;
+   }
+   else
+   {
+      map_block_killer(exports, "have-adminaddr-info");
+   }
+
    if(csp->config->proxy_info_url != NULL)
    {
       map(exports, "proxy-info-url", 1, csp->config->proxy_info_url, 1);
+      local_help_exists = 1;
    }
    else
    {
       map_block_killer(exports, "have-proxy-info");
-   }   
+   }
+
+   if (local_help_exists == 0)
+      map_block_killer(exports, "have-help-info");
 
    return (exports);
 
@@ -974,9 +1071,9 @@ char *make_menu(const char *self)
    }
 
    /* List available unhidden CGI's and export as "other-cgis" */
-   for (d = cgi_dispatcher; d->handler; d++)
+   for (d = cgi_dispatchers; d->name; d++)
    {
-      if (strncmp(d->description, "HIDE", 4) && strcmp(d->name, self))
+      if (d->description && strcmp(d->name, self))
       {
          snprintf(buf, BUFFER_SIZE, "<li><a href=%s/config/%s>%s</a></li>\n",
               HOME_PAGE_URL, d->name, d->description);