Skip to content

Commit 469f0eb

Browse files
committed
Implemented processing 'Content-Length' header and limiting received bytes
1 parent 0d69a4c commit 469f0eb

File tree

1 file changed

+50
-16
lines changed

1 file changed

+50
-16
lines changed

adafruit_httpserver/server.py

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

1010
try:
11-
from typing import Callable, Protocol
11+
from typing import Callable, Protocol, Union
12+
from socket import socket
13+
from socketpool import SocketPool
1214
except ImportError:
1315
pass
1416

@@ -92,6 +94,40 @@ def start(self, host: str, port: int = 80, root_path: str = "") -> None:
9294
self._sock.listen(10)
9395
self._sock.setblocking(False) # non-blocking socket
9496

97+
def _receive_header_bytes(
98+
self, sock: Union["SocketPool.Socket", "socket.socket"]
99+
) -> bytes:
100+
"""Receive bytes until a empty line is received."""
101+
received_bytes = bytes()
102+
while b"\r\n\r\n" not in received_bytes:
103+
try:
104+
length = sock.recv_into(self._buffer, len(self._buffer))
105+
received_bytes += self._buffer[:length]
106+
except OSError as ex:
107+
if ex.errno == ETIMEDOUT:
108+
break
109+
except Exception as ex:
110+
raise ex
111+
return received_bytes
112+
113+
def _receive_body_bytes(
114+
self,
115+
sock: Union["SocketPool.Socket", "socket.socket"],
116+
received_body_bytes: bytes,
117+
content_length: int,
118+
) -> bytes:
119+
"""Receive bytes until the given content length is received."""
120+
while len(received_body_bytes) < content_length:
121+
try:
122+
length = sock.recv_into(self._buffer, len(self._buffer))
123+
received_body_bytes += self._buffer[:length]
124+
except OSError as ex:
125+
if ex.errno == ETIMEDOUT:
126+
break
127+
except Exception as ex:
128+
raise ex
129+
return received_body_bytes[:content_length]
130+
95131
def poll(self):
96132
"""
97133
Call this method inside your main event loop to get the server to
@@ -102,25 +138,23 @@ def poll(self):
102138
conn, _ = self._sock.accept()
103139
with conn:
104140
conn.settimeout(self._timeout)
105-
received_data = bytearray()
106-
107-
# Receiving data until timeout
108-
while "Receiving data":
109-
try:
110-
length = conn.recv_into(self._buffer, len(self._buffer))
111-
received_data += self._buffer[:length]
112-
except OSError as ex:
113-
if ex.errno == ETIMEDOUT:
114-
break
115-
except Exception as ex:
116-
raise ex
141+
142+
# Receiving data until empty line
143+
header_bytes = self._receive_header_bytes(conn)
117144

118145
# Return if no data received
119-
if not received_data:
146+
if not header_bytes:
120147
return
121148

122-
# Parsing received data
123-
request = HTTPRequest(raw_request=received_data)
149+
request = HTTPRequest(header_bytes)
150+
151+
content_length = int(request.headers.get("content-length", 0))
152+
received_body_bytes = request.body
153+
154+
# Receiving remaining body bytes
155+
request.body = self._receive_body_bytes(
156+
conn, received_body_bytes, content_length
157+
)
124158

125159
handler = self.route_handlers.get(
126160
_HTTPRoute(request.path, request.method), None

0 commit comments

Comments
 (0)