[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for fs: URIs without redirecting to http: #70

Merged
merged 6 commits into from
Feb 14, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
support for fs: URIs without redirecting to http:
fixes #48
  • Loading branch information
the8472 committed Feb 14, 2016
commit 44c3a826b671b6e2fbc660aba778f2301a0cdbd2
6 changes: 6 additions & 0 deletions lib/gateways.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,9 @@ Object.defineProperty(exports, 'linkify', {
return prefs.linkify
}
})

Object.defineProperty(exports, 'fsUris', {
get: function () {
return prefs.fsUris
}
})
1 change: 1 addition & 0 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const parent = require('sdk/remote/parent')

exports.main = function (options, callbacks) { // eslint-disable-line no-unused-vars
require('./redirects.js')
require('./request-fix.js')
require('./peer-watch.js')
protocols.register()
parent.remoteRequire('./child-main.js', module)
Expand Down
85 changes: 65 additions & 20 deletions lib/protocols.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,39 @@ const HANDLERS = {
'web+ipns': WebIpnsProtocolHandler
}

/*
nsIURI does not not resolve relative paths properly
nsIStandardURL does, but always uses /// for authority-less URLs
thus we convert back and forth
*/
function resolveRelative (base, relative) {
let newBase = Cc['@mozilla.org/network/standard-url;1'].createInstance(Ci.nsIStandardURL)
newBase.QueryInterface(Ci.nsIURI)
newBase.init(Ci.nsIStandardURL.URLTYPE_NO_AUTHORITY, -1, base.spec, null, null)
let resolved = Cc['@mozilla.org/network/standard-url;1'].createInstance(Ci.nsIStandardURL)
resolved.init(Ci.nsIStandardURL.URLTYPE_NO_AUTHORITY, -1, relative, null, newBase)
resolved.QueryInterface(Ci.nsIURI)

// console.log("rel", base, relative, newBase, resolved)

return resolved.spec
}

CommonProtocolHandler.prototype = Object.freeze({
defaultPort: -1,
allowPort: function (port, scheme) { // eslint-disable-line no-unused-vars
return false
},

/*
since ipfs is a public network and pages could just embed their own js-ipfs code anyway to fetch the data
we allow any page to embed ipfs uris and waive CORS restrictions

TODO: consider adding URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT (discussion needed)
*/
protocolFlags: Ci.nsIProtocolHandler.URI_NOAUTH |
Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE |
Ci.nsIProtocolHandler.URI_FETCHABLE_BY_ANYONE,

normalizedIpfsPath: function (uriSpec) {
let schemeExp = this.scheme.replace(/\+/, '\\+') // fix for web+fs etc
Expand All @@ -56,41 +81,61 @@ CommonProtocolHandler.prototype = Object.freeze({

newURI: function (aSpec, aOriginCharset, aBaseURI) {
// console.info('Detected newURI with IPFS protocol: ' + aSpec)
// console.log(aSpec, aOriginCharset, aBaseURI && aBaseURI.spec)

if (aBaseURI && aBaseURI.scheme === this.scheme) {
// presence of aBaseURI means a dependent resource or a relative link
// and we need to return correct http URI
let http = gw.publicUri.spec + this.pathPrefix + aBaseURI.path
let base = ioservice.newURI(http, null, null)
let uri = ioservice.newURI(aSpec, aOriginCharset, base)
return uri
// resolve relative within the current protocol
// leave the decision to convert to http to the next steps
aSpec = resolveRelative(aBaseURI, aSpec)
}

/* Left for future use (if we enable channel.originalURI in newChannel method)
let uri = Cc['@mozilla.org/network/simple-uri;1'].createInstance(Ci.nsIURI)
uri.spec = aSpec
return uri
*/
let normalized = this.normalizedIpfsPath(aSpec)

// console.log("norm", normalized)

if (gw.fsUris && this.scheme === FS_SCHEME && new RegExp(`^${this.scheme}:`).test(aSpec)) {
let uri = Cc['@mozilla.org/network/simple-uri;1'].createInstance(Ci.nsIURI)
uri.spec = this.scheme + ':/' + normalized
return uri
}

let http = gw.publicUri.spec + this.normalizedIpfsPath(aSpec)
let uri = ioservice.newURI(http, aOriginCharset, null)
let uri = ioservice.newURI(normalized, aOriginCharset, gw.publicUri)

// console.info('newURI routed to HTTP gateway: ' + uri.spec)
return uri
},

newChannel: function (aURI) {
newChannel2: function (aURI, loadInfo) {
// console.info('Detected newChannel for IPFS protocol: ' + aURI.spec)
let http = gw.publicUri.spec + this.pathPrefix + aURI.path
let channel = ioservice.newChannel(http, aURI.originCharset, null)
let normalized = this.normalizedIpfsPath(this.pathPrefix + aURI.path)
let gwUri = gw.publicUri
let httpUri = ioservice.newURI(normalized, aURI.originCharset, gwUri)
let channel = null

if (loadInfo !== null) {
channel = ioservice.newChannelFromURIWithLoadInfo(httpUri, loadInfo)
} else {
channel = ioservice.newChannelFromURI(httpUri)
}

// line below would keep nice protocol URL in GUI
// but is disabled for now due to issues like
// https://github.com/lidel/ipfs-firefox-addon/issues/3
// channel.originalURI = aURI
if (gw.fsUris && this.scheme === FS_SCHEME) {
channel.originalURI = aURI
channel.loadFlags &= ~Ci.nsIChannel.LOAD_REPLACE
// channel.loadFlags |= Ci.nsIChannel.LOAD_ANONYMOUS
}

channel.loadInfo = loadInfo

channel.QueryInterface(Ci.nsIWritablePropertyBag)
channel.QueryInterface(Ci.nsIWritablePropertyBag2)
channel.setPropertyAsAString('ipfs-uri', aURI.spec)

// console.info('newChannel routed to HTTP gateway: ' + channel.URI.spec)
return channel
},
newChannel: function (aUri) {
return this.newChannel2(aUri, null)
}

})
Expand Down
49 changes: 49 additions & 0 deletions lib/request-fix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict'

const {Ci} = require('chrome')
const events = require('sdk/system/events')
const gw = require('./gateways.js')

/*
const catman = Cc['@mozilla.org/categorymanager;1'].getService(CI.nsICategoryManager)
// category ("net-channel-event-sinks")
catman.addCategoryEntry(in string aCategory, in string aEntry, in string aValue, in boolean aPersist, in boolean aReplace)
*/

function fixupRequest (e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@the8472 I am going over the backlog and trying to have a better understanding of this part of code. I see this is related to protocols.js#L121-L131 but can't infer full picture from code alone.

Could you elaborate what is the purpose of this fixup?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure if it's still necessary.

There were some cases with redirects coming from the server which needed the LOAD_REPLACE flag to be removed. If it is not removed the new channel's URI overrides originalURI which leads to a http URI in the address bar.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While implementing #72 I did some cleanup in c75a05d.

I did not notice any regressions, but would appreciate if you took a second look, perhaps I missed something.

if (e.type !== 'http-on-modify-request') {
return
}
if (!gw.fsUris) {
return
}
const channel = e.subject.QueryInterface(Ci.nsIHttpChannel)

channel.QueryInterface(Ci.nsIHttpChannelInternal)
channel.QueryInterface(Ci.nsIPropertyBag2)
channel.QueryInterface(Ci.nsIPropertyBag)

let isIpfsReq = null
try {
isIpfsReq = channel.hasKey('ipfs-uri')
} catch (e) {
// console.log(e)
}

if (isIpfsReq && channel.originalURI.scheme === 'fs') {
/*
// TODO: investigate effects of the following flags
// cookies make no sense in the ipfs context, we don't want to carry different gateway cookies into the page
channel.loadFlags |= Ci.nsIRequest.LOAD_ANONYMOUS
// should only do that for /ipfs/ paths since those are stable
channel.loadFlags |= Ci.nsIRequest.VALIDATE_NEVER
*/

// prevent redirects from replacing the effective URI
channel.loadFlags &= ~Ci.nsIChannel.LOAD_REPLACE

}

}

events.on('http-on-modify-request', fixupRequest)
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@
"title": "Extended IPFS Link Support",
"type": "bool",
"value": false
},
{
"name": "fsUris",
"title": "[Experimental] display fs:/ URIs as-is instead of rewriting to http://",
"type": "bool",
"value": false
}
],
"permissions": {
Expand Down
79 changes: 79 additions & 0 deletions test/test-canonical-fs-uris.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
'use strict'

const tabs = require('sdk/tabs')
const protocols = require('../lib/protocols.js')
const fsFactory = protocols.fs

protocols.register()

const fs = fsFactory.createInstance()
const gw = require('../lib/gateways.js')
const self = require('sdk/self')
const testpage = self.data.url('linkify-demo.html')
const sripage = 'fs:/ipfs/QmSrCRJmzE4zE1nAfWPbzVfanKQNBhp7ZWmMnEdbiLvYNh/mdown#sample.md'
const parent = require('sdk/remote/parent')

const childMain = require.resolve('../lib/child-main.js')

parent.remoteRequire(childMain)

const {Cc, Ci} = require('chrome')
const ioservice = Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService)

ioservice.newURI('fs:/ipns/foo', null, null)

exports['test newURI'] = function (assert) {
require('sdk/simple-prefs').prefs.fsUris = true

assert.equal(fs.newURI('fs:/ipns/foo', null, null).spec, 'fs:/ipns/foo', 'keeps fs:/ uris as-is')
}

exports['test newChannel'] = function (assert) {
require('sdk/simple-prefs').prefs.fsUris = true

let uri = fs.newURI('fs:///ipns/foo', null, null)
let chan = fs.newChannel(uri)

assert.equal(chan.originalURI.spec, 'fs:/ipns/foo', "keeps fs: URI as channel's originalURI")

// double and triple slashes lead to gateway redirects, which cause CORS troubles -> check normalization
assert.equal(chan.URI.spec, 'https://ipfs.io/ipns/foo', 'channel has normalized http urls')
}

// https://github.com/lidel/ipfs-firefox-addon/issues/3
exports['test subresource loading'] = function (assert, done) {
require('sdk/simple-prefs').prefs.fsUris = true
gw.redirectEnabled = false

tabs.open({
url: testpage,
onReady: (tab) => {

// first load somehow doesn't have protocol handlers registered. so load resource:// first, then redirect to fs:/ page
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is the same bug as in #33 (comment)
We probably need to do this workaround for now, hopefully it will be fixed in WebExtensions.

if (tab.url !== sripage) {
tab.url = sripage
tab.reload()
return
}

let worker = tab.attach({
contentScript: `
let obs = new MutationObserver(function(mutations) {
let result = (document.querySelector("#ipfs-markdown-reader") instanceof HTMLHeadingElement)
self.port.emit("test result", {result: result})
})
obs.observe(document.body,{childList: true})
`
})
worker.port.on('test result', (msg) => {
assert.equal(msg.result, true, 'subresource loaded successfully')

require('sdk/simple-prefs').prefs.fsUris = false
tab.close(done)
})
}
})
}

require('./prefs-util.js').isolateTestCases(exports)
require('sdk/test').run(exports)
4 changes: 3 additions & 1 deletion test/test-linkify.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ const tabs = require('sdk/tabs')
const parent = require('sdk/remote/parent')
const self = require('sdk/self')
const testpage = self.data.url('linkify-demo.html')
const prefs = require('sdk/simple-prefs').prefs

require('../lib/rewrite-pages.js')
parent.remoteRequire('resource://ipfs-firefox-addon-at-lidel-dot-org/lib/rewrite-pages.js')

exports['test link processing, plain text conversion'] = function (assert, done) {
require('sdk/simple-prefs').prefs.linkify = true
prefs.linkify = true
prefs.fsUris = true

tabs.open({
url: testpage,
Expand Down