Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Protocol handler in Gecko

KuoE0
March 03, 2015

Protocol handler in Gecko

A brief introduction to protocol handler in gecko. Shared in Mozilla Taiwan.

KuoE0

March 03, 2015
Tweet

More Decks by KuoE0

Other Decks in Programming

Transcript

  1. Outline • What Protocol Handlers Can Do • The Walkthrough

    from Awesome Bar to Protocol Handlers • The Brief Introduction to Channels
  2. 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
  3. Protocol Handler Format the URI Create the channel Get flags

    NewChannel2(…) NewProxiedChannel2(…) NewURI(…) GetProtocolFlags(…)
  4. nsresult nsIOService::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)
  5. 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)
  6. 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)
  7. Create An Protocol Handler • Implementation • NewURI • NewChannel2

    / NewChannel (not recommended) • GetProtocolFlags • Registration • See 謀智菜逼⼋八談 XPCOM 實務⼊入⾨門
  8. ./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 [^,]+,[^\}]+ \}" .
  9. 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
  10. <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
  11. 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)
  12. openUILinkIn 1. Set parameters • third-party fix-up permission • post

    data • referrer URI 2. Call openLinkIn browser/base/content/utilityOverlay.js
  13. openLinkIn 1. Set target to open URI • current tab

    • new tab • new window 2. Call loadURIWithFlags (tabbrowser) browser/base/content/utilityOverlay.js
  14. loadURIWithFlags (browser) 1. Set “about:blank” for empty URI 2. Call

    loadURI • Call nsDocShell::LoadURI actually source/toolkit/content/widgets/browser.xml
  15. 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
  16. 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
  17. 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
  18. 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
  19. NS_NewURI NS_NewChannelInternal (7 parameter) nsIOService::NewURI GetProtocolHandler NS_NewChannelInternal (11 parameter) NewChannelFromURI2

    NewChannelFromURIWithProxyFlagsInternal GetProtocolHandler DoURILoad LoadURIWithBase Call Stack
  20. 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.
  21. 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.
  22. 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.