adafruit_httpserver
¶
Socket based HTTP Server for CircuitPython
Author(s): Dan Halbert, Michał Pokusa
Implementation Notes¶
Software and Dependencies:
Adafruit CircuitPython firmware for the supported boards: https://github.com/adafruit/circuitpython/releases
adafruit_httpserver.server
¶
Author(s): Dan Halbert, Michał Pokusa
- class adafruit_httpserver.server.Server(socket_source: _ISocketPool, root_path: str = None, *, debug: bool = False)¶
A basic socket-based HTTP server.
Create a server, and get it ready to run.
- Parameters:
socket – An object that is a source of sockets. This could be a
socketpool
in CircuitPython or thesocket
module in CPython.root_path (str) – Root directory to serve files from
debug (bool) – Enables debug messages useful during development
- add_routes(routes: List[Route]) None ¶
Add multiple routes at once.
- Parameters:
routes (List[Route]) – List of routes to add to the server
Example:
from separate_file import external_route1, external_route2 ... server.add_routes([ Route("/example", GET, route_func1, append_slash=True), Route("/example/<my_parameter>", GET, route_func2), Route("/example/..../something", [GET, POST], route_func3), external_route1, external_route2, ]}
- property headers: Headers¶
Headers to be sent with every response, without the need to specify them in each handler.
If a header is specified in both the handler and the server, the handler’s header will be used.
Example:
server = Server(pool, "/static") server.headers = { "X-Server": "Adafruit CircuitPython HTTP Server", "Access-Control-Allow-Origin": "*", }
- poll() str ¶
Call this method inside your main loop to get the server to check for new incoming client requests. When a request comes in, it will be handled by the handler function.
Returns str representing the result of the poll e.g.
NO_REQUEST
orREQUEST_HANDLED_RESPONSE_SENT
.
- property request_buffer_size: int¶
The maximum size of the incoming request buffer. If the default size isn’t adequate to handle your incoming data you can set this after creating the server instance.
Default size is 1024 bytes.
Example:
server = Server(pool, "/static") server.request_buffer_size = 2048 server.serve_forever(str(wifi.radio.ipv4_address))
- require_authentication(auths: List[Basic | Token | Bearer]) None ¶
Requires authentication for all routes and files in
root_path
. Any non-authenticated request will be rejected with a 401 status code.Example:
server = Server(pool, "/static") server.require_authentication([Basic("username", "password")])
- route(path: str, methods: str | Iterable[str] = GET, *, append_slash: bool = False) Callable ¶
Decorator used to add a route.
If request matches multiple routes, the first matched one added will be used.
- Parameters:
Example:
# Default method is GET @server.route("/example") def route_func(request): ... # It is necessary to specify other methods like POST, PUT, etc. @server.route("/example", POST) def route_func(request): ... # If you want to access URL with and without trailing slash, use append_slash=True @server.route("/example-with-slash", append_slash=True) # which is equivalent to @server.route("/example-with-slash") @server.route("/example-with-slash/") def route_func(request): ... # Multiple methods can be specified @server.route("/example", [GET, POST]) def route_func(request): ... # URL parameters can be specified @server.route("/example/<my_parameter>", GET) e.g. /example/123 def route_func(request, my_parameter): ... # It is possible to use wildcard that can match any number of path segments @server.route("/example/.../something", GET) # e.g. /example/123/something @server.route("/example/..../something", GET) # e.g. /example/123/456/something def route_func(request): ...
- serve_forever(host: str = '0.0.0.0', port: int = 5000, *, poll_interval: float = 0.1) None ¶
Wait for HTTP requests at the given host and port. Does not return. Ignores any exceptions raised by the handler function and continues to serve. Returns only when the server is stopped by calling
.stop()
.
- property socket_timeout: int¶
Timeout after which the socket will stop waiting for more incoming data.
Must be set to positive integer or float. Default is 1 second.
When exceeded, raises
OSError
witherrno.ETIMEDOUT
.Example:
server = Server(pool, "/static") server.socket_timeout = 3 server.serve_forever(str(wifi.radio.ipv4_address))
adafruit_httpserver.request
¶
Author(s): Dan Halbert, Michał Pokusa
- class adafruit_httpserver.request.File(filename: str, content_type: str, content: str | bytes)¶
Class representing a file uploaded via POST.
Examples:
file = request.form_data.files.get("uploaded_file") # File(filename="foo.txt", content_type="text/plain", size=14) file.content # "Hello, world!\n"
- class adafruit_httpserver.request.Files¶
Class for files uploaded via POST.
- property fields¶
Returns a list of field names.
- items()¶
Returns a list of (name, value) tuples.
- keys()¶
Returns a list of header names.
- values()¶
Returns a list of header values.
- class adafruit_httpserver.request.FormData(data: bytes, headers: Headers, *, debug: bool = False)¶
Class for parsing and storing form data from POST requests.
Supports
application/x-www-form-urlencoded
,multipart/form-data
andtext/plain
content types.Examples:
form_data = FormData(b"foo=bar&baz=qux&baz=quuz", "application/x-www-form-urlencoded") # or form_data = FormData(b"foo=bar\r\nbaz=qux\r\nbaz=quux", "text/plain") # FormData({"foo": ["bar"], "baz": ["qux", "quux"]}) form_data.get("foo") # "bar" form_data["foo"] # "bar" form_data.get("non-existent-key") # None form_data.get_list("baz") # ["qux", "quux"] "unknown-key" in form_data # False form_data.fields # ["foo", "baz"]
- property fields¶
Returns a list of field names.
- get(field_name: str, default: str | bytes = None, *, safe=True) str | bytes | None ¶
Get the value of a field.
- items()¶
Returns a list of (name, value) tuples.
- keys()¶
Returns a list of header names.
- values()¶
Returns a list of header values.
- class adafruit_httpserver.request.QueryParams(query_string: str)¶
Class for parsing and storing GET query parameters requests.
Examples:
query_params = QueryParams("foo=bar&baz=qux&baz=quux") # QueryParams({"foo": ["bar"], "baz": ["qux", "quux"]}) query_params.get("foo") # "bar" query_params["foo"] # "bar" query_params.get("non-existent-key") # None query_params.get_list("baz") # ["qux", "quux"] "unknown-key" in query_params # False query_params.fields # ["foo", "baz"]
- property fields¶
Returns a list of field names.
- items()¶
Returns a list of (name, value) tuples.
- keys()¶
Returns a list of header names.
- values()¶
Returns a list of header values.
- class adafruit_httpserver.request.Request(server: Server, connection: _ISocket, client_address: Tuple[str, int], raw_request: bytes = None)¶
Incoming request, constructed from raw incoming bytes. It is passed as first argument to all route handlers.
- client_address: Tuple[str, int]¶
Address and port bound to the socket on the other end of the connection.
Example:
request.client_address # ('192.168.137.1', 40684)
- connection: _ISocket¶
Socket object used to send and receive data on the connection.
- property cookies: Dict[str, str]¶
Cookies sent with the request.
Example:
request.headers["Cookie"] # "foo=bar; baz=qux; foo=quux" request.cookies # {"foo": "quux", "baz": "qux"}
- property form_data: FormData | None¶
POST data of the request.
Example:
# application/x-www-form-urlencoded request = Request(..., raw_request=b"""... foo=bar&baz=qux""" ) # or # multipart/form-data request = Request(..., raw_request=b"""... --boundary Content-Disposition: form-data; name="foo" bar --boundary Content-Disposition: form-data; name="baz" qux --boundary--""" ) # or # text/plain request = Request(..., raw_request=b"""... foo=bar baz=qux """ ) request.form_data # FormData({'foo': ['bar'], 'baz': ['qux']}) request.form_data["foo"] # "bar" request.form_data.get_list("baz") # ["qux"]
- json() dict | None ¶
Body of the request, as a JSON-decoded dictionary. Only available for POST, PUT, PATCH and DELETE requests.
- query_params: QueryParams¶
Query/GET parameters in the request.
Example:
request = Request(..., raw_request=b"GET /?foo=bar&baz=qux HTTP/1.1...") request.query_params # QueryParams({"foo": "bar"}) request.query_params["foo"] # "bar" request.query_params.get_list("baz") # ["qux"]
adafruit_httpserver.response
¶
Author(s): Dan Halbert, Michał Pokusa
- class adafruit_httpserver.response.ChunkedResponse(request: Request, body: Generator[str | bytes, Any, Any], *, status: Status | Tuple[int, str] = OK_200, headers: Headers | Dict[str, str] = None, cookies: Dict[str, str] = None, content_type: str = None)¶
Specialized version of
Response
class for sending data using chunked transfer encoding.Instead of requiring the whole content to be passed to the constructor, it expects a generator that yields chunks of data.
Example:
@server.route(path, method) def route_func(request: Request): def body(): yield "Some ch" yield "unked co" yield "ntent" return ChunkedResponse(request, body, content_type="text/plain")
- Parameters:
request (Request) – Request object
body (Generator) – Generator that yields chunks of data.
status (Status) – Status object or tuple with code and message.
headers (Headers) – Headers to be sent with the response.
cookies (Dict[str, str]) – Cookies to be sent with the response.
content_type (str) – Content type of the response.
- class adafruit_httpserver.response.FileResponse(request: Request, filename: str = 'index.html', root_path: str = None, *, status: Status | Tuple[int, str] = OK_200, headers: Headers | Dict[str, str] = None, cookies: Dict[str, str] = None, content_type: str = None, as_attachment: bool = False, download_filename: str = None, buffer_size: int = 1024, head_only: bool = False, safe: bool = True)¶
Specialized version of
Response
class for sending files.Instead of
body
it takesfilename
androot_path
arguments. It is also possible to send only headers withhead_only
argument or modifybuffer_size
.If browsers should download the file instead of displaying it, use
as_attachment
anddownload_filename
arguments.Example:
@server.route(path, method) def route_func(request: Request): return FileResponse(request, filename='index.html', root_path='/www')
- Parameters:
request (Request) – Request that this is a response to.
filename (str) – Name of the file to send.
root_path (str) – Path to the root directory from which to serve files. Defaults to server’s
root_path
.status (Status) – Status code and text. Defaults to
200 OK
.headers (Headers) – Headers to include in response.
cookies (Dict[str, str]) – Cookies to be sent with the response.
content_type (str) – Content type of response.
as_attachment (bool) – If
True
, the file will be sent as an attachment.download_filename (str) – Name of the file to send as an attachment.
buffer_size (int) – Size of the buffer used to send the file. Defaults to
1024
.head_only (bool) – If
True
, only headers will be sent. Defaults toFalse
.safe (bool) – If
True
, checks iffilename
is valid. Defaults toTrue
.
- class adafruit_httpserver.response.JSONResponse(request: Request, data: Dict[Any, Any], *, headers: Headers | Dict[str, str] = None, cookies: Dict[str, str] = None, status: Status | Tuple[int, str] = OK_200)¶
Specialized version of
Response
class for sending JSON data.Instead of requiring
body
to be passed to the constructor, it expectsdata
to be passed instead.Example:
@server.route(path, method) def route_func(request: Request): return JSONResponse(request, {"key": "value"})
- class adafruit_httpserver.response.Redirect(request: Request, url: str, *, permanent: bool = False, preserve_method: bool = False, status: Status | Tuple[int, str] = None, headers: Headers | Dict[str, str] = None, cookies: Dict[str, str] = None)¶
Specialized version of
Response
class for redirecting to another URL.Instead of requiring the body to be passed to the constructor, it expects a URL to redirect to.
Example:
@server.route(path, method) def route_func(request: Request): return Redirect(request, "https://www.example.com")
By default uses
permament
andpreserve_method
to determine thestatus
code to use, but if you prefer you can specify it directly.Note that
301 Moved Permanently
and302 Found
can change the method toGET
while307 Temporary Redirect
and308 Permanent Redirect
preserve the method.More information: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages
- Parameters:
request (Request) – Request that this is a response to.
url (str) – URL to redirect to.
permanent (bool) – Whether to use a permanent redirect or a temporary one.
preserve_method (bool) – Whether to preserve the method of the request.
status (Status) – Status object or tuple with code and message.
headers (Headers) – Headers to include in response.
cookies (Dict[str, str]) – Cookies to be sent with the response.
- class adafruit_httpserver.response.Response(request: Request, body: str | bytes = '', *, status: Status | Tuple[int, str] = OK_200, headers: Headers | Dict[str, str] = None, cookies: Dict[str, str] = None, content_type: str = None)¶
Response to a given
Request
. Use inServer.route
handler functions.Base class for all other response classes.
Example:
@server.route(path, method) def route_func(request: Request): return Response(request, body='Some content', content_type="text/plain")
- Parameters:
request (Request) – Request that this is a response to.
body (str) – Body of response. Defaults to empty string.
status (Status) – Status code and text. Defaults to 200 OK.
headers (Headers) – Headers to include in response. Defaults to empty dict.
cookies (Dict[str, str]) – Cookies to be sent with the response.
content_type (str) – Content type of response. Defaults to None.
- class adafruit_httpserver.response.SSEResponse(request: Request, headers: Headers | Dict[str, str] = None, cookies: Dict[str, str] = None)¶
Specialized version of
Response
class for sending Server-Sent Events.Allows one way communication with the client using a persistent connection.
Keep in mind, that in order to send events, the socket must be kept open. This means that you have to store the response object somewhere, so you can send events to it and close it later.
It is very important to close the connection manually, it will not be done automatically.
Example:
sse = None @server.route(path, method) def route_func(request: Request): # Store the response object somewhere in global scope global sse sse = SSEResponse(request) return sse ... # Later, when you want to send an event sse.send_event("Simple message") sse.send_event("Message", event="event_name", id=1, retry=5000) # Close the connection sse.close()
- Parameters:
- close()¶
Close the connection.
Always call this method when you are done sending events.
- class adafruit_httpserver.response.Websocket(request: Request, headers: Headers | Dict[str, str] = None, cookies: Dict[str, str] = None, buffer_size: int = 1024)¶
Specialized version of
Response
class for creating a websocket connection.Allows two way communication between the client and the server.
Keep in mind, that in order to send and receive messages, the socket must be kept open. This means that you have to store the response object somewhere, so you can send events to it and close it later.
It is very important to close the connection manually, it will not be done automatically.
Example:
ws = None @server.route(path, method) def route_func(request: Request): # Store the response object somewhere in global scope global ws ws = Websocket(request) return ws ... # Receive message from client message = ws.receive() # Later, when you want to send an event ws.send_message("Simple message") # Close the connection ws.close()
- Parameters:
- close()¶
Close the connection.
Always call this method when you are done sending events.
- receive(fail_silently: bool = False) str | bytes | None ¶
Receive a message from the client.
- Parameters:
fail_silently (bool) – If True, no error will be raised if the connection is closed.
adafruit_httpserver.headers
¶
Author(s): Michał Pokusa
- class adafruit_httpserver.headers.Headers(headers: str | Dict[str, str] = None)¶
A dict-like class for storing HTTP headers.
Allows access to headers using case insensitive names.
Does not implement all dict methods.
Examples:
headers = Headers("Content-Type: text/html\r\nContent-Length: 1024\r\n") # or headers = Headers({"Content-Type": "text/html", "Content-Length": "1024"}) len(headers) # 2 headers.setdefault("Access-Control-Allow-Origin", "*") headers["Access-Control-Allow-Origin"] # '*' headers["Content-Length"] # '1024' headers["content-type"] # 'text/html' headers["User-Agent"] # KeyError: User-Agent "CONTENT-TYPE" in headers # True
- add(field_name: str, value: str)¶
Adds a header with the given field name and value. Allows adding multiple headers with the same name.
- copy()¶
Returns a copy of the headers.
- property fields¶
Returns a list of field names.
- get(field_name: str, default: str = None) str | None ¶
Returns the value for the given header name, or default if not found.
- get_directive(name: str, default: str = None) str | None ¶
Returns the main value (directive) for the given header name, or default if not found.
Example:
headers = Headers({"Content-Type": "text/html; charset=utf-8"}) headers.get_directive("Content-Type") # 'text/html'
- get_parameter(name: str, parameter: str, default: str = None) str | None ¶
Returns the value of the given parameter for the given header name, or default if not found.
Example:
headers = Headers({"Content-Type": "text/html; charset=utf-8"}) headers.get_parameter("Content-Type", "charset") # 'utf-8'
- items()¶
Returns a list of (name, value) tuples.
- keys()¶
Returns a list of header names.
- setdefault(name: str, default: str = None)¶
Sets the value for the given header name if it does not exist.
- values()¶
Returns a list of header values.
adafruit_httpserver.status
¶
Author(s): Dan Halbert, Michał Pokusa
- class adafruit_httpserver.status.Status(code: int, text: str)¶
HTTP status code.
Define a status code.
adafruit_httpserver.mime_types
¶
Author(s): Michał Pokusa
- class adafruit_httpserver.mime_types.MIMETypes¶
Contains MIME types for common file extensions. Allows to set default type for unknown files, unregister unused types and register new ones using the
MIMETypes.configure()
.- DEFAULT = 'text/plain'¶
Default MIME type for unknown files. Can be changed using
MIMETypes.configure(default_to=...)
.
- classmethod configure(default_to: str = None, keep_for: List[str] = None, register: Dict[str, str] = None) None ¶
Allows to globally configure the MIME types.
It is recommended to always call this method before starting the
Server
. Unregistering unused MIME types will decrease overall memory usage.- Parameters:
Example:
MIMETypes.configure( default_to="text/plain", keep_for=[".jpg", ".mp4", ".txt"], register={".foo": "text/foo", ".bar": "text/bar", ".baz": "text/baz"}, )
adafruit_httpserver.exceptions
¶
Author(s): Michał Pokusa
- exception adafruit_httpserver.exceptions.AuthenticationError¶
Raised by
require_authentication
when theRequest
is not authorized.
- exception adafruit_httpserver.exceptions.BackslashInPathError(path: str)¶
Backslash
\
in path.Creates a new
BackslashInPathError
for thepath
.
- exception adafruit_httpserver.exceptions.FileNotExistsError(path: str)¶
Raised when a file does not exist.
Creates a new
FileNotExistsError
for the file atpath
.
- exception adafruit_httpserver.exceptions.InvalidPathError¶
Parent class for all path related errors.
- exception adafruit_httpserver.exceptions.ParentDirectoryReferenceError(path: str)¶
Path contains
..
, a reference to the parent directory.Creates a new
ParentDirectoryReferenceError
for thepath
.
- exception adafruit_httpserver.exceptions.ServerStoppedError¶
Raised when
.poll
is called on a stoppedServer
.
- exception adafruit_httpserver.exceptions.ServingFilesDisabledError¶
Raised when
root_path
is not set and there is no handler forrequest
.