Add responses hook, fix conflicts with last PR

This commit is contained in:
Aurélien Georget 2016-03-11 14:18:37 +01:00
commit f335d74f3f
13 changed files with 422 additions and 174 deletions

View File

@ -21,7 +21,7 @@ module.exports = function (strapi) {
initialize: function (cb) {
if (strapi.config.gzip === true) {
strapi.app.use(strapi.middlewares.gzip());
strapi.app.use(strapi.middlewares.compress());
}
cb();

View File

@ -0,0 +1,24 @@
'use strict';
module.exports = function () {
const hook = {
/**
* Default options
*/
defaults: {
enabled: true
},
/**
* Initialize the hook
*/
initialize: function (cb) {
cb();
}
};
return hook;
};

View File

@ -0,0 +1,22 @@
'use strict';
/**
* Module dependencies
*/
// Public node modules.
const _ = require('lodash');
// Local utilities.
const responses = require('../responses/index');
/**
* Policy used to add responses in the `this.response` object.
*/
module.exports = function * (next) {
// Add the custom responses to the `this.response` object.
this.response = _.merge(this.response, responses);
yield next;
};

View File

@ -0,0 +1,18 @@
'use strict';
/**
* Default `badRequest` response.
*/
module.exports = function * badRequest(data) {
// Set the status.
this.status = 400;
// Delete the `data` object if the app is used in production environment.
if (strapi.config.environment === 'production') {
data = undefined;
}
// Finally send the response.
this.body = data;
};

View File

@ -0,0 +1,13 @@
'use strict';
/**
* Default `created` response.
*/
module.exports = function * created(data) {
// Set the status.
this.status = 201;
// Finally send the response.
this.body = data;
};

View File

@ -0,0 +1,18 @@
'use strict';
/**
* Default `forbidden` response.
*/
module.exports = function * forbidden(data) {
// Set the status.
this.status = 403;
// Delete the `data` object if the app is used in production environment.
if (strapi.config.environment === 'production') {
data = undefined;
}
// Finally send the response.
this.body = data;
};

View File

@ -0,0 +1,14 @@
'use strict';
/**
* Index of the responses hook responses.
*/
module.exports = {
badRequest: require('./badRequest'),
created: require('./created'),
forbidden: require('./forbidden'),
notFound: require('./notFound'),
ok: require('./ok'),
serverError: require('./serverError')
};

View File

@ -0,0 +1,18 @@
'use strict';
/**
* Default `notFound` response.
*/
module.exports = function * notFound(data) {
// Set the status.
this.status = 404;
// Delete the `data` object if the app is used in production environment.
if (strapi.config.environment === 'production') {
data = undefined;
}
// Finally send the response.
this.body = data;
};

View File

@ -0,0 +1,13 @@
'use strict';
/**
* Default `ok` response.
*/
module.exports = function sendOk(data) {
// Set the status.
this.status = 200;
// Finally send the response.
this.body = data;
};

View File

@ -0,0 +1,18 @@
'use strict';
/**
* Default `serverError` response.
*/
module.exports = function * serverError(data) {
// Set the status.
this.status = 500;
// Delete the `data` object if the app is used in production environment.
if (strapi.config.environment === 'production') {
data = undefined;
}
// Finally send the response.
this.body = data;
};

View File

@ -40,10 +40,10 @@
"koa": "~1.1.2",
"koa-bodyparser": "~2.0.1",
"koa-compose": "~2.3.0",
"koa-compress": "^1.0.9",
"koa-cors": "~0.0.16",
"koa-favicon": "~1.2.0",
"koa-graphql": "^0.4.5",
"koa-gzip": "~0.1.0",
"koa-i18n": "~1.2.0",
"koa-ip": "~0.1.0",
"koa-load-middlewares": "~1.0.0",

View File

@ -0,0 +1,262 @@
'use strict';
const fs = require('fs');
const should = require('should');
const request = require('supertest');
const assert = require('assert');
const http = require('http');
const Stream = require('stream');
const crypto = require('crypto');
const path = require('path');
const strapi = require('../../..');
const Koa = strapi.server;
describe('compress', function() {
describe('strapi.middlewares.compress()', function() {
it('should work with no options', function() {
strapi.middlewares.compress();
});
});
const buffer = crypto.randomBytes(1024);
const string = buffer.toString('hex');
function* sendString(next) {
this.body = string
}
function* sendBuffer(next) {
this.compress = true;
this.body = buffer
}
it('should compress strings', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(sendString);
request(app.listen()).get('/').expect(200).end(function(err, res) {
if (err) return done(err);
//res.should.have.header('Content-Encoding', 'gzip')
res.should.have.header('Transfer-Encoding', 'chunked');
res.should.have.header('Vary', 'Accept-Encoding');
res.headers.should.not.have.property('content-length');
res.text.should.equal(string);
done()
})
});
it('should not compress strings below threshold', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress({
threshold: '1mb'
}));
app.use(sendString);
request(app.listen()).get('/').expect(200).end(function(err, res) {
if (err) return done(err);
res.should.have.header('Content-Length', '2048');
res.should.have.header('Vary', 'Accept-Encoding');
res.headers.should.not.have.property('content-encoding');
res.headers.should.not.have.property('transfer-encoding');
res.text.should.equal(string);
done()
})
});
it('should compress JSON body', function(done) {
var jsonBody = {
'status': 200,
'message': 'ok',
'data': string
};
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(function*(next) {
this.body = jsonBody
});
request(app.listen()).get('/').expect(200).end(function(err, res) {
if (err)
return done(err);
res.should.have.header('Transfer-Encoding', 'chunked');
res.should.have.header('Vary', 'Accept-Encoding');
res.headers.should.not.have.property('content-length');
res.text.should.equal(JSON.stringify(jsonBody));
done()
})
});
it('should not compress JSON body below threshold', function(done) {
var jsonBody = {
'status': 200,
'message': 'ok'
};
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(function* sendJSON(next) {
this.body = jsonBody
});
request(app.listen()).get('/').expect(200).end(function(err, res) {
if (err)
return done(err);
res.should.have.header('Vary', 'Accept-Encoding');
res.headers.should.not.have.property('content-encoding');
res.headers.should.not.have.property('transfer-encoding');
res.text.should.equal(JSON.stringify(jsonBody));
done()
})
});
it('should compress buffers', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(sendBuffer);
request(app.listen()).get('/').expect(200).end(function(err, res) {
if (err)
return done(err);
//res.should.have.header('Content-Encoding', 'gzip')
res.should.have.header('Transfer-Encoding', 'chunked');
res.should.have.header('Vary', 'Accept-Encoding');
res.headers.should.not.have.property('content-length');
done()
})
});
it('should compress streams', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(function*(next) {
this.type = 'application/javascript';
this.body = fs.createReadStream(path.join(__dirname, 'index.js'))
});
request(app.listen()).get('/').expect(200).end(function(err, res) {
if (err)
return done(err);
//res.should.have.header('Content-Encoding', 'gzip')
res.should.have.header('Transfer-Encoding', 'chunked');
res.should.have.header('Vary', 'Accept-Encoding');
res.headers.should.not.have.property('content-length');
done()
})
});
it('should compress when this.compress === true', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(sendBuffer);
request(app.listen()).get('/').expect(200).end(function(err, res) {
if (err)
return done(err);
//res.should.have.header('Content-Encoding', 'gzip')
res.should.have.header('Transfer-Encoding', 'chunked');
res.should.have.header('Vary', 'Accept-Encoding');
res.headers.should.not.have.property('content-length');
done()
})
});
it('should not compress when this.compress === false', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(function*(next) {
this.compress = false;
this.body = buffer
});
request(app.listen()).get('/').expect(200).end(function(err, res) {
if (err)
return done(err);
res.should.have.header('Content-Length', '1024');
res.should.have.header('Vary', 'Accept-Encoding');
res.headers.should.not.have.property('content-encoding');
res.headers.should.not.have.property('transfer-encoding');
done()
})
});
it('should not compress HEAD requests', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(sendString);
request(app.listen()).head('/').expect(200).expect('', function(err, res) {
if (err)
return done(err);
res.headers.should.not.have.property('content-encoding');
done()
})
});
it('should not crash even if accept-encoding: sdch', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(sendBuffer);
request(app.listen()).get('/').set('Accept-Encoding', 'sdch, gzip, deflate').expect(200, done)
});
it('should not crash if no accept-encoding is sent', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(sendBuffer);
request(app.listen()).get('/').expect(200, done)
});
it('should not crash if a type does not pass the filter', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress());
app.use(function*() {
this.type = 'image/png';
this.body = new Buffer(2048)
});
request(app.listen()).get('/').expect(200, done)
});
it('should not compress when transfer-encoding is already set', function(done) {
let app = strapi.server();
app.use(strapi.middlewares.compress({
threshold: 0
}));
app.use(function*() {
this.set('Content-Encoding', 'identity');
this.type = 'text';
this.body = 'asdf'
});
request(app.listen()).get('/').expect('asdf', done)
});
});

View File

@ -1,172 +0,0 @@
'use strict';
const fs = require('fs');
const should = require('should');
const request = require('supertest');
const strapi = require('../../..');
const Koa = strapi.server;
describe('gzip', function () {
const options = {};
const BODY = 'foo bar string, foo bar string, foo bar string, foo bar string, \
foo bar string, foo bar string, foo bar string, foo bar string, foo bar string, foo bar string, \
foo bar string, foo bar string, foo bar string, foo bar string, foo bar string, foo bar string';
let app = strapi.server();
app.use(strapi.middlewares.gzip(options));
app.use(strapi.middlewares.gzip(options));
app.use(function * (next) {
if (this.url === '/404') {
return yield next;
}
if (this.url === '/small') {
return this.body = 'foo bar string';
}
if (this.url === '/string') {
return this.body = BODY;
}
if (this.url === '/buffer') {
return this.body = new Buffer(BODY);
}
if (this.url === '/object') {
return this.body = {
foo: BODY
};
}
if (this.url === '/number') {
return this.body = 1984;
}
if (this.url === '/stream') {
const stat = fs.statSync(__filename);
this.set('content-length', stat.size);
return this.body = fs.createReadStream(__filename);
}
if (this.url === '/exists-encoding') {
this.set('content-encoding', 'gzip');
return this.body = new Buffer('gzip');
}
if (this.url === '/error') {
return this.throw(new Error('mock error'));
}
});
before(function (done) {
app = app.listen(0, done);
});
describe('strapi.middlewares.gzip()', function () {
it('should work with no options', function () {
strapi.middlewares.gzip();
});
});
describe('when status 200 and request accept-encoding include gzip', function () {
it('should return gzip string body', function (done) {
request(app)
.get('/string')
.set('Accept-Encoding', 'gzip,deflate,sdch')
.expect(200)
.expect('content-encoding', 'gzip')
.expect('content-length', '46')
.expect(BODY, done);
});
it('should return raw string body if body smaller than minLength', function (done) {
request(app)
.get('/small')
.set('Accept-Encoding', 'gzip,deflate,sdch')
.expect(200)
.expect('content-length', '14')
.expect('foo bar string', function (err, res) {
should.not.exist(err);
should.not.exist(res.headers['content-encoding']);
done();
});
});
it('should return gzip buffer body', function (done) {
request(app)
.get('/buffer')
.set('Accept-Encoding', 'gzip,deflate,sdch')
.expect(200)
.expect('content-encoding', 'gzip')
.expect('content-length', '46')
.expect(BODY, done);
});
it('should return gzip stream body', function (done) {
request(app)
.get('/stream')
.set('Accept-Encoding', 'gzip,deflate,sdch')
.expect(200)
.expect('Content-Encoding', 'gzip')
.expect(fs.readFileSync(__filename, 'utf8'),
function (err, res) {
should.not.exist(err);
should.not.exist(res.headers['content-length']);
done();
});
});
it('should return gzip json body', function (done) {
request(app)
.get('/object')
.set('Accept-Encoding', 'gzip,deflate,sdch')
.expect(200)
.expect('Content-Encoding', 'gzip')
.expect('content-length', '52')
.expect({
foo: BODY
}, done);
});
it('should return number body', function (done) {
request(app)
.get('/number')
.set('Accept-Encoding', 'gzip,deflate,sdch')
.expect('content-length', '4')
.expect(200, function (err, res) {
should.not.exist(err);
res.body.should.equal(1984);
done();
});
});
});
describe('when status 200 and request accept-encoding exclude gzip', function () {
it('should return raw body', function (done) {
request(app)
.get('/string')
.set('Accept-Encoding', 'deflate,sdch')
.expect(200)
.expect('content-length', '' + BODY.length)
.expect(BODY,
function (err, res) {
should.not.exist(err);
should.not.exist(res.headers['content-encoding']);
done();
});
});
});
describe('when status non 200', function () {
it('should return 404', function (done) {
request(app)
.get('/404')
.set('Accept-Encoding', 'gzip,deflate,sdch')
.expect(404)
.expect('Not Found', done);
});
it('should return 500', function (done) {
request(app)
.get('/error')
.set('Accept-Encoding', 'gzip,deflate,sdch')
.expect(500)
.expect('Internal Server Error', done);
});
});
});