Protocol handler in Gecko

40
PROTOCOL HANDLER in Gecko Tommy Kuo [:KuoE0] [email protected] 2015.03.03 @Mozilla Taiwan

Transcript of Protocol handler in Gecko

Page 1: Protocol handler in Gecko

PROTOCOL HANDLER in GeckoTommy Kuo [:KuoE0] [email protected]

2015.03.03 @Mozilla Taiwan

Page 2: Protocol handler in Gecko

Outline• What Protocol Handlers Can Do

• The Walkthrough from Awesome Bar to Protocol Handlers

• The Brief Introduction to Channels

Page 3: Protocol handler in Gecko

What Protocol Handlers Can Do

Page 4: Protocol handler in Gecko

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

Page 5: Protocol handler in Gecko

Protocol Handler

Format the URI Create the channel Get flags

NewChannel2(…)

NewProxiedChannel2(…)

NewURI(…) GetProtocolFlags(…)

Page 6: Protocol handler in Gecko

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)

Page 7: Protocol handler in Gecko

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)

Page 8: Protocol handler in Gecko

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)

Page 9: Protocol handler in Gecko

Create An Protocol Handler• Implementation

• NewURI

• NewChannel2 / NewChannel (not recommended)

• GetProtocolFlags

• Registration

• See 謀智菜逼⼋八談 XPCOM 實務⼊入⾨門

Page 10: Protocol handler in Gecko

./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 [^,]+,[^\}]+ \}" .

Page 11: Protocol handler in Gecko

Awesome Bar to Protocol Handlers

Page 12: Protocol handler in Gecko
Page 13: Protocol handler in Gecko

http://google.com/

Page 14: Protocol handler in Gecko

http://google.com/

How to interact to HTTP protocol?

Page 15: Protocol handler in Gecko

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

Page 16: Protocol handler in Gecko

Browser UI

Page 17: Protocol handler in Gecko

<textbox id=“urlbar"></text>

browser/base/content/browser.xul

<tabbrowser />

Page 18: Protocol handler in Gecko

<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

Page 19: Protocol handler in Gecko

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)

Page 20: Protocol handler in Gecko

openUILinkIn

1. Set parameters

• third-party fix-up permission

• post data

• referrer URI

2. Call openLinkIn

browser/base/content/utilityOverlay.js

Page 21: Protocol handler in Gecko

openLinkIn

1. Set target to open URI

• current tab

• new tab

• new window

2. Call loadURIWithFlags (tabbrowser)

browser/base/content/utilityOverlay.js

Page 22: Protocol handler in Gecko

loadURIWithFlags (tabbrowser)

1. Call loadURIWithFlags of its member browser object

browser/base/content/tabbrowser.xml

Page 23: Protocol handler in Gecko

loadURIWithFlags (browser)

1. Set “about:blank” for empty URI

2. Call loadURI

• Call nsDocShell::LoadURI actually

source/toolkit/content/widgets/browser.xml

Page 24: Protocol handler in Gecko

DocShell

Page 25: Protocol handler in Gecko

LoadURI(char16_t*, …)

1. Call LoadURIWithBase

docshell/base/nsDocShell.cpp

Page 26: Protocol handler in Gecko

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

Page 27: Protocol handler in Gecko

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

Page 28: Protocol handler in Gecko

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

Page 29: Protocol handler in Gecko

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

Page 30: Protocol handler in Gecko

Necko

Page 31: Protocol handler in Gecko

NS_NewURI NS_NewChannelInternal (7 parameter)

nsIOService::NewURI

GetProtocolHandler

NS_NewChannelInternal (11 parameter)

NewChannelFromURI2

NewChannelFromURIWithProxyFlagsInternal

GetProtocolHandler

DoURILoadLoadURIWithBase

Call Stack

Page 32: Protocol handler in Gecko

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.

Page 33: Protocol handler in Gecko
Page 34: Protocol handler in Gecko

The Brief Introduction to Channels

Page 35: Protocol handler in Gecko

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.

Page 36: Protocol handler in Gecko

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.

Page 37: Protocol handler in Gecko

nsDocShell::DoChannelLoad

nsURILoader::OpenURI nsDocumentOpenInfo

nsIChannel::AsyncOpen

nsIChannel

create

call

call

nsIAsyncInputStreamcreate

nsInputStreamPump::AsyncRead

call

Page 38: Protocol handler in Gecko

nsDocShell

nsIChannel

nsIAsyncStream

listen by nsDocmentOpenInfo

listen by self (nsIChannel)

Page 39: Protocol handler in Gecko

nsDocShell nsIChannel nsIAsyncStream

OnStartRequest

OnDataAvailable

OnStopRequest

OnStartRequest

OnDataAvailable

OnStopRequest

Read

Page 40: Protocol handler in Gecko

Thank you!