Skip to content

Commit 5de66fa

Browse files
authored
Merge pull request #22 from paul-1/my-main
Added Features.
2 parents 11ae0bc + 4768bbd commit 5de66fa

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

adafruit_httpserver/response.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class HTTPResponse:
2929
status: HTTPStatus
3030
headers: Dict[str, str]
3131
content_type: str
32-
32+
cache: Optional[int]
3333
filename: Optional[str]
3434
root_path: str
3535

@@ -41,6 +41,7 @@ def __init__( # pylint: disable=too-many-arguments
4141
body: str = "",
4242
headers: Dict[str, str] = None,
4343
content_type: str = MIMEType.TYPE_TXT,
44+
cache: Optional[int] = 0,
4445
filename: Optional[str] = None,
4546
root_path: str = "",
4647
http_version: str = "HTTP/1.1",
@@ -54,6 +55,7 @@ def __init__( # pylint: disable=too-many-arguments
5455
self.body = body
5556
self.headers = headers or {}
5657
self.content_type = content_type
58+
self.cache = cache
5759
self.filename = filename
5860
self.root_path = root_path
5961
self.http_version = http_version
@@ -64,8 +66,10 @@ def _construct_response_bytes( # pylint: disable=too-many-arguments
6466
status: HTTPStatus = CommonHTTPStatus.OK_200,
6567
content_type: str = MIMEType.TYPE_TXT,
6668
content_length: Union[int, None] = None,
69+
cache: int = 0,
6770
headers: Dict[str, str] = None,
6871
body: str = "",
72+
chunked: bool = False,
6973
) -> bytes:
7074
"""Constructs the response bytes from the given parameters."""
7175

@@ -75,12 +79,17 @@ def _construct_response_bytes( # pylint: disable=too-many-arguments
7579
response_headers = {} if headers is None else headers.copy()
7680

7781
response_headers.setdefault("Content-Type", content_type)
78-
response_headers.setdefault("Content-Length", content_length or len(body))
7982
response_headers.setdefault("Connection", "close")
83+
if chunked:
84+
response_headers.setdefault("Transfer-Encoding", "chunked")
85+
else:
86+
response_headers.setdefault("Content-Length", content_length or len(body))
8087

8188
for header, value in response_headers.items():
8289
response += f"{header}: {value}\r\n"
8390

91+
response += f"Cache-Control: max-age={cache}\r\n"
92+
8493
response += f"\r\n{body}"
8594

8695
return response.encode("utf-8")
@@ -116,6 +125,33 @@ def send(self, conn: Union["SocketPool.Socket", "socket.socket"]) -> None:
116125
body=self.body,
117126
)
118127

128+
def send_chunk_headers(
129+
self, conn: Union["SocketPool.Socket", "socket.socket"]
130+
) -> None:
131+
"""Send Headers for a chunked response over the given socket."""
132+
self._send_bytes(
133+
conn,
134+
self._construct_response_bytes(
135+
status=self.status,
136+
content_type=self.content_type,
137+
chunked=True,
138+
cache=self.cache,
139+
body="",
140+
),
141+
)
142+
143+
def send_body_chunk(
144+
self, conn: Union["SocketPool.Socket", "socket.socket"], chunk: str
145+
) -> None:
146+
"""Send chunk of data to the given socket. Send an empty("") chunk to finish the session.
147+
148+
:param Union["SocketPool.Socket", "socket.socket"] conn: Current connection.
149+
:param str chunk: String data to be sent.
150+
"""
151+
size = "%X\r\n".encode() % len(chunk)
152+
self._send_bytes(conn, size)
153+
self._send_bytes(conn, chunk.encode() + b"\r\n")
154+
119155
def _send_response( # pylint: disable=too-many-arguments
120156
self,
121157
conn: Union["SocketPool.Socket", "socket.socket"],
@@ -129,6 +165,7 @@ def _send_response( # pylint: disable=too-many-arguments
129165
self._construct_response_bytes(
130166
status=status,
131167
content_type=content_type,
168+
cache=self.cache,
132169
headers=headers,
133170
body=body,
134171
),
@@ -148,6 +185,7 @@ def _send_file_response( # pylint: disable=too-many-arguments
148185
status=self.status,
149186
content_type=MIMEType.from_file_name(filename),
150187
content_length=file_length,
188+
cache=self.cache,
151189
headers=headers,
152190
),
153191
)

adafruit_httpserver/server.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ def route_func(request):
5353
print("Received a request of length", len(raw_text), "bytes")
5454
return HTTPResponse(body="hello world")
5555
56+
57+
@server.route(path, method)
58+
def route_func(request, conn):
59+
raw_text = request.raw_request.decode("utf8")
60+
print("Received a request of length", len(raw_text), "bytes")
61+
res = HTTPResponse(content_type="text/html")
62+
res.send_chunk_headers(conn)
63+
res.send_body_chunk(conn, "Some content")
64+
res.send_body_chunk(conn, "Some more content")
65+
res.send_body_chunk(conn, "") # Send empty packet to finish chunked stream
66+
return None # Return None, so server knows that nothing else needs to be sent.
5667
"""
5768

5869
def route_decorator(func: Callable) -> Callable:
@@ -162,12 +173,18 @@ def poll(self):
162173

163174
# If a handler for route exists and is callable, call it.
164175
if handler is not None and callable(handler):
165-
response = handler(request)
176+
# Need to pass connection for chunked encoding to work.
177+
try:
178+
response = handler(request, conn)
179+
except TypeError:
180+
response = handler(request)
181+
if response is None:
182+
return
166183

167184
# If no handler exists and request method is GET, try to serve a file.
168185
elif request.method == HTTPMethod.GET:
169186
response = HTTPResponse(
170-
filename=request.path, root_path=self.root_path
187+
filename=request.path, root_path=self.root_path, cache=604800
171188
)
172189

173190
# If no handler exists and request method is not GET, return 400 Bad Request.

0 commit comments

Comments
 (0)