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

Conversation

mirko
Copy link

@mirko mirko commented May 29, 2024

Allows HTTP Basic Auth URLs being passed, parsed and handled correctly to authorise against a server expecting that.
This is a simplification, completely ignoring if the server supports or asks for HTTP Basic Auth. We simply format and set the header if the URL indicates so.

This also fixes parsing URLs containing a colon (':') /not/ indicating a custom port (but e.g. the seperation between user and password as part of the HTTP Basic Auth credentials).

Previously, the lib died ungracefully when parsing an URL containing HTTP Basic Auth credentials, as it was always expecting at most only one colon (':') and also the part coming afterwards being neccesarily a number (port).

Allows HTTP Basic Auth URLs being passed, parsed and handled correctly
to authorise against a server expecting that.
This is a simplification, completely ignoring if the server supports or
asks for HTTP Basic Auth. We simply format and set the header if
the URL indicates so.

This also fixes parsing URLs containing a colon (':') /not/ indicating
a custom port (but e.g. the seperation between user and password as part
of the HTTP Basic Auth credentials).

Previously, the lib died ungracefully when parsing an URL containing
HTTP Basic Auth credentials, as it was always expecting at most only one
colon (':') and also the part coming afterwards being neccesarily a
number (port).
@dpgeorge
Copy link
Member

Thanks for the contribution.

This package is actually quite outdated now. It still works but there's a much newer python-ecosys/aiohttp package which has a lot more features than this one (although not basic auth yet...).

Do you have a particular reason to use uaiohttpclient?

If we continue to maintain this package then it should offer something different to python-ecosys/aiohttp. For example this one should be much more light weight.

@mirko
Copy link
Author

mirko commented Jun 12, 2024

I just picked the first async HTTP client lib I found, verified it working, embedding it into my project - and found out (way too late), it lacks HTTP auth. And instead of searching around and trying out other libs with each havingtheir own quirks and uasynciohttpclient basically working for me. I just hacked it in and created this PR.

@dpgeorge
Copy link
Member

OK, thanks for the explanation.

I'm happy to accept the changes in this PR, but will make some more specific comments about them.

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().

# 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.

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")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants