UNPKG

2.56 kBJavaScriptView Raw
1'use strict'
2
3var uuid = require('node-uuid')
4 , CombinedStream = require('combined-stream')
5 , isstream = require('isstream')
6
7
8function Multipart (request) {
9 this.request = request
10 this.boundary = uuid()
11 this.chunked = false
12 this.body = null
13}
14
15Multipart.prototype.isChunked = function (options) {
16 var self = this
17 , chunked = false
18 , parts = options.data || options
19
20 if (!parts.forEach) {
21 self.request.emit('error', new Error('Argument error, options.multipart.'))
22 }
23
24 if (options.chunked !== undefined) {
25 chunked = options.chunked
26 }
27
28 if (self.request.getHeader('transfer-encoding') === 'chunked') {
29 chunked = true
30 }
31
32 if (!chunked) {
33 parts.forEach(function (part) {
34 if (typeof part.body === 'undefined') {
35 self.request.emit('error', new Error('Body attribute missing in multipart.'))
36 }
37 if (isstream(part.body)) {
38 chunked = true
39 }
40 })
41 }
42
43 return chunked
44}
45
46Multipart.prototype.setHeaders = function (chunked) {
47 var self = this
48
49 if (chunked && !self.request.hasHeader('transfer-encoding')) {
50 self.request.setHeader('transfer-encoding', 'chunked')
51 }
52
53 var header = self.request.getHeader('content-type')
54
55 if (!header || header.indexOf('multipart') === -1) {
56 self.request.setHeader('content-type', 'multipart/related; boundary=' + self.boundary)
57 } else {
58 if (header.indexOf('boundary') !== -1) {
59 self.boundary = header.replace(/.*boundary=([^\s;]+).*/, '$1')
60 } else {
61 self.request.setHeader('content-type', header + '; boundary=' + self.boundary)
62 }
63 }
64}
65
66Multipart.prototype.build = function (parts, chunked) {
67 var self = this
68 var body = chunked ? new CombinedStream() : []
69
70 function add (part) {
71 return chunked ? body.append(part) : body.push(new Buffer(part))
72 }
73
74 if (self.request.preambleCRLF) {
75 add('\r\n')
76 }
77
78 parts.forEach(function (part) {
79 var preamble = '--' + self.boundary + '\r\n'
80 Object.keys(part).forEach(function (key) {
81 if (key === 'body') { return }
82 preamble += key + ': ' + part[key] + '\r\n'
83 })
84 preamble += '\r\n'
85 add(preamble)
86 add(part.body)
87 add('\r\n')
88 })
89 add('--' + self.boundary + '--')
90
91 if (self.request.postambleCRLF) {
92 add('\r\n')
93 }
94
95 return body
96}
97
98Multipart.prototype.onRequest = function (options) {
99 var self = this
100
101 var chunked = self.isChunked(options)
102 , parts = options.data || options
103
104 self.setHeaders(chunked)
105 self.chunked = chunked
106 self.body = self.build(parts, chunked)
107}
108
109exports.Multipart = Multipart