You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					113 lines
				
				2.6 KiB
			
		
		
			
		
	
	
					113 lines
				
				2.6 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var uuid = require('uuid/v4')
							 | 
						||
| 
								 | 
							
								var CombinedStream = require('combined-stream')
							 | 
						||
| 
								 | 
							
								var isstream = require('isstream')
							 | 
						||
| 
								 | 
							
								var Buffer = require('safe-buffer').Buffer
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function Multipart (request) {
							 | 
						||
| 
								 | 
							
								  this.request = request
							 | 
						||
| 
								 | 
							
								  this.boundary = uuid()
							 | 
						||
| 
								 | 
							
								  this.chunked = false
							 | 
						||
| 
								 | 
							
								  this.body = null
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Multipart.prototype.isChunked = function (options) {
							 | 
						||
| 
								 | 
							
								  var self = this
							 | 
						||
| 
								 | 
							
								  var chunked = false
							 | 
						||
| 
								 | 
							
								  var 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) {
							 | 
						||
| 
								 | 
							
								    if (typeof part === 'number') {
							 | 
						||
| 
								 | 
							
								      part = part.toString()
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return chunked ? body.append(part) : body.push(Buffer.from(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)
							 | 
						||
| 
								 | 
							
								  var parts = options.data || options
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  self.setHeaders(chunked)
							 | 
						||
| 
								 | 
							
								  self.chunked = chunked
							 | 
						||
| 
								 | 
							
								  self.body = self.build(parts, chunked)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exports.Multipart = Multipart
							 |