Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uaiohttpclient: Implement parsing and handling HTTP auth URLs #867

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions micropython/uaiohttpclient/uaiohttpclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,28 @@ async def request_raw(method, url):
proto, dummy, host = url.split("/", 2)
path = ""

# Although we use HTTP protocol version 1.0, we still explicitly
# set the header "Connection: close", even though this should be
# default for 1.0, but some servers misbehave w/o it.
hdrs = {'Connection': "close", 'User-Agent': "compat"}
if "@" in host:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this "@" notation to specify the auth standard/used elsewhere?

An alternative would be to pass the auth info as a separate argument to this function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I'm getting this right, but the de-facto indication of whether HTTP Basic Auth is about to be used, is, adding (at least) a username in form of http://USERNAME@HOST:PORT/PATH.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that was my question, whether http://USERNAME@HOST:PORT/PATH is the standard way to add a username/password.

This format is specified in the RFC for URLs: https://datatracker.ietf.org/doc/html/rfc1738

So, let's keep this as you have it.

# split off potential login creds from host
auth, host = host.split("@", 1)
from binascii import b2a_base64
#usr, pwd = auth.split(":", 1)
hdrs['Authorization'] = "Basic " + b2a_base64(auth).decode()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use str(..., "utf-8") instead of .decode().


if ":" in host:
host, port = host.split(":")
host, port = host.rsplit(":", 1)
port = int(port)
else:
port = 80

if proto != "http:":
raise ValueError("Unsupported protocol: " + proto)
reader, writer = await asyncio.open_connection(host, port)
# Use protocol 1.0, because 1.1 always allows to use chunked
# transfer-encoding But explicitly set Connection: close, even
# though this should be default for 1.0, because some servers
# misbehave w/o it.
query = "%s /%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\nUser-Agent: compat\r\n\r\n" % (
method,
path,
host,
)
# Use protocol 1.0, because 1.1 always allows to use chunked transfer-encoding
query = "%s /%s HTTP/1.0\r\nHost: %s\r\n%s\r\n\r\n" % (method, path, host, "\r\n".join("%s: %s" % (k,v) for k,v in hdrs.items()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating a very long string here, I suggest writing out the headers one-by-one, eg:

await write.awrite(bytes(query, "utf-8"))
for k in hdrs:
    await writer.awrite(k)
    await writer.awrite(b": ")
    await writer.awrite(hdrs[k])
    await writer.awrite(b"\r\n")

await writer.awrite(query.encode("latin-1"))
return reader

Expand Down
Loading