urequests.get() error related to getaddrinfo
Hello:
I just compiled MicroPython for RPI Pico with WIZNET5k support as described here: https://github.com/Wiznet/RP2040-HAT-MicroPython
Ethernet connects and works.
However urequests gives this error:
request = urequests.get('http://bipes.net.br/test.txt')
Traceback (most recent call last):
File "<stdin>", line 14, in <module>
File "urequests.py", line 116, in get
File "urequests.py", line 55, in request
TypeError: function takes 2 positional arguments but 4 were given
I checked urequests.py and the implementation is:
ai = usocket.getaddrinfo(host, port, 0, usocket.SOCK_STREAM)
If I change this line to
ai = usocket.getaddrinfo(host, port)
The problem is solved and urequests.get() works!
However, I am uncertain if this would cause other boards/implementations problems.
Can this fix be applied to urequests.py, or it could break other network implementations?
thanks
Fix `urequests.request` failing with `OSError: 97`
… when getaddrinfo returns addresses in unexpected order.
urequests.request incorrectly assumes that usocket.getaddrinfo always returns the addrinfo for IPv4/TCP as the first item and passes the address from this to socket.connect. This will fail with OSError: 97 if the the first item returned by getaddrinfo is actually a IPv6 address.
Example:
>>> import usocket
>>> import urequests
>>> [ai[:3] for ai in usocket.getaddrinfo('jsonplaceholder.typicode.com', 80)]
[
(10, 1, 6),
(10, 2, 17),
(10, 3, 0),
(10, 1, 6),
(10, 2, 17),
(10, 3, 0),
(2, 1, 6),
(2, 2, 17),
(2, 3, 0),
(2, 1, 6),
(2, 2, 17),
(2, 3, 0)
]
>>> urequests.get('http://jsonplaceholder.typicode.com/posts/1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/micropython/urequests.py", line 108, in get
File "/usr/lib/micropython/urequests.py", line 96, in request
File "/usr/lib/micropython/urequests.py", line 58, in request
OSError: 97
This PR fixes that by iterating over the tuple of addrinfos returned by getaddrinfo and picking the addr from the first one, where the first three items match (usocket.AF_INT, usocket.SOCK_STREAM, usocket.IPPROTO_TCP). If no matching address is found, OSError is raised (to be be consistent with what getaddrinfo raises).
Since usocket.IPPROTO_TCP is not available on every port, the module defines its own constant IPPROTO_TCP. It might be sufficient to check only the first two items of each addrinfo, though, and leave this out.
The error number and message of the OSError exception are only a (sensible) suggestion.
Signed-off-by: Christopher Arndt chris@chrisarndt.de
Yes, this issue needs to be solved, but solved by actually implementing more args to getaddrinfo() for all ports...
Until that time, it remains that
urequests.requesta) will fail unpredictably for reasons not under control of the user where it shouldn't and b) there's no proper way for the user to recover from the error. And thus makes it rather useless in practice.Do you have a suggestion how to fix this in better way until
usocket.getaddrinfois fixed everywhere?Some ideas:
micropython-socketand provide a better implementation ofgetaddrinfothere.urequestsbut fall back to two arguments, if aTypeErroris thrown.urequests, which checks whetherusocket.getaddrsupports a third (fourth, fifth) argumentOptions 2) and 3) would still leave
urequestsin a state of questionable usefulness on ports wheregetaddrinfoaccepts only two arguments.I'm not sure that's the proven case in the general, before it's fully understood why it happens to some users. This is definitely not the 1st report of that (though maybe the previous was from you too?). And you don't specify what system it happens on and any background info.
And anyway, why look for workarounds instead of working towards the proper fix?
That's EAFNOSUPPORT
And that's IPv6, SOCK_STREAM, IPPROTO_TCP.
So, the resolver returns IPv6 address as the first choice, then when it comes to connecting to it, the system says IPv6 is not supported. Seems like system (or resolver) misconfiguration to me.
urequests won't force IPv4 on its users - there's nothing wrong with connecting over IPv6, and indeed, IPv4 may be not even available.
Ok, now I get it: the actual error lies in the way the socket is created on line 56 of
urequests.py. The socket should be configured for the correct address family.I'll close this PR and hopefully come up with a better one.