Skip to content

Commit

Permalink
Cache dnslookup results
Browse files Browse the repository at this point in the history
- implements #44
- simple map with automatic key expiration
- tests
  • Loading branch information
lidel committed Feb 3, 2016
1 parent 4abe934 commit 49a00cc
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

Firefox addon that provides transparent access to IPFS resources via local HTTP2IPFS gateway.

(If you are using Chrome or Chromium, check [ipfs-chrome-extension](https://github.com/dylanPowers/ipfs-chrome-extension) instead)
(If you are using Google Chrome or Chromium check [ipfs-chrome-extension](https://github.com/dylanPowers/ipfs-chrome-extension) or [ipfs-chrome-station](https://github.com/xicombd/ipfs-chrome-station) instead)

![screenshot of v1.4.0](screenshot.png)

Expand Down
31 changes: 23 additions & 8 deletions lib/api.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
'use strict'

const prefs = require('sdk/simple-prefs').prefs
const { prefs } = require('sdk/simple-prefs')

const notifications = require('sdk/notifications')
const {Request} = require('sdk/request')
const {XMLHttpRequest} = require('sdk/net/xhr')
const URL = require('sdk/url').URL
const { notify } = require('sdk/notifications')
const { Request } = require('sdk/request')
const { XMLHttpRequest } = require('sdk/net/xhr')
const { URL } = require('sdk/url')

const dnsCache = require('./dns-cache.js')

function apiUrl (path) {
return URL('http://' + prefs.customGatewayHost + ':' + prefs.customApiPort + '/api/v0/' + path).toString()
Expand All @@ -19,7 +21,7 @@ function pin (address) {
url: apiUrl('pin/add?arg=' + address),
onComplete: function (response) {
let pinned = response.status === 200 && response.json.Pinned ? response.json.Pinned[0] : false
notifications.notify({
notify({
title: pinned ? 'Pinned' : 'Failed to pin',
text: pinned || address.slice(6)
})
Expand Down Expand Up @@ -52,7 +54,11 @@ function isDnslinkPresent (fqdn) {
let xhr = new XMLHttpRequest()
xhr.overrideMimeType('application/json')
xhr.open('GET', apiUrl('dns/' + fqdn), false)
xhr.send(null)
try {
xhr.send(null)
} catch (e) {
return false
}
if (xhr.status === 200) {
let json = JSON.parse(xhr.responseText)
return !!json.Path
Expand All @@ -61,9 +67,18 @@ function isDnslinkPresent (fqdn) {
}
}

function isDnslinkPresentCached (fqdn) {
let ipfsSupport = dnsCache.get(fqdn)
if (typeof ipfsSupport === 'undefined') {
ipfsSupport = isDnslinkPresent(fqdn)
dnsCache.put(fqdn, ipfsSupport)
}
return ipfsSupport
}

exports.apiUrl = apiUrl
exports.query = query
exports.pin = pin
exports.getVersion = getVersion
exports.getSwarmPeers = getSwarmPeers
exports.isDnslinkPresent = isDnslinkPresent
exports.isDnslinkPresent = isDnslinkPresentCached
58 changes: 58 additions & 0 deletions lib/dns-cache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict'

const { prefs } = require('sdk/simple-prefs')
const { setInterval, clearInterval } = require('sdk/timers')

const cache = Object.create(null)
const ttl = 30 * 60 * 1000

let size = 0
let hits = 0
let misses = 0

exports.put = function (key, value, expire) {
if (!cache[key]) { size++ }
cache[key] = { value: value, expire: (expire || Date.now() + ttl) }
// console.log('cache.put: ' + key)
return value
}
exports.get = function (key) {
const data = cache[key]
if (typeof data !== 'undefined') {
hits++
// console.log('cache.hit: ' + key)
return data.value
} else {
misses++
// console.log('cache.miss: ' + key)
return undefined
}
}
exports.dropExpired = function () {
// console.log('cache.size=' + size)
// console.log('cache.hits=' + hits)
// console.log('cache.misses=' + misses)
// console.log('cache.dropExpired..')
for (let key in cache) {
const data = cache[key]
if (data.expire && data.expire < Date.now()) {
// console.log('cache.drop: ' + key)
delete cache[key]
cache.size--
}
}
}
exports.ttl = ttl

// execute on startup and then on every preference change
let cleanup = null
require('sdk/simple-prefs').on('dns', (function f () {
clearInterval(cleanup)
if (prefs.dns) {
cleanup = setInterval(exports.dropExpired, exports.ttl)
// blacklist hosts which may confuse gateway
exports.put('127.0.0.1', false, null)
exports.put(prefs.customGatewayHost, false, null)
}
return f
})())
17 changes: 0 additions & 17 deletions lib/dns.js

This file was deleted.

8 changes: 4 additions & 4 deletions lib/redirects.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict'

const prefs = require('sdk/simple-prefs').prefs
const gw = require('./gateways')
const dns = require('./dns')
const gw = require('./gateways.js')
const api = require('./api.js')

const {Cc, Ci} = require('chrome')

Expand All @@ -16,9 +16,9 @@ function redirectFor (uri) {
if (uriSpec.match(gw.publicHosts) && uriSpec.match(gw.IPFS_RESOURCE)) {
// redirect IPFS paths from known public gateways
redirectUri = ioservice.newURI(uriSpec.replace(gw.publicHosts, gw.customUri.spec), null, null)
} else if (prefs.dns && dns.isIpfsEnabled(uri.host)) {
} else if (prefs.dns && api.isDnslinkPresent(uri.host)) {
// redirect sites with dnslink record in DNS
redirectUri = ioservice.newURI(gw.customUri.spec + 'ipns/' + uri.host + uri.path + uri.ref, null, null)
redirectUri = ioservice.newURI(gw.customUri.spec + 'ipns/' + uri.host + uri.path, null, null)
}
}
// if (redirectUri) console.log('redirectFor(' + uri.spec + ')=' + redirectUri.spec)
Expand Down
46 changes: 46 additions & 0 deletions test/test-dnslink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict'

require('../lib/redirects.js')

const gw = require('../lib/gateways.js')
const api = require('../lib/api.js')
const tabs = require('sdk/tabs')
const { prefs } = require('sdk/simple-prefs')
const dnsCache = require('../lib/dns-cache.js')

exports['test a redirect triggered by dnslink'] = function (assert, done) {
const fqdnWithDnslink = 'ipfs.git.sexy'
const sitePath = '/some/path/to-resource#with-hash'
const openURL = 'http://' + fqdnWithDnslink + sitePath
const expectedURL = gw.customUri.spec + 'ipns/' + fqdnWithDnslink + sitePath

dnsCache.put(fqdnWithDnslink, true) // mock: /api/v0/dns/ returned IPFS Path
assert.equal(api.isDnslinkPresent(fqdnWithDnslink), true, 'fqdnWithDnslink should return true')

const dnsPref = prefs.dns
prefs.dns = true
gw.redirectEnabled = true

tabs.open({
url: openURL,
onReady: function onReady (tab) {
assert.equal(tab.url, expectedURL, 'expected redirect')
prefs.dns = dnsPref
tab.close(done)
}
})
}

exports['test DNS Cache expiration'] = function (assert) {
const expired = Date.now() - 1000
const key = 'foo.test'
const value = true
dnsCache.put(key, value, expired)
assert.equal(dnsCache.get(key), value, 'dnsCache should be a map')
dnsCache.dropExpired()
assert.ok(typeof dnsCache.get(key) === 'undefined', 'dnsCache.dropExpired should drop regular key')
assert.equal(dnsCache.get('127.0.0.1'), false, 'special key should not be dropped')
assert.equal(dnsCache.get(prefs.customGatewayHost), false, 'special key should not be dropped')
}

require('sdk/test').run(exports)

0 comments on commit 49a00cc

Please sign in to comment.