From 5d1c903638335cf5397ef34500c1a61f62586bd3 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Wed, 13 May 2020 08:53:07 +0300 Subject: feat: use TLS unconditionally Later on, we'll need to support non-TLS as well, for Let's Encrypt, but this'll do for now. --- ewww.md | 20 ++++++------- ewww.py | 94 ++++++++++++++++++++++++++++++++++++++----------------------- ewww.yaml | 2 +- src/main.rs | 5 ++++ 4 files changed, 73 insertions(+), 48 deletions(-) diff --git a/ewww.md b/ewww.md index 2232e75..8e60f8b 100644 --- a/ewww.md +++ b/ewww.md @@ -88,21 +88,23 @@ for static content only. Every other method returns an error. ## Minimal smoke test ~~~scenario -given a running server using config file minimal.yaml -when I request GET http://example.com/ +given a self-signed certificate as snakeoil.pem, using key snakeoil.key +and a running server using config file minimal.yaml +when I request GET https://example.com/ then I get status code 200 ~~~ ~~~{#minimal.yaml .file .yaml} -hosts: - - example.com +tls_key: snakeoil.key +tls_cert: snakeoil.pem ~~~ ## Smoke test ~~~scenario -given a running server using config file smoke.yaml +given a self-signed certificate as snakeoil.pem, using key snakeoil.key +and a running server using config file smoke.yaml when I create webroot/foo with "hello, world" and I request GET https://example.com/foo then I get status code 200 @@ -143,12 +145,8 @@ scaffolding adds randomly chosen port numbers so that the test can run without being root. ~~~{#smoke.yaml .file .yaml .numberLines} -webroot: webroot -hosts: - - example.com - - www.example.com -tlscert: snakeoil.pem -tlskey: snakeoil.key +tls_cert: snakeoil.pem +tls_key: snakeoil.key ~~~ ## Performance test diff --git a/ewww.py b/ewww.py index 8e179be..2e45aa9 100644 --- a/ewww.py +++ b/ewww.py @@ -5,6 +5,7 @@ import json import os import random import re +import shutil import subprocess import time import urllib.parse @@ -16,36 +17,36 @@ import yaml def _run(ctx, argv): p = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate("") - ctx['argv'] = argv - ctx['stdout'] = stdout.decode('utf-8') - ctx['stderr'] = stderr.decode('utf-8') - ctx['exit'] = p.returncode + ctx["argv"] = argv + ctx["stdout"] = stdout.decode("utf-8") + ctx["stderr"] = stderr.decode("utf-8") + ctx["exit"] = p.returncode # Check that latest call of _run ended with an specific exit code. def _run_exit(ctx, expected): - if ctx['exit'] != expected: - print('ctx:', ctx.as_dict()) - assert_eq(ctx['exit'], expected) + if ctx["exit"] != expected: + print("ctx:", ctx.as_dict()) + assert_eq(ctx["exit"], expected) # Name of Rust binary, debug-build. def _binary(name): - return os.path.abspath(os.path.join(srcdir, 'target', 'debug', name)) + return os.path.abspath(os.path.join(srcdir, "target", "debug", name)) # Write a file with given content. def _write(filename, content): - open(filename, 'w').write(content) + open(filename, "w").write(content) # Construct a URL that points to server running on localhost by # replacing the actual scheme and host with ones that work for test. def _url(ctx, url): - port = ctx['config']['port'] + port = ctx["config"]["port"] c = urllib.parse.urlparse(url) host = c[1] - c = ('http', 'localhost:{}'.format(port)) + c[2:] + c = (c[0], "localhost:{}".format(port)) + c[2:] return urllib.parse.urlunparse(c), host @@ -57,59 +58,80 @@ def _url(ctx, url): def fixme(*args, **kwargs): assert 0 + # Create a file. def create_file(ctx, filename=None, content=None): dirname = os.path.dirname(filename) os.makedirs(dirname) _write(filename, content) + +# Copy test certificate from source tree, where it's been created previously by +# ./check. +def copy_test_certificate(ctx, cert=None, key=None): + shutil.copy(os.path.join(srcdir, "test.pem"), cert) + shutil.copy(os.path.join(srcdir, "test.key"), key) + + # Start server using named configuration file. def start_server(ctx, filename=None): - config = get_file(filename).decode('UTF-8') + config = get_file(filename).decode("UTF-8") config = yaml.safe_load(config) - config['port'] = random.randint(2000, 30000) - ctx['config'] = config + config["port"] = random.randint(2000, 30000) + ctx["config"] = config config = yaml.safe_dump(config) _write(filename, config) - _run(ctx, [ - '/usr/sbin/daemonize', - '-c', os.getcwd(), - '-p', 'ewww.pid', - '-o', 'ewww.stdout', - '-e', 'ewww.stderr', - _binary('ewww'), - filename - ]) + _run( + ctx, + [ + "/usr/sbin/daemonize", + "-c", + os.getcwd(), + "-p", + "ewww.pid", + "-o", + "ewww.stdout", + "-e", + "ewww.stderr", + _binary("ewww"), + filename, + ], + ) _run_exit(ctx, 0) - ctx['pid'] = open('ewww.pid').read() + ctx["pid"] = open("ewww.pid").read() + # Make a HTTP request. def request(ctx, method=None, url=None): url, host = _url(ctx, url) - _run(ctx, ['curl', '-sv', '-X', method, '-HHost: {}'.format(host), url]) + print(url) + _run(ctx, ["curl", "-ksv", "-X", method, "-HHost: {}".format(host), url]) _run_exit(ctx, 0) + # Check status code of latest HTTP request. def status_code_is(ctx, code=None): - pattern = '\n< HTTP/1.1 {} '.format(code) - assert_eq(pattern in ctx['stderr'], True) + pattern = "\n< HTTP/2 {} ".format(code) + assert_eq(pattern in ctx["stderr"], True) + # Check a HTTP response header for latest request has a given value. def http_header_is(ctx, header=None, value=None): - s = ctx['stderr'] - pattern = '\n< {}: {}'.format(header, value) + s = ctx["stderr"] + pattern = "\n< {}: {}".format(header, value) if pattern not in s: - print('stderr:', repr(s)) - print('pattern:', repr(pattern)) + print("stderr:", repr(s)) + print("pattern:", repr(pattern)) assert_eq(pattern in s, True) - + + # Check a HTTP body response for latest request has a given value. def http_body_is(ctx, body=None): - s = ctx['stdout'] - body = body.encode('UTF8').decode('unicode-escape') + s = ctx["stdout"] + body = body.encode("UTF8").decode("unicode-escape") if body != s: - print('stdout:', repr(s)) - prin('pattern:', repr(body)) + print("stdout:", repr(s)) + prin("pattern:", repr(body)) assert_eq(body, s) diff --git a/ewww.yaml b/ewww.yaml index 56be410..94c33c1 100644 --- a/ewww.yaml +++ b/ewww.yaml @@ -1,5 +1,5 @@ - given: a self-signed certificate as {cert}, using key {key} - function: fixme + function: copy_test_certificate - given: a running server using config file {filename} function: start_server diff --git a/src/main.rs b/src/main.rs index 35728a9..c6e22ab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,8 @@ use warp::Filter; #[derive(Debug, Deserialize)] struct Config { port: u16, + tls_key: PathBuf, + tls_cert: PathBuf, } #[derive(Debug, StructOpt)] @@ -25,6 +27,9 @@ async fn main() { eprintln!("starting server: {:?}", config); warp::serve(hello) + .tls() + .key_path(config.tls_key) + .cert_path(config.tls_cert) .run(([127, 0, 0, 1], config.port)) .await; } -- cgit v1.2.1