diff options
author | Ron Yorston <rmy@pobox.com> | 2020-04-05 09:51:56 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2020-04-05 10:05:01 +0100 |
commit | fbfb02e8637409f1367cb0d8a3d02f6366261ab4 (patch) | |
tree | bc930441e13d7e27c2aa60436a8346dde0d31ec5 /networking/httpd.c | |
parent | 2b4c25bd2cac034cdc52d29d6bb8c675c87a731c (diff) | |
download | busybox-w32-fbfb02e8637409f1367cb0d8a3d02f6366261ab4.tar.gz busybox-w32-fbfb02e8637409f1367cb0d8a3d02f6366261ab4.tar.bz2 busybox-w32-fbfb02e8637409f1367cb0d8a3d02f6366261ab4.zip |
httpd: WIN32 port
Use mingw_spawn_detach() to daemonize the server. Pass the open
socket to the child process on the command line.
Omit handling of SIGHUP and SIGALRM. Timeouts are handled using
poll(2) instead of alarm(2).
Diffstat (limited to '')
-rw-r--r-- | networking/httpd.c | 135 |
1 files changed, 133 insertions, 2 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index 1757e09c9..7e1c187a5 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -229,7 +229,12 @@ | |||
229 | //usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" | 229 | //usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" |
230 | //usage:#define httpd_full_usage "\n\n" | 230 | //usage:#define httpd_full_usage "\n\n" |
231 | //usage: "Listen for incoming HTTP requests\n" | 231 | //usage: "Listen for incoming HTTP requests\n" |
232 | //usage: IF_NOT_PLATFORM_MINGW32( | ||
232 | //usage: "\n -i Inetd mode" | 233 | //usage: "\n -i Inetd mode" |
234 | //usage: ) | ||
235 | //usage: IF_PLATFORM_MINGW32( | ||
236 | //usage: "\n -i fd Inetd mode file descriptor" | ||
237 | //usage: ) | ||
233 | //usage: "\n -f Don't daemonize" | 238 | //usage: "\n -f Don't daemonize" |
234 | //usage: "\n -v[v] Verbose" | 239 | //usage: "\n -v[v] Verbose" |
235 | //usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:80)" | 240 | //usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:80)" |
@@ -267,6 +272,8 @@ | |||
267 | 272 | ||
268 | #define HEADER_READ_TIMEOUT 60 | 273 | #define HEADER_READ_TIMEOUT 60 |
269 | 274 | ||
275 | static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; | ||
276 | |||
270 | static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; | 277 | static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; |
271 | static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; | 278 | static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; |
272 | static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; | 279 | static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; |
@@ -652,8 +659,16 @@ static void parse_conf(const char *path, int flag) | |||
652 | 659 | ||
653 | filename = opt_c_configFile; | 660 | filename = opt_c_configFile; |
654 | if (flag == SUBDIR_PARSE || filename == NULL) { | 661 | if (flag == SUBDIR_PARSE || filename == NULL) { |
662 | #if !ENABLE_PLATFORM_MINGW32 | ||
655 | filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2); | 663 | filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2); |
656 | sprintf((char *)filename, "%s/%s", path, HTTPD_CONF); | 664 | sprintf((char *)filename, "%s/%s", path, HTTPD_CONF); |
665 | #else | ||
666 | char *sd = get_system_drive(); | ||
667 | |||
668 | filename = auto_string(xasprintf("%s%s/%s", | ||
669 | (sd && path[0] == '/' && root_len(path) == 0) ? sd : "", | ||
670 | path, HTTPD_CONF)); | ||
671 | #endif | ||
657 | } | 672 | } |
658 | 673 | ||
659 | while ((f = fopen_for_read(filename)) == NULL) { | 674 | while ((f = fopen_for_read(filename)) == NULL) { |
@@ -702,6 +717,7 @@ static void parse_conf(const char *path, int flag) | |||
702 | * without needless copying, therefore we don't merge | 717 | * without needless copying, therefore we don't merge |
703 | * this operation into next while loop. */ | 718 | * this operation into next while loop. */ |
704 | while ((ch = *p0) != '\0' && ch != '\n' && ch != '#' | 719 | while ((ch = *p0) != '\0' && ch != '\n' && ch != '#' |
720 | IF_PLATFORM_MINGW32(&& ch != '\r') | ||
705 | && ch != ' ' && ch != '\t' | 721 | && ch != ' ' && ch != '\t' |
706 | ) { | 722 | ) { |
707 | p0++; | 723 | p0++; |
@@ -709,7 +725,11 @@ static void parse_conf(const char *path, int flag) | |||
709 | p = p0; | 725 | p = p0; |
710 | /* if we enter this loop, we have some whitespace. | 726 | /* if we enter this loop, we have some whitespace. |
711 | * discard it */ | 727 | * discard it */ |
728 | #if !ENABLE_PLATFORM_MINGW32 | ||
712 | while (ch != '\0' && ch != '\n' && ch != '#') { | 729 | while (ch != '\0' && ch != '\n' && ch != '#') { |
730 | #else | ||
731 | while (ch != '\0' && ch != '\n' && ch != '\r' && ch != '#') { | ||
732 | #endif | ||
713 | if (ch != ' ' && ch != '\t') { | 733 | if (ch != ' ' && ch != '\t') { |
714 | *p++ = ch; | 734 | *p++ = ch; |
715 | } | 735 | } |
@@ -1249,7 +1269,21 @@ static unsigned get_line(void) | |||
1249 | count = 0; | 1269 | count = 0; |
1250 | while (1) { | 1270 | while (1) { |
1251 | if (hdr_cnt <= 0) { | 1271 | if (hdr_cnt <= 0) { |
1272 | #if ENABLE_PLATFORM_MINGW32 | ||
1273 | int nfds = 1; | ||
1274 | struct pollfd fds = {STDIN_FILENO, POLLIN, 0}; | ||
1275 | |||
1276 | switch (poll(&fds, nfds, HEADER_READ_TIMEOUT*1000)) { | ||
1277 | case 0: | ||
1278 | send_REQUEST_TIMEOUT_and_exit(0); | ||
1279 | break; | ||
1280 | case -1: | ||
1281 | bb_simple_perror_msg_and_die("poll"); | ||
1282 | break; | ||
1283 | } | ||
1284 | #else | ||
1252 | alarm(HEADER_READ_TIMEOUT); | 1285 | alarm(HEADER_READ_TIMEOUT); |
1286 | #endif | ||
1253 | hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); | 1287 | hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); |
1254 | if (hdr_cnt <= 0) | 1288 | if (hdr_cnt <= 0) |
1255 | goto ret; | 1289 | goto ret; |
@@ -2090,7 +2124,6 @@ static Htaccess_Proxy *find_proxy_entry(const char *url) | |||
2090 | /* | 2124 | /* |
2091 | * Handle timeouts | 2125 | * Handle timeouts |
2092 | */ | 2126 | */ |
2093 | static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; | ||
2094 | static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) | 2127 | static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) |
2095 | { | 2128 | { |
2096 | send_headers_and_exit(HTTP_REQUEST_TIMEOUT); | 2129 | send_headers_and_exit(HTTP_REQUEST_TIMEOUT); |
@@ -2134,11 +2167,21 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2134 | remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr); | 2167 | remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr); |
2135 | } | 2168 | } |
2136 | #if ENABLE_FEATURE_IPV6 | 2169 | #if ENABLE_FEATURE_IPV6 |
2170 | # if !ENABLE_PLATFORM_MINGW32 | ||
2137 | if (fromAddr->u.sa.sa_family == AF_INET6 | 2171 | if (fromAddr->u.sa.sa_family == AF_INET6 |
2138 | && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0 | 2172 | && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0 |
2139 | && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0 | 2173 | && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0 |
2140 | && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff) | 2174 | && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff) |
2141 | remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]); | 2175 | remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]); |
2176 | # else | ||
2177 | if (fromAddr->u.sa.sa_family == AF_INET6 | ||
2178 | && fromAddr->u.sin6.sin6_addr.s6_words[0] == 0 | ||
2179 | && fromAddr->u.sin6.sin6_addr.s6_words[1] == 0 | ||
2180 | && fromAddr->u.sin6.sin6_addr.s6_words[2] == 0 | ||
2181 | && fromAddr->u.sin6.sin6_addr.s6_words[3] == 0 | ||
2182 | && ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+4)) == 0xffff) | ||
2183 | remote_ip = ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+6)); | ||
2184 | # endif | ||
2142 | #endif | 2185 | #endif |
2143 | if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) { | 2186 | if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) { |
2144 | /* NB: can be NULL (user runs httpd -i by hand?) */ | 2187 | /* NB: can be NULL (user runs httpd -i by hand?) */ |
@@ -2153,8 +2196,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2153 | } | 2196 | } |
2154 | if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip); | 2197 | if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip); |
2155 | 2198 | ||
2199 | #ifdef SIGALRM | ||
2156 | /* Install timeout handler. get_line() needs it. */ | 2200 | /* Install timeout handler. get_line() needs it. */ |
2157 | signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); | 2201 | signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); |
2202 | #endif | ||
2158 | 2203 | ||
2159 | if (!get_line()) /* EOF or error or empty line */ | 2204 | if (!get_line()) /* EOF or error or empty line */ |
2160 | send_headers_and_exit(HTTP_BAD_REQUEST); | 2205 | send_headers_and_exit(HTTP_BAD_REQUEST); |
@@ -2527,12 +2572,14 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2527 | #endif | 2572 | #endif |
2528 | } | 2573 | } |
2529 | 2574 | ||
2575 | |||
2530 | /* | 2576 | /* |
2531 | * The main http server function. | 2577 | * The main http server function. |
2532 | * Given a socket, listen for new connections and farm out | 2578 | * Given a socket, listen for new connections and farm out |
2533 | * the processing as a [v]forked process. | 2579 | * the processing as a [v]forked process. |
2534 | * Never returns. | 2580 | * Never returns. |
2535 | */ | 2581 | */ |
2582 | # if !ENABLE_PLATFORM_MINGW32 | ||
2536 | #if BB_MMU | 2583 | #if BB_MMU |
2537 | static void mini_httpd(int server_socket) NORETURN; | 2584 | static void mini_httpd(int server_socket) NORETURN; |
2538 | static void mini_httpd(int server_socket) | 2585 | static void mini_httpd(int server_socket) |
@@ -2614,6 +2661,39 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv) | |||
2614 | /* never reached */ | 2661 | /* never reached */ |
2615 | } | 2662 | } |
2616 | #endif | 2663 | #endif |
2664 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
2665 | static void mini_httpd_win32(int fg, int sock, int argc, char **argv) NORETURN; | ||
2666 | static void mini_httpd_win32(int fg, int sock, int argc, char **argv) | ||
2667 | { | ||
2668 | char *argv_copy[argc + 5]; | ||
2669 | |||
2670 | argv_copy[0] = (char *)bb_busybox_exec_path; | ||
2671 | argv_copy[1] = (char *)"--busybox"; | ||
2672 | argv_copy[2] = (char *)"httpd"; | ||
2673 | argv_copy[3] = (char *)"-i"; | ||
2674 | memcpy(&argv_copy[5], &argv[1], argc * sizeof(argv[0])); | ||
2675 | |||
2676 | while (1) { | ||
2677 | int n; | ||
2678 | |||
2679 | /* Wait for connections... */ | ||
2680 | n = accept(sock, NULL, NULL); | ||
2681 | if (n < 0) | ||
2682 | continue; | ||
2683 | |||
2684 | /* set the KEEPALIVE option to cull dead connections */ | ||
2685 | setsockopt_keepalive(n); | ||
2686 | |||
2687 | argv_copy[4] = itoa(n); | ||
2688 | if ((fg ? spawn(argv_copy) : mingw_spawn_detach(argv_copy)) == -1) | ||
2689 | bb_perror_msg_and_die("can't execute 'httpd'"); | ||
2690 | |||
2691 | /* parent, or spawn failed */ | ||
2692 | close(n); | ||
2693 | } /* while (1) */ | ||
2694 | /* never reached */ | ||
2695 | } | ||
2696 | #endif | ||
2617 | 2697 | ||
2618 | /* | 2698 | /* |
2619 | * Process a HTTP connection on stdin/out. | 2699 | * Process a HTTP connection on stdin/out. |
@@ -2631,12 +2711,39 @@ static void mini_httpd_inetd(void) | |||
2631 | handle_incoming_and_exit(&fromAddr); | 2711 | handle_incoming_and_exit(&fromAddr); |
2632 | } | 2712 | } |
2633 | 2713 | ||
2714 | #if ENABLE_PLATFORM_MINGW32 | ||
2715 | static void mingw_daemonize(char **argv) | ||
2716 | { | ||
2717 | char **new_argv; | ||
2718 | int argc, fd; | ||
2719 | |||
2720 | argc = string_array_len((char **)argv); | ||
2721 | new_argv = xmalloc(sizeof(*argv)*(argc+3)); | ||
2722 | new_argv[0] = (char *)bb_busybox_exec_path; | ||
2723 | new_argv[1] = (char *)"--busybox"; | ||
2724 | new_argv[2] = (char *)"-httpd"; | ||
2725 | memcpy(&new_argv[3], &argv[1], sizeof(*argv)*argc); | ||
2726 | |||
2727 | fd = xopen(bb_dev_null, O_RDWR); | ||
2728 | xdup2(fd, 0); | ||
2729 | xdup2(fd, 1); | ||
2730 | xdup2(fd, 2); | ||
2731 | close(fd); | ||
2732 | |||
2733 | if (mingw_spawn_detach(new_argv)) | ||
2734 | exit(EXIT_SUCCESS); /* parent */ | ||
2735 | exit(EXIT_FAILURE); /* parent */ | ||
2736 | } | ||
2737 | #endif | ||
2738 | |||
2739 | #ifdef SIGHUP | ||
2634 | static void sighup_handler(int sig UNUSED_PARAM) | 2740 | static void sighup_handler(int sig UNUSED_PARAM) |
2635 | { | 2741 | { |
2636 | int sv = errno; | 2742 | int sv = errno; |
2637 | parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); | 2743 | parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); |
2638 | errno = sv; | 2744 | errno = sv; |
2639 | } | 2745 | } |
2746 | #endif | ||
2640 | 2747 | ||
2641 | enum { | 2748 | enum { |
2642 | c_opt_config_file = 0, | 2749 | c_opt_config_file = 0, |
@@ -2674,6 +2781,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2674 | IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;) | 2781 | IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;) |
2675 | IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;) | 2782 | IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;) |
2676 | IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;) | 2783 | IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;) |
2784 | IF_PLATFORM_MINGW32(int fd;) | ||
2677 | 2785 | ||
2678 | INIT_G(); | 2786 | INIT_G(); |
2679 | 2787 | ||
@@ -2692,7 +2800,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2692 | IF_FEATURE_HTTPD_BASIC_AUTH("r:") | 2800 | IF_FEATURE_HTTPD_BASIC_AUTH("r:") |
2693 | IF_FEATURE_HTTPD_AUTH_MD5("m:") | 2801 | IF_FEATURE_HTTPD_AUTH_MD5("m:") |
2694 | IF_FEATURE_HTTPD_SETUID("u:") | 2802 | IF_FEATURE_HTTPD_SETUID("u:") |
2695 | "p:ifv" | 2803 | IF_NOT_PLATFORM_MINGW32("p:ifv") |
2804 | IF_PLATFORM_MINGW32("p:i:+fv") | ||
2696 | "\0" | 2805 | "\0" |
2697 | /* -v counts, -i implies -f */ | 2806 | /* -v counts, -i implies -f */ |
2698 | "vv:if", | 2807 | "vv:if", |
@@ -2702,6 +2811,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2702 | IF_FEATURE_HTTPD_AUTH_MD5(, &pass) | 2811 | IF_FEATURE_HTTPD_AUTH_MD5(, &pass) |
2703 | IF_FEATURE_HTTPD_SETUID(, &s_ugid) | 2812 | IF_FEATURE_HTTPD_SETUID(, &s_ugid) |
2704 | , &bind_addr_or_port | 2813 | , &bind_addr_or_port |
2814 | IF_PLATFORM_MINGW32(, &fd) | ||
2705 | , &verbose | 2815 | , &verbose |
2706 | ); | 2816 | ); |
2707 | if (opt & OPT_DECODE_URL) { | 2817 | if (opt & OPT_DECODE_URL) { |
@@ -2731,15 +2841,22 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2731 | } | 2841 | } |
2732 | #endif | 2842 | #endif |
2733 | 2843 | ||
2844 | #if !ENABLE_PLATFORM_MINGW32 | ||
2734 | #if !BB_MMU | 2845 | #if !BB_MMU |
2735 | if (!(opt & OPT_FOREGROUND)) { | 2846 | if (!(opt & OPT_FOREGROUND)) { |
2736 | bb_daemonize_or_rexec(0, argv); /* don't change current directory */ | 2847 | bb_daemonize_or_rexec(0, argv); /* don't change current directory */ |
2737 | } | 2848 | } |
2738 | #endif | 2849 | #endif |
2850 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
2851 | if (!(opt & OPT_FOREGROUND) && argv[0][0] != '-') | ||
2852 | mingw_daemonize(argv); | ||
2853 | #endif | ||
2739 | 2854 | ||
2740 | xchdir(home_httpd); | 2855 | xchdir(home_httpd); |
2741 | if (!(opt & OPT_INETD)) { | 2856 | if (!(opt & OPT_INETD)) { |
2857 | #ifdef SIGCHLD | ||
2742 | signal(SIGCHLD, SIG_IGN); | 2858 | signal(SIGCHLD, SIG_IGN); |
2859 | #endif | ||
2743 | server_socket = openServer(); | 2860 | server_socket = openServer(); |
2744 | #if ENABLE_FEATURE_HTTPD_SETUID | 2861 | #if ENABLE_FEATURE_HTTPD_SETUID |
2745 | /* drop privileges */ | 2862 | /* drop privileges */ |
@@ -2773,12 +2890,23 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2773 | #endif | 2890 | #endif |
2774 | 2891 | ||
2775 | parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); | 2892 | parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); |
2893 | #ifdef SIGHUP | ||
2776 | if (!(opt & OPT_INETD)) | 2894 | if (!(opt & OPT_INETD)) |
2777 | signal(SIGHUP, sighup_handler); | 2895 | signal(SIGHUP, sighup_handler); |
2896 | #endif | ||
2778 | 2897 | ||
2779 | xfunc_error_retval = 0; | 2898 | xfunc_error_retval = 0; |
2899 | #if ENABLE_PLATFORM_MINGW32 | ||
2900 | if (opt & OPT_INETD) { | ||
2901 | xmove_fd(fd, 0); | ||
2902 | xdup2(0, 1); | ||
2903 | while (--fd > 2) | ||
2904 | close(fd); | ||
2905 | } | ||
2906 | #endif | ||
2780 | if (opt & OPT_INETD) | 2907 | if (opt & OPT_INETD) |
2781 | mini_httpd_inetd(); /* never returns */ | 2908 | mini_httpd_inetd(); /* never returns */ |
2909 | #if !ENABLE_PLATFORM_MINGW32 | ||
2782 | #if BB_MMU | 2910 | #if BB_MMU |
2783 | if (!(opt & OPT_FOREGROUND)) | 2911 | if (!(opt & OPT_FOREGROUND)) |
2784 | bb_daemonize(0); /* don't change current directory */ | 2912 | bb_daemonize(0); /* don't change current directory */ |
@@ -2786,5 +2914,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2786 | #else | 2914 | #else |
2787 | mini_httpd_nommu(server_socket, argc, argv); /* never returns */ | 2915 | mini_httpd_nommu(server_socket, argc, argv); /* never returns */ |
2788 | #endif | 2916 | #endif |
2917 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
2918 | mini_httpd_win32(opt & OPT_FOREGROUND, server_socket, argc, argv); | ||
2919 | #endif | ||
2789 | /* return 0; */ | 2920 | /* return 0; */ |
2790 | } | 2921 | } |