Double-digit link-local IPv6 zone id raises ValueError
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 54.3k
- Forks
- 10.4k
- Avg merge
- 16h 43m
- Merged PRs (30d)
- 3
Description
When making a request to a link-local IPv6 address, it becomes necessary to specify the "zone id" aka "scope id". RFC 6874 specifies zone ids as follows:
According to IPv6 Scoped Address syntax [RFC4007], a zone identifier
is attached to the textual representation of an IPv6 address by
concatenating "%" followed by <zone_id>, where <zone_id> is a string
identifying the zone of the address. However, the IPv6 Scoped
Address Architecture specification gives no precise definition of the
character set allowed in <zone_id>. There are no rules or de facto
standards for this. For example, the first Ethernet interface in a
host might be called %0, %1, %en1, %eth0, or whatever the implementer
happened to choose.In a URI, a literal IPv6 address is always embedded between "[" and
"]". This document specifies how a <zone_id> can be appended to the
address. According to URI syntax [RFC3986], "%" is always treated as
an escape character in a URI, so, according to the established URI
syntax [RFC3986] any occurrences of literal "%" symbols in a URI MUST
be percent-encoded and represented in the form "%25". Thus, the
scoped address fe80::a%en1 would appear in a URI as
http://[fe80::a%25en1].
I understand the above to mean that the "zone id" can be multiple characters (even when it's an integer.)
When using requests.get to request information from IoT devices using link-local networking, I occasionally see double-digit integer zone ids. An example of such a scoped address is fe80::be0f:a7ff:fe00:2929%53. As such, I'm escaping the % as %25 as indicated in the RFC. (In this case, this has no effect on the results.)
Expected Result
This does not throw.
import requests
host = 'fe80::be0f:a7ff:fe00:2929%2553'
url = f'http://[{host}]'
requests.get(url)
Actual Result
It throws:
ValueError: 'fe80::be0f:a7ff:fe00:2929S' does not appear to be an IPv4 or IPv6 address
Some debugging reveals that urllib3.util.parse_url replaces %25 with % in its result.
Reproduction Steps
- Run the code in the expected result section.
System Information
$ python -m requests.help
{
"chardet": {
"version": "5.2.0"
},
"charset_normalizer": {
"version": "3.3.2"
},
"cryptography": {
"version": ""
},
"idna": {
"version": "3.7"
},
"implementation": {
"name": "CPython",
"version": "3.12.3"
},
"platform": {
"release": "6.8.0-40-generic",
"system": "Linux"
},
"pyOpenSSL": {
"openssl_version": "",
"version": null
},
"requests": {
"version": "2.32.3"
},
"system_ssl": {
"version": "30000020"
},
"urllib3": {
"version": "2.2.2"
},
"using_charset_normalizer": false,
"using_pyopenssl": false
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the reproduction with requests.get and tracing the host through urllib3.util.parse_url, which the report identifies as replacing %25 with %. Done means a double-digit IPv6 zone id such as %2553 no longer raises ValueError when requesting the link-local URL; add or update coverage for this case if the existing test location is found.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100