diff --git a/README.md b/README.md index 507b3f9..5c66fc5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +// 提交测试 +该项目的目的是学习并改写为 windows 环境下 C++ 构建的项目。 + A mirror for tinyhttpd(Tinyhttpd非官方镜像,Fork自[sourceForge](https://sourceforge.net/projects/tiny-httpd/),仅供学习) 测试CGI时需要本机安装PERL,同时安装perl-cgi diff --git a/httpd.c b/httpd.c deleted file mode 100644 index d4eb456..0000000 --- a/httpd.c +++ /dev/null @@ -1,516 +0,0 @@ -/* J. David's webserver */ -/* This is a simple webserver. - * Created November 1999 by J. David Blackstone. - * CSE 4344 (Network concepts), Prof. Zeigler - * University of Texas at Arlington - */ -/* This program compiles for Sparc Solaris 2.6. - * To compile for Linux: - * 1) Comment out the #include line. - * 2) Comment out the line that defines the variable newthread. - * 3) Comment out the two lines that run pthread_create(). - * 4) Uncomment the line that runs accept_request(). - * 5) Remove -lsocket from the Makefile. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ISspace(x) isspace((int)(x)) - -#define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n" -#define STDIN 0 -#define STDOUT 1 -#define STDERR 2 - -void accept_request(void *); -void bad_request(int); -void cat(int, FILE *); -void cannot_execute(int); -void error_die(const char *); -void execute_cgi(int, const char *, const char *, const char *); -int get_line(int, char *, int); -void headers(int, const char *); -void not_found(int); -void serve_file(int, const char *); -int startup(u_short *); -void unimplemented(int); - -/**********************************************************************/ -/* A request has caused a call to accept() on the server port to - * return. Process the request appropriately. - * Parameters: the socket connected to the client */ -/**********************************************************************/ -void accept_request(void *arg) -{ - int client = (intptr_t)arg; - char buf[1024]; - size_t numchars; - char method[255]; - char url[255]; - char path[512]; - size_t i, j; - struct stat st; - int cgi = 0; /* becomes true if server decides this is a CGI - * program */ - char *query_string = NULL; - - numchars = get_line(client, buf, sizeof(buf)); - i = 0; j = 0; - while (!ISspace(buf[i]) && (i < sizeof(method) - 1)) - { - method[i] = buf[i]; - i++; - } - j=i; - method[i] = '\0'; - - if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) - { - unimplemented(client); - return; - } - - if (strcasecmp(method, "POST") == 0) - cgi = 1; - - i = 0; - while (ISspace(buf[j]) && (j < numchars)) - j++; - while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < numchars)) - { - url[i] = buf[j]; - i++; j++; - } - url[i] = '\0'; - - if (strcasecmp(method, "GET") == 0) - { - query_string = url; - while ((*query_string != '?') && (*query_string != '\0')) - query_string++; - if (*query_string == '?') - { - cgi = 1; - *query_string = '\0'; - query_string++; - } - } - - sprintf(path, "htdocs%s", url); - if (path[strlen(path) - 1] == '/') - strcat(path, "index.html"); - if (stat(path, &st) == -1) { - while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ - numchars = get_line(client, buf, sizeof(buf)); - not_found(client); - } - else - { - if ((st.st_mode & S_IFMT) == S_IFDIR) - strcat(path, "/index.html"); - if ((st.st_mode & S_IXUSR) || - (st.st_mode & S_IXGRP) || - (st.st_mode & S_IXOTH) ) - cgi = 1; - if (!cgi) - serve_file(client, path); - else - execute_cgi(client, path, method, query_string); - } - - close(client); -} - -/**********************************************************************/ -/* Inform the client that a request it has made has a problem. - * Parameters: client socket */ -/**********************************************************************/ -void bad_request(int client) -{ - char buf[1024]; - - sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n"); - send(client, buf, sizeof(buf), 0); - sprintf(buf, "Content-type: text/html\r\n"); - send(client, buf, sizeof(buf), 0); - sprintf(buf, "\r\n"); - send(client, buf, sizeof(buf), 0); - sprintf(buf, "

Your browser sent a bad request, "); - send(client, buf, sizeof(buf), 0); - sprintf(buf, "such as a POST without a Content-Length.\r\n"); - send(client, buf, sizeof(buf), 0); -} - -/**********************************************************************/ -/* Put the entire contents of a file out on a socket. This function - * is named after the UNIX "cat" command, because it might have been - * easier just to do something like pipe, fork, and exec("cat"). - * Parameters: the client socket descriptor - * FILE pointer for the file to cat */ -/**********************************************************************/ -void cat(int client, FILE *resource) -{ - char buf[1024]; - - fgets(buf, sizeof(buf), resource); - while (!feof(resource)) - { - send(client, buf, strlen(buf), 0); - fgets(buf, sizeof(buf), resource); - } -} - -/**********************************************************************/ -/* Inform the client that a CGI script could not be executed. - * Parameter: the client socket descriptor. */ -/**********************************************************************/ -void cannot_execute(int client) -{ - char buf[1024]; - - sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "Content-type: text/html\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "

Error prohibited CGI execution.\r\n"); - send(client, buf, strlen(buf), 0); -} - -/**********************************************************************/ -/* Print out an error message with perror() (for system errors; based - * on value of errno, which indicates system call errors) and exit the - * program indicating an error. */ -/**********************************************************************/ -void error_die(const char *sc) -{ - perror(sc); - exit(1); -} - -/**********************************************************************/ -/* Execute a CGI script. Will need to set environment variables as - * appropriate. - * Parameters: client socket descriptor - * path to the CGI script */ -/**********************************************************************/ -void execute_cgi(int client, const char *path, - const char *method, const char *query_string) -{ - char buf[1024]; - int cgi_output[2]; - int cgi_input[2]; - pid_t pid; - int status; - int i; - char c; - int numchars = 1; - int content_length = -1; - - buf[0] = 'A'; buf[1] = '\0'; - if (strcasecmp(method, "GET") == 0) - while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ - numchars = get_line(client, buf, sizeof(buf)); - else if (strcasecmp(method, "POST") == 0) /*POST*/ - { - numchars = get_line(client, buf, sizeof(buf)); - while ((numchars > 0) && strcmp("\n", buf)) - { - buf[15] = '\0'; - if (strcasecmp(buf, "Content-Length:") == 0) - content_length = atoi(&(buf[16])); - numchars = get_line(client, buf, sizeof(buf)); - } - if (content_length == -1) { - bad_request(client); - return; - } - } - else/*HEAD or other*/ - { - } - - - if (pipe(cgi_output) < 0) { - cannot_execute(client); - return; - } - if (pipe(cgi_input) < 0) { - cannot_execute(client); - return; - } - - if ( (pid = fork()) < 0 ) { - cannot_execute(client); - return; - } - sprintf(buf, "HTTP/1.0 200 OK\r\n"); - send(client, buf, strlen(buf), 0); - if (pid == 0) /* child: CGI script */ - { - char meth_env[255]; - char query_env[255]; - char length_env[255]; - - dup2(cgi_output[1], STDOUT); - dup2(cgi_input[0], STDIN); - close(cgi_output[0]); - close(cgi_input[1]); - sprintf(meth_env, "REQUEST_METHOD=%s", method); - putenv(meth_env); - if (strcasecmp(method, "GET") == 0) { - sprintf(query_env, "QUERY_STRING=%s", query_string); - putenv(query_env); - } - else { /* POST */ - sprintf(length_env, "CONTENT_LENGTH=%d", content_length); - putenv(length_env); - } - execl(path, NULL); - exit(0); - } else { /* parent */ - close(cgi_output[1]); - close(cgi_input[0]); - if (strcasecmp(method, "POST") == 0) - for (i = 0; i < content_length; i++) { - recv(client, &c, 1, 0); - write(cgi_input[1], &c, 1); - } - while (read(cgi_output[0], &c, 1) > 0) - send(client, &c, 1, 0); - - close(cgi_output[0]); - close(cgi_input[1]); - waitpid(pid, &status, 0); - } -} - -/**********************************************************************/ -/* Get a line from a socket, whether the line ends in a newline, - * carriage return, or a CRLF combination. Terminates the string read - * with a null character. If no newline indicator is found before the - * end of the buffer, the string is terminated with a null. If any of - * the above three line terminators is read, the last character of the - * string will be a linefeed and the string will be terminated with a - * null character. - * Parameters: the socket descriptor - * the buffer to save the data in - * the size of the buffer - * Returns: the number of bytes stored (excluding null) */ -/**********************************************************************/ -int get_line(int sock, char *buf, int size) -{ - int i = 0; - char c = '\0'; - int n; - - while ((i < size - 1) && (c != '\n')) - { - n = recv(sock, &c, 1, 0); - /* DEBUG printf("%02X\n", c); */ - if (n > 0) - { - if (c == '\r') - { - n = recv(sock, &c, 1, MSG_PEEK); - /* DEBUG printf("%02X\n", c); */ - if ((n > 0) && (c == '\n')) - recv(sock, &c, 1, 0); - else - c = '\n'; - } - buf[i] = c; - i++; - } - else - c = '\n'; - } - buf[i] = '\0'; - - return(i); -} - -/**********************************************************************/ -/* Return the informational HTTP headers about a file. */ -/* Parameters: the socket to print the headers on - * the name of the file */ -/**********************************************************************/ -void headers(int client, const char *filename) -{ - char buf[1024]; - (void)filename; /* could use filename to determine file type */ - - strcpy(buf, "HTTP/1.0 200 OK\r\n"); - send(client, buf, strlen(buf), 0); - strcpy(buf, SERVER_STRING); - send(client, buf, strlen(buf), 0); - sprintf(buf, "Content-Type: text/html\r\n"); - send(client, buf, strlen(buf), 0); - strcpy(buf, "\r\n"); - send(client, buf, strlen(buf), 0); -} - -/**********************************************************************/ -/* Give a client a 404 not found status message. */ -/**********************************************************************/ -void not_found(int client) -{ - char buf[1024]; - - sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, SERVER_STRING); - send(client, buf, strlen(buf), 0); - sprintf(buf, "Content-Type: text/html\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "Not Found\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "

The server could not fulfill\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "your request because the resource specified\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "is unavailable or nonexistent.\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "\r\n"); - send(client, buf, strlen(buf), 0); -} - -/**********************************************************************/ -/* Send a regular file to the client. Use headers, and report - * errors to client if they occur. - * Parameters: a pointer to a file structure produced from the socket - * file descriptor - * the name of the file to serve */ -/**********************************************************************/ -void serve_file(int client, const char *filename) -{ - FILE *resource = NULL; - int numchars = 1; - char buf[1024]; - - buf[0] = 'A'; buf[1] = '\0'; - while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ - numchars = get_line(client, buf, sizeof(buf)); - - resource = fopen(filename, "r"); - if (resource == NULL) - not_found(client); - else - { - headers(client, filename); - cat(client, resource); - } - fclose(resource); -} - -/**********************************************************************/ -/* This function starts the process of listening for web connections - * on a specified port. If the port is 0, then dynamically allocate a - * port and modify the original port variable to reflect the actual - * port. - * Parameters: pointer to variable containing the port to connect on - * Returns: the socket */ -/**********************************************************************/ -int startup(u_short *port) -{ - int httpd = 0; - int on = 1; - struct sockaddr_in name; - - httpd = socket(PF_INET, SOCK_STREAM, 0); - if (httpd == -1) - error_die("socket"); - memset(&name, 0, sizeof(name)); - name.sin_family = AF_INET; - name.sin_port = htons(*port); - name.sin_addr.s_addr = htonl(INADDR_ANY); - if ((setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) - { - error_die("setsockopt failed"); - } - if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0) - error_die("bind"); - if (*port == 0) /* if dynamically allocating a port */ - { - socklen_t namelen = sizeof(name); - if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1) - error_die("getsockname"); - *port = ntohs(name.sin_port); - } - if (listen(httpd, 5) < 0) - error_die("listen"); - return(httpd); -} - -/**********************************************************************/ -/* Inform the client that the requested web method has not been - * implemented. - * Parameter: the client socket */ -/**********************************************************************/ -void unimplemented(int client) -{ - char buf[1024]; - - sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, SERVER_STRING); - send(client, buf, strlen(buf), 0); - sprintf(buf, "Content-Type: text/html\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "Method Not Implemented\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "

HTTP request method not supported.\r\n"); - send(client, buf, strlen(buf), 0); - sprintf(buf, "\r\n"); - send(client, buf, strlen(buf), 0); -} - -/**********************************************************************/ - -int main(void) -{ - int server_sock = -1; - u_short port = 4000; - int client_sock = -1; - struct sockaddr_in client_name; - socklen_t client_name_len = sizeof(client_name); - pthread_t newthread; - - server_sock = startup(&port); - printf("httpd running on port %d\n", port); - - while (1) - { - client_sock = accept(server_sock, - (struct sockaddr *)&client_name, - &client_name_len); - if (client_sock == -1) - error_die("accept"); - /* accept_request(&client_sock); */ - if (pthread_create(&newthread , NULL, (void *)accept_request, (void *)(intptr_t)client_sock) != 0) - perror("pthread_create"); - } - - close(server_sock); - - return(0); -} diff --git a/httpd.cpp b/httpd.cpp new file mode 100644 index 0000000..c87815e --- /dev/null +++ b/httpd.cpp @@ -0,0 +1,563 @@ +/* J. David's webserver */ +/* This is a simple webserver. + * Created November 1999 by J. David Blackstone. + * CSE 4344 (Network concepts), Prof. Zeigler + * University of Texas at Arlington + */ + /* This program compiles for Sparc Solaris 2.6. + * To compile for Linux: + * 1) Comment out the #include line. + * 2) Comment out the line that defines the variable newthread. + * 3) Comment out the two lines that run pthread_create(). + * 4) Uncomment the line that runs accept_request(). + * 5) Remove -lsocket from the Makefile. + */ +#include + // #include // + // #include // + // #include // +#include // +// Ӹ lib +#pragma comment(lib,"Ws2_32.lib") // +#include +// #include +#include +// #include +#include +#include +// #include +#include +// #include +#include +#include + +#define ISspace(x) isspace((int)(x)) + +#define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n" +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 + +//void accept_request(void *); +void accept_request(SOCKET); +void bad_request(SOCKET); +void cat(SOCKET, FILE*); +void cannot_execute(SOCKET); +inline void error_die(const char*); +void execute_cgi(SOCKET, const char*, const char*, const char*); +int get_line(SOCKET, char*, int); +void headers(SOCKET, const char*); +void not_found(SOCKET); +void serve_file(SOCKET, const char*); +SOCKET startup(u_short*); +void unimplemented(SOCKET); + +/**********************************************************************/ +/* Print out an error message with perror() (for system errors; based + * on value of errno, which indicates system call errors) and exit the + * program indicating an error. */ + /**********************************************************************/ +inline void error_die(const char* sc) { + printf("%s failed with error: %d\n", sc, WSAGetLastError()); + WSACleanup(); + exit(1); +} + +// ȽЧַǷ +int strcasecmp(const char* str1, const char* str2) { + int i = 0; + char c1, c2; + while (str1[i] != '\0' && str2[i] != '\0') { + c1 = tolower(str1[i]); + c2 = tolower(str2[i]); + if (c1 != c2) + return c1 - c2; + i++; + } + return 0; +} +/**********************************************************************/ +/* A request has caused a call to accept() on the server port to + * return. Process the request appropriately. + * Parameters: the socket connected to the client */ + /**********************************************************************/ +void accept_request(SOCKET client) +{ + //int client = (intptr_t)arg; + char buf[1024]; + size_t numchars; + char method[255]; + char url[255]; + char path[512]; + size_t i, j; + struct stat st; + int cgi = 0; /* becomes true if server decides this is a CGI + * program */ + char* query_string = NULL; + + numchars = get_line(client, buf, sizeof(buf)); + printf("Recv the message: %s\n", buf); + i = 0; j = 0; + while (!ISspace(buf[i]) && (i < sizeof(method) - 1)) + { + method[i] = buf[i]; + i++; + } + j = i; + method[i] = '\0'; + + if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) + { + unimplemented(client); + return; + } + + if (strcasecmp(method, "POST") == 0) + cgi = 1; + + i = 0; + while (ISspace(buf[j]) && (j < numchars)) + j++; + while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < numchars)) + { + url[i] = buf[j]; + i++; j++; + } + url[i] = '\0'; + + if (strcasecmp(method, "GET") == 0) + { + query_string = url; + while ((*query_string != '?') && (*query_string != '\0')) + query_string++; + if (*query_string == '?') + { + cgi = 1; + *query_string = '\0'; + query_string++; + } + } + + sprintf_s(path, "htdocs%s", url); + if (path[strlen(path) - 1] == '/') + // C ⺯ char *strcat(char *dest, const char *src) src ַָ׷ӵ dest ַָĽβ + strcat_s(path, sizeof(path), "index.html"); + + //ͷļ#include #include + //庯int stat(const char* file_name, struct stat* buf); + //˵stat()file_name ָļ״̬, Ƶbuf ָĽṹС + //ִֵгɹ򷵻0ʧܷ-1errno + if (stat(path, &st) == -1) { + //C ⺯ int strcmp(const char *str1, const char *str2) str1 ַָ str2 ַָбȽϡ + //úֵ£ + // ֵ str1-str2 ͬţΪǷ falseͬʱ true + //ֵС 0ʾ str1 С str2 + //ֵ 0ʾ str1 str2 + //ֵ 0ʾ str1 str2 + while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ + numchars = get_line(client, buf, sizeof(buf)); + not_found(client); + } + else + { + if ((st.st_mode & S_IFMT) == S_IFDIR) + strcat_s(path, sizeof(path), "/index.html"); + /* + if ((st.st_mode & S_IXUSR) || + (st.st_mode & S_IXGRP) || + (st.st_mode & S_IXOTH) ) + cgi = 1; + */ + if (!cgi) + serve_file(client, path); + else + execute_cgi(client, path, method, query_string); + } + + closesocket(client); +} + +/**********************************************************************/ +/* Inform the client that a request it has made has a problem. + * Parameters: client socket */ + /**********************************************************************/ +void bad_request(SOCKET client) +{ + char buf[1024]; + + sprintf_s(buf, "HTTP/1.0 400 BAD REQUEST\r\n"); + send(client, buf, sizeof(buf), 0); + sprintf_s(buf, "Content-type: text/html\r\n"); + send(client, buf, sizeof(buf), 0); + sprintf_s(buf, "\r\n"); + send(client, buf, sizeof(buf), 0); + sprintf_s(buf, "

Your browser sent a bad request, "); + send(client, buf, sizeof(buf), 0); + sprintf_s(buf, "such as a POST without a Content-Length.\r\n"); + send(client, buf, sizeof(buf), 0); +} + +/**********************************************************************/ +/* Put the entire contents of a file out on a socket. This function + * is named after the UNIX "cat" command, because it might have been + * easier just to do something like pipe, fork, and exec("cat"). + * Parameters: the client socket descriptor + * FILE pointer for the file to cat */ + /**********************************************************************/ +void cat(SOCKET client, FILE* resource) +{ + char buf[1024]; + + fgets(buf, sizeof(buf), resource); + while (!feof(resource)) + { + send(client, buf, int(strlen(buf)), 0); + fgets(buf, sizeof(buf), resource); + } +} + +/**********************************************************************/ +/* Inform the client that a CGI script could not be executed. + * Parameter: the client socket descriptor. */ + /**********************************************************************/ +void cannot_execute(SOCKET client) +{ + char buf[1024]; + + sprintf_s(buf, "HTTP/1.0 500 Internal Server Error\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "Content-type: text/html\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "

Error prohibited CGI execution.\r\n"); + send(client, buf, (int)strlen(buf), 0); +} + +/**********************************************************************/ +/* Execute a CGI script. Will need to set environment variables as + * appropriate. + * Parameters: client socket descriptor + * path to the CGI script */ + /**********************************************************************/ +void execute_cgi(SOCKET client, const char* path, + const char* method, const char* query_string) +{ + //char buf[1024]; + //int cgi_output[2]; + //int cgi_input[2]; + //// pid_t Linux ڶ IDҪͷļ + //pid_t pid; + //int status; + //int i; + //char c; + //int numchars = 1; + //int content_length = -1; + + //buf[0] = 'A'; buf[1] = '\0'; + //if (strcasecmp(method, "GET") == 0) + // while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ + // numchars = get_line(client, buf, sizeof(buf)); + //else if (strcasecmp(method, "POST") == 0) /*POST*/ + //{ + // numchars = get_line(client, buf, sizeof(buf)); + // while ((numchars > 0) && strcmp("\n", buf)) + // { + // buf[15] = '\0'; + // if (strcasecmp(buf, "Content-Length:") == 0) + // content_length = atoi(&(buf[16])); + // numchars = get_line(client, buf, sizeof(buf)); + // } + // if (content_length == -1) { + // bad_request(client); + // return; + // } + //} + //else/*HEAD or other*/ + //{ + //} + + + //if (pipe(cgi_output) < 0) { + // cannot_execute(client); + // return; + //} + //if (pipe(cgi_input) < 0) { + // cannot_execute(client); + // return; + //} + + //if ( (pid = fork()) < 0 ) { + // cannot_execute(client); + // return; + //} + //sprintf_s(buf, "HTTP/1.0 200 OK\r\n"); + //send(client, buf, strlen(buf), 0); + //if (pid == 0) /* child: CGI script */ + //{ + // char meth_env[255]; + // char query_env[255]; + // char length_env[255]; + + // dup2(cgi_output[1], STDOUT); + // dup2(cgi_input[0], STDIN); + // close(cgi_output[0]); + // close(cgi_input[1]); + // sprintf_s(meth_env, "REQUEST_METHOD=%s", method); + // putenv(meth_env); + // if (strcasecmp(method, "GET") == 0) { + // sprintf_s(query_env, "QUERY_STRING=%s", query_string); + // putenv(query_env); + // } + // else { /* POST */ + // sprintf_s(length_env, "CONTENT_LENGTH=%d", content_length); + // putenv(length_env); + // } + // execl(path, NULL); + // exit(0); + //} else { /* parent */ + // close(cgi_output[1]); + // close(cgi_input[0]); + // if (strcasecmp(method, "POST") == 0) + // for (i = 0; i < content_length; i++) { + // recv(client, &c, 1, 0); + // write(cgi_input[1], &c, 1); + // } + // while (read(cgi_output[0], &c, 1) > 0) + // send(client, &c, 1, 0); + + // close(cgi_output[0]); + // close(cgi_input[1]); + // waitpid(pid, &status, 0); + //} +} + +/**********************************************************************/ +/* Get a line from a socket, whether the line ends in a newline, + * carriage return, or a CRLF combination. Terminates the string read + * with a null character. If no newline indicator is found before the + * end of the buffer, the string is terminated with a null. If any of + * the above three line terminators is read, the last character of the + * string will be a linefeed and the string will be terminated with a + * null character. + * Parameters: the socket descriptor + * the buffer to save the data in + * the size of the buffer + * Returns: the number of bytes stored (excluding null) */ + /**********************************************************************/ +int get_line(SOCKET sock, char* buf, int size) +{ + int i = 0; + char c = '\0'; + int n; + + while ((i < size - 1) && (c != '\n')) + { + n = recv(sock, &c, 1, 0); + /* DEBUG printf("%02X\n", c); */ + if (n > 0) + { + if (c == '\r') + { + n = recv(sock, &c, 1, MSG_PEEK); + /* DEBUG printf("%02X\n", c); */ + if ((n > 0) && (c == '\n')) + recv(sock, &c, 1, 0); + else + c = '\n'; + } + buf[i] = c; + i++; + } + else + c = '\n'; + } + buf[i] = '\0'; + + return(i); +} + +/**********************************************************************/ +/* Return the informational HTTP headers about a file. */ +/* Parameters: the socket to print the headers on + * the name of the file */ + /**********************************************************************/ +void headers(SOCKET client, const char* filename) +{ + char buf[1024]; + (void)filename; /* could use filename to determine file type */ + + strcpy_s(buf, sizeof(buf), "HTTP/1.0 200 OK\r\n"); + send(client, buf, (int)strlen(buf), 0); + strcpy_s(buf, sizeof(buf), SERVER_STRING); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, sizeof(buf), "Content-Type: text/html\r\n"); + send(client, buf, (int)strlen(buf), 0); + strcpy_s(buf, sizeof(buf), "\r\n"); + send(client, buf, (int)strlen(buf), 0); +} + +/**********************************************************************/ +/* Give a client a 404 not found status message. */ +/**********************************************************************/ +void not_found(SOCKET client) +{ + char buf[1024]; + + sprintf_s(buf, "HTTP/1.0 404 NOT FOUND\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, SERVER_STRING); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "Content-Type: text/html\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "Not Found\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "

The server could not fulfill\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "your request because the resource specified\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "is unavailable or nonexistent.\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "\r\n"); + send(client, buf, (int)strlen(buf), 0); +} + +/**********************************************************************/ +/* Send a regular file to the client. Use headers, and report + * errors to client if they occur. + * Parameters: a pointer to a file structure produced from the socket + * file descriptor + * the name of the file to serve */ + /**********************************************************************/ +void serve_file(SOCKET client, const char* filename) +{ + FILE* resource = NULL; + int numchars = 1; + char buf[1024]; + + buf[0] = 'A'; buf[1] = '\0'; + while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ + numchars = get_line(client, buf, sizeof(buf)); + + resource = fopen(filename, "r"); + if (resource == NULL) + not_found(client); + else + { + headers(client, filename); + cat(client, resource); + } + fclose(resource); +} + +/**********************************************************************/ +/* This function starts the process of listening for web connections + * on a specified port. If the port is 0, then dynamically allocate a + * port and modify the original port variable to reflect the actual + * port. + * Parameters: pointer to variable containing the port to connect on + * Returns: the socket */ + /**********************************************************************/ +SOCKET startup(u_short* port) +{ + SOCKET httpd = 0; + char on[4]{}; + struct sockaddr_in name; + + httpd = socket(PF_INET, SOCK_STREAM, 0); + if (httpd == -1) + error_die("socket"); + //memset(&name, 0, sizeof(name)); + ZeroMemory(&name, sizeof(name)); + name.sin_family = AF_INET; + name.sin_port = htons(*port); + name.sin_addr.s_addr = htonl(INADDR_ANY); + if ((setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, on, sizeof(on))) < 0) + { + error_die("setsockopt"); + } + if (bind(httpd, (struct sockaddr*)&name, sizeof(name)) < 0) + error_die("bind"); + if (*port == 0) /* if dynamically allocating a port */ + { + int namelen = sizeof(name); + if (getsockname(httpd, (struct sockaddr*)&name, &namelen) == -1) + error_die("getsockname"); + *port = ntohs(name.sin_port); + } + if (listen(httpd, 5) != 0)//2Ӷе󳤶 + error_die("listen"); + return(httpd); +} + +/**********************************************************************/ +/* Inform the client that the requested web method has not been + * implemented. + * Parameter: the client socket */ + /**********************************************************************/ +void unimplemented(SOCKET client) +{ + char buf[1024]; + + sprintf_s(buf, "HTTP/1.0 501 Method Not Implemented\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, SERVER_STRING); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "Content-Type: text/html\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "Method Not Implemented\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "

HTTP request method not supported.\r\n"); + send(client, buf, (int)strlen(buf), 0); + sprintf_s(buf, "\r\n"); + send(client, buf, (int)strlen(buf), 0); +} + +/**********************************************************************/ + +int main() +{ + // ʼDLL + WSADATA wsaData; + int result = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (result != 0) { + printf("WSAStartup failed: %d\n", result); + return 1; + } + + SOCKET server_sock = -1; + u_short port = 27015; + SOCKET client_sock = -1; + struct sockaddr_in client_name; + int client_name_len = sizeof(client_name); + //pthread_t newthread; + + server_sock = startup(&port); + printf("httpd running on port %d\n", port); + + while (1) + { + client_sock = accept(server_sock, + (struct sockaddr*)&client_name, + &client_name_len); + if (client_sock == INVALID_SOCKET) + error_die("accept"); + /* accept_request(&client_sock); */ + /*if (pthread_create(&newthread, NULL, (void*)accept_request, (void*)(intptr_t)client_sock) != 0) + perror("pthread_create");*/ + + std::thread newthread(accept_request, client_sock); + } + + //close(server_sock);// + closesocket(server_sock); + WSACleanup(); + + return(0); +} diff --git a/simpleclient.c b/simpleclient.c index b868014..1efa3fd 100644 --- a/simpleclient.c +++ b/simpleclient.c @@ -5,7 +5,7 @@ #include #include -int main(int argc, char *argv[]) +int main2(int argc, char *argv[]) { int sockfd; int len;