Compare commits
2
Commits
ba9c2dff67
..
2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bab41a0084 | ||
|
|
cec8a80714 |
+11
-43
@@ -47,9 +47,8 @@ import threading
|
|||||||
import ssl
|
import ssl
|
||||||
import socket
|
import socket
|
||||||
import signal
|
import signal
|
||||||
# Experimental imports go here
|
|
||||||
import select
|
import select
|
||||||
import subprocess
|
# Experimental imports go here
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not os.getcwd() in sys.path:
|
if not os.getcwd() in sys.path:
|
||||||
@@ -63,7 +62,7 @@ except ImportError:
|
|||||||
)
|
)
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
AMETHYST_BUILD_NUMBER = "0.3.1-0130-mt-tryout2"
|
AMETHYST_BUILD_NUMBER = "0.99.0-0134-ff"
|
||||||
AMETHYST_REPO = "https://git.novacow.ch/Nova/PyWebServer/"
|
AMETHYST_REPO = "https://git.novacow.ch/Nova/PyWebServer/"
|
||||||
|
|
||||||
|
|
||||||
@@ -115,7 +114,6 @@ class ConfigParser:
|
|||||||
if host:
|
if host:
|
||||||
value = self.data["hosts"].get(host, {}).get(key)
|
value = self.data["hosts"].get(host, {}).get(key)
|
||||||
elif key == "hosts":
|
elif key == "hosts":
|
||||||
print(f"\n\n\nHosts!\nHosts: {self.data['hosts']}\n\n\n")
|
|
||||||
value = list(self.data["hosts"].keys())
|
value = list(self.data["hosts"].keys())
|
||||||
else:
|
else:
|
||||||
value = self.data["globals"].get(key)
|
value = self.data["globals"].get(key)
|
||||||
@@ -172,9 +170,6 @@ class FileHandler:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
def read_config(self, key, host_name=None):
|
def read_config(self, key, host_name=None):
|
||||||
print(
|
|
||||||
f"\n\n\nQuery!\nkey: {key}\nhost_name: {host_name}\nret: {self.cfg.query_config(key, host_name)}"
|
|
||||||
)
|
|
||||||
return self.cfg.query_config(key, host_name)
|
return self.cfg.query_config(key, host_name)
|
||||||
|
|
||||||
def autocert(self):
|
def autocert(self):
|
||||||
@@ -190,7 +185,6 @@ class RequestParser:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.file_handler = FileHandler()
|
self.file_handler = FileHandler()
|
||||||
self.hosts = self.file_handler.read_config("hosts")
|
self.hosts = self.file_handler.read_config("hosts")
|
||||||
print(f"Hosts: {self.hosts}")
|
|
||||||
|
|
||||||
def extract_header(self, header: str, request: bytes | str):
|
def extract_header(self, header: str, request: bytes | str):
|
||||||
if isinstance(request, bytes):
|
if isinstance(request, bytes):
|
||||||
@@ -260,7 +254,6 @@ class RequestParser:
|
|||||||
Mfw im in an ugly code writing contest and my opponent is nova while writing a side project
|
Mfw im in an ugly code writing contest and my opponent is nova while writing a side project
|
||||||
"""
|
"""
|
||||||
host = f"{host}"
|
host = f"{host}"
|
||||||
print(f"hosts: {self.hosts}, host: {host}, split: {host.rsplit(':', 1)[0]}")
|
|
||||||
if ":" in host:
|
if ":" in host:
|
||||||
host = host.rsplit(":", 1)[0]
|
host = host.rsplit(":", 1)[0]
|
||||||
host = host.lstrip()
|
host = host.lstrip()
|
||||||
@@ -296,9 +289,7 @@ class ProxyServer:
|
|||||||
def try_connection(
|
def try_connection(
|
||||||
self, host: str, port: int, data: bytes, chost: str, force_tls: bool = None
|
self, host: str, port: int, data: bytes, chost: str, force_tls: bool = None
|
||||||
):
|
):
|
||||||
print(f"\n\n\nchost: {chost}\n\n\n")
|
|
||||||
nhost = self.file_handler.read_config("proxy", chost)
|
nhost = self.file_handler.read_config("proxy", chost)
|
||||||
print(f"\n\n\nnhost: {nhost}\n\n\n")
|
|
||||||
# nhost will include http or https.
|
# nhost will include http or https.
|
||||||
if nhost.startswith("https"):
|
if nhost.startswith("https"):
|
||||||
nhost = nhost[6:-1]
|
nhost = nhost[6:-1]
|
||||||
@@ -313,16 +304,13 @@ class ProxyServer:
|
|||||||
)
|
)
|
||||||
if force_tls is True:
|
if force_tls is True:
|
||||||
do_tls = True
|
do_tls = True
|
||||||
print(f"\n\n\nnhost: {nhost}\n\n\n")
|
|
||||||
if ":" in nhost:
|
if ":" in nhost:
|
||||||
nport = int(nhost.split(":")[1])
|
nport = int(nhost.split(":")[1])
|
||||||
nhost = nhost.split(":")[0]
|
nhost = nhost.split(":")[0]
|
||||||
else:
|
else:
|
||||||
nport = port
|
nport = port
|
||||||
print(f"{nhost}, {nport}, {data}")
|
|
||||||
data = self.reset_host(nhost, nport, data)
|
data = self.reset_host(nhost, nport, data)
|
||||||
try:
|
try:
|
||||||
print("Waiting on TCP start.")
|
|
||||||
return self.tcp_send(nhost, nport, data, do_tls)
|
return self.tcp_send(nhost, nport, data, do_tls)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise Exception(f"Server replied unexpected. Reply from Python subsystem: {e}")
|
raise Exception(f"Server replied unexpected. Reply from Python subsystem: {e}")
|
||||||
@@ -378,7 +366,6 @@ class ProxyServer:
|
|||||||
raw_sock, server_hostname=server_hostname
|
raw_sock, server_hostname=server_hostname
|
||||||
) as ssock:
|
) as ssock:
|
||||||
ssock.sendall(data)
|
ssock.sendall(data)
|
||||||
print("data reached")
|
|
||||||
resp = self.recv_all(ssock)
|
resp = self.recv_all(ssock)
|
||||||
if self.rq.extract_header("Transfer-Encoding", resp) == "chunked":
|
if self.rq.extract_header("Transfer-Encoding", resp) == "chunked":
|
||||||
ssock.sendall(b"TRANSER-ENCODING IS NOT SUPPORTED")
|
ssock.sendall(b"TRANSER-ENCODING IS NOT SUPPORTED")
|
||||||
@@ -393,9 +380,7 @@ class ProxyServer:
|
|||||||
)
|
)
|
||||||
return resp
|
return resp
|
||||||
else:
|
else:
|
||||||
print(f"\n\n\nraw data: {data}\n\n\n")
|
|
||||||
raw_sock.sendall(data)
|
raw_sock.sendall(data)
|
||||||
print("Waiting for response...")
|
|
||||||
resp = self.recv_all(raw_sock)
|
resp = self.recv_all(raw_sock)
|
||||||
if self.rq.extract_header("Transfer-Encoding", resp) is not None:
|
if self.rq.extract_header("Transfer-Encoding", resp) is not None:
|
||||||
raw_sock.sendall(b"TRANSER-ENCODING IS NOT SUPPORTED")
|
raw_sock.sendall(b"TRANSER-ENCODING IS NOT SUPPORTED")
|
||||||
@@ -454,11 +439,9 @@ class WebServer:
|
|||||||
|
|
||||||
self.http_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
self.http_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
||||||
self.http_socket.bind(("::", self.http_port))
|
self.http_socket.bind(("::", self.http_port))
|
||||||
# self.http_socket.settimeout(1)
|
|
||||||
|
|
||||||
self.https_socket_raw = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
self.https_socket_raw = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
||||||
self.https_socket_raw.bind(("::", self.https_port))
|
self.https_socket_raw.bind(("::", self.https_port))
|
||||||
# self.https_socket_raw.settimeout(1)
|
|
||||||
|
|
||||||
self.proxy_handler = ProxyServer(self.file_handler)
|
self.proxy_handler = ProxyServer(self.file_handler)
|
||||||
|
|
||||||
@@ -493,20 +476,27 @@ class WebServer:
|
|||||||
def start(self, http, https):
|
def start(self, http, https):
|
||||||
signal.signal(signal.SIGINT, self.shutdown)
|
signal.signal(signal.SIGINT, self.shutdown)
|
||||||
signal.signal(signal.SIGTERM, self.shutdown)
|
signal.signal(signal.SIGTERM, self.shutdown)
|
||||||
|
|
||||||
|
http_thread = threading.Thread(target=self.start_http, daemon=True)
|
||||||
|
https_thread = threading.Thread(target=self.start_https, daemon=True)
|
||||||
|
|
||||||
if https is True:
|
if https is True:
|
||||||
if self.skip_ssl is True:
|
if self.skip_ssl is True:
|
||||||
print("WARN: You have enabled HTTPS without SSL!!")
|
print("WARN: You have enabled HTTPS without SSL!!")
|
||||||
yn = input("Is this intended behaviour? [y/N] ")
|
yn = input("Is this intended behaviour? [y/N] ")
|
||||||
if yn.lower() == "n":
|
if yn.lower() == "n":
|
||||||
exit(1)
|
exit(1)
|
||||||
self.start_https()
|
https_thread.start()
|
||||||
else:
|
else:
|
||||||
self.https_socket.close()
|
self.https_socket.close()
|
||||||
if http is True:
|
if http is True:
|
||||||
self.start_http()
|
http_thread.start()
|
||||||
else:
|
else:
|
||||||
self.http_socket.close()
|
self.http_socket.close()
|
||||||
|
|
||||||
|
http_thread.join()
|
||||||
|
https_thread.join()
|
||||||
|
|
||||||
def start_http(self):
|
def start_http(self):
|
||||||
self.http_socket.listen(5)
|
self.http_socket.listen(5)
|
||||||
print(f"HTTP server listening on port {self.http_port}...")
|
print(f"HTTP server listening on port {self.http_port}...")
|
||||||
@@ -535,7 +525,6 @@ class WebServer:
|
|||||||
except OSError as e:
|
except OSError as e:
|
||||||
if not self.running:
|
if not self.running:
|
||||||
break
|
break
|
||||||
print(f"OSError! {e}")
|
|
||||||
continue
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"HTTP error: {e}")
|
print(f"HTTP error: {e}")
|
||||||
@@ -568,7 +557,6 @@ class WebServer:
|
|||||||
except OSError as e:
|
except OSError as e:
|
||||||
if not self.running:
|
if not self.running:
|
||||||
break
|
break
|
||||||
print(f"OSError! {e}")
|
|
||||||
continue
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"HTTPS error: {e}")
|
print(f"HTTPS error: {e}")
|
||||||
@@ -591,14 +579,10 @@ class WebServer:
|
|||||||
if line.lower().startswith(b"content-length:"):
|
if line.lower().startswith(b"content-length:"):
|
||||||
content_length = int(line.split(b":")[1].strip())
|
content_length = int(line.split(b":")[1].strip())
|
||||||
|
|
||||||
# print(f"Content-Length to server: {content_length}")
|
|
||||||
|
|
||||||
# Read body
|
# Read body
|
||||||
body = rest
|
body = rest
|
||||||
print(f"Rest length: {len(rest)}")
|
|
||||||
while len(body) < content_length:
|
while len(body) < content_length:
|
||||||
chunk = conn.recv(4096)
|
chunk = conn.recv(4096)
|
||||||
# print(f"\n\nrecv returned {len(chunk)}\n\n")
|
|
||||||
if not chunk:
|
if not chunk:
|
||||||
print("\n\nsocket closed\n\n")
|
print("\n\nsocket closed\n\n")
|
||||||
break
|
break
|
||||||
@@ -618,7 +602,6 @@ class WebServer:
|
|||||||
if isinstance(response, str):
|
if isinstance(response, str):
|
||||||
response = response.encode()
|
response = response.encode()
|
||||||
|
|
||||||
print(len(response))
|
|
||||||
conn.sendall(response)
|
conn.sendall(response)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error handling connection: {e}")
|
print(f"Error handling connection: {e}")
|
||||||
@@ -633,10 +616,8 @@ class WebServer:
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def handle_request(self, data, addr):
|
def handle_request(self, data, addr):
|
||||||
# print(f"data: {data}")
|
|
||||||
request_line = data.splitlines()[0]
|
request_line = data.splitlines()[0]
|
||||||
|
|
||||||
# Extract host from headers, never works though
|
|
||||||
for line in data.splitlines():
|
for line in data.splitlines():
|
||||||
if "Host" in line:
|
if "Host" in line:
|
||||||
host = line.split(":", 1)[1].strip()
|
host = line.split(":", 1)[1].strip()
|
||||||
@@ -735,7 +716,6 @@ class WebServer:
|
|||||||
file_content, mimetype = self.file_handler.read_file(path, directory)
|
file_content, mimetype = self.file_handler.read_file(path, directory)
|
||||||
|
|
||||||
if file_content == 403:
|
if file_content == 403:
|
||||||
print("WARN: Directory traversal attack prevented.") # look ma, security!!
|
|
||||||
return self.build_response(403, self.http_403_html)
|
return self.build_response(403, self.http_403_html)
|
||||||
if file_content == 404:
|
if file_content == 404:
|
||||||
return self.build_response(404, self.http_404_html)
|
return self.build_response(404, self.http_404_html)
|
||||||
@@ -789,7 +769,6 @@ class WebServer:
|
|||||||
200: "OK",
|
200: "OK",
|
||||||
204: "No Content",
|
204: "No Content",
|
||||||
302: "Found",
|
302: "Found",
|
||||||
304: "Not Modified", # TODO KEKL
|
|
||||||
400: "Bad Request",
|
400: "Bad Request",
|
||||||
403: "Forbidden",
|
403: "Forbidden",
|
||||||
404: "Not Found",
|
404: "Not Found",
|
||||||
@@ -803,8 +782,6 @@ class WebServer:
|
|||||||
if isinstance(body, str):
|
if isinstance(body, str):
|
||||||
body = body.encode()
|
body = body.encode()
|
||||||
|
|
||||||
# TODO: dont encode yet, and i encode. awesome comments here.
|
|
||||||
# Don't encode yet, if 302 status code we have to include location.
|
|
||||||
headers = (
|
headers = (
|
||||||
f"HTTP/1.1 {status_code} {status_message}\r\n"
|
f"HTTP/1.1 {status_code} {status_message}\r\n"
|
||||||
f"Server: Amethyst/build-{AMETHYST_BUILD_NUMBER}\r\n"
|
f"Server: Amethyst/build-{AMETHYST_BUILD_NUMBER}\r\n"
|
||||||
@@ -813,13 +790,6 @@ class WebServer:
|
|||||||
).encode()
|
).encode()
|
||||||
|
|
||||||
if status_code == 302:
|
if status_code == 302:
|
||||||
# 302 currently only happens when the reload is triggered.
|
|
||||||
# Why not 307, Moved Permanently? Because browsers will cache the
|
|
||||||
# response and not send the reload command.
|
|
||||||
# if port == 443:
|
|
||||||
# host = f"https://{host}/"
|
|
||||||
# else:
|
|
||||||
# host = f"http://{host}/"
|
|
||||||
headers = (
|
headers = (
|
||||||
f"HTTP/1.1 {status_code} {status_message}\r\n"
|
f"HTTP/1.1 {status_code} {status_message}\r\n"
|
||||||
f"Location: {host}\r\n"
|
f"Location: {host}\r\n"
|
||||||
@@ -864,9 +834,7 @@ def main():
|
|||||||
http_port = file_handler.read_config("port")
|
http_port = file_handler.read_config("port")
|
||||||
https_port = file_handler.read_config("https-port")
|
https_port = file_handler.read_config("https-port")
|
||||||
http_enabled = bool(file_handler.read_config("http"))
|
http_enabled = bool(file_handler.read_config("http"))
|
||||||
print(http_enabled)
|
|
||||||
https_enabled = bool(file_handler.read_config("https"))
|
https_enabled = bool(file_handler.read_config("https"))
|
||||||
print(https_enabled)
|
|
||||||
server = WebServer(http_port=http_port, https_port=https_port)
|
server = WebServer(http_port=http_port, https_port=https_port)
|
||||||
server.start(http_enabled, https_enabled)
|
server.start(http_enabled, https_enabled)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user