-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Uri.toString() for "mailto" does not encode spaces properly (
instead of
)
#43838
Comments
The Dart |
Same here. How to fix it? |
The lazy approach would be: print(uri.toString().replaceAll(" ", " ")); A more intricate approach could be: final uri = Uri.parse('mailto:[email protected]?subject='
'Example Subject & Symbols are allowed!'.replaceAll(" ", " "));
print(uri.toString()); or final uri = Uri(
scheme: 'mailto',
path: '[email protected]',
query:
'subject=Example Subject & Symbols are allowed!'.replaceAll(" ", " ")
);
print(uri.toString()); There currently is no way to use the (If we do a complete rewrite of the |
I'm personally constructing the final subject = Uri.encodeComponent("Example Subject & Symbols are allowed!")
final uri = "mailto:[email protected]?subject=$subject"; It seems to work fine. |
This is backwards though, as the generic form of URL encoding is percent encoding (click on your link there, then click on "URL encoding" in that text, which leads to https://en.wikipedia.org/wiki/Percent-encoding). The issue isn't that
The correct statement is that there is no way to configure
These suggestions are both incorrect, as they will not encode anything else. Notably in this case, the subject will just be "Example Subject ", because the unencoded
Perhaps an alternate constructor that does the right thing as an interim solution? This issue makes it very hard for people to correctly use the Or, alternately, switch on the scheme and keep the existing behavior for http/https, and do a breaking change for any others? While it is a breaking change, it's hard to imagine many scenarios where anyone would prefer the current behavior for other schemes. |
(Also, perhaps the encodeComponent docs could be updated in the short term; currently they say "For encoding the query part consider using encodeQueryComponent." which is actively misleading advice for any non-http URI. It could say "For encoding the query part of an HTTP or HTTPS URI, consider ...") |
The simplest safe solution I can see at this point to use Uri for anything that has query parameters but isn't an http* URL is to manually re-implement what
For |
https://url.spec.whatwg.org/ is the controlling standard here and it describes our current behaviour as invalid. Since we are not following the standard, we should fix our behaviour accordingly. |
Changing our behavior to match the whatwg spec was one of our plans for Dart 2.0, but it didn't pan out (we significantly over-estimated how much change we could do in the time available). See #29420 It's still a worthy goal, and would make web compilers save a lot of code, but also a highly breaking change to anyone using the existing It's going to be a big undertaking. The (Reducing the complexity was one of the reasons for rewriting |
Can you comment on the possiblity of doing one of the two small changes I suggested above (a new named constructor for non-web Uris, or a breaking change for the constructor just for non-web schemes)? I understand there are other issues that make a major rewrite desirable, but if we could avoid letting the perfect being the enemy of the good in fixing this particular issue in the short term it would make it feasible to use |
I don't see how making our behaviour less broken could be considered a breaking change. Could you elaborate on the flow that you're concerned would break? |
If we don't normalize on creation (and the whatwg spec doesn't), then people relying on creating two |
A new constructor which does only rudimentary normalization (and the /// Creates a URI with the given scheme and content.
///
/// The [scheme] must be a valid, non-empty scheme and
/// the [content] is everything which occurs
/// after the colon following the scheme.
///
/// If [scheme] is a *recognized scheme*,
/// one of `http`, `https`, `ws`, `wss`, `file` or `package`,
/// the URI is normalized as normal for `Uri.parse("$scheme:$content")`.
/// Otherwise the URI is assumed to be non-hierarchical and
/// the only normalization which happens is scheme normalization,
/// percent-escape normalization of existing escapes,
/// and percent-escaping of non-visible-ASCII characters of the content,
/// where non-ASCII characters are UTF-8 encoded first.
///
/// The entirety of the normalized content will be accessible as the [path]
/// of the created URI.
///
/// Example:
/// ```dart
/// var uri = Uri.raw("Unknown", "#!%
?/\xa0::\n[]");
/// print(uri.path); // #!%
?/ ::
[]
/// ```
factory Uri.raw(String scheme, String content) => ... That should cover |
I'm confused; I don't think this issue has anything to do with normalization. AFAICT it's purely a question of whether Consider this code: // Case a.
final parameters = <String, String>{
'subject': 'a & b',
'body': 'c & d',
};
var uri = Uri(
scheme: 'mailto',
path: '[email protected]',
queryParameters: parameters,
);
print(uri.toString());
// Case b.
uri = Uri(
scheme: 'mailto',
path: '[email protected]',
query: parameters.entries.map((e) => '${Uri.encodeQueryComponent(e.key)}=${Uri.encodeQueryComponent(e.value)}').join('&'),
);
print(uri.toString());
// Case c.
uri = Uri(
scheme: 'mailto',
path: '[email protected]',
query: parameters.entries.map((e) => '${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}').join('&'),
);
print(uri.toString()); It prints:
The first two (a and b) are identical (presumably the first is actually using I'm simply suggesting a new named constructor that is identical to the
That seems equivalent to |
To elaborate on the background here, as an illustration of the use case I'm trying to solve: the
To help users avoid these pitfalls, we added an example to the plugin README that demonstrates how to correctly (we thought; I didn't realize that My goal here is to have a similarly-high-level example code to replace that incorrect example. Given that the issue here is with Anything that involves the developer already having had to correctly construct a properly encoded |
I don't see why we need a new constructor. The current one is just behaving incorrectly. I could see an argument for accepting an optional named boolean parameter, which is basically what the standard does, that enables the |
That works for me as well. I'm just trying to find an option that doesn't involve waiting an indefinitely long time to rewrite everything, given that it sounds like changing behavior—even incorrect behavior—before that point is a non-starter. (I'm not saying I agree that we shouldn't just change the behavior to be right, just that if that's a non-negotiable, I would like some other option that can be implemented in the short term.) |
Changing broken behaviour should not be a non-starter. What we have today is a bug. We are corrupting user data. |
The The encoding of If that's not what users are expecting, then that is a usability problem, but it is not a bug. We can add a flag to the constructor to make it use percent normal encoding instead of In the longer run, we should do a full breaking change to become WHATWG URL compatible. It would help our JS compilers and probably confuse users less. (Again, I'd have preferred to do that at the Dart 2.0 release, but it didn't make the cut). |
RFC 3986 doesn't specify any sort of
The current behaviour is already broken. This isn't a situation where we are doing something valid but want to change to something else valid and we have to worry about compatibility. We are literally misencoding ASCII space and causing user data corruption as a result. It's just a bug. |
What's the next step here? E.g., is there a formal process for deciding whether to make the breaking change here? |
@lrhn Ping on this question? We're continuing to have users bitten by this issue, and I need to know if this is going to be fixed in Dart, or a workaround added to |
I guess the next step is either:
The breaking change can be either:
A non-breaking change could be:
The easiest to implement is just a clean break switching to new behavior. If you want So the next step is to decide which solution to go for, then we can file a breaking change request for that (if necessary, which is probably likely, the non-breaking approaches are not great). |
Any updates on this? having this problem with the url_launcher plugin |
Either of these options sounds good to me. Who are the other stakeholders who need to weigh in prior to making the breaking change request? |
Just as a side note, I created the |
Hi.
This ticket was first opened on
flutter
bug tracker: flutter/flutter#68406It seems
in
Uri.toString()
convert spaces tosubject
andbody
formailto
scheme.This seems to be a problem, when the link is opened with
url_launcher
for example then the subject displayed in the mail app is like this:For some reason, the app does not handle
symbols in the uri as expected. However, it works fine if
is used instead.
I tested this with
url_launcher
v5.7.5,flutter
v1.23.0,dart
v2.10.0, Android v8.0.0 and opening the link with Gmail app.Should the spaces be automatically converted to
instead to ensure portability?
The text was updated successfully, but these errors were encountered: