community icon indicating copy to clipboard operation
community copied to clipboard

`UrlRequest` decodes bytes response to string regardless of `decode` param

Open naomiven opened this issue 1 year ago • 0 comments

Software Versions

  • Python: 3.9.2
  • OS: "Debian GNU/Linux 11 (bullseye)" on Raspberry Pi 4
  • Kivy: 2.3.0
  • Kivy installation method: pip

Describe the bug

UrlRequest decodes the response in bytes to string regardless of what is passed in the decode parameter. Note my response header is application/octet-stream.

The issue could be in this line -> https://github.com/kivy/kivy/blob/aeb27bbbcfa2d118da95d42c89237cfc19c69c53/kivy/network/urlrequest.py#L341

Expected behavior The response should be in bytes.

To Reproduce

  1. Run a simple HTTP server on port 5001 (see example below)
  • send response as bytes in /test endpoint
  1. Call UrlRequest to POST to /test endpoint

Code and Logs and screenshots

Simple server

server.py:

from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer


class TestRequestHandler(BaseHTTPRequestHandler):
    protocol_version = 'HTTP/1.1'

    def _set_response(self, status_code: int, content_type: str, content_length: int):
        self.send_response(status_code)
        self.send_header('Content-Type', content_type)
        self.send_header('Content-Length', content_length)
        self.end_headers()

    def send(self, status_code: int, content_type: str, data):
        """Set response and send data"""
        self._set_response(
            status_code=status_code, content_type=content_type, content_length=len(data)
        )
        self.wfile.write(data)

    def do_POST(self):
        """Handle POST"""
        if self.path == '/test':
            self.send(status_code=200, content_type='application/octet-stream', data=bytes(True))


if __name__ == '__main__':
    print('Starting server...')
    with ThreadingHTTPServer(('localhost', 5001), TestRequestHandler) as server:
        server.serve_forever()

Calling requests with UrlRequest

urlrequest_test.py:

from kivy.clock import Clock
from kivy.network.urlrequest import UrlRequest


url = 'http://localhost:5001/test'

class Test:
    def __init__(self):
        self.req = None
        self.res = None
    def on_success(self, req, res):
        self.req = req
        self.res = res
    def call(self):
        UrlRequest(url=url, method='POST', on_success=self.on_success, decode=False)


test = Test()
test.call()

Clock.tick()
Clock.tick()

print(f'response data type: {type(test.res)}')
print(f'response headers: {test.req.resp_headers}')

Output

Run server

$ python3 server.py
Starting server...

In another terminal, run the UrlRequest call. Notice the data type of the response is str.

$ python3 urlrequest_test.py
[INFO   ] [Logger      ] Record log in /root/.kivy/logs/kivy_24-10-09_16.txt
[INFO   ] [Kivy        ] v2.3.0
[INFO   ] [Kivy        ] Installed at "/var/dev/osensa-dashboard/venv/lib/python3.9/site-packages/kivy/__init__.py"
[INFO   ] [Python      ] v3.9.2 (default, Feb 28 2021, 17:03:44)
[GCC 10.2.1 20210110]
[INFO   ] [Python      ] Interpreter at "/var/dev/osensa-dashboard/venv/bin/python3"
[INFO   ] [Logger      ] Purge log fired. Processing...
[INFO   ] [Logger      ] Purge finished!
response data type: <class 'str'>
response headers: {'Server': 'BaseHTTP/0.6 Python/3.9.2', 'Date': 'Wed, 09 Oct 2024 20:58:46 GMT', 'Content-Type': 'application/octet-stream', 'Content-Length': '1', 'Set-Cookie': ''}

Additional context

When using the requests lib, the response is in bytes, which is correct.

req.py:

import requests

r = requests.post('http://localhost:5001/test')

print(f'response: {r.content}')
print(f'response data type: {type(r.content)}')
$ python req.py
response: b'\x00'
response data type: <class 'bytes'>

naomiven avatar Oct 09 '24 21:10 naomiven