From bde4b52adadf7252db4d8222df2fe178382fd958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Sat, 5 Mar 2022 14:14:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=86=85=E5=AD=98=E6=B3=84?= =?UTF-8?q?=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.c | 286 +++++++++++++++++++++++++++---------------------------- 1 file changed, 142 insertions(+), 144 deletions(-) diff --git a/server.c b/server.c index 088d46b..f9128a7 100644 --- a/server.c +++ b/server.c @@ -7,7 +7,7 @@ * Modified June 2021 by Fumiama(源文雨) */ /* See feature_test_macros(7) */ -#define _GNU_SOURCE 1 +#define _GNU_SOURCE #include #include #include @@ -77,7 +77,6 @@ static void unimplemented(int); #define skiptext(buf, j, cap) while(!ISspace(buf[j]) && (j < (cap))) j++ #define skipspace(buf, j, cap) while(ISspace(buf[j]) && (j < (cap))) j++ #define getmethod(method_type) ((method_type == GET)?"GET":"POST") - static void accept_request(void *cli) { int client = (int)cli; char buf[1024], *path, *query_string; @@ -85,9 +84,9 @@ static void accept_request(void *cli) { struct stat st; METHOD_TYPE method_type; - signal(SIGCHLD, SIG_IGN); signal(SIGQUIT, handle_quit); signal(SIGPIPE, handle_quit); + pthread_detach(pthread_self()); numchars = get_line(client, buf, sizeof(buf)); j = 0; @@ -235,103 +234,92 @@ static void error_die(const char *sc) { * path to the CGI script */ /**********************************************************************/ static void execute_cgi(int client, int content_length, const HTTP_REQUEST* request) { - int cgi_output[2], cgi_input[2], i; + int cgi_output[2], cgi_input[2]; pid_t pid; + char buf[1024]; - if(pipe(cgi_output) < 0 || pipe(cgi_input) < 0 || (pid = fork()) < 0) internal_error(client); + if(pipe(cgi_output) < 0 || pipe(cgi_input) < 0 || (pid = fork()) < 0) { + internal_error(client); + return; + } /* child: CGI script */ - else if(pid == 0) { - char env[255]; - + if(pid == 0) { dup2(cgi_output[1], 1); dup2(cgi_input[0], 0); close(cgi_output[0]); close(cgi_input[1]); - sprintf(env, "REQUEST_METHOD=%s", request->method); - putenv(env); - if(request->method_type == GET) { - sprintf(env, "QUERY_STRING=%s", request->query_string); - putenv(env); - } - else { /* POST */ - sprintf(env, "CONTENT_LENGTH=%d", content_length); - putenv(env); - } + execl(request->path, request->path, request->method, request->query_string, NULL); - exit(0); + exit(EXIT_SUCCESS); } - else { /* parent */ - char buf[1024]; - - close(cgi_output[1]); - close(cgi_input[0]); - if(request->method_type == POST) { - #if __APPLE__ - for(i = 0; i < content_length;) { - int cnt = recv(client, buf, 1024, 0); - if(cnt > 0) { - write(cgi_input[1], buf, cnt); - i += cnt; - } else { - internal_error(client); - goto CGI_CLOSE; - } + /* parent */ + close(cgi_output[1]); + close(cgi_input[0]); + if(request->method_type == POST) { + #if __APPLE__ + for(int i = 0; i < content_length;) { + int cnt = recv(client, buf, 1024, 0); + if(cnt > 0) { + write(cgi_input[1], buf, cnt); + i += cnt; + } else { + internal_error(client); + goto CGI_CLOSE; } - #else - int len = 0; - while(len < content_length) { - int delta = splice(client, NULL, cgi_input[1], NULL, content_length - len, SPLICE_F_GIFT); - if(delta <= 0) { - internal_error(client); - goto CGI_CLOSE; - } - len += delta; - } - #endif - } - - uint32_t cnt = 0; - char* p = (char*)&cnt; - while(p - (char*)&cnt < sizeof(uint32_t)) { - int offset = read(cgi_output[0], p, sizeof(uint32_t)); - if(offset > 0) p += offset; - else { - internal_error(client); - goto CGI_CLOSE; } - } - printf("CGI msg len: %u bytes.\n", cnt); - if(cnt > 0) { + #else int len = 0; - #if __APPLE__ - int cap = (cnt>1024)?1024:cnt; - char data[cap]; - while(len < cnt) { - int n = read(cgi_output[0], data, cap); - if(n <= 0) { - internal_error(client); - goto CGI_CLOSE; - } - len += n; - send(client, data, cap, 0); + while(len < content_length) { + int delta = splice(client, NULL, cgi_input[1], NULL, content_length - len, SPLICE_F_GIFT); + if(delta <= 0) { + internal_error(client); + goto CGI_CLOSE; } - #else - while(len < cnt) { - int delta = splice(cgi_output[0], NULL, client, NULL, cnt - len, SPLICE_F_GIFT); - if(delta <= 0) { - internal_error(client); - goto CGI_CLOSE; - } - len += delta; - } - #endif - printf("CGI send %d bytes\n", len); - } - CGI_CLOSE: - close(cgi_output[0]); - close(cgi_input[1]); - waitpid(pid, &i, 0); + len += delta; + } + #endif } + + uint32_t cnt = 0; + char* p = (char*)&cnt; + while(p - (char*)&cnt < sizeof(uint32_t)) { + int offset = read(cgi_output[0], p, sizeof(uint32_t)); + if(offset > 0) p += offset; + else { + internal_error(client); + goto CGI_CLOSE; + } + } + printf("CGI msg len: %u bytes.\n", cnt); + if(cnt > 0) { + int len = 0; + #if __APPLE__ + int cap = (cnt>1024)?1024:cnt; + while(len < cnt) { + int n = read(cgi_output[0], buf, cap); + if(n <= 0) { + internal_error(client); + goto CGI_CLOSE; + } + len += n; + send(client, buf, n, 0); + } + #else + while(len < cnt) { + int delta = splice(cgi_output[0], NULL, client, NULL, cnt - len, SPLICE_F_GIFT); + if(delta <= 0) { + internal_error(client); + goto CGI_CLOSE; + } + len += delta; + } + #endif + printf("CGI send %d bytes\n", len); + } +CGI_CLOSE: + close(cgi_output[0]); + close(cgi_input[1]); + waitpid(pid, NULL, 0); } /**********************************************************************/ @@ -397,14 +385,13 @@ static void handle_quit(int signo) { /* Parameters: the socket to print the headers on * the name of the file */ /**********************************************************************/ -#define ADD_HERDER(h)\ +#define add_header(h)\ strcpy(buf + offset, h);\ offset += sizeof(h) - 1; -#define ADD_HERDER_PARAM(h, p)\ +#define add_header_para(h, p)\ sprintf(buf + offset, h,(p));\ offset += strlen(buf + offset); -#define EXTNM_IS_NOT(name)(strcmp(filepath+extpos, name)) - +#define extisnot(name) (strcmp(filepath+extpos, name)) #define HTTP200 "HTTP/1.0 200 OK\r\n" #define CONTENT_TYPE "Content-Type: %s\r\n" #define CONTENT_LEN "Content-Length: %d\r\n" @@ -414,9 +401,9 @@ static int headers(int client, const char *filepath) { uint32_t extpos = strlen(filepath) - 4; uint32_t file_size = get_file_size(filepath, client); if(file_size) { - ADD_HERDER(HTTP200 SERVER_STRING); - ADD_HERDER_PARAM(CONTENT_TYPE, EXTNM_IS_NOT("html")?(EXTNM_IS_NOT(".css")?(EXTNM_IS_NOT(".ico")?"text/plain":"image/x-icon"):"text/css"):"text/html"); - ADD_HERDER_PARAM(CONTENT_LEN "\r\n", file_size); + add_header(HTTP200 SERVER_STRING); + add_header_para(CONTENT_TYPE, extisnot("html")?(extisnot(".css")?(extisnot(".ico")?"text/plain":"image/x-icon"):"text/css"):"text/html"); + add_header_para(CONTENT_LEN "\r\n", file_size); send(client, buf, offset, 0); puts("200 OK."); return 1; @@ -467,7 +454,6 @@ static void serve_file(int client, const char *filename) { static struct sockaddr_in name; static struct sockaddr_in client_name; #endif - static int startup(uint16_t *port) { int httpd = 0; @@ -484,6 +470,7 @@ static int startup(uint16_t *port) { httpd = socket(AF_INET, SOCK_STREAM, 0); #endif if(httpd < 0) error_die("socket"); + if(bind(httpd,(struct sockaddr *)&name, struct_len) < 0) error_die("bind"); /* if dynamically allocating a port */ if(*port == 0) { @@ -495,22 +482,26 @@ static int startup(uint16_t *port) { #endif } if(listen(httpd, 5) < 0) error_die("listen"); + return httpd; } static struct sockaddr_un uname; static int startupunix(char *path) { int httpd = socket(AF_UNIX, SOCK_STREAM, 0); + if(httpd < 0) error_die("unix socket"); + uname.sun_family = AF_UNIX; strncpy(uname.sun_path, path, sizeof(uname.sun_path)); uname.sun_path[sizeof(uname.sun_path)-1] = 0; // avoid overlap #if __APPLE__ uname.sun_len = strlen(uname.sun_path); #endif - if(httpd < 0) error_die("unix socket"); + unlink(path); // in case it already exists if(bind(httpd, (struct sockaddr *)&uname, SUN_LEN(&uname)) < 0) error_die("bind"); if(listen(httpd, 5) < 0) error_die("listen"); + return httpd; } @@ -533,7 +524,7 @@ static pthread_attr_t attr; static int accept_client(int is_unix_sock) { pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, 1); - + signal(SIGCHLD, SIG_IGN); while(1) { socklen_t client_name_len = sizeof(client_name); int client_sock = accept(server_sock, (struct sockaddr *)(is_unix_sock?NULL:&client_name), is_unix_sock?NULL:&client_name_len); @@ -558,61 +549,68 @@ static int accept_client(int is_unix_sock) { } pthread_t accept_thread; if(pthread_create(&accept_thread, &attr, &accept_request, client_sock) != 0) perror("pthread_create"); - printf("Created new thread at 0x%x\n", accept_thread); + printf("Created new thread at 0x%p\n", (void*)accept_thread); } } #define argequ(arg) (*(uint16_t*)argv[i] == *(uint16_t*)(arg)) #define USAGE "Usage:\tsimple-http-server [-h] [-d] [-p ] [-r ] [-u ]\n -h:\tdisplay this help.\n -d:\trun as daemon.\n -p:\tif not set, we will choose a random port.\n -r:\thttp root dir.\n -u:\trun as this uid." int main(int argc, char **argv) { - if(argc > 8) puts(USAGE); - else { - int as_daemon = 0; - uint16_t port = 0; - char* socket_path = NULL; - char *cdir = "./"; - uid_t uid = -1; - int pid = -1; + int as_daemon = 0; + uint16_t port = 0; + char* socket_path = NULL; + char *cdir = "./"; + uid_t uid = -1; + int pid = -1; - for(int i = 1; i < argc; i++) { - if(!as_daemon && argequ("-d")) as_daemon = 1; - else if(argequ("-p")) { - i++; - if(isdigit(argv[i][0])) port = (uint16_t)atoi(argv[i]); - else socket_path = argv[i]; - } - else if(argequ("-r")) cdir = argv[++i]; - else if(argequ("-u")) uid = atoi(argv[++i]); - else if(argequ("-h")) { - puts(USAGE); - exit(EXIT_SUCCESS); - } - else { - printf("unknown argument: %s\n", argv[i]); - puts(USAGE); - exit(EXIT_FAILURE); - } + if(argc > 8) { + puts(USAGE); + exit(EXIT_SUCCESS); + } + + for(int i = 1; i < argc; i++) { + if(!as_daemon && argequ("-d")) as_daemon = 1; + else if(argequ("-p")) { + i++; + if(isdigit(argv[i][0])) port = (uint16_t)atoi(argv[i]); + else socket_path = argv[i]; + } + else if(argequ("-r")) cdir = argv[++i]; + else if(argequ("-u")) uid = atoi(argv[++i]); + else if(argequ("-h")) { + puts(USAGE); + exit(EXIT_SUCCESS); + } + else { + printf("unknown argument: %s\n", argv[i]); + puts(USAGE); + exit(EXIT_FAILURE); + } + } + + if(chdir(cdir)) error_die("chdir"); + + server_sock = (!port&&socket_path)?startupunix(socket_path):startup(&port); + if(port) printf("httpd running on 0.0.0.0:%d at %s\n", port, cdir); + else printf("httpd running on %s at %s\n", socket_path, cdir); + + if(uid > 0) { + setuid(uid); + setgid(uid); + } + + if(as_daemon) { + pid = fork(); + if(pid == 0) pid = fork(); + else return 0; + + while(pid > 0) { // 主进程监控子进程状态,如果子进程异常终止则重启之 + wait(NULL); + puts("Server subprocess exited. Restart..."); + pid = fork(); } - if(chdir(cdir)) error_die("chdir"); - server_sock = (!port&&socket_path)?startupunix(socket_path):startup(&port); - if(port) printf("httpd running on 0.0.0.0:%d at %s\n", port, cdir); - else printf("httpd running on %s at %s\n", socket_path, cdir); - if(as_daemon) { - if(uid > 0) { - setuid(uid); - setgid(uid); - } - pid = fork(); - if(pid == 0) pid = fork(); - else return 0; - while(pid > 0) { // 主进程监控子进程状态,如果子进程异常终止则重启之 - wait(NULL); - puts("Server subprocess exited. Restart..."); - pid = fork(); - } - if(pid < 0) perror("fork"); - else accept_client(!port); - } else accept_client(!port); - } + if(pid < 0) perror("fork"); + else accept_client(!port); + } else accept_client(!port); }