110 lines
2.5 KiB
JavaScript
110 lines
2.5 KiB
JavaScript
|
'use strict'
|
||
|
|
||
|
var uuid = require('node-uuid')
|
||
|
, CombinedStream = require('combined-stream')
|
||
|
, isstream = require('isstream')
|
||
|
|
||
|
|
||
|
function Multipart (request) {
|
||
|
this.request = request
|
||
|
this.boundary = uuid()
|
||
|
this.chunked = false
|
||
|
this.body = null
|
||
|
}
|
||
|
|
||
|
Multipart.prototype.isChunked = function (options) {
|
||
|
var self = this
|
||
|
, chunked = false
|
||
|
, parts = options.data || options
|
||
|
|
||
|
if (!parts.forEach) {
|
||
|
self.request.emit('error', new Error('Argument error, options.multipart.'))
|
||
|
}
|
||
|
|
||
|
if (options.chunked !== undefined) {
|
||
|
chunked = options.chunked
|
||
|
}
|
||
|
|
||
|
if (self.request.getHeader('transfer-encoding') === 'chunked') {
|
||
|
chunked = true
|
||
|
}
|
||
|
|
||
|
if (!chunked) {
|
||
|
parts.forEach(function (part) {
|
||
|
if (typeof part.body === 'undefined') {
|
||
|
self.request.emit('error', new Error('Body attribute missing in multipart.'))
|
||
|
}
|
||
|
if (isstream(part.body)) {
|
||
|
chunked = true
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
return chunked
|
||
|
}
|
||
|
|
||
|
Multipart.prototype.setHeaders = function (chunked) {
|
||
|
var self = this
|
||
|
|
||
|
if (chunked && !self.request.hasHeader('transfer-encoding')) {
|
||
|
self.request.setHeader('transfer-encoding', 'chunked')
|
||
|
}
|
||
|
|
||
|
var header = self.request.getHeader('content-type')
|
||
|
|
||
|
if (!header || header.indexOf('multipart') === -1) {
|
||
|
self.request.setHeader('content-type', 'multipart/related; boundary=' + self.boundary)
|
||
|
} else {
|
||
|
if (header.indexOf('boundary') !== -1) {
|
||
|
self.boundary = header.replace(/.*boundary=([^\s;]+).*/, '$1')
|
||
|
} else {
|
||
|
self.request.setHeader('content-type', header + '; boundary=' + self.boundary)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Multipart.prototype.build = function (parts, chunked) {
|
||
|
var self = this
|
||
|
var body = chunked ? new CombinedStream() : []
|
||
|
|
||
|
function add (part) {
|
||
|
return chunked ? body.append(part) : body.push(new Buffer(part))
|
||
|
}
|
||
|
|
||
|
if (self.request.preambleCRLF) {
|
||
|
add('\r\n')
|
||
|
}
|
||
|
|
||
|
parts.forEach(function (part) {
|
||
|
var preamble = '--' + self.boundary + '\r\n'
|
||
|
Object.keys(part).forEach(function (key) {
|
||
|
if (key === 'body') { return }
|
||
|
preamble += key + ': ' + part[key] + '\r\n'
|
||
|
})
|
||
|
preamble += '\r\n'
|
||
|
add(preamble)
|
||
|
add(part.body)
|
||
|
add('\r\n')
|
||
|
})
|
||
|
add('--' + self.boundary + '--')
|
||
|
|
||
|
if (self.request.postambleCRLF) {
|
||
|
add('\r\n')
|
||
|
}
|
||
|
|
||
|
return body
|
||
|
}
|
||
|
|
||
|
Multipart.prototype.onRequest = function (options) {
|
||
|
var self = this
|
||
|
|
||
|
var chunked = self.isChunked(options)
|
||
|
, parts = options.data || options
|
||
|
|
||
|
self.setHeaders(chunked)
|
||
|
self.chunked = chunked
|
||
|
self.body = self.build(parts, chunked)
|
||
|
}
|
||
|
|
||
|
exports.Multipart = Multipart
|