Created
April 17, 2016 23:47
-
-
Save alastairparagas/6efd7d2758563043b6d7784d789a1463 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import socket | |
| import sys | |
| import mimetypes | |
| import threading | |
| import os | |
| import time | |
| def getFileMimetype(absoluteFilePath): | |
| """ | |
| Gets the HTTP mime type of a file located at provided file path | |
| """ | |
| return mimetypes.guess_type(absoluteFilePath)[0] | |
| def getFileLastModified(absoluteFilePath): | |
| """ | |
| Gets the HTTP content type of a file located at provided file path | |
| """ | |
| return time.strftime("%a, %d %b %Y %H:%M:%S GMT", | |
| time.gmtime(getLastModifiedTime(absoluteFilePath))) | |
| def generateHeaders(statusCode=200, | |
| contentLength=0, | |
| contentType="text/html", | |
| lastModified=""): | |
| """ | |
| Generates HTTP headers as a string | |
| """ | |
| headerText = [] | |
| if statusCode == 200: | |
| headerText.append("HTTP/1.1 200 OK\r\n") | |
| elif statusCode == 400: | |
| headerText.append("HTTP/1.1 404 Not Found\r\n") | |
| else: | |
| headerText.append("HTTP/1.1 400 Bad Request\r\n") | |
| if len(lastModified) > 0: | |
| headerText.append("".join(["Last-Modified: ", lastModified, "\r\n"])) | |
| headerText.append("".join(["Content-Type: ", contentType, "\r\n"])) | |
| headerText.append("".join(["Content-Length: ", str(contentLength), "\r\n"])) | |
| headerText.append("Server: Alastair's Python Server\r\n") | |
| headerText.append("Connection: close\r\n\n") | |
| return "".join(headerText) | |
| def handleRequest(tcpCliSock, data): | |
| """ | |
| Handle proxy requests | |
| """ | |
| # Extract the requested resource/URL from the given HTTP data | |
| dataSplit = data.split()[1] | |
| print dataSplit | |
| filename = dataSplit.partition("/")[2] | |
| print filename | |
| try: | |
| # Check whether the file exist in the cache | |
| f = open(filename, "r") | |
| outputData = f.readlines() | |
| f.close() | |
| outputData = "".join(outputData) | |
| # ProxyServer finds a cache hit and generates a response message | |
| tcpCliSock.send( | |
| generateHeaders(contentLength=len(outputData), | |
| contentType=getFileMimeType(filename), | |
| lastModified=time.ctime(os.stat(filename)[8])) | |
| ) | |
| tcpCliSock.send(outputData) | |
| tcpCliSock.close() | |
| print 'Read from cache' | |
| # Error handling for file not found in cache | |
| except IOError: | |
| try: | |
| # Create a socket on the proxyserver | |
| clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
| hostname = filename.replace("www.", "", 1) | |
| print hostname | |
| # Connect to the socket to port 80 | |
| clientSock.connect((hostname, 80)) | |
| print "Connected to host: " + hostname + ", port 80" | |
| # Create a temporary file on this socket and ask | |
| # port 80 for the file requested by the client | |
| fileobj = clientSock.makefile('r', 0) | |
| fileobj.write("GET " + "http://" + filename + " HTTP/1.1\n" + | |
| "Connection: close\n\n") | |
| # Read the response into buffer | |
| outputData = fileobj.readlines() | |
| outputData = "".join(outputData) | |
| print outputData | |
| fileobj.close() | |
| # Create a new file in the cache for the requested file. | |
| # Also send the response in the buffer to client socket | |
| # and the corresponding file in the cache | |
| tmpFile = open("./" + filename, "wb") | |
| tmpFile.write(outputData) | |
| tmpFile.close() | |
| tcpCliSock.send( | |
| generateHeaders(contentLength=len(outputData), | |
| contentType=getFileMimetype(filename)) | |
| ) | |
| tcpCliSock.send(outputData) | |
| tcpCliSock.close() | |
| fileobj.close() | |
| except Exception: | |
| notFoundMessage = """ | |
| <!DOCTYPE HTML> | |
| <html> | |
| <head><title>404 Not Found</title></head> | |
| <body>404 Not Found</body> | |
| </html> | |
| """ | |
| tcpCliSock.send( | |
| generateHeaders(statusCode=404, contentLength=len(notFoundMessage)) | |
| ) | |
| tcpCliSock.send(notFoundMessage) | |
| tcpCliSock.close() | |
| if len(sys.argv) <= 1: | |
| print ('Usage : "python ProxyServer.py server_ip"\n' + | |
| '[server_ip : The IP Address Of Proxy Server]') | |
| sys.exit(2) | |
| # Create a server socket, bind it to a port and start listening | |
| tcpSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
| tcpSerSock.bind(("", 8000)) | |
| tcpSerSock.listen(2) | |
| while 1: | |
| # Start receiving data from the client | |
| print 'Ready to serve...' | |
| # Accept an HTTP message with a maximum possible request size of | |
| # 8192 bytes = 8KB. This HTTP message will look something like | |
| # GET www.google.com | |
| tcpCliSock, addr = tcpSerSock.accept() | |
| print 'Received a connection from:', addr | |
| message = tcpCliSock.recv(8192) | |
| print message | |
| requestThread = threading.Thread(target=handleRequest, args=(tcpCliSock, message)) | |
| requestThread.start() | |
| tcpSerSock.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment