-
Notifications
You must be signed in to change notification settings - Fork 1
/
ccc-http.js
110 lines (83 loc) · 4.49 KB
/
ccc-http.js
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
const debug = require('debug')('cdn-cache-check-http');
debug('Entry: [%s]', __filename);
//Load configuration library
const config = require('./ccc-configuration');
// Initialise 'needle' HTTP client
const needle = require('needle');
let issueRequests = (urls, settings) => {
debug('issueRequests() :: Entry');
return new Promise(function (resolve, reject) {
if ((Array.isArray(urls) && urls.length)) { // Process urls[] array
// Keep array of request/response headers
let responses = [];
// Initialise variable to keep track of progress
let requestCounter = 0;
debug(`The urls[] array has ${urls.length} entries`);
for (let i = 0; i < urls.length; i++) { // Loop through each URL
requestCounter++; // Increment the request counter
debug(`(${requestCounter} of ${urls.length}) - Issuing HTTP ${settings.method.toUpperCase()} request to [${urls[i]}]...`);
// Initialise result object
let result = config.initResponseObject();
// Parse URL into component parts
let requestURL = new URL(urls[i]);
// Populate the request properties for reference
result.request.protocol = requestURL.protocol;
result.request.host = requestURL.hostname;
result.request.path = requestURL.pathname;
result.request.url = urls[i];
// Send HTTP request for current URL
let resp = needle.request(settings.method, urls[i], '', settings.options.httpOptions, (error, response) => {
debug('Callback for [%s] received', urls[i]);
if (error) {
debug('Error for [%s]: %O', urls[i], error);
// Log error to JSON result
result.error = true;
result.response.headers = [];
// The 'error' object may have different properties depending on the cause (e.g. HTTP error vs network error)
if (Object.prototype.hasOwnProperty.call(error, 'code')) {
result.statusCode = error.code;
} else if (Object.prototype.hasOwnProperty.call(error, 'message')) {
result.statusCode = error.message;
} else {
result.statusCode = 'error';
debug('A response error occurred when requesting [%s] but the specific error code could not be extracted from the error object:', urls[i]);
debug(error);
}
} else {
// We got a HTTP response
debug(`${response.statusCode} ${urls[i]}`);
// Save request details and HTTP response headers as JSON
result.statusCode = response.statusCode;
result.request.protocol = response.req.protocol;
result.request.host = response.req.host;
result.request.path = response.req.path;
result.response.headers = response.headers;
// Get IP Address from response if it exists
if (typeof (response.socket?.remoteAddress) === 'string') {
result.ipAddress = response.socket.remoteAddress;
}
// Get the IP Family (IPv4 or IPv6) from the response if it exists
if (typeof (response.socket?.remoteFamily) === 'string') {
result.ipFamily = response.socket.remoteFamily;
}
}
// Add request/response result to array (for later parsing once we have them all)
responses.push(result);
debug('Completed request %s of %s', responses.length, urls.length);
if (responses.length === urls.length) {
debug(`About to resolve the issueRequests() Promise after ${responses.length} responses out of ${urls.length} requests`);
resolve(responses);
}
});
resp.on('redirect', (url) => {
result.redirectCount += 1;
debug('redirectCount incremented to %s by redirect event to [%s] ', result.redirectCount, url);
});
}
} else {
// urls[] array does not exist, is not an array, or is empty ⇒ do not attempt to process url array
reject(new Error('issueRequests() :: urls[]] array either does not exist, is not an array, or is empty.'));
}
});
};
module.exports = { issueRequests };