#include #include #include #include #include #include #include #include // Local Includes #include "httpStruct.h" #include "socketHelp.h" #include "returnRequest.h" #include "server.h" static int verbose_flag = 0; bool enableHTTPS = 0; int printDebug(char message[]) { if (verbose_flag == 1) { printf("[Debug] %s\n", message); } return 0; } int parseHTTPRequest(char buffer[], struct HTTPRequest *r) { char temp[1]; // Used to check newlines char *token = calloc(8, sizeof(char)); int line = 0; char *checkLine = calloc(1000, sizeof(char)); for (int i = 0; i < strlen(buffer); i++) { temp[0] = buffer[i]; if ((!strcmp(temp, "\n")) && (i != 0)) { // Config Check if (line == 0) { token = strtok(checkLine, " "); // HTTP Request Type if (!strcmp(token, "GET")) { // Grabbing HTTP Request Type r->requestType = malloc(strlen(token)); strcpy(r->requestType, token); // Grabbing HTTP Request Dir token = strtok(NULL, " "); r->requestDir = malloc(strlen(token)); strcpy(r->requestDir, token); // Grabbing HTTP Request Version token = strtok(NULL, ""); r->requestVersion = malloc(strlen(token)); strcpy(r->requestVersion, token); } else { return 1; } } else { token = strtok(checkLine, ":"); // Host Check if (!strcmp(token, "Host")) { token = strtok(NULL, ""); r->requestHost = malloc(strlen(token)); strcpy(r->requestHost, token); } // Reset checkline } if (strlen(checkLine) > 0) { // Clear checkLine memset(checkLine,0,strlen(checkLine)); } line++; } else { strcat(checkLine, temp); } } free(checkLine); return 0; } int handleRequest(char buffer[], int socket, SSL *ssl) { struct HTTPRequest r; // Holds relevant HTTP request information int checkerr = 0; printDebug("Received Request"); // Grabbing relevant information out of request checkerr = parseHTTPRequest(buffer, &r); if (checkerr != 0) { // Checking for HTTP parsing error printf("Error parsing: exit code %d\n", checkerr); return return404Request(socket, ssl); } // Return response to socket return200Request(socket, ssl); return 0; } int main(int argc, char **argv) { struct sockaddr_in address; int server_fd, new_socket; int port = 0; // Define what port server listens on int checkerr = 0; // Used for error checking int addrlen = sizeof(address); char *certFile = malloc(1); char *privKeyFile = malloc(1); certFile[0] = '\0'; privKeyFile[0] = '\0'; uint32_t listenAddrNum = -1; char *listenAddr = malloc(1); listenAddr[0] = '\0'; SSL_CTX *ctx = NULL; char buffer[1024] = {}; // Setting up options static const struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, {"listen", required_argument, NULL, 'l'}, {"cert", required_argument, NULL, 'c'}, {"privkey", required_argument, NULL, 'k'}, {"verbose", no_argument, &verbose_flag, 1}, {0, 0, 0, 0} }; const char* usage = "Usage: seaweb [options]\n\n" " -h --help\t\t\tShows this message\n" " -p --port\t\t\tStarts webserver on passed port\n" " -l --listen\t\t\tDefines what addr to listen on (default 0.0.0.0)\n" " -c --cert\t\t\tPath to certificate\n" " -k --privkey\t\t\tPath to private key\n" "\n" "\n" " --verbose\t\t\tPrints debug messages\n" "\n"; int c; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hp:l:c:k:", long_options, &option_index); if(c == -1) { // Break if no more options are present to parse break; } switch(c) { case 'h': printf("%s", usage); exit(EXIT_SUCCESS); case 'p': sscanf(optarg, "%d", &port); break; case 'l': listenAddr = calloc(strlen(optarg), sizeof(char)); strcpy(listenAddr, optarg); listenAddrNum = addr2sin_addr(listenAddr); if (listenAddrNum == -1) { exit(EXIT_FAILURE); } break; case 'c': certFile = calloc(strlen(optarg), sizeof(char)); strcpy(certFile, optarg); printf("Cert: %s\n", certFile); break; case 'k': privKeyFile = calloc(strlen(optarg), sizeof(char)); strcpy(privKeyFile, optarg); printf("Priv: %s\n", privKeyFile); break; } } // Argument checks if (port == 0) { // Setting default port if none is passed port = 8080; } if (!((strlen(certFile) > 0) == (strlen(privKeyFile) > 0))) { // XNOR of string lengths // Checking what flag was not passed if (strlen(certFile)) { // Privkey not passed printf("If certificate file is specified, a private key files needs to be specified\n"); } else if (strlen(privKeyFile)) { // Cert not passed printf("If privkey file is specified, a certificate files needs to be specified\n"); } printf("Exiting...\n"); exit(EXIT_FAILURE); } else if ( (strlen(certFile) > 0) && (strlen(privKeyFile) > 0) ) { // Enabling HTTPS enableHTTPS = 1; } if ( enableHTTPS == 1 ) { printf("Opening secure socket on port: %d\n", port); checkerr = createSecureSocket(port, &server_fd, &address, &addrlen, listenAddrNum, &ctx, certFile, privKeyFile); if ( ctx == NULL ) { printf("Error creating ctx\n"); } } else { printf("Opening socket on port: %d\n", port); checkerr = createSocket(port, &server_fd, &address, &addrlen, listenAddrNum); } if (checkerr != 0) { perror("Error creating socket"); exit(EXIT_FAILURE); } // Handle incoming requests while(1) { if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen))<0) { perror("Accept connection error"); exit(EXIT_FAILURE); } if ( enableHTTPS ) { SSL *ssl; ssl = SSL_new(ctx); SSL_set_fd(ssl, new_socket); SSL_accept(ssl); SSL_read(ssl, buffer, sizeof(buffer)); handleRequest(buffer, new_socket, ssl); } else { read(new_socket, buffer, 1024); handleRequest(buffer, new_socket, NULL); } close(new_socket); } free(privKeyFile); free(certFile); free(listenAddr); close(server_fd); exit(EXIT_SUCCESS); }