pcrs_compile_replacement(): Silence a coverity warning (CID #161203)
[privoxy.git] / cgi.c
diff --git a/cgi.c b/cgi.c
index 556aa43..5b5d16f 100644 (file)
--- a/cgi.c
+++ b/cgi.c
@@ -1,4 +1,4 @@
-const char cgi_rcs[] = "$Id: cgi.c,v 1.151 2012/06/08 15:07:53 fabiankeil Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.164 2016/04/04 10:55:47 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
@@ -100,6 +100,12 @@ static const struct cgi_dispatcher cgi_dispatchers[] = {
          cgi_show_version,
          "View the source code version numbers",
           TRUE },
+#ifdef FEATURE_CLIENT_TAGS
+   { "client-tags",
+         cgi_show_client_tags,
+         "View or toggle the tags that can be set based on the clients address",
+          FALSE },
+#endif
    { "show-request",
          cgi_show_request,
          "View the request headers",
@@ -346,6 +352,21 @@ struct http_response *dispatch_cgi(struct client_state *csp)
       return NULL;
    }
 
+   if (strcmpic(csp->http->gpc, "GET")
+    && strcmpic(csp->http->gpc, "HEAD"))
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "CGI request with unsupported method received: %s", csp->http->gpc);
+      /*
+       * The CGI pages currently only support GET and HEAD requests.
+       *
+       * If the client used a different method, ditch any data following
+       * the current headers to reduce the likelihood of parse errors
+       * with the following request.
+       */
+      csp->client_iob->eod = csp->client_iob->cur;
+   }
+
    /*
     * This is a CGI call.
     */
@@ -480,9 +501,12 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
    if (*query_args_start == '/')
    {
       *query_args_start++ = '\0';
-      if ((param_list = new_map()))
-      {
-         map(param_list, "file", 1, url_decode(query_args_start), 0);
+      param_list = new_map();
+      err = map(param_list, "file", 1, url_decode(query_args_start), 0);
+      if (JB_ERR_OK != err) {
+         free(param_list);
+         free(path_copy);
+         return cgi_error_memory();
       }
    }
    else
@@ -614,18 +638,9 @@ static struct map *parse_cgi_parameters(char *argstring)
        */
       max_segments = 1;
    }
-   vector = malloc(max_segments * sizeof(char *));
-
-   if (NULL == vector)
-   {
-      return NULL;
-   }
+   vector = malloc_or_die(max_segments * sizeof(char *));
 
-   if (NULL == (cgi_params = new_map()))
-   {
-      freez(vector);
-      return NULL;
-   }
+   cgi_params = new_map();
 
    /*
     * IE 5 does, of course, violate RFC 2316 Sect 4.1 and sends
@@ -637,7 +652,7 @@ static struct map *parse_cgi_parameters(char *argstring)
       *p = '\0';
    }
 
-   pairs = ssplit(argstring, "&", vector, max_segments, 1, 1);
+   pairs = ssplit(argstring, "&", vector, max_segments);
    assert(pairs != -1);
    if (pairs == -1)
    {
@@ -798,8 +813,7 @@ jb_err get_number_param(struct client_state *csp,
                         unsigned *pvalue)
 {
    const char *param;
-   char ch;
-   unsigned value;
+   char *endptr;
 
    assert(csp);
    assert(parameters);
@@ -814,36 +828,12 @@ jb_err get_number_param(struct client_state *csp,
       return JB_ERR_CGI_PARAMS;
    }
 
-   /* We don't use atoi because I want to check this carefully... */
-
-   value = 0;
-   while ((ch = *param++) != '\0')
+   *pvalue = (unsigned int)strtol(param, &endptr, 0);
+   if (*endptr != '\0')
    {
-      if ((ch < '0') || (ch > '9'))
-      {
-         return JB_ERR_CGI_PARAMS;
-      }
-
-      ch = (char)(ch - '0');
-
-      /* Note:
-       *
-       * <limits.h> defines UINT_MAX
-       *
-       * (UINT_MAX - ch) / 10 is the largest number that
-       *     can be safely multiplied by 10 then have ch added.
-       */
-      if (value > ((UINT_MAX - (unsigned)ch) / 10U))
-      {
-         return JB_ERR_CGI_PARAMS;
-      }
-
-      value = value * 10 + (unsigned)ch;
+      return JB_ERR_CGI_PARAMS;
    }
 
-   /* Success */
-   *pvalue = value;
-
    return JB_ERR_OK;
 
 }
@@ -968,6 +958,9 @@ struct http_response *error_response(struct client_state *csp,
          case SOCKS_5:
             socks_type = "socks5-";
             break;
+         case SOCKS_5T:
+            socks_type = "socks5t-";
+            break;
          default:
             log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
       }
@@ -1186,11 +1179,7 @@ jb_err cgi_error_no_template(const struct client_state *csp,
    rsp->head_length = 0;
    rsp->is_static = 0;
 
-   rsp->body = malloc(body_size);
-   if (rsp->body == NULL)
-   {
-      return JB_ERR_MEMORY;
-   }
+   rsp->body = malloc_or_die(body_size);
    strlcpy(rsp->body, body_prefix, body_size);
    strlcat(rsp->body, template_name, body_size);
    strlcat(rsp->body, body_suffix, body_size);
@@ -1266,11 +1255,7 @@ jb_err cgi_error_unknown(const struct client_state *csp,
    rsp->is_static = 0;
    rsp->crunch_reason = INTERNAL_ERROR;
 
-   rsp->body = malloc(body_size);
-   if (rsp->body == NULL)
-   {
-      return JB_ERR_MEMORY;
-   }
+   rsp->body = malloc_or_die(body_size);
 
    snprintf(rsp->body, body_size, "%s%d%s", body_prefix, error_to_report, body_suffix);
 
@@ -1391,7 +1376,7 @@ char *add_help_link(const char *item,
    }
    else
    {
-      string_append(&result, "http://");
+      string_append(&result, "https://");
       string_append(&result, CGI_SITE_2_HOST);
       string_append(&result, "/user-manual/");
    }
@@ -1528,12 +1513,7 @@ char *compress_buffer(char *buffer, size_t *buffer_length, int compression_level
    /* Let zlib figure out the maximum length of the compressed data */
    new_length = compressBound((uLongf)*buffer_length);
 
-   compressed_buffer = malloc(new_length);
-   if (NULL == compressed_buffer)
-   {
-      log_error(LOG_LEVEL_FATAL,
-         "Out of memory allocation compression buffer.");
-   }
+   compressed_buffer = malloc_or_die(new_length);
 
    if (Z_OK != compress2((Bytef *)compressed_buffer, &new_length,
          (Bytef *)buffer, *buffer_length, compression_level))
@@ -1573,7 +1553,7 @@ char *compress_buffer(char *buffer, size_t *buffer_length, int compression_level
  *                On error, free()s rsp and returns cgi_error_memory()
  *
  *********************************************************************/
-struct http_response *finish_http_response(const struct client_state *csp, struct http_response *rsp)
+struct http_response *finish_http_response(struct client_state *csp, struct http_response *rsp)
 {
    char buf[BUFFER_SIZE];
    jb_err err;
@@ -1623,6 +1603,11 @@ struct http_response *finish_http_response(const struct client_state *csp, struc
    if (!err)
    {
       snprintf(buf, sizeof(buf), "Content-Length: %d", (int)rsp->content_length);
+      /*
+       * Signal serve() that the client will be able to figure out
+       * the end of the response without having to close the connection.
+       */
+      csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET;
       err = enlist(rsp->headers, buf);
    }
 
@@ -1732,7 +1717,8 @@ struct http_response *finish_http_response(const struct client_state *csp, struc
       if (!err) err = enlist_unique_header(rsp->headers, "Pragma", "no-cache");
    }
 
-   if (!err && !(csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE))
+   if (!err && (!(csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)
+              || (csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)))
    {
       err = enlist_unique_header(rsp->headers, "Connection", "close");
    }
@@ -2156,10 +2142,6 @@ struct map *default_exports(const struct client_state *csp, const char *caller)
    assert(csp);
 
    exports = new_map();
-   if (exports == NULL)
-   {
-      return NULL;
-   }
 
    if (csp->config->hostname)
    {