server.js
7.43 KB
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/**
* Guzzle node.js test server to return queued responses to HTTP requests and
* expose a RESTful API for enqueueing responses and retrieving the requests
* that have been received.
*
* - Delete all requests that have been received:
* > DELETE /guzzle-server/requests
* > Host: 127.0.0.1:8126
*
* - Enqueue responses
* > PUT /guzzle-server/responses
* > Host: 127.0.0.1:8126
* >
* > [{'status': 200, 'reason': 'OK', 'headers': {}, 'body': '' }]
*
* - Get the received requests
* > GET /guzzle-server/requests
* > Host: 127.0.0.1:8126
*
* < HTTP/1.1 200 OK
* <
* < [{'http_method': 'GET', 'uri': '/', 'headers': {}, 'body': 'string'}]
*
* - Attempt access to the secure area
* > GET /secure/by-digest/qop-auth/guzzle-server/requests
* > Host: 127.0.0.1:8126
*
* < HTTP/1.1 401 Unauthorized
* < WWW-Authenticate: Digest realm="Digest Test", qop="auth", nonce="0796e98e1aeef43141fab2a66bf4521a", algorithm="MD5", stale="false"
* <
* < 401 Unauthorized
*
* - Shutdown the server
* > DELETE /guzzle-server
* > Host: 127.0.0.1:8126
*
* @package Guzzle PHP <http://www.guzzlephp.org>
* @license See the LICENSE file that was distributed with this source code.
*/
var http = require('http');
var url = require('url');
/**
* Guzzle node.js server
* @class
*/
var GuzzleServer = function(port, log) {
this.port = port;
this.log = log;
this.responses = [];
this.requests = [];
var that = this;
var md5 = function(input) {
var crypto = require('crypto');
var hasher = crypto.createHash('md5');
hasher.update(input);
return hasher.digest('hex');
};
/**
* Node.js HTTP server authentication module.
*
* It is only initialized on demand (by loadAuthentifier). This avoids
* requiring the dependency to http-auth on standard operations, and the
* performance hit at startup.
*/
var auth;
/**
* Provides authentication handlers (Basic, Digest).
*/
var loadAuthentifier = function(type, options) {
var typeId = type;
if (type == 'digest') {
typeId += '.'+(options && options.qop ? options.qop : 'none');
}
if (!loadAuthentifier[typeId]) {
if (!auth) {
try {
auth = require('http-auth');
} catch (e) {
if (e.code == 'MODULE_NOT_FOUND') {
return;
}
}
}
switch (type) {
case 'digest':
var digestParams = {
realm: 'Digest Test',
login: 'me',
password: 'test'
};
if (options && options.qop) {
digestParams.qop = options.qop;
}
loadAuthentifier[typeId] = auth.digest(digestParams, function(username, callback) {
callback(md5(digestParams.login + ':' + digestParams.realm + ':' + digestParams.password));
});
break
}
}
return loadAuthentifier[typeId];
};
var firewallRequest = function(request, req, res, requestHandlerCallback) {
var securedAreaUriParts = request.uri.match(/^\/secure\/by-(digest)(\/qop-([^\/]*))?(\/.*)$/);
if (securedAreaUriParts) {
var authentifier = loadAuthentifier(securedAreaUriParts[1], { qop: securedAreaUriParts[2] });
if (!authentifier) {
res.writeHead(501, 'HTTP authentication not implemented', { 'Content-Length': 0 });
res.end();
return;
}
authentifier.check(req, res, function(req, res) {
req.url = securedAreaUriParts[4];
requestHandlerCallback(request, req, res);
});
} else {
requestHandlerCallback(request, req, res);
}
};
var controlRequest = function(request, req, res) {
if (req.url == '/guzzle-server/perf') {
res.writeHead(200, 'OK', {'Content-Length': 16});
res.end('Body of response');
} else if (req.method == 'DELETE') {
if (req.url == '/guzzle-server/requests') {
// Clear the received requests
that.requests = [];
res.writeHead(200, 'OK', { 'Content-Length': 0 });
res.end();
if (that.log) {
console.log('Flushing requests');
}
} else if (req.url == '/guzzle-server') {
// Shutdown the server
res.writeHead(200, 'OK', { 'Content-Length': 0, 'Connection': 'close' });
res.end();
if (that.log) {
console.log('Shutting down');
}
that.server.close();
}
} else if (req.method == 'GET') {
if (req.url === '/guzzle-server/requests') {
if (that.log) {
console.log('Sending received requests');
}
// Get received requests
var body = JSON.stringify(that.requests);
res.writeHead(200, 'OK', { 'Content-Length': body.length });
res.end(body);
} else if (req.url == '/guzzle-server/read-timeout') {
if (that.log) {
console.log('Sleeping');
}
res.writeHead(200, 'OK');
res.write("sleeping 60 seconds ...\n");
setTimeout(function () {
res.end("slept 60 seconds\n");
}, 60*1000);
}
} else if (req.method == 'PUT' && req.url == '/guzzle-server/responses') {
if (that.log) {
console.log('Adding responses...');
}
if (!request.body) {
if (that.log) {
console.log('No response data was provided');
}
res.writeHead(400, 'NO RESPONSES IN REQUEST', { 'Content-Length': 0 });
} else {
that.responses = eval('(' + request.body + ')');
for (var i = 0; i < that.responses.length; i++) {
if (that.responses[i].body) {
that.responses[i].body = new Buffer(that.responses[i].body, 'base64');
}
}
if (that.log) {
console.log(that.responses);
}
res.writeHead(200, 'OK', { 'Content-Length': 0 });
}
res.end();
}
};
var receivedRequest = function(request, req, res) {
if (req.url.indexOf('/guzzle-server') === 0) {
controlRequest(request, req, res);
} else if (req.url.indexOf('/guzzle-server') == -1 && !that.responses.length) {
res.writeHead(500);
res.end('No responses in queue');
} else {
if (that.log) {
console.log('Returning response from queue and adding request');
}
that.requests.push(request);
var response = that.responses.shift();
res.writeHead(response.status, response.reason, response.headers);
res.end(response.body);
}
};
this.start = function() {
that.server = http.createServer(function(req, res) {
var parts = url.parse(req.url, false);
var request = {
http_method: req.method,
scheme: parts.scheme,
uri: parts.pathname,
query_string: parts.query,
headers: req.headers,
version: req.httpVersion,
body: ''
};
// Receive each chunk of the request body
req.addListener('data', function(chunk) {
request.body += chunk;
});
// Called when the request completes
req.addListener('end', function() {
firewallRequest(request, req, res, receivedRequest);
});
});
that.server.listen(this.port, '127.0.0.1');
if (this.log) {
console.log('Server running at http://127.0.0.1:8126/');
}
};
};
// Get the port from the arguments
port = process.argv.length >= 3 ? process.argv[2] : 8126;
log = process.argv.length >= 4 ? process.argv[3] : false;
// Start the server
server = new GuzzleServer(port, log);
server.start();