Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 45eef09

Browse files
refactor: convert Request, Response, CodeResponseType, TokenResponseType to ES6 classes
Merge pull request #225 from menewman/fix-convert-request-response-classes-to-es6 thanks to @menewman
2 parents f460371 + 8ea6699 commit 45eef09

File tree

6 files changed

+124
-137
lines changed

6 files changed

+124
-137
lines changed

‎lib/request.js‎

Lines changed: 39 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,67 +7,53 @@
77
const InvalidArgumentError = require('./errors/invalid-argument-error');
88
const typeis = require('type-is');
99

10-
/**
11-
* Constructor.
12-
*/
13-
14-
function Request(options) {
15-
options = options || {};
10+
class Request {
11+
constructor({ headers, method, query, body, ...otherOptions } = {}) {
12+
if (!headers) {
13+
throw new InvalidArgumentError('Missing parameter: `headers`');
14+
}
1615

17-
if (!options.headers) {
18-
throw new InvalidArgumentError('Missing parameter: `headers`');
19-
}
16+
if (!method) {
17+
throw new InvalidArgumentError('Missing parameter: `method`');
18+
}
2019

21-
if (!options.method) {
22-
throw new InvalidArgumentError('Missing parameter: `method`');
23-
}
20+
if (!query) {
21+
throw new InvalidArgumentError('Missing parameter: `query`');
22+
}
2423

25-
if (!options.query) {
26-
throw new InvalidArgumentError('Missing parameter: `query`');
24+
this.body = body || {};
25+
this.headers = {};
26+
this.method = method;
27+
this.query = query;
28+
29+
// Store the headers in lower case.
30+
Object.entries(headers).forEach(([header, value]) => {
31+
this.headers[header.toLowerCase()] = value;
32+
});
33+
34+
// Store additional properties of the request object passed in
35+
Object.entries(otherOptions)
36+
.filter(([property]) => !this[property])
37+
.forEach(([property, value]) => {
38+
this[property] = value;
39+
});
2740
}
2841

29-
this.body = options.body || {};
30-
this.headers = {};
31-
this.method = options.method;
32-
this.query = options.query;
33-
34-
// Store the headers in lower case.
35-
for (const field in options.headers) {
36-
if (Object.prototype.hasOwnProperty.call(options.headers, field)) {
37-
this.headers[field.toLowerCase()] = options.headers[field];
38-
}
42+
/**
43+
* Get a request header.
44+
* @param {String} field
45+
*/
46+
get(field) {
47+
return this.headers[field.toLowerCase()];
3948
}
4049

41-
// Store additional properties of the request object passed in
42-
for (const property in options) {
43-
if (Object.prototype.hasOwnProperty.call(options, property) && !this[property]) {
44-
this[property] = options[property];
45-
}
50+
/**
51+
* Check if the content-type matches any of the given mime types.
52+
* @param {...String|Array} types
53+
*/
54+
is(...types) {
55+
return typeis(this, types.flat()) || false;
4656
}
4757
}
4858

49-
/**
50-
* Get a request header.
51-
*/
52-
53-
Request.prototype.get = function(field) {
54-
return this.headers[field.toLowerCase()];
55-
};
56-
57-
/**
58-
* Check if the content-type matches any of the given mime type.
59-
*/
60-
61-
Request.prototype.is = function(types) {
62-
if (!Array.isArray(types)) {
63-
types = [].slice.call(arguments);
64-
}
65-
66-
return typeis(this, types) || false;
67-
};
68-
69-
/**
70-
* Export constructor.
71-
*/
72-
7359
module.exports = Request;

‎lib/response-types/code-response-type.js‎

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,27 @@
77
const InvalidArgumentError = require('../errors/invalid-argument-error');
88
const url = require('url');
99

10-
/**
11-
* Constructor.
12-
*/
10+
class CodeResponseType {
11+
constructor(code) {
12+
if (!code) {
13+
throw new InvalidArgumentError('Missing parameter: `code`');
14+
}
1315

14-
function CodeResponseType(code) {
15-
if (!code) {
16-
throw new InvalidArgumentError('Missing parameter: `code`');
16+
this.code = code;
1717
}
1818

19-
this.code = code;
20-
}
19+
buildRedirectUri(redirectUri) {
20+
if (!redirectUri) {
21+
throw new InvalidArgumentError('Missing parameter: `redirectUri`');
22+
}
2123

22-
/**
23-
* Build redirect uri.
24-
*/
25-
26-
CodeResponseType.prototype.buildRedirectUri = function(redirectUri) {
27-
if (!redirectUri) {
28-
throw new InvalidArgumentError('Missing parameter: `redirectUri`');
29-
}
24+
const uri = url.parse(redirectUri, true);
3025

31-
const uri = url.parse(redirectUri, true);
26+
uri.query.code = this.code;
27+
uri.search = null;
3228

33-
uri.query.code = this.code;
34-
uri.search = null;
35-
36-
return uri;
37-
};
38-
39-
/**
40-
* Export constructor.
41-
*/
29+
return uri;
30+
}
31+
}
4232

4333
module.exports = CodeResponseType;

‎lib/response-types/token-response-type.js‎

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,10 @@
66

77
const ServerError = require('../errors/server-error');
88

9-
/**
10-
* Constructor.
11-
*/
12-
13-
function TokenResponseType() {
14-
throw new ServerError('Not implemented.');
9+
class TokenResponseType {
10+
constructor() {
11+
throw new ServerError('Not implemented.');
12+
}
1513
}
1614

17-
/**
18-
* Export constructor.
19-
*/
20-
2115
module.exports = TokenResponseType;

‎lib/response.js‎

Lines changed: 35 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,45 @@
11
'use strict';
22

3-
/**
4-
* Constructor.
5-
*/
6-
7-
function Response(options) {
8-
options = options || {};
3+
class Response {
4+
constructor({ headers = {}, body = {}, ...otherOptions } = {}) {
5+
this.status = 200;
6+
this.body = body;
7+
this.headers = {};
8+
9+
// Store the headers in lower case.
10+
Object.entries(headers).forEach(([header, value]) => {
11+
this.headers[header.toLowerCase()] = value;
12+
});
13+
14+
// Store additional properties of the response object passed in
15+
Object.entries(otherOptions)
16+
.filter(([property]) => !this[property])
17+
.forEach(([property, value]) => {
18+
this[property] = value;
19+
});
20+
}
921

10-
this.body = options.body || {};
11-
this.headers = {};
12-
this.status = 200;
22+
/**
23+
* Get a response header.
24+
*/
25+
get(field) {
26+
return this.headers[field.toLowerCase()];
27+
}
1328

14-
// Store the headers in lower case.
15-
for (const field in options.headers) {
16-
if (Object.prototype.hasOwnProperty.call(options.headers, field)) {
17-
this.headers[field.toLowerCase()] = options.headers[field];
18-
}
29+
/**
30+
* Redirect response.
31+
*/
32+
redirect(url) {
33+
this.set('Location', url);
34+
this.status = 302;
1935
}
2036

21-
// Store additional properties of the response object passed in
22-
for(constpropertyinoptions){
23-
if(Object.prototype.hasOwnProperty.call(options,property)&&!this[property]){
24-
this[property]=options[property];
25-
}
37+
/**
38+
* Set a response header.
39+
*/
40+
set(field,value){
41+
this.headers[field.toLowerCase()]=value;
2642
}
2743
}
2844

29-
/**
30-
* Get a response header.
31-
*/
32-
33-
Response.prototype.get = function(field) {
34-
return this.headers[field.toLowerCase()];
35-
};
36-
37-
/**
38-
* Redirect response.
39-
*/
40-
41-
Response.prototype.redirect = function(url) {
42-
this.set('Location', url);
43-
this.status = 302;
44-
};
45-
46-
/**
47-
* Set a response header.
48-
*/
49-
50-
Response.prototype.set = function(field, value) {
51-
this.headers[field.toLowerCase()] = value;
52-
};
53-
54-
/**
55-
* Export constructor.
56-
*/
57-
5845
module.exports = Response;

‎test/unit/request_test.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,22 @@ describe('Request', function() {
127127
request.custom2.should.eql(originalRequest.custom2);
128128
});
129129

130+
it('should not allow overwriting methods on the Request prototype via custom properties', () => {
131+
const request = new Request({
132+
query: {},
133+
method: 'GET',
134+
headers: {
135+
'content-type': 'application/json'
136+
},
137+
get() {
138+
// malicious attempt to override the 'get' method
139+
return 'text/html';
140+
}
141+
});
142+
143+
request.get('content-type').should.equal('application/json');
144+
});
145+
130146
it('should allow getting of headers using `request.get`', function() {
131147
const originalRequest = generateBaseRequest();
132148

‎test/unit/response_test.js‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,20 @@ describe('Request', function() {
8383
response.custom2.should.eql(originalResponse.custom2);
8484
});
8585

86+
it('should not allow overwriting methods on the Response prototype via custom properties', () => {
87+
const response = new Response({
88+
headers: {
89+
'content-type': 'application/json'
90+
},
91+
get() {
92+
// malicious attempt to override the 'get' method
93+
return 'text/html';
94+
}
95+
});
96+
97+
response.get('content-type').should.equal('application/json');
98+
});
99+
86100
it('should allow getting of headers using `response.get`', function() {
87101
const originalResponse = generateBaseResponse();
88102

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /