move setHeader charset patch to .set

note that application/json no longer adds charset=utf-8. could be a
regression.

closes #1952
See also: https://github.com/broofa/node-mime/issues/86
This commit is contained in:
Jonathan Ong 2014-03-07 16:32:41 -08:00
parent 3cf7b2e39e
commit bad55f7977
8 changed files with 42 additions and 87 deletions

View File

@ -2,22 +2,20 @@
* Module dependencies. * Module dependencies.
*/ */
var http = require('http') var http = require('http');
, path = require('path') var path = require('path');
, mixin = require('utils-merge') var mixin = require('utils-merge');
, escapeHtml = require('escape-html') var escapeHtml = require('escape-html');
, sign = require('cookie-signature').sign var sign = require('cookie-signature').sign;
, normalizeType = require('./utils').normalizeType var normalizeType = require('./utils').normalizeType;
, normalizeTypes = require('./utils').normalizeTypes var normalizeTypes = require('./utils').normalizeTypes;
, etag = require('./utils').etag var etag = require('./utils').etag;
, statusCodes = http.STATUS_CODES var statusCodes = http.STATUS_CODES;
, cookie = require('cookie') var cookie = require('cookie');
, send = require('send') var send = require('send');
, basename = path.basename var basename = path.basename;
, extname = path.extname var extname = path.extname;
, mime = send.mime; var mime = send.mime;
var ServerResponse = http.ServerResponse;
var setHeader = ServerResponse.prototype.setHeader;
/** /**
* Response prototype. * Response prototype.
@ -525,6 +523,11 @@ res.header = function(field, val){
if (2 == arguments.length) { if (2 == arguments.length) {
if (Array.isArray(val)) val = val.map(String); if (Array.isArray(val)) val = val.map(String);
else val = String(val); else val = String(val);
field = field.toLowerCase();
if ('content-type' == field && !/;\s*charset\s*=/.test(val)) {
var charset = mime.charsets.lookup(val.split(';')[0]);
if (charset) val += '; charset=' + charset.toLowerCase();
}
this.setHeader(field, val); this.setHeader(field, val);
} else { } else {
for (var key in field) { for (var key in field) {
@ -780,23 +783,3 @@ res.render = function(view, options, fn){
// render // render
app.render(view, options, fn); app.render(view, options, fn);
}; };
/**
* Set header `field` to `val`, special-casing
* the `Set-Cookie` field for multiple support.
*
* @param {String} field
* @param {String} val
* @api public
*/
res.setHeader = function(field, val){
var key = field.toLowerCase();
if ('content-type' == key && this.charset) {
val += '; charset=' + this.charset;
}
return setHeader.call(this, field, val);
};

View File

@ -16,7 +16,7 @@ function req(ct) {
describe('req.is()', function(){ describe('req.is()', function(){
it('should ignore charset', function(){ it('should ignore charset', function(){
req('application/json; charset=utf-8') req('application/json')
.is('json') .is('json')
.should.equal('json'); .should.equal('json');
}) })

View File

@ -1,34 +0,0 @@
var express = require('../')
, request = require('supertest');
describe('res', function(){
describe('.charset', function(){
it('should add the charset param to Content-Type', function(done){
var app = express();
app.use(function(req, res){
res.charset = 'utf-8';
res.set('Content-Type', 'text/x-foo');
res.end(res.get('Content-Type'));
});
request(app)
.get('/')
.expect("text/x-foo; charset=utf-8", done);
})
it('should take precedence over res.send() defaults', function(done){
var app = express();
app.use(function(req, res){
res.charset = 'whoop';
res.send('hey');
});
request(app)
.get('/')
.expect('Content-Type', 'text/html; charset=whoop', done);
})
})
})

View File

@ -28,7 +28,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('null'); res.text.should.equal('null');
done(); done();
}) })
@ -46,7 +46,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('["foo","bar","baz"]'); res.text.should.equal('["foo","bar","baz"]');
done(); done();
}) })
@ -64,7 +64,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('{"name":"tobi"}'); res.text.should.equal('{"name":"tobi"}');
done(); done();
}) })
@ -131,7 +131,7 @@ describe('res', function(){
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.statusCode.should.equal(201); res.statusCode.should.equal(201);
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('{"id":1}'); res.text.should.equal('{"id":1}');
done(); done();
}) })
@ -150,7 +150,7 @@ describe('res', function(){
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.statusCode.should.equal(201); res.statusCode.should.equal(201);
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('{"id":1}'); res.text.should.equal('{"id":1}');
done(); done();
}) })

View File

@ -114,7 +114,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('null'); res.text.should.equal('null');
done(); done();
}) })
@ -132,7 +132,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('["foo","bar","baz"]'); res.text.should.equal('["foo","bar","baz"]');
done(); done();
}) })
@ -150,7 +150,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('{"name":"tobi"}'); res.text.should.equal('{"name":"tobi"}');
done(); done();
}) })
@ -217,7 +217,7 @@ describe('res', function(){
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.statusCode.should.equal(201); res.statusCode.should.equal(201);
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('{"id":1}'); res.text.should.equal('{"id":1}');
done(); done();
}) })
@ -236,7 +236,7 @@ describe('res', function(){
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.statusCode.should.equal(201); res.statusCode.should.equal(201);
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('{"id":1}'); res.text.should.equal('{"id":1}');
done(); done();
}) })

View File

@ -139,7 +139,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.expect('Content-Type', 'text/plain') .expect('Content-Type', 'text/plain; charset=utf-8')
.expect('hey') .expect('hey')
.expect(200, done); .expect(200, done);
}) })
@ -187,7 +187,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.headers.should.have.property('content-type', 'text/plain'); res.headers.should.have.property('content-type', 'text/plain; charset=utf-8');
res.text.should.equal('hey'); res.text.should.equal('hey');
res.statusCode.should.equal(200); res.statusCode.should.equal(200);
done(); done();
@ -206,7 +206,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.end(function(err, res){ .end(function(err, res){
res.headers.should.have.property('content-type', 'application/json; charset=utf-8'); res.headers.should.have.property('content-type', 'application/json');
res.text.should.equal('{"name":"tobi"}'); res.text.should.equal('{"name":"tobi"}');
done(); done();
}) })

View File

@ -67,7 +67,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.expect('Content-Type', 'text/plain') .expect('Content-Type', 'text/plain; charset=utf-8')
.end(done); .end(done);
}) })

View File

@ -9,12 +9,12 @@ describe('res', function(){
var app = express(); var app = express();
app.use(function(req, res){ app.use(function(req, res){
res.set('Content-Type', 'text/x-foo').end(); res.set('Content-Type', 'text/x-foo; charset=utf-8').end();
}); });
request(app) request(app)
.get('/') .get('/')
.expect('Content-Type', 'text/x-foo') .expect('Content-Type', 'text/x-foo; charset=utf-8')
.end(done); .end(done);
}) })
@ -44,6 +44,12 @@ describe('res', function(){
res.set('ETag', [123, 456]); res.set('ETag', [123, 456]);
JSON.stringify(res.get('ETag')).should.equal('["123","456"]'); JSON.stringify(res.get('ETag')).should.equal('["123","456"]');
}) })
it('should not set a charset of one is already set', function () {
res.headers = {};
res.set('Content-Type', 'text/html; charset=lol');
res.get('content-type').should.equal('text/html; charset=lol');
})
}) })
describe('.set(object)', function(){ describe('.set(object)', function(){