Closed Bug 440620 Opened 16 years ago Closed 5 years ago

Implement navigator.isProtocolHandlerRegistered and navigator.isContentHandlerRegistered

Categories

(Core :: DOM: Core & HTML, enhancement)

enhancement
Not set
normal

Tracking

()

RESOLVED INVALID

People

(Reporter: mithgol, Unassigned)

References

(Blocks 1 open bug, )

Details

(Keywords: dev-doc-needed, Whiteboard: [tw-dom])

Attachments

(2 files)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9) Gecko/2008052906 Firefox/3.0
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9) Gecko/2008052906 Firefox/3.0

Any site may allow its user to launch registerProtocolHandler() from one of the site's pages in order for the site to handle non-standard URL schemes from now on. (A good example is http://fghi.pp.ru/ which handles FGHI protocols like area:// and fecho:// for Fidonet hyperlinks.) However, the site have no means to find out whether a protocol is registered, and thus the site cannot safely provide the user with non-standard hyperlinks even after registerProtocolHandler() was successful.

Reproducible: Always

Steps to Reproduce:
1. Visit http://fghi.pp.ru/?area://Ru.Blog.Mithgol/

2. Hover your over mouse over hyperlinks. Note they all start from http://fghi.pp.ru/?area://Ru.Blog.Mithgol/?msgid=

3. Visit http://fghi.pp.ru/handler.php and notice the message "Add FGHI GaNJa NeTWoRK Gate Area Protocol (fghi.pp.ru) as an application for area links?" above. Hit "Add application" button.

4. The message "Add FGHI GaNJa NeTWoRK Gate Fecho Protocol (fghi.pp.ru) as an application for fecho links?" above. Hit "Add application" button.

5. While you are at it, view the page's source. It has two JavaScript lines in it:
navigator.registerProtocolHandler("area", "http://fghi.pp.ru/?%s", "FGHI GaNJa NeTWoRK Gate Area Protocol");
navigator.registerProtocolHandler("fecho", "http://fghi.pp.ru/?%s", "FGHI GaNJa NeTWoRK Gate Fecho Protocol");

6. Go to address bar. Paste the following URL: area://Ru.Blog.Mithgol/ -- and hit "Enter".

7. The "Launch Application" window appears that suggests "FGHI GaNJa NeTWoRK Gate Fecho Protocol" as a handler. Notice a minor bug: Firefox 3.0RC2 does not allow "FGHI GaNJa NeTWoRK Gate Area Protocol" and "FGHI GaNJa NeTWoRK Gate Fecho Protocol" to coexist on the same "http://fghi.pp.ru/?%s" URL, even though they handle different URL schemes. You may report this bug in Bugzilla later by yourself if you wish; that's not the same problem I'm reporting here. Now choose "FGHI GaNJa NeTWoRK Gate Fecho Protocol" and hit OK.

8. You appear on the page http://fghi.pp.ru/?area%3A%2F%2FRu.Blog.Mithgol%2F and its URL is slightly more %-encoded but still equivalent to http://fghi.pp.ru/?area://Ru.Blog.Mithgol/ you visited in step 1 above.

9. Hover your over mouse over hyperlinks.
Actual Results:  
The hyperlinks' URLs all still start from http://fghi.pp.ru/?area://Ru.Blog.Mithgol/?msgid= (and not just area://Ru.Blog.Mithgol/?msgid=) because the site cannot know that you've registered a protocol handler.

Expected Results:  
The site should know that you've registered a protocol handler, otherwise the full power of registerProtocolHandler() cannot be achieved. For the above example, the reader (the user) may not encounter area:// hyperlinks and just right-click to choose "Copy Link Location" (right now the user still has to strip such links from the handler's part of the URL; some users won't care; it obviously makes URLs not so universal and encourages the users to "advertise" and "concretize" handler sites in the URLs shared between users instead of allowing the URL's receiver to use its own favourite handler site).

The HTML5 standard function registerProtocolHandler() should probably remain void as in standard, but Firefox could implement some boolean protocolRegistered("area"), with the only argument (protocol name), to check whether a protocol is registered.

See http://www.whatwg.org/specs/web-apps/current-work/#custom-handlers section 5.6.1.1 for the list of possible security implications. Take the following two thoughts into your consideration:

1) Firefox should prevent continous registration spamming, i.e. a site should not harm its reader (the user) even if the site decides to repeat registerProtocolHandler() until protocolRegistered() returns true. In steps 3 and 4 (see above) you could notice that Firefox already shows its notification one after another; that's probably enough.

2) A site should be prevented from being able to bargain for protocol registering, e.g. the scenario "in order to login for porn, register your mailto handler here and allow us to harvest your addressees for spam" should not be made possible. A mere checkbox ("I register evil.example.org as a handler for mailto links that appear on the pages of evil.example.org only.") should be enough for the site to see protocolRegistered() as true and even verify that a "mailto:example@evil.example.org" link, when clicked on the evil site, leads to the same site's handler page, but no other harm would occur.

P. S.  Yet another minor misfeature: in "Tools" menu, hit "Options" item, choose "Applications" category and remove "FGHI GaNJa NeTWoRK Gate Area Protocol". Notice that "area" URL scheme continues to be registered. For the purposes of the above suggested protocolRegistered(), it should not persist this way.
Summary: web sites have no means to know whether registerProtocolHandler was successful → web sites have no means to know whether registerProtocolHandler was successful (a boolean function named like protocolRegistered() is necessary)
Yet another thought to clarify: protocolRegistered("area") could return not just boolean true but a string "http://fghi.pp.ru/?%s". However, that would be likely to leak intranet structure (of handler pages) to the outworld, and would also encourage handler sites to use their own prefixes to non-standard URLs even when they could use such URLs directly (but that would direct a user to the rival handler site that the user prefers). That's an obvious Bad Thing, so I suggest only a boolean protocolRegistered() function here.
For the step 1 of the above reproducing steps to present the site fghi.pp.ru as slightly more obvious handler, you may split the step in two:

1a. Visit http://fghi.pp.ru/

1b. Paste the FGHI URL area://Ru.Blog.Mithgol/ in the address field (in the form on top of the page) and hit "Submit Query" button.

However, the form on http://fghi.pp.ru/ is POST and not GET, so it would not bring you to http://fghi.pp.ru/?area://Ru.Blog.Mithgol/ as in step 1 above (though the page after step 1b is exactly the same as http://fghi.pp.ru/?area://Ru.Blog.Mithgol/ was in step 1, the URL remains http://fghi.pp.ru/ after POST).
This sounds like the sort of thing that would want to be part of the standard, not just a Firefox-only feature.

> 2) A site should be prevented from being able to bargain for protocol
> registering, e.g. the scenario "in order to login for porn, register your
> mailto handler here and allow us to harvest your addressees for spam" should
> not be made possible. A mere checkbox ("I register evil.example.org as a
> handler for mailto links that appear on the pages of evil.example.org only.")
> should be enough for the site to see protocolRegistered() as true and even
> verify that a "mailto:example@evil.example.org" link, when clicked on the evil
> site, leads to the same site's handler page, but no other harm would occur.

While this attack scenario is plausible, I suspect the checkbox prevention strategy would make the UI confusing for many users.
Status: UNCONFIRMED → NEW
Ever confirmed: true
I don't really understand the use case here.
(In reply to comment #4)
> I don't really understand the use case here.

Ask smart questions then; I am willing to provide you with any necessary clarifications.

The use case in brief: the URL handler site should provide the user (i.e. its reader) with "pure" area://... hyperlinks instead of "handler" http://fghi.pp.ru/?area://... hyperlinks, if and after registerProtocolHandler() was successful. But the site cannot do that, because Firefox does not give any feedback to the site about whether the necessary non-standard URL scheme (protocol) was formerly registered by this site (or by any other site).

Does it make any sense now?

(In reply to comment #3)
> This sounds like the sort of thing that would want to be part of the standard,
> not just a Firefox-only feature.

Maybe; but WhatWG does not have any bugzillas in order for random remarks to suggest features in.

(In reply to comment #3)
> While this attack scenario is plausible, I suspect the checkbox prevention
> strategy would make the UI confusing for many users.

I could not imagine any better strategy, but yet I feel that without any such strategy the whole feature would become too dangerous to be suggested.
(In reply to comment #3)
> This sounds like the sort of thing that would want to be part of the standard,
> not just a Firefox-only feature.

I actually wrote to WhatWG about my suggestion and the reasons behind it:

http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2009-January/018101.html

As you may see, noone replied:

http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2009-January/thread.html

It looks like nobody cares.
Letting a site ask if a particular protocol is registered, let alone registered as being handled by a specific site, raises privacy and tracking concerns. Maybe it would be OK to answer if the handler is the same site that's asking, but that's fairly limited.

The site could, instead, have a preference for users to say which form they want their URLs in. "I have an area: handler" which might be the web-based handler installed by that site, or it could be a local installed handler or addon.

That preference could be stored as part of a logged-in user's server-side state, or it could be a client-side cookie.

I hope I'm not stepping on the module-owner's toes, but this looks like a WONTFIX unless/until the HTML5 spec requires us to do it.
Status: NEW → RESOLVED
Closed: 16 years ago
Resolution: --- → WONTFIX
+1 

I think this could be a critical missing feature for gaining adoption of registerProtocolHandler.

See localStorage contortions needed otherwise:
http://bit.ly/repo-the-web
I've implemented a Firefox extension to handle this kind of functionality as link attributes (though a function would be nice too): See Bug 539889 and https://addons.mozilla.org/en-US/firefox/addon/162154/
I see that there is an 'isProtocolHandlerRegistered' function in the HTML5 spec now. Chrome implements it. Another reason why this should be implemented is that, currently, if a page registers a protocol handler, the user gets the "Blagh App has already been added as a handler for blagh links" message on every subsequent visit.
We need to investigate implementation of the feature added to the HTML spec, indeed.
Status: RESOLVED → REOPENED
Component: File Handling → DOM: Core & HTML
Product: Firefox → Core
QA Contact: file.handling → general
Resolution: WONTFIX → ---
Summary: web sites have no means to know whether registerProtocolHandler was successful (a boolean function named like protocolRegistered() is necessary) → web sites have no means to know whether registerProtocolHandler was successful (implement navigator.isProtocolHandlerRegistered)
While you are implementing this, please take the two following issues into account:

https://github.com/jquery/standards/issues/10

https://github.com/jquery/standards/issues/12
Assignee: nobody → evilpies
Status: REOPENED → ASSIGNED
Attached patch protocol-handlerSplinter Review
No tests yet, sorry about that. WebContentConvert.js is a horrible mix of code that could be in C++ and crosses abstractions between platform and frontend. I tried not changing too much. The way error reporting is supposed to work is totally broken, raw strings are not going to cut it. It seems like the spec is quite clear on the error type nowadays, but it's unclear to me on how to implement that in JS.
Attachment #801072 - Flags: review?(dao)
Summary: web sites have no means to know whether registerProtocolHandler was successful (implement navigator.isProtocolHandlerRegistered) → Implement navigator.isProtocolHandlerRegistered and navigator.isContentHandlerRegistered
Attached patch C++ rewriteSplinter Review
I rewrote the permission checks in register*Handler in C++ for fun. Not sure if that is something you would be interested in.
(In reply to Tom Schuster [:evilpie] from comment #15)
> Created attachment 801146 [details] [diff] [review]
> C++ rewrite
> 
> I rewrote the permission checks in register*Handler in C++ for fun. Not sure
> if that is something you would be interested in.

Fine by me, but you should really ask a DOM peer about adding code there ;)
Comment on attachment 801146 [details] [diff] [review]
C++ rewrite

Boris, what do you think of this?
Attachment #801146 - Flags: feedback?(bzbarsky)
Attachment #801072 - Flags: review?(dao) → review?(bzbarsky)
I'd like to understand why we're rewriting in C++.  Why?
Flags: needinfo?(evilpies)
I would like to have a clear split between the frontend logic (showing the prompt etc.). This way we can also more easily make this work with e10s, because passing DOMWindows is really not that awesome. But this was mostly for fun, I will probably move this to an other bug. I actually have a real need for isProtocolHanlerRegistered, because I want irccloud to use that function to check if they are already registered, to avoid some awful prompting.
Flags: needinfo?(evilpies)
OK.  So I should only worry about the "protocol-handler" patch for now?
Yes, please.
Comment on attachment 801072 [details] [diff] [review]
protocol-handler

Not sure why you changed the order of RegisterProtocolHandler and RegisterContentHandler in Navigator.cpp.  Can you change it back, please?

>+++ b/browser/components/feeds/src/WebContentConverter.js
>+    // First, check to make sure this isn't already handled internally (we don't
>+    // want to let them take over, say "chrome").

Per spec, this should return "registered", right?  This part of the spec:

    The described handler is permanently blocked from being (re)registered.
    (Maybe the user marked the registration attempt as spam, or blocked the
    site for other reasons.) 

>+    // check if it is in the black list

Likewise.

>   function WCCR_checkAndGetURI(aURIString, aContentWindow)
>-      // not supposed to throw according to spec
>-      return; 
>+      throw NS_ERROR_DOM_SYNTAX_ERR;

Why this change?

>+  function WCCR_isProtocolHandlerRegistered(aProtocol, aURIString, aContentWindow) {
>+    try {
>+      this._checkProtocol(aProtocol, aURIString);
>+      uri = this._checkAndGetURI(aURIString, aContentWindow);
>+    } catch (ex) {
>+      return "declined";

So I think that should return "registered", per above....

Basically, it doesn't look like we can tell apart the "new" and "declined" cases very easily, right?

>+  function WCCR_isContentHandlerRegistered(aContentType, aURIString, aContentWindow) {
>+    let uri;
>+    try {
>+      uri = this._checkAndGetURI(aURIString, aContentWindow);
>+    } catch (ex) {
>+      return "declined";

Again, seems like it should be "registered" per spec.

>+    if (contentType != TYPE_MAYBE_FEED)
>+      return "declined";

And here.
Attachment #801072 - Flags: review?(bzbarsky) → review-
Comment on attachment 801146 [details] [diff] [review]
C++ rewrite

What's the benefit here?
Attachment #801146 - Flags: feedback?(bzbarsky)
(In reply to Boris Zbarsky [:bz] from comment #22)
> Comment on attachment 801072 [details] [diff] [review]
> protocol-handler
> 
> Not sure why you changed the order of RegisterProtocolHandler and
> RegisterContentHandler in Navigator.cpp.  Can you change it back, please?
> 
> >+++ b/browser/components/feeds/src/WebContentConverter.js
> >+    // First, check to make sure this isn't already handled internally (we don't
> >+    // want to let them take over, say "chrome").
> 
> Per spec, this should return "registered", right?  This part of the spec:
> 
>     The described handler is permanently blocked from being (re)registered.
>     (Maybe the user marked the registration attempt as spam, or blocked the
>     site for other reasons.) 
> 
I don't really understand why that is not under the conditions for "declined", but I can change it.

> >+    // check if it is in the black list
> 
> Likewise.
> 
> >   function WCCR_checkAndGetURI(aURIString, aContentWindow)
> >-      // not supposed to throw according to spec
> >-      return; 
> >+      throw NS_ERROR_DOM_SYNTAX_ERR;
> 
> Why this change?
I think this is covered by
"User agents must throw a SyntaxError exception if resolving the url argument relative to the entry script's base URL, is not successful.".
> 
> >+  function WCCR_isProtocolHandlerRegistered(aProtocol, aURIString, aContentWindow) {
> >+    try {
> >+      this._checkProtocol(aProtocol, aURIString);
> >+      uri = this._checkAndGetURI(aURIString, aContentWindow);
> >+    } catch (ex) {
> >+      return "declined";
> 
> So I think that should return "registered", per above....
> 
> Basically, it doesn't look like we can tell apart the "new" and "declined"
> cases very easily, right?
> 
You mean "registered" and "declined"? I think the main problem is that "registered" and "declined" have pretty confusing semantics.
> >+  function WCCR_isContentHandlerRegistered(aContentType, aURIString, aContentWindow) {
> >+    let uri;
> >+    try {
> >+      uri = this._checkAndGetURI(aURIString, aContentWindow);
> >+    } catch (ex) {
> >+      return "declined";
> 
> Again, seems like it should be "registered" per spec.
> 
> >+    if (contentType != TYPE_MAYBE_FEED)
> >+      return "declined";
> 
> And here.
From a pure logic perspective returning "registered" even when recommended by the spec seems super weird. Eg. this could lead to a confusion like this:
if (navigator.isContentHandlerRegistered("image/png", "/us?%s") {
  navigator . unregisterContentHandler("image/png", "/us?%s")
}
Because it would look like they registered for this mime type, but in reality it's impossible to register it.
Last if should have been:
if (navigator.isContentHandlerRegistered("image/png", "/us?%s") == "registered") { .. }
> I don't really understand why that is not under the conditions for "declined"

"declined" means "Tried to register before, user said no, but if you try again maybe they'll say yes".

"registered" means "there is no point in trying" (whether because it's already registered or because the attempt will be automatically denied anyway).

At least as the spec is currently written.  It's not clear to me that this is the right way to do it.  Worth raising a spec issue, perhaps.

> I think this is covered by

Indeed, thanks.

> You mean "registered" and "declined"?

No, I mean "new" and "declined": both are not registered, but could be; the only difference is whether an attempt to register has been made in the past.  And we don't keep track of that.
I am not really interested anymore after some other bug was fixed and I don't see bar for registerProtocolHandler anymore.
Assignee: evilpies → nobody
Status: ASSIGNED → NEW
I'm confused about what's caused you to lose interest. Can you explain a bit more?

Thanks!
So I also found this:

http://www.w3.org/html/wg/drafts/html/master/webappapis.html#dom-navigator-isprotocolhandlerregistered

I'm particularly interested in seeing navigator.isProtocolHandlerRegistered implemented to help improve the user experience of scenarios like that described here:

http://tantek.com/2014/084/b1/urls-people-focused-mobile-communication

In particular the ability to hide/show a link based on whether the protocol handler is registered for its URL or not. Or maybe link to an install http URL instead of the special comms URL if that comms URL is not registered.
Blocks: 1056860
Whiteboard: [tw-dom]
I’m also interested in this in the context of the geo: uri and favoring the user’s preferred map/navigation app over switching to a polyfill that uses a specific webapp/service.

This functionality was dropped from the specification due to the tracking abilities it would give. We won't consider this until there's a more viable design (at which point a new bug will be opened by the specification folks (perhaps also me)).

Status: NEW → RESOLVED
Closed: 16 years ago5 years ago
Resolution: --- → INVALID
You need to log in before you can comment on or make changes to this bug.