Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove serve_once and deamon-specific options from utils.py #102

Merged
merged 6 commits into from
Apr 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.PHONY: all lint diff format test

all: format test

lint:
python3 -m isort -c src/ tests/ example/
python3 -m black --check src/ tests/ example/
Expand All @@ -13,6 +17,6 @@ format:
python3 -m black src/ tests/ example/

test:
pip install .
pip3 install .
coverage run -m pytest
coverage report -m
24 changes: 0 additions & 24 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,30 +323,6 @@ Will raise an exception if failed.
:param timeout: a timeout
:return read: the bytes read

## start_daemon
```python
start_daemon(target)
```

starts a thread as daemon
:param target: the function
:return: the started thread

## serve_once
```python
serve_once(html, start_port=5000, autoincrement_port=True, content_type='text/html', headers=None)
```

Render Text in the users browser
Opens a web server that serves a HTML string once and shuts down after the first request.
The port will be open when this function returns. (though serving the request may take a few mils)
:param html: The html code to deliver on the initial request
:param start_port: The port it should try to listen on first.
:param autoincrement_port: If the port should be increased if the server cannot listen on the provided start_port
:param content_type: The content type this server should report (change it if you want json, for example)
:param headers: Additional headers as {header_key: value} dict.
:return: The port the server started listening on

## SimpleSocket
```python
SimpleSocket(self, host=None, port=0, timeout=<object object at 0x000000000303A670>)
Expand Down
2 changes: 0 additions & 2 deletions src/enochecker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@
ensure_bytes,
ensure_unicode,
ensure_valid_filename,
serve_once,
sha256ify,
snake_caseify,
start_daemon,
)

name = "enochecker"
105 changes: 1 addition & 104 deletions src/enochecker/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,10 @@
import re
import socket
import telnetlib
import threading
import time
from http.server import BaseHTTPRequestHandler, HTTPServer
from typing import (
TYPE_CHECKING,
Any,
Callable,
Dict,
List,
Match,
Optional,
Pattern,
Sequence,
Tuple,
Union,
)
from typing import Any, Callable, List, Match, Optional, Pattern, Sequence, Tuple, Union

from .results import BrokenServiceException

if TYPE_CHECKING: # pragma: no cover
import requests

PORT_MAX = 65535

logging.basicConfig(level=logging.DEBUG)
Expand Down Expand Up @@ -181,91 +163,6 @@ def debase64ify(
return base64.b64decode(s).decode("utf-8")


def start_daemon(target: Callable[..., Any]) -> threading.Thread:
"""
Start a thread as daemon.
:param target: the function
:return: the started thread
"""
t = threading.Thread(target=target)
t.daemon = True
t.start()
return t


def serve_once(
html: Union[str, bytes, "requests.Response"],
start_port: int = 5000,
autoincrement_port: bool = True,
content_type: str = "text/html",
headers: Optional[Dict[str, str]] = None,
logger: Optional[logging.Logger] = None,
) -> int:
"""
Render Text in the users browser.
Opens a web server that serves a HTML string once and shuts down after the first request.
The port will be open when this function returns. (though serving the request may take a few mils)
:param html: The html code to deliver on the initial request
:param start_port: The port it should try to listen on first.
:param autoincrement_port: If the port should be increased if the server cannot listen on the provided start_port
:param content_type: The content type this server should report (change it if you want json, for example)
:param headers: Additional headers as {header_key: value} dict.
:param logger: the optional logger to redirect logs to.
:return: The port the server started listening on
"""
# see https://github.com/psf/requests/issues/2925
import requests

logger_: logging.Logger = logger or utilslogger
headers_: Dict[str, str] = headers or {}
if isinstance(html, requests.Response):
payload: bytes = html.text.encode("UTF-8")
elif isinstance(html, str):
payload = html.encode("UTF-8")
else:
payload = html

class OutputHandler(BaseHTTPRequestHandler):

# noinspection PyPep8Naming
def do_GET(self) -> None:
self.send_response(200)
self.send_header("Content-type", content_type)
for key, value in headers_.items():
self.send_header(key, value)
self.end_headers()
self.wfile.write(payload)
logger_.info("Served HTTP once. Stopping.")
start_daemon(self.server.shutdown)

for port in range(start_port, PORT_MAX):
try:
server = HTTPServer(("", port), OutputHandler)
logging.debug("Serving {} bytes on port {}".format(len(payload), port))
start_daemon(server.serve_forever)
time.sleep(0.1) # some extra time thrown in for good measure. :)
return port
except OSError as ex:
if not autoincrement_port:
logger_.info(
"Serve once was not set to automatically increment port {} but faced socket exception{}".format(
start_port, ex
),
exc_info=True,
stack_info=True,
)
break

raise OSError(
"No unused port found, start_port={}, autoincrement_port={}".format(
start_port, autoincrement_port
)
)


class SimpleSocket(telnetlib.Telnet):
"""
Telnetlib with some additions.
Expand Down
25 changes: 0 additions & 25 deletions tests/test_enochecker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import functools
import sys
import tempfile
import time
from logging import DEBUG

import pytest
Expand All @@ -17,7 +16,6 @@
assert_in,
ensure_bytes,
ensure_unicode,
serve_once,
snake_caseify,
)

Expand Down Expand Up @@ -168,29 +166,6 @@ def test_dict():
assert len(db) == 0


@temp_storage_dir
def test_checker_connections():
# TODO: Check timeouts?
text = "ECHO :)"
_ = serve_once(text, 9999)
checker = CheckerExampleImpl(
CheckerMethod.CHECKER_METHOD_PUTFLAG,
) # Conflict between logging and enochecker.logging because of wildcart import
assert (
checker.http_get("/").text == text
) # Should probably rename it to enologger to avoid further conflicts

# Give server time to shut down
time.sleep(0.2)

_ = serve_once(text, 9999)
checker = CheckerExampleImpl(CheckerMethod.CHECKER_METHOD_PUTFLAG)
t = checker.connect()
t.write(b"GET / HTTP/1.0\r\n\r\n")
assert t.readline_expect("HTTP")
t.close()


@temp_storage_dir
def test_checker():
flag = "ENOFLAG"
Expand Down