Project

General

Profile

Download (3.12 KB) Statistics
| Branch: | Tag: | Revision:

haketilo / test / server.py @ b1444d9c

1
#!/usr/bin/env python3
2
#
3
# Copyright (C) 2021 jahoti <jahoti@tilde.team>
4
# Licensing information is collated in the `copyright` file
5

    
6
"""
7
A modular "virtual network" proxy,
8
wrapping the classes in proxy_core.py
9
"""
10

    
11
import proxy_core
12
from urllib.parse import parse_qs
13
from misc_constants import *
14
from world_wide_library import catalog as internet
15

    
16
class RequestHijacker(proxy_core.ProxyRequestHandler):
17
	def handle_request(self, req_body):
18
		path_components = self.path.split('?', maxsplit=1)
19
		path = path_components[0]
20
		try:
21
			# Response format: (status_code, headers (dict. of strings),
22
			#       body as bytes or filename containing body as string)
23
			if path in internet:
24
				info = internet[path]
25
				if type(info) == tuple:
26
					status_code, headers, body_file = info
27
					if type(body_file) == str:
28
						if 'Content-Type' not in headers and '.' in body_file:
29
							ext = body_file.rsplit('.', maxsplit=1)[-1]
30
							if ext in mime_types:
31
								headers['Content-Type'] = mime_types[ext]
32
							
33
						with open(body_file, mode='rb') as f:
34
							body_file = f.read()
35
						
36
				else:
37
					# A function to evaluate to get the response
38
					get_params, post_params = {}, {}
39
					if len(path_components) == 2:
40
						get_params = parse_qs(path_components[1])
41
					
42
					# Parse POST parameters; currently only supports
43
					# application/x-www-form-urlencoded
44
					if req_body:
45
						post_params = parse_qs(req_body.encode())
46

    
47
					status_code, headers, body_file = info(self.command, get_params, post_params)
48
					if type(body_file) == str:
49
						body_file = body_file.encode()
50
			
51
				if type(status_code) != int or status_code <= 0:
52
					raise Exception('Invalid status code %r' % status_code)
53
				
54
				for header, header_value in headers.items():
55
					if type(header) != str:
56
						raise Exception('Invalid header key %r' % header)
57
					
58
					elif type(header_value) != str:
59
						raise Exception('Invalid header value %r' % header_value)
60
			else:
61
				status_code, headers = 404, {'Content-Type': 'text/plain'}
62
				body_file = b'Handler for this URL not found.'
63
		
64
		except Exception as e:
65
			status_code, headers, body_file = 500, {'Content-Type': 'text/plain'}, b'Internal Error:\n' + repr(e).encode()
66
		
67
		headers['Content-Length'] = str(len(body_file))
68
		self.send_response(status_code)
69
		for header, header_value in headers.items():
70
			self.send_header(header, header_value)
71
		
72
		self.end_headers()
73
		self.wfile.write(body_file)
74
		
75

    
76

    
77
def do_an_internet(certdir, port):
78
	"""Start up the proxy/server"""
79
	proxy_core.certdir = certdir
80
	httpd = proxy_core.ThreadingHTTPServer(('', port), RequestHijacker)
81
	httpd.serve_forever()
82

    
83
if __name__ == '__main__':
84
	import sys
85
	def fail(msg, error_code):
86
		print('Error:', msg)
87
		print('Usage:', sys.argv[0], '[certificates directory] (port)')
88
		sys.exit(error_code)
89
	
90
	if len(sys.argv) < 2:
91
		fail('missing required argument "certificates directory".', 1)
92
	
93
	certdir = sys.argv[1]
94
	if not proxy_core.os.path.isdir(certdir):
95
		fail('selected certificate directory does not exist.', 2)
96
	
97
	port = sys.argv[2] if len(sys.argv) > 2 else '1337'
98
	if not port.isnumeric():
99
		fail('port must be an integer.', 3)
100
	
101
	do_an_internet(certdir, int(port))
(5-5/6)