| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 |
1x
1x
1x
64x
64x
64x
64x
64x
64x
64x
64x
64x
64x
64x
64x
64x
64x
64x
64x
64x
64x
64x
61x
61x
61x
61x
61x
61x
61x
61x
61x
61x
1x
3x
3x
3x
3x
64x
64x
64x
64x
62x
2x
2x
64x
64x
64x
1x
1x
1x
1x
64x
64x
64x
64x
2x
2x
1x
63x
2x
2x
2x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
| 'use strict';
const FilePathBuilderService = require('../services/FilePathBuilderService.js');
const FileLoaderService = require('../services/FileLoaderService.js');
const Toolbox = require('../utils/Toolbox.js');
/**
* This controller is for processing the requests and building the response
*/
class MockCtrl {
/**
* Constructor.
*/
constructor({Configuration, Logger}) {
this.Configuration = Configuration;
this.Logger = Logger;
this.pathBuilder = new FilePathBuilderService({Configuration, Logger});
this.fileLoader = new FileLoaderService({Configuration, Logger});
}
/**
* Build a response based on the user request.
* @param request
* @param response
*/
buildResponse(request, response) {
let method = request.method;
let httpCode = 201;
let responseHeaders = {};
let rawContent = null;
let extension = 'json';
let location = null;
let delay = 1;
// Get the URL
const url = Toolbox.removeTrailingSlash(request.url);
responseHeaders['X-Mockiji-Url'] = url;
this.Logger.info({
'type': 'request',
'method': method,
'url': url
}, `Received a request: "${method} ${url}"`);
// Retreive authorization token if needed
this._handleToken(request);
// replace dynamic markers
let customUrl = this._handleDynamicMarkers(url);
// List every possible paths
let paths = this.pathBuilder.generatePaths(method.toLowerCase(), customUrl);
// Find the file to load and extract the content
let fileToLoad = this.fileLoader.find(paths.mocks);
if (fileToLoad !== null) {
let fileData = this.fileLoader.load(fileToLoad, request, paths);
rawContent = fileData.rawContent;
httpCode = fileData.httpCode;
extension = fileData.extension;
location = fileData.location;
delay = fileData.delay;
responseHeaders['X-Mockiji-File'] = fileToLoad;
responseHeaders['X-Mockiji-Notices'] = fileData.notices;
responseHeaders['Cache-Control'] = 'no-cache';
if (location) {
responseHeaders['Location'] = location;
}
} else {
httpCode = this.Configuration.get('http_codes.mock_file_not_found');
responseHeaders['X-Mockiji-Not-Found'] = true;
rawContent = {
'errorCode': httpCode,
'errorDescription': 'No mock file was found',
'evaluatedMockFilePaths': paths.mocks,
};
this.Logger.warn({
'method': request.method,
'url': url,
'httpCode': httpCode,
'evaluatedMockFilePaths': paths.mocks,
}, `Could not find a mock file for "${request.method} ${url}"`);
}
// Set Response Headers
response.set(responseHeaders);
// Send Response
setTimeout(() => {
Iif (rawContent !== null && extension === 'html') {
response.status(httpCode).send(rawContent);
} else if (rawContent !== null) {
response.status(httpCode).json(rawContent);
} else {
response.set('X-Mockiji-Empty-Response-Body', true);
response.status(httpCode).send('');
}
this.Logger.info({
'type': 'response',
'method': method,
'url': url,
'httpCode': httpCode,
'mockPath': fileToLoad,
}, `Response sent for "${method} ${url}" (${httpCode})`);
}, delay);
}
/**
* Decode token if needed.
* @param request
*/
_handleToken(request) {
let tokenType = this.Configuration.get('authorization_token');
if (tokenType && tokenType !== '' && request.headers.authorization) {
Eif (tokenType === 'base64') {
let encoded = request.headers.authorization.split(' ')[1];
let decoded = new Buffer(encoded, 'base64').toString('utf8');
this.token = JSON.parse(decoded);
}
}
}
/**
* Replace dynamic markers from raw url
* @param url
*/
_handleDynamicMarkers(url) {
Eif(typeof(this.Configuration.get('dynamic_markers')) === 'object') {
let markerConfigs = this.Configuration.get('dynamic_markers');
Eif (markerConfigs) {
// We browse the token configs array
for(let i in markerConfigs) {
// We test the config regexp
let newUrl = this._testAndReplaceUrl(markerConfigs[i], url);
if (newUrl !== null) {
return newUrl;
}
}
}
}
return url;
}
/**
* Test regex on url and apply it
* @param config
* @param url
*/
_testAndReplaceUrl(config, url) {
let rawRegexp = config.regexp;
let regexp = new RegExp(rawRegexp, 'i');
if(regexp.test(url)) {
// If matched, we invert the replacing group to replace the good ones
let invertedRegExp = this._invertRegexpGroups(rawRegexp);
let iRegExp = new RegExp(invertedRegExp,'i');
// We fetch the replacement data to replace the group
let replacementKey = config.replacement_key;
let replacement = null;
Eif (config.type === 'token' && this.token && this.token.hasOwnProperty(replacementKey)) {
replacement = this.token[replacementKey];
}
Eif (replacement !== null) {
// We recompose the url with the replacement
return url.replace(iRegExp, ['$1',replacement,'$2'].join(''));
}
}
return null;
}
/**
* invert the replacing group to replace the good ones
* @param regexp
*/
_invertRegexpGroups(regexp) {
let startGroup = regexp.indexOf('(');
let stopGroup = regexp.indexOf(')');
let invertedRegExp = [
'(',
regexp.substring(0, startGroup),
')',
regexp.substring(startGroup+1, stopGroup),
'(',
regexp.substring(stopGroup+1),
')'].join('');
return invertedRegExp;
}
}
module.exports = MockCtrl;
|