bifocal/node_modules/@sentry/node/cjs/transports/http.js

162 lines
4.7 KiB
JavaScript

var {
_nullishCoalesce
} = require('@sentry/utils');
Object.defineProperty(exports, '__esModule', { value: true });
const http = require('http');
const https = require('https');
const stream = require('stream');
const url = require('url');
const zlib = require('zlib');
const core = require('@sentry/core');
const utils = require('@sentry/utils');
const index = require('../proxy/index.js');
// Estimated maximum size for reasonable standalone event
const GZIP_THRESHOLD = 1024 * 32;
/**
* Gets a stream from a Uint8Array or string
* Readable.from is ideal but was added in node.js v12.3.0 and v10.17.0
*/
function streamFromBody(body) {
return new stream.Readable({
read() {
this.push(body);
this.push(null);
},
});
}
/**
* Creates a Transport that uses native the native 'http' and 'https' modules to send events to Sentry.
*/
function makeNodeTransport(options) {
let urlSegments;
try {
urlSegments = new url.URL(options.url);
} catch (e) {
utils.consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn(
'[@sentry/node]: Invalid dsn or tunnel option, will not send any events. The tunnel option must be a full URL when used.',
);
});
return core.createTransport(options, () => Promise.resolve({}));
}
const isHttps = urlSegments.protocol === 'https:';
// Proxy prioritization: http => `options.proxy` | `process.env.http_proxy`
// Proxy prioritization: https => `options.proxy` | `process.env.https_proxy` | `process.env.http_proxy`
const proxy = applyNoProxyOption(
urlSegments,
options.proxy || (isHttps ? process.env.https_proxy : undefined) || process.env.http_proxy,
);
const nativeHttpModule = isHttps ? https : http;
const keepAlive = options.keepAlive === undefined ? false : options.keepAlive;
// TODO(v7): Evaluate if we can set keepAlive to true. This would involve testing for memory leaks in older node
// versions(>= 8) as they had memory leaks when using it: #2555
const agent = proxy
? (new index.HttpsProxyAgent(proxy) )
: new nativeHttpModule.Agent({ keepAlive, maxSockets: 30, timeout: 2000 });
const requestExecutor = createRequestExecutor(options, _nullishCoalesce(options.httpModule, () => ( nativeHttpModule)), agent);
return core.createTransport(options, requestExecutor);
}
/**
* Honors the `no_proxy` env variable with the highest priority to allow for hosts exclusion.
*
* @param transportUrl The URL the transport intends to send events to.
* @param proxy The client configured proxy.
* @returns A proxy the transport should use.
*/
function applyNoProxyOption(transportUrlSegments, proxy) {
const { no_proxy } = process.env;
const urlIsExemptFromProxy =
no_proxy &&
no_proxy
.split(',')
.some(
exemption => transportUrlSegments.host.endsWith(exemption) || transportUrlSegments.hostname.endsWith(exemption),
);
if (urlIsExemptFromProxy) {
return undefined;
} else {
return proxy;
}
}
/**
* Creates a RequestExecutor to be used with `createTransport`.
*/
function createRequestExecutor(
options,
httpModule,
agent,
) {
const { hostname, pathname, port, protocol, search } = new url.URL(options.url);
return function makeRequest(request) {
return new Promise((resolve, reject) => {
let body = streamFromBody(request.body);
const headers = { ...options.headers };
if (request.body.length > GZIP_THRESHOLD) {
headers['content-encoding'] = 'gzip';
body = body.pipe(zlib.createGzip());
}
const req = httpModule.request(
{
method: 'POST',
agent,
headers,
hostname,
path: `${pathname}${search}`,
port,
protocol,
ca: options.caCerts,
},
res => {
res.on('data', () => {
// Drain socket
});
res.on('end', () => {
// Drain socket
});
res.setEncoding('utf8');
// "Key-value pairs of header names and values. Header names are lower-cased."
// https://nodejs.org/api/http.html#http_message_headers
const retryAfterHeader = _nullishCoalesce(res.headers['retry-after'], () => ( null));
const rateLimitsHeader = _nullishCoalesce(res.headers['x-sentry-rate-limits'], () => ( null));
resolve({
statusCode: res.statusCode,
headers: {
'retry-after': retryAfterHeader,
'x-sentry-rate-limits': Array.isArray(rateLimitsHeader) ? rateLimitsHeader[0] : rateLimitsHeader,
},
});
},
);
req.on('error', reject);
body.pipe(req);
});
};
}
exports.makeNodeTransport = makeNodeTransport;
//# sourceMappingURL=http.js.map