Initial commit
[yaffs-website] / node_modules / request / lib / multipart.js
1 'use strict'
2
3 var uuid = require('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     if (typeof part === 'number') {
72       part = part.toString()
73     }
74     return chunked ? body.append(part) : body.push(new Buffer(part))
75   }
76
77   if (self.request.preambleCRLF) {
78     add('\r\n')
79   }
80
81   parts.forEach(function (part) {
82     var preamble = '--' + self.boundary + '\r\n'
83     Object.keys(part).forEach(function (key) {
84       if (key === 'body') { return }
85       preamble += key + ': ' + part[key] + '\r\n'
86     })
87     preamble += '\r\n'
88     add(preamble)
89     add(part.body)
90     add('\r\n')
91   })
92   add('--' + self.boundary + '--')
93
94   if (self.request.postambleCRLF) {
95     add('\r\n')
96   }
97
98   return body
99 }
100
101 Multipart.prototype.onRequest = function (options) {
102   var self = this
103
104   var chunked = self.isChunked(options)
105     , parts = options.data || options
106
107   self.setHeaders(chunked)
108   self.chunked = chunked
109   self.body = self.build(parts, chunked)
110 }
111
112 exports.Multipart = Multipart