hush: fix "true | func_with_return" not allowing return.
[oweals/busybox.git] / networking / httpd.c
index 39aad90a8eca29cfe8de72300696fdaa303baadc..079145757dcf265478d37bac87f2eb76e3cd4c8f 100644 (file)
  */
  /* TODO: use TCP_CORK, parse_config() */
 //config:config HTTPD
-//config:      bool "httpd"
+//config:      bool "httpd (32 kb)"
 //config:      default y
 //config:      help
-//config:        HTTP server.
+//config:      HTTP server.
 //config:
 //config:config FEATURE_HTTPD_RANGES
 //config:      bool "Support 'Ranges:' header"
 //config:      default y
 //config:      depends on HTTPD
 //config:      help
-//config:        Makes httpd emit "Accept-Ranges: bytes" header and understand
-//config:        "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted
-//config:        downloads, seeking in multimedia players etc.
+//config:      Makes httpd emit "Accept-Ranges: bytes" header and understand
+//config:      "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted
+//config:      downloads, seeking in multimedia players etc.
 //config:
 //config:config FEATURE_HTTPD_SETUID
 //config:      bool "Enable -u <user> option"
 //config:      default y
 //config:      depends on HTTPD
 //config:      help
-//config:        This option allows the server to run as a specific user
-//config:        rather than defaulting to the user that starts the server.
-//config:        Use of this option requires special privileges to change to a
-//config:        different user.
+//config:      This option allows the server to run as a specific user
+//config:      rather than defaulting to the user that starts the server.
+//config:      Use of this option requires special privileges to change to a
+//config:      different user.
 //config:
 //config:config FEATURE_HTTPD_BASIC_AUTH
-//config:      bool "Enable Basic http Authentication"
+//config:      bool "Enable HTTP authentication"
 //config:      default y
 //config:      depends on HTTPD
 //config:      help
-//config:        Utilizes password settings from /etc/httpd.conf for basic
-//config:        authentication on a per url basis.
-//config:        Example for httpd.conf file:
-//config:        /adm:toor:PaSsWd
+//config:      Utilizes password settings from /etc/httpd.conf for basic
+//config:      authentication on a per url basis.
+//config:      Example for httpd.conf file:
+//config:      /adm:toor:PaSsWd
 //config:
 //config:config FEATURE_HTTPD_AUTH_MD5
-//config:      bool "Support MD5 crypted passwords for http Authentication"
+//config:      bool "Support MD5-encrypted passwords in HTTP authentication"
 //config:      default y
 //config:      depends on FEATURE_HTTPD_BASIC_AUTH
 //config:      help
-//config:        Enables encrypted passwords, and wildcard user/passwords
-//config:        in httpd.conf file.
-//config:        User '*' means 'any system user name is ok',
-//config:        password of '*' means 'use system password for this user'
-//config:        Examples:
-//config:        /adm:toor:$1$P/eKnWXS$aI1aPGxT.dJD5SzqAKWrF0
-//config:        /adm:root:*
-//config:        /wiki:*:*
+//config:      Enables encrypted passwords, and wildcard user/passwords
+//config:      in httpd.conf file.
+//config:      User '*' means 'any system user name is ok',
+//config:      password of '*' means 'use system password for this user'
+//config:      Examples:
+//config:      /adm:toor:$1$P/eKnWXS$aI1aPGxT.dJD5SzqAKWrF0
+//config:      /adm:root:*
+//config:      /wiki:*:*
 //config:
 //config:config FEATURE_HTTPD_CGI
 //config:      bool "Support Common Gateway Interface (CGI)"
 //config:      default y
 //config:      depends on HTTPD
 //config:      help
-//config:        This option allows scripts and executables to be invoked
-//config:        when specific URLs are requested.
+//config:      This option allows scripts and executables to be invoked
+//config:      when specific URLs are requested.
 //config:
 //config:config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
 //config:      bool "Support running scripts through an interpreter"
 //config:      default y
 //config:      depends on FEATURE_HTTPD_CGI
 //config:      help
-//config:        This option enables support for running scripts through an
-//config:        interpreter. Turn this on if you want PHP scripts to work
-//config:        properly. You need to supply an additional line in your
-//config:        httpd.conf file:
-//config:        *.php:/path/to/your/php
+//config:      This option enables support for running scripts through an
+//config:      interpreter. Turn this on if you want PHP scripts to work
+//config:      properly. You need to supply an additional line in your
+//config:      httpd.conf file:
+//config:      *.php:/path/to/your/php
 //config:
 //config:config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
 //config:      bool "Set REMOTE_PORT environment variable for CGI"
 //config:      default y
 //config:      depends on FEATURE_HTTPD_CGI
 //config:      help
-//config:        Use of this option can assist scripts in generating
-//config:        references that contain a unique port number.
+//config:      Use of this option can assist scripts in generating
+//config:      references that contain a unique port number.
 //config:
 //config:config FEATURE_HTTPD_ENCODE_URL_STR
 //config:      bool "Enable -e option (useful for CGIs written as shell scripts)"
 //config:      default y
 //config:      depends on HTTPD
 //config:      help
-//config:        This option allows html encoding of arbitrary strings for display
-//config:        by the browser. Output goes to stdout.
-//config:        For example, httpd -e "<Hello World>" produces
-//config:        "&#60Hello&#32World&#62".
+//config:      This option allows html encoding of arbitrary strings for display
+//config:      by the browser. Output goes to stdout.
+//config:      For example, httpd -e "<Hello World>" produces
+//config:      "&#60Hello&#32World&#62".
 //config:
 //config:config FEATURE_HTTPD_ERROR_PAGES
 //config:      bool "Support custom error pages"
 //config:      default y
 //config:      depends on HTTPD
 //config:      help
-//config:        This option allows you to define custom error pages in
-//config:        the configuration file instead of the default HTTP status
-//config:        error pages. For instance, if you add the line:
-//config:              E404:/path/e404.html
-//config:        in the config file, the server will respond the specified
-//config:        '/path/e404.html' file instead of the terse '404 NOT FOUND'
-//config:        message.
+//config:      This option allows you to define custom error pages in
+//config:      the configuration file instead of the default HTTP status
+//config:      error pages. For instance, if you add the line:
+//config:              E404:/path/e404.html
+//config:      in the config file, the server will respond the specified
+//config:      '/path/e404.html' file instead of the terse '404 NOT FOUND'
+//config:      message.
 //config:
 //config:config FEATURE_HTTPD_PROXY
 //config:      bool "Support reverse proxy"
 //config:      default y
 //config:      depends on HTTPD
 //config:      help
-//config:        This option allows you to define URLs that will be forwarded
-//config:        to another HTTP server. To setup add the following line to the
-//config:        configuration file
-//config:              P:/url/:http://hostname[:port]/new/path/
-//config:        Then a request to /url/myfile will be forwarded to
-//config:        http://hostname[:port]/new/path/myfile.
+//config:      This option allows you to define URLs that will be forwarded
+//config:      to another HTTP server. To setup add the following line to the
+//config:      configuration file
+//config:              P:/url/:http://hostname[:port]/new/path/
+//config:      Then a request to /url/myfile will be forwarded to
+//config:      http://hostname[:port]/new/path/myfile.
 //config:
 //config:config FEATURE_HTTPD_GZIP
 //config:      bool "Support GZIP content encoding"
 //config:      default y
 //config:      depends on HTTPD
 //config:      help
-//config:        Makes httpd send files using GZIP content encoding if the
-//config:        client supports it and a pre-compressed <file>.gz exists.
+//config:      Makes httpd send files using GZIP content encoding if the
+//config:      client supports it and a pre-compressed <file>.gz exists.
 
 //applet:IF_HTTPD(APPLET(httpd, BB_DIR_USR_SBIN, BB_SUID_DROP))
 
@@ -460,11 +460,6 @@ struct globals {
 #define ip_a_d            (G.ip_a_d           )
 #define g_realm           (G.g_realm          )
 #define remoteuser        (G.remoteuser       )
-#define referer           (G.referer          )
-#define user_agent        (G.user_agent       )
-#define host              (G.host             )
-#define http_accept       (G.http_accept      )
-#define http_accept_language (G.http_accept_language)
 #define file_size         (G.file_size        )
 #if ENABLE_FEATURE_HTTPD_RANGES
 #define range_start       (G.range_start      )
@@ -1152,7 +1147,7 @@ static void send_headers(int responseNum)
                        "Last-Modified: %s\r\n"
                        "%s %"OFF_FMT"u\r\n",
                                date_str,
-                               content_gzip ? "Transfer-length:" : "Content-length:",
+                               content_gzip ? "Transfer-Length:" : "Content-Length:",
                                file_size
                );
        }
@@ -1529,11 +1524,11 @@ static void send_cgi_and_exit(
 #endif
                }
        }
-       setenv1("HTTP_USER_AGENT", user_agent);
-       if (http_accept)
-               setenv1("HTTP_ACCEPT", http_accept);
-       if (http_accept_language)
-               setenv1("HTTP_ACCEPT_LANGUAGE", http_accept_language);
+       setenv1("HTTP_USER_AGENT", G.user_agent);
+       if (G.http_accept)
+               setenv1("HTTP_ACCEPT", G.http_accept);
+       if (G.http_accept_language)
+               setenv1("HTTP_ACCEPT_LANGUAGE", G.http_accept_language);
        if (post_len)
                putenv(xasprintf("CONTENT_LENGTH=%d", post_len));
        if (cookie)
@@ -1546,9 +1541,9 @@ static void send_cgi_and_exit(
                putenv((char*)"AUTH_TYPE=Basic");
        }
 #endif
-       if (referer)
-               setenv1("HTTP_REFERER", referer);
-       setenv1("HTTP_HOST", host); /* set to "" if NULL */
+       if (G.referer)
+               setenv1("HTTP_REFERER", G.referer);
+       setenv1("HTTP_HOST", G.host); /* set to "" if NULL */
        /* setenv1("SERVER_NAME", safe_gethostname()); - don't do this,
         * just run "env SERVER_NAME=xyz httpd ..." instead */
 
@@ -2269,10 +2264,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 #if ENABLE_FEATURE_HTTPD_PROXY
                        /* We need 2 more bytes for yet another "\r\n" -
                         * see near fdprintf(proxy_fd...) further below */
-                       if (proxy_entry && (header_ptr - header_buf) < IOBUF_SIZE - 2) {
-                               int len = strlen(iobuf);
-                               if (len > IOBUF_SIZE - (header_ptr - header_buf) - 4)
-                                       len = IOBUF_SIZE - (header_ptr - header_buf) - 4;
+                       if (proxy_entry && (header_ptr - header_buf) < IOBUF_SIZE - 4) {
+                               int len = strnlen(iobuf, IOBUF_SIZE - (header_ptr - header_buf) - 4);
                                memcpy(header_ptr, iobuf, len);
                                header_ptr += len;
                                header_ptr[0] = '\r';
@@ -2283,14 +2276,14 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 
 #if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY
                        /* Try and do our best to parse more lines */
-                       if ((STRNCASECMP(iobuf, "Content-length:") == 0)) {
+                       if ((STRNCASECMP(iobuf, "Content-Length:") == 0)) {
                                /* extra read only for POST */
                                if (prequest != request_GET
 # if ENABLE_FEATURE_HTTPD_CGI
                                 && prequest != request_HEAD
 # endif
                                ) {
-                                       tptr = skip_whitespace(iobuf + sizeof("Content-length:") - 1);
+                                       tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1);
                                        if (!tptr[0])
                                                send_headers_and_exit(HTTP_BAD_REQUEST);
                                        /* not using strtoul: it ignores leading minus! */
@@ -2303,19 +2296,26 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 #endif
 #if ENABLE_FEATURE_HTTPD_CGI
                        else if (STRNCASECMP(iobuf, "Cookie:") == 0) {
-                               cookie = xstrdup(skip_whitespace(iobuf + sizeof("Cookie:")-1));
+                               if (!cookie) /* in case they send millions of these, do not OOM */
+                                       cookie = xstrdup(skip_whitespace(iobuf + sizeof("Cookie:")-1));
                        } else if (STRNCASECMP(iobuf, "Content-Type:") == 0) {
-                               content_type = xstrdup(skip_whitespace(iobuf + sizeof("Content-Type:")-1));
+                               if (!content_type)
+                                       content_type = xstrdup(skip_whitespace(iobuf + sizeof("Content-Type:")-1));
                        } else if (STRNCASECMP(iobuf, "Referer:") == 0) {
-                               referer = xstrdup(skip_whitespace(iobuf + sizeof("Referer:")-1));
+                               if (!G.referer)
+                                       G.referer = xstrdup(skip_whitespace(iobuf + sizeof("Referer:")-1));
                        } else if (STRNCASECMP(iobuf, "User-Agent:") == 0) {
-                               user_agent = xstrdup(skip_whitespace(iobuf + sizeof("User-Agent:")-1));
+                               if (!G.user_agent)
+                                       G.user_agent = xstrdup(skip_whitespace(iobuf + sizeof("User-Agent:")-1));
                        } else if (STRNCASECMP(iobuf, "Host:") == 0) {
-                               host = xstrdup(skip_whitespace(iobuf + sizeof("Host:")-1));
+                               if (!G.host)
+                                       G.host = xstrdup(skip_whitespace(iobuf + sizeof("Host:")-1));
                        } else if (STRNCASECMP(iobuf, "Accept:") == 0) {
-                               http_accept = xstrdup(skip_whitespace(iobuf + sizeof("Accept:")-1));
+                               if (!G.http_accept)
+                                       G.http_accept = xstrdup(skip_whitespace(iobuf + sizeof("Accept:")-1));
                        } else if (STRNCASECMP(iobuf, "Accept-Language:") == 0) {
-                               http_accept_language = xstrdup(skip_whitespace(iobuf + sizeof("Accept-Language:")-1));
+                               if (!G.http_accept_language)
+                                       G.http_accept_language = xstrdup(skip_whitespace(iobuf + sizeof("Accept-Language:")-1));
                        }
 #endif
 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH