mirror of https://github.com/lukechilds/node.git
Felix Geisendörfer
15 years ago
committed by
Ryan Dahl
2 changed files with 213 additions and 0 deletions
@ -0,0 +1,162 @@ |
|||||
|
exports.Stream = function(options) { |
||||
|
node.EventEmitter.call(this); |
||||
|
|
||||
|
this.init(options); |
||||
|
}; |
||||
|
node.inherits(exports.Stream, node.EventEmitter); |
||||
|
|
||||
|
|
||||
|
var proto = exports.Stream.prototype; |
||||
|
|
||||
|
proto.init = function(options) { |
||||
|
this.buffer = ''; |
||||
|
this.bytesReceived = 0; |
||||
|
this.bytesTotal = 0; |
||||
|
this.part = null; |
||||
|
|
||||
|
if ('headers' in options) { |
||||
|
var req = options, contentType = req.headers['Content-Type']; |
||||
|
if (contentType) { |
||||
|
contentType = contentType.split(/; ?boundary=/) |
||||
|
this.boundary = '--'+contentType[1]; |
||||
|
} |
||||
|
|
||||
|
this.bytesTotal = req.headers['Content-Length']; |
||||
|
|
||||
|
var self = this; |
||||
|
req |
||||
|
.addListener('body', function(chunk) { |
||||
|
req.pause(); |
||||
|
self.write(chunk); |
||||
|
setTimeout(function() { |
||||
|
req.resume(); |
||||
|
}); |
||||
|
}) |
||||
|
.addListener('complete', function() { |
||||
|
self.emit('complete'); |
||||
|
}); |
||||
|
} else { |
||||
|
this.boundary = options.boundary; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
proto.write = function(chunk) { |
||||
|
this.bytesReceived = this.bytesReceived + chunk.length; |
||||
|
this.buffer = this.buffer + chunk; |
||||
|
|
||||
|
while (this.buffer.length) { |
||||
|
var offset = this.buffer.indexOf(this.boundary); |
||||
|
|
||||
|
if (offset === 0) { |
||||
|
this.buffer = this.buffer.substr(offset + this.boundary.length + 2); |
||||
|
} else if (offset == -1) { |
||||
|
if (this.buffer === "\r\n") { |
||||
|
this.buffer = ''; |
||||
|
} else { |
||||
|
this.part = (this.part || new Part(this)); |
||||
|
this.part.write(this.buffer); |
||||
|
this.buffer = []; |
||||
|
} |
||||
|
} else if (offset > 0) { |
||||
|
this.part = (this.part || new Part(this)); |
||||
|
this.part.write(this.buffer.substr(0, offset - 2)); |
||||
|
|
||||
|
this.part.emit('complete'); |
||||
|
|
||||
|
this.part = new Part(this); |
||||
|
this.buffer = this.buffer.substr(offset + this.boundary.length + 2); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
function Part(stream) { |
||||
|
node.EventEmitter.call(this); |
||||
|
|
||||
|
this.headers = {}; |
||||
|
this.buffer = ''; |
||||
|
this.bytesReceived = 0; |
||||
|
|
||||
|
// Avoids turning Part into a circular JSON object
|
||||
|
this.getStream = function() { |
||||
|
return stream; |
||||
|
}; |
||||
|
|
||||
|
this._headersComplete = false; |
||||
|
} |
||||
|
node.inherits(Part, node.EventEmitter); |
||||
|
|
||||
|
Part.prototype.parsedHeaders = function() { |
||||
|
for (var header in this.headers) { |
||||
|
var parts = this.headers[header].split(/; ?/), parsedHeader = {}; |
||||
|
for (var i = 0; i < parts.length; i++) { |
||||
|
var pair = parts[i].split('='); |
||||
|
if (pair.length < 2) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
var key = pair[0].toLowerCase(), val = pair[1] || ''; |
||||
|
val = stripslashes(val).substr(1); |
||||
|
val = val.substr(0, val.length - 1); |
||||
|
|
||||
|
parsedHeader[key] = val; |
||||
|
} |
||||
|
this.headers[header] = parsedHeader; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
Part.prototype.write = function(chunk) { |
||||
|
if (this._headersComplete) { |
||||
|
this.bytesReceived = this.bytesReceived + chunk.length; |
||||
|
this.emit('body', chunk); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.buffer = this.buffer + chunk; |
||||
|
while (this.buffer.length) { |
||||
|
var offset = this.buffer.indexOf("\r\n"); |
||||
|
|
||||
|
if (offset === 0) { |
||||
|
this._headersComplete = true; |
||||
|
this.parsedHeaders(); |
||||
|
this.getStream().emit('part', this); |
||||
|
|
||||
|
this.buffer = this.buffer.substr(2); |
||||
|
this.bytesReceived = this.bytesReceived + this.buffer.length; |
||||
|
this.emit('body', this.buffer); |
||||
|
return; |
||||
|
} else if (offset > 0) { |
||||
|
var header = this.buffer.substr(0, offset).split(/: ?/); |
||||
|
this.headers[header[0]] = header[1]; |
||||
|
this.buffer = this.buffer.substr(offset+2); |
||||
|
} else if (offset === false) { |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
function stripslashes(str) { |
||||
|
// + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
||||
|
// + improved by: Ates Goral (http://magnetiq.com)
|
||||
|
// + fixed by: Mick@el
|
||||
|
// + improved by: marrtins
|
||||
|
// + bugfixed by: Onno Marsman
|
||||
|
// + improved by: rezna
|
||||
|
// + input by: Rick Waldron
|
||||
|
// + reimplemented by: Brett Zamir (http://brett-zamir.me)
|
||||
|
// * example 1: stripslashes('Kevin\'s code');
|
||||
|
// * returns 1: "Kevin's code"
|
||||
|
// * example 2: stripslashes('Kevin\\\'s code');
|
||||
|
// * returns 2: "Kevin\'s code"
|
||||
|
return (str+'').replace(/\\(.?)/g, function (s, n1) { |
||||
|
switch(n1) { |
||||
|
case '\\': |
||||
|
return '\\'; |
||||
|
case '0': |
||||
|
return '\0'; |
||||
|
case '': |
||||
|
return ''; |
||||
|
default: |
||||
|
return n1; |
||||
|
} |
||||
|
}); |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
include("common.js"); |
||||
|
|
||||
|
var multipart = require('/multipart.js'); |
||||
|
var port = 8222; |
||||
|
var parts_reveived = 0; |
||||
|
var parts_complete = 0; |
||||
|
var parts = {}; |
||||
|
|
||||
|
var server = node.http.createServer(function(req, res) { |
||||
|
var stream = new multipart.Stream(req); |
||||
|
|
||||
|
stream.addListener('part', function(part) { |
||||
|
parts_reveived++; |
||||
|
|
||||
|
var name = part.headers['Content-Disposition'].name; |
||||
|
|
||||
|
if (parts_reveived == 1) { |
||||
|
assertEquals('test-field', name); |
||||
|
} else if (parts_reveived == 2) { |
||||
|
assertEquals('test-file', name); |
||||
|
} |
||||
|
|
||||
|
parts[name] = ''; |
||||
|
part.addListener('body', function(chunk) { |
||||
|
parts[name] += chunk; |
||||
|
}); |
||||
|
part.addListener('complete', function(chunk) { |
||||
|
if (parts_reveived == 1) { |
||||
|
assertEquals('foobar', parts[name]); |
||||
|
} else if (parts_reveived == 2) { |
||||
|
assertEquals(node.fs.cat(__filename).wait(), parts[name]); |
||||
|
} |
||||
|
parts_complete++; |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
stream.addListener('complete', function() { |
||||
|
res.sendHeader(200, {"Content-Type": "text/plain"}); |
||||
|
res.sendBody('thanks'); |
||||
|
res.finish(); |
||||
|
server.close(); |
||||
|
}); |
||||
|
}); |
||||
|
server.listen(port); |
||||
|
|
||||
|
var cmd = 'curl -H "Expect:" -F "test-field=foobar" -F test-file=@'+__filename+' http://localhost:'+port+'/'; |
||||
|
var result = node.exec(cmd).wait(); |
||||
|
|
||||
|
process.addListener('exit', function() { |
||||
|
assertEquals(2, parts_complete); |
||||
|
}); |
Loading…
Reference in new issue