Skip to content

4.0.0 - Huge refactor, more examples, authentication, configurable MIMETypes #54

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
0fff602
Replaced public header_body_bytes by private methods
michalpokusa Apr 24, 2023
75ac0f2
Added authentication logic, AuthenticationError, UNAUTHORIZED_401 status
michalpokusa Apr 25, 2023
d4a8a8d
Removed HTTP... prefix from class names
michalpokusa Apr 25, 2023
4224ac8
Replaced CommonHTTPStatus with direct values
michalpokusa Apr 25, 2023
33fecc9
Allowed passing multiple methods at the same time to .route
michalpokusa Apr 25, 2023
ee7a8b0
Major refactor of MIMETypes
michalpokusa Apr 25, 2023
142c89b
Added option to restrict access to whole Server with Authentication
michalpokusa Apr 26, 2023
ffa62d9
Replaced decorator that prevents sending Response multiple times with…
michalpokusa Apr 26, 2023
ee67bdb
_Route now respects "/" suffix of path
michalpokusa Apr 26, 2023
18d4a53
Changed positional url parameters to keyword
michalpokusa Apr 26, 2023
e5ddaaf
Refactor of .poll and .server_forever, added option to disable filesy…
michalpokusa Apr 26, 2023
85254e5
Changes to docstrings
michalpokusa Apr 27, 2023
fdf66bf
Merge remote-tracking branch 'origin/main' into 4.0.0-todo
michalpokusa Apr 27, 2023
15b00cb
Added server parameter to Request
michalpokusa Apr 28, 2023
5d533da
Default .send_file to server's root_path
michalpokusa Apr 28, 2023
223086d
Added imports directly from adafruit_httpserver
michalpokusa Apr 28, 2023
19148a5
Extensive updates and expansion of docs and examples
michalpokusa Apr 28, 2023
240a2c4
Added home.html file to one of the examples
michalpokusa Apr 28, 2023
b9d1eac
Added :emphasize-lines: and minor change in one of example descriptions
michalpokusa Apr 28, 2023
cd8146e
Fix: Missing Copyright information
michalpokusa Apr 28, 2023
eba7a91
Added Server.stop
michalpokusa Apr 29, 2023
e5bf831
Added Multiple servers example
michalpokusa Apr 29, 2023
07782b6
Removed accidentally commited leftover
michalpokusa Apr 29, 2023
61135f1
Added checking if compatible send method is used
michalpokusa Apr 29, 2023
752dcaf
Returning from serve_forever on KeyboardInterrupt
michalpokusa Apr 30, 2023
e5f506b
Added Request.json()
michalpokusa Apr 30, 2023
e1d3e3b
Added method for verifying that server can be started on given host:port
michalpokusa Apr 30, 2023
0607776
Added host and port attributes to Server
michalpokusa Apr 30, 2023
dbdbacd
Added Server.debug for verbose messages during development
michalpokusa Apr 30, 2023
7c6ae2a
Updated the NeoPixel example to also show using values from POST data
michalpokusa Apr 30, 2023
0eef2e8
Changes/fixes in docs
michalpokusa May 1, 2023
a5be235
Added stopping server on Ctrl-C and debug message on stop
michalpokusa May 1, 2023
33d6b25
Refactor of _Route and _Routes, added append_slash
michalpokusa May 1, 2023
191e91c
Changed format of debug logs, added Response.size, fix in send_chunk
michalpokusa May 2, 2023
a424d27
Added ... and .... wildcards
michalpokusa May 3, 2023
3359668
Imported missing exception in module init, updated authors
michalpokusa May 3, 2023
55be729
Fix: Incorrectly changing from list to set using brackets
michalpokusa May 5, 2023
c299f9f
Corrected typing in Response.send
michalpokusa May 6, 2023
e3529d6
Moved debugging exception to .poll()
michalpokusa May 7, 2023
f95781a
Rewrite of Response logic from context managers to returns, added som…
michalpokusa May 8, 2023
87b0e27
Updated docs and examples to new Response API, added example of Redirect
michalpokusa May 8, 2023
90ce536
Minor refactor of sending response, modified guard
michalpokusa May 8, 2023
3336d40
Merge remote-tracking branch 'origin/main' into 4.0.0-examples-refact…
michalpokusa May 11, 2023
85b452b
Fix: Incorrect parsing of default route methods
michalpokusa May 22, 2023
4ad7995
Added warning about exposing files and some docstrings
michalpokusa May 22, 2023
f59d10c
Fix: Removed text keyword from Response
michalpokusa May 22, 2023
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
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ HTTP Server for CircuitPython.
- Gives access to request headers, query parameters, body and client's address, the one from which the request came.
- Supports chunked transfer encoding.
- Supports URL parameters and wildcard URLs.
- Supports HTTP Basic and Bearer Authentication on both server and route per level.


Dependencies
Expand Down
62 changes: 60 additions & 2 deletions adafruit_httpserver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
`adafruit_httpserver`
================================================================================

Simple HTTP Server for CircuitPython
Socket based HTTP Server for CircuitPython


* Author(s): Dan Halbert
* Author(s): Dan Halbert, Michał Pokusa

Implementation Notes
--------------------
Expand All @@ -21,3 +21,61 @@

__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_HTTPServer.git"


from .authentication import (
Basic,
Bearer,
check_authentication,
require_authentication,
)
from .exceptions import (
ServerStoppedError,
AuthenticationError,
InvalidPathError,
ParentDirectoryReferenceError,
BackslashInPathError,
ServingFilesDisabledError,
FileNotExistsError,
)
from .headers import Headers
from .methods import (
GET,
POST,
PUT,
DELETE,
PATCH,
HEAD,
OPTIONS,
TRACE,
CONNECT,
)
from .mime_types import MIMETypes
from .request import Request
from .response import (
Response,
FileResponse,
ChunkedResponse,
JSONResponse,
Redirect,
)
from .server import Server
from .status import (
Status,
OK_200,
CREATED_201,
ACCEPTED_202,
NO_CONTENT_204,
PARTIAL_CONTENT_206,
TEMPORARY_REDIRECT_307,
PERMANENT_REDIRECT_308,
BAD_REQUEST_400,
UNAUTHORIZED_401,
FORBIDDEN_403,
NOT_FOUND_404,
METHOD_NOT_ALLOWED_405,
TOO_MANY_REQUESTS_429,
INTERNAL_SERVER_ERROR_500,
NOT_IMPLEMENTED_501,
SERVICE_UNAVAILABLE_503,
)
64 changes: 64 additions & 0 deletions adafruit_httpserver/authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_httpserver.authentication`
====================================================
* Author(s): Michał Pokusa
"""

try:
from typing import Union, List
except ImportError:
pass

from binascii import b2a_base64

from .exceptions import AuthenticationError
from .request import Request


class Basic:
"""Represents HTTP Basic Authentication."""

def __init__(self, username: str, password: str) -> None:
self._value = b2a_base64(f"{username}:{password}".encode()).decode().strip()

def __str__(self) -> str:
return f"Basic {self._value}"


class Bearer:
"""Represents HTTP Bearer Token Authentication."""

def __init__(self, token: str) -> None:
self._value = token

def __str__(self) -> str:
return f"Bearer {self._value}"


def check_authentication(request: Request, auths: List[Union[Basic, Bearer]]) -> bool:
"""
Returns ``True`` if request is authorized by any of the authentications, ``False`` otherwise.
"""

auth_header = request.headers.get("Authorization")

if auth_header is None:
return False

return any(auth_header == str(auth) for auth in auths)


def require_authentication(request: Request, auths: List[Union[Basic, Bearer]]) -> None:
"""
Checks if the request is authorized and raises ``AuthenticationError`` if not.

If the error is not caught, the server will return ``401 Unauthorized``.
"""

if not check_authentication(request, auths):
raise AuthenticationError(
"Request is not authenticated by any of the provided authentications"
)
16 changes: 14 additions & 2 deletions adafruit_httpserver/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@
"""


class ServerStoppedError(Exception):
"""
Raised when ``.poll`` is called on a stopped ``Server``.
"""


class AuthenticationError(Exception):
"""
Raised by ``require_authentication`` when the ``Request`` is not authorized.
"""


class InvalidPathError(Exception):
"""
Parent class for all path related errors.
Expand All @@ -34,9 +46,9 @@ def __init__(self, path: str) -> None:
super().__init__(f"Backslash in path: {path}")


class ResponseAlreadySentError(Exception):
class ServingFilesDisabledError(Exception):
"""
Another ``HTTPResponse`` has already been sent. There can only be one per ``HTTPRequest``.
Raised when ``root_path`` is not set and there is no handler for ``request``.
"""


Expand Down
8 changes: 4 additions & 4 deletions adafruit_httpserver/headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: MIT
"""
`adafruit_httpserver.headers.HTTPHeaders`
`adafruit_httpserver.headers`
====================================================
* Author(s): Michał Pokusa
"""
Expand All @@ -13,7 +13,7 @@
pass


class HTTPHeaders:
class Headers:
"""
A dict-like class for storing HTTP headers.

Expand All @@ -23,7 +23,7 @@ class HTTPHeaders:

Examples::

headers = HTTPHeaders({"Content-Type": "text/html", "Content-Length": "1024"})
headers = Headers({"Content-Type": "text/html", "Content-Length": "1024"})

len(headers)
# 2
Expand Down Expand Up @@ -80,7 +80,7 @@ def update(self, headers: Dict[str, str]):

def copy(self):
"""Returns a copy of the headers."""
return HTTPHeaders(dict(self._storage.values()))
return Headers(dict(self._storage.values()))

def __getitem__(self, name: str):
return self._storage[name.lower()][1]
Expand Down
32 changes: 10 additions & 22 deletions adafruit_httpserver/methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,26 @@
#
# SPDX-License-Identifier: MIT
"""
`adafruit_httpserver.methods.HTTPMethod`
`adafruit_httpserver.methods`
====================================================
* Author(s): Michał Pokusa
"""


class HTTPMethod: # pylint: disable=too-few-public-methods
"""Enum with HTTP methods."""
GET = "GET"

GET = "GET"
"""GET method."""
POST = "POST"

POST = "POST"
"""POST method."""
PUT = "PUT"

PUT = "PUT"
"""PUT method"""
DELETE = "DELETE"

DELETE = "DELETE"
"""DELETE method"""
PATCH = "PATCH"

PATCH = "PATCH"
"""PATCH method"""
HEAD = "HEAD"

HEAD = "HEAD"
"""HEAD method"""
OPTIONS = "OPTIONS"

OPTIONS = "OPTIONS"
"""OPTIONS method"""
TRACE = "TRACE"

TRACE = "TRACE"
"""TRACE method"""

CONNECT = "CONNECT"
"""CONNECT method"""
CONNECT = "CONNECT"
100 changes: 0 additions & 100 deletions adafruit_httpserver/mime_type.py

This file was deleted.

Loading