From 7946387f9364ebcb8c9d5dccced69369b00cd80f Mon Sep 17 00:00:00 2001 From: Nicholas Pease Date: Tue, 2 Dec 2025 22:22:34 +0000 Subject: [PATCH] First Working Version --- hw | Bin 16408 -> 25584 bytes hw.c | 442 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 418 insertions(+), 24 deletions(-) mode change 100644 => 100755 hw diff --git a/hw b/hw old mode 100644 new mode 100755 index 83546c8deae44486c2c305cdae94d4e790827a0e..c0d6bcea365838a98e11682b228b5b28e09897f4 GIT binary patch literal 25584 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 z zquax8R#N7?<26#so3#GVTITc6&Hu-M*KzwBY}PNiF^#)4-l#FJaaiMo#z~D+8mBe- z+y6&0ub153)^>U1;@v$1S$iO|ZbNiKw7F^HfE3r?w!S6W+_FZ~AKoJ6w@$q0_^s&r z(W=qAbb=$=06&~owWsSF7L8&`??=$)BBJ?YK7NDdd3>>b2Pz?qj>ec``1;c->yS9x z9WP3Y?>kVTxIA8&-zV*txZ{ucM^UMEzO~MazKaOq+l;ykxP>xSYlnV)4vBMw|Nc2B z-OhB^(Q_-WN&BVlIAs29RI06G{-6fG42g=cvj_J}9#5l~heUNF_(nXXIM1wY1%F0( zvEb(z^KHbl;K3Ve@cA12NDcme@YElFKOd3yjUuIkCv@xs;3J-XaP1h)SD5zSjNX{$wyw=P+RgTz zTTLvM-+JB7%{w~UKx6ZU*=}g9v9(K>+dHq`vboc|dfT>Z+q=!~&09L#O}YL*#_RRv z(tQ7309T7O{2#h*-%7^qxR9rW_?0^k+(uf|_5)X@kZM0c1ts?uR4~XenpfKba5=2F zZJGVHoi{U9u^8{OkgHq<>Ov~phwznq2+U+LXZFXlN!nk~aW%}6sjN9rw36lh3l-7S z{)Y+*7buB_dx}Nf3As^%c2rcDsXY=Elxbpv179K9`A~H`L*-tJ$_D7#>m3^v3K1<1 zW$btl&@L$K=UOU@ofUZz&E{+?+Ls-O<_o#JRj`LVRL?*PyNgmuO>N%N(L{HVKJ|c`Y7&_#do_ zf1e=FYqeV1a-Hy_IA|`({LXS8{CQrT0!LFc_UHEl zMt&cFi7dJ~7R47)qq#Qw^Zc4IqAj`qY{z&T^fY&8ndk3}G41c~zox}FDwI?9e^3Wv zoYsaM-+%u5wf`1v$L}YMa~^-nncx2#;3y~DzWe`A{~zS{HrQX}agrT1vL7QYE%f%E_Y*V9WssgW*pI1aeEvLd zWaRf^w)c;p=e55($B1Z4jedKU8Gokz`TnV6KaE#H?=9@d+%Hj~^Jo89L}?gbRHFOI z_YV`tQCWn8#vm2m56Amh{q`&~z6YNM9PH2E2Mjh*Yvub@NoAS+>3x9iUH0eq4&Il{ z`;Te-QDHy6j^6=C=g#M#1 diff --git a/hw.c b/hw.c index e9dd9a5..2e10881 100644 --- a/hw.c +++ b/hw.c @@ -12,36 +12,409 @@ #include #include #include +#include + +// Program Settings +#define BOUND_IP "10.4.78.8" +#define PORT 5000 + +#define DEBUG 1 // Controls Optional Debug Output // Constants -#define PORT 5000 -#define DEBUG 0 +#define REQ_HTTP_START_LINE_METHOD_LENGTH 8 +#define REQ_HTTP_START_LINE_PATH_LENGTH 1024 +#define REQ_HTTP_START_LINE_VERSION_LENGTH 16 +#define REQ_HTTP_START_LINE_EXTRA_CHARS 4 +#define REQ_HTTP_START_LINE_SEPARATOR ' ' -// Globals +#define RES_HTTP_START_LINE_VERSION_LENGTH 16 +#define RES_HTTP_START_LINE_STATUS_CODE_LENGTH 4 +#define RES_HTTP_START_LINE_REASON_PHRASE_LENGTH 64 + +#define HTTP_HEADER_FIELD_SEPARATOR ": " +#define HTTP_HEADER_FIELD_NAME_LENGTH 256 +#define HTTP_HEADER_FIELD_VALUE_LENGTH 1024 +#define HTTP_HEADER_FIELD_EXTRA_CHARS 4 +#define HTTP_HEADER_LINE_ENDING "\r\n" + +#define HTTP_MESSAGE_MAX_HEADERS 100 +#define HTTP_MESSAGE_BODY_LENGTH 8192 +#define HTTP_BODY_SEPARATOR "\r\n\r\n" + +#define MAX_MESSAGE_SIZE 20000 +#define MAX_MESSAGE_COUNT 10 // Structs -struct http_start_line { - char method[8]; - char path[1024]; - char version[16]; +struct req_http_start_line { + char method[REQ_HTTP_START_LINE_METHOD_LENGTH]; + char path[REQ_HTTP_START_LINE_PATH_LENGTH]; + char version[REQ_HTTP_START_LINE_VERSION_LENGTH]; +}; + +struct res_http_start_line { + char version[RES_HTTP_START_LINE_VERSION_LENGTH]; + char status_code[RES_HTTP_START_LINE_STATUS_CODE_LENGTH]; + char reason_phrase[RES_HTTP_START_LINE_REASON_PHRASE_LENGTH]; }; struct http_header { - char field_name[256]; - char field_value[1024]; + char field_name[HTTP_HEADER_FIELD_NAME_LENGTH]; + char field_value[HTTP_HEADER_FIELD_VALUE_LENGTH]; }; -struct http_message { - struct http_start_line start_line; - struct http_header headers[100]; - char body[8192]; +struct req_http_message { + struct req_http_start_line start_line; + struct http_header headers[HTTP_MESSAGE_MAX_HEADERS]; + int header_count; + char body[HTTP_MESSAGE_BODY_LENGTH]; +}; + +struct res_http_message { + struct res_http_start_line start_line; + struct http_header headers[HTTP_MESSAGE_MAX_HEADERS]; + int header_count; + char body[HTTP_MESSAGE_BODY_LENGTH]; +}; + +struct http_forward_info { + char host[REQ_HTTP_START_LINE_PATH_LENGTH]; + int port; + char transport_protocol[5]; + struct req_http_message new_message; }; // Functions -struct http_message create_http_message_from_string(char *message_str) { - struct http_message message; + +// Construct REQ Start Line +struct req_http_start_line parse_req_http_start_line(char *start_line_unparsed) { + + struct req_http_start_line start_line; + + // Method + int first_space_seperator = strchr(start_line_unparsed, REQ_HTTP_START_LINE_SEPARATOR) - start_line_unparsed; + memcpy(start_line.method, start_line_unparsed, first_space_seperator); + start_line.method[first_space_seperator] = '\0'; + + // Path + char *path_start = start_line_unparsed + first_space_seperator + 1; + int second_space_seperator = strchr(path_start, REQ_HTTP_START_LINE_SEPARATOR) - path_start; + memcpy(start_line.path, path_start, second_space_seperator); + start_line.path[second_space_seperator] = '\0'; + + // Version + char *version_start = path_start + second_space_seperator + 1; + int line_end = strchr(version_start, '\r') - version_start; + memcpy(start_line.version, version_start, line_end); + start_line.version[line_end] = '\0'; + + // Debug: Print All Parts + if (DEBUG) { + printf(" Parsed HTTP Start Line:\n"); + printf(" Method: %s\n", start_line.method); + printf(" Path: %s\n", start_line.path); + printf(" Version: %s\n", start_line.version); + } + + return start_line; +} + +// Construct Header from String +struct http_header parse_http_header(char *header_str) { + struct http_header header; + + // Header Field Name + char *separator_pos = strstr(header_str, HTTP_HEADER_FIELD_SEPARATOR); + int field_name_len = separator_pos - header_str; + memcpy(header.field_name, header_str, field_name_len); + header.field_name[field_name_len] = '\0'; + + // Header Field Value + char *field_value_start = separator_pos + strlen(HTTP_HEADER_FIELD_SEPARATOR); + int field_value_len = strlen(field_value_start); + memcpy(header.field_value, field_value_start, field_value_len); + header.field_value[field_value_len] = '\0'; + + return header; +} + +// Construct HTTP Message from String +struct req_http_message create_req_http_message_from_string(char *message_str) { + struct req_http_message message; + // Parse Start Line + int start_line_len = REQ_HTTP_START_LINE_METHOD_LENGTH + REQ_HTTP_START_LINE_PATH_LENGTH + REQ_HTTP_START_LINE_VERSION_LENGTH + REQ_HTTP_START_LINE_EXTRA_CHARS; + char start_line_unparsed[start_line_len]; + memcpy(start_line_unparsed, message_str, start_line_len); + message.start_line = parse_req_http_start_line(start_line_unparsed); + // Parse Headers + + // Find start of headers (after first \r\n) + char *headers_start = strstr(message_str, HTTP_HEADER_LINE_ENDING) + 2; + char *headers_end = strstr(headers_start, HTTP_BODY_SEPARATOR); + + // Parse each header line + char *current_line = headers_start; + int header_count = 0; + while (current_line < headers_end && header_count < HTTP_MESSAGE_MAX_HEADERS) { + + char *line_end = strstr(current_line, HTTP_HEADER_LINE_ENDING); + if (line_end == NULL || line_end > headers_end) break; + + char current_header_unparsed[HTTP_HEADER_FIELD_NAME_LENGTH + HTTP_HEADER_FIELD_VALUE_LENGTH + 4]; + memcpy(current_header_unparsed, current_line, line_end - current_line); + current_header_unparsed[line_end - current_line] = '\0'; + + message.headers[header_count] = parse_http_header(current_header_unparsed); + if (DEBUG) { + printf(" Parsed HTTP Header %d:\n", header_count + 1); + printf(" Field Name: %s\n", message.headers[header_count].field_name); + printf(" Field Value: %s\n", message.headers[header_count].field_value); + } + header_count++; + + current_line = line_end + strlen(HTTP_HEADER_LINE_ENDING); + } + message.header_count = header_count; + + // Parse body + char *body_start = headers_end + strlen(HTTP_BODY_SEPARATOR); + int body_len = strlen(body_start); + memcpy(message.body, body_start, body_len); + message.body[body_len] = '\0'; + if (DEBUG) { + printf(" Parsed HTTP Body:\n"); + printf(" Body Length: %d\n", body_len); + printf(" Body Content: %s\n", message.body); + } + + return message; +} + +// Process Message for Relay +struct http_forward_info process_for_relay(struct req_http_message received_message) { + struct http_forward_info forward_info; + forward_info.new_message = received_message; + + // New Transport Protocol + char *original_host = memcpy(received_message.start_line.path, received_message.start_line.path, strlen(received_message.start_line.path)); + char *transport_protocol_end = strstr(original_host, "://") + 3; + memcpy(forward_info.transport_protocol, original_host, transport_protocol_end - original_host); + + // New Host + char *host_end = strchr(transport_protocol_end, ':'); + char *port_end = strchr(host_end, '/'); + memcpy(forward_info.host, transport_protocol_end, host_end - transport_protocol_end); + forward_info.host[host_end - transport_protocol_end] = '\0'; + + // New Port + forward_info.port = atoi(host_end + 1); + printf(" Extracted Port: %d\n", forward_info.port); + + // New Path + char *entire_host_string_end = strchr(transport_protocol_end, '/'); + memcpy(forward_info.new_message.start_line.path, entire_host_string_end, strlen(entire_host_string_end)); + forward_info.new_message.start_line.path[strlen(entire_host_string_end)] = '\0'; + + // Strip out Proxy-Connection Header and replace with Connection: Close + int new_header_count = 0; + for (int i = 0; i < forward_info.new_message.header_count; i++) { + if (strcmp(forward_info.new_message.headers[i].field_name, "Proxy-Connection") == 0) { + // Replace Proxy-Connection with Connection: close + strcpy(forward_info.new_message.headers[new_header_count].field_name, "Connection"); + strcpy(forward_info.new_message.headers[new_header_count].field_value, "Close"); + new_header_count++; + } else { + // Keep the existing header + forward_info.new_message.headers[new_header_count] = forward_info.new_message.headers[i]; + new_header_count++; + } + } + forward_info.new_message.header_count = new_header_count; + + if (DEBUG) { + printf(" Processed Forward Info:\n"); + printf(" Host: %s\n", forward_info.host); + printf(" Port: %d\n", forward_info.port); + printf(" New Path: %s\n", forward_info.new_message.start_line.path); + for (int i = 0; i < forward_info.new_message.header_count; i++) { + printf(" Header %d: %s: %s\n", i + 1, + forward_info.new_message.headers[i].field_name, + forward_info.new_message.headers[i].field_value); + } + } + + return forward_info; +} + +// Convert HTTP REQ Message Struct to String +void req_http_message_to_string(struct req_http_message message, char *message_str) { + // Start Line + sprintf(message_str, "%s %s %s%s", message.start_line.method, message.start_line.path, message.start_line.version, HTTP_HEADER_LINE_ENDING); + + // Headers + for (int i = 0; i < message.header_count; i++) { + strcat(message_str, message.headers[i].field_name); + strcat(message_str, HTTP_HEADER_FIELD_SEPARATOR); + strcat(message_str, message.headers[i].field_value); + strcat(message_str, HTTP_HEADER_LINE_ENDING); + } + + // End of Headers + strcat(message_str, HTTP_HEADER_LINE_ENDING); + + // Body + strcat(message_str, message.body); +} + +// Convert HTTP RES Message Struct to String +void res_http_message_to_string(struct res_http_message message, char *message_str) { + // Start Line + sprintf(message_str, "%s %s %s%s", message.start_line.version, message.start_line.status_code, message.start_line.reason_phrase, HTTP_HEADER_LINE_ENDING); + + // Headers + for (int i = 0; i < message.header_count; i++) { + strcat(message_str, message.headers[i].field_name); + strcat(message_str, HTTP_HEADER_FIELD_SEPARATOR); + strcat(message_str, message.headers[i].field_value); + strcat(message_str, HTTP_HEADER_LINE_ENDING); + } + + // End of Headers + strcat(message_str, HTTP_HEADER_LINE_ENDING); + + // Body + strcat(message_str, message.body); +} + +// Construct RES Start Line +struct res_http_start_line parse_res_http_start_line(char *start_line_unparsed) { + + struct res_http_start_line start_line; + + // Version + int first_space_seperator = strchr(start_line_unparsed, REQ_HTTP_START_LINE_SEPARATOR) - start_line_unparsed; + memcpy(start_line.version, start_line_unparsed, first_space_seperator); + start_line.version[first_space_seperator] = '\0'; + + // Status Code + char *status_code_start = start_line_unparsed + first_space_seperator + 1; + int second_space_seperator = strchr(status_code_start, REQ_HTTP_START_LINE_SEPARATOR) - status_code_start; + memcpy(start_line.status_code, status_code_start, second_space_seperator); + start_line.status_code[second_space_seperator] = '\0'; + + // Reason Phrase + char *reason_phrase_start = status_code_start + second_space_seperator + 1; + int line_end = strchr(reason_phrase_start, '\r') - reason_phrase_start; + memcpy(start_line.reason_phrase, reason_phrase_start, line_end); + start_line.reason_phrase[line_end] = '\0'; + + // Debug: Print All Parts + if (DEBUG) { + printf(" Parsed HTTP Start Line:\n"); + printf(" Version: %s\n", start_line.version); + printf(" Status Code: %s\n", start_line.status_code); + printf(" Reason Phrase: %s\n", start_line.reason_phrase); + } + + return start_line; +} + +// Construct HTTP RES Message from String +struct res_http_message create_res_http_message_from_string(char *message_str) { + struct res_http_message message; + + // Parse Start Line + int start_line_len = RES_HTTP_START_LINE_VERSION_LENGTH + RES_HTTP_START_LINE_STATUS_CODE_LENGTH + RES_HTTP_START_LINE_REASON_PHRASE_LENGTH + REQ_HTTP_START_LINE_EXTRA_CHARS; + char start_line_unparsed[start_line_len]; + memcpy(start_line_unparsed, message_str, start_line_len); + message.start_line = parse_res_http_start_line(start_line_unparsed); + + // Parse Headers + + // Find start of headers (after first \r\n) + char *headers_start = strstr(message_str, HTTP_HEADER_LINE_ENDING) + 2; + char *headers_end = strstr(headers_start, HTTP_BODY_SEPARATOR); + + // Parse each header line + char *current_line = headers_start; + int header_count = 0; + while (current_line < headers_end && header_count < HTTP_MESSAGE_MAX_HEADERS) { + + char *line_end = strstr(current_line, HTTP_HEADER_LINE_ENDING); + if (line_end == NULL || line_end > headers_end) break; + + char current_header_unparsed[HTTP_HEADER_FIELD_NAME_LENGTH + HTTP_HEADER_FIELD_VALUE_LENGTH + 4]; + memcpy(current_header_unparsed, current_line, line_end - current_line); + current_header_unparsed[line_end - current_line] = '\0'; + + message.headers[header_count] = parse_http_header(current_header_unparsed); + if (DEBUG) { + printf(" Parsed HTTP Header %d:\n", header_count + 1); + printf(" Field Name: %s\n", message.headers[header_count].field_name); + printf(" Field Value: %s\n", message.headers[header_count].field_value); + } + header_count++; + + current_line = line_end + strlen(HTTP_HEADER_LINE_ENDING); + } + message.header_count = header_count; + + // Parse body + char *body_start = headers_end + strlen(HTTP_BODY_SEPARATOR); + int body_len = strlen(body_start); + memcpy(message.body, body_start, body_len); + message.body[body_len] = '\0'; + if (DEBUG) { + printf(" Parsed HTTP Body:\n"); + printf(" Body Length: %d\n", body_len); + printf(" Body Content: %s\n", message.body); + } + return message; +} + +// Forward Message and Await Response +struct res_http_message forward_message_await_response(struct http_forward_info forward_info) { + char response_buffer[MAX_MESSAGE_SIZE]; + + // Convert HTTP Message Struct to String + char message_str[MAX_MESSAGE_SIZE]; + req_http_message_to_string(forward_info.new_message, message_str); + + if (DEBUG) printf("FORWARD:\n%s\n", message_str); + + // Create TCP Socket to Origin Server + struct sockaddr_in sa; + int my_sock = socket(AF_INET, SOCK_STREAM, 0); + sa.sin_family = AF_INET; + sa.sin_port = htons(forward_info.port); + inet_pton(AF_INET, forward_info.host, &(sa.sin_addr)); + int recv_size = connect(my_sock, (struct sockaddr *)&sa, sizeof(sa)); + + // Send Message to Origin Server + send(my_sock, message_str, strlen(message_str), 0); + if (DEBUG) printf("FORWARD: Message Sent to Origin Server\n"); + + // Await Response from Origin Server + memset(response_buffer, 0, MAX_MESSAGE_SIZE); + int total_received = 0; + int bytes_received; + + while ((bytes_received = recv(my_sock, response_buffer + total_received, MAX_MESSAGE_SIZE - total_received - 1, 0)) > 0) { + total_received += bytes_received; + } + + if (DEBUG) { + printf("FORWARD: Response Received from Origin Server (%d bytes)\n", total_received); + printf("RESPONSE:\n"); + printf("%s\n", response_buffer); + } + + struct res_http_message response_message = create_res_http_message_from_string(response_buffer); + + close(my_sock); + + return response_message; } // Main @@ -51,7 +424,7 @@ int main(int argc, char *argv[]) { if (DEBUG) printf("SETUP: Setup Sockets\n"); int serv_sock, client_sock, read_size; struct sockaddr_in server, client; - char client_message[20000]; + char client_message[MAX_MESSAGE_SIZE]; serv_sock = socket(AF_INET, SOCK_STREAM, 0); client_sock = socket(AF_INET, SOCK_STREAM, 0); if (DEBUG) printf("SETUP: Socket Created\n"); @@ -59,8 +432,15 @@ int main(int argc, char *argv[]) { // Bind Sockets server.sin_family = AF_INET; server.sin_port = htons(PORT); - // inet_pton(AF_INET, INADDR_ANY, &(server.sin_addr)); - bind(serv_sock,(struct sockaddr *)&server, sizeof(server)); + inet_pton(AF_INET, BOUND_IP, &(server.sin_addr)); + + // TODO: REMOVE THIS BEFORE SUBMISSION + setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &server, sizeof(server)); + + if (bind(serv_sock, (struct sockaddr *)&server, sizeof(server)) < 0) { + perror("BIND FAILED"); + return 1; + } if (DEBUG) printf("SETUP: Socket Bound\n"); // Start Listening and Waiting for Connections @@ -69,23 +449,37 @@ int main(int argc, char *argv[]) { while (1) { // Accept Connection from Client - if (DEBUG) printf("WAIT: Waiting for incoming connections...\n"); + printf("WAIT: Waiting for incoming connections...\n"); int c = sizeof(struct sockaddr_in); client_sock = accept(serv_sock, (struct sockaddr *)&client, &c); - if (DEBUG) printf("CONNECT: Connection Accepted\n"); + printf("CONNECT: Connection Accepted\n"); // Receive Message from Client memset(client_message, 0, sizeof(client_message)); read_size = recv(client_sock, client_message, sizeof(client_message), 0); - if (DEBUG) printf("RECEIVE: Message Received\n"); + printf("RECEIVE: Message Received\n"); // Process Message From Client - if (DEBUG) printf("PROCESS: Processing Message\n"); - struct http_message message = create_http_message_from_string(client_message); + printf("PROCESS: Processing Message\n"); + struct req_http_message received_message = create_req_http_message_from_string(client_message); + + // Process Message for Relay + printf("PROCESS: Processing for Relay\n"); + struct http_forward_info relay_message = process_for_relay(received_message); + + // Forward Message to Destination Server + printf("FORWARD: Forwarding Message to %s\n", relay_message.host); + struct res_http_message origin_response = forward_message_await_response(relay_message); + // Send Response Back to Client + char response_str[MAX_MESSAGE_SIZE]; + res_http_message_to_string(origin_response, response_str); + send(client_sock, response_str, strlen(response_str), 0); + printf("RESPONSE: Response Sent Back to Client\n"); + // Close Client Socket close(client_sock); - if (DEBUG) printf("DISCONNECT: Client Disconnected\n\n"); + printf("DISCONNECT: Client Disconnected\n\n"); } return 0;