I have no idea about Mozilla coding, but here it goes.
According to nsIChannel::asyncOpen(),
Asynchronously open this channel. Data
is fed to the specified stream
listener as it becomes available. The
stream listener's methods are called
on the thread that calls asyncOpen and
are not called until after asyncOpen
returns. If asyncOpen returns
successfully, the channel promises to
call at least onStartRequest and
onStopRequest.
So as the protocol hander, you implement a channel object on your own or redirect it to a channel object, the consumer of the channel calls your channel up using asyncOpen()
. Since it is an async call, the idea is to return the control back to the consumer immediately, and it is suppose to call the callbacks as it loads in the data.
I am not sure if I understand what you mean by "but I don't seem to get control back in the thread that AsyncOpen was called in." The thread is created by the consumer of your protocol, and it opens the channel.
Also from nsIChannel::asyncOpen():
If asyncOpen returns successfully, the
channel is responsible for keeping
itself alive until it has called
onStopRequest on aListener or called
onChannelRedirect.
Since asyncOpen returns the control right back, the channel itself needs to keep itself alive somewhere.
If you are looking for example code, I found codase to be very useful. See nsIProtocolHandler and
nsIChannel. Using that I came across view-source protocol (this implementation may be older, but doesn't matter).
nsViewSourceHandler
implements custom channel.
nsViewSourceHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
{
nsresult rv;
nsViewSourceChannel* channel;
rv = nsViewSourceChannel::Create(nsnull, NS_GET_IID(nsIChannel), (void**)&channel);
if (NS_FAILED(rv)) return rv;
rv = channel->Init(uri);
if (NS_FAILED(rv)) {
NS_RELEASE(channel);
return rv;
}
*result = NS_STATIC_CAST(nsIViewSourceChannel*, channel);
return NS_OK;
}
Here's the nsViewSourceChannel
's AsyncOpen:
nsViewSourceChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
{
NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
mListener = aListener;
/*
* We want to add ourselves to the loadgroup before opening
* mChannel, since we want to make sure we're in the loadgroup
* when mChannel finishes and fires OnStopRequest()
*/
nsCOMPtr<nsILoadGroup> loadGroup;
mChannel->GetLoadGroup(getter_AddRefs(loadGroup));
if (loadGroup)
loadGroup->AddRequest(NS_STATIC_CAST(nsIViewSourceChannel*,
this), nsnull);
nsresult rv = mChannel->AsyncOpen(this, ctxt);
if (NS_FAILED(rv) && loadGroup)
loadGroup->RemoveRequest(NS_STATIC_CAST(nsIViewSourceChannel*,
this),
nsnull, rv);
if (NS_SUCCEEDED(rv)) {
mOpened = PR_TRUE;
}
return rv;
}
Anyway, this is a long and winding way of asking, how are you creating your channel?
Best Answer
AFAIK there is no other solution with firefox. But there are two other possibilities with google chrome:
Google chrome frame http://www.progdigy.com/?p=116
Chromium Embeded http://code.google.com/p/delphichromiumembedded