Skip to content

FollowRedirect can't handle IDNA domains in Location headers #630

@CathalMullan

Description

@CathalMullan
  • I have looked for existing issues (including closed) about this

Related to seanmonstar/reqwest#2875

Bug Report

Version

tower-http v0.6.8

Platform

Not a platform specific issue.

Crates

tower-http (specifically the follow-redirect feature)

Description

The FollowRedirect middleware fails to follow redirects when the Location header contains:

  • IDNA (e.g. https://münchen.com)
  • Unicode characters in paths (e.g. /café)
use http::Uri;
use iri_string::types::{UriAbsoluteString, UriReferenceStr};

/// Try to resolve a URI reference `relative` against a base URI `base`.
fn resolve_uri(relative: &str, base: &Uri) -> Option<Uri> {
    let relative = UriReferenceStr::new(relative).ok()?;
    let base = UriAbsoluteString::try_from(base.to_string()).ok()?;
    let uri = relative.resolve_against(&base).to_string();
    Uri::try_from(uri).ok()
}

iri_string is strict with what characters it allows. It follows RFC 3986 closely, so expects everything to be pre-encoded.

The unicode path issue could be resolved by using iri_string::percent_encode::PercentEncodedForUri, but the IDNA issue would remain.

The simplest fix would be switching to using url internally instead of iri_string. Though I'm aware that might not be ideal since it's a heavier dependency.

use http::Uri;
use url::Url;

/// Try to resolve a URI reference `relative` against a base URI `base`.
fn resolve_uri(relative: &str, base: &Uri) -> Option<Uri> {
    let base = Url::parse(&base.to_string()).ok()?;
    let resolved = base.join(relative).ok()?;
    resolved.as_str().parse().ok()
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions