url -> URI

This commit is contained in:
Michelle Tilley
2017-10-17 15:23:10 -07:00
parent e02337265a
commit 5e43084cd3
15 changed files with 92 additions and 92 deletions

View File

@@ -1,5 +1,5 @@
module.exports = {
activate: () => null,
deactivate: () => null,
handleUrl: () => null,
handleURI: () => null,
}

View File

@@ -0,0 +1,6 @@
{
"name": "package-with-uri-handler",
"uriHandler": {
"method": "handleURI"
}
}

View File

@@ -1,6 +0,0 @@
{
"name": "package-with-url-handler",
"urlHandler": {
"method": "handleUrl"
}
}

View File

@@ -3,7 +3,7 @@
import parseCommandLine from '../../src/main-process/parse-command-line'
describe('parseCommandLine', function () {
describe('when --url-handler is not passed', function () {
describe('when --uri-handler is not passed', function () {
it('parses arguments as normal', function () {
const args = parseCommandLine(['-d', '--safe', '--test', '/some/path', 'atom://test/url', 'atom://other/url'])
assert.isTrue(args.devMode)
@@ -14,9 +14,9 @@ describe('parseCommandLine', function () {
})
})
describe('when --url-handler is passed', function () {
describe('when --uri-handler is passed', function () {
it('ignores other arguments and limits to one URL', function () {
const args = parseCommandLine(['-d', '--url-handler', '--safe', '--test', '/some/path', 'atom://test/url', 'atom://other/url'])
const args = parseCommandLine(['-d', '--uri-handler', '--safe', '--test', '/some/path', 'atom://test/url', 'atom://other/url'])
assert.isUndefined(args.devMode)
assert.isUndefined(args.safeMode)
assert.isUndefined(args.test)

View File

@@ -1040,16 +1040,16 @@ describe('PackageManager', () => {
})
describe("URL handler registration", () => {
it("registers the package's specified URL handler", async () => {
const uri = 'atom://package-with-url-handler/some/url?with=args'
const mod = require('./fixtures/packages/package-with-url-handler')
spyOn(mod, 'handleUrl')
describe("URI handler registration", () => {
it("registers the package's specified URI handler", async () => {
const uri = 'atom://package-with-uri-handler/some/url?with=args'
const mod = require('./fixtures/packages/package-with-uri-handler')
spyOn(mod, 'handleURI')
spyOn(atom.packages, 'hasLoadedInitialPackages').andReturn(true)
const activationPromise = atom.packages.activatePackage('package-with-url-handler')
atom.dispatchUrlMessage(uri)
const activationPromise = atom.packages.activatePackage('package-with-uri-handler')
atom.dispatchURIMessage(uri)
await activationPromise
expect(mod.handleUrl).toHaveBeenCalledWith(url.parse(uri, true), uri)
expect(mod.handleURI).toHaveBeenCalledWith(url.parse(uri, true), uri)
})
})

View File

@@ -4,30 +4,30 @@ import url from 'url'
import {it} from './async-spec-helpers'
import UrlHandlerRegistry from '../src/url-handler-registry'
import URIHandlerRegistry from '../src/uri-handler-registry'
describe('UrlHandlerRegistry', () => {
describe('URIHandlerRegistry', () => {
let registry
beforeEach(() => {
registry = new UrlHandlerRegistry(5)
registry = new URIHandlerRegistry(5)
})
it('handles URLs on a per-host basis', () => {
it('handles URIs on a per-host basis', () => {
const testPackageSpy = jasmine.createSpy()
const otherPackageSpy = jasmine.createSpy()
registry.registerHostHandler('test-package', testPackageSpy)
registry.registerHostHandler('other-package', otherPackageSpy)
registry.handleUrl('atom://yet-another-package/path')
registry.handleURI('atom://yet-another-package/path')
expect(testPackageSpy).not.toHaveBeenCalled()
expect(otherPackageSpy).not.toHaveBeenCalled()
registry.handleUrl('atom://test-package/path')
registry.handleURI('atom://test-package/path')
expect(testPackageSpy).toHaveBeenCalledWith(url.parse('atom://test-package/path', true), 'atom://test-package/path')
expect(otherPackageSpy).not.toHaveBeenCalled()
registry.handleUrl('atom://other-package/path')
registry.handleURI('atom://other-package/path')
expect(otherPackageSpy).toHaveBeenCalledWith(url.parse('atom://other-package/path', true), 'atom://other-package/path')
})
@@ -39,7 +39,7 @@ describe('UrlHandlerRegistry', () => {
registry.registerHostHandler('two', spy2)
registry.onHistoryChange(changeSpy)
const urls = [
const uris = [
'atom://one/something?asdf=1',
'atom://fake/nothing',
'atom://two/other/stuff',
@@ -47,19 +47,19 @@ describe('UrlHandlerRegistry', () => {
'atom://two/more/stuff'
]
urls.forEach(u => registry.handleUrl(u))
uris.forEach(u => registry.handleURI(u))
expect(changeSpy.callCount).toBe(5)
expect(registry.getRecentlyHandledUrls()).toEqual(urls.map((u, idx) => {
return {id: idx + 1, url: u, handled: !u.match(/fake/), host: url.parse(u).host}
expect(registry.getRecentlyHandledURIs()).toEqual(uris.map((u, idx) => {
return {id: idx + 1, uri: u, handled: !u.match(/fake/), host: url.parse(u).host}
}).reverse())
registry.handleUrl('atom://another/url')
registry.handleURI('atom://another/url')
expect(changeSpy.callCount).toBe(6)
const history = registry.getRecentlyHandledUrls()
const history = registry.getRecentlyHandledURIs()
expect(history.length).toBe(5)
expect(history[0].url).toBe('atom://another/url')
expect(history[4].url).toBe(urls[1])
expect(history[0].uri).toBe('atom://another/url')
expect(history[4].uri).toBe(uris[1])
})
it('refuses to handle bad URLs', () => {
@@ -69,7 +69,7 @@ describe('UrlHandlerRegistry', () => {
'user:pass@atom://package/path',
'smth://package/path'
].forEach(uri => {
expect(() => registry.handleUrl(uri)).toThrow()
expect(() => registry.handleURI(uri)).toThrow()
})
})
})

View File

@@ -233,13 +233,13 @@ class ApplicationDelegate
new Disposable ->
ipcRenderer.removeListener('context-command', outerCallback)
onURLMessage: (callback) ->
onURIMessage: (callback) ->
outerCallback = (event, args...) ->
callback(args...)
ipcRenderer.on('url-message', outerCallback)
ipcRenderer.on('uri-message', outerCallback)
new Disposable ->
ipcRenderer.removeListener('url-message', outerCallback)
ipcRenderer.removeListener('uri-message', outerCallback)
onDidRequestUnload: (callback) ->
outerCallback = (event, message) ->

View File

@@ -22,7 +22,7 @@ Config = require './config'
KeymapManager = require './keymap-extensions'
TooltipManager = require './tooltip-manager'
CommandRegistry = require './command-registry'
UrlHandlerRegistry = require './url-handler-registry'
URIHandlerRegistry = require './uri-handler-registry'
GrammarRegistry = require './grammar-registry'
{HistoryManager, HistoryProject} = require './history-manager'
ReopenProjectMenuManager = require './reopen-project-menu-manager'
@@ -149,14 +149,14 @@ class AtomEnvironment extends Model
@keymaps = new KeymapManager({notificationManager: @notifications})
@tooltips = new TooltipManager(keymapManager: @keymaps, viewRegistry: @views)
@commands = new CommandRegistry
@urlHandlerRegistry = new UrlHandlerRegistry
@uriHandlerRegistry = new URIHandlerRegistry
@grammars = new GrammarRegistry({@config})
@styles = new StyleManager()
@packages = new PackageManager({
@config, styleManager: @styles,
commandRegistry: @commands, keymapManager: @keymaps, notificationManager: @notifications,
grammarRegistry: @grammars, deserializerManager: @deserializers, viewRegistry: @views,
urlHandlerRegistry: @urlHandlerRegistry
uriHandlerRegistry: @uriHandlerRegistry
})
@themes = new ThemeManager({
packageManager: @packages, @config, styleManager: @styles,
@@ -356,7 +356,7 @@ class AtomEnvironment extends Model
@stylesElement.remove()
@config.unobserveUserConfig()
@autoUpdater.destroy()
@urlHandlerRegistry.destroy()
@uriHandlerRegistry.destroy()
@uninstallWindowEventHandler()
@@ -697,7 +697,7 @@ class AtomEnvironment extends Model
@disposables.add(@applicationDelegate.onDidOpenLocations(@openLocations.bind(this)))
@disposables.add(@applicationDelegate.onApplicationMenuCommand(@dispatchApplicationMenuCommand.bind(this)))
@disposables.add(@applicationDelegate.onContextMenuCommand(@dispatchContextMenuCommand.bind(this)))
@disposables.add(@applicationDelegate.onURLMessage(@dispatchUrlMessage.bind(this)))
@disposables.add(@applicationDelegate.onURIMessage(@dispatchURIMessage.bind(this)))
@disposables.add @applicationDelegate.onDidRequestUnload =>
@saveState({isUnloading: true})
.catch(console.error)
@@ -1100,13 +1100,13 @@ class AtomEnvironment extends Model
dispatchContextMenuCommand: (command, args...) ->
@commands.dispatch(@contextMenu.activeElement, command, args)
dispatchUrlMessage: (uri) ->
dispatchURIMessage: (uri) ->
if @packages.hasLoadedInitialPackages()
@urlHandlerRegistry.handleUrl(uri)
@uriHandlerRegistry.handleURI(uri)
else
sub = @packages.onDidLoadInitialPackages ->
sub.dispose()
@urlHandlerRegistry.handleUrl(uri)
@uriHandlerRegistry.handleURI(uri)
openLocations: (locations) ->
needsProjectPaths = @project?.getPaths().length is 0

View File

@@ -666,12 +666,12 @@ class AtomApplication
windowInitializationScript ?= require.resolve('../initialize-application-window')
if @lastFocusedWindow?
@lastFocusedWindow.sendUrlMessage url
@lastFocusedWindow.sendURIMessage url
else
windowDimensions = @getDimensionsForNewWindow()
@lastFocusedWindow = new AtomWindow(this, @fileRecoveryService, {resourcePath, windowInitializationScript, devMode, safeMode, windowDimensions, env})
@lastFocusedWindow.on 'window:loaded', =>
@lastFocusedWindow.sendUrlMessage url
@lastFocusedWindow.sendURIMessage url
findPackageWithName: (packageName, devMode) ->
_.find @getPackageManager(devMode).getAvailablePackageMetadata(), ({name}) -> name is packageName

View File

@@ -232,8 +232,8 @@ class AtomWindow
unless @atomApplication.sendCommandToFirstResponder(command)
@sendCommandToBrowserWindow(command, args...)
sendUrlMessage: (url) ->
@browserWindow.webContents.send 'url-message', url
sendURIMessage: (uri) ->
@browserWindow.webContents.send 'uri-message', uri
sendCommandToBrowserWindow: (command, args...) ->
action = if args[0]?.contextCommand then 'context-command' else 'command'

View File

@@ -58,15 +58,15 @@ module.exports = function parseCommandLine (processArgs) {
options.string('user-data-dir')
options.boolean('clear-window-state').describe('clear-window-state', 'Delete all Atom environment state.')
options.boolean('enable-electron-logging').describe('enable-electron-logging', 'Enable low-level logging messages from Electron.')
options.boolean('url-handler')
options.boolean('uri-handler')
let args = options.argv
// If --url-handler is set, then we parse NOTHING else
if (args.urlHandler) {
// If --uri-handler is set, then we parse NOTHING else
if (args.uriHandler) {
args = {
urlHandler: true,
'url-handler': true,
uriHandler: true,
'uri-handler': true,
_: args._.filter(str => str.startsWith('atom://')).slice(0, 1)
}
}

View File

@@ -32,7 +32,7 @@ module.exports = class PackageManager {
({
config: this.config, styleManager: this.styleManager, notificationManager: this.notificationManager, keymapManager: this.keymapManager,
commandRegistry: this.commandRegistry, grammarRegistry: this.grammarRegistry, deserializerManager: this.deserializerManager, viewRegistry: this.viewRegistry,
urlHandlerRegistry: this.urlHandlerRegistry
uriHandlerRegistry: this.uriHandlerRegistry
} = params)
this.emitter = new Emitter()
@@ -649,7 +649,7 @@ module.exports = class PackageManager {
}
registerUrlHandlerForPackage (packageName, handler) {
return this.urlHandlerRegistry.registerHostHandler(packageName, handler)
return this.uriHandlerRegistry.registerHostHandler(packageName, handler)
}
// another type of package manager can handle other package types.

View File

@@ -323,13 +323,13 @@ class Package
registerUrlHandler: ->
handlerConfig = @getUrlHandler()
if methodName = handlerConfig?.method
@urlHandlerSubscription = @packageManager.registerUrlHandlerForPackage @name, (args...) =>
@handleUrl(methodName, args)
@uriHandlerSubscription = @packageManager.registerUrlHandlerForPackage @name, (args...) =>
@handleURI(methodName, args)
unregisterUrlHandler: ->
@urlHandlerSubscription?.dispose()
@uriHandlerSubscription?.dispose()
handleUrl: (methodName, args) ->
handleURI: (methodName, args) ->
@activate().then =>
@mainModule[methodName]?.apply(@mainModule, args)
unless @mainActivated
@@ -695,7 +695,7 @@ class Package
@activationHooks = _.uniq(@activationHooks)
getUrlHandler: ->
@metadata?.urlHandler
@metadata?.uriHandler
# Does the given module path contain native code?
isNativeModule: (modulePath) ->

View File

@@ -12,13 +12,13 @@ class ProtocolHandlerInstaller {
}
isDefaultProtocolClient () {
return remote.app.isDefaultProtocolClient('atom', process.execPath, ['--url-handler'])
return remote.app.isDefaultProtocolClient('atom', process.execPath, ['--uri-handler'])
}
setAsDefaultProtocolClient () {
// This Electron API is only available on Windows and macOS. There might be some
// hacks to make it work on Linux; see https://github.com/electron/electron/issues/6440
return this.isSupported() && remote.app.setAsDefaultProtocolClient('atom', process.execPath, ['--url-handler'])
return this.isSupported() && remote.app.setAsDefaultProtocolClient('atom', process.execPath, ['--uri-handler'])
}
initialize (config, notifications) {

View File

@@ -1,41 +1,41 @@
const url = require('url')
const {Emitter, Disposable} = require('event-kit')
// Private: Associates listener functions with URLs from outside the application.
// Private: Associates listener functions with URIs from outside the application.
//
// The global URL handler registry maps URLs to listener functions. URLs are mapped
// based on the hostname of the URL; the format is atom://package/command?args.
// The "core" package name is reserved for URLs handled by Atom core (it is not possible
// The global URI handler registry maps URIs to listener functions. URIs are mapped
// based on the hostname of the URI; the format is atom://package/command?args.
// The "core" package name is reserved for URIs handled by Atom core (it is not possible
// to register a package with the name "core").
//
// Because URL handling can be triggered from outside the application (e.g. from
// Because URI handling can be triggered from outside the application (e.g. from
// the user's browser), package authors should take great care to ensure that malicious
// activities cannot be performed by an attacker. A good rule to follow is that
// **URL handlers should not take action on behalf of the user**. For example, clicking
// **URI handlers should not take action on behalf of the user**. For example, clicking
// a link to open a pane item that prompts the user to install a package is okay;
// automatically installing the package right away is not.
//
// Packages can register their desire to handle URLs via a special key in their
// `package.json` called "urlHandler". The value of this key should be an object
// Packages can register their desire to handle URIs via a special key in their
// `package.json` called "uriHandler". The value of this key should be an object
// that contains, at minimum, a key named "method". This is the name of the method
// on your package object that Atom will call when it receives a URL your package
// is responsible for handling. It will pass the parsed URL as the first argument (by using
// on your package object that Atom will call when it receives a URI your package
// is responsible for handling. It will pass the parsed URI as the first argument (by using
// [Node's `url.parse(uri, true)`](https://nodejs.org/docs/latest/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost))
// and the raw URL as the second argument.
// and the raw URI string as the second argument.
//
// By default, Atom will defer activation of your package until a URL it needs to handle
// By default, Atom will defer activation of your package until a URI it needs to handle
// is triggered. If you need your package to activate right away, you can add
// `"deferActivation": false` to your "urlHandler" configuration object. When activation
// is deferred, once Atom receives a request for a URL in your package's namespace, it will
// `"deferActivation": false` to your "uriHandler" configuration object. When activation
// is deferred, once Atom receives a request for a URI in your package's namespace, it will
// activate your pacakge and then call `methodName` on it as before.
//
// If your package specifies a deprecated `urlMain` property, you cannot register URL handlers
// via the `urlHandler` key.
// If your package specifies a deprecated `urlMain` property, you cannot register URI handlers
// via the `uriHandler` key.
//
// ## Example
//
// Here is a sample package that will be activated and have its `handleUrl` method called
// when a URL beginning with `atom://my-package` is triggered:
// Here is a sample package that will be activated and have its `handleURI` method called
// when a URI beginning with `atom://my-package` is triggered:
//
// `package.json`:
//
@@ -43,8 +43,8 @@ const {Emitter, Disposable} = require('event-kit')
// {
// "name": "my-package",
// "main": "./lib/my-package.js",
// "urlHandler": {
// "method": "handleUrl"
// "uriHandler": {
// "method": "handleURI"
// }
// }
// ```
@@ -57,13 +57,13 @@ const {Emitter, Disposable} = require('event-kit')
// // code to activate your package
// }
//
// handleUrl(url) {
// // parse and handle url
// handleURI(parsedUri, rawUri) {
// // parse and handle uri
// }
// }
// ```
module.exports =
class UrlHandlerRegistry {
class URIHandlerRegistry {
constructor (maxHistoryLength = 50) {
this.registrations = new Map()
this.history = []
@@ -75,11 +75,11 @@ class UrlHandlerRegistry {
registerHostHandler (host, callback) {
if (typeof callback !== 'function') {
throw new Error('Cannot register a URL host handler with a non-function callback')
throw new Error('Cannot register a URI host handler with a non-function callback')
}
if (this.registrations.has(host)) {
throw new Error(`There is already a URL host handler for the host ${host}`)
throw new Error(`There is already a URI host handler for the host ${host}`)
} else {
this.registrations.set(host, callback)
}
@@ -89,15 +89,15 @@ class UrlHandlerRegistry {
})
}
handleUrl (uri) {
handleURI (uri) {
const parsed = url.parse(uri, true)
const {protocol, slashes, auth, port, host} = parsed
if (protocol !== 'atom:' || slashes !== true || auth || port) {
throw new Error(`UrlHandlerRegistry#handleUrl asked to handle an invalid URL: ${uri}`)
throw new Error(`URIHandlerRegistry#handleURI asked to handle an invalid URI: ${uri}`)
}
const registration = this.registrations.get(host)
const historyEntry = {id: ++this._id, url: uri, handled: false, host}
const historyEntry = {id: ++this._id, uri: uri, handled: false, host}
try {
if (registration) {
historyEntry.handled = true
@@ -112,7 +112,7 @@ class UrlHandlerRegistry {
}
}
getRecentlyHandledUrls () {
getRecentlyHandledURIs () {
return this.history
}