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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions