Skip to content

Commit 8a4f5c4

Browse files
committed
Extracted multiple send calls logic into decorator
1 parent a545ca7 commit 8a4f5c4

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

adafruit_httpserver/exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def __init__(self, path: str) -> None:
3434
super().__init__(f"Backslash in path: {path}")
3535

3636

37-
class ResponseAlreadySentException(Exception):
37+
class ResponseAlreadySentError(Exception):
3838
"""
3939
Another ``HTTPResponse`` has already been sent. There can only be one per ``HTTPRequest``.
4040
"""

adafruit_httpserver/response.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"""
99

1010
try:
11-
from typing import Optional, Dict, Union, Tuple
11+
from typing import Optional, Dict, Union, Tuple, Callable
1212
from socket import socket
1313
from socketpool import SocketPool
1414
except ImportError:
@@ -21,14 +21,29 @@
2121
BackslashInPathError,
2222
FileNotExistsError,
2323
ParentDirectoryReferenceError,
24-
ResponseAlreadySentException,
24+
ResponseAlreadySentError,
2525
)
2626
from .mime_type import MIMEType
2727
from .request import HTTPRequest
2828
from .status import HTTPStatus, CommonHTTPStatus
2929
from .headers import HTTPHeaders
3030

3131

32+
def _prevent_multiple_send_calls(function: Callable):
33+
"""
34+
Decorator that prevents calling ``send`` or ``send_file`` more than once.
35+
"""
36+
37+
def wrapper(self: "HTTPResponse", *args, **kwargs):
38+
if self._response_already_sent: # pylint: disable=protected-access
39+
raise ResponseAlreadySentError
40+
41+
result = function(self, *args, **kwargs)
42+
return result
43+
44+
return wrapper
45+
46+
3247
class HTTPResponse:
3348
"""
3449
Response to a given `HTTPRequest`. Use in `HTTPServer.route` decorator functions.
@@ -79,8 +94,8 @@ def route_func(request):
7994
"""
8095
Defaults to ``text/plain`` if not set.
8196
82-
Can be explicitly provided in the constructor, in `send()` or
83-
implicitly determined from filename in `send_file()`.
97+
Can be explicitly provided in the constructor, in ``send()`` or
98+
implicitly determined from filename in ``send_file()``.
8499
85100
Common MIME types are defined in `adafruit_httpserver.mime_type.MIMEType`.
86101
"""
@@ -100,7 +115,7 @@ def __init__( # pylint: disable=too-many-arguments
100115
Sets `status`, ``headers`` and `http_version`
101116
and optionally default ``content_type``.
102117
103-
To send the response, call `send` or `send_file`.
118+
To send the response, call ``send`` or ``send_file``.
104119
For chunked response use
105120
``with HTTPRequest(request, content_type=..., chunked=True) as r:`` and `send_chunk`.
106121
"""
@@ -121,7 +136,7 @@ def _send_headers(
121136
) -> None:
122137
"""
123138
Sends headers.
124-
Implicitly called by `send` and `send_file` and in
139+
Implicitly called by ``send`` and ``send_file`` and in
125140
``with HTTPResponse(request, chunked=True) as response:`` context manager.
126141
"""
127142
headers = self.headers.copy()
@@ -147,6 +162,7 @@ def _send_headers(
147162
self.request.connection, response_message_header.encode("utf-8")
148163
)
149164

165+
@_prevent_multiple_send_calls
150166
def send(
151167
self,
152168
body: str = "",
@@ -158,8 +174,6 @@ def send(
158174
159175
Should be called **only once** per response.
160176
"""
161-
if self._response_already_sent:
162-
raise ResponseAlreadySentException
163177

164178
if getattr(body, "encode", None):
165179
encoded_response_message_body = body.encode("utf-8")
@@ -200,6 +214,7 @@ def _get_file_length(file_path: str) -> int:
200214
except OSError:
201215
raise FileNotExistsError(file_path) # pylint: disable=raise-missing-from
202216

217+
@_prevent_multiple_send_calls
203218
def send_file(
204219
self,
205220
filename: str = "index.html",
@@ -214,8 +229,6 @@ def send_file(
214229
215230
Should be called **only once** per response.
216231
"""
217-
if self._response_already_sent:
218-
raise ResponseAlreadySentException
219232

220233
if safe:
221234
self._check_file_path_is_valid(filename)

0 commit comments

Comments
 (0)