зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1373640 implement async dns resolve api for webextensions, r=kmag
MozReview-Commit-ID: Bzfr2x6Vmx2 --HG-- extra : rebase_source : cfde60f191c470e483a95b7e668a7ac9e5ba5af3
This commit is contained in:
Родитель
88d4860b5d
Коммит
3891cc84f5
|
@ -101,6 +101,7 @@ webextPerms.description.browsingData=Clear recent browsing history, cookies, and
|
|||
webextPerms.description.clipboardRead=Get data from the clipboard
|
||||
webextPerms.description.clipboardWrite=Input data to the clipboard
|
||||
webextPerms.description.devtools=Extend developer tools to access your data in open tabs
|
||||
webextPerms.description.dns=Access IP address and hostname information
|
||||
webextPerms.description.downloads=Download files and read and modify the browser’s download history
|
||||
webextPerms.description.downloads.open=Open files downloaded to your computer
|
||||
webextPerms.description.find=Read the text of all open tabs
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
const dnssFlags = {
|
||||
"allow_name_collisions": Ci.nsIDNSService.RESOLVE_ALLOW_NAME_COLLISION,
|
||||
"bypass_cache": Ci.nsIDNSService.RESOLVE_BYPASS_CACHE,
|
||||
"canonical_name": Ci.nsIDNSService.RESOLVE_CANONICAL_NAME,
|
||||
"disable_ipv4": Ci.nsIDNSService.RESOLVE_DISABLE_IPV4,
|
||||
"disable_ipv6": Ci.nsIDNSService.RESOLVE_DISABLE_IPV6,
|
||||
"disable_trr": Ci.nsIDNSService.RESOLVE_DISABLE_TRR,
|
||||
"offline": Ci.nsIDNSService.RESOLVE_OFFLINE,
|
||||
"priority_low": Ci.nsIDNSService.RESOLVE_PRIORITY_LOW,
|
||||
"priority_medium": Ci.nsIDNSService.RESOLVE_PRIORITY_MEDIUM,
|
||||
"speculate": Ci.nsIDNSService.RESOLVE_SPECULATE,
|
||||
};
|
||||
|
||||
function getErrorString(nsresult) {
|
||||
let e = new Components.Exception("", nsresult);
|
||||
return e.name;
|
||||
}
|
||||
|
||||
this.dns = class extends ExtensionAPI {
|
||||
getAPI(context) {
|
||||
const dnss = Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService);
|
||||
return {
|
||||
dns: {
|
||||
resolve: function(hostname, flags) {
|
||||
let dnsFlags = flags.reduce((mask, flag) => mask | dnssFlags[flag], 0);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let request;
|
||||
let response = {
|
||||
addresses: [],
|
||||
};
|
||||
let listener = (inRequest, inRecord, inStatus) => {
|
||||
if (inRequest === request) {
|
||||
if (!Components.isSuccessCode(inStatus)) {
|
||||
return reject({message: getErrorString(inStatus)});
|
||||
}
|
||||
if (dnsFlags & Ci.nsIDNSService.RESOLVE_CANONICAL_NAME) {
|
||||
try {
|
||||
response.canonicalName = inRecord.canonicalName;
|
||||
} catch (e) {
|
||||
// no canonicalName
|
||||
}
|
||||
}
|
||||
response.isTRR = inRecord.IsTRR();
|
||||
while (inRecord.hasMore()) {
|
||||
let addr = inRecord.getNextAddrAsString();
|
||||
// Sometimes there are duplicate records with the same ip.
|
||||
if (!response.addresses.includes(addr)) {
|
||||
response.addresses.push(addr);
|
||||
}
|
||||
}
|
||||
return resolve(response);
|
||||
}
|
||||
};
|
||||
try {
|
||||
request = dnss.asyncResolve(hostname, dnsFlags, listener, null, {} /* defaultOriginAttributes */);
|
||||
} catch (e) {
|
||||
// handle exceptions such as offline mode.
|
||||
return reject({message: e.name});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
|
@ -58,6 +58,14 @@
|
|||
["cookies"]
|
||||
]
|
||||
},
|
||||
"dns": {
|
||||
"url": "chrome://extensions/content/ext-dns.js",
|
||||
"schema": "chrome://extensions/content/schemas/dns.json",
|
||||
"scopes": ["addon_parent"],
|
||||
"paths": [
|
||||
["dns"]
|
||||
]
|
||||
},
|
||||
"downloads": {
|
||||
"url": "chrome://extensions/content/ext-downloads.js",
|
||||
"schema": "chrome://extensions/content/schemas/downloads.json",
|
||||
|
|
|
@ -13,6 +13,7 @@ toolkit.jar:
|
|||
content/extensions/ext-contextualIdentities.js
|
||||
content/extensions/ext-clipboard.js
|
||||
content/extensions/ext-cookies.js
|
||||
content/extensions/ext-dns.js
|
||||
content/extensions/ext-downloads.js
|
||||
content/extensions/ext-extension.js
|
||||
content/extensions/ext-i18n.js
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
[
|
||||
{
|
||||
"namespace": "manifest",
|
||||
"types": [
|
||||
{
|
||||
"$extend": "Permission",
|
||||
"choices": [{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"dns"
|
||||
]
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"namespace": "dns",
|
||||
"description": "Asynchronous DNS API",
|
||||
"permissions": ["dns"],
|
||||
"types": [
|
||||
{
|
||||
"id": "DNSRecord",
|
||||
"type": "object",
|
||||
"description": "An object encapsulating a DNS Record.",
|
||||
"properties": {
|
||||
"canonicalName": {
|
||||
"type": "string",
|
||||
"optional": true,
|
||||
"description": "The canonical hostname for this record. this value is empty if the record was not fetched with the 'canonical_name' flag."
|
||||
},
|
||||
"isTRR": {
|
||||
"type": "string",
|
||||
"description": "Record retreived with TRR."
|
||||
},
|
||||
"addresses": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ResolveFlags",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"allow_name_collisions",
|
||||
"bypass_cache",
|
||||
"canonical_name",
|
||||
"disable_ipv4",
|
||||
"disable_ipv6",
|
||||
"disable_trr",
|
||||
"offline",
|
||||
"priority_low",
|
||||
"priority_medium",
|
||||
"speculate"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"name": "resolve",
|
||||
"type": "function",
|
||||
"description": "Resolves a hostname to a DNS record.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "hostname",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "flags",
|
||||
"optional": true,
|
||||
"default": [],
|
||||
"$ref": "ResolveFlags"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -10,6 +10,7 @@ toolkit.jar:
|
|||
content/extensions/schemas/content_scripts.json
|
||||
content/extensions/schemas/contextual_identities.json
|
||||
content/extensions/schemas/cookies.json
|
||||
content/extensions/schemas/dns.json
|
||||
content/extensions/schemas/downloads.json
|
||||
content/extensions/schemas/events.json
|
||||
content/extensions/schemas/experiments.json
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
"use strict";
|
||||
|
||||
// Some test machines and android are not returing ipv6, turn it
|
||||
// off to get consistent test results.
|
||||
Services.prefs.setBoolPref("network.dns.disableIPv6", true);
|
||||
|
||||
function getExtension(background = undefined) {
|
||||
let manifest = {
|
||||
"permissions": [
|
||||
"dns",
|
||||
],
|
||||
};
|
||||
return ExtensionTestUtils.loadExtension({
|
||||
manifest,
|
||||
background() {
|
||||
browser.test.onMessage.addListener(async (msg, data) => {
|
||||
browser.test.log(`=== dns resolve test ${JSON.stringify(data)}`);
|
||||
browser.dns.resolve(data.hostname, data.flags).then(result => {
|
||||
browser.test.log(`=== dns resolve result ${JSON.stringify(result)}`);
|
||||
browser.test.sendMessage("resolved", result);
|
||||
}).catch(e => {
|
||||
browser.test.log(`=== dns resolve error ${e.message}`);
|
||||
browser.test.sendMessage("resolved", {message: e.message});
|
||||
});
|
||||
});
|
||||
browser.test.sendMessage("ready");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const tests = [
|
||||
{
|
||||
request: {
|
||||
hostname: "localhost",
|
||||
},
|
||||
expect: {
|
||||
addresses: ["127.0.0.1"], // ipv6 disabled , "::1"
|
||||
},
|
||||
},
|
||||
{
|
||||
request: {
|
||||
hostname: "localhost",
|
||||
flags: ["offline"],
|
||||
},
|
||||
expect: {
|
||||
addresses: ["127.0.0.1"], // ipv6 disabled , "::1"
|
||||
},
|
||||
},
|
||||
{
|
||||
request: {
|
||||
hostname: "test.example",
|
||||
},
|
||||
expect: {
|
||||
// android will error with offline
|
||||
error: /NS_ERROR_UNKNOWN_HOST|NS_ERROR_OFFLINE/,
|
||||
},
|
||||
},
|
||||
{
|
||||
request: {
|
||||
hostname: "127.0.0.1",
|
||||
flags: ["canonical_name"],
|
||||
},
|
||||
expect: {
|
||||
canonicalName: "127.0.0.1",
|
||||
addresses: ["127.0.0.1"],
|
||||
},
|
||||
},
|
||||
{
|
||||
request: {
|
||||
hostname: "localhost",
|
||||
flags: ["disable_ipv6"],
|
||||
},
|
||||
expect: {
|
||||
addresses: ["127.0.0.1"],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function test_dns_resolve() {
|
||||
let extension = getExtension();
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("ready");
|
||||
|
||||
for (let test of tests) {
|
||||
extension.sendMessage("resolve", test.request);
|
||||
let result = await extension.awaitMessage("resolved");
|
||||
if (test.expect.error) {
|
||||
ok(test.expect.error.test(result.message), `expected error ${result.message}`);
|
||||
} else {
|
||||
equal(result.canonicalName, test.expect.canonicalName, "canonicalName match");
|
||||
// It seems there are platform differences happening that make this
|
||||
// testing difficult. We're going to rely on other existing dns tests to validate
|
||||
// the dns service itself works and only validate that we're getting generally
|
||||
// expected results in the webext api.
|
||||
ok(result.addresses.length >= test.expect.addresses.length, "expected number of addresses returned");
|
||||
if (test.expect.addresses.length > 0 && result.addresses.length > 0) {
|
||||
ok(result.addresses.includes(test.expect.addresses[0]), "got expected ip address");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await extension.unload();
|
||||
});
|
|
@ -20,6 +20,7 @@ skip-if = os == "android"
|
|||
[test_ext_contextual_identities.js]
|
||||
skip-if = os == "android" # Containers are not exposed to android.
|
||||
[test_ext_debugging_utils.js]
|
||||
[test_ext_dns.js]
|
||||
[test_ext_downloads.js]
|
||||
[test_ext_downloads_download.js]
|
||||
skip-if = os == "android"
|
||||
|
|
Загрузка…
Ссылка в новой задаче