⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mini_ws.c

📁 程序代码使用说明: (1)所有源代码目录下都提供了Makefile(非Qt)
💻 C
字号:
/* * web_server.c - A primary Web server . */#include <stdio.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/wait.h>#include <sys/stat.h>#include <sys/mman.h>#include <unistd.h>#include <signal.h>#include <fcntl.h>#include <netinet/in.h>#define MAXLINE 150typedef struct sockaddr SA;extern char **environ; /* defined by libc */void handle_req(int fd); int parse_uri(char *uri, char *filename, char *cgiargs);void serve_static(int fd, char *filename, int filesize);void get_filetype(char *filename, char *filetype);void exec_cgi(int fd, char *method, int content_length, char *filename, char *cgiargs);void error_msg(int fd, char *cause, char *errnum, 		 char *shortmsg, char *longmsg);int main(int argc, char **argv) {    /* Check command line args */    if (argc != 2) {	    fprintf(stderr, "usage: %s <port>\n", argv[0]);    	exit(1);    }    signal(SIGCHLD, SIG_IGN);    signal(SIGPIPE, SIG_IGN);    int port = atoi(argv[1]);    int listen_fd;    struct sockaddr_in client_addr;    struct sockaddr_in server_addr;    if((listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {        perror("Unable to obtain network");        exit(1);    }        int optval = 1;    if((setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval,            sizeof(int))) < 0) {        perror("setsockopt failed");        exit(1);    }    server_addr.sin_family = AF_INET;    server_addr.sin_port = htons(port);    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);        if(bind(listen_fd, (SA *)&server_addr,         sizeof(server_addr)) < 0)  {        perror("Unable to bind socket");        exit(1);    }    if(listen(listen_fd, 1024) < 0) {         perror("Unable to listen");        exit(1);    }    #ifdef DEBUG    printf("listening... s=%d \n", listen_fd);#endif        int conn_fd, len;    while (1) {        len = sizeof(client_addr);          if((conn_fd = accept(listen_fd, (SA *)&client_addr, &len)) < 0) {            exit(1);            close(listen_fd);        }#ifdef DEBUG        printf("connected. fd=%d \n", conn_fd);#endif        handle_req(conn_fd);        close(conn_fd);    }}/* * handle one HTTP request/response transaction */void handle_req(int fd) {    char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];    char filename[MAXLINE], cgiargs[MAXLINE];    FILE *f = fdopen(fd, "r");    if (!f) {        perror("Unable to open input fd");        close(fd);        return;    }    setbuf(f, 0);    /* Get HTTP command line*/    if (!fgets(buf, MAXLINE, f)) {        perror("Error reading buffer");        fclose(f);        return;    }    sscanf(buf, "%s %s %s", method, uri, version);#ifdef DEBUG        printf("method: %s, uri: %s, version: %s \n", method, uri, version);#endif        if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) {         error_msg(fd, method, "501", "Not Implemented",                "MiniWebServer does not support this method yet!");        return;    }    /* read headers and parse "Content-length"*/    char buf_header[MAXLINE];    int content_length = 0;    while (fgets(buf_header, 150, f) && (strlen(buf_header) > 2)) {        if (strncasecmp(buf_header, "Content-length:", 15) == 0) {            content_length = atoi(buf_header + 15);        }     }#ifdef DEBUG    printf("content length: %d \n", content_length);#endif        /* Parse URI */    int is_cgi = parse_uri(uri, filename, cgiargs);    struct stat sbuf;    if (stat(filename, &sbuf) < 0) {    	error_msg(fd, filename, "404", "Not found",		    "Couldn't find this file");	    return;    }    if (is_cgi) { /* Serve CGI request */	    if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {	        error_msg(fd, filename, "403", "Forbidden",			            "You have no permission to run the CGI program");	        return;	    }	    exec_cgi(fd, method, content_length, filename, cgiargs);    }    else { /* Serve static content */	    if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {	        error_msg(fd, filename, "403", "Forbidden",			            "You have no permission to read the file");	        return;	    }	    serve_static(fd, filename, sbuf.st_size);    }}/* * parse_uri - parse URI into filename and CGI args *             return 1 if cgi request, 0 if static */int parse_uri(char *uri, char *filename, char *cgiargs) {    char *ptr;    if (!strstr(uri, "cgi-bin")) {  /* Static content */    	strcpy(cgiargs, "");	    strcpy(filename, "."); /*serve the current directory*/	    strcat(filename, uri);	    if (uri[strlen(uri)-1] == '/')	        strcat(filename, "index.html");    	return 0;    }    else {  /* CGI request */	    ptr = index(uri, '?');	    if (ptr) {	        strcpy(cgiargs, ptr+1);	        *ptr = '\0';	    }	    else 	        strcpy(cgiargs, "");	            strcpy(filename, ".");	    strcat(filename, uri);	    return 1;    }}/* * serve_static - copy a file back to the client  */void serve_static(int fd, char *filename, int filesize) {#ifdef DEBUG        printf("serve static file: %s \n", filename);#endif        int srcfd;    char *srcp, filetype[MAXLINE], buf[MAXLINE];     /* Send response headers to client */    get_filetype(filename, filetype);    sprintf(buf, "HTTP/1.0 200 OK\r\n");    sprintf(buf, "%sServer: Mini Web Server\r\n", buf);    sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);    sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);    write(fd, buf, strlen(buf));    /* Send response body to client */    srcfd = open(filename, O_RDONLY, 0);    srcp = mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);    close(srcfd);    write(fd, srcp, filesize);    munmap(srcp, filesize);}/* * get_filetype - derive file type from file name */void get_filetype(char *filename, char *filetype) {    if (strstr(filename, ".html"))	    strcpy(filetype, "text/html");    else if (strstr(filename, ".gif"))    	strcpy(filetype, "image/gif");    else if (strstr(filename, ".jpg"))    	strcpy(filetype, "image/jpeg");    else    	strcpy(filetype, "text/plain");}  /* * exec_cgi - run a CGI program on behalf of the client */void exec_cgi(int fd, char *method, int content_length, char *filename, char *cgiargs) {    char buf[MAXLINE], *emptylist[] = { NULL };    /* Return first part of HTTP response */    sprintf(buf, "HTTP/1.1 200 OK\r\n");    write(fd, buf, strlen(buf));    sprintf(buf, "Server: Mini Web Server\r\n");    write(fd, buf, strlen(buf));      if (fork() == 0) { /* child */        /*handle POST method*/        if (strcasecmp(method, "POST") == 0) {            int pfd[2];            int rc = pipe(pfd);            if (rc < 0) {                perror("pipe in POST failed");                exit(1);            }            int post_pid = fork();            if (post_pid == 0) {                close(pfd[0]);                int n = 0, bytes_read = 0;                /*only read length of "content_length"*/                while (n < content_length) {                     bytes_read = read(fd, buf, sizeof(buf)-1);                    printf("content read: %s \n", buf);                    if (bytes_read > 0) {                        write(pfd[1], buf, bytes_read);                        n += bytes_read;                        }                }                exit(0);            }                             close(pfd[1]);            /*redirect to STDIN*/            dup2(pfd[0],STDIN_FILENO);        } 	    /* set CGI vars, only support "QUERY_STRING" and "CONTENT_LENGTH" */	    setenv("QUERY_STRING", cgiargs, 1);         sprintf(buf, "%d", content_length);        setenv("CONTENT_LENGTH", buf);	    dup2(fd, STDOUT_FILENO);         /* Redirect stdout to client */	    execve(filename, emptylist, environ); /* Run CGI program */    }    wait(NULL); /* Parent waits for and reaps child */}/* * error_msg - returns an error message to the client */void error_msg(int fd, char *cause, char *errnum, 		 char *shortmsg, char *longmsg) {    char buf[MAXLINE], body[MAXLINE];    /* Build the HTTP response body */    sprintf(body, "<html><title>Error</title>");    sprintf(body, "%s<body bgcolor=""ffffff"">\r\n", body);    sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg);    sprintf(body, "%s<p>%s: %s\r\n", body, longmsg, cause);    sprintf(body, "%s<hr><em>Mini Web server</em>\r\n", body);    /* Print the HTTP response */    sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);    write(fd, buf, strlen(buf));    sprintf(buf, "Content-type: text/html\r\n");    write(fd, buf, strlen(buf));    sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body));    write(fd, buf, strlen(buf));    write(fd, body, strlen(body));}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -