Upon further review I can see your point about having a default protocol
handler. It can create a dummy channel as well. Calls to AsyncRead and
OpenInputStream could both return errors but cause the url to get sent
to the operating system. (i.e. the code I added to nsDocShell would get
moved to the AsyncRead and OpenInputStream methods of this dummy channel).
This would allow anyone who trys to open a channel for a URL we don't
support to get the correct behavior instead of just urls that are opened
by nsDocShell::LoadURI.
I'd just need to do a couple things to make this happen
1) the exthandler can implement a default protocol handler and channel.
I'm not sure what protocol scheme "key", I'd use to describe this
protocol handler yet.
2) nsIOService::NewURI would be modified such that if it can't get a
protocol handler for the url scheme, we'll attempt to create this
"default" protocol handler and use it instead to create the URI.
Sound good?
Thanks for the comments Rick,
-Scott
Scott MacGregor wrote:
>
>
> Rick Potts wrote:
>
>> hey scott,
>>
>> I see your problem... That basically 3rd party helper apps only
>> interact with the URILoader - not Necko or the rest of Mozilla...
>>
>> I see a couple of issues with your proposal... First, there are some
>> protocol handlers wich actually use nsSimpleURI (such as javascript)
>> so it would be difficult to distinguish between these and the
>> situation where no protocol handler was found...
>
>
> I don't care if someone else uses a simple URI as well. This won't
> interfere with the normal flow of loadiing urls at all.
>
>>
>>
>> Second, unless the URILoader is ultimately used to open the URI, the
>> helper app will still not be launched...
>
>
> this doesn't have anything to do with helper apps per say. It has more
> to deal with giving a URL we don't have a protocol handler for over to
> the OS to handle. You are right though, my fix is in Docshell. If you
> don't click on a link or otherwise force the url to get loaded via your
> docshell, we won't pass the url out to the registry.
>
>>
>>
>> As far as I can see, your change is basically meant to allow NewURI to
>> always succeed, so the URILoader will be called allowing the helper
>> app to be located and invoked...
>>
>> Personally, I think that the right thing is to move "some amount" of
>> helper app support down into Necko... So there is some mechinism for
>> associating a protocol (such as telnet://) with an application...
>>
>> We can create a 3rd party "helper app" protocol which allows an
>> assocation between a protocol and an executable... And have some
>> standardized rules for parsing the URI path and passing it as
>> argument(s) to the external app...
>>
>> It seems like this "helper app protocol" will solve standard cases
>> (ie. mailto://, telnet://...)
>>
>> I know creating a helper app protocol is a bit more work, but I think
>> that it is the direction we want to go...
>>
>> what do you think?
>
>
> I'm not quite sure I see why writing a default helper app protocol is
> the right way to go. Yes it does seem like more work which is part of
> the reason but I don't see what the gain is?
>
> Right now, all I'm proposing is that NS_NewURI creates a simple URI if
> it can't get a protocol handler to create a url for us.
>
> Then in docshell, I added a couple lines of code after we try to open
> the url. If we were unable to get a channel for the URL then we pass the
> URL to the OS.
>
> Here's an excerpt showing that behavior:
> rv = NS_OpenURI(getter_AddRefs(channel), aURI, nsnull, loadGroup,
> ifreq);
> if(NS_FAILED(rv))
> {
> if(NS_ERROR_DOM_RETVAL_UNDEFINED == rv) // if causing the channel
> changed the
> return NS_OK; // dom and there is
> nothing else to do
> else
> {
> // if we are unable to create a channel / protocol handler for
> the specified
> // url then we should attempt to pass the url off to any
> application registered
> // with the OS for this url scheme...
> if (!channel)
> {
> nsCOMPtr<nsIExternalProtocolService> extProtService
> (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
> PRBool haveHandler = PR_FALSE;
> if (extProtService)
> {
> extProtService->ExternalProtocolHandlerExists(urlScheme,
> &haveHandler);
> if (haveHandler)
> return extProtService->LoadUrl(aURI);
> }
> }
>
> return NS_ERROR_FAILURE;
> }
> }
>
> We won't break support of other protocol handlers that use nsSimpleURI
> 'cause when we call NS_NewURI on them, we'll open the uri and everything
> will just work. It's only in the case that we were able to create a
> nsIURI but are unable to find a channel to open the data with that this
> code gets invoked.
>
> I guess I'm fuzzy as to why we would want to write a default protocol
> handler for this case. Protocol handlers are used to create URIs and to
> create channels for the URIs which you can use to open the data. In this
> case we aren't opening the data at all. We never want to return a
> channel and allow the user to call AsyncRead on the channel so most of
> the functionality of the protocol handler would be empty.
>
> Does my argument make sense?
>
> -Scott
>
>>
>> -- rick
>>
>> Scott MacGregor wrote:
>>
>>> In order to create a url object for a spec, nsIOService::NewURI
>>> attempts to find a protocol handler for the scheme of the url and
>>> then use it to create the url. If there is no registered protocol
>>> handler then we fail to create a nsIURI for the spec and we return an
>>> error.
>>>
>>> This makes it very hard for 3rd party applications to get their urls
>>> to run in the mozilla application because they have to write protocol
>>> handler stubs for mozilla.
>>>
>>> 3rd party apps typically go through internet config and the windows
>>> registry to list themselves as applications which can handle
>>> particular url schemes. I already have code for nsDocShell::LoadURI
>>> where a failure to create a channel causes us to pass the URL out to
>>> the operating system and lets it attempt to load the url using this
>>> information.
>>>
>>> Unfortunately we never reach this code because any call to create a
>>> nsIURI object for a protocol scheme which mozilla doesn't know about
>>> already returns an error (nsIOService::NewURI).
>>>
>>> Gagan and I wanted to propose a change to the behavior of this
>>> method. In the event that we can't find a protocol handler to create
>>> a url for the passed in url, then let's create a simple URL object
>>> which can represent the URL. Then when we attempt to actually try to
>>> run that url and create a channel for it, we'll fail and kick out to
>>> the OS.
>>>
>>> An example of this would behavior would be someone who doesn't have
>>> mozilla mail/news installed so they don't have a mailto protocol
>>> handler registered. If they click on a mailto link we should use the
>>> default mailto application as specified by the OS. Today, nothing
>>> will happen if you click on mailto urls without mozilla mail/news
>>> installed (or another mozilla app which registers mailto protocols).
>>>
>>> Here's a possible patch.
>>>
>>> -Scott
>>>
>>>
>>> ------------------------------------------------------------------------
>>>
>>> Index: nsIOService.cpp
>>> ===================================================================
>>> RCS file: /cvsroot/mozilla/netwerk/base/src/nsIOService.cpp,v
>>> retrieving revision 1.87
>>> diff -u -r1.87 nsIOService.cpp
>>> --- nsIOService.cpp 2001/01/17 23:42:42 1.87
>>> +++ nsIOService.cpp 2001/02/05 01:07:15
>>> @@ -41,6 +41,7 @@
>>> static NS_DEFINE_CID(kSocketTransportServiceCID,
>>> NS_SOCKETTRANSPORTSERVICE_CID);
>>> static NS_DEFINE_CID(kDNSServiceCID, NS_DNSSERVICE_CID);
>>> static NS_DEFINE_CID(kErrorServiceCID, NS_ERRORSERVICE_CID);
>>> +static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
>>>
>>> ////////////////////////////////////////////////////////////////////////////////
>>>
>>>
>>> @@ -262,7 +263,18 @@
>>> nsCOMPtr<nsIProtocolHandler> handler;
>>> rv = GetProtocolHandler(scheme, getter_AddRefs(handler));
>>> nsCRT::free(scheme);
>>> - if (NS_FAILED(rv)) return rv;
>>> + if (NS_FAILED(rv) || !handler) {
>>> + // we don't know how to create a url for this scheme so create
>>> + // a simple URL
>>> + rv = nsComponentManager::CreateInstance(kSimpleURICID, nsnull,
>>> + NS_GET_IID(nsIURI),
>>> + (void**) result);
>>> + if (NS_FAILED(rv)) return rv;
>>> + rv = (*result)->SetSpec(aSpec);
>>> + if (hdlrResult)
>>> + *hdlrResult = nsnull;
>>> + return rv;
>>> + }
>>>
>>> if (hdlrResult) {
>>> *hdlrResult = handler;
>>> newURI.diff
>>>
>>> Content-Type:
>>>
>>> text/plain
>>> Content-Encoding:
>>>
>>> 7bit
>>
>>
>>