Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <arpa/inet.h>
- #include <dirent.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <pthread.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <unistd.h>
- #include "libhttp.h"
- #include "wq.h"
- /*
- * Global configuration variables.
- * You need to use these in your implementation of handle_files_request and
- * handle_proxy_request. Their values are set up in main() using the
- * command line arguments (already implemented for you).
- */
- wq_t work_queue;
- int num_threads;
- int server_port;
- char *server_files_directory;
- char *server_proxy_hostname;
- int server_proxy_port;
- char *str_error_not_found = "<center>"
- "<h1>404 Not Found</h1>"
- "<hr>"
- "<p>Requested Domani Not Found!!!</p>"
- "</center>";
- char * H_html_start = "<html>";
- char * H_html_end = "</html>";
- char * H_ul_start = "<ul>";
- char * H_ul_end = "<ul>";
- char * H_li_start = "<li>";
- char * H_li_end = "</li>";
- char * H_href = "<a href=\"%s\">%s</a>";
- char *read_from_file(char *path, int *data_size)
- {
- char *data = malloc(1);
- int file_fd = open(path, O_RDONLY, 0644);
- if (file_fd == -1)
- {
- perror("");
- }
- else
- {
- int BUF_SIZE = 1024;
- char buff[BUF_SIZE];
- int bytes_read = 0;
- while (bytes_read = read(file_fd, buff, BUF_SIZE), bytes_read > 0)
- {
- data = (char *)realloc(data, *data_size + bytes_read);
- memcpy(data + *data_size, buff, bytes_read);
- *data_size += bytes_read;
- }
- }
- return data;
- }
- char *read_from_dir(char *path, int *data_size){
- char * html = malloc(strlen(H_html_start) + strlen(H_html_end) + strlen(H_ul_start) + strlen(H_ul_end));
- strcpy(html, H_html_start);
- DIR *d = opendir(path);
- if (d)
- {
- struct dirent *dir;
- strcat(html, H_ul_start);
- while ((dir = readdir(d)) != NULL)
- {
- char * cur_file = malloc(strlen(H_href) + 2*strlen(dir->d_name) + strlen(H_li_start) + strlen(H_li_end));
- sprintf(cur_file, H_href, dir->d_name, dir->d_name);
- strcat(html, H_li_start);
- strcat(html, cur_file);
- strcat(html, H_li_end);
- }
- closedir(d);
- }
- strcat(html, H_ul_end);
- strcat(html, H_html_end);
- *data_size = strlen(html);
- return html;
- }
- /*
- * Reads an HTTP request from stream (fd), and writes an HTTP response
- * containing:
- *
- * 1) If user requested an existing file, respond with the file
- * 2) If user requested a directory and index.html exists in the directory,
- * send the index.html file.
- * 3) If user requested a directory and index.html doesn't exist, send a list
- * of files in the directory with links to each.
- * 4) Send a 404 Not Found response.
- */
- void handle_files_request(int fd)
- {
- struct http_request *request = http_request_parse(fd);
- // get full path of file
- char *full_path = malloc(strlen(server_files_directory) + strlen(request->path));
- strcpy(full_path, server_files_directory);
- strcat(full_path, request->path);
- // file check struct
- struct stat stat_file;
- int stat_res = stat(full_path, &stat_file);
- // data to send in http
- int status_code;
- char *content_type;
- char *data;
- int data_size = 0;
- if (stat_res == -1) // error 404
- {
- content_type = "text/html";
- status_code = 404;
- data = str_error_not_found;
- data_size = strlen(data);
- }
- else
- {
- status_code = 200;
- char *index = "index.html";
- if (S_ISDIR(stat_file.st_mode))
- {
- // check if index.html exists in given folder
- char *full_path_index = malloc(strlen(full_path) + strlen(index) + 1);
- strcpy(full_path_index, full_path);
- strcat(full_path_index, "/");
- strcat(full_path_index, index);
- stat_res = stat(full_path_index, &stat_file);
- if (stat_res == -1) // does not exists
- {
- content_type = "text/html";
- data = read_from_dir(full_path, &data_size);
- }
- else // index.html exists
- {
- full_path = full_path_index;
- }
- }
- if (S_ISREG(stat_file.st_mode))
- {
- content_type = http_get_mime_type(full_path);
- data = read_from_file(full_path, &data_size);
- }
- }
- char data_size_str[100] = {'\0'};
- sprintf(data_size_str, "%d", data_size);
- http_start_response(fd, status_code);
- http_send_header(fd, "Content-Type", content_type);
- http_send_header(fd, "Content-Length", data_size_str);
- http_end_headers(fd);
- http_send_data(fd, data, data_size);
- }
- /*
- * Opens a connection to the proxy target (hostname=server_proxy_hostname and
- * port=server_proxy_port) and relays traffic to/from the stream fd and the
- * proxy target. HTTP requests from the client (fd) should be sent to the
- * proxy target, and HTTP responses from the proxy target should be sent to
- * the client (fd).
- *
- * +--------+ +------------+ +--------------+
- * | client | <-> | httpserver | <-> | proxy target |
- * +--------+ +------------+ +--------------+
- */
- void handle_proxy_request(int fd)
- {
- /*
- * The code below does a DNS lookup of server_proxy_hostname and
- * opens a connection to it. Please do not modify.
- */
- struct sockaddr_in target_address;
- memset(&target_address, 0, sizeof(target_address));
- target_address.sin_family = AF_INET;
- target_address.sin_port = htons(server_proxy_port);
- struct hostent *target_dns_entry = gethostbyname2(server_proxy_hostname, AF_INET);
- int client_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
- if (client_socket_fd == -1)
- {
- fprintf(stderr, "Failed to create a new socket: error %d: %s\n", errno, strerror(errno));
- exit(errno);
- }
- if (target_dns_entry == NULL)
- {
- fprintf(stderr, "Cannot find host: %s\n", server_proxy_hostname);
- exit(ENXIO);
- }
- char *dns_address = target_dns_entry->h_addr_list[0];
- memcpy(&target_address.sin_addr, dns_address, sizeof(target_address.sin_addr));
- int connection_status = connect(client_socket_fd, (struct sockaddr *)&target_address,
- sizeof(target_address));
- if (connection_status < 0)
- {
- /* Dummy request parsing, just to be compliant. */
- http_request_parse(fd);
- http_start_response(fd, 502);
- http_send_header(fd, "Content-Type", "text/html");
- http_end_headers(fd);
- http_send_string(fd, "<center><h1>502 Bad Gateway</h1><hr></center>");
- return;
- }
- /*
- * TODO: Your solution for task 3 belongs here!
- */
- }
- void init_thread_pool(int num_threads, void (*request_handler)(int))
- {
- /*
- * TODO: Part of your solution for Task 2 goes here!
- */
- }
- /*
- * Opens a TCP stream socket on all interfaces with port number PORTNO. Saves
- * the fd number of the server socket in *socket_number. For each accepted
- * connection, calls request_handler with the accepted fd number.
- */
- void serve_forever(int *socket_number, void (*request_handler)(int))
- {
- struct sockaddr_in server_address, client_address;
- size_t client_address_length = sizeof(client_address);
- int client_socket_number;
- *socket_number = socket(PF_INET, SOCK_STREAM, 0);
- if (*socket_number == -1)
- {
- perror("Failed to create a new socket");
- exit(errno);
- }
- int socket_option = 1;
- if (setsockopt(*socket_number, SOL_SOCKET, SO_REUSEADDR, &socket_option,
- sizeof(socket_option)) == -1)
- {
- perror("Failed to set socket options");
- exit(errno);
- }
- memset(&server_address, 0, sizeof(server_address));
- server_address.sin_family = AF_INET;
- server_address.sin_addr.s_addr = INADDR_ANY;
- server_address.sin_port = htons(server_port);
- if (bind(*socket_number, (struct sockaddr *)&server_address,
- sizeof(server_address)) == -1)
- {
- perror("Failed to bind on socket");
- exit(errno);
- }
- if (listen(*socket_number, 1024) == -1)
- {
- perror("Failed to listen on socket");
- exit(errno);
- }
- printf("Listening on port %d...\n", server_port);
- init_thread_pool(num_threads, request_handler);
- while (1)
- {
- client_socket_number = accept(*socket_number,
- (struct sockaddr *)&client_address,
- (socklen_t *)&client_address_length);
- if (client_socket_number < 0)
- {
- perror("Error accepting socket");
- continue;
- }
- printf("Accepted connection from %s on port %d\n",
- inet_ntoa(client_address.sin_addr),
- client_address.sin_port);
- // TODO: Change me?
- request_handler(client_socket_number);
- close(client_socket_number);
- printf("Accepted connection from %s on port %d\n",
- inet_ntoa(client_address.sin_addr),
- client_address.sin_port);
- }
- shutdown(*socket_number, SHUT_RDWR);
- close(*socket_number);
- }
- int server_fd;
- void signal_callback_handler(int signum)
- {
- printf("Caught signal %d: %s\n", signum, strsignal(signum));
- printf("Closing socket %d\n", server_fd);
- if (close(server_fd) < 0)
- perror("Failed to close server_fd (ignoring)\n");
- exit(0);
- }
- char *USAGE =
- "Usage: ./httpserver --files www_directory/ --port 8000 [--num-threads 5]\n"
- " ./httpserver --proxy inst.eecs.berkeley.edu:80 --port 8000 [--num-threads 5]\n";
- void exit_with_usage()
- {
- fprintf(stderr, "%s", USAGE);
- exit(EXIT_SUCCESS);
- }
- int main(int argc, char **argv)
- {
- signal(SIGINT, signal_callback_handler);
- /* Default settings */
- server_port = 8000;
- void (*request_handler)(int) = NULL;
- int i;
- for (i = 1; i < argc; i++)
- {
- if (strcmp("--files", argv[i]) == 0)
- {
- request_handler = handle_files_request;
- free(server_files_directory);
- server_files_directory = argv[++i];
- if (!server_files_directory)
- {
- fprintf(stderr, "Expected argument after --files\n");
- exit_with_usage();
- }
- }
- else if (strcmp("--proxy", argv[i]) == 0)
- {
- request_handler = handle_proxy_request;
- char *proxy_target = argv[++i];
- if (!proxy_target)
- {
- fprintf(stderr, "Expected argument after --proxy\n");
- exit_with_usage();
- }
- char *colon_pointer = strchr(proxy_target, ':');
- if (colon_pointer != NULL)
- {
- *colon_pointer = '\0';
- server_proxy_hostname = proxy_target;
- server_proxy_port = atoi(colon_pointer + 1);
- }
- else
- {
- server_proxy_hostname = proxy_target;
- server_proxy_port = 80;
- }
- }
- else if (strcmp("--port", argv[i]) == 0)
- {
- char *server_port_string = argv[++i];
- if (!server_port_string)
- {
- fprintf(stderr, "Expected argument after --port\n");
- exit_with_usage();
- }
- server_port = atoi(server_port_string);
- }
- else if (strcmp("--num-threads", argv[i]) == 0)
- {
- char *num_threads_str = argv[++i];
- if (!num_threads_str || (num_threads = atoi(num_threads_str)) < 1)
- {
- fprintf(stderr, "Expected positive integer after --num-threads\n");
- exit_with_usage();
- }
- }
- else if (strcmp("--help", argv[i]) == 0)
- {
- exit_with_usage();
- }
- else
- {
- fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
- exit_with_usage();
- }
- }
- if (server_files_directory == NULL && server_proxy_hostname == NULL)
- {
- fprintf(stderr, "Please specify either \"--files [DIRECTORY]\" or \n"
- " \"--proxy [HOSTNAME:PORT]\"\n");
- exit_with_usage();
- }
- serve_forever(&server_fd, request_handler);
- return EXIT_SUCCESS;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement