Skip to content

Instantly share code, notes, and snippets.

@eden-chung
Created December 25, 2023 21:47
Show Gist options
  • Select an option

  • Save eden-chung/bbb2af0e035835e4fd1c22aa196adda8 to your computer and use it in GitHub Desktop.

Select an option

Save eden-chung/bbb2af0e035835e4fd1c22aa196adda8 to your computer and use it in GitHub Desktop.
HTTP Server and Client
#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;
}
#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);
}
}
@kthopeleee

Copy link
Copy Markdown

Great Work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment