Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

Commit

Permalink
Add symlink support
Browse files Browse the repository at this point in the history
  • Loading branch information
fbaiodias committed Mar 2, 2016
1 parent 58553cc commit 493f51b
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 99 deletions.
16 changes: 11 additions & 5 deletions lib/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ const Transform = stream.Transform

const multipartFormdataType = 'multipart/form-data'
const applicationDirectory = 'application/x-directory'
const applicationSymlink = 'application/symlink'

const isDirectory = (mediatype) => mediatype === multipartFormdataType || mediatype === applicationDirectory

const parseDisposition = (disposition) => {
const details = {}
details.type = disposition.split(';')[0]
if (details.type === 'file' || details.type === 'form-data') {
const fileNamePattern = /\ filename=\"(.[^\"]+)\"/
details.fileName = disposition.match(fileNamePattern)[1]
const namePattern = /\ filename=\"(.[^\"]+)\"/
details.name = disposition.match(namePattern)[1]
}

return details
Expand All @@ -27,7 +28,7 @@ const parseHeader = (header) => {
const disposition = parseDisposition(header['content-disposition'][0])

const details = type
details.fileName = disposition.fileName
details.name = disposition.name
details.type = disposition.type

return details
Expand Down Expand Up @@ -64,8 +65,13 @@ Parser.prototype.handlePart = function (part) {
const partHeader = parseHeader(header)

if (isDirectory(partHeader.mime)) {
// ignore directories
part.on('data', () => false)
this.emit('directory', partHeader.name)
return
}

if (partHeader.mime === applicationSymlink) {
part.on('data', (target) => this.emit('symlink', partHeader.name, target.toString()))
return
}

Expand All @@ -77,7 +83,7 @@ Parser.prototype.handlePart = function (part) {
return
}

this.emit('file', partHeader.fileName, part)
this.emit('file', partHeader.name, part)
})
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"homepage": "https://github.com/xicombd/ipfs-multipart#readme",
"devDependencies": {
"chai": "^3.5.0",
"ipfs-api": "github:xicombd/js-ipfs-api#a994abc",
"ipfs-api": "github:ipfs/js-ipfs-api#524ebfc",
"mocha": "^2.4.5",
"pre-commit": "^1.1.2",
"request": "^2.69.0",
Expand Down
84 changes: 1 addition & 83 deletions test/fixtures/config
Original file line number Diff line number Diff line change
@@ -1,87 +1,5 @@
{
"API": {
"HTTPHeaders": {
"Access-Control-Allow-Origin": [
"http://example.com"
]
}
},
"Addresses": {
"API": "/ip4/127.0.0.1/tcp/5001",
"Gateway": "/ip4/127.0.0.1/tcp/8080",
"Swarm": [
"/ip4/0.0.0.0/tcp/4001",
"/ip6/::/tcp/4001"
]
},
"Bootstrap": [
"/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z",
"/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM",
"/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm",
"/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu",
"/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64",
"/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd",
"/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3",
"/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx"
],
"Datastore": {
"GCPeriod": "",
"NoSync": false,
"Params": null,
"Path": "",
"StorageGCWatermark": 0,
"StorageMax": "",
"Type": ""
},
"Discovery": {
"MDNS": {
"Enabled": true,
"Interval": 10
}
},
"Gateway": {
"HTTPHeaders": null,
"RootRedirect": "",
"Writable": false
},
"Identity": {
"PeerID": "QmWTNDWjxEaLoaQSuotpM1gxvH9xixqFMCGt2ZPDLkL3rK",
"PrivKey": "CAASpwkwggSjAgEAAoIBAQCv0SnHZQhxaXyjX4RnuaHJB1wtlfW02aGMArfDuRIub1mjCgWoeszaaui5H7E8RPQWTfILiOKKd0JnKxdmDO3K0L87KPXqux0GnFGlz8ggxH/wyA7ej7+r//L0Y44H6PoPaP9zTO37zIBEjs/ssL0ZV5dmHiFCk20roGskcdJAgJyrScojLZGjEEK2BuH4+WZkeqJ1tyl1ukWseRKED3ROppY9G4fs+PbfNlybWuAZpe8QAs07zlX06py8I09lP0hcj8MwrXM8BqOPTSaJSldWIhSprziqwYJD6YDKZcCFEWvIO1a3yYS6Y0UuFohwzr8v8Wah67p/xxiVhFFDUd4fAgMBAAECggEAdZSnoS8jX12Rulzl2sydsyjV77KreQBW9qDWrvF1hFJ5mvzX3d4KZEQ9UZktWcYviz8jka1A/CNX6FE8O8aHvSyvx2vUUuBCQCqIvCBike94NNpGf3eZUvlATUrLMOURXv70X/Lh8ZTJb5Am4/8q5+jZWrTpv3GDADsvjFcGqpV77i3RQU9rVU1DkrVoqPGiEwIGOAIHeIgPX9n0ckhzHnMEHaaOdFnXy2YVl/iBEjxE2EAqQ+sUZX7odefew+kzu1gdWSxmeQ5U4dSmpC7UKYV2uUNE7OgoKadQ/EdKjwVTW664M76jUGj0yZcPOa1BKR6MoB3JKBJMvZ4/22QCgQKBgQDmrrKLVzhMb1upjOF8wAWrO/SJ/VSAMX5281v8uwxF7l2Pp0scB4FPx9KUmxeQmh380cp9vfHHH2HfSqXim5Qtn8VXI7mHdG4wNW3BmfktfS46+6juKr7clzXg21bWEZGa+Ed4hqe4xmbSH9ErsK9cQZzM7i4isKiZ6UcoXA/fwQKBgQDDHPTjvhID8AYP0YJ0vVh6+Bc0gxuZJfUNNxf6ekolQNTRbeZECGrguk9ohpFNt91Gda3X86EVkXZ1U7kOcnbWI5LXj+CtaHdZxdyQhTzwuLsHXmbW9eV4t+zPH+pmSyaxe1XWdLTDvZIma5F4Vqgm0f4BRkqwiMrQSDa/4us13wKBgGSqQaHKyveX9MEViGS/CvpBbKI22YQjlRNleXPdUCrILS3+DCnMIKLnCT7uOydQCdwE1L9wfyysxjIBykgMKmqKeTxgi5rPtTH2btH4ViOCqAT3Qy3Dm4x5s/pO3SMHganFxLKU2GYqtj3lwoq1TKEOxNUs7xcWTkzz3qh/HDJBAoGANBdSBk+jjauSYrzDwJkgu0vrHhj20E+C+jFAVJ47l3CUoQlfVcCNkEwNkVGED6TMDdizPhmMYy6/2pksqf/DXG6I8MY37PQcETqzJV59I6OeQ1xfxnpF9pHcRnw133Om8/GCvEvSSwQctec4IlG4eQzNbNewbytGQo9VFqvlsi8CgYEA5UEbCke1KKpzzuDxPWDgscbXQRGsXoWYWKIwiH7PSeEBCmcXm5aU/pkcBO/qudhOkTatgXFRARyq6loWXWFH703kgO+Voc2Cuh5ociWT65xquVyPDzO54PMGcwumefofLevvE+enNWTuuPljYFxeasD9Gyv1l7/ZDamcSM0n+uw="
},
"Ipns": {
"RecordLifetime": "",
"RepublishPeriod": "",
"ResolveCacheSize": 128
},
"Mounts": {
"FuseAllowOther": false,
"IPFS": "/ipfs",
"IPNS": "/ipns"
},
"SupernodeRouting": {
"Servers": [
"/ip4/104.236.176.52/tcp/4002/ipfs/QmXdb7tWTxdFEQEFgWBqkuYSrZd3mXrC7HxkD4krGNYx2U",
"/ip4/104.236.179.241/tcp/4002/ipfs/QmVRqViDByUxjUMoPnjurjKvZhaEMFDtK35FJXHAM4Lkj6",
"/ip4/104.236.151.122/tcp/4002/ipfs/QmSZwGx8Tn8tmcM4PtDJaMeUQNRhNFdBLVGPzRiNaRJtFH",
"/ip4/162.243.248.213/tcp/4002/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP",
"/ip4/128.199.219.111/tcp/4002/ipfs/Qmb3brdCYmKG1ycwqCbo6LUwWxTuo3FisnJV2yir7oN92R",
"/ip4/104.236.76.40/tcp/4002/ipfs/QmdRBCV8Cz2dGhoKLkD3YjPwVFECmqADQkx5ZteF2c6Fy4",
"/ip4/178.62.158.247/tcp/4002/ipfs/QmUdiMPci7YoEUBkyFZAh2pAbjqcPr7LezyiPD2artLw3v",
"/ip4/178.62.61.185/tcp/4002/ipfs/QmVw6fGNqBixZE4bewRLT2VXX7fAHUHs8JyidDiJ1P7RUN"
]
},
"Swarm": {
"AddrFilters": null
},
"Tour": {
"Last": ""
},
"Version": {
"AutoUpdate": "minor",
"Check": "error",
"CheckDate": "0001-01-01T00:00:00Z",
"CheckPeriod": "172800000000000",
"Current": "0.4.0-dev"
"HTTPHeaders": null
}
}
1 change: 1 addition & 0 deletions test/fixtures/folderlink
1 change: 1 addition & 0 deletions test/fixtures/link
2 changes: 1 addition & 1 deletion test/fixtures/otherfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
HELLO
OTHERFILE CONTENT
2 changes: 1 addition & 1 deletion test/fixtures/subfolder/deepfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SO DEEP
DEEPFILE CONTENT
43 changes: 35 additions & 8 deletions test/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,14 @@ describe('parser', () => {
describe('directory', () => {
const dirPath = path.resolve(__dirname, 'fixtures')

let files = []
let symlinks = []

before(() => {
handler = (req, cb) => {
expect(req.headers['content-type']).to.be.a('string')
const parser = IPFSMultipart.reqParser(req)

const files = []

parser.on('file', (fileName, fileStream) => {
const file = { fileName: fileName, content: '' }
fileStream.on('data', (data) => {
Expand All @@ -101,19 +102,45 @@ describe('parser', () => {
})
})

parser.on('end', () => {
expect(files.length).to.equal(3)
expect(files[0].fileName).to.contain('fixtures/config')
expect(files[1].fileName).to.equal('fixtures/otherfile')
expect(files[2].fileName).to.equal('fixtures/subfolder/deepfile')
cb()
parser.on('symlink', (fileName, target) => {
symlinks.push({ fileName: fileName, target: target })
})

parser.on('end', cb)
}
})

beforeEach(() => {
files = []
symlinks = []
})

it('parses ctl.add correctly', (done) => {
ctl.add(dirPath, { recursive: true, followSymlinks: false }, (err, res) => {
expect(err).to.not.exist

expect(files.length).to.equal(3)
expect(files[0].fileName).to.equal('fixtures/config')
expect(files[1].fileName).to.equal('fixtures/otherfile')
expect(files[2].fileName).to.equal('fixtures/subfolder/deepfile')

expect(symlinks.length).to.equal(2)
expect(symlinks[0].fileName).to.equal('fixtures/folderlink')
expect(symlinks[1].fileName).to.equal('fixtures/link')
expect(symlinks[0].target).to.equal('subfolder')
expect(symlinks[1].target).to.equal('subfolder/deepfile')

done()
})
})

it('parses ctl.add following symlinks correctly', (done) => {
ctl.add(dirPath, { recursive: true }, (err, res) => {
expect(err).to.not.exist

expect(files.length).to.equal(5)
expect(symlinks.length).to.equal(0)

done()
})
})
Expand Down

0 comments on commit 493f51b

Please sign in to comment.