Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

remove multipart, limit, and staticCache middleware

  • Loading branch information...
commit ec30812d59efdb2f11a81302e952272752c49be1 1 parent ff0e3a9
jongleberry jonathanong authored
40 examples/bodyParser.js
View
@@ -1,40 +0,0 @@
-
-var connect = require('../')
- , http = require('http');
-
-// visit form.html
-
-var app = connect()
- .use(connect.static(__dirname + '/public'))
- .use(connect.bodyParser())
- .use(form)
- .use(upload);
-
-function form(req, res, next){
- if ('GET' != req.method) return next();
- res.statusCode = 302;
- res.setHeader('Location', 'form.html');
- res.end();
-}
-
-function upload(req, res){
- res.setHeader('Content-Type', 'text/html');
- res.write('<p>thanks ' + req.body.name + '</p>');
- res.write('<ul>');
-
- if (Array.isArray(req.files.images)) {
- req.files.images.forEach(function(image){
- var kb = image.size / 1024 | 0;
- res.write('<li>uploaded ' + image.name + ' ' + kb + 'kb</li>');
- });
- } else {
- var image = req.files.images;
- var kb = image.size / 1024 | 0;
- res.write('<li>uploaded ' + image.name + ' ' + kb + 'kb</li>');
- }
-
- res.end('</ul>');
-}
-
-http.Server(app).listen(3000);
-console.log('Server started on port 3000');
41 examples/limit.js
View
@@ -1,41 +0,0 @@
-
-var connect = require('../')
- , http = require('http');
-
-// visit form.html
-
-var app = connect()
- .use(connect.static(__dirname + '/public'))
- .use(connect.limit('5mb'))
- .use(connect.bodyParser())
- .use(form)
- .use(upload);
-
-function form(req, res, next){
- if ('GET' != req.method) return next();
- res.statusCode = 302;
- res.setHeader('Location', 'form.html');
- res.end();
-}
-
-function upload(req, res){
- res.setHeader('Content-Type', 'text/html');
- res.write('<p>thanks ' + req.body.name + '</p>');
- res.write('<ul>');
-
- if (Array.isArray(req.files.images)) {
- req.files.images.forEach(function(image){
- var kb = image.size / 1024 | 0;
- res.write('<li>uploaded ' + image.name + ' ' + kb + 'kb</li>');
- });
- } else {
- var image = req.files.images;
- var kb = image.size / 1024 | 0;
- res.write('<li>uploaded ' + image.name + ' ' + kb + 'kb</li>');
- }
-
- res.end('</ul>');
-}
-
-http.Server(app).listen(3000);
-console.log('Server started on port 3000');
5 examples/public/form.html
View
@@ -1,5 +0,0 @@
-<form action="/" method="post" enctype="multipart/form-data">
- <input type="text" name="name" placeholder="Name:" />
- <input type="file" name="images" multiple="multiple" />
- <input type="submit" value="Upload" />
-</form>
37 examples/upload-stream.js
View
@@ -1,37 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../');
-var fs = require('fs');
-
-connect()
- .use(connect.bodyParser({ defer: true }))
- .use(form)
- .use(upload)
- .listen(3000);
-
-function form(req, res, next) {
- if ('GET' !== req.method) return next();
- res.setHeader('Content-Type', 'text/html');
- res.end('<form method="post" enctype="multipart/form-data">'
- + '<input type="file" name="images" multiple="multiple" />'
- + '<input type="submit" value="Upload" />'
- + '</form>');
-}
-
-function upload(req, res, next) {
- if ('POST' !== req.method) return next();
-
- req.form.on('part', function(part){
- // transfer to s3 etc
- console.log('upload %s %s', part.name, part.filename);
- var out = fs.createWriteStream('/tmp/' + part.filename);
- part.pipe(out);
- });
-
- req.form.on('close', function(){
- res.end('uploaded!');
- });
-}
29 examples/upload.js
View
@@ -1,29 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../');
-
-connect()
- .use(connect.bodyParser())
- .use(form)
- .use(upload)
- .listen(3000);
-
-function form(req, res, next) {
- if ('GET' !== req.method) return next();
- res.setHeader('Content-Type', 'text/html');
- res.end('<form method="post" enctype="multipart/form-data">'
- + '<input type="file" name="images" multiple="multiple" />'
- + '<input type="submit" value="Upload" />'
- + '</form>');
-}
-
-function upload(req, res, next) {
- if ('POST' !== req.method) return next();
- req.files.images.forEach(function(file){
- console.log(' uploaded : %s %skb : %s', file.originalFilename, file.size / 1024 | 0, file.path);
- });
- res.end('Thanks');
-}
15 lib/middleware/bodyParser.js
View
@@ -10,9 +10,8 @@
* Module dependencies.
*/
-var multipart = require('./multipart')
- , urlencoded = require('./urlencoded')
- , json = require('./json');
+var urlencoded = require('./urlencoded');
+var json = require('./json');
/**
* Body parser:
@@ -52,17 +51,13 @@ var multipart = require('./multipart')
*/
exports = module.exports = function bodyParser(options){
- var _urlencoded = urlencoded(options)
- , _multipart = multipart(options)
- , _json = json(options);
+ var _urlencoded = urlencoded(options);
+ var _json = json(options);
return function bodyParser(req, res, next) {
_json(req, res, function(err){
if (err) return next(err);
- _urlencoded(req, res, function(err){
- if (err) return next(err);
- _multipart(req, res, next);
- });
+ _urlencoded(req, res, next);
});
}
};
89 lib/middleware/limit.js
View
@@ -1,89 +0,0 @@
-
-/*!
- * Connect - limit
- * Copyright(c) 2011 TJ Holowaychuk
- * MIT Licensed
- */
-
-/**
- * Module dependencies.
- */
-
-var utils = require('../utils'),
- brokenPause = utils.brokenPause;
-
-/**
- * Limit:
- *
- * Status: Deprecated. This middleware will be removed in Connect 3.0.
- * If you still wish to use some type of limit middleware,
- * you may be interested in:
- *
- * - [raw-body](https://github.com/stream-utils/raw-body)
- *
- * Limit request bodies to the given size in `bytes`.
- *
- * A string representation of the bytesize may also be passed,
- * for example "5mb", "200kb", "1gb", etc.
- *
- * connect()
- * .use(connect.limit('5.5mb'))
- * .use(handleImageUpload)
- *
- * @param {Number|String} bytes
- * @return {Function}
- * @api public
- */
-
-module.exports = function limit(bytes){
- if ('string' == typeof bytes) bytes = utils.parseBytes(bytes);
- if ('number' != typeof bytes) throw new Error('limit() bytes required');
-
- if (process.env.NODE_ENV !== 'test') {
- console.warn('connect.limit() will be removed in connect 3.0');
- }
-
- return function limit(req, res, next){
- var received = 0
- , len = req.headers['content-length']
- ? parseInt(req.headers['content-length'], 10)
- : null;
-
- // self-awareness
- if (req._limit) return next();
- req._limit = true;
-
- // limit by content-length
- if (len && len > bytes) return next(utils.error(413));
-
- // limit
- if (brokenPause) {
- listen();
- } else {
- req.on('newListener', function handler(event) {
- if (event !== 'data') return;
-
- req.removeListener('newListener', handler);
- // Start listening at the end of the current loop
- // otherwise the request will be consumed too early.
- // Sideaffect is `limit` will miss the first chunk,
- // but that's not a big deal.
- // Unfortunately, the tests don't have large enough
- // request bodies to test this.
- process.nextTick(listen);
- });
- };
-
- next();
-
- function listen() {
- req.on('data', function(chunk) {
- received += Buffer.isBuffer(chunk)
- ? chunk.length :
- Buffer.byteLength(chunk);
-
- if (received > bytes) req.destroy();
- });
- };
- };
-};
171 lib/middleware/multipart.js
View
@@ -1,171 +0,0 @@
-/*!
- * Connect - multipart
- * Copyright(c) 2010 Sencha Inc.
- * Copyright(c) 2011 TJ Holowaychuk
- * MIT Licensed
- */
-
-/**
- * Module dependencies.
- */
-
-var multiparty = require('multiparty')
- , _limit = require('./limit')
- , utils = require('../utils')
- , qs = require('qs');
-
-/**
- * Multipart:
- *
- * Status: Deprecated. The multipart parser will be removed in Connect 3.0.
- * Please use one of the following parsers/middleware directly:
- *
- * - [formidable](https://github.com/felixge/node-formidable)
- * - [connect-multiparty](https://github.com/superjoe30/connect-multiparty) or [multiparty]
- * - [connect-busboy](https://github.com/mscdex/connect-busboy) or [busboy](https://github.com/mscdex/busboy)
- *
- * Parse multipart/form-data request bodies,
- * providing the parsed object as `req.body`
- * and `req.files`.
- *
- * Configuration:
- *
- * The options passed are merged with [multiparty](https://github.com/superjoe30/node-multiparty)'s
- * `Form` object, allowing you to configure the upload directory,
- * size limits, etc. For example if you wish to change the upload dir do the following.
- *
- * app.use(connect.multipart({ uploadDir: path }));
- *
- * Options:
- *
- * - `limit` byte limit defaulting to [100mb]
- * - `defer` defers processing and exposes the multiparty form object as `req.form`.
- * `next()` is called without waiting for the form's "end" event.
- * This option is useful if you need to bind to the "progress" or "part" events, for example.
- *
- * Temporary Files:
- *
- * By default temporary files are used, stored in `os.tmpDir()`. These
- * are not automatically garbage collected, you are in charge of moving them
- * or deleting them. When `defer` is not used and these files are created you
- * may refernce them via the `req.files` object.
- *
- * req.files.images.forEach(function(file){
- * console.log(' uploaded : %s %skb : %s', file.originalFilename, file.size / 1024 | 0, file.path);
- * });
- *
- * It is highly recommended to monitor and clean up tempfiles in any production
- * environment, you may use tools like [reap](https://github.com/visionmedia/reap)
- * to do so.
- *
- * Streaming:
- *
- * When `defer` is used files are _not_ streamed to tmpfiles, you may
- * access them via the "part" events and stream them accordingly:
- *
- * req.form.on('part', function(part){
- * // transfer to s3 etc
- * console.log('upload %s %s', part.name, part.filename);
- * var out = fs.createWriteStream('/tmp/' + part.filename);
- * part.pipe(out);
- * });
- *
- * req.form.on('close', function(){
- * res.end('uploaded!');
- * });
- *
- * @param {Object} options
- * @return {Function}
- * @api public
- */
-
-exports = module.exports = function(options){
- options = options || {};
-
- if (process.env.NODE_ENV !== 'test') {
- console.warn('connect.multipart() will be removed in connect 3.0');
- console.warn('visit https://github.com/senchalabs/connect/wiki/Connect-3.0 for alternatives');
- }
-
- var limit = _limit(options.limit || '100mb');
-
- return function multipart(req, res, next) {
- if (req._body) return next();
- req.body = req.body || {};
- req.files = req.files || {};
-
- if (!utils.hasBody(req)) return next();
-
- // ignore GET
- if ('GET' == req.method || 'HEAD' == req.method) return next();
-
- // check Content-Type
- if ('multipart/form-data' != utils.mime(req)) return next();
-
- // flag as parsed
- req._body = true;
-
- // parse
- limit(req, res, function(err){
- if (err) return next(err);
-
- var form = new multiparty.Form(options)
- , data = {}
- , files = {}
- , done;
-
- Object.keys(options).forEach(function(key){
- form[key] = options[key];
- });
-
- function ondata(name, val, data){
- if (Array.isArray(data[name])) {
- data[name].push(val);
- } else if (data[name]) {
- data[name] = [data[name], val];
- } else {
- data[name] = val;
- }
- }
-
- form.on('field', function(name, val){
- ondata(name, val, data);
- });
-
- if (!options.defer) {
- form.on('file', function(name, val){
- val.name = val.originalFilename;
- val.type = val.headers['content-type'] || null;
- ondata(name, val, files);
- });
- }
-
- form.on('error', function(err){
- if (!options.defer) {
- err.status = 400;
- next(err);
- }
- done = true;
- });
-
- form.on('close', function(){
- if (done) return;
- try {
- req.body = qs.parse(data);
- req.files = qs.parse(files);
- } catch (err) {
- form.emit('error', err);
- return;
- }
- if (!options.defer) next();
- });
-
- form.parse(req);
-
- if (options.defer) {
- req.form = form;
- next();
- }
- });
- }
-};
238 lib/middleware/staticCache.js
View
@@ -1,238 +0,0 @@
-
-/*!
- * Connect - staticCache
- * Copyright(c) 2011 Sencha Inc.
- * MIT Licensed
- */
-
-/**
- * Module dependencies.
- */
-
-var utils = require('../utils')
- , Cache = require('../cache')
- , fresh = require('fresh');
-
-/**
- * Static cache:
- *
- * Status: Deprecated. This middleware will be removed in
- * Connect 3.0. You may be interested in:
- *
- * - [st](https://github.com/isaacs/st)
- *
- * Enables a memory cache layer on top of
- * the `static()` middleware, serving popular
- * static files.
- *
- * By default a maximum of 128 objects are
- * held in cache, with a max of 256k each,
- * totalling ~32mb.
- *
- * A Least-Recently-Used (LRU) cache algo
- * is implemented through the `Cache` object,
- * simply rotating cache objects as they are
- * hit. This means that increasingly popular
- * objects maintain their positions while
- * others get shoved out of the stack and
- * garbage collected.
- *
- * Benchmarks:
- *
- * static(): 2700 rps
- * node-static: 5300 rps
- * static() + staticCache(): 7500 rps
- *
- * Options:
- *
- * - `maxObjects` max cache objects [128]
- * - `maxLength` max cache object length 256kb
- *
- * @param {Object} options
- * @return {Function}
- * @api public
- */
-
-module.exports = function staticCache(options){
- var options = options || {}
- , cache = new Cache(options.maxObjects || 128)
- , maxlen = options.maxLength || 1024 * 256;
-
- if (process.env.NODE_ENV !== 'test') {
- console.warn('connect.staticCache() is deprecated and will be removed in 3.0');
- console.warn('use varnish or similar reverse proxy caches.');
- }
-
- return function staticCache(req, res, next){
- var key = cacheKey(req)
- , ranges = req.headers.range
- , hasCookies = req.headers.cookie
- , hit = cache.get(key);
-
- // cache static
- // TODO: change from staticCache() -> cache()
- // and make this work for any request
- req.on('static', function(stream){
- var headers = res._headers
- , cc = utils.parseCacheControl(headers['cache-control'] || '')
- , contentLength = headers['content-length']
- , hit;
-
- // dont cache set-cookie responses
- if (headers['set-cookie']) return hasCookies = true;
-
- // dont cache when cookies are present
- if (hasCookies) return;
-
- // ignore larger files
- if (!contentLength || contentLength > maxlen) return;
-
- // don't cache partial files
- if (headers['content-range']) return;
-
- // dont cache items we shouldn't be
- // TODO: real support for must-revalidate / no-cache
- if ( cc['no-cache']
- || cc['no-store']
- || cc['private']
- || cc['must-revalidate']) return;
-
- // if already in cache then validate
- if (hit = cache.get(key)){
- if (headers.etag == hit[0].etag) {
- hit[0].date = new Date;
- return;
- } else {
- cache.remove(key);
- }
- }
-
- // validation notifiactions don't contain a steam
- if (null == stream) return;
-
- // add the cache object
- var arr = [];
-
- // store the chunks
- stream.on('data', function(chunk){
- arr.push(chunk);
- });
-
- // flag it as complete
- stream.on('end', function(){
- var cacheEntry = cache.add(key);
- delete headers['x-cache']; // Clean up (TODO: others)
- cacheEntry.push(200);
- cacheEntry.push(headers);
- cacheEntry.push.apply(cacheEntry, arr);
- });
- });
-
- if (req.method == 'GET' || req.method == 'HEAD') {
- if (ranges) {
- next();
- } else if (!hasCookies && hit && !mustRevalidate(req, hit)) {
- res.setHeader('X-Cache', 'HIT');
- respondFromCache(req, res, hit);
- } else {
- res.setHeader('X-Cache', 'MISS');
- next();
- }
- } else {
- next();
- }
- }
-};
-
-/**
- * Respond with the provided cached value.
- * TODO: Assume 200 code, that's iffy.
- *
- * @param {Object} req
- * @param {Object} res
- * @param {Object} cacheEntry
- * @return {String}
- * @api private
- */
-
-function respondFromCache(req, res, cacheEntry) {
- var status = cacheEntry[0]
- , headers = utils.merge({}, cacheEntry[1])
- , content = cacheEntry.slice(2);
-
- headers.age = (new Date - new Date(headers.date)) / 1000 || 0;
-
- switch (req.method) {
- case 'HEAD':
- res.writeHead(status, headers);
- res.end();
- break;
- case 'GET':
- if (utils.conditionalGET(req) && fresh(req.headers, headers)) {
- headers['content-length'] = 0;
- res.writeHead(304, headers);
- res.end();
- } else {
- res.writeHead(status, headers);
-
- function write() {
- while (content.length) {
- if (false === res.write(content.shift())) {
- res.once('drain', write);
- return;
- }
- }
- res.end();
- }
-
- write();
- }
- break;
- default:
- // This should never happen.
- res.writeHead(500, '');
- res.end();
- }
-}
-
-/**
- * Determine whether or not a cached value must be revalidated.
- *
- * @param {Object} req
- * @param {Object} cacheEntry
- * @return {String}
- * @api private
- */
-
-function mustRevalidate(req, cacheEntry) {
- var cacheHeaders = cacheEntry[1]
- , reqCC = utils.parseCacheControl(req.headers['cache-control'] || '')
- , cacheCC = utils.parseCacheControl(cacheHeaders['cache-control'] || '')
- , cacheAge = (new Date - new Date(cacheHeaders.date)) / 1000 || 0;
-
- if ( cacheCC['no-cache']
- || cacheCC['must-revalidate']
- || cacheCC['proxy-revalidate']) return true;
-
- if (reqCC['no-cache']) return true;
-
- if (null != reqCC['max-age']) return reqCC['max-age'] < cacheAge;
-
- if (null != cacheCC['max-age']) return cacheCC['max-age'] < cacheAge;
-
- return false;
-}
-
-/**
- * The key to use in the cache. For now, this is the URL path and query.
- *
- * 'http://example.com?key=value' -> '/?key=value'
- *
- * @param {Object} req
- * @return {String}
- * @api private
- */
-
-function cacheKey(req) {
- return utils.parseUrl(req).path;
-}
3  package.json
View
@@ -26,8 +26,7 @@
"debug": ">= 0.7.3 < 1",
"methods": "0.1.0",
"raw-body": "1.1.2",
- "negotiator": "0.3.0",
- "multiparty": "2.2.0"
+ "negotiator": "0.3.0"
},
"devDependencies": {
"should": ">= 2.0.2 < 3",
38 support/docs.jade
View
@@ -1,38 +0,0 @@
-doctype html
-html
- head
- title Connect - High quality middleware for node.js
- meta(http-equiv="Content-Type", content="text/html; charset=utf-8")
- link(rel='stylesheet', href='style.css')
- script(src='jquery.js')
- script(src='docs.js')
- body
- #content
- h1 Connect
- for comment in comments
- unless ignore(comment)
- .comment(id=id(comment))
- h2= title(comment)
- .description!= comment.description.full
-
- if comment.tags.length
- ul.tags
- for tag in comment.tags
- if tag.types
- if 'param' == tag.type
- li <em>#{tag.types.join(' | ')}</em> #{tag.name} #{tag.description}
- else
- li returns <em>#{tag.types.join(' | ')}</em> #{tag.description}
- else if tag.name
- li #{tag.name} #{tag.description}
-
- if comment.code
- h3 Source
- pre
- code!= comment.code
-
- ul#menu
- for comment in comments
- unless ignore(comment)
- li
- a(href='#' + id(comment))= title(comment)
46 support/docs.js
View
@@ -1,46 +0,0 @@
-
-var fs = require('fs')
- , jade = require('jade');
-
-var tmpl = fs.readFileSync('support/docs.jade', 'utf8');
-var fn = jade.compile(tmpl);
-
-var json = '';
-process.stdin.setEncoding('utf8');
-process.stdin.on('data', function(chunk){
- json += chunk;
-}).on('end', function(){
- json = JSON.parse(json);
- render(json);
-}).resume();
-
-function title(comment) {
- if (!comment.ctx) return '';
- if (~comment.ctx.string.indexOf('module.exports')) return '';
- if (~comment.ctx.string.indexOf('prototype')) {
- return comment.ctx.string.replace('.prototype.', '#');
- } else {
- return comment.ctx.string;
- }
-}
-
-function id(comment) {
- if (!comment.ctx) return '';
- return comment.ctx.string
- .replace('()', '');
-}
-
-function ignore(comment) {
- return comment.ignore
- || (comment.ctx && ~comment.ctx.string.indexOf('__proto__'))
- || ~comment.description.full.indexOf('Module dependencies');
-}
-
-function render(obj) {
- process.stdout.write(fn({
- comments: obj
- , ignore: ignore
- , title: title
- , id: id
- }));
-}
257 test/bodyParser.js
View
@@ -41,261 +41,4 @@ describe('connect.bodyParser()', function(){
done();
});
})
-
- describe('with multipart/form-data', function(){
- it('should populate req.body', function(done){
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user"\r\n')
- .write('\r\n')
- .write('Tobi')
- .write('\r\n--foo--')
- .end(function(res){
- res.body.should.equal('{"user":"Tobi"}');
- done();
- });
- })
-
- it('should support files', function(done){
- var app = connect();
-
- app.use(connect.bodyParser());
-
- app.use(function(req, res){
- assert('Tobi' == req.body.user.name);
- req.files.text.originalFilename.should.equal('foo.txt');
- req.files.text.path.should.include('.txt');
- res.end(req.files.text.originalFilename);
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user[name]"\r\n')
- .write('\r\n')
- .write('Tobi')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="text"; filename="foo.txt"\r\n')
- .write('\r\n')
- .write('some text here')
- .write('\r\n--foo--')
- .end(function(res){
- res.body.should.equal('foo.txt');
- done();
- });
- })
-
- it('should expose options to multiparty', function(done){
- var app = connect();
-
- app.use(connect.bodyParser({
- keepExtensions: true
- }));
-
- app.use(function(req, res){
- assert('Tobi' == req.body.user.name);
- assert(~req.files.text.path.indexOf('.txt'));
- res.end(req.files.text.originalFilename);
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user[name]"\r\n')
- .write('\r\n')
- .write('Tobi')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="text"; filename="foo.txt"\r\n')
- .write('\r\n')
- .write('some text here')
- .write('\r\n--foo--')
- .end(function(res){
- res.body.should.equal('foo.txt');
- done();
- });
- })
-
- it('should work with multiple fields', function(done){
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user"\r\n')
- .write('\r\n')
- .write('Tobi')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="age"\r\n')
- .write('\r\n')
- .write('1')
- .write('\r\n--foo--')
- .end(function(res){
- res.body.should.equal('{"user":"Tobi","age":"1"}');
- done();
- });
- })
-
- it('should support nesting', function(done){
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user[name][first]"\r\n')
- .write('\r\n')
- .write('tobi')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="user[name][last]"\r\n')
- .write('\r\n')
- .write('holowaychuk')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="user[age]"\r\n')
- .write('\r\n')
- .write('1')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="species"\r\n')
- .write('\r\n')
- .write('ferret')
- .write('\r\n--foo--')
- .end(function(res){
- var obj = JSON.parse(res.body);
- obj.user.age.should.equal('1');
- obj.user.name.should.eql({ first: 'tobi', last: 'holowaychuk' });
- obj.species.should.equal('ferret');
- done();
- });
- })
-
- it('should support multiple files of the same name', function(done){
- var app = connect();
-
- app.use(connect.bodyParser());
-
- app.use(function(req, res){
- req.files.text.should.have.length(2);
- assert(req.files.text[0]);
- assert(req.files.text[1]);
- res.end();
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="text"; filename="foo.txt"\r\n')
- .write('\r\n')
- .write('some text here')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="text"; filename="bar.txt"\r\n')
- .write('\r\n')
- .write('some more text stuff')
- .write('\r\n--foo--')
- .end(function(res){
- res.statusCode.should.equal(200);
- done();
- });
- })
-
- it('should support nested files', function(done){
- var app = connect();
-
- app.use(connect.bodyParser());
-
- app.use(function(req, res){
- Object.keys(req.files.docs).should.have.length(2);
- req.files.docs.foo.originalFilename.should.equal('foo.txt');
- req.files.docs.bar.originalFilename.should.equal('bar.txt');
- res.end();
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="docs[foo]"; filename="foo.txt"\r\n')
- .write('\r\n')
- .write('some text here')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="docs[bar]"; filename="bar.txt"\r\n')
- .write('\r\n')
- .write('some more text stuff')
- .write('\r\n--foo--')
- .end(function(res){
- res.statusCode.should.equal(200);
- done();
- });
- })
-
- it('should next(err) on multipart failure', function(done){
- var app = connect();
-
- app.use(connect.bodyParser());
-
- app.use(function(req, res){
- res.end('whoop');
- });
-
- app.use(function(err, req, res, next){
- err.message.should.equal('parser error, 16 of 28 bytes parsed');
- res.statusCode = 500;
- res.end();
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-filename="foo.txt"\r\n')
- .write('\r\n')
- .write('some text here')
- .write('Content-Disposition: form-data; name="text"; filename="bar.txt"\r\n')
- .write('\r\n')
- .write('some more text stuff')
- .write('\r\n--foo--')
- .end(function(res){
- res.statusCode.should.equal(500);
- done();
- });
- })
- })
-
- // I'm too lazy to test this in both `.json()` and `.urlencoded()`
- describe('verify', function () {
- it('should throw 403 if verification fails', function (done) {
- var app = connect();
-
- app.use(connect.bodyParser({
- verify: function () {
- throw new Error();
- }
- }))
-
- app.request()
- .post('/')
- .set('Content-Type', 'application/json')
- .write('{"user":"tobi"}')
- .expect(403, done);
- })
-
- it('should not throw if verification does not throw', function (done) {
- var app = connect();
-
- app.use(connect.bodyParser({
- verify: function () {}
- }))
-
- app.use(function (req, res, next) {
- res.statusCode = 204;
- res.end();
- })
-
- app.request()
- .post('/')
- .set('Content-Type', 'application/json')
- .write('{"user":"tobi"}')
- .expect(204, done);
- })
- })
})
30 test/limit.js
View
@@ -1,30 +0,0 @@
-
-var connect = require('../');
-
-var app = connect();
-
-app.use(connect.limit('5kb'));
-
-app.use(function(req, res){
- res.end('stuff');
-});
-
-describe('connect.limit()', function(){
- describe('when Content-Length is below', function(){
- it('should bypass limit()', function(done){
- app.request()
- .post('/')
- .set('Content-Length', 500)
- .expect(200, done);
- })
- })
-
- describe('when Content-Length is too large', function(){
- it('should respond with 413', function(done){
- app.request()
- .post('/')
- .set('Content-Length', 10 * 1024)
- .expect(413, done);
- })
- })
-})
300 test/multipart.js
View
@@ -1,300 +0,0 @@
-
-var connect = require('../');
-var assert = require('assert');
-var should = require('./shared');
-
-var app = connect();
-
-app.use(connect.multipart({ limit: '20mb' }));
-
-app.use(function(req, res){
- res.end(JSON.stringify(req.body));
-});
-
-describe('connect.multipart()', function(){
- should['default request body'](app);
- should['limit body to']('20mb', 'multipart/form-data', app);
-
- it('should ignore GET', function(done){
- app.request()
- .get('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user"\r\n')
- .write('\r\n')
- .write('Tobi')
- .write('\r\n--foo--')
- .end(function(res){
- res.body.should.equal('{}');
- done();
- });
- })
-
- describe('with multipart/form-data', function(){
- it('should populate req.body', function(done){
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user"\r\n')
- .write('\r\n')
- .write('Tobi')
- .write('\r\n--foo--')
- .end(function(res){
- res.body.should.equal('{"user":"Tobi"}');
- done();
- });
- })
-
- it('should support files', function(done){
- var app = connect();
-
- app.use(connect.multipart());
-
- app.use(function(req, res){
- assert('Tobi' == req.body.user.name);
- assert('text/plain' == req.files.text.type);
- res.end(req.files.text.name);
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user[name]"\r\n')
- .write('\r\n')
- .write('Tobi')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="text"; filename="foo.txt"\r\n')
- .write('Content-Type: text/plain\r\n')
- .write('\r\n')
- .write('some text here')
- .write('\r\n--foo--')
- .end(function(res){
- res.body.should.equal('foo.txt');
- done();
- });
- })
-
- it('should expose options to multiparty', function(done){
- var app = connect();
-
- app.use(connect.multipart({
- keepExtensions: true
- }));
-
- app.use(function(req, res){
- assert('Tobi' == req.body.user.name);
- assert(~req.files.text.path.indexOf('.txt'));
- res.end(req.files.text.originalFilename);
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user[name]"\r\n')
- .write('\r\n')
- .write('Tobi')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="text"; filename="foo.txt"\r\n')
- .write('\r\n')
- .write('some text here')
- .write('\r\n--foo--')
- .end(function(res){
- res.body.should.equal('foo.txt');
- done();
- });
- })
-
- it('should work with multiple fields', function(done){
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user"\r\n')
- .write('\r\n')
- .write('Tobi')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="age"\r\n')
- .write('\r\n')
- .write('1')
- .write('\r\n--foo--')
- .end(function(res){
- res.body.should.equal('{"user":"Tobi","age":"1"}');
- done();
- });
- })
-
- it('should support nesting', function(done){
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user[name][first]"\r\n')
- .write('\r\n')
- .write('tobi')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="user[name][last]"\r\n')
- .write('\r\n')
- .write('holowaychuk')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="user[age]"\r\n')
- .write('\r\n')
- .write('1')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="species"\r\n')
- .write('\r\n')
- .write('ferret')
- .write('\r\n--foo--')
- .end(function(res){
- var obj = JSON.parse(res.body);
- obj.user.age.should.equal('1');
- obj.user.name.should.eql({ first: 'tobi', last: 'holowaychuk' });
- obj.species.should.equal('ferret');
- done();
- });
- })
-
- it('should support multiple files of the same name', function(done){
- var app = connect();
-
- app.use(connect.multipart());
-
- app.use(function(req, res){
- req.files.text.should.have.length(2);
- assert(req.files.text[0]);
- assert(req.files.text[1]);
- res.end();
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="text"; filename="foo.txt"\r\n')
- .write('\r\n')
- .write('some text here')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="text"; filename="bar.txt"\r\n')
- .write('\r\n')
- .write('some more text stuff')
- .write('\r\n--foo--')
- .end(function(res){
- res.statusCode.should.equal(200);
- done();
- });
- })
-
- it('should support nested files', function(done){
- var app = connect();
-
- app.use(connect.multipart());
-
- app.use(function(req, res){
- Object.keys(req.files.docs).should.have.length(2);
- req.files.docs.foo.originalFilename.should.equal('foo.txt');
- req.files.docs.bar.originalFilename.should.equal('bar.txt');
- res.end();
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="docs[foo]"; filename="foo.txt"\r\n')
- .write('\r\n')
- .write('some text here')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="docs[bar]"; filename="bar.txt"\r\n')
- .write('\r\n')
- .write('some more text stuff')
- .write('\r\n--foo--')
- .end(function(res){
- res.statusCode.should.equal(200);
- done();
- });
- })
-
- it('should next(err) on multipart failure', function(done){
- var app = connect();
-
- app.use(connect.multipart());
-
- app.use(function(req, res){
- res.end('whoop');
- });
-
- app.use(function(err, req, res, next){
- err.message.should.equal('Expected alphabetic character, received 61');
- res.statusCode = err.status;
- res.end('bad request');
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-filename="foo.txt"\r\n')
- .write('\r\n')
- .write('some text here')
- .write('Content-Disposition: form-data; name="text"; filename="bar.txt"\r\n')
- .write('\r\n')
- .write('some more text stuff')
- .write('\r\n--foo--')
- .end(function(res){
- res.statusCode.should.equal(400);
- res.body.should.equal('bad request');
- done();
- });
- })
-
- it('should default req.files to {}', function(done){
- var app = connect();
-
- app.use(connect.multipart());
-
- app.use(function(req, res){
- res.end(JSON.stringify(req.files));
- });
-
- app.request()
- .post('/')
- .end(function(res){
- res.body.should.equal('{}');
- done();
- });
- })
-
- it('should defer processing if `defer` is set', function(done){
- var app = connect();
-
- app.use(connect.multipart({ defer: true }));
-
- app.use(function(req, res){
- JSON.stringify(req.body).should.equal("{}");
- req.form.on('close', function() {
- res.end(JSON.stringify(req.body));
- });
- });
-
- app.request()
- .post('/')
- .set('Content-Type', 'multipart/form-data; boundary=foo')
- .write('--foo\r\n')
- .write('Content-Disposition: form-data; name="user"\r\n')
- .write('\r\n')
- .write('Tobi')
- .write('\r\n--foo\r\n')
- .write('Content-Disposition: form-data; name="age"\r\n')
- .write('\r\n')
- .write('1')
- .write('\r\n--foo--')
- .end(function(res){
- res.body.should.equal('{"user":"Tobi","age":"1"}');
- done();
- });
- })
-
- })
-})
6 test/server.js
View
@@ -23,11 +23,10 @@ describe('app', function(){
it('should allow old-style constructor middleware', function(done){
var app = connect(
connect.json()
- , connect.multipart()
, connect.urlencoded()
, function(req, res){ res.end(JSON.stringify(req.body)) });
- app.stack.should.have.length(4);
+ app.stack.should.have.length(3);
app.request()
.post('/')
@@ -39,10 +38,9 @@ describe('app', function(){
it('should allow old-style .createServer()', function(){
var app = connect.createServer(
connect.json()
- , connect.multipart()
, connect.urlencoded());
- app.stack.should.have.length(3);
+ app.stack.should.have.length(2);
})
it('should work as middlware', function(done){
Please sign in to comment.
Something went wrong with that request. Please try again.