Provide get_http_time() with the buffer size so it doesn't
[privoxy.git] / cgi.c
diff --git a/cgi.c b/cgi.c
index 7ca1d2c..65b6810 100644 (file)
--- a/cgi.c
+++ b/cgi.c
@@ -1,4 +1,4 @@
-const char cgi_rcs[] = "$Id: cgi.c,v 1.90 2007/01/25 13:47:26 fabiankeil Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.104 2008/03/26 18:07:06 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
@@ -38,6 +38,59 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.90 2007/01/25 13:47:26 fabiankeil Exp $";
  *
  * Revisions   :
  *    $Log: cgi.c,v $
+ *    Revision 1.104  2008/03/26 18:07:06  fabiankeil
+ *    Add hostname directive. Closes PR#1918189.
+ *
+ *    Revision 1.103  2008/03/21 11:13:57  fabiankeil
+ *    Only gather host information if it's actually needed.
+ *    Also move the code out of accept_connection() so it's less likely
+ *    to delay other incoming connections if the host is misconfigured.
+ *
+ *    Revision 1.102  2008/02/23 16:33:43  fabiankeil
+ *    Let forward_url() use the standard parameter ordering
+ *    and mark its second parameter immutable.
+ *
+ *    Revision 1.101  2008/02/03 15:45:06  fabiankeil
+ *    Add SOCKS5 support for "Forwarding failure" CGI page.
+ *
+ *    Revision 1.100  2007/10/17 18:40:53  fabiankeil
+ *    - Send CGI pages as HTTP/1.1 unless the client asked for HTTP/1.0.
+ *    - White space fix.
+ *
+ *    Revision 1.99  2007/08/05 13:42:22  fabiankeil
+ *    #1763173 from Stefan Huehner: declare some more functions static.
+ *
+ *    Revision 1.98  2007/05/14 10:33:51  fabiankeil
+ *    - Use strlcpy() and strlcat() instead of strcpy() and strcat().
+ *
+ *    Revision 1.97  2007/04/09 18:11:35  fabiankeil
+ *    Don't mistake VC++'s _snprintf() for a snprintf() replacement.
+ *
+ *    Revision 1.96  2007/03/08 17:41:05  fabiankeil
+ *    Use sizeof() more often.
+ *
+ *    Revision 1.95  2007/02/10 17:01:37  fabiankeil
+ *    Don't overlook map result for the forwarding-type.
+ *
+ *    Revision 1.94  2007/02/08 19:44:49  fabiankeil
+ *    Use a transparent background for the PNG replacement pattern.
+ *
+ *    Revision 1.93  2007/02/07 10:45:22  fabiankeil
+ *    - Save the reason for generating http_responses.
+ *    - Fix --disable-toggle (again).
+ *    - Use TBL birthday hack for 403 responses as well.
+ *    - Uglify the @menu@ again to fix JavaScript
+ *      errors on the "blocked" template.
+ *    - Escape an ampersand in cgi_error_unknown().
+ *
+ *    Revision 1.92  2007/01/28 13:41:17  fabiankeil
+ *    - Add HEAD support to finish_http_response.
+ *    - Add error favicon to internal HTML error messages.
+ *
+ *    Revision 1.91  2007/01/27 13:09:16  fabiankeil
+ *    Add new config option "templdir" to
+ *    change the templates directory.
+ *
  *    Revision 1.90  2007/01/25 13:47:26  fabiankeil
  *    Added "forwarding-failed" template support for error_response().
  *
@@ -558,10 +611,6 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.90 2007/01/25 13:47:26 fabiankeil Exp $";
 #include <limits.h>
 #include <assert.h>
 
-#ifdef _WIN32
-#define snprintf _snprintf
-#endif /* def _WIN32 */
-
 #include "project.h"
 #include "cgi.h"
 #include "list.h"
@@ -571,6 +620,7 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.90 2007/01/25 13:47:26 fabiankeil Exp $";
 #include "filters.h"
 #include "miscutil.h"
 #include "cgisimple.h"
+#include "jbsockets.h"
 #ifdef FEATURE_CGI_EDIT_ACTIONS
 #include "cgiedit.h"
 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
@@ -734,12 +784,12 @@ static const struct cgi_dispatcher cgi_dispatchers[] = {
  */
 const char image_pattern_data[] =
    "\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104"
-   "\122\000\000\000\004\000\000\000\004\010\002\000\000\000\046"
-   "\223\011\051\000\000\000\006\142\113\107\104\000\310\000\310"
-   "\000\310\052\045\225\037\000\000\000\032\111\104\101\124\170"
-   "\332\143\070\161\342\304\377\377\377\041\044\003\234\165\342"
-   "\304\011\006\234\062\000\125\200\052\251\125\174\360\223\000"
-   "\000\000\000\111\105\116\104\256\102\140\202";
+   "\122\000\000\000\004\000\000\000\004\010\006\000\000\000\251"
+   "\361\236\176\000\000\000\006\142\113\107\104\000\000\000\000"
+   "\000\000\371\103\273\177\000\000\000\033\111\104\101\124\010"
+   "\327\143\140\140\140\060\377\377\377\077\003\234\106\341\060"
+   "\060\230\063\020\124\001\000\161\021\031\241\034\364\030\143"
+   "\000\000\000\000\111\105\116\104\256\102\140\202";
 
 /*
  * 1x1 transparant PNG.
@@ -874,7 +924,7 @@ struct http_response *dispatch_cgi(struct client_state *csp)
  * Returns     :  pointer to value (no copy!), or NULL if none found.
  *
  *********************************************************************/
-char *grep_cgi_referrer(const struct client_state *csp)
+static char *grep_cgi_referrer(const struct client_state *csp)
 {
    struct list_entry *p;
 
@@ -906,7 +956,7 @@ char *grep_cgi_referrer(const struct client_state *csp)
  *                FALSE if the referrer is unsafe or not set.
  *
  *********************************************************************/
-int referrer_is_safe (const struct client_state *csp)
+static int referrer_is_safe(const struct client_state *csp)
 {
    char *referrer;
    const char alternative_prefix[] = "http://" CGI_SITE_1_HOST "/";
@@ -1013,10 +1063,6 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
       return cgi_error_memory();
    }
 
-   log_error(LOG_LEVEL_GPC, "%s%s cgi call", csp->http->hostport, csp->http->path);
-   log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", 
-                            csp->ip_addr_str, csp->http->cmd); 
-
    /* 
     * Find and start the right CGI function
     */
@@ -1066,7 +1112,8 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
          if (!err)
          {
             /* It worked */
-            return finish_http_response(rsp);
+            rsp->reason = RSP_REASON_CGI_CALL;
+            return finish_http_response(csp, rsp);
          }
          else
          {
@@ -1353,11 +1400,13 @@ struct http_response *error_response(struct client_state *csp,
       return cgi_error_memory();
    }
 
+#ifdef FEATURE_FORCE_LOAD
    if (csp->flags & CSP_FLAG_FORCED)
    {
       path = strdup(FORCE_PREFIX);
    }
    else
+#endif /* def FEATURE_FORCE_LOAD */
    {
       path = strdup("");
    }
@@ -1395,10 +1444,12 @@ struct http_response *error_response(struct client_state *csp,
          free_http_response(rsp);
          return cgi_error_memory();
       }
+      rsp->reason = RSP_REASON_NO_SUCH_DOMAIN;
    }
    else if (!strcmp(templatename, "forwarding-failed"))
    {
-      const struct forward_spec * fwd = forward_url(csp->http, csp);
+      const struct forward_spec *fwd = forward_url(csp, csp->http);
+      char *socks_type = NULL;
       if (fwd == NULL)
       {
          log_error(LOG_LEVEL_FATAL, "gateway spec is NULL. This shouldn't happen!");
@@ -1424,8 +1475,27 @@ struct http_response *error_response(struct client_state *csp,
          csp->error_message = strdup("Failure reason missing. Check the log file for details.");
       }
       if (!err) err = map(exports, "gateway", 1, fwd->gateway_host, 1);
-      if (!err) map(exports, "forwarding-type", 1, (fwd->type == SOCKS_4) ?
-                   "socks4-" : "socks4a-", 1);
+
+      /*
+       * XXX: this is almost the same code as in cgi_show_url_info()
+       * and thus should be factored out and shared.
+       */
+      switch (fwd->type)
+      {
+         case SOCKS_4:
+            socks_type = "socks4-";
+            break;
+         case SOCKS_4A:
+            socks_type = "socks4a-";
+            break;
+         case SOCKS_5:
+            socks_type = "socks5-";
+            break;
+         default:
+            log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
+      }
+
+      if (!err) err = map(exports, "forwarding-type", 1, socks_type, 1);
       if (!err) err = map(exports, "error-message", 1, html_encode(csp->error_message), 0);
 
       if (!err) rsp->status = strdup("503 Forwarding failure");
@@ -1435,6 +1505,7 @@ struct http_response *error_response(struct client_state *csp,
          free_http_response(rsp);
          return cgi_error_memory();
       }
+      rsp->reason = RSP_REASON_FORWARDING_FAILED;
    }
    else if (!strcmp(templatename, "connect-failed"))
    {
@@ -1445,6 +1516,7 @@ struct http_response *error_response(struct client_state *csp,
          free_http_response(rsp);
          return cgi_error_memory();
       }
+      rsp->reason = RSP_REASON_CONNECT_FAILED;
    }
 
    err = template_fill_for_cgi(csp, templatename, exports, rsp);
@@ -1454,7 +1526,7 @@ struct http_response *error_response(struct client_state *csp,
       return cgi_error_memory();
    }
 
-   return finish_http_response(rsp);
+   return finish_http_response(csp, rsp);
 }
 
 
@@ -1522,7 +1594,10 @@ void cgi_init_error_messages(void)
       "\r\n";
    cgi_error_memory_response->body =
       "<html>\r\n"
-      "<head><title>500 Internal Privoxy Error</title></head>\r\n"
+      "<head>\r\n"
+      " <title>500 Internal Privoxy Error</title>\r\n"
+      " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">"
+      "</head>\r\n"
       "<body>\r\n"
       "<h1>500 Internal Privoxy Error</h1>\r\n"
       "<p>Privoxy <b>ran out of memory</b> while processing your request.</p>\r\n"
@@ -1534,6 +1609,7 @@ void cgi_init_error_messages(void)
       strlen(cgi_error_memory_response->head);
    cgi_error_memory_response->content_length =
       strlen(cgi_error_memory_response->body);
+   cgi_error_memory_response->reason = RSP_REASON_OUT_OF_MEMORY;
 }
 
 
@@ -1586,7 +1662,10 @@ jb_err cgi_error_no_template(struct client_state *csp,
       "500 Internal Privoxy Error";
    static const char body_prefix[] =
       "<html>\r\n"
-      "<head><title>500 Internal Privoxy Error</title></head>\r\n"
+      "<head>\r\n"
+      " <title>500 Internal Privoxy Error</title>\r\n"
+      " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">"
+      "</head>\r\n"
       "<body>\r\n"
       "<h1>500 Internal Privoxy Error</h1>\r\n"
       "<p>Privoxy encountered an error while processing your request:</p>\r\n"
@@ -1605,6 +1684,7 @@ jb_err cgi_error_no_template(struct client_state *csp,
       ").</p>\r\n"
       "</body>\r\n"
       "</html>\r\n";
+   const size_t body_size = strlen(body_prefix) + strlen(template_name) + strlen(body_suffix) + 1;
 
    assert(csp);
    assert(rsp);
@@ -1618,14 +1698,14 @@ jb_err cgi_error_no_template(struct client_state *csp,
    rsp->head_length = 0;
    rsp->is_static = 0;
 
-   rsp->body = malloc(strlen(body_prefix) + strlen(template_name) + strlen(body_suffix) + 1);
+   rsp->body = malloc(body_size);
    if (rsp->body == NULL)
    {
       return JB_ERR_MEMORY;
    }
-   strcpy(rsp->body, body_prefix);
-   strcat(rsp->body, template_name);
-   strcat(rsp->body, body_suffix);
+   strlcpy(rsp->body, body_prefix, body_size);
+   strlcat(rsp->body, template_name, body_size);
+   strlcat(rsp->body, body_suffix, body_size);
 
    rsp->status = strdup(status);
    if (rsp->status == NULL)
@@ -1669,7 +1749,10 @@ jb_err cgi_error_unknown(struct client_state *csp,
       "500 Internal Privoxy Error";
    static const char body_prefix[] =
       "<html>\r\n"
-      "<head><title>500 Internal Privoxy Error</title></head>\r\n"
+      "<head>\r\n"
+      " <title>500 Internal Privoxy Error</title>\r\n"
+      " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">"
+      "</head>\r\n"
       "<body>\r\n"
       "<h1>500 Internal Privoxy Error</h1>\r\n"
       "<p>Privoxy encountered an error while processing your request:</p>\r\n"
@@ -1677,11 +1760,16 @@ jb_err cgi_error_unknown(struct client_state *csp,
    static const char body_suffix[] =
       "</b></p>\r\n"
       "<p>Please "
-      "<a href=\"http://sourceforge.net/tracker/?group_id=11118&atid=111118\">"
+      "<a href=\"http://sourceforge.net/tracker/?group_id=11118&amp;atid=111118\">"
       "file a bug report</a>.</p>\r\n"
       "</body>\r\n"
       "</html>\r\n";
    char errnumbuf[30];
+   /*
+    * Due to sizeof(errnumbuf), body_size will be slightly
+    * bigger than necessary but it doesn't really matter.
+    */
+   const size_t body_size = strlen(body_prefix) + sizeof(errnumbuf) + strlen(body_suffix) + 1;
    assert(csp);
    assert(rsp);
 
@@ -1692,17 +1780,18 @@ jb_err cgi_error_unknown(struct client_state *csp,
    rsp->content_length = 0;
    rsp->head_length = 0;
    rsp->is_static = 0;
+   rsp->reason = RSP_REASON_INTERNAL_ERROR;
 
    snprintf(errnumbuf, sizeof(errnumbuf), "%d", error_to_report);
 
-   rsp->body = malloc(strlen(body_prefix) + strlen(errnumbuf) + strlen(body_suffix) + 1);
+   rsp->body = malloc(body_size);
    if (rsp->body == NULL)
    {
       return JB_ERR_MEMORY;
    }
-   strcpy(rsp->body, body_prefix);
-   strcat(rsp->body, errnumbuf);
-   strcat(rsp->body, body_suffix);
+   strlcpy(rsp->body, body_prefix, body_size);
+   strlcat(rsp->body, errnumbuf,   body_size);
+   strlcat(rsp->body, body_suffix, body_size);
 
    rsp->status = strdup(status);
    if (rsp->status == NULL)
@@ -1846,13 +1935,15 @@ char *add_help_link(const char *item,
  * Parameters  :  
  *          1  :  time_offset = Time returned will be current time
  *                              plus this number of seconds.
- *          2  :  buf = Destination for result.  Must be long enough
- *                      to hold 29 characters plus a trailing zero.
+ *          2  :  buf = Destination for result.
+ *          3  :  buffer_size = Size of the buffer above. Must be big
+ *                              enough to hold 29 characters plus a
+ *                              trailing zero.
  *
  * Returns     :  N/A
  *
  *********************************************************************/
-void get_http_time(int time_offset, char *buf)
+void get_http_time(int time_offset, char *buf, size_t buffer_size)
 {
    static const char day_names[7][4] =
       { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
@@ -1873,6 +1964,7 @@ void get_http_time(int time_offset, char *buf)
 #endif
 
    assert(buf);
+   assert(buffer_size > 29);
 
    time(&current_time); /* get current time */
 
@@ -1892,7 +1984,7 @@ void get_http_time(int time_offset, char *buf)
    }
 
    /* Format: "Sun, 06 Nov 1994 08:49:37 GMT" */
-   snprintf(buf, 30,
+   snprintf(buf, buffer_size,
       "%s, %02d %s %4d %02d:%02d:%02d GMT",
       day_names[t->tm_wday],
       t->tm_mday,
@@ -1912,6 +2004,8 @@ void get_http_time(int time_offset, char *buf)
  *
  * Description :  Fill in the missing headers in an http response,
  *                and flatten the headers to an http head.
+ *                For HEAD requests the body is freed once
+ *                the Content-Length header is set.
  *
  * Parameters  :
  *          1  :  rsp = pointer to http_response to be processed
@@ -1920,7 +2014,7 @@ void get_http_time(int time_offset, char *buf)
  *                On error, free()s rsp and returns cgi_error_memory()
  *
  *********************************************************************/
-struct http_response *finish_http_response(struct http_response *rsp)
+struct http_response *finish_http_response(const struct client_state *csp, struct http_response *rsp)
 {
    char buf[BUFFER_SIZE];
    jb_err err;
@@ -1934,9 +2028,12 @@ struct http_response *finish_http_response(struct http_response *rsp)
    }
 
    /* 
-    * Fill in the HTTP Status
+    * Fill in the HTTP Status, using HTTP/1.1
+    * unless the client asked for HTTP/1.0.
     */
-   snprintf(buf, sizeof(buf), "HTTP/1.0 %s", rsp->status ? rsp->status : "200 OK");
+   snprintf(buf, sizeof(buf), "%s %s",
+      strcmpic(csp->http->ver, "HTTP/1.0") ? "HTTP/1.1" : "HTTP/1.0",
+      rsp->status ? rsp->status : "200 OK");
    err = enlist_first(rsp->headers, buf);
 
    /* 
@@ -1952,14 +2049,32 @@ struct http_response *finish_http_response(struct http_response *rsp)
       err = enlist(rsp->headers, buf);
    }
 
+   if (0 == strcmpic(csp->http->gpc, "head"))
+   {
+      /*
+       * The client only asked for the head. Dispose
+       * the body and log an offensive message.
+       *
+       * While it may seem to be a bit inefficient to
+       * prepare the body if it isn't needed, it's the
+       * only way to get the Content-Length right for
+       * dynamic pages. We could have disposed the body
+       * earlier, but not without duplicating the
+       * Content-Length setting code above.
+       */
+      log_error(LOG_LEVEL_CGI, "Preparing to give head to %s.", csp->ip_addr_str);
+      freez(rsp->body);
+      rsp->content_length = 0;
+   }
+
    if (strncmpic(rsp->status, "302", 3))
    {
-     /*
-      * If it's not a redirect without any content,
-      * set the Content-Type to text/html if it's
-      * not already specified.
-      */
-     if (!err) err = enlist_unique(rsp->headers, "Content-Type: text/html", 13);
+      /*
+       * If it's not a redirect without any content,
+       * set the Content-Type to text/html if it's
+       * not already specified.
+       */
+      if (!err) err = enlist_unique(rsp->headers, "Content-Type: text/html", 13);
    }
 
    /*
@@ -1981,7 +2096,7 @@ struct http_response *finish_http_response(struct http_response *rsp)
 
       if (!err)
       {
-         get_http_time(0, buf);
+         get_http_time(0, buf, sizeof(buf));
          err = enlist_unique_header(rsp->headers, "Date", buf);
       }
 
@@ -1990,13 +2105,13 @@ struct http_response *finish_http_response(struct http_response *rsp)
 
       if (!err)
       {
-         get_http_time(10 * 60, buf); /* 10 * 60sec = 10 minutes */
+         get_http_time(10 * 60, buf, sizeof(buf)); /* 10 * 60sec = 10 minutes */
          err = enlist_unique_header(rsp->headers, "Expires", buf);
       }
    }
    else if (!strncmpic(rsp->status, "302", 3))
    {
-      get_http_time(0, buf);
+      get_http_time(0, buf, sizeof(buf));
       if (!err) err = enlist_unique_header(rsp->headers, "Date", buf);
    }
    else
@@ -2013,7 +2128,7 @@ struct http_response *finish_http_response(struct http_response *rsp)
        * is older than Privoxy's error message, the server would send status code
        * 304 and the browser would display the outdated error message again and again.
        *
-       * For documents delivered with status code 404 or 503 we set "Last-Modified"
+       * For documents delivered with status code 403, 404 and 503 we set "Last-Modified"
        * to Tim Berners-Lee's birthday, which predates the age of any page on the web
        * and can be safely used to "revalidate" without getting a status code 304.
        *
@@ -2022,9 +2137,11 @@ struct http_response *finish_http_response(struct http_response *rsp)
        */
       if (!err) err = enlist_unique_header(rsp->headers, "Cache-Control", "no-cache");
 
-      get_http_time(0, buf);
+      get_http_time(0, buf, sizeof(buf));
       if (!err) err = enlist_unique_header(rsp->headers, "Date", buf);
-      if (!strncmpic(rsp->status, "404", 3) || !strncmpic(rsp->status, "503", 3))
+      if (!strncmpic(rsp->status, "403", 3)
+       || !strncmpic(rsp->status, "404", 3)
+       || !strncmpic(rsp->status, "503", 3))
       {
          if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", "Wed, 08 Jun 1955 12:00:00 GMT");
       }
@@ -2457,6 +2574,8 @@ struct map *default_exports(const struct client_state *csp, const char *caller)
    jb_err err;
    struct map * exports;
    int local_help_exists = 0;
+   char *ip_address = NULL;
+   char *hostname = NULL;
 
    assert(csp);
 
@@ -2466,9 +2585,21 @@ struct map *default_exports(const struct client_state *csp, const char *caller)
       return NULL;
    }
 
+   if (csp->config->hostname)
+   {
+      get_host_information(csp->cfd, &ip_address, NULL);
+      hostname = strdup(csp->config->hostname);
+   }
+   else
+   {
+      get_host_information(csp->cfd, &ip_address, &hostname);
+   }
+
    err = map(exports, "version", 1, html_encode(VERSION), 0);
-   if (!err) err = map(exports, "my-ip-address", 1, html_encode(csp->my_ip_addr_str ? csp->my_ip_addr_str : "unknown"), 0);
-   if (!err) err = map(exports, "my-hostname",   1, html_encode(csp->my_hostname ? csp->my_hostname : "unknown"), 0);
+   if (!err) err = map(exports, "my-ip-address", 1, html_encode(ip_address ? ip_address : "unknown"), 0);
+   freez(ip_address);
+   if (!err) err = map(exports, "my-hostname",   1, html_encode(hostname ? hostname : "unknown"), 0);
+   freez(hostname);
    if (!err) err = map(exports, "homepage",      1, html_encode(HOME_PAGE_URL), 0);
    if (!err) err = map(exports, "default-cgi",   1, html_encode(CGI_PREFIX), 0);
    if (!err) err = map(exports, "menu",          1, make_menu(caller, csp->config->feature_flags), 0);
@@ -2491,7 +2622,7 @@ struct map *default_exports(const struct client_state *csp, const char *caller)
    if (!err) err = map_block_killer(exports, "can-toggle");
 #endif
 
-   snprintf(buf, 20, "%d", csp->config->hport);
+   snprintf(buf, sizeof(buf), "%d", csp->config->hport);
    if (!err) err = map(exports, "my-port", 1, buf, 1);
 
    if(!strcmp(CODE_STATUS, "stable"))
@@ -2560,7 +2691,7 @@ jb_err map_block_killer(struct map *exports, const char *name)
    assert(name);
    assert(strlen(name) < 490);
 
-   snprintf(buf, 1000, "if-%s-start.*if-%s-end", name, name);
+   snprintf(buf, sizeof(buf), "if-%s-start.*if-%s-end", name, name);
    return map(exports, buf, 1, "", 1);
 }
 
@@ -2590,7 +2721,7 @@ jb_err map_block_keep(struct map *exports, const char *name)
    assert(name);
    assert(strlen(name) < 490);
 
-   snprintf(buf, 500, "if-%s-start", name);
+   snprintf(buf, sizeof(buf), "if-%s-start", name);
    err = map(exports, buf, 1, "", 1);
 
    if (err)
@@ -2598,7 +2729,7 @@ jb_err map_block_keep(struct map *exports, const char *name)
       return err;
    }
 
-   snprintf(buf, 500, "if-%s-end", name);
+   snprintf(buf, sizeof(buf), "if-%s-end", name);
    return map(exports, buf, 1, "", 1);
 }
 
@@ -2637,7 +2768,7 @@ jb_err map_conditional(struct map *exports, const char *name, int choose_first)
    assert(name);
    assert(strlen(name) < 480);
 
-   snprintf(buf, 1000, (choose_first
+   snprintf(buf, sizeof(buf), (choose_first
       ? "else-not-%s@.*@endif-%s"
       : "if-%s-then@.*@else-not-%s"),
       name, name);
@@ -2648,7 +2779,7 @@ jb_err map_conditional(struct map *exports, const char *name, int choose_first)
       return err;
    }
 
-   snprintf(buf, 1000, (choose_first ? "if-%s-then" : "endif-%s"), name);
+   snprintf(buf, sizeof(buf), (choose_first ? "if-%s-then" : "endif-%s"), name);
    return map(exports, buf, 1, "", 1);
 }
 
@@ -2698,6 +2829,10 @@ char *make_menu(const char *self, const unsigned feature_flags)
       {
          char *html_encoded_prefix;
 
+         /*
+          * Line breaks would be great, but break
+          * the "blocked" template's JavaScript.
+          */
          string_append(&result, "<li><a href=\"");
          html_encoded_prefix = html_encode(CGI_PREFIX);
          if (html_encoded_prefix == NULL)
@@ -2712,7 +2847,7 @@ char *make_menu(const char *self, const unsigned feature_flags)
          string_append(&result, d->name);
          string_append(&result, "\">");
          string_append(&result, d->description);
-         string_append(&result, "</a></li>\n");
+         string_append(&result, "</a></li>");
       }
    }