Protocol handler in Gecko
-
Upload
chih-hsuan-kuo -
Category
Software
-
view
294 -
download
1
Transcript of Protocol handler in Gecko
PROTOCOL HANDLER in GeckoTommy Kuo [:KuoE0] [email protected]
2015.03.03 @Mozilla Taiwan
Outline• What Protocol Handlers Can Do
• The Walkthrough from Awesome Bar to Protocol Handlers
• The Brief Introduction to Channels
What Protocol Handlers Can Do
URI Syntax<scheme name> : <hierarchical part> [ ? <query> ] [ # <fragment> ]
http : //google.com/search ? q=Mozilla
https : //www.facebook.com/pages/郝神好神/871866229523862
file : ///Downloads/郝神好帥.jpg
about : config
mailto : [email protected]
chrome : //browser/skin/Info.png
line : //shop/detail/xxx
Protocol Handler
Format the URI Create the channel Get flags
NewChannel2(…)
NewProxiedChannel2(…)
NewURI(…) GetProtocolFlags(…)
nsresultnsIOService::NewURI(const nsACString &aSpec, const char *aCharset, nsIURI *aBaseURI, nsIURI **result){ NS_ASSERTION(NS_IsMainThread(), "wrong thread");
static uint32_t recursionCount = 0; if (recursionCount >= MAX_RECURSION_COUNT) return NS_ERROR_MALFORMED_URI; AutoIncrement inc(&recursionCount);
nsAutoCString scheme; nsresult rv = ExtractScheme(aSpec, scheme); if (NS_FAILED(rv)) { // then aSpec is relative if (!aBaseURI) return NS_ERROR_MALFORMED_URI;
rv = aBaseURI->GetScheme(scheme); if (NS_FAILED(rv)) return rv; }
// now get the handler for this scheme nsCOMPtr<nsIProtocolHandler> handler; rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); if (NS_FAILED(rv)) return rv;
return handler->NewURI(aSpec, aCharset, aBaseURI, result);}
nsIOService::NewURI (netwerk/base/nsIOService.cpp)
nsCOMPtr<nsIProtocolHandler> handler; rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); if (NS_FAILED(rv)) return rv;
uint32_t protoFlags; rv = handler->GetProtocolFlags(&protoFlags); if (NS_FAILED(rv)) return rv;
bool newChannel2Succeeded = true;
nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler); if (pph) { rv = pph->NewProxiedChannel2(aURI, nullptr, aProxyFlags, aProxyURI, aLoadInfo, result); // if calling NewProxiedChannel2() fails we try to fall back to // creating a new proxied channel by calling NewProxiedChannel(). if (NS_FAILED(rv)) { newChannel2Succeeded = false; rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI, result); } } else { rv = handler->NewChannel2(aURI, aLoadInfo, result); // if calling newChannel2() fails we try to fall back to // creating a new channel by calling NewChannel(). if (NS_FAILED(rv)) { newChannel2Succeeded = false; rv = handler->NewChannel(aURI, result); } }
nsIOService::NewChannelFromURIWithProxyFlagsInternal (netwerk/base/nsIOService.cpp)
nsCOMPtr<nsIProtocolHandler> handler; rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); if (NS_FAILED(rv)) return rv;
uint32_t protoFlags; rv = handler->GetProtocolFlags(&protoFlags); if (NS_FAILED(rv)) return rv;
bool newChannel2Succeeded = true;
nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler); if (pph) { rv = pph->NewProxiedChannel2(aURI, nullptr, aProxyFlags, aProxyURI, aLoadInfo, result); // if calling NewProxiedChannel2() fails we try to fall back to // creating a new proxied channel by calling NewProxiedChannel(). if (NS_FAILED(rv)) { newChannel2Succeeded = false; rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI, result); } } else { rv = handler->NewChannel2(aURI, aLoadInfo, result); // if calling newChannel2() fails we try to fall back to // creating a new channel by calling NewChannel(). if (NS_FAILED(rv)) { newChannel2Succeeded = false; rv = handler->NewChannel(aURI, result); } }
nsIOService::NewChannelFromURIWithProxyFlagsInternal (netwerk/base/nsIOService.cpp)
Create An Protocol Handler• Implementation
• NewURI
• NewChannel2 / NewChannel (not recommended)
• GetProtocolFlags
• Registration
• See 謀智菜逼⼋八談 XPCOM 實務⼊入⾨門
./extensions/gnomevfs/nsGnomeVFSProtocolHandler.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX MOZ_GNOMEVFS_SCHEME, &kNS_GNOMEVFSPROTOCOLHANDLER_CID },./extensions/gio/nsGIOProtocolHandler.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX MOZ_GIO_SCHEME, &kNS_GIOPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "file", &kNS_FILEPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &kNS_HTTPPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "https", &kNS_HTTPSPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &kNS_FTPPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "resource", &kNS_RESPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "about", &kNS_ABOUTPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-safe-about", &kNS_SAFEABOUTPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "app", &kNS_APPPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "data", &kNS_DATAPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-device", &kNS_DEVICEPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "view-source", &kNS_VIEWSOURCEHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "wyciwyg", &kNS_WYCIWYGPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ws", &kNS_WEBSOCKETPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "wss", &kNS_WEBSOCKETSSLPROTOCOLHANDLER_CID },./netwerk/build/nsNetModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "rtsp", &kNS_RTSPPROTOCOLHANDLER_CID },./image/decoders/icon/nsIconModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-icon", &kNS_ICONPROTOCOL_CID },./xpcom/build/XPCOMInit.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "chrome", &kNS_CHROMEPROTOCOLHANDLER_CID },./toolkit/components/places/nsPlacesModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-anno", &kNS_ANNOPROTOCOLHANDLER_CID },./widget/android/nsWidgetFactory.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "android", &kNS_ANDROIDPROTOCOLHANDLER_CID },./layout/build/nsLayoutModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX BLOBURI_SCHEME, &kNS_BLOBPROTOCOLHANDLER_CID },./layout/build/nsLayoutModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX MEDIASTREAMURI_SCHEME, &kNS_MEDIASTREAMPROTOCOLHANDLER_CID },./layout/build/nsLayoutModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX MEDIASOURCEURI_SCHEME, &kNS_MEDIASOURCEPROTOCOLHANDLER_CID },./layout/build/nsLayoutModule.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX FONTTABLEURI_SCHEME, &kNS_FONTTABLEPROTOCOLHANDLER_CID },./modules/libjar/nsJARFactory.cpp: { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "jar", &kNS_JARPROTOCOLHANDLER_CID },
$ grep -ir -E "\{ NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX [^,]+,[^\}]+ \}" .
Awesome Bar to Protocol Handlers
http://google.com/
handleCommand
openUILinkIn
openLinkIn
loadURIWithFlags (tabbrowser)
loadURIWithFlags (browser)
LoadURI(char16_t*, …)
LoadURIWithBase
LoadURI(nsIURI*, …)
InternalLoad
DoURILoad
DoChannelLoad
NS_NewURI
NS_NewChannelInternal
Browser UI (XUL)
DocShell Necko
GetProtocolHandler
GetProtocolHandler
nsIURI
nsIChannel
NewURI
NewChannel2
Browser UI
<textbox id=“urlbar"></text>
browser/base/content/browser.xul
<tabbrowser />
<textbox id="urlbar" flex="1" placeholder="&urlbar.placeholder2;" type="autocomplete" autocompletesearch="urlinline history" autocompletesearchparam="enable-actions" autocompletepopup="PopupAutoCompleteRichResult" completeselectedindex="true" tabscrolling="true" showcommentcolumn="true" showimagecolumn="true" enablehistory="true" maxrows="6" newlines="stripsurroundingwhitespace" ontextentered="this.handleCommand(param);" ontextreverted="return this.handleRevert();" pageproxystate="invalid" onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'" onblur="setTimeout(() => { document.getElementById('identity-box').style.MozUserFocus = ''; }, 0);”>
. . . . . .
</textbox>
browser/base/content/urlbarBindings.xml
handleCommand
1.Canonize URI
2.Detect target in the current tab or a new tab
3.Call openUILinkIn
browser/base/content/urlbarBindings.xml
google mozilla ⇒ https://www.google.com.tw/search?q=mozilla search engine
tv ⇒ http://tv.atmovies.com.tw/tv/attv.cfm?action=todaytime bookmark keyword
google ⇒ http://www.google.com hotkey (Ctrl/Cmd+Enter)
google ⇒ http://www.google.net hotkey (Shift+Enter)
openUILinkIn
1. Set parameters
• third-party fix-up permission
• post data
• referrer URI
2. Call openLinkIn
browser/base/content/utilityOverlay.js
openLinkIn
1. Set target to open URI
• current tab
• new tab
• new window
2. Call loadURIWithFlags (tabbrowser)
browser/base/content/utilityOverlay.js
loadURIWithFlags (tabbrowser)
1. Call loadURIWithFlags of its member browser object
browser/base/content/tabbrowser.xml
loadURIWithFlags (browser)
1. Set “about:blank” for empty URI
2. Call loadURI
• Call nsDocShell::LoadURI actually
source/toolkit/content/widgets/browser.xml
DocShell
LoadURI(char16_t*, …)
1. Call LoadURIWithBase
docshell/base/nsDocShell.cpp
LoadURIWithBase
1. Check navigatable or not
2. Call NS_NewURI to create an instance of nsIURI
3. Fix up URI if allowed
4. Call LoadURI
docshell/base/nsDocShell.cpp
ttp → http ps → https
le → file
LoadURI(nsIURI*, …)
1. Check navigatable or not
2. Redirect if needed
3. Call LoadHistoryEntry to load from history if shEntry exists
4. Call InternalLoad
docshell/base/nsDocShell.cpp
session history
InternalLoad
1. Get content policy
2. Decide to load or not according to the content policy
3. Do shortcut loading if only hash tags are different
4. Call DoURILoad
docshell/base/nsDocShell.cpp
DoURILoad
1. URI is not a source document
• Call NS_NewChannelInternal to create channel
2. URI is a source document
• Get “view-source” channel if protocol is “view-source”
• Call NS_NewInputStreamChannelInternal to create channel for “text/html”
3. Setup some data for specific protocols
4. Call DoChannelLoad to load channel
docshell/base/nsDocShell.cpp
Necko
NS_NewURI NS_NewChannelInternal (7 parameter)
nsIOService::NewURI
GetProtocolHandler
NS_NewChannelInternal (11 parameter)
NewChannelFromURI2
NewChannelFromURIWithProxyFlagsInternal
GetProtocolHandler
DoURILoadLoadURIWithBase
Call Stack
GetProtocolHandler
1.Return protocol handler if the protocol handler was cached
2. For internal protocol
• Cache the protocol handler and return
3. For external protocol
• Get default external protocol handler for external protocol
netwerk/base/nsIOService.cpp
Protocols are not provided in gecko.
The Brief Introduction to Channels
Channel (nsIChannel)
AsyncOpen() (Non-blocking IO)
Asynchronously open this channel. Data is fed to the specified stream listener as it becomes available.
Open() (Blocking IO)
Synchronously open the channel.
Listener (nsIStreamListener)
OnStartRequest()
Called to signify the beginning of an asynchronous request.
OnStopRequest()
Called to signify the end of an asynchronous request.
OnDataAvailable()
Called when the next chunk of data may be read without blocking the calling thread.
nsDocShell::DoChannelLoad
nsURILoader::OpenURI nsDocumentOpenInfo
nsIChannel::AsyncOpen
nsIChannel
create
call
call
nsIAsyncInputStreamcreate
nsInputStreamPump::AsyncRead
call
nsDocShell
nsIChannel
nsIAsyncStream
listen by nsDocmentOpenInfo
listen by self (nsIChannel)
nsDocShell nsIChannel nsIAsyncStream
OnStartRequest
OnDataAvailable
OnStopRequest
OnStartRequest
OnDataAvailable
OnStopRequest
Read
Thank you!