Skip to content
This repository has been archived by the owner on Nov 5, 2022. It is now read-only.

Expand on why registerProtocolHandler and registerProtocolHandler are a hack #21

Closed
domenic opened this issue Apr 8, 2016 · 2 comments

Comments

@domenic
Copy link

domenic commented Apr 8, 2016

The explainer says:

registerProtocolHandler and registerContentHandler: Can be used for this purpose, but it's a hack. We'd rather design an API that properly solves these use cases.

As someone new to this design and problem space, they seem perfect to me. All we need is to do some kind of push (standardization, marketing, who knows) for standardizing a few protocols, e.g. "share". You could bootstrap the ecosystem, even, by "pre-registering" all the native apps that are set up to intercept certain "intent://" URLs.

It seems like the main new feature here is the ability to use a service worker to respond in the background. But that could be achieved through extensions to register(Protocol|Content)Handler, presumably.

To be clear, I'm not trying to derail this proposal; if it has implementer interest, that's great. I just think it would be helpful for people reading through it to give a more in-depth explanation of why working with, or at least integrating with, the existing primitives of the web platform is not good enough.

@mgiuca
Copy link
Contributor

mgiuca commented May 25, 2016

Hi Domenic,

Sorry I didn't get back to you on this for a long time. I'd like to update my documentation to explain this in a bit more detail but I'll explain here for now, and leave this bug open until the docs are updated. Warning: Wall of text incoming.

I guess there are a couple of issues here that I consider to be "a hack", but it depends on whether we're talking about one-way or two-way actions, so I'll address each separately.

Two-way actions

For two-way actions, we're talking about doing something like Austin King suggested in 2010, where you load the handler site in an iframe, then talk between the requester's foreground page and the handler's intercept page in a two-way protocol via iframe messaging. That "works" right now, but when I tried it, it had some rough edge cases in both Chrome and Firefox (mostly bugs that could be fixed) but that aside, it just feels hacky for a number of reasons:

  • It is built upon hidden iframes.
  • It requires the handler and requester to both understand a messaging protocol (and so there could be bugs on either side). That can be encapsulated with libraries, but I'd rather present a much simpler interface for web apps and hide the messaging protocol as an implementation detail for browser vendors.
  • It makes life tricky for doing interop with native applications. Say the browser wants to let a web requester talk to a native handler; it has to create a dummy web page for the native handler, let the requester load it into an iframe, then proxy all the communication to the native app. So you actually end up with more complexity in the browser because all the browsers have to be able to talk this new protocol, on both ends.
  • Lastly, I don't know of any way to solve the "requester goes away" data loss issue (which we solve with service workers). The only handle the requester has in the conversation is the iframe in its foreground page. I don't know of a way to embed a hidden iframe in a service worker context which means if the requester foreground goes away, the connection is over. Letting the requester close but still with the ability to receive updates is one of the problems we'd like to address here.

So the iframe thing kind of works but if we're going to do a standardization effort, the above is why I'd like to focus on a new standard and not reuse RPH. Having said that, a lot of what we're doing is just for one-way actions and we're getting a lot of questions about producing a simplified spec for one-way only. So...

One-way actions

Could we use RPH for one-way actions like share? As you say, we could have a simple URL scheme like "intent://" (that already works on Android, but is very platform-specific) or "share://"? The obvious precedent for actions in URI schemes is mailto: (originating in 1994 or earlier). Essentially, mailto: and share: serve almost exactly the same function: upon opening the URI, a registered handler of the user's choosing is opened, receives the URI fields, and usually presents the user with some UI (in the mailto: case, a mail draft, in the share: case, it could be anything). So we definitely could build share: the same way.

The question I have to ask myself, though, is if we were designing mailto: today, would we do it the same way? And I think the answer is "no, mailto: is and always was a hack, because we didn't have JavaScript". Here's a quote from RFC 2368 (mailto), emphasis mine:

A mailto URL designates an "internet resource", which is the mailbox specified in the address. When additional headers are supplied, the resource designated is the same address, but with an additional profile for accessing the resource. While there are Internet resources that can only be accessed via electronic mail, the mailto URL is not intended as a way of retrieving such objects automatically.

In current practice, resolving URLs such as those in the "http" scheme causes an immediate interaction between client software and a host running an interactive server. The "mailto" URL has unusual semantics because resolving such a URL does not cause an immediate interaction. Instead, the client creates a message to the designated address with the various header fields set as default. The user can edit the message, send this message unedited, or choose not to send the message. The operation of how any URL scheme is resolved is not mandated by the URL specifications.

In other words, mailto: doesn't actually have any specified behaviour. It can't, because URI schemes are declarative, not operational (they tell implementors what resource the URI refers to, but not what to do). So this particular document says, "We can't tell you what to do when the user clicks a mailto link, but wink-wink, you should open an email client with a draft." So we could spec share: in the same way, but I think there is kind of a semantic problem with mailto: that we don't necessarily want to replicate. I think if mailto: were being designed in 2016, it would be a DOM API, navigator.sendMailTo(address, fields), not a URI scheme.

The main downside that would have is that you couldn't easily put people's email addresses in links within emails or other non-web documents, but we don't necessarily want that for share. The other downside is that you can't invoke a DOM API from a non-web context, but I'm also not sure there is value in having "share://" available as a general operating system level URL scheme.

From an API perspective, the URI is easier to build a link to activate, the DOM API is easier to activate programmatically (not from a link), so that goes both ways.

Another upside of building a new API is that we can do declarative registration. One downside of RPH is that it happens programmatically, so it's out of the browser's control when to do the registration. We'd prefer to have handlers registered declaratively, in the web manifest, allowing search engines to index handlers, and allowing browsers to decide when to do registration (e.g., when the user elects to add the app to home screen; see my mocks).

So I'm open to discussion on whether share should be a URI scheme or a DOM API, but my preference is leaning towards a DOM API.

@mgiuca
Copy link
Contributor

mgiuca commented Jun 20, 2016

I've put a summary of this discussion in the web-share explainer so I'll close this issue now. Please open a new issue on the web-share issue tracker if you wish to discuss further.

@mgiuca mgiuca closed this as completed Jun 20, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants