155 lines
6.5 KiB
JavaScript
155 lines
6.5 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.redactObjectForLogging = exports.doHttpRequest = void 0;
|
|
const LogService_1 = require("./logging/LogService");
|
|
const request_1 = require("./request");
|
|
const MatrixError_1 = require("./models/MatrixError");
|
|
let lastRequestId = 0;
|
|
const defaultErrorHandler = (response, errBody) => {
|
|
return typeof (errBody) === "object" && 'errcode' in errBody ?
|
|
new MatrixError_1.MatrixError(errBody, response.statusCode, response.headers) : undefined;
|
|
};
|
|
/**
|
|
* Performs a web request to a server.
|
|
* @category Unit testing
|
|
* @param {string} baseUrl The base URL to apply to the call.
|
|
* @param {"GET"|"POST"|"PUT"|"DELETE"} method The HTTP method to use in the request
|
|
* @param {string} endpoint The endpoint to call. For example: "/_matrix/client/v3/account/whoami"
|
|
* @param {any} qs The query string to send. Optional.
|
|
* @param {any} body The request body to send. Optional. Will be converted to JSON unless the type is a Buffer.
|
|
* @param {any} headers Additional headers to send in the request.
|
|
* @param {number} timeout The number of milliseconds to wait before timing out.
|
|
* @param {boolean} raw If true, the raw response will be returned instead of the response body.
|
|
* @param {string} contentType The content type to send. Only used if the `body` is a Buffer.
|
|
* @param {string} noEncoding Set to true to disable encoding, and return a Buffer. Defaults to false
|
|
* @returns {Promise<any>} Resolves to the response (body), rejected if a non-2xx status code was returned.
|
|
*/
|
|
async function doHttpRequest(baseUrl, method, endpoint, qs = null, body = null, headers = {}, timeout = 60000, raw = false, contentType = "application/json", noEncoding = false, opts = {
|
|
errorHandler: defaultErrorHandler,
|
|
}) {
|
|
if (!endpoint.startsWith('/')) {
|
|
endpoint = '/' + endpoint;
|
|
}
|
|
const requestId = ++lastRequestId;
|
|
const url = baseUrl + endpoint;
|
|
// This is logged at info so that when a request fails people can figure out which one.
|
|
LogService_1.LogService.debug("MatrixHttpClient", "(REQ-" + requestId + ")", method + " " + url);
|
|
// Don't log the request unless we're in debug mode. It can be large.
|
|
if (LogService_1.LogService.level.includes(LogService_1.LogLevel.TRACE)) {
|
|
if (qs)
|
|
LogService_1.LogService.trace("MatrixHttpClient", "(REQ-" + requestId + ")", "qs = " + JSON.stringify(qs));
|
|
if (body && !Buffer.isBuffer(body))
|
|
LogService_1.LogService.trace("MatrixHttpClient", "(REQ-" + requestId + ")", "body = " + JSON.stringify(redactObjectForLogging(body)));
|
|
if (body && Buffer.isBuffer(body))
|
|
LogService_1.LogService.trace("MatrixHttpClient", "(REQ-" + requestId + ")", "body = <Buffer>");
|
|
}
|
|
const params = {
|
|
uri: url,
|
|
method: method,
|
|
qs: qs,
|
|
// If this is undefined, then a string will be returned. If it's null, a Buffer will be returned.
|
|
encoding: noEncoding === false ? undefined : null,
|
|
useQuerystring: true,
|
|
qsStringifyOptions: {
|
|
options: { arrayFormat: 'repeat' },
|
|
},
|
|
timeout: timeout,
|
|
headers: headers,
|
|
// Enable KeepAlive for HTTP
|
|
forever: true,
|
|
};
|
|
if (body) {
|
|
if (Buffer.isBuffer(body)) {
|
|
params.headers["Content-Type"] = contentType;
|
|
params.body = body;
|
|
}
|
|
else {
|
|
params.headers["Content-Type"] = "application/json";
|
|
params.body = JSON.stringify(body);
|
|
}
|
|
}
|
|
const { response, resBody } = await new Promise((resolve, reject) => {
|
|
(0, request_1.getRequestFn)()(params, (err, res, rBody) => {
|
|
if (err) {
|
|
LogService_1.LogService.error("MatrixHttpClient", "(REQ-" + requestId + ")", err);
|
|
reject(err);
|
|
return;
|
|
}
|
|
if (typeof (rBody) === 'string') {
|
|
try {
|
|
rBody = JSON.parse(rBody);
|
|
}
|
|
catch (e) {
|
|
}
|
|
}
|
|
if (typeof (res.body) === 'string') {
|
|
try {
|
|
res.body = JSON.parse(res.body);
|
|
}
|
|
catch (e) {
|
|
}
|
|
}
|
|
resolve({ response: res, resBody: rBody });
|
|
});
|
|
});
|
|
const respIsBuffer = (response.body instanceof Buffer);
|
|
// Check for errors.
|
|
const errBody = response.body || resBody;
|
|
const handledError = opts.errorHandler(response, errBody);
|
|
if (handledError) {
|
|
const redactedBody = respIsBuffer ? '<Buffer>' : redactObjectForLogging(errBody);
|
|
LogService_1.LogService.error("MatrixHttpClient", "(REQ-" + requestId + ")", redactedBody);
|
|
throw handledError;
|
|
}
|
|
// Don't log the body unless we're in debug mode. They can be large.
|
|
if (LogService_1.LogService.level.includes(LogService_1.LogLevel.TRACE)) {
|
|
const redactedBody = respIsBuffer ? '<Buffer>' : redactObjectForLogging(response.body);
|
|
LogService_1.LogService.trace("MatrixHttpClient", "(REQ-" + requestId + " RESP-H" + response.statusCode + ")", redactedBody);
|
|
}
|
|
if (response.statusCode < 200 || response.statusCode >= 300) {
|
|
const redactedBody = respIsBuffer ? '<Buffer>' : redactObjectForLogging(response.body);
|
|
LogService_1.LogService.error("MatrixHttpClient", "(REQ-" + requestId + ")", redactedBody);
|
|
throw response;
|
|
}
|
|
return raw ? response : resBody;
|
|
}
|
|
exports.doHttpRequest = doHttpRequest;
|
|
function redactObjectForLogging(input) {
|
|
if (!input)
|
|
return input;
|
|
const fieldsToRedact = [
|
|
'access_token',
|
|
'password',
|
|
'new_password',
|
|
];
|
|
const redactFn = (i) => {
|
|
if (!i)
|
|
return i;
|
|
// Don't treat strings like arrays/objects
|
|
if (typeof i === 'string')
|
|
return i;
|
|
if (Array.isArray(i)) {
|
|
const rebuilt = [];
|
|
for (const v of i) {
|
|
rebuilt.push(redactFn(v));
|
|
}
|
|
return rebuilt;
|
|
}
|
|
if (i instanceof Object) {
|
|
const rebuilt = {};
|
|
for (const key of Object.keys(i)) {
|
|
if (fieldsToRedact.includes(key)) {
|
|
rebuilt[key] = '<redacted>';
|
|
}
|
|
else {
|
|
rebuilt[key] = redactFn(i[key]);
|
|
}
|
|
}
|
|
return rebuilt;
|
|
}
|
|
return i; // It's a primitive value
|
|
};
|
|
return redactFn(input);
|
|
}
|
|
exports.redactObjectForLogging = redactObjectForLogging;
|
|
//# sourceMappingURL=http.js.map
|