Protocol handler in Gecko

Post on 15-Jul-2015

294 views 1 download

Transcript of Protocol handler in Gecko

PROTOCOL HANDLER in GeckoTommy Kuo [:KuoE0] kuoe0@mozilla.com

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 : kuoe0@mozilla.com

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/

http://google.com/

How to interact to HTTP protocol?

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!