diff --git a/micropython/uaiohttpclient/manifest.py b/micropython/uaiohttpclient/manifest.py index 8b35e0a70..61b13c24d 100644 --- a/micropython/uaiohttpclient/manifest.py +++ b/micropython/uaiohttpclient/manifest.py @@ -1,4 +1,4 @@ -metadata(description="HTTP client module for MicroPython asyncio module", version="0.5.2") +metadata(description="HTTP client module for MicroPython asyncio module", version="0.5.3") # Originally written by Paul Sokolovsky. diff --git a/micropython/uaiohttpclient/test_uaiohttpclient.py b/micropython/uaiohttpclient/test_uaiohttpclient.py new file mode 100644 index 000000000..bd98bb93d --- /dev/null +++ b/micropython/uaiohttpclient/test_uaiohttpclient.py @@ -0,0 +1,108 @@ +import io +import sys + +_MP_STREAM_POLL = 3 +_SERVER_RESPONSE_200_OK = b"HTTP/1.1 200 OK\r\n\r\n" + + +class Socket(io.IOBase): + def __init__(self, read_data): + self._write_buffer = io.BytesIO() + self._read_buffer = io.BytesIO(read_data) + + def ioctl(self, cmd, arg): + if cmd == _MP_STREAM_POLL: + return arg + return -1 + + def setblocking(self, value): + pass + + def connect(self, address): + pass + + def write(self, buf): + self._write_buffer.write(buf) + return len(buf) + + def readline(self): + return self._read_buffer.readline() + + def read(self, size=-1): + return self._read_buffer.read(size) + + def readinto(self, buf): + return self._read_buffer.readinto(buf) + + def close(self): + pass + + +class socket: + AF_INET = 2 + SOCK_STREAM = 1 + IPPROTO_TCP = 6 + + @staticmethod + def _set_responses(r): + socket._responses = r + + @staticmethod + def getaddrinfo(host, port, af=0, type=0, flags=0): + return [(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", ("127.0.0.1", 80))] + + def socket(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP): + return Socket(socket._responses.pop(0)) + + +# Patch the socket module with a mock one for testing. +sys.modules["socket"] = socket + +# ruff: noqa: E402 +import asyncio +import uaiohttpclient +import unittest + + +class Test(unittest.TestCase): + async def do_request(self, url): + resp = await uaiohttpclient.request("GET", url) + body = await resp.read() + return resp, body + + def test_request(self): + BODY_DATA = b"body" + socket._set_responses([_SERVER_RESPONSE_200_OK + BODY_DATA]) + + resp, body = asyncio.run(self.do_request("http://example.com")) + request_data = resp.content.s._write_buffer.getvalue() + self.assertEqual( + request_data, + b"GET / HTTP/1.0\r\nHost: example.com\r\nConnection: close\r\nUser-Agent: compat\r\n\r\n", + ) + self.assertEqual(resp.status, 200) + self.assertEqual(resp.headers, []) + self.assertEqual(body, BODY_DATA) + + def test_redirect_absolute(self): + BODY_DATA = b"body" + socket._set_responses( + [ + b"HTTP/1.1 301 OK\r\nLocation: http://example.com/index\r\n\r\n", + _SERVER_RESPONSE_200_OK + BODY_DATA, + ] + ) + + resp, body = asyncio.run(self.do_request("http://example.com")) + request_data = resp.content.s._write_buffer.getvalue() + self.assertEqual( + request_data, + b"GET /index HTTP/1.0\r\nHost: example.com\r\nConnection: close\r\nUser-Agent: compat\r\n\r\n", + ) + self.assertEqual(resp.status, 200) + self.assertEqual(resp.headers, []) + self.assertEqual(body, BODY_DATA) + + +if __name__ == "__main__": + unittest.main() diff --git a/micropython/uaiohttpclient/uaiohttpclient.py b/micropython/uaiohttpclient/uaiohttpclient.py index 2e782638c..94777a893 100644 --- a/micropython/uaiohttpclient/uaiohttpclient.py +++ b/micropython/uaiohttpclient/uaiohttpclient.py @@ -65,7 +65,7 @@ async def request_raw(method, url): path, host, ) - await writer.awrite(query.encode("latin-1")) + await writer.awrite(query.encode("utf8")) return reader @@ -87,7 +87,7 @@ async def request(method, url): if b"chunked" in line: chunked = True elif line.startswith(b"Location:"): - url = line.rstrip().split(None, 1)[1].decode("latin-1") + url = line.rstrip().split(None, 1)[1].decode("utf8") if 301 <= status <= 303: redir_cnt += 1 diff --git a/tools/ci.sh b/tools/ci.sh index 4c56fb9c5..2fc6fe90c 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -92,6 +92,7 @@ function ci_package_tests_run { done for path in \ + micropython/uaiohttpclient \ micropython/ucontextlib \ python-stdlib/colorsys \ python-stdlib/contextlib \