aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-12-20 13:45:32 +0000
committerRon Yorston <rmy@pobox.com>2023-12-20 13:59:17 +0000
commit8d85a4a5be88931978fad594b94e762313d37afc (patch)
tree0f964f6cd9b0c71b02de5011a2f815e1470c8740 /networking
parent4f9b703c31e6360d1e7ffe7d3410e42e5118b4fd (diff)
downloadbusybox-w32-8d85a4a5be88931978fad594b94e762313d37afc.tar.gz
busybox-w32-8d85a4a5be88931978fad594b94e762313d37afc.tar.bz2
busybox-w32-8d85a4a5be88931978fad594b94e762313d37afc.zip
httpd: enable support for CGI
The upstream code uses fork/exec when running a CGI process. Emulate this by: - Spawning a child httpd process with the special '-I 0' option, along with the options provided on the server command line. This sets up the proper state then calls the cgi_handler() function. - The cgi_handler() function fixes the pipe file descriptors and starts another child process to run the CGI script. These processes are detached from the console on creation. When spawn() functions are run in P_DETACH mode they don't connect to the standard file descriptors. Normally this doesn't matter but the process which runs the CGI scripts needs to inherit the pipe endpoints. The create_detached_process() function handles this. See: https://github.com/rprichard/win32-console-docs/blob/master/README.md Adds about 2.9Kb to the size of the binary. (GitHub issue #266)
Diffstat (limited to 'networking')
-rw-r--r--networking/httpd.c117
1 files changed, 110 insertions, 7 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index 0de56a47a..d049e3842 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -461,6 +461,13 @@ static const struct {
461 461
462struct globals { 462struct globals {
463 int verbose; /* must be int (used by getopt32) */ 463 int verbose; /* must be int (used by getopt32) */
464#if ENABLE_PLATFORM_MINGW32
465 smallint foreground;
466# if ENABLE_FEATURE_HTTPD_CGI
467 int server_argc;
468 char **server_argv;
469# endif
470#endif
464 smallint flg_deny_all; 471 smallint flg_deny_all;
465#if ENABLE_FEATURE_HTTPD_GZIP 472#if ENABLE_FEATURE_HTTPD_GZIP
466 /* client can handle gzip / we are going to send gzip */ 473 /* client can handle gzip / we are going to send gzip */
@@ -518,6 +525,11 @@ struct globals {
518}; 525};
519#define G (*ptr_to_globals) 526#define G (*ptr_to_globals)
520#define verbose (G.verbose ) 527#define verbose (G.verbose )
528#if ENABLE_PLATFORM_MINGW32
529#define foreground (G.foreground )
530#define server_argc (G.server_argc )
531#define server_argv (G.server_argv )
532#endif
521#define flg_deny_all (G.flg_deny_all ) 533#define flg_deny_all (G.flg_deny_all )
522#if ENABLE_FEATURE_HTTPD_GZIP 534#if ENABLE_FEATURE_HTTPD_GZIP
523# define content_gzip (G.content_gzip ) 535# define content_gzip (G.content_gzip )
@@ -1563,6 +1575,52 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1563#endif 1575#endif
1564 1576
1565#if ENABLE_FEATURE_HTTPD_CGI 1577#if ENABLE_FEATURE_HTTPD_CGI
1578# if ENABLE_PLATFORM_MINGW32
1579static void cgi_handler(char **argv)
1580{
1581 struct fd_pair fromCgi; /* CGI -> httpd pipe */
1582 struct fd_pair toCgi; /* httpd -> CGI pipe */
1583 char *dir, *script;
1584
1585 xfunc_error_retval = 242;
1586
1587 if (sscanf(argv[0], "%d:%d:%d:%d", &toCgi.wr, &toCgi.rd,
1588 &fromCgi.wr, &fromCgi.rd) != 4) {
1589 exit(242);
1590 }
1591
1592 /* NB: close _first_, then move fds! */
1593 close(toCgi.wr);
1594 close(fromCgi.rd);
1595 xmove_fd(toCgi.rd, 0); /* replace stdin with the pipe */
1596 xmove_fd(fromCgi.wr, 1); /* replace stdout with the pipe */
1597
1598 dir = argv[1];
1599 script = argv[2];
1600
1601 if (chdir_or_warn(dir) != 0) {
1602 goto error_execing_cgi;
1603 }
1604
1605 /* set argv[0] to name without path */
1606 argv[0] = script;
1607 argv[1] = NULL;
1608
1609 /* _NOT_ execvp. We do not search PATH. argv[0] is a filename
1610 * without any dir components and will only match a file
1611 * in the current directory */
1612 if (foreground)
1613 execv(argv[0], argv);
1614 else
1615 httpd_execv_detach(argv[0], argv);
1616 if (verbose)
1617 bb_perror_msg("can't execute '%s'", argv[0]);
1618 error_execing_cgi:
1619 /* send to stdout */
1620 iobuf = xmalloc(IOBUF_SIZE);
1621 send_headers_and_exit(HTTP_NOT_FOUND);
1622}
1623# endif
1566 1624
1567static void setenv1(const char *name, const char *value) 1625static void setenv1(const char *name, const char *value)
1568{ 1626{
@@ -1596,6 +1654,10 @@ static void send_cgi_and_exit(
1596 struct fd_pair toCgi; /* httpd -> CGI pipe */ 1654 struct fd_pair toCgi; /* httpd -> CGI pipe */
1597 char *script, *last_slash; 1655 char *script, *last_slash;
1598 int pid; 1656 int pid;
1657#if ENABLE_PLATFORM_MINGW32
1658 char **argv;
1659 int i;
1660#endif
1599 1661
1600 /* Make a copy. NB: caller guarantees: 1662 /* Make a copy. NB: caller guarantees:
1601 * url[0] == '/', url[1] != '/' */ 1663 * url[0] == '/', url[1] != '/' */
@@ -1682,6 +1744,32 @@ static void send_cgi_and_exit(
1682 xpiped_pair(fromCgi); 1744 xpiped_pair(fromCgi);
1683 xpiped_pair(toCgi); 1745 xpiped_pair(toCgi);
1684 1746
1747#if ENABLE_PLATFORM_MINGW32
1748 /* Find script's dir */
1749 script = last_slash;
1750 if (script != url) { /* paranoia */
1751 *script = '\0';
1752 }
1753 script++;
1754
1755 argv = xzalloc((server_argc + 9) * sizeof(char *));
1756 argv[0] = (char *)bb_busybox_exec_path;
1757 argv[1] = (char *)"--busybox";
1758 argv[2] = (char *)"-httpd" + 1; // skip '-'
1759 argv[3] = (char *)"-I";
1760 argv[4] = (char *)"0";
1761 for (i = 0; i < server_argc; ++i)
1762 argv[i + 5] = server_argv[i];
1763 argv[server_argc + 5] = xasprintf("%d:%d:%d:%d", toCgi.wr, toCgi.rd,
1764 fromCgi.wr, fromCgi.rd);
1765 argv[server_argc + 6] = (char *)url + 1; // script directory
1766 argv[server_argc + 7] = (char *)script; // script name
1767 /* argv[server_argc + 8] = NULL; - xzalloc did it */
1768
1769 pid = foreground ? mingw_spawn(argv) : mingw_spawn_detach(argv);
1770 if (pid == -1)
1771 log_and_exit();
1772#else
1685 pid = vfork(); 1773 pid = vfork();
1686 if (pid < 0) { 1774 if (pid < 0) {
1687 /* TODO: log perror? */ 1775 /* TODO: log perror? */
@@ -1759,6 +1847,7 @@ static void send_cgi_and_exit(
1759 1847
1760 /* Restore variables possibly changed by child */ 1848 /* Restore variables possibly changed by child */
1761 xfunc_error_retval = 0; 1849 xfunc_error_retval = 0;
1850#endif
1762 1851
1763 /* Pump data */ 1852 /* Pump data */
1764 close(fromCgi.wr); 1853 close(fromCgi.wr);
@@ -2797,8 +2886,8 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv)
2797} 2886}
2798#endif 2887#endif
2799#else /* ENABLE_PLATFORM_MINGW32 */ 2888#else /* ENABLE_PLATFORM_MINGW32 */
2800static void mini_httpd_win32(int fg, int sock, int argc, char **argv) NORETURN; 2889static void mini_httpd_win32(int sock, int argc, char **argv) NORETURN;
2801static void mini_httpd_win32(int fg, int sock, int argc, char **argv) 2890static void mini_httpd_win32(int sock, int argc, char **argv)
2802{ 2891{
2803 char *argv_copy[argc + 5]; 2892 char *argv_copy[argc + 5];
2804 2893
@@ -2820,7 +2909,8 @@ static void mini_httpd_win32(int fg, int sock, int argc, char **argv)
2820 setsockopt_keepalive(n); 2909 setsockopt_keepalive(n);
2821 2910
2822 argv_copy[4] = itoa(n); 2911 argv_copy[4] = itoa(n);
2823 if ((fg ? spawn(argv_copy) : mingw_spawn_detach(argv_copy)) == -1) 2912 if ((foreground ?
2913 spawn(argv_copy) : mingw_spawn_detach(argv_copy)) == -1)
2824 bb_perror_msg_and_die("can't execute 'httpd'"); 2914 bb_perror_msg_and_die("can't execute 'httpd'");
2825 2915
2826 /* parent, or spawn failed */ 2916 /* parent, or spawn failed */
@@ -2936,7 +3026,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2936 "\0" 3026 "\0"
2937 /* -v counts, -i implies -f */ 3027 /* -v counts, -i implies -f */
2938 IF_NOT_PLATFORM_MINGW32("vv:if",) 3028 IF_NOT_PLATFORM_MINGW32("vv:if",)
2939 IF_PLATFORM_MINGW32("vv:If",) 3029 IF_PLATFORM_MINGW32("vv:",)
2940 &opt_c_configFile, &url_for_decode, &home_httpd 3030 &opt_c_configFile, &url_for_decode, &home_httpd
2941 IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) 3031 IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
2942 IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) 3032 IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
@@ -2981,7 +3071,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2981 } 3071 }
2982#endif 3072#endif
2983#else /* ENABLE_PLATFORM_MINGW32 */ 3073#else /* ENABLE_PLATFORM_MINGW32 */
2984 if (!(opt & OPT_FOREGROUND) && argv[0][0] != '-') 3074 foreground = (opt & OPT_FOREGROUND) == OPT_FOREGROUND;
3075 if (!foreground && argv[0][0] != '-')
2985 mingw_daemonize(argv); 3076 mingw_daemonize(argv);
2986#endif 3077#endif
2987 3078
@@ -3032,7 +3123,14 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
3032#endif 3123#endif
3033 3124
3034 parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); 3125 parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE);
3035#if !ENABLE_PLATFORM_MINGW32 3126#if ENABLE_PLATFORM_MINGW32
3127# if ENABLE_FEATURE_HTTPD_CGI
3128 if ((opt & OPT_INETD) && fd == 0) {
3129 cgi_handler(argv + optind);
3130 return 0;
3131 }
3132# endif
3133#else
3036 if (!(opt & OPT_INETD)) 3134 if (!(opt & OPT_INETD))
3037 signal(SIGHUP, sighup_handler); 3135 signal(SIGHUP, sighup_handler);
3038#endif 3136#endif
@@ -3044,6 +3142,11 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
3044 xdup2(0, 1); 3142 xdup2(0, 1);
3045 while (--fd > 2) 3143 while (--fd > 2)
3046 close(fd); 3144 close(fd);
3145# if ENABLE_FEATURE_HTTPD_CGI
3146 /* Skip 'httpd -I N' and omit any non-option arguments */
3147 server_argc = optind - 3;
3148 server_argv = argv + 3;
3149# endif
3047 } 3150 }
3048#endif 3151#endif
3049 if (opt & OPT_INETD) 3152 if (opt & OPT_INETD)
@@ -3057,7 +3160,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
3057 mini_httpd_nommu(server_socket, argc, argv); /* never returns */ 3160 mini_httpd_nommu(server_socket, argc, argv); /* never returns */
3058#endif 3161#endif
3059#else /* ENABLE_PLATFORM_MINGW32 */ 3162#else /* ENABLE_PLATFORM_MINGW32 */
3060 mini_httpd_win32(opt & OPT_FOREGROUND, server_socket, argc, argv); 3163 mini_httpd_win32(server_socket, argc, argv);
3061#endif 3164#endif
3062 /* return 0; */ 3165 /* return 0; */
3063} 3166}