Skip to content
This repository was archived by the owner on Apr 29, 2020. It is now read-only.
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ipfs-inactive/js-ipfs-multipart
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: edc2f725fcaabd65d2d4f443997971bede60501f
Choose a base ref
...
head repository: ipfs-inactive/js-ipfs-multipart
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 81b7ffe9718b7022feffe8902c38b946376f8036
Choose a head ref
  • 4 commits
  • 9 files changed
  • 2 contributors

Commits on Aug 27, 2019

  1. chore: refactor to async/await (#17)

    BREAKING CHANGE: This module used to export a class that extended EventEmitter,
    now it exports a function that returns an async iterable.
    
    I also updated the deps to use the latest http api, though it's removed
    the ability to add whole paths at once, along with some special logic
    to handle symlinks.  The `Dicer` module that this module depends on
    will still emit events for when it encounters symlinks so I left the
    handlers in though am unsure if we actually use them.
    achingbrain authored and hugomrdias committed Aug 27, 2019
    Copy the full SHA
    55d926e View commit details
  2. Unverified

    This user has not yet uploaded their public signing key.
    Copy the full SHA
    c75bd13 View commit details
  3. chore: update contributors

    hugomrdias committed Aug 27, 2019

    Unverified

    This user has not yet uploaded their public signing key.
    Copy the full SHA
    0c785db View commit details
  4. Unverified

    This user has not yet uploaded their public signing key.
    Copy the full SHA
    81b7ffe View commit details
Showing with 333 additions and 336 deletions.
  1. +22 −0 CHANGELOG.md
  2. +21 −18 README.md
  3. +15 −23 example.js
  4. +4 −3 package.json
  5. +12 −15 src/index.js
  6. +50 −53 src/parser.js
  7. +0 −14 test/node.js
  8. +0 −210 test/parser.js
  9. +209 −0 test/parser.spec.js
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
<a name="0.2.0"></a>
# [0.2.0](https://github.com/ipfs/js-ipfs-multipart/compare/v0.1.1...v0.2.0) (2019-08-27)


### Chores

* refactor to async/await ([#17](https://github.com/ipfs/js-ipfs-multipart/issues/17)) ([55d926e](https://github.com/ipfs/js-ipfs-multipart/commit/55d926e))


### BREAKING CHANGES

* This module used to export a class that extended EventEmitter,
now it exports a function that returns an async iterable.

I also updated the deps to use the latest http api, though it's removed
the ability to add whole paths at once, along with some special logic
to handle symlinks. The `Dicer` module that this module depends on
will still emit events for when it encounters symlinks so I left the
handlers in though am unsure if we actually use them.



<a name="0.1.1"></a>
## [0.1.1](https://github.com/ipfs/js-ipfs-multipart/compare/v0.1.0...v0.1.1) (2019-07-12)

39 changes: 21 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -19,6 +19,10 @@ ipfs-multipart

[Hugo Dias](https://github.com/hugomrdias)

### Notice
> This module is moving to async iterators starting from 0.2.0.
> The last minor version to support event emitter is 0.1.1, any backports will merged to the branch `event-emitter` and released under `>0.1.0 <0.2.0`.
## Install
```
npm install ipfs-multipart
@@ -27,31 +31,30 @@ npm install ipfs-multipart
## Usage
```javascript
const http = require('http')
const IPFSMultipart = require('ipfs-multipart')
const parser = require('ipfs-multipart')

http.createServer((req, res) => {
http.createServer(async (req, res) => {
if (req.method === 'POST' && req.headers['content-type']) {
const parser = IPFSMultipart.reqParser(req)

parser.on('file', (fileName, fileStream) => {
console.log(`file ${fileName} start`)
for await (const entry of parser(req)) {
if (entry.type === 'directory') {
console.log(`dir ${entry.name} start`)
}

fileStream.on('data', (data) => {
console.log(`file ${fileName} contents:`, data.toString())
})
if (entry.type === 'file') {
console.log(`file ${entry.name} start`)

fileStream.on('end', (data) => {
console.log(`file ${fileName} end`)
})
})
for await (const data of entry.content) {
console.log(`file ${entry.name} contents:`, data.toString())
}

parser.on('end', () => {
console.log('finished parsing')
res.writeHead(200)
res.end()
})
console.log(`file ${entry.name} end`)
}
}

return
console.log('finished parsing')
res.writeHead(200)
res.end()
}

res.writeHead(404)
38 changes: 15 additions & 23 deletions example.js
Original file line number Diff line number Diff line change
@@ -3,31 +3,23 @@
/* eslint-disable no-console */

const http = require('http')
const IPFSMultipart = require('.')
const multipart = require('ipfs-multipart')

http.createServer((req, res) => {
http.createServer(async (req, res) => {
if (req.method === 'POST' && req.headers['content-type']) {
const parser = IPFSMultipart.reqParser(req)

parser.on('file', (fileName, fileStream) => {
console.log(`file ${fileName} start`)

fileStream.on('data', (data) => {
console.log(`file ${fileName} contents:`, data.toString())
})

fileStream.on('end', (data) => {
console.log(`file ${fileName} end`)
})
})

parser.on('end', () => {
console.log('finished parsing')
res.writeHead(200)
res.end()
})

return
for await (const part of multipart(req)) {
console.log(`file ${part.name} start`)

if (part.type === 'file') {
for await (const chunk of part.content) {
console.log(`file ${part.name} contents:`, chunk.toString())
}
}
}

console.log('finished parsing')
res.writeHead(200)
res.end()
}

res.writeHead(404)
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ipfs-multipart",
"version": "0.1.1",
"version": "0.2.0",
"description": "A set of utilities to help dealing with IPFS multipart.",
"keywords": [
"ipfs",
@@ -27,12 +27,12 @@
},
"dependencies": {
"@hapi/content": "^4.1.0",
"dicer": "~0.3.0"
"it-multipart": "~0.0.2"
},
"devDependencies": {
"aegir": "^20.0.0",
"chai": "^4.2.0",
"ipfs-api": "github:ipfs/js-ipfs-api#1fd9749",
"ipfs-http-client": "^33.1.1",
"request": "^2.88.0"
},
"engines": {
@@ -41,6 +41,7 @@
},
"contributors": [
"Alan Shaw <alan.shaw@protocol.ai>",
"Alex Potsides <alex@achingbrain.net>",
"Francisco Baio Dias <xicombd@gmail.com>",
"Hugo Dias <hugomrdias@gmail.com>",
"Hugo Dias <mail@hugodias.me>",
27 changes: 12 additions & 15 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
'use strict'

const content = require('@hapi/content')
const Parser = require('./parser')
const parser = require('./parser')

module.exports = {
Parser,
/**
* Request Parser
*
* @param {Object} req - Request
* @returns {Parser}
*/
reqParser: (req) => {
const boundary = content.type(req.headers['content-type']).boundary
const parser = new Parser({ boundary: boundary })
req.pipe(parser)
return parser
}
/**
* Request Parser
*
* @param {Object} req - Request
* @param {Object} options - Options passed to stream constructors
* @returns {Object} an async iterable
*/
module.exports = (req, options = {}) => {
options.boundary = content.type(req.headers['content-type']).boundary

return parser(req.payload || req, options)
}
103 changes: 50 additions & 53 deletions src/parser.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
'use strict'

const Dicer = require('dicer')
const Content = require('@hapi/content')
const stream = require('stream')
const util = require('util')
const Transform = stream.Transform
const multipart = require('it-multipart')

const multipartFormdataType = 'multipart/form-data'
const applicationDirectory = 'application/x-directory'
@@ -25,79 +22,79 @@ const parseDisposition = (disposition) => {
}

const parseHeader = (header) => {
const type = Content.type(header['content-type'][0])
const disposition = parseDisposition(header['content-disposition'][0])
const type = Content.type(header['content-type'])
const disposition = parseDisposition(header['content-disposition'])

const details = type
details.name = disposition.name
details.name = decodeURIComponent(disposition.name)
details.type = disposition.type

return details
}

/**
* Parser
*
* @constructor
* @param {Object} options
* @returns {Parser}
*/
function Parser (options) {
// allow use without new
if (!(this instanceof Parser)) {
return new Parser(options)
}

this.dicer = new Dicer({ boundary: options.boundary })

this.dicer.on('part', (part) => this.handlePart(part))

this.dicer.on('error', (err) => this.emit('err', err))
const collect = async (stream) => {
const buffers = []
let size = 0

this.dicer.on('finish', () => {
this.emit('finish')
this.emit('end')
})
for await (const buf of stream) {
size += buf.length
buffers.push(buf)
}

Transform.call(this, options)
return Buffer.concat(buffers, size)
}
util.inherits(Parser, Transform)

Parser.prototype._transform = function (chunk, enc, cb) {
this.dicer.write(chunk, enc)
cb()
}
const ignore = async (stream) => {
for await (const _ of stream) { // eslint-disable-line no-unused-vars

Parser.prototype._flush = function (cb) {
this.dicer.end()
cb()
}
}

Parser.prototype.handlePart = function (part) {
part.on('header', (header) => {
const partHeader = parseHeader(header)
async function * parser (stream, options) {
for await (const part of multipart(stream, options.boundary)) {
const partHeader = parseHeader(part.headers)

if (isDirectory(partHeader.mime)) {
part.on('data', () => false)
this.emit('directory', partHeader.name)
return
yield {
type: 'directory',
name: partHeader.name
}

await ignore(part.body)

continue
}

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

yield {
type: 'symlink',
name: partHeader.name,
target: target.toString('utf8')
}

continue
}

if (partHeader.boundary) {
// recursively parse nested multiparts
const parser = new Parser({ boundary: partHeader.boundary })
parser.on('file', (file) => this.emit('file', file))
part.pipe(parser)
return
for await (const entry of parser(part, {
...options,
boundary: partHeader.boundary
})) {
yield entry
}

continue
}

this.emit('file', partHeader.name, part)
})
yield {
type: 'file',
name: partHeader.name,
content: part.body
}
}
}

module.exports = Parser
module.exports = parser
14 changes: 0 additions & 14 deletions test/node.js

This file was deleted.

Loading