diff --git a/browser.py b/browser.py index 8c743d9..d7de99a 100644 --- a/browser.py +++ b/browser.py @@ -28,7 +28,8 @@ class URL: ) s.connect((self.host, self.port)) if self.scheme == "https": - context = ssl.create_default_context() + ssl.create_default_context() + context = ssl.SSLContext(ssl.PROTOCOL_TLS) s = context.wrap_socket(s, server_hostname=self.host) request_str = f"GET {self.path} HTTP/1.0\r\n" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/cert.pem b/tests/cert.pem new file mode 100644 index 0000000..58c44a6 --- /dev/null +++ b/tests/cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDbzCCAlegAwIBAgIUROO7imFPFyMzfKCmSSa8TGvAx6AwDQYJKoZIhvcNAQEL +BQAwRzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExDzANBgNVBAcM +BkxvbXBvYzESMBAGA1UEAwwJMTI3LjAuMC4xMB4XDTI0MTEyODAyMjIwN1oXDTI0 +MTIyODAyMjIwN1owRzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx +DzANBgNVBAcMBkxvbXBvYzESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Je+aeCg977nlzBJQ+9iqqbos7INnDqMgxUC +oUtpd9+1/++z+WcxUxTCUAhDV/OD6nOLGe4H2O/5jeK/IHcAs/0Gq6ksd0Qvx7J2 +VC84WN598e+acgH9b82aYGB63yQqxTUoAJTqjNRJvJnOCjnSlpS8MvBv8DTCKFeF +8rjDu7uxLgdt1787P/uTM62nrZUygLCtJqcDFPxFYjSnnMT2lALwuYab9080bV3w +QoomSs4FTo3ZIFDD6YZ6eyCrUOubIAg8ZAVfcrKUjTY1IkIwnwKiUCMpcg8hD+Gb +BHo9fQiDj1npk++9XjNF0qZy16rgL6aOZqMQiNORxr6coPG+QwIDAQABo1MwUTAd +BgNVHQ4EFgQUHxewwI1PpcU165FViyArQv4bJ3IwHwYDVR0jBBgwFoAUHxewwI1P +pcU165FViyArQv4bJ3IwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC +AQEAGHLiixpwlRO5euyrqWEnNPzzLmrOhFQ1SSlo3KnG3kmDcPLC1vifzi9IeqSZ +zG/rl+JQYh30Ij0/CsgZTubXu6F3jQDiG5g3nvN/lDlzWRsePjZAN1OYh7UTKcNY +B5dvjCKXDcMeYM7jYYGKVlS/iowiCogTfd4mgV+jMoQRLXoYi5xTfr3Y5Flb7opu +6G2w4WHT6d/2vPdEuBhMp/2/G6d0WRZ5QILLeF02b6v7MjbZ9sIlNztVq5IWj466 +dbqUP6eVHNDjALwwu/6GGChH1rDzbEcRMdzs254oIsQnNbVJannGy7qswKAb5Xrb +Oja90IiarO3y+zfC6xc9gwXpfw== +-----END CERTIFICATE----- diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..9f3be4c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,20 @@ +import pytest + +from tests.server import create_http_server_process +from tests.server import create_https_server_process + + +@pytest.fixture +def http_server(request): + server = create_http_server_process(request.param) + server.start() + yield + server.terminate() + + +@pytest.fixture +def https_server(request): + server = create_https_server_process(request.param) + server.start() + yield + server.terminate() diff --git a/tests/key.pem b/tests/key.pem new file mode 100644 index 0000000..df3e01b --- /dev/null +++ b/tests/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDYl75p4KD3vueX +MElD72Kqpuizsg2cOoyDFQKhS2l337X/77P5ZzFTFMJQCENX84Pqc4sZ7gfY7/mN +4r8gdwCz/QarqSx3RC/HsnZULzhY3n3x75pyAf1vzZpgYHrfJCrFNSgAlOqM1Em8 +mc4KOdKWlLwy8G/wNMIoV4XyuMO7u7EuB23Xvzs/+5MzraetlTKAsK0mpwMU/EVi +NKecxPaUAvC5hpv3TzRtXfBCiiZKzgVOjdkgUMPphnp7IKtQ65sgCDxkBV9yspSN +NjUiQjCfAqJQIylyDyEP4ZsEej19CIOPWemT771eM0XSpnLXquAvpo5moxCI05HG +vpyg8b5DAgMBAAECggEACdMsUdzc1brPrOXa/51oHN9Ftq0GKAbnNnpUAba22eII +fUvFdAlFzVknjVN/9ok3JoHyQTgGcW/v9+CIFJ7BUJN9jiOLlFIVVsTWJZsfaQyY +AEsC9wFMb+9kKCiy5NSyVKVveJieC8sEw0I40fGYh2Mc0bS4EdiFfCioN1VBRQ6O +SBy5px0qFuYaGlZQrqUOZqJSMtPoQZf/ivEm2tvhVS8WACBZKvniex9LycqrhJAY +4qh+LwvC2qjszQonL52zcKQMy+/rgk4soaGPdmG09FeTFYhGIR0HWEFMFqgoejiH +oDC08yFLauKkvgc2EOuD5IkZHU+2/zpVLN9xldq3wQKBgQD+cXWuchD+N7qBpZd5 +CDbHzm6b+vLpCcHst+DyajrV9laabnlFGDFuR0EktWieldDvwyb3LgL42YJg5zIZ +ghyWzyhpFn/OkAjbwoWIkcOgn/50O02JHkmjc103UJXuAmkgiVSJ2k2ewtjHN8GL +AYSMx/mOB8Yrls9rm8Bdws38QQKBgQDZ6v+BNWpkd3PrEVSDGQM4EvkDtbvYPS4p +9+1HhF6uYZ3EoP3e/Qzp9P1iyX/4NUXeWkyWsdMBJf5vJg42B/gEKEXYnT5tQhqF +ac+JnzDYWw3udpl2W1X2oiGH3B04PSbMb41+DQ5NYSZtnJPOwH/mS5bfLoZpATrW +2rm3rFNpgwKBgH4o5a/UUQarvScxYvSZFQhnG8LtX+oac3QbDEdGUtvqI7C43Bpd +T40deXhpFnGjWRC406Y1wzV+K74+hEHPmLtSBfhtNnvGQQ4t2iYIGFaZXgJlsSEu +ylZoCi02IND9kwCV9zvO6TOx6uiEhcuVuhJPyTYaNrFAOqJhfLVAtP/BAoGAWrxW +lt4+5oY2ZfJZVhzcEkUUGk9ZX7hZuG/bBKRBKCrNHkpKasbC0ceImdF8z0SfSu4e +ZcC1Mw022+DkmerHgjOioYcXrzaPBG4CVDNMi0mei2QmkfmF2aO4gnFMWVZdCVKJ +f6rAAcgp0AoaIURV/PYMY/FjVeWFMmDwY2IFeTECgYBhI8vjdFDpfwZvD2d7GwqT +/wK7GOJWbqJGx5KgzVxxNzZtOF8pM1+3AKcoVhnO42oalB+Zywq4Ju3d5673owm3 +HZ83nrgiHvYrIb/xEjIfctqKZLWyQndFY++TTenFPhNHw6BV12tZlPKbS3bl6lHX +EY3aH2GtHyGlOssSyMSWZQ== +-----END PRIVATE KEY----- diff --git a/tests/server.py b/tests/server.py new file mode 100644 index 0000000..a0a85ea --- /dev/null +++ b/tests/server.py @@ -0,0 +1,44 @@ +import ssl +from multiprocessing import Process +from http import HTTPStatus +from http.server import HTTPServer +from http.server import BaseHTTPRequestHandler + + +class Handler(BaseHTTPRequestHandler): + def log_message(self, format, *args): + pass + + def send_text(self, content: str): + self.wfile.write(content.encode("utf8")) + + def do_GET(self): + if self.path == "/": + self.send_response(HTTPStatus.OK) + self.end_headers() + self.send_text("test") + + +def get_ssl_context(cert_file, key_file): + context = ssl.SSLContext(ssl.PROTOCOL_TLS) + context.load_cert_chain(cert_file, key_file) + context.set_ciphers("@SECLEVEL=1:ALL") + return context + + +def _start_http_server(port: int, use_tls: bool = False): + with HTTPServer(("127.0.0.1", port), Handler) as httpd: + if use_tls: + context = get_ssl_context("tests/cert.pem", "tests/key.pem") + httpd.socket = context.wrap_socket(httpd.socket, server_side=True) + httpd.serve_forever() + + +def create_http_server_process(port: int = 80): + server_process = Process(target=_start_http_server, kwargs={"port": port, "use_tls": False}) + return server_process + + +def create_https_server_process(port: int = 443): + server_process = Process(target=_start_http_server, kwargs={"port": port, "use_tls": True}) + return server_process diff --git a/tests/url_test.py b/tests/url_test.py new file mode 100644 index 0000000..fa88025 --- /dev/null +++ b/tests/url_test.py @@ -0,0 +1,83 @@ +import pytest + +from browser import URL + +@pytest.mark.parametrize( + "url_string,scheme,host,port,path", + [ + ( + "http://example.com", + "http", + "example.com", + 80, + "/", + ), + ( + "http://example.com/", + "http", + "example.com", + 80, + "/", + ), + ( + "https://example.com/", + "https", + "example.com", + 443, + "/", + ), + ( + "http://example.com:5000/", + "http", + "example.com", + 5000, + "/", + ), + ( + "http://example.com:5000/test/example", + "http", + "example.com", + 5000, + "/test/example", + ), + ( + "https://example.com:5000/test/example", + "https", + "example.com", + 5000, + "/test/example", + ), + ], +) +def test_url_parsing(url_string, scheme, host, port, path): + url = URL(url_string) + assert url.scheme == scheme + assert url.host == host + assert url.port == port + assert url.path == path + + +@pytest.mark.parametrize( + "http_server,url_string", + [ + (80, "http://127.0.0.1/"), + (5000, "http://127.0.0.1:5000/"), + ], + indirect=["http_server"], +) +def test_http_request(http_server, url_string): + url = URL(url_string) + assert url.request() == "test" + + +@pytest.mark.parametrize( + "https_server,url_string", + [ + (443, "https://127.0.0.1/"), + (5000, "https://127.0.0.1:5000/"), + ], + indirect=["https_server"], +) +def test_https_request(https_server, url_string): + url = URL(url_string) + assert url.request() == "test"