micropython-lib icon indicating copy to clipboard operation
micropython-lib copied to clipboard

urequests.get ignores content-length header

Open GM-Script-Writer-62850 opened this issue 3 years ago • 5 comments

When connecting a server running this php sample

<?php
set_time_limit(0);
ob_start();
header('Content-type: text/plain');
header("Content-Encoding: none");
echo "OK";
header('Content-Length: '.ob_get_length());
header('Connection: close');
ob_end_flush();
@ob_flush();
flush();
if(session_id()) session_write_close();
sleep(10);
die("Client should never see this");
?>

if you view this page in a web browser or in curl you will only get OK, however urequests.get ignores the content length and waits for sleep to finish and get the die message before returning content, urequests.head has the same issue except you can't get the status_code

i managed to fix this, but my fix does nothing when i import it even though it works if i copy/paste the library inside my script this was how i fixed it

    @property
    def content(self):
        if self._cached is None:
            try:
                if(self.headers["Content-Length"]):
                    self._cached = self.raw.read(int(self.headers["Content-Length"]))
                else:
                    self._cached = self.raw.read()
            finally:
                self.raw.close()
                self.raw = None
        return self._cached

GM-Script-Writer-62850 avatar Oct 09 '22 20:10 GM-Script-Writer-62850

I think this probably makes sense to fix!

i managed to fix this, but my fix does nothing when i import it even though it works if i copy/paste the library inside my script this was how i fixed it

How are you copying your fixed script to the device. Which directory are you putting it in. Note that sys.path by default is ["", ".frozen", "/lib"] so if you put it in "/lib" the frozen copy will take precedence. Place the file in the root directory instead (alongside your main.py if you want it to override the frozen one).

jimmo avatar Oct 10 '22 00:10 jimmo

i was putting it in /lib/urequests.py i got it to work by using /lib/urequest.py

i guess urequests in included on the stock pico firmware, thought it was not but i must have made a typo in the lib name when i tried to import it the 1st time

Now i can just use import urequest as urequests or just use import urequest instead of import urequests as urequest

it took deleting /lib/urequests.py for me to figure out what was going on

GM-Script-Writer-62850 avatar Oct 10 '22 00:10 GM-Script-Writer-62850

The problem arises for me with a service that sends a payload without a final newline. But I couldn't use the workaround. I ended up using a terrible hack where I read(1) until I notice the ending } in the payload.

bmidgley avatar Jan 30 '23 08:01 bmidgley

Is this still a problem in the latest versions of requests library?

jonnor avatar Aug 25 '24 10:08 jonnor

Yes this is present in MicroPython v1.24.0-preview.224.g6c3dc0c0b on 2024-08-22; Raspberry Pi Pico W with RP2040 PICO W Test Code:

#!/usr/bin/python3
import requests as urequest
import uasyncio
sleep=uasyncio.sleep
sleep_ms=uasyncio.sleep_ms

class GPIO:
	wlan=None

async def wifi():
	from wifi_auth import ssid, password
	import network

	GPIO.wlan = network.WLAN(network.STA_IF)
	wlan = GPIO.wlan
	wlan.active(True)
	#wlan.config(pm = 0xa11140)# Power management is very very bad, ping time is around 1000x worse and packet loss insane
	wlan.connect(ssid, password)

	while True:
		while True:
			wstat=wlan.status()
			if wstat < 0 or wstat >= 3:
				break
			print('Waiting for WiFi connection...')
			await sleep(1)

		if wlan.status() == 3:
			status = wlan.ifconfig()
			print('Wifi Connected; ip =',status[0])
			while wlan.isconnected():
				await sleep(30)
			print('WiFi Down')
		else:
			print("Failed to connect to wifi; retry in 30 seconds")
			await sleep(30)
		wlan.connect(ssid, password)

async def wait4wifi():
	uasyncio.create_task(wifi())
	while GPIO.wlan is None:
		await sleep(1)
	while not GPIO.wlan.isconnected():
		await sleep(1)
	print('wifi up')

uasyncio.run(wait4wifi())
print("ifconfig:",GPIO.wlan.ifconfig())
print("status:",GPIO.wlan.status())

r=urequest.get("http://10.0.0.69:8080/die.php")
print(r.status_code)
print(r.content)
print(r.text)
r.close()

Ouput:

Wifi Connected; ip = 10.0.0.190
wifi up
ifconfig: ('10.0.0.190', '255.255.255.0', '10.0.0.1', '10.0.0.1')
status: 3
200
b'OKClient should never see this'
OKClient should never see this

EDIT: Note that aiohttp does not have this issue

GM-Script-Writer-62850 avatar Aug 25 '24 14:08 GM-Script-Writer-62850