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

Add support for zone identifiers #26

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

chrysn
Copy link
Contributor

@chrysn chrysn commented Oct 11, 2022

Closes: #6

This is based on #25, please only consider the top commit. (But I'm using that PR in testing already; sadly there seems to be no way to tell GitHub that it's dependent on that PR). If #25 does get rejected, I can rebase it to get rid of those changes -- otherwise I think it's best to merge after it, and then things would be easy.

The implementation already follows https://datatracker.ietf.org/doc/draft-ietf-6man-rfc6874bis/ (the upcoming revision of RFC6874) in that it doesn't do any percent encoding of the percent sign.

As zone identifiers are necessarily non-empty, a URI with an IPv6 address without zone identifier is represented by an empty string as a zone identifier.

Testing

$ cargo run --example cli -- 'coap://[fe80::1%eth0]/'
<coap://[fe80::1%eth0]/>: Ok(
    URIReference {
        authority: Some(
            Authority {
                host: IPv6Address(
                    fe80::1,
                    "eth0",
                ),
                password: None,
                port: None,
                username: None,
            },
        ),
        fragment: None,
        path: Path {
            absolute: true,
            double_dot_segment_count: 0,
            leading_double_dot_segment_count: 0,
            segments: [
                Segment {
                    normalized: true,
                    segment: "",
                },
            ],
            single_dot_segment_count: 0,
            unnormalized_count: 0,
        },
        query: None,
        scheme: Some(
            CoAP,
        ),
    },
)

API

Given that the enum Host variants are exhaustive, this is an API breaking change -- and I don't see how it could be made non-breaking.

Copy link
Owner

@sgodwincs sgodwincs left a comment

Choose a reason for hiding this comment

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

Thanks for the PR.

One other thing is that the types in this library generally keep track of whether they are normalized, but I'm not sure what it means for a zone ID to be normalized. It also doesn't specify whether it's case sensitive.

src/authority.rs Outdated
@@ -773,7 +773,7 @@ pub enum Host<'host> {
IPv4Address(Ipv4Addr),

/// An IPv6 address. This will always be encased in brackets (`'['` and `']'`).
IPv6Address(Ipv6Addr),
IPv6Address(Ipv6Addr, Cow<'host, str>),
Copy link
Owner

Choose a reason for hiding this comment

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

Since the RFC says that a zone ID must be at least one character, I think it makes more sense to wrap this in an Option.

src/authority.rs Outdated
@@ -773,7 +773,7 @@ pub enum Host<'host> {
IPv4Address(Ipv4Addr),

/// An IPv6 address. This will always be encased in brackets (`'['` and `']'`).
IPv6Address(Ipv6Addr),
IPv6Address(Ipv6Addr, Cow<'host, str>),
Copy link
Owner

Choose a reason for hiding this comment

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

I generally prefer using strong types rather than strings (as you can see by the library having Port, Username, Password, etc. types). I'd prefer if this was a new ZoneID type.

src/authority.rs Outdated

if !check_ipv6(ipv6) {
if !check_ipv6(ipv6) || !check_zone(zone) {
Copy link
Owner

Choose a reason for hiding this comment

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

I think it'd be better if this condition was done separately from check_ipv6 and a different error type was returned, something like InvalidIPv6ZoneIDCharacter

@chrysn
Copy link
Contributor Author

chrysn commented Oct 11, 2022 via email

Use dedicated type for ZoneID
Use dedicated error type for invalid zone characters
Use Option<non-empty-zone> instead of plain possibly-empty-zone
@chrysn
Copy link
Contributor Author

chrysn commented Oct 11, 2022

I think the update addresses all your points.

I've isolated some creation and error logic into a private ::new() function that IMO looks prettier and has its unsafe part easier to match to the check that was done. This also showed that there is an error case I previously missed ([fe80::1%] would have been silently accepted in the place of [fe80::1] even though the former is invalid syntactically); I've grouped that with the InvalidZoneCharacter, but if you prefer, it's easy to split InvalidZoneCharacter from InvalidZoneEmpty.

If you're happy with the changes I'd smush them into a single commit.

formatter.write_char('[')?;
address.fmt(formatter)?;
if let Some(zone) = zone {
formatter.write_char('%')?;
formatter.write_str(zone.as_str())?;
Copy link
Owner

Choose a reason for hiding this comment

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

Can you implement Display for zone ID and do zone.fmt(formatter)? instead

}

impl ZoneID<'_> {
fn new<'a>(value: Option<&'a [u8]>) -> Result<Option<ZoneID<'a>>, HostError> {
Copy link
Owner

Choose a reason for hiding this comment

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

Following other types in this library, can you move this to a TryFrom<&[u8]> implementation

/// characters.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ZoneID<'zone> {
Copy link
Owner

Choose a reason for hiding this comment

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

It's a bit tedious, but can you impl all the traits other types do in this library? For example, just go through fragment and implement stuff like AsRef, Deref, PartialEq with strings, etc.

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.

Add support for RFC6874
2 participants