1 | Object.defineProperty(exports, "__esModule", { value: true });
|
2 | var tslib_1 = require("tslib");
|
3 | var core_1 = require("@sentry/core");
|
4 | var types_1 = require("@sentry/types");
|
5 | var utils_1 = require("@sentry/utils");
|
6 | var fs = require("fs");
|
7 | var url_1 = require("url");
|
8 | var version_1 = require("../../version");
|
9 | var CATEGORY_MAPPING = {
|
10 | event: 'error',
|
11 | transaction: 'transaction',
|
12 | session: 'session',
|
13 | attachment: 'attachment',
|
14 | };
|
15 |
|
16 | var BaseTransport = (function () {
|
17 |
|
18 | function BaseTransport(options) {
|
19 | this.options = options;
|
20 |
|
21 | this._buffer = new utils_1.PromiseBuffer(30);
|
22 |
|
23 | this._rateLimits = {};
|
24 |
|
25 | this.urlParser = function (url) { return new url_1.URL(url); };
|
26 | this._api = new core_1.API(options.dsn, options._metadata, options.tunnel);
|
27 | }
|
28 | |
29 |
|
30 |
|
31 | BaseTransport.prototype.sendEvent = function (_) {
|
32 | throw new utils_1.SentryError('Transport Class has to implement `sendEvent` method.');
|
33 | };
|
34 | |
35 |
|
36 |
|
37 | BaseTransport.prototype.close = function (timeout) {
|
38 | return this._buffer.drain(timeout);
|
39 | };
|
40 | |
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | BaseTransport.prototype._getProxy = function (protocol) {
|
50 | var e_1, _a;
|
51 | var _b = process.env, no_proxy = _b.no_proxy, http_proxy = _b.http_proxy, https_proxy = _b.https_proxy;
|
52 | var _c = this.options, httpProxy = _c.httpProxy, httpsProxy = _c.httpsProxy;
|
53 | var proxy = protocol === 'http' ? httpProxy || http_proxy : httpsProxy || httpProxy || https_proxy || http_proxy;
|
54 | if (!no_proxy) {
|
55 | return proxy;
|
56 | }
|
57 | var _d = this._api.getDsn(), host = _d.host, port = _d.port;
|
58 | try {
|
59 | for (var _e = tslib_1.__values(no_proxy.split(',')), _f = _e.next(); !_f.done; _f = _e.next()) {
|
60 | var np = _f.value;
|
61 | if (host.endsWith(np) || (host + ":" + port).endsWith(np)) {
|
62 | return;
|
63 | }
|
64 | }
|
65 | }
|
66 | catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
67 | finally {
|
68 | try {
|
69 | if (_f && !_f.done && (_a = _e.return)) _a.call(_e);
|
70 | }
|
71 | finally { if (e_1) throw e_1.error; }
|
72 | }
|
73 | return proxy;
|
74 | };
|
75 |
|
76 | BaseTransport.prototype._getRequestOptions = function (urlParts) {
|
77 | var headers = tslib_1.__assign(tslib_1.__assign({}, this._api.getRequestHeaders(version_1.SDK_NAME, core_1.SDK_VERSION)), this.options.headers);
|
78 | var hostname = urlParts.hostname, pathname = urlParts.pathname, port = urlParts.port, protocol = urlParts.protocol;
|
79 |
|
80 |
|
81 | var path = "" + pathname;
|
82 | return tslib_1.__assign({ agent: this.client, headers: headers,
|
83 | hostname: hostname, method: 'POST', path: path,
|
84 | port: port,
|
85 | protocol: protocol }, (this.options.caCerts && {
|
86 | ca: fs.readFileSync(this.options.caCerts),
|
87 | }));
|
88 | };
|
89 | |
90 |
|
91 |
|
92 | BaseTransport.prototype._disabledUntil = function (requestType) {
|
93 | var category = CATEGORY_MAPPING[requestType];
|
94 | return this._rateLimits[category] || this._rateLimits.all;
|
95 | };
|
96 | |
97 |
|
98 |
|
99 | BaseTransport.prototype._isRateLimited = function (requestType) {
|
100 | return this._disabledUntil(requestType) > new Date(Date.now());
|
101 | };
|
102 | |
103 |
|
104 |
|
105 | BaseTransport.prototype._handleRateLimit = function (headers) {
|
106 | var e_2, _a, e_3, _b;
|
107 | var now = Date.now();
|
108 | var rlHeader = headers['x-sentry-rate-limits'];
|
109 | var raHeader = headers['retry-after'];
|
110 | if (rlHeader) {
|
111 | try {
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 | for (var _c = tslib_1.__values(rlHeader.trim().split(',')), _d = _c.next(); !_d.done; _d = _c.next()) {
|
123 | var limit = _d.value;
|
124 | var parameters = limit.split(':', 2);
|
125 | var headerDelay = parseInt(parameters[0], 10);
|
126 | var delay = (!isNaN(headerDelay) ? headerDelay : 60) * 1000;
|
127 | try {
|
128 | for (var _e = (e_3 = void 0, tslib_1.__values((parameters[1] && parameters[1].split(';')) || ['all'])), _f = _e.next(); !_f.done; _f = _e.next()) {
|
129 | var category = _f.value;
|
130 |
|
131 |
|
132 | var categoriesAllowed = tslib_1.__spread(Object.keys(CATEGORY_MAPPING).map(function (k) { return CATEGORY_MAPPING[k]; }), [
|
133 | 'all',
|
134 | ]);
|
135 | if (categoriesAllowed.includes(category))
|
136 | this._rateLimits[category] = new Date(now + delay);
|
137 | }
|
138 | }
|
139 | catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
140 | finally {
|
141 | try {
|
142 | if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
|
143 | }
|
144 | finally { if (e_3) throw e_3.error; }
|
145 | }
|
146 | }
|
147 | }
|
148 | catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
149 | finally {
|
150 | try {
|
151 | if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
152 | }
|
153 | finally { if (e_2) throw e_2.error; }
|
154 | }
|
155 | return true;
|
156 | }
|
157 | else if (raHeader) {
|
158 | this._rateLimits.all = new Date(now + utils_1.parseRetryAfterHeader(now, raHeader));
|
159 | return true;
|
160 | }
|
161 | return false;
|
162 | };
|
163 |
|
164 | BaseTransport.prototype._send = function (sentryRequest, originalPayload) {
|
165 | return tslib_1.__awaiter(this, void 0, void 0, function () {
|
166 | var _this = this;
|
167 | return tslib_1.__generator(this, function (_a) {
|
168 | if (!this.module) {
|
169 | throw new utils_1.SentryError('No module available');
|
170 | }
|
171 | if (originalPayload && this._isRateLimited(sentryRequest.type)) {
|
172 | return [2 , Promise.reject({
|
173 | payload: originalPayload,
|
174 | type: sentryRequest.type,
|
175 | reason: "Transport for " + sentryRequest.type + " requests locked till " + this._disabledUntil(sentryRequest.type) + " due to too many requests.",
|
176 | status: 429,
|
177 | })];
|
178 | }
|
179 | if (!this._buffer.isReady()) {
|
180 | return [2 , Promise.reject(new utils_1.SentryError('Not adding Promise due to buffer limit reached.'))];
|
181 | }
|
182 | return [2 , this._buffer.add(function () {
|
183 | return new Promise(function (resolve, reject) {
|
184 | if (!_this.module) {
|
185 | throw new utils_1.SentryError('No module available');
|
186 | }
|
187 | var options = _this._getRequestOptions(_this.urlParser(sentryRequest.url));
|
188 | var req = _this.module.request(options, function (res) {
|
189 | var statusCode = res.statusCode || 500;
|
190 | var status = types_1.Status.fromHttpCode(statusCode);
|
191 | res.setEncoding('utf8');
|
192 | |
193 |
|
194 |
|
195 |
|
196 | var retryAfterHeader = res.headers ? res.headers['retry-after'] : '';
|
197 | retryAfterHeader = (Array.isArray(retryAfterHeader) ? retryAfterHeader[0] : retryAfterHeader);
|
198 | var rlHeader = res.headers ? res.headers['x-sentry-rate-limits'] : '';
|
199 | rlHeader = (Array.isArray(rlHeader) ? rlHeader[0] : rlHeader);
|
200 | var headers = {
|
201 | 'x-sentry-rate-limits': rlHeader,
|
202 | 'retry-after': retryAfterHeader,
|
203 | };
|
204 | var limited = _this._handleRateLimit(headers);
|
205 | if (limited)
|
206 | utils_1.logger.warn("Too many " + sentryRequest.type + " requests, backing off until: " + _this._disabledUntil(sentryRequest.type));
|
207 | if (status === types_1.Status.Success) {
|
208 | resolve({ status: status });
|
209 | }
|
210 | else {
|
211 | var rejectionMessage = "HTTP Error (" + statusCode + ")";
|
212 | if (res.headers && res.headers['x-sentry-error']) {
|
213 | rejectionMessage += ": " + res.headers['x-sentry-error'];
|
214 | }
|
215 | reject(new utils_1.SentryError(rejectionMessage));
|
216 | }
|
217 |
|
218 | res.on('data', function () {
|
219 |
|
220 | });
|
221 | res.on('end', function () {
|
222 |
|
223 | });
|
224 | });
|
225 | req.on('error', reject);
|
226 | req.end(sentryRequest.body);
|
227 | });
|
228 | })];
|
229 | });
|
230 | });
|
231 | };
|
232 | return BaseTransport;
|
233 | }());
|
234 | exports.BaseTransport = BaseTransport;
|
235 |
|
\ | No newline at end of file |