Skip to content

Commit 1847da8

Browse files
committed
Fix inheritance should not overwrite the methods of http.ServerResponse and http.IncomingMessage
1 parent a46cfdc commit 1847da8

File tree

3 files changed

+62
-6
lines changed

3 files changed

+62
-6
lines changed

lib/application.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ var merge = require('utils-merge');
2525
var resolve = require('path').resolve;
2626
var once = require('once')
2727
var Router = require('router');
28+
var setPrototypeUntil = require('./setPrototypeUntil')
2829
var setPrototypeOf = require('setprototypeof')
30+
var resProto = require('./response')
31+
var reqProto = require('./request')
2932

3033
/**
3134
* Module variables.
@@ -117,8 +120,6 @@ app.defaultConfiguration = function defaultConfiguration() {
117120
}
118121

119122
// inherit protos
120-
setPrototypeOf(this.request, parent.request)
121-
setPrototypeOf(this.response, parent.response)
122123
setPrototypeOf(this.engines, parent.engines)
123124
setPrototypeOf(this.settings, parent.settings)
124125
});
@@ -168,8 +169,8 @@ app.handle = function handle(req, res, callback) {
168169
res.req = req;
169170

170171
// alter the prototypes
171-
setPrototypeOf(req, this.request)
172-
setPrototypeOf(res, this.response)
172+
setPrototypeUntil(req, this.request, reqProto)
173+
setPrototypeUntil(res, this.response, resProto)
173174

174175
// setup locals
175176
if (!res.locals) {
@@ -232,8 +233,8 @@ app.use = function use(fn) {
232233
router.use(path, function mounted_app(req, res, next) {
233234
var orig = req.app;
234235
fn.handle(req, res, function (err) {
235-
setPrototypeOf(req, orig.request)
236-
setPrototypeOf(res, orig.response)
236+
setPrototypeUntil(req, orig.request)
237+
setPrototypeUntil(res, orig.response)
237238
next(err);
238239
});
239240
});

lib/setPrototypeUntil.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
function setPrototypeUntil(obj, proto, until) {
3+
var currentProto = proto;
4+
until = until || proto;
5+
var last = Object.getPrototypeOf(until);
6+
while (currentProto && currentProto !== last) {
7+
Object.keys(currentProto).forEach(function (key) {
8+
setPrototypeKey(obj, proto, key, until)
9+
});
10+
currentProto = Object.getPrototypeOf(currentProto)
11+
}
12+
}
13+
14+
function setPrototypeKey(obj, proto, key, until) {
15+
Object.defineProperty(obj, key, {
16+
configurable: true,
17+
enumerable: proto.propertyIsEnumerable(key),
18+
get: function () {
19+
var desc = Object.getOwnPropertyDescriptor(until, key)
20+
if (desc && typeof desc.get === 'function') {
21+
// property defined with defineGetter, we need to change the `this` of the getter accordingly
22+
return desc.get.call(obj)
23+
}
24+
return proto[key]
25+
},
26+
set: function (v) {
27+
proto[key] = v
28+
}
29+
})
30+
}
31+
32+
module.exports = setPrototypeUntil

test/app.response.js

+23
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,28 @@ describe('app', function(){
139139
.get('/sub/foo')
140140
.expect(200, 'FOO', cb)
141141
})
142+
143+
it('should inherit parent app', function (done) {
144+
var app1 = express()
145+
var app2 = express()
146+
var cb = after(1, done)
147+
148+
app2.request.foo = 'bar';
149+
app1.response.shout = function (str) {
150+
this.setHeader('foo', this.req.foo)
151+
this.send(str.toUpperCase())
152+
}
153+
154+
app1.use('/sub', app2)
155+
156+
app2.get('/', function (req, res) {
157+
res.shout('foo')
158+
})
159+
160+
request(app1)
161+
.get('/sub')
162+
.expect('foo', 'bar')
163+
.expect(200, 'FOO', cb)
164+
})
142165
})
143166
})

0 commit comments

Comments
 (0)