diff --git a/.travis.yml b/.travis.yml index 39835f9..29c7016 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,6 @@ dist: trusty sudo: required script: - make test - - make integration addons: apt: packages: diff --git a/Makefile b/Makefile index 25d30c0..b264880 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,12 @@ GTEST_FLAGS=-std=c++11 -isystem $(GTEST_DIR)/include GMOCK_FLAGS=-isystem $(GMOCK_DIR)/include CXXFLAGS= -g $(CXXOPTIMIZE) -Wall -Werror -static-libgcc -static-libstdc++ -pthread -Wl,-Bstatic -pedantic -std=c++11 $(BOOST) -CLASSES=nginx-configparser/config_parser server/server server/webserver http/httpRequest http/httpMutableRequest http/httpResponse http/http filesystem/file_opener handlers/file_handler handlers/echo_handler handlers/request_handler handlers/not_found_handler handlers/status_handler handlers/proxy_handler handlers/blocking_handler handlers/markdown_handler handlers/cloud_file_handler -GCOV=config_parser.cc server.cc webserver.cc httpRequest.cc httpMutableRequest.cc http.cc httpResponse.cc file_opener.cc file_handler.cc echo_handler.cc request_handler.cc not_found_handler.cc status_handler.cc proxy_handler.cc blocking_handler.cc +CLASSES=nginx-configparser/config_parser server/server server/webserver http/httpRequest http/httpMutableRequest http/httpResponse http/http filesystem/file_opener handlers/file_handler handlers/echo_handler handlers/request_handler handlers/not_found_handler handlers/status_handler handlers/proxy_handler handlers/blocking_handler handlers/markdown_handler handlers/cloud_file_handler handlers/rsa_handler + +CLASSES=nginx-configparser/config_parser server/server server/webserver http/httpRequest http/httpMutableRequest http/httpResponse http/http filesystem/file_opener handlers/file_handler handlers/echo_handler handlers/request_handler handlers/not_found_handler handlers/status_handler handlers/proxy_handler handlers/blocking_handler handlers/markdown_handler handlers/cloud_file_handler handlers/rsa_handler + +GCOV=config_parser.cc server.cc webserver.cc httpRequest.cc httpMutableRequest.cc http.cc httpResponse.cc file_opener.cc file_handler.cc echo_handler.cc request_handler.cc not_found_handler.cc status_handler.cc proxy_handler.cc blocking_handler.cc rsa_handler.cc UTIL_CLASSES=$(CLASSES:=.cc) TESTS=$(CLASSES:=_test) @@ -32,6 +35,7 @@ handlers/file_handler.cc: handlers/file_handler.h handlers/echo_handler.cc: handlers/echo_handler.h handlers/not_found_handler.cc: handlers/not_found_handler.h handlers/proxy_handler.cc: handlers/proxy_handler.h +handlers/rsa_handler.cc: handlers/rsa_handler.h server/webserver.cc: server/webserver.h @@ -70,7 +74,6 @@ docker: rm -f deploy/binary.tar cd deploy && \ docker build -t httpserver --file ./Dockerfile.run . - clean: find . -type f -iname \*.o -delete diff --git a/handlers/markdown_handler_test b/handlers/markdown_handler_test deleted file mode 100755 index 728776e..0000000 Binary files a/handlers/markdown_handler_test and /dev/null differ diff --git a/handlers/proxy_handler_test b/handlers/proxy_handler_test deleted file mode 100755 index 5cac685..0000000 Binary files a/handlers/proxy_handler_test and /dev/null differ diff --git a/handlers/rsa_handler.cc b/handlers/rsa_handler.cc new file mode 100644 index 0000000..1a3b309 --- /dev/null +++ b/handlers/rsa_handler.cc @@ -0,0 +1,84 @@ +#include "rsa_handler.h" + +#include +#include + +//For the crypto-secure rng seeding +#include + + +#include "../http/httpRequest.h" +#include "../http/httpResponse.h" +#include "../http/http.h" + +//The init process generates the two numbers p and q, +//and initializes the other member variables using p and q's values. +RequestHandler::Status RsaHandler::Init(const std::string& uri_prefix, const NginxConfig& config) { + //Todo + // Generate p and q using random num generator + // boost::random_device rd; + // p = rd(); + //p = (p << 32) | rd(); + //q = rd(); + //q = (q << 32) | rd(); + p = 11; + q = 13; + n = p*q; + t = (p-1)*(q-1); + //Now we calculate e and d + //We hardcode e as is common practice, using a number + //of possible e's, as e must be relatively prime to t. + //Else, we start incrementing e until a found number works. + //Thi is method used by GnuPG v1.2.3 + if(t % 41 != 0) + e = 41; + else if(t % 257 != 0) + e = 257; + else{ + int temp1 = 0, temp2 = 0; + e = 65537; + while (gcdExtended(e, t, &temp1, &temp2) != 1) + e += 2; + } + //Find d using EEA + int x = 0, y = 0; + gcdExtended(e,t,&x,&y); + d = x; + std::cout << "The initialization values for the RSA Handler:\n"; + std::cout << "n: " << n << ", t: " << t << ", e: " << e << ", d: " << d <<"\n"; + return OK; +} + +//used as reference for below: http://www.sanfoundry.com/cpp-program-implement-rsa-algorithm/ +RequestHandler::Status RsaHandler::HandleRequest(const Request& request, + Response* response) { + m = (request.raw_request()); + std::size_t lengthm = m.length(); + long int encodedArray[128]; + std::string output = ""; + long int plain; + long int cipher; + std::size_t u; + for(u = 0; u < lengthm; u++) { + plain = m[u]; + //Conversion to number + plain = plain - 96; + long k = 1; + for(long j = 0; j < e; j++) { + k = k*plain; + k = k % n; + } + cipher = k + 96; + encodedArray[u] = cipher; + } + + for(int temp = 0; temp < 128; temp++){ + output += std::to_string(encodedArray[temp]); + } + std::cout << "Encrypted Output:\n"; + std::cout <SetStatus(Response::OK); + response->AddHeader("Content-Type", http::mime_type::ContentTypeAsString(http::mime_type::CONTENT_TYPE_TEXT_PLAIN)); + response->SetBody(output.c_str()); + return OK; +} diff --git a/handlers/rsa_handler.cc~ b/handlers/rsa_handler.cc~ new file mode 100644 index 0000000..c0112b5 --- /dev/null +++ b/handlers/rsa_handler.cc~ @@ -0,0 +1,83 @@ +#include "rsa_handler.h" + +#include +#include + +//For the crypto-secure rng seeding +#include + + +#include "../http/httpRequest.h" +#include "../http/httpResponse.h" +#include "../http/http.h" + +//The init process generates the two numbers p and q, +//and initializes the other member variables using p and q's values. +RequestHandler::Status RsaHandler::Init(const std::string& uri_prefix, const NginxConfig& config) { + //Todo + // Generate p and q using random num generator + // boost::random_device rd; + p = 11; + q = 13; + n = p*q; + t = (p-1)*(q-1); + //Now we calculate e and d + //We hardcode e as is common practice, using a number + //of possible e's, as e must be relatively prime to t. + //Else, we start incrementing e until a found number works. + //Thi is method used by GnuPG v1.2.3 + if(t % 41 != 0) + e = 41; + else if(t % 257 != 0) + e = 257; + else{ + int temp1 = 0, temp2 = 0; + e = 65537; + while (gcdExtended(e, t, &temp1, &temp2) != 1) + e += 2; + } + //Find d using EEA + int x = 0, y = 0; + gcdExtended(e,t,&x,&y); + d = x; + std::cout << "\nThe initialization values for the RSA Handler:\n"; + std::cout << "n: " << n << ", t: " << t << ", e: " << e << ", d: " << d <<"\n"; + return OK; +} + +RequestHandler::Status RsaHandler::HandleRequest(const Request& request, + Response* response) { + long int encodedArray[128]; + std::string output = ""; + long int plain; + long int cipher; + m = (request.raw_request()); + EorD = m[0]; + m.erase(0,1); + std::size_t lengthm = m.length(); + std::size_t u; + for(u = 0; u < lengthm; u++) { + plain = m[u]; + //Conversion to number + plain = plain - 96; + long k = 1; + for(long j = 0; j < e; j++) { + k = k*plain; + k = k % n; + } + cipher = k + 96; + encodedArray[u] = cipher; + } + + for(int temp = 0; temp < 128; temp++){ + output += std::to_string(encodedArray[temp]); + } + std::cout <SetStatus(Response::OK); + std::cout << "!!@EFAE"; + response->AddHeader("Content-Type", http::mime_type::ContentTypeAsString(http::mime_type::CONTENT_TYPE_TEXT_PLAIN)); + std::cout << "!!@EFAE"; + response->SetBody(output.c_str()); + std::cout << "!!@EFAE"; + return OK; +} diff --git a/handlers/rsa_handler.h b/handlers/rsa_handler.h new file mode 100644 index 0000000..92d46cd --- /dev/null +++ b/handlers/rsa_handler.h @@ -0,0 +1,65 @@ +#ifndef RSA_HANDLER_H +#define RSA_HANDLER_H + +#include + +#include "../nginx-configparser/config_parser.h" +#include "../http/httpRequest.h" +#include "../http/httpResponse.h" +#include "request_handler.h" + +class RsaHandler : public RequestHandler { + public: + Status Init(const std::string& uri_prefix, + const NginxConfig& config); + + bool isPrime(long long x){ + int sqrtX = std::sqrt(x); + for (int i = 2; i < sqrtX; i++) + if (x % i == 0) + return false; + return true; + } + + //Extended Eucliden algorithm used to determine d + //see : http://www.geeksforgeeks.org/basic-and-extended-euclidean-algorithms +int gcdExtended(int a, int b, int *x, int *y) +{ + // Base Case + if (a == 0) + { + *x = 0; + *y = 1; + return b; + } + + int x1, y1; // To store results of recursive call + int gcd = gcdExtended(b%a, a, &x1, &y1); + + // Update x and y using results of recursive + // call + *x = y1 - (b/a) * x1; + *y = x1; + + return gcd; +} + + //Handle Request encrypts if the first letter of the + //request body is e, and decrypts if it is d, fails otherwise. + //The 'message' in both cases is the rest of the message. + Status HandleRequest(const Request& request, + Response* response); + + private: + long long p, q, n, t, e, d; + std::string m; + //p, q are initial prime numbers. n, the product of p and q, is the modulus. + //t is Euler's Totient, computed as (n-1)(p-1). + //e and d are the public and private exponents used in the modular arithmetic + //m is the input message. + +}; + +REGISTER_REQUEST_HANDLER(RsaHandler); + +#endif diff --git a/handlers/rsa_handler.h~ b/handlers/rsa_handler.h~ new file mode 100644 index 0000000..75d4cfe --- /dev/null +++ b/handlers/rsa_handler.h~ @@ -0,0 +1,43 @@ +#ifndef RSA_HANDLER_H +#define RSA_HANDLER_H + +#include + +#include "../nginx-configparser/config_parser.h" +#include "../http/httpRequest.h" +#include "../http/httpResponse.h" +#include "request_handler.h" + +class RsaHandler : public RequestHandler { + public: + Status Init(const std::string& uri_prefix, + const NginxConfig& config); + + bool isPrime(long long x){ + int sqrtX = std::sqrt(x); + for (int i = 2; i < sqrtX; i++) + if (x % i == 0) + return false; + return true; + } + + //Handle Request encrypts if the first letter of the + //request body is e, and decrypts if it is d, fails otherwise. + //The 'message' in both cases is the rest of the message. + Status HandleRequest(const Request& request, + Response* response); + + private: + long long p, q, n, t, e, d; + std::string m; + std::string EorD; + //p, q are initial prime numbers. n, the product of p and q, is the modulus. + //t is Euler's Totient, computed as (n-1)(p-1). + //e and d are the public and private exponents used in the modular arithmetic + //m is the input message. + +}; + +REGISTER_REQUEST_HANDLER(RsaHandler); + +#endif diff --git a/handlers/rsa_handler_test.cc b/handlers/rsa_handler_test.cc new file mode 100644 index 0000000..e69de29 diff --git a/handlers/status_handler.cc b/handlers/status_handler.cc index c9c9011..9e08f23 100644 --- a/handlers/status_handler.cc +++ b/handlers/status_handler.cc @@ -18,13 +18,14 @@ RequestHandler::Status StatusHandler::HandleRequest(const Request& request, if (status_ == nullptr) { return RequestHandler::MISCONFIGURED_HANDLER; } + //status_->Status_.stsMx->lock(); ServerStatus::Status status = status_->GetStatus(); - - response->SetStatus(Response::OK); response->AddHeader("Content-Type", http::mime_type::ContentTypeAsString(http::mime_type::CONTENT_TYPE_TEXT_HTML)); response->SetBody(StatusToHtml(status)); + + //status_->Status_.stsMx->unlock(); return OK; } @@ -33,15 +34,17 @@ RequestHandler::Status StatusHandler::InitStatus(ServerStatus* status) { if (status == nullptr) { return RequestHandler::MISCONFIGURED_HANDLER; } + status->GetStatus().stsMx->lock(); status_ = status; + status->GetStatus().stsMx->unlock(); return OK; } std::string StatusHandler::StatusToHtml(const ServerStatus::Status& status) { + status.stsMx->lock(); std::string html_string; - html_string.append("\n"); html_string.append("\n"); html_string.append("Status Page"); @@ -74,6 +77,6 @@ std::string StatusHandler::StatusToHtml(const ServerStatus::Status& status) { html_string.append("\n"); html_string.append("\n"); - + status.stsMx->unlock(); return html_string; } diff --git a/integration_config b/integration_config new file mode 100644 index 0000000..603316f --- /dev/null +++ b/integration_config @@ -0,0 +1,25 @@ +port 2029; # This is also a comment. + +path /serve StaticHandler { + root files_served/; +} + +path /echo EchoHandler {} + +path /status StatusHandler {} + +path /proxy ProxyHandler { + host www.ucla.edu; + port 80; +} + +path /cloud CloudFileHandler { + bucket cs130-s3; +} + +path /block BlockingHandler {} + +path /rsa RsaHandler {} + +# Default response handler if no handlers match. +default NotFoundHandler {} diff --git a/integration_test.py b/integration_test.py index 7690b8d..e84cd73 100644 --- a/integration_test.py +++ b/integration_test.py @@ -1,15 +1,14 @@ # This is an integration test which analyzes the server's # ability to respond to a request made by curl import subprocess -import sys import os -import telnetlib import time - +import telnetlib ## Global Vars ## -passing = True #Variable to check if all tests passed -port = 2020; -failedTests = [] +passing = True +port = 2029; +#TODO: add a data strx to hold names of failed tests + ## Formatting Functions ## def line(): @@ -19,148 +18,62 @@ def nameTest(name): print("Testing: " + name) def pas(): print("PASSED\n") -def fail(msg): - print("FAILED: " + str(msg) + "\n") - global passing + +## Start Server ## +#subprocess.call("./webserver integration_config >/dev/null 2>&1 &", shell = True) +subprocess.call("nohup ./webserver test_config &", shell = True) +pid = subprocess.check_output('ps -a | grep webserver', shell = True).split()[0] +print(pid) + + +## Testing Process ## +print("\nBeginning Integration Test.\n") + +#try : +nameTest("Connection") +command2 = 'curl -Is localhost:' + str(port) + " | cat" +output=subprocess.check_output(command2, shell=True) +if output != "": + pas() + print(output) + line() +#except CalledProcessError: +else: + print("ERROR: Cannot connect to server.") passing = False -## Begin Testing ## -if __name__ == "__main__": - print("Starting Integration Test.\n") +## Multithreading Test ## +req1 = 'GET /block HTTP/1.1\r\nHost: localhost:2029\r\n\r\n' +req2 = 'GET /echo HTTP/1.1\r\nHost: localhost:2029\r\n\r\n' +print('Multithreading Test\n') +print('Sending blocking request\n') +p = telnetlib.Telnet('localhost', 2029, 2) +p.write(req1.encode('ascii')) - ## Start Server ## - outputToNull = open(os.devnull, 'w') - serverProcess = subprocess.Popen(['./webserver', 'test_config'], stdout=outputToNull) - time.sleep(3) +print('Sending echo request after blocking request.\n') +q = telnetlib.Telnet('localhost', 2029, 2) +q.write(req2.encode('ascii')) +result = q.read_all().decode('utf-8') -##### +print(result) - ## Server Status Test ## - nameTest("Server Status Request") - statusRawRequest = 'GET /status HTTP/1.1\r\nHost: localhost:2020\r\n\r\n' - statusSession = telnetlib.Telnet('localhost', port) - print('Sending Status Request.\n') - statusSession.write(statusRawRequest.encode('ascii')) - statusResult = statusSession.read_all().decode('utf-8') - print(statusResult) - time.sleep(3) +expectedResult = ""; -##### - ## Multithreading Test ## - nameTest('Multithreading') - blockingRawRequest = 'GET /block HTTP/1.1\r\nHost: localhost:2020\r\n\r\n' - print('Sending Blocking Request\n') - blockingSession = telnetlib.Telnet('localhost', port) - blockingSession.write(blockingRawRequest.encode('ascii')) +## Kill Server ## +subprocess.call('kill ' + pid, shell = True) - time.sleep(3) +## Conclusion ## +print("Passed all tests?\n" + str(passing) + '\n') +#if passing: +# return True +#else: +# return False + ## Notes ## # Todo: add/utilize an http response parser that checks for correct # status codes, content type, etc. - print('Sending Echo Request after Blocking Request.\n') - echoRawRequest = 'GET /echo HTTP/1.1\r\nHost: localhost:2020\r\n\r\n' - echoSession = telnetlib.Telnet('localhost', port) - echoSession.write(echoRawRequest.encode('ascii')) - echoResult = echoSession.read_all().decode('utf-8') - print("Result of echo request:\n") - print(echoResult) - #Echo tested elsewhere, just testing it returns here - if echoResult != "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nGET /echo HTTP/1.1\r\nHost: localhost:2020\r\n\r\n": - failedTests.append("Multithreading") - passing = False - -##### - - ## Testing Complete, Kill Server ## - print("\nKilling Server.\n") - serverProcess.kill() - - -##### - - def TestProxyHandler(): - nameTest("ProxyHandler") - backend_config = ( - 'port 8080;\n' - 'path /echo EchoHandler {}\n' - 'default NotFoundHandler {}\n' - ) - proxy_config = ( - 'port 8081;\n' - 'path /proxy ProxyHandler {\n' - ' host localhost;\n' - ' port 8080;\n' - '}\n' - 'default NotFoundHandler {}\n' - ) - backend_config_file = 'test_backend_config' - proxy_config_file = 'test_proxy_config' - with open(backend_config_file, 'w') as f: - f.write(backend_config) - with open(proxy_config_file, 'w') as f: - f.write(proxy_config) - - WEBSERVER_EXECUTABLE = './webserver' - backend_process = subprocess.Popen([WEBSERVER_EXECUTABLE, backend_config_file]) - proxy_process = subprocess.Popen([WEBSERVER_EXECUTABLE, proxy_config_file]) - time.sleep(0.2) # give time for webservers to open - try: - if backend_process.poll(): - return fail("backend webserver exited with status %d" % backend_process.returncode) - if proxy_process.poll(): - return fail("proxy webserver exited with status %d" % proxy_process.returncode) - - backend_curl = 'curl -Is localhost:8080/echo | cat' - proxy_curl = 'curl -Is localhost:8081/proxy/echo | cat' - - backend_output = subprocess.check_output(backend_curl, shell=True) - if backend_output == "": - backend_process.terminate() - proxy_process.terminate() - return fail("backend produced wrong output") - proxy_output = subprocess.check_output(proxy_curl, shell=True) - if proxy_output == "": - backend_process.terminate() - proxy_process.terminate() - return fail("proxy produced wrong output") - - if (proxy_output != backend_output): - fail("Proxy and actual outputs differ!") - else: - pas() - finally: - backend_process.terminate() # kill server - proxy_process.terminate() - backend_process.wait() # wait for server to die - proxy_process.wait() - - # delete temporary config files - os.remove(backend_config_file) - os.remove(proxy_config_file) - - line() - - TestProxyHandler() - - -##### - - ## Conclusion ## - print("Passed all tests?\n" + str(passing) + '\n') - if passing: - sys.exit(0) - #return True - else: - print("Failed Tests:") - for test in failedTests: - print(test, '\n') - sys.exit(1) - #return False - - ## Notes ## - # Todo: add/utilize an http response parser that checks for correct - # status codes, content type, etc. - + + diff --git a/integration_test2.py b/integration_test2.py deleted file mode 100644 index 6eb5327..0000000 --- a/integration_test2.py +++ /dev/null @@ -1,80 +0,0 @@ -# This is an integration test which analyzes the server's -# ability to respond to a request made by curl -import subprocess -import os -import time -import telnetlib -## Global Vars ## -passing = True -port = 2024; -#TODO: add a data strx to hold names of failed tests - - -## Formatting Functions ## -def line(): - print("----------------------------------------") -def nameTest(name): - line() - print("Testing: " + name) -def pas(): - print("PASSED\n") - -## Start Server ## -#subprocess.call("./webserver test_config >/dev/null 2>&1 &", shell = True) -subprocess.call("nohup ./webserver test_config &", shell = True) -pid = subprocess.check_output('ps -a | grep webserver', shell = True).split()[0] -print(pid) - - -## Testing Process ## -print("\nBeginning Integration Test.\n") -#For Curl: -I sends a HEAD Http Request; -s silences output to the terminal - -#try : -nameTest("Connection") -command2 = 'curl -Is localhost:' + str(port) + " | cat" -output=subprocess.check_output(command2, shell=True) -if output != "": - pas() - print(output) - line() -#except CalledProcessError: -else: - print("ERROR: Cannot connect to server.") - passing = False - -## Multithreading Test ## -req1 = 'GET /block HTTP/1.1\r\nHost: localhost:2024\r\n\r\n' -req2 = 'GET /echo HTTP/1.1\r\nHost: localhost:2024\r\n\r\n' -print('Multithreading Test\n') -print('Sending blocking request\n') -p = telnetlib.Telnet('localhost', 2024, 2) -p.write(req1.encode('ascii')) - -print('Sending echo request after blocing request.\n') -q = telnetlib.Telnet('localhost', 2024, 2) -q.write(req2.encode('ascii')) -result = q.read_all().decode('utf-8') - -print(result) - -expectedResult = ""; - - -## Kill Server ## -subprocess.call('kill ' + pid, shell = True) - - -## Conclusion ## -print("Passed all tests?\n" + str(passing) + '\n') -#if passing: -# return True -#else: -# return False - - -## Notes ## -# Todo: add/utilize an http response parser that checks for correct -# status codes, content type, etc. - - diff --git a/rsa_demo.py b/rsa_demo.py new file mode 100644 index 0000000..5153620 --- /dev/null +++ b/rsa_demo.py @@ -0,0 +1,29 @@ +import time +import telnetlib +import subprocess + +print("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n") +time.sleep(1) +print("Welcome.") +time.sleep(2) +print("\nThis is a demo of the RSA Encryption Capabilities of this server.") +time.sleep(3) +print("\nRSA works based on the fact that it is really difficult to factor the products of large primes.") +time.sleep(5) +print("\nAs in, it could take millions of years to break 4096-bit RSA by brute strength using one of our laptops.") +time.sleep(5) +print("\nIn RSA there is a public key used to encrypt messages, and a private key to decrpyt the message. The public key is distributed, the private key is kept secret.") +time.sleep(5) +print("Here, we implement the two stages of RSA - key generation and the RSA Algorithm - to encrypt an HTTP request sent to the server.") +time.sleep(4) +print("\nBeginning Server") +time.sleep(2) + +subprocess.Popen(['./webserver', 'rsa_test_config']) +time.sleep(6) +req = 'GET /rsa HTTP/1.1\r\nHost: localhost:2035\r\n\r\n' +print("\nPlain Text:"+req) +time.sleep(3) +print("Encoded Text:\n") +tn = telnetlib.Telnet('localhost', 2035) +tn.write(req.encode('ascii')) diff --git a/rsa_demo.py~ b/rsa_demo.py~ new file mode 100644 index 0000000..554ceb9 --- /dev/null +++ b/rsa_demo.py~ @@ -0,0 +1,26 @@ +import time +import telnetlib +import subprocess + +print("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n") +time.sleep(1) +print("Welcome.") +time.sleep(2) +print("\nThis is a demo of the RSA Encryption Capabilities of this server.") +time.sleep(3) +print("\nRSA works based on the fact that is is really difficult to factor the products of large primes.") +time.sleep(5) +print("\nAs in, it could take millions of years to break 4096-bit RSA by brute strength using one of our laptops.") +time.sleep(5) +print("\nIn RSA there is a public key used to encrypt messages, and a private key to decrpyt the message. The public key is distributed, the private key is what's secret.") +time.sleep(5) +print("Here, we implement the two stages of RSA - key generation and the RSA Algorithm - to encrypt an HTTP request sent to the server.") +time.sleep(3) +print("\nBeginning Server") +time.sleep(2) + +subprocess.Popen(['sh', './webserver', 'rsa_test_config']) +req = 'GET /rsa HTTP/1.1\r\nHost: localhost:2020\r\n\r\n' +tn = telnetlib.Telnet('localhost', 2020) +tn.write(req.encode('ascii')) + diff --git a/rsa_helper.sh b/rsa_helper.sh new file mode 100755 index 0000000..c2af1ed --- /dev/null +++ b/rsa_helper.sh @@ -0,0 +1,3 @@ +#! /bin/bash + +./webserver rsa_test_config diff --git a/rsa_test_config b/rsa_test_config new file mode 100644 index 0000000..f30c255 --- /dev/null +++ b/rsa_test_config @@ -0,0 +1,21 @@ +port 2035; # This is also a comment. + +path /serve StaticHandler { + root files_served/; +} + +path /echo EchoHandler {} + +path /status StatusHandler {} + +path /proxy ProxyHandler { + host www.ucla.edu; + port 80; +} + +path /block BlockingHandler {} + +path /rsa RsaHandler {} + +# Default response handler if no handlers match. +default NotFoundHandler {} diff --git a/rsa_test_config~ b/rsa_test_config~ new file mode 100644 index 0000000..73e7a47 --- /dev/null +++ b/rsa_test_config~ @@ -0,0 +1,21 @@ +port 2021; # This is also a comment. + +path /serve StaticHandler { + root files_served/; +} + +path /echo EchoHandler {} + +path /status StatusHandler {} + +path /proxy ProxyHandler { + host www.ucla.edu; + port 80; +} + +path /block BlockingHandler {} + +path /rsa RsaHandler {} + +# Default response handler if no handlers match. +default NotFoundHandler {} diff --git a/server/server.cc b/server/server.cc index 511957a..445f49e 100644 --- a/server/server.cc +++ b/server/server.cc @@ -71,27 +71,27 @@ void Session::do_read() { RequestStatus = handler_->RequestHandlers->find(best_key)->second->HandleRequest(*req, response); } - if(RequestStatus == RequestHandler::BAD_REQUEST) { response_string = "HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/html\r\n\r\n"; + status_->GetStatus().stsMx->lock(); status_->LogIncomingRequest(req->uri(), 500); + status_->GetStatus().stsMx->unlock(); } else { response_string = response->ToString(); + status_->GetStatus().stsMx->lock(); status_->LogIncomingRequest(req->uri(), response->GetStatus()); + status_->GetStatus().stsMx->unlock(); } } else { // response invalid, return a 400 - if(data_.length()==0){ - printf("Emtpy raw request. Ended the session to avoid segmentation fault!\n"); - delete response; - return; - } response_string = "HTTP/1.1 400 Bad Request\r\nContent-Type: text/html\r\n\r\n"; + status_->GetStatus().stsMx->lock(); status_->LogIncomingRequest(req->uri(), 400); + status_->GetStatus().stsMx->lock(); } - + do_write(response_string); delete response; } @@ -123,7 +123,7 @@ Server::Server(boost::asio::io_service& io_service, int port, HandlerConfigurati void Server::do_accept(HandlerConfiguration* handler, ServerStatus* status,Session* new_session, const boost::system::error_code& error) { - if(!error){ + if(!error){ new_session->start(); new_session = new Session(this->io_service_,handler,status); acceptor_.async_accept(new_session->getSocket(), @@ -148,7 +148,9 @@ void Server::run(){ } void ServerStatus::AddHandler(std::string path, std::string handler) { + Status_.stsMx->lock(); Status_.RequestHandlers_.insert(std::make_pair(path, handler)); + Status_.stsMx->unlock(); } ServerStatus::Status ServerStatus::GetStatus() { @@ -156,6 +158,7 @@ ServerStatus::Status ServerStatus::GetStatus() { } void ServerStatus::LogIncomingRequest(std::string url, int RespCode) { + Status_.stsMx->lock(); auto RespCodeCount = Status_.ResponseCountByCode_.insert(std::make_pair(RespCode, 1)); if (RespCodeCount.second == false) { // The particular response code is already in the map RespCodeCount.first->second++; @@ -165,10 +168,12 @@ void ServerStatus::LogIncomingRequest(std::string url, int RespCode) { if (URLCodeCount.second == false) { // The particular url is already in the map URLCodeCount.first->second++; } - Status_.requests_++; + Status_.stsMx->unlock(); } void ServerStatus::SetDefaultHandler(std::string handler) { + Status_.stsMx->lock(); Status_.defaultHandler_ = handler; + Status_.stsMx->unlock(); } diff --git a/server/server.h b/server/server.h index 1807618..f9b690e 100644 --- a/server/server.h +++ b/server/server.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -56,10 +57,19 @@ class Server class ServerStatus { public: struct Status { + Status(){ + printf("Mutex Created.\n"); + stsMx = new std::mutex; + } + void destroyMutex(){ + delete stsMx; + } std::map RequestCountByURL_; std::map ResponseCountByCode_; std::map RequestHandlers_; + std::mutex* stsMx; + std::string defaultHandler_; int requests_ = 0; }; @@ -68,6 +78,7 @@ class ServerStatus { Status GetStatus(); void LogIncomingRequest(std::string path, int RespCode); void SetDefaultHandler(std::string handler); + private: Status Status_; }; diff --git a/server/webserver.cc b/server/webserver.cc index e8dbf74..113940a 100644 --- a/server/webserver.cc +++ b/server/webserver.cc @@ -21,6 +21,7 @@ std::string WebServer::ToString() const { } bool WebServer::AddHandler(std::string path, std::string HandlerName, NginxConfig* config) { + auto handler = RequestHandler::CreateByName(HandlerName.c_str()); if(handler == nullptr) { printf("Invalid Handler %s\n", HandlerName.c_str()); @@ -31,14 +32,11 @@ bool WebServer::AddHandler(std::string path, std::string HandlerName, NginxConfi statusHandler->InitStatus(&status_); // handler = f; } - RequestHandler::Status s = handler->Init(path, *config); - if(s == RequestHandler::INVALID_CONFIG) { printf("Error initializing Handler %s due to invalid config %s\n", HandlerName.c_str(), config->ToString().c_str()); return false; } - printf("Registered Handler %s to path %s\n", HandlerName.c_str(), path.c_str()); auto res = HandlerMapping_.RequestHandlers->insert(std::make_pair(path, handler)); if(res.second == false) { @@ -124,6 +122,7 @@ bool WebServer::Init() { //Modeled after team AAAA's class example and this stack overflow page: bool WebServer::run_server() { + printf("Starting Server..."); try { boost::asio::io_service io_service; Server s(io_service, port_, &HandlerMapping_, &status_); @@ -134,5 +133,6 @@ bool WebServer::run_server() { printf("Exception %s\n", e.what()); return false; } + status_.GetStatus().destroyMutex(); return true; } diff --git a/test_config b/test_config index bd23f5d..4407e8e 100644 --- a/test_config +++ b/test_config @@ -19,5 +19,7 @@ path /cloud CloudFileHandler { path /block BlockingHandler {} +path /rsa RsaHandler {} + # Default response handler if no handlers match. default NotFoundHandler {}