-
-
Save eden-chung/bbb2af0e035835e4fd1c22aa196adda8 to your computer and use it in GitHub Desktop.
HTTP Server and Client
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <ctype.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <assert.h> | |
| #include <unistd.h> | |
| #include <sys/wait.h> | |
| #include <sys/stat.h> | |
| #include <arpa/inet.h> | |
| #include <sys/types.h> | |
| #include <sys/socket.h> | |
| #include <netdb.h> | |
| static void die(const char *s) { perror(s); exit(1); } | |
| int main(int argc, char **argv) | |
| { | |
| if (argc != 4) { | |
| //fprintf(stderr, "usage: %s <host name> <port number> <file path> \n", argv[0]); | |
| fprintf(stderr, "usage: http-client <host name> <port number> <file path> \n ex) http-client www.example.com 80 /index.html\n"); | |
| exit(1); | |
| } | |
| if (argv[3][0] != '/') { | |
| fprintf(stderr, "usage: http-client <host name> <port number> <file path> \n ex) http-client www.example.com 80 /index.html\n"); | |
| exit(1); | |
| } | |
| if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) | |
| die("signal() failed"); | |
| char *host_name = argv[1]; | |
| unsigned short port = atoi(argv[2]); | |
| char *file_path = argv[3]; | |
| // Create a listening socket (also called server socket) | |
| int sock; | |
| if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) | |
| die("socket failed"); | |
| struct hostent *he; | |
| char *serverName = argv[1]; | |
| // get server ip from server name | |
| if ((he = gethostbyname(serverName)) == NULL) { | |
| die("gethostbyname failed"); | |
| } | |
| char *serverIP = inet_ntoa(*(struct in_addr *)he->h_addr); | |
| // Construct a server address structure | |
| struct sockaddr_in servaddr; | |
| memset(&servaddr, 0, sizeof(servaddr)); | |
| servaddr.sin_family = AF_INET; | |
| servaddr.sin_addr.s_addr = inet_addr(serverIP); | |
| servaddr.sin_port = htons(port); | |
| char header_request[1000]; | |
| snprintf(header_request, 1000, "GET %s HTTP/1.0\r\nHost: %s:%d\r\n\r\n", file_path, host_name, port); | |
| // Establish a TCP connection to the server | |
| if (connect(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) | |
| die("connect failed"); | |
| if (send(sock, header_request, strlen(header_request), 0) != strlen(header_request)) | |
| die("send size failed"); | |
| //getting the last part of the url | |
| char *file_output_name; | |
| file_output_name = strrchr(file_path, '/') + 1; | |
| FILE *input = fdopen(sock, "r"); | |
| char line[4000]; | |
| int count = 0; | |
| while (fgets(line, sizeof(line), input) != NULL) { | |
| if (count == 0) { | |
| if (((line[5] == '1' && line[6] == '.' && line[7] == '0') || (line[5] == '1' && line[6] == '.' && line[7] == '1')) && (line[9] == '2' && line[10] == '0' && line[11] == '0')) { | |
| ; | |
| } else { | |
| printf("%s\n", line); | |
| exit(1); | |
| } | |
| } | |
| if(line[0] == '\r' && line[1] == '\n') { | |
| break; | |
| } | |
| count++; | |
| } | |
| FILE *output_file = fopen(file_output_name, "wb"); | |
| if (output_file == NULL) { | |
| die("can't open output file"); | |
| } | |
| int size_line_read; | |
| while ((size_line_read = fread(line, 1, sizeof(line), input)) > 0) { | |
| fwrite(line, 1, size_line_read, output_file); | |
| } | |
| fclose(input); | |
| fclose(output_file); | |
| close(sock); | |
| return 0; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <assert.h> | |
| #include <unistd.h> | |
| #include <sys/wait.h> | |
| #include <sys/stat.h> | |
| #include <arpa/inet.h> | |
| #include <sys/types.h> | |
| #include <sys/socket.h> | |
| #include <netdb.h> | |
| static void die(const char *s) { perror(s); exit(1); } | |
| int main(int argc, char **argv) | |
| { | |
| if (argc != 5) { | |
| fprintf(stderr, "usage: %s <server-port> <web-root> <mdb-lookup-host> <mdb-lookup-port>\n", argv[0]); | |
| exit(1); | |
| } | |
| unsigned short server_port = atoi(argv[1]); | |
| const char *web_root = argv[2]; | |
| const char *mdb_lookup_host = argv[3]; | |
| unsigned short mdb_lookup_port = atoi(argv[4]); | |
| // Create a listening socket (also called server socket) | |
| int servsock; | |
| if ((servsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) | |
| die("socket failed"); | |
| // Construct local address structure | |
| struct sockaddr_in servaddr; | |
| memset(&servaddr, 0, sizeof(servaddr)); | |
| servaddr.sin_family = AF_INET; | |
| servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // any network interface | |
| servaddr.sin_port = htons(server_port); | |
| // Bind to the local address | |
| if (bind(servsock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) | |
| die("bind failed"); | |
| // Start listening for incoming connections | |
| if (listen(servsock, 5 /* queue size for connection requests */ ) < 0) | |
| die("listen failed"); | |
| int clntsock; | |
| socklen_t clntlen; | |
| struct sockaddr_in clntaddr; | |
| int r; | |
| char buf[4096]; | |
| char buf_withoutnewline[4096]; | |
| char ipaddress[4096]; | |
| //mdb lookup section | |
| // Create a socket for TCP connection | |
| struct hostent *he; | |
| // get server ip from server name | |
| if ((he = gethostbyname(mdb_lookup_host)) == NULL) { | |
| die("gethostbyname failed"); | |
| } | |
| char *serverIP = inet_ntoa(*(struct in_addr *)he->h_addr); | |
| // Construct a server address structure | |
| int sock; | |
| if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) | |
| die("socket failed"); | |
| struct sockaddr_in servaddr_mdb; | |
| memset(&servaddr_mdb, 0, sizeof(servaddr_mdb)); // must zero out the structure | |
| servaddr_mdb.sin_family = AF_INET; | |
| servaddr_mdb.sin_addr.s_addr = inet_addr(serverIP); | |
| servaddr_mdb.sin_port = htons(mdb_lookup_port); // must be in network byte order | |
| // Establish a TCP connection to the server | |
| if (connect(sock, (struct sockaddr *) &servaddr_mdb, sizeof(servaddr_mdb)) < 0) | |
| die("connect failed"); | |
| FILE *mdb = fdopen(sock, "r"); | |
| if (mdb == NULL) { | |
| die("IO error"); | |
| } | |
| while (1) { | |
| // Accept an incoming connection | |
| clntlen = sizeof(clntaddr); // initialize the in-out parameter | |
| if ((clntsock = accept(servsock, | |
| (struct sockaddr *) &clntaddr, &clntlen)) < 0) | |
| die("accept failed"); | |
| FILE *input = fdopen(clntsock, "r"); | |
| char *invalid_response_400 = "HTTP/1.0 400 Bad Request\r\n\r\n<html><body><h1>400 Bad Request</h1></body></html>\r\n"; | |
| if (input == NULL) { | |
| if (send(clntsock, invalid_response_400, strlen(invalid_response_400), 0) != strlen(invalid_response_400)) { | |
| continue; | |
| } | |
| fprintf(stderr, "\" \" 400 Bad Request\n"); | |
| continue; | |
| } | |
| //read in line by line instead | |
| if (fgets(buf, sizeof(buf), input) == NULL) { | |
| if (send(clntsock, invalid_response_400, strlen(invalid_response_400), 0) != strlen(invalid_response_400)) { | |
| fclose(input); | |
| continue; | |
| } | |
| fprintf(stderr, "\" \" 400 Bad Request\n"); | |
| fclose(input); | |
| continue; | |
| } | |
| if (fgets(ipaddress, sizeof(ipaddress), input) == NULL) { | |
| if (send(clntsock, invalid_response_400, strlen(invalid_response_400), 0) != strlen(invalid_response_400)) { | |
| fclose(input); | |
| continue; | |
| } | |
| fprintf(stderr, "\" \" 400 Bad Request\n"); | |
| fclose(input); | |
| continue; | |
| } | |
| //error checking | |
| char *end_line = strchr(buf, '\r'); | |
| if (end_line != NULL) { | |
| size_t len_buf = end_line - buf; | |
| strncpy(buf_withoutnewline, buf, len_buf); | |
| } | |
| char *invalid_response_501 = "HTTP/1.0 501 Not Implemented\r\n\r\n<html><body><h1>501 Not Implemented</h1></body></html>\r\n"; | |
| char *token_separators = "\t \r\n"; // tab, space, new line | |
| char *method = strtok(buf, token_separators); | |
| char *requestURI = strtok(NULL, token_separators); | |
| char *httpVersion = strtok(NULL, token_separators); | |
| struct stat statbuf; | |
| int resStat = stat(requestURI, &statbuf); | |
| int isDir = S_ISDIR(statbuf.st_mode); | |
| if (method == NULL || requestURI == NULL || httpVersion == NULL) { | |
| if (send(clntsock, invalid_response_400, strlen(invalid_response_400), 0) != strlen(invalid_response_400)) { | |
| fclose(input); | |
| continue; | |
| } | |
| fprintf(stderr, "%s \"%s %s %s\" 400 Bad Request\n", inet_ntoa(clntaddr.sin_addr), method, requestURI, httpVersion); | |
| fclose(input); | |
| continue; | |
| } else if (strcmp(method, "GET") != 0 || (strcmp(httpVersion, "HTTP/1.1") != 0 && strcmp(httpVersion, "HTTP/1.0") != 0 )) { | |
| if (send(clntsock, invalid_response_501, strlen(invalid_response_501), 0) != strlen(invalid_response_501)) { | |
| fclose(input); | |
| continue; | |
| } | |
| fprintf(stderr, "%s \"%s %s %s\" 501 Not Implemented\n", inet_ntoa(clntaddr.sin_addr), method, requestURI, httpVersion); | |
| fclose(input); | |
| continue; | |
| } else if(requestURI[0] != '/') { | |
| if (send(clntsock, invalid_response_400, strlen(invalid_response_400), 0) != strlen(invalid_response_400)) { | |
| fclose(input); | |
| continue; | |
| } | |
| fprintf(stderr, "%s \"%s %s %s\" 400 Bad Request\n", inet_ntoa(clntaddr.sin_addr), method, requestURI, httpVersion); | |
| fclose(input); | |
| continue; | |
| } else if (strstr(requestURI, "/..") != NULL || strstr(requestURI, "/../") != NULL) { | |
| if (send(clntsock, invalid_response_400, strlen(invalid_response_400), 0) != strlen(invalid_response_400)) { | |
| fclose(input); | |
| continue; | |
| } | |
| fprintf(stderr, "%s \"%s %s %s\" 400 Bad Request\n", inet_ntoa(clntaddr.sin_addr), method, requestURI, httpVersion); | |
| fclose(input); | |
| continue; | |
| } else if ((resStat == 0 && isDir == 0) && web_root[strlen(web_root) - 1] != '/') { | |
| if (send(clntsock, invalid_response_501, strlen(invalid_response_501), 0) != strlen(invalid_response_501)) { | |
| fclose(input); | |
| continue; | |
| } | |
| fprintf(stderr, "%s \"%s %s %s\" 501 Not Implemented\n", inet_ntoa(clntaddr.sin_addr), method, requestURI, httpVersion); | |
| fclose(input); | |
| continue; | |
| } else if (strstr(requestURI, "/mdb-lookup")) { | |
| char *ok_header = "HTTP/1.0 200 OK\r\n\r\n"; | |
| if (send(clntsock, ok_header, strlen(ok_header), 0) != strlen(ok_header)) { | |
| fclose(input); | |
| continue; | |
| } | |
| const char *form = | |
| "<h1>mdb-lookup</h1>\n" | |
| "<p>\n" | |
| "<form method=GET action=/mdb-lookup>\n" | |
| "lookup: <input type=text name=key>\n" | |
| "<input type=submit>\n" | |
| "</form>\n" | |
| "<p>\n"; | |
| if (send(clntsock, form, strlen(form), 0) != strlen(form)) { | |
| fclose(input); | |
| continue; | |
| } | |
| if (strstr(requestURI, "?key=")) { | |
| //get the part after = | |
| char *key = strchr(requestURI, '=') + 1; | |
| char key_with_new_line[4096]; | |
| sprintf(key_with_new_line, "%s\n", key); | |
| if (send(sock, key_with_new_line, strlen(key_with_new_line), 0) != strlen(key_with_new_line)) { | |
| fprintf(stderr, "ERROR"); | |
| fclose(input); | |
| continue; | |
| } | |
| char entry[1096]; | |
| char *table_beg = "<table border=\"\">\n"; | |
| char *table_end = "</table>\n"; | |
| if (send(clntsock, table_beg, strlen(table_beg), 0) != strlen(table_beg)) { | |
| fclose(input); | |
| continue; | |
| } | |
| //while(fgets(entry, sizeof(entry), mdb) != NULL) { | |
| while(1) { | |
| if(fgets(entry, sizeof(entry), mdb) == NULL) { | |
| char *invalid_response_500 = "<html><body><h1>500 Internal Server Error</h1></body></html>\r\n"; | |
| if (send(clntsock, invalid_response_500, strlen(invalid_response_500), 0) != strlen(invalid_response_500)) { | |
| fclose(input); | |
| break; | |
| } | |
| fprintf(stderr, "mdb-lookup-server connection failed: Broken pipe\n"); | |
| break; | |
| } | |
| if (strcmp(entry, "\n") == 0) { | |
| break; | |
| } | |
| char row[4096]; | |
| sprintf(row, "<tr>\n<td>\n%s\n</td>\n</tr>\n", entry); | |
| if (send(clntsock, row, strlen(row), 0) != strlen(row)) { | |
| fclose(input); | |
| continue; | |
| } | |
| } | |
| if (send(clntsock, table_end, strlen(table_end), 0) != strlen(table_end)) { | |
| fclose(input); | |
| continue; | |
| } | |
| fprintf(stderr, "looking up [%s]: ", key); | |
| } | |
| fprintf(stderr, "%s \"%s %s %s\" 200 OK\n", inet_ntoa(clntaddr.sin_addr), method, requestURI, httpVersion); | |
| } else { | |
| //READ FILE FROM WEB ROOT | |
| char request_path[1096]; | |
| sprintf(request_path, "%s%s", web_root, requestURI); | |
| char text_buf[4096]; | |
| char request_path_new[4096]; | |
| if (request_path[strlen(request_path) - 1] == '/') { | |
| sprintf(request_path_new, "%sindex.html", request_path); | |
| } else { | |
| sprintf(request_path_new, "%s", request_path); | |
| } | |
| FILE *output = fopen(request_path_new, "rb"); | |
| if (output == NULL) { | |
| char *invalid_response_404 = "HTTP/1.0 404 Not Found\r\n\r\n<html><body><h1>404 Not Found</h1></body></html>\r\n"; | |
| fprintf(stderr, "%s \"%s %s %s\" 404 Not Found\n", inet_ntoa(clntaddr.sin_addr), method, requestURI, httpVersion); | |
| if (send(clntsock, invalid_response_404, strlen(invalid_response_404), 0) != strlen(invalid_response_404)) { | |
| fclose(input); | |
| continue; | |
| } | |
| fclose(input); | |
| continue; | |
| } else { | |
| char *ok_header = "HTTP/1.0 200 OK\r\n\r\n"; | |
| if (send(clntsock, ok_header, strlen(ok_header), 0) != strlen(ok_header)) { | |
| fclose(input); | |
| continue; | |
| } | |
| fprintf(stderr, "%s \"%s %s %s\" 200 OK\n", inet_ntoa(clntaddr.sin_addr), method, requestURI, httpVersion); | |
| while ((r = fread(text_buf, 1, sizeof(text_buf), output)) > 0) { | |
| if (send(clntsock, text_buf, r, 0) != r) { | |
| fclose(input); | |
| continue; | |
| } | |
| } | |
| } | |
| fclose(output); | |
| } | |
| fclose(input); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great Work!