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. PROTOCOL HANDLER
    in Gecko
    Tommy Kuo [:KuoE0]
    [email protected]
    2015.03.03 @Mozilla Taiwan

    View full-size slide

  2. Outline
    • What Protocol Handlers Can Do
    • The Walkthrough from Awesome Bar to Protocol
    Handlers
    • The Brief Introduction to Channels

    View full-size slide

  3. What Protocol Handlers
    Can Do

    View full-size slide

  4. URI Syntax
    : [ ? ] [ # ]
    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

    View full-size slide

  5. Protocol Handler
    Format the URI Create the channel Get flags
    NewChannel2(…)
    NewProxiedChannel2(…)
    NewURI(…) GetProtocolFlags(…)

    View full-size slide

  6. 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 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)

    View full-size slide

  7. nsCOMPtr 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 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)

    View full-size slide

  8. nsCOMPtr 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 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)

    View full-size slide

  9. Create An Protocol Handler
    • Implementation
    • NewURI
    • NewChannel2 / NewChannel (not recommended)
    • GetProtocolFlags
    • Registration
    • See 謀智菜逼⼋八談 XPCOM 實務⼊入⾨門

    View full-size slide

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

    View full-size slide

  11. Awesome Bar to
    Protocol Handlers

    View full-size slide

  12. http://google.com/

    View full-size slide

  13. http://google.com/
    How to interact to HTTP protocol?

    View full-size slide

  14. 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

    View full-size slide


  15. browser/base/content/browser.xul

    View full-size slide

  16. 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);”>
    . . . . . .

    browser/base/content/urlbarBindings.xml

    View full-size slide

  17. 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)

    View full-size slide

  18. openUILinkIn
    1. Set parameters
    • third-party fix-up permission
    • post data
    • referrer URI
    2. Call openLinkIn
    browser/base/content/utilityOverlay.js

    View full-size slide

  19. openLinkIn
    1. Set target to open URI
    • current tab
    • new tab
    • new window
    2. Call loadURIWithFlags (tabbrowser)
    browser/base/content/utilityOverlay.js

    View full-size slide

  20. loadURIWithFlags (tabbrowser)
    1. Call loadURIWithFlags of its member browser
    object
    browser/base/content/tabbrowser.xml

    View full-size slide

  21. loadURIWithFlags (browser)
    1. Set “about:blank” for empty URI
    2. Call loadURI
    • Call nsDocShell::LoadURI actually
    source/toolkit/content/widgets/browser.xml

    View full-size slide

  22. LoadURI(char16_t*, …)
    1. Call LoadURIWithBase
    docshell/base/nsDocShell.cpp

    View full-size slide

  23. 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

    View full-size slide

  24. 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

    View full-size slide

  25. 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

    View full-size slide

  26. 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

    View full-size slide

  27. NS_NewURI NS_NewChannelInternal (7 parameter)
    nsIOService::NewURI
    GetProtocolHandler
    NS_NewChannelInternal (11 parameter)
    NewChannelFromURI2
    NewChannelFromURIWithProxyFlagsInternal
    GetProtocolHandler
    DoURILoad
    LoadURIWithBase
    Call Stack

    View full-size slide

  28. 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.

    View full-size slide

  29. The Brief Introduction to
    Channels

    View full-size slide

  30. 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.

    View full-size slide

  31. 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.

    View full-size slide

  32. nsDocShell::DoChannelLoad
    nsURILoader::OpenURI nsDocumentOpenInfo
    nsIChannel::AsyncOpen
    nsIChannel
    create
    call
    call
    nsIAsyncInputStream
    create
    nsInputStreamPump::AsyncRead
    call

    View full-size slide

  33. nsDocShell
    nsIChannel
    nsIAsyncStream
    listen by nsDocmentOpenInfo
    listen by self (nsIChannel)

    View full-size slide

  34. nsDocShell nsIChannel nsIAsyncStream
    OnStartRequest
    OnDataAvailable
    OnStopRequest
    OnStartRequest
    OnDataAvailable
    OnStopRequest
    Read

    View full-size slide