@belmonddev/catch-request-express-middleware 3.2.0 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +38 -9
- package/package.json +3 -9
- package/deleteme.js +0 -175
package/index.js
CHANGED
|
@@ -56,26 +56,55 @@ const catchHttpResponse = (reqObject, responseCb) => {
|
|
|
56
56
|
});
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
const transformHeaderValues = (headers) => {
|
|
60
|
+
let transformedHeaders = {};
|
|
61
|
+
const headerEntries = Object.entries(headers);
|
|
62
|
+
headerEntries.forEach(([key, value]) => {
|
|
63
|
+
transformedHeaders[key] = typeof value === 'string' ? [value] : value;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return transformedHeaders;
|
|
67
|
+
};
|
|
68
|
+
|
|
59
69
|
const overrideHttpModule = (httpModule, requestSentCb) => {
|
|
60
|
-
override(httpModule, 'request', (reqObject, request) => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
override(httpModule, 'request', (reqObject, urlOrRequest, request) => {
|
|
71
|
+
// node-fetch v3+ will return the 2nd arg as url, so correctly identify the request object
|
|
72
|
+
request = typeof urlOrRequest === 'string' ? request : urlOrRequest;
|
|
73
|
+
|
|
74
|
+
// transform headers to use array values instead of string
|
|
75
|
+
const headers = transformHeaderValues(request.headers);
|
|
76
|
+
const contentLength = getHeaderValue(headers || {}, 'content-length');
|
|
65
77
|
const requestHasBody = !!contentLength;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
);
|
|
78
|
+
|
|
79
|
+
const [pathname, query] = request.path.split('?');
|
|
80
|
+
const params = Object.fromEntries(new URLSearchParams(query).entries());
|
|
81
|
+
|
|
82
|
+
// add values not included in node-fetch v3+
|
|
83
|
+
request = {
|
|
84
|
+
...request,
|
|
85
|
+
href: `${reqObject.protocol}//${reqObject.host}${request.path}`,
|
|
86
|
+
protocol: reqObject.protocol,
|
|
87
|
+
host: reqObject.host,
|
|
88
|
+
search: `&${query}`,
|
|
89
|
+
pathname,
|
|
90
|
+
query,
|
|
91
|
+
};
|
|
69
92
|
|
|
70
93
|
let responseCb;
|
|
71
94
|
if (requestHasBody) {
|
|
95
|
+
let requestBody = '';
|
|
72
96
|
override(reqObject, 'write', (result, data) => {
|
|
73
97
|
const body = data.toString();
|
|
98
|
+
requestBody += body;
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
override(reqObject, 'end', () => {
|
|
74
102
|
responseCb = requestSentCb({
|
|
75
103
|
...request,
|
|
76
104
|
params,
|
|
77
|
-
body,
|
|
105
|
+
body: requestBody,
|
|
78
106
|
});
|
|
107
|
+
|
|
79
108
|
if (responseCb) {
|
|
80
109
|
catchHttpResponse(reqObject, responseCb);
|
|
81
110
|
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@belmonddev/catch-request-express-middleware",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.2",
|
|
4
4
|
"main": "index.js",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"start": "nodemon -L --experimental-specifier-resolution=node ./src/index.js"
|
|
7
|
-
},
|
|
8
5
|
"author": "David Escalera",
|
|
9
6
|
"license": "ISC",
|
|
10
|
-
"
|
|
11
|
-
"devDependencies": {
|
|
12
|
-
"nodemon": "^2.0.7"
|
|
13
|
-
},
|
|
7
|
+
"description": "",
|
|
14
8
|
"type": "module",
|
|
15
|
-
"
|
|
9
|
+
"dependencies": {}
|
|
16
10
|
}
|
package/deleteme.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import http from 'http';
|
|
2
|
-
import https from 'https';
|
|
3
|
-
import zlib from 'zlib';
|
|
4
|
-
|
|
5
|
-
const override = (module, attr, fn) => {
|
|
6
|
-
let original = module[attr];
|
|
7
|
-
|
|
8
|
-
function wrapper(...args) {
|
|
9
|
-
const result = original.apply(this, args);
|
|
10
|
-
fn.apply(this, [result, ...args]);
|
|
11
|
-
return result;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
module[attr] = wrapper;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const getHeaderValue = (headers, key) =>
|
|
18
|
-
Object.entries(headers).find(([k]) => k.toLowerCase() === key)?.[1];
|
|
19
|
-
|
|
20
|
-
const catchHttpResponse = (reqObject, responseCb) => {
|
|
21
|
-
override(reqObject, 'emit', (result, eventName, response) => {
|
|
22
|
-
const chunks = [];
|
|
23
|
-
switch (eventName) {
|
|
24
|
-
case 'response': {
|
|
25
|
-
response.on('data', (d) => {
|
|
26
|
-
chunks.push(d);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
response.on('end', () => {
|
|
30
|
-
const responseObj = {
|
|
31
|
-
headers: response.headers,
|
|
32
|
-
statusCode: response.statusCode,
|
|
33
|
-
statusMessage: response.statusMessage,
|
|
34
|
-
};
|
|
35
|
-
const contentEncoding = getHeaderValue(
|
|
36
|
-
response.headers,
|
|
37
|
-
'content-encoding'
|
|
38
|
-
);
|
|
39
|
-
if (['gzip', 'deflate'].indexOf(contentEncoding) !== -1) {
|
|
40
|
-
const buffer = Buffer.concat(chunks);
|
|
41
|
-
const zlibFunc =
|
|
42
|
-
contentEncoding === 'gzip' ? zlib.gunzip : zlib.inflate;
|
|
43
|
-
zlibFunc(buffer, (_, decoded) => {
|
|
44
|
-
const stringBody = decoded.toString('utf8');
|
|
45
|
-
const request = { ...responseObj, body: stringBody };
|
|
46
|
-
responseCb(request);
|
|
47
|
-
});
|
|
48
|
-
} else {
|
|
49
|
-
const stringBody = chunks.map((c) => c.toString('utf8')).join('');
|
|
50
|
-
const request = { ...responseObj, body: stringBody };
|
|
51
|
-
responseCb(request);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const overrideHttpModule = (httpModule, requestSentCb) => {
|
|
60
|
-
override(httpModule, 'request', (reqObject, request) => {
|
|
61
|
-
const contentLength = getHeaderValue(
|
|
62
|
-
request.headers || {},
|
|
63
|
-
'content-length'
|
|
64
|
-
);
|
|
65
|
-
const requestHasBody = !!contentLength;
|
|
66
|
-
const params = Object.fromEntries(
|
|
67
|
-
new URLSearchParams(request.query).entries()
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
if (requestHasBody) {
|
|
71
|
-
override(reqObject, 'write', (result, data) => {
|
|
72
|
-
const body = data.toString();
|
|
73
|
-
const responseCb = requestSentCb({
|
|
74
|
-
...request,
|
|
75
|
-
params,
|
|
76
|
-
body,
|
|
77
|
-
});
|
|
78
|
-
if (responseCb) {
|
|
79
|
-
catchHttpResponse(reqObject, responseCb);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
} else {
|
|
83
|
-
const responseCb = requestSentCb({ ...request, params, body: null });
|
|
84
|
-
if (responseCb) {
|
|
85
|
-
catchHttpResponse(reqObject, responseCb);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const callResponseCb = (responseCb, res) => {
|
|
92
|
-
const response = {
|
|
93
|
-
headers: res.getHeaders(),
|
|
94
|
-
statusCode: res.statusCode,
|
|
95
|
-
statusMessage: res.statusMessage,
|
|
96
|
-
body: res.bodyWritten,
|
|
97
|
-
};
|
|
98
|
-
responseCb(response);
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const callReceivedCbs = (req, res, requestReceivedCb, body) => {
|
|
102
|
-
const responseCb = requestReceivedCb({
|
|
103
|
-
originalRequest: req,
|
|
104
|
-
headers: req.headers,
|
|
105
|
-
method: req.method,
|
|
106
|
-
host: req.headers.host,
|
|
107
|
-
pathname: req._parsedUrl.pathname,
|
|
108
|
-
params: req.params,
|
|
109
|
-
query: req.query,
|
|
110
|
-
body,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
if (responseCb) {
|
|
114
|
-
res.setMaxListeners(100);
|
|
115
|
-
if (res.writableFinished) {
|
|
116
|
-
callResponseCb(responseCb, res);
|
|
117
|
-
} else {
|
|
118
|
-
res.on('finish', () => {
|
|
119
|
-
callResponseCb(responseCb, res);
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
const catchExpressReceivedRequest = (req, res, requestReceivedCb) => {
|
|
126
|
-
// we override write method ASAP cause otherwise if the request finishes too fast the response callback is not called
|
|
127
|
-
let writeCount = 0;
|
|
128
|
-
let firstData = '';
|
|
129
|
-
override(req.socket, 'write', (result, data) => {
|
|
130
|
-
writeCount++;
|
|
131
|
-
if (writeCount === 1) {
|
|
132
|
-
firstData = data;
|
|
133
|
-
} else if (writeCount === 2) {
|
|
134
|
-
res.bodyWritten = data.toString();
|
|
135
|
-
if (!res.bodyWritten.length) {
|
|
136
|
-
res.bodyWritten = firstData.split('\r\n\r\n')?.[1];
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
if (req.body !== undefined) {
|
|
142
|
-
callReceivedCbs(req, res, requestReceivedCb, req.body);
|
|
143
|
-
} else {
|
|
144
|
-
const contentLength = getHeaderValue(req.headers, 'content-length');
|
|
145
|
-
if (contentLength) {
|
|
146
|
-
let body = '';
|
|
147
|
-
req.on('data', function (data) {
|
|
148
|
-
body += data;
|
|
149
|
-
});
|
|
150
|
-
req.on('end', function () {
|
|
151
|
-
callReceivedCbs(req, res, requestReceivedCb, body);
|
|
152
|
-
});
|
|
153
|
-
} else {
|
|
154
|
-
callReceivedCbs(req, res, requestReceivedCb, '');
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
const catchRequestExpressMiddleware = (
|
|
160
|
-
requestReceivedCb = null,
|
|
161
|
-
requestSentCb = null
|
|
162
|
-
) => {
|
|
163
|
-
if (requestSentCb) {
|
|
164
|
-
overrideHttpModule(http, requestSentCb);
|
|
165
|
-
overrideHttpModule(https, requestSentCb);
|
|
166
|
-
}
|
|
167
|
-
return (req, res, next) => {
|
|
168
|
-
if (requestReceivedCb) {
|
|
169
|
-
catchExpressReceivedRequest(req, res, requestReceivedCb);
|
|
170
|
-
}
|
|
171
|
-
next();
|
|
172
|
-
};
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
export default catchRequestExpressMiddleware;
|