Skip to content

Uri does not encode (or double-encodes) non-URL safe base64 path segments. #57015

@diegotori

Description

@diegotori

When attempting to create a Uri with a base64 encoded path segment value that is NOT URL safe (i.e containing illegal characters), it does not encode it (or double-encodes it when encoding it prior to creating the instance), when either creating a URI from scratch, or when replacing an existing one.

In other words, when encoding the base64 value using Uri.encodeComponent and creating the Uri using Uri.parse, it properly converts the unsafe == into properly encoded %3D%3D characters.

However, when creating the Uri either from its constructor, or when calling replace on an existing one, when placing an unencoded base64 value as a path segment, it returns == when calling toString on the resulting instance. Furthermore, when encoding the value using Uri.encodeComponent and placing it as a path segment, it double-encodes the already encoded %3D%3D value to %253D%253D instead.

Here is code that highlights this issue:

void main() {
  final baseUri = Uri(
    scheme: "https",
    host: "www.something.com",
    pathSegments: ["share"],
  );

  // Given an unsafe base64 URL value
  const unsafeBase64UrlValue = "c29tZSB2YWx1ZQ==";
  
  // When encoding it for use in a URL.
  final encoded = Uri.encodeComponent(unsafeBase64UrlValue);

  // Properly retains the parsed URL's encoded path segments.
  final properlyEncoded =
      Uri.parse("https://www.something.com/share/$encoded").replace(
    queryParameters: {
      "foo": "bar",
    },
  );
  print("Properly encoded base64 path URI: ${properlyEncoded.toString()}");

  // Does not encode the unsafe base64 path segment
  final unencodedBase64PathUri = baseUri.replace(
    pathSegments: [
      "share",
      unsafeBase64UrlValue,
    ],
    queryParameters: {
      "foo": "bar",
    },
  );
  print("Unencoded base64 path URI: ${unencodedBase64PathUri.toString()}");

  // Double encodes the encoded base64 path segment
  final doubleEncodedBase64PathUri = baseUri.replace(
    pathSegments: [
      "share",
      encoded,
    ],
    queryParameters: {
      "foo": "bar",
    },
  );
  print(
      "Double encoded base64 path URI: ${doubleEncodedBase64PathUri.toString()}");
}

Also available as a DartPad.

Currently running the following Dart version on macOS 14.5:

Dart SDK version: 3.5.3 (stable) (Wed Sep 11 16:22:47 2024 +0000) on "macos_arm64"

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-core-librarySDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries.library-coretype-documentationA request to add or improve documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions