Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81141 views
1
'use strict'
2
3
var uuid = require('node-uuid')
4
, CombinedStream = require('combined-stream')
5
, isstream = require('isstream')
6
7
8
function Multipart (request) {
9
this.request = request
10
this.boundary = uuid()
11
this.chunked = false
12
this.body = null
13
}
14
15
Multipart.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
46
Multipart.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
66
Multipart.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
98
Multipart.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
109
exports.Multipart = Multipart
110
111