@microsoft/1ds-post-js
Version:
Microsoft Application Insights JavaScript SDK - 1ds-post-channel-js
793 lines • 73.3 kB
JavaScript
/*
* 1DS JS SDK POST plugin, 4.3.9
* Copyright (c) Microsoft and contributors. All rights reserved.
* (Microsoft Internal Only)
*/
var _a;
/**
* HttpManager.ts
* @author Abhilash Panwar (abpanwar); Hector Hernandez (hectorh); Nev Wylie (newylie)
* @copyright Microsoft 2018-2020
*/
import dynamicProto from "@microsoft/dynamicproto-js";
import { FullVersionString, SenderPostManager, _getAllResponseHeaders, _throwInternal, _warnToConsole, arrForEach, dateNow, doPerf, dumpObj, extend, getCommonSchemaMetaData, getNavigator, getResponseText, getTime, hasOwnProperty, isBeaconsSupported, isFeatureEnabled, isFetchSupported, isNullOrUndefined, isReactNative, isUndefined, isValueAssigned, objForEachKey, objKeys, onConfigChange, optimizeObject, prependTransports, strUndefined } from "@microsoft/1ds-core-js";
import { arrAppend, getInst, isFunction } from "@nevware21/ts-utils";
import { ClockSkewManager } from "./ClockSkewManager";
import { EventBatch } from "./EventBatch";
import { DEFAULT_CACHE_CONTROL, DEFAULT_CONTENT_TYPE, STR_API_KEY, STR_AUTH_XTOKEN, STR_CACHE_CONTROL, STR_CLIENT_ID, STR_CLIENT_VERSION, STR_CONTENT_TYPE_HEADER, STR_DROPPED, STR_EMPTY, STR_KILL_DURATION_HEADER, STR_KILL_TOKENS_HEADER, STR_MSA_DEVICE_TICKET, STR_MSFPC, STR_NO_RESPONSE_BODY, STR_OTHER, STR_REQUEUE, STR_RESPONSE_FAIL, STR_SENDING, STR_TIME_DELTA_HEADER, STR_TIME_DELTA_TO_APPLY, STR_UPLOAD_TIME } from "./InternalConstants";
import { KillSwitch } from "./KillSwitch";
import { retryPolicyGetMillisToBackoffForRetry, retryPolicyShouldRetryForStatus } from "./RetryPolicy";
import { Serializer } from "./Serializer";
import { createTimeoutWrapper } from "./TimeoutOverrideWrapper";
import { _DYN_ADD_NO_RESPONSE, _DYN_ALLOW_REQUEST_SENDIN0, _DYN_ALWAYS_USE_XHR_OVERR7, _DYN_AVOID_OPTIONS, _DYN_BATCHES, _DYN_CAN_SEND_REQUEST, _DYN_CLEAR_TIMEOUT_OVERRI3, _DYN_CONCAT, _DYN_COUNT, _DYN_CREATE_ONE_DSPAYLOAD, _DYN_CREATE_PAYLOAD, _DYN_DISABLE_EVENT_TIMING5, _DYN_DISABLE_FETCH_KEEP_A6, _DYN_DISABLE_XHR_SYNC, _DYN_ENABLE_COMPOUND_KEY, _DYN_EVENTS, _DYN_FETCH_CREDENTIALS, _DYN_GET_CLOCK_SKEW_HEADE2, _DYN_GET_OFFLINE_REQUEST_9, _DYN_GET_WPARAM, _DYN_HDRS, _DYN_HEADERS, _DYN_INITIALIZE, _DYN_IS_BEACON, _DYN_IS_TEARDOWN, _DYN_I_KEY, _DYN_LENGTH, _DYN_OVERRIDE_ENDPOINT_UR4, _DYN_PAYLOAD_BLOB, _DYN_PAYLOAD_PREPROCESSOR, _DYN_PUSH, _DYN_SEND_QUEUED_REQUESTS, _DYN_SEND_SYNCHRONOUS_BAT10, _DYN_SEND_TYPE, _DYN_SERIALIZE_OFFLINE_EV8, _DYN_SET_CLOCK_SKEW, _DYN_SET_KILL_SWITCH_TENA11, _DYN_SET_TIMEOUT_OVERRIDE, _DYN_SET_UNLOADING, _DYN_SHOULD_ADD_CLOCK_SKE1, _DYN_SPLIT, _DYN_TIMINGS, _DYN_TO_LOWER_CASE, _DYN_USE_HDRS, _DYN_USE_SEND_BEACON, _DYN__BACK_OFF_TRANSMISSI12, _DYN__SEND_REASON, _DYN__THE_PAYLOAD, _DYN__TRANSPORT } from "./__DynamicConstants";
var strSendAttempt = "sendAttempt";
var _noResponseQs = "&" + STR_NO_RESPONSE_BODY + "=true";
var UrlQueryString = "?cors=true&" + STR_CONTENT_TYPE_HEADER[_DYN_TO_LOWER_CASE /* @min:%2etoLowerCase */]() + "=" + DEFAULT_CONTENT_TYPE;
/**
* Identifies the default notification reason to the action names
*/
var _eventActionMap = (_a = {},
_a[1 /* EventBatchNotificationReason.Paused */] = STR_REQUEUE,
_a[100 /* EventBatchNotificationReason.RequeueEvents */] = STR_REQUEUE,
_a[200 /* EventBatchNotificationReason.Complete */] = "sent",
_a[8004 /* EventBatchNotificationReason.KillSwitch */] = STR_DROPPED,
_a[8003 /* EventBatchNotificationReason.SizeLimitExceeded */] = STR_DROPPED,
_a);
var _collectorQsHeaders = {};
var _collectorHeaderToQs = {};
function _addCollectorHeaderQsMapping(qsName, headerName, allowQs) {
_collectorQsHeaders[qsName] = headerName;
if (allowQs !== false) {
_collectorHeaderToQs[headerName] = qsName;
}
}
_addCollectorHeaderQsMapping(STR_MSA_DEVICE_TICKET, STR_MSA_DEVICE_TICKET, false);
_addCollectorHeaderQsMapping(STR_CLIENT_VERSION, STR_CLIENT_VERSION);
_addCollectorHeaderQsMapping(STR_CLIENT_ID, "Client-Id");
_addCollectorHeaderQsMapping(STR_API_KEY, STR_API_KEY);
_addCollectorHeaderQsMapping(STR_TIME_DELTA_TO_APPLY, STR_TIME_DELTA_TO_APPLY);
_addCollectorHeaderQsMapping(STR_UPLOAD_TIME, STR_UPLOAD_TIME);
_addCollectorHeaderQsMapping(STR_AUTH_XTOKEN, STR_AUTH_XTOKEN);
function _hasHeader(headers, header) {
var hasHeader = false;
if (headers && header) {
var keys = objKeys(headers);
if (keys && keys[_DYN_LENGTH /* @min:%2elength */] > 0) {
var lowerHeader = header[_DYN_TO_LOWER_CASE /* @min:%2etoLowerCase */]();
for (var lp = 0; lp < keys[_DYN_LENGTH /* @min:%2elength */]; lp++) {
var value = keys[lp];
if (value && hasOwnProperty(header, value) &&
value[_DYN_TO_LOWER_CASE /* @min:%2etoLowerCase */]() === lowerHeader) {
hasHeader = true;
break;
}
}
}
}
return hasHeader;
}
function _addRequestDetails(details, name, value, useHeaders) {
if (name && value && value[_DYN_LENGTH /* @min:%2elength */] > 0) {
if (useHeaders && _collectorQsHeaders[name]) {
details[_DYN_HDRS /* @min:%2ehdrs */][_collectorQsHeaders[name]] = value;
details[_DYN_USE_HDRS /* @min:%2euseHdrs */] = true;
}
else {
details.url += "&" + name + "=" + value;
}
}
}
function _addQueryStringParameter(qsParams, name, value) {
for (var i = 0; i < qsParams[_DYN_LENGTH /* @min:%2elength */]; i++) {
if (qsParams[i].name === name) {
qsParams[i].value = value;
return;
}
}
qsParams[_DYN_PUSH /* @min:%2epush */]({ name: name, value: value });
}
function _removeQueryStringParameter(qsParams, name) {
for (var i = 0; i < qsParams[_DYN_LENGTH /* @min:%2elength */]; i++) {
if (qsParams[i].name === name) {
qsParams.splice(i, 1);
return;
}
}
}
/**
* Class managing the sending of requests.
*/
var HttpManager = /** @class */ (function () {
/**
* @constructor
* @param requestQueue - The queue that contains the requests to be sent.
*/
function HttpManager(maxEventsPerBatch, maxConnections, maxRequestRetriesBeforeBackoff, actions) {
// ------------------------------------------------------------------------------------------------------------------------
// Only set "Default" values in the _initDefaults() method, unless value are not "reset" during unloading
// ------------------------------------------------------------------------------------------------------------------------
var _urlString;
var _killSwitch;
var _paused;
var _clockSkewManager;
var _useBeacons = false;
var _outstandingRequests; // Holds the number of outstanding async requests that have not returned a response yet
var _postManager;
var _logger;
var _sendInterfaces;
var _core;
var _customHttpInterface;
var _queryStringParameters;
var _headers;
var _batchQueue;
var _serializer;
var _enableEventTimings;
var _cookieMgr;
var _isUnloading;
var _useHeaders;
var _xhrTimeout;
var _zipPayload;
var _disableXhrSync;
var _disableFetchKeepAlive;
var _canHaveReducedPayload;
var _addNoResponse;
var _unloadHooks;
var _sendHook;
var _sendListener;
var _responseHandlers;
var _isInitialized;
var _timeoutWrapper;
var _excludeCsMetaData;
var _sendPostMgr;
var _fetchCredentials;
var _maxEvtPerBatch = maxEventsPerBatch; // Sets default value in case the value is null
dynamicProto(HttpManager, this, function (_self) {
_initDefaults();
var _sendCredentials = true;
_self[_DYN_INITIALIZE /* @min:%2einitialize */] = function (theConfig, core, postChannel) {
if (!_isInitialized) {
_core = core;
_cookieMgr = core.getCookieMgr();
_postManager = postChannel;
_logger = _postManager.diagLog();
arrAppend(_unloadHooks, onConfigChange(theConfig, function (details) {
var _a;
var coreConfig = details.cfg;
var channelConfig = details.cfg.extensionConfig[postChannel.identifier];
_timeoutWrapper = createTimeoutWrapper(channelConfig[_DYN_SET_TIMEOUT_OVERRIDE /* @min:%2esetTimeoutOverride */], channelConfig[_DYN_CLEAR_TIMEOUT_OVERRI3 /* @min:%2eclearTimeoutOverride */]);
if (isValueAssigned(coreConfig.anonCookieName)) {
_addQueryStringParameter(_queryStringParameters, "anoncknm", coreConfig.anonCookieName);
}
else {
_removeQueryStringParameter(_queryStringParameters, "anoncknm");
}
_sendHook = channelConfig[_DYN_PAYLOAD_PREPROCESSOR /* @min:%2epayloadPreprocessor */];
_sendListener = channelConfig.payloadListener;
var httpInterface = channelConfig.httpXHROverride;
// Override endpointUrl if provided in Post config
var endpointUrl = channelConfig[_DYN_OVERRIDE_ENDPOINT_UR4 /* @min:%2eoverrideEndpointUrl */] ? channelConfig[_DYN_OVERRIDE_ENDPOINT_UR4 /* @min:%2eoverrideEndpointUrl */] : coreConfig.endpointUrl;
_urlString = endpointUrl + UrlQueryString;
_useHeaders = !isUndefined(channelConfig[_DYN_AVOID_OPTIONS /* @min:%2eavoidOptions */]) ? !channelConfig[_DYN_AVOID_OPTIONS /* @min:%2eavoidOptions */] : true;
_enableEventTimings = !channelConfig[_DYN_DISABLE_EVENT_TIMING5 /* @min:%2edisableEventTimings */];
var maxEvtCfg = channelConfig.maxEvtPerBatch;
_maxEvtPerBatch = maxEvtCfg && maxEvtCfg <= maxEventsPerBatch ? maxEvtCfg : maxEventsPerBatch;
var valueSanitizer = channelConfig.valueSanitizer;
var stringifyObjects = channelConfig.stringifyObjects;
var enableCompoundKey = !!coreConfig[_DYN_ENABLE_COMPOUND_KEY /* @min:%2eenableCompoundKey */];
if (!isUndefined(channelConfig[_DYN_ENABLE_COMPOUND_KEY /* @min:%2eenableCompoundKey */])) {
enableCompoundKey = !!channelConfig[_DYN_ENABLE_COMPOUND_KEY /* @min:%2eenableCompoundKey */];
}
_xhrTimeout = channelConfig.xhrTimeout;
var csStream = getInst("CompressionStream");
// Controls whether payload compression (gzip) is enabled.
_zipPayload = isFeatureEnabled("zipPayload", coreConfig, false);
// if user has payload processor (_sendHook), they may compress the payload themselves
// to avoid double compression, we should disable the zipPayload
if (!isFunction(csStream) || _sendHook) {
_zipPayload = false;
}
_disableXhrSync = !!channelConfig[_DYN_DISABLE_XHR_SYNC /* @min:%2edisableXhrSync */];
_disableFetchKeepAlive = !!channelConfig[_DYN_DISABLE_FETCH_KEEP_A6 /* @min:%2edisableFetchKeepAlive */];
_addNoResponse = channelConfig[_DYN_ADD_NO_RESPONSE /* @min:%2eaddNoResponse */] !== false;
_excludeCsMetaData = !!channelConfig.excludeCsMetaData;
if (!!core.getPlugin("LocalStorage")) {
// Always disable fetch keep alive when persisten storage is available
_disableFetchKeepAlive = true;
}
_useBeacons = !isReactNative(); // Only use beacons if not running in React Native
_serializer = new Serializer(_core, valueSanitizer, stringifyObjects, enableCompoundKey, getCommonSchemaMetaData, _excludeCsMetaData, channelConfig);
if (!isNullOrUndefined(channelConfig[_DYN_USE_SEND_BEACON /* @min:%2euseSendBeacon */])) {
_useBeacons = !!channelConfig[_DYN_USE_SEND_BEACON /* @min:%2euseSendBeacon */];
}
if (channelConfig[_DYN_FETCH_CREDENTIALS /* @min:%2efetchCredentials */]) {
_fetchCredentials = channelConfig[_DYN_FETCH_CREDENTIALS /* @min:%2efetchCredentials */];
}
var sendPostConfig = _getSendPostMgrConfig();
// only init it once
if (!_sendPostMgr) {
_sendPostMgr = new SenderPostManager();
_sendPostMgr[_DYN_INITIALIZE /* @min:%2einitialize */](sendPostConfig, _logger);
}
else {
_sendPostMgr.SetConfig(sendPostConfig);
}
var syncHttpInterface = httpInterface;
var beaconHttpInterface = channelConfig[_DYN_ALWAYS_USE_XHR_OVERR7 /* @min:%2ealwaysUseXhrOverride */] ? httpInterface : null;
var fetchSyncHttpInterface = channelConfig[_DYN_ALWAYS_USE_XHR_OVERR7 /* @min:%2ealwaysUseXhrOverride */] ? httpInterface : null;
var beaconUnloadTransports = [3 /* TransportType.Beacon */, 2 /* TransportType.Fetch */];
if (!httpInterface) {
_customHttpInterface = false;
// this is handled in SendPostManager now
// let location = getLocation();
// if (location && location.protocol && location.protocol.toLowerCase() === "file:") {
// // Special case where a local html file fails with a CORS error on Chromium browsers
// _sendCredentials = false;
// }
var theTransports = [];
if (isReactNative()) {
// Use Fetch or XDR/XHR
theTransports = [2 /* TransportType.Fetch */, 1 /* TransportType.Xhr */];
beaconUnloadTransports = [2 /* TransportType.Fetch */, 1 /* TransportType.Xhr */, 3 /* TransportType.Beacon */];
}
else {
// Use XDR/XHR, Fetch or beacons
theTransports = [1 /* TransportType.Xhr */, 2 /* TransportType.Fetch */, 3 /* TransportType.Beacon */];
}
// Prefix any user requested transport(s) values
theTransports = prependTransports(theTransports, channelConfig.transports);
httpInterface = _getSenderInterface(theTransports, false);
if (!httpInterface) {
_warnToConsole(_logger, "No available transport to send events");
}
syncHttpInterface = _getSenderInterface(theTransports, true);
}
if (!beaconHttpInterface) {
// Allow overriding the usage of sendBeacon
beaconUnloadTransports = prependTransports(beaconUnloadTransports, channelConfig.unloadTransports);
beaconHttpInterface = _getSenderInterface(beaconUnloadTransports, true);
}
_canHaveReducedPayload = !_customHttpInterface && ((_useBeacons && isBeaconsSupported()) || (!_disableFetchKeepAlive && isFetchSupported(true)));
_sendInterfaces = (_a = {},
_a[0 /* EventSendType.Batched */] = httpInterface,
_a[1 /* EventSendType.Synchronous */] = syncHttpInterface || _getSenderInterface([1 /* TransportType.Xhr */, 2 /* TransportType.Fetch */, 3 /* TransportType.Beacon */], true),
_a[2 /* EventSendType.SendBeacon */] = beaconHttpInterface || syncHttpInterface || _getSenderInterface([1 /* TransportType.Xhr */], true),
_a[3 /* EventSendType.SyncFetch */] = fetchSyncHttpInterface || _getSenderInterface([2 /* TransportType.Fetch */, 3 /* TransportType.Beacon */], true) || syncHttpInterface || _getSenderInterface([1 /* TransportType.Xhr */], true),
_a);
}));
_isInitialized = true;
}
};
_self.addResponseHandler = function (responseHandler) {
_responseHandlers[_DYN_PUSH /* @min:%2epush */](responseHandler);
return {
rm: function () {
var index = _responseHandlers.indexOf(responseHandler);
if (index >= 0) {
_responseHandlers.splice(index, 1);
}
}
};
};
_self[_DYN_SERIALIZE_OFFLINE_EV8 /* @min:%2eserializeOfflineEvt */] = function (evt) {
try {
if (_serializer) {
return _serializer.getEventBlob(evt);
}
}
catch (e) {
// eslint-disable-next-line no-empty
}
return STR_EMPTY;
};
_self[_DYN_GET_OFFLINE_REQUEST_9 /* @min:%2egetOfflineRequestDetails */] = function () {
try {
// get current url without paramter
var payload = _serializer && _serializer[_DYN_CREATE_PAYLOAD /* @min:%2ecreatePayload */](0, false, false, false, 1 /* SendRequestReason.NormalSchedule */, 0 /* EventSendType.Batched */);
return _buildRequestDetails(payload, _useHeaders);
}
catch (e) {
// eslint-disable-next-line no-empty
}
return null;
};
_self[_DYN_CREATE_ONE_DSPAYLOAD /* @min:%2ecreateOneDSPayload */] = function (evts, optimize) {
try {
// TODO: optimize
var theBatches_1 = [];
// create a eventBatch for each event
arrForEach(evts, function (evt) {
if (optimize) {
evt = optimizeObject(evt);
}
var batch = EventBatch.create(evt[_DYN_I_KEY /* @min:%2eiKey */], [evt]);
theBatches_1[_DYN_PUSH /* @min:%2epush */](batch);
});
var thePayload = null;
while (theBatches_1[_DYN_LENGTH /* @min:%2elength */] > 0 && _serializer) {
var theBatch = theBatches_1.shift();
if (theBatch && theBatch[_DYN_COUNT /* @min:%2ecount */]() > 0) {
thePayload = thePayload || _serializer[_DYN_CREATE_PAYLOAD /* @min:%2ecreatePayload */](0, false, false, false, 1 /* SendRequestReason.NormalSchedule */, 0 /* EventSendType.Batched */);
_serializer.appendPayload(thePayload, theBatch, _maxEvtPerBatch);
}
}
var requestDetails = _buildRequestDetails(thePayload, _useHeaders);
var payloadData = {
data: thePayload[_DYN_PAYLOAD_BLOB /* @min:%2epayloadBlob */],
urlString: requestDetails.url,
headers: requestDetails[_DYN_HDRS /* @min:%2ehdrs */],
timeout: _xhrTimeout,
disableXhrSync: _disableXhrSync,
disableFetchKeepAlive: _disableFetchKeepAlive
};
// Only automatically add the following headers if already sending headers and we are not attempting to avoid an options call
if (_useHeaders) {
if (!_hasHeader(payloadData[_DYN_HEADERS /* @min:%2eheaders */], STR_CACHE_CONTROL)) {
payloadData[_DYN_HEADERS /* @min:%2eheaders */][STR_CACHE_CONTROL] = DEFAULT_CACHE_CONTROL;
}
if (!_hasHeader(payloadData[_DYN_HEADERS /* @min:%2eheaders */], STR_CONTENT_TYPE_HEADER)) {
payloadData[_DYN_HEADERS /* @min:%2eheaders */][STR_CONTENT_TYPE_HEADER] = DEFAULT_CONTENT_TYPE;
}
}
return payloadData;
}
catch (e) {
// eslint-disable-next-line no-empty
}
return null;
};
// Special internal method to allow the DebugPlugin to hook embedded objects
function _getSenderInterface(transports, syncSupport) {
try {
return _sendPostMgr && _sendPostMgr.getSenderInst(transports, syncSupport);
}
catch (e) {
// eslint-disable-next-line no-empty
}
return null;
}
_self["_getDbgPlgTargets"] = function () {
return [_sendInterfaces[0 /* EventSendType.Batched */], _killSwitch, _serializer, _sendInterfaces, _getSendPostMgrConfig(), _urlString, _maxEvtPerBatch];
};
function _getSendPostMgrConfig() {
try {
var onCompleteFuncs = {
xdrOnComplete: _xdrOncomplete,
fetchOnComplete: _fetchOnComplete,
xhrOnComplete: _xhrOnComplete,
beaconOnRetry: _onBeaconRetry
};
var config = {
enableSendPromise: false,
isOneDs: true,
disableCredentials: !_sendCredentials,
fetchCredentials: _fetchCredentials,
disableXhr: false,
disableBeacon: !_useBeacons,
disableBeaconSync: !_useBeacons,
disableFetchKeepAlive: _disableFetchKeepAlive,
timeWrapper: _timeoutWrapper,
addNoResponse: _addNoResponse,
senderOnCompleteCallBack: onCompleteFuncs
};
return config;
}
catch (e) {
// eslint-disable-next-line no-empty
}
return null;
}
function _xdrOncomplete(xdr, oncomplete, payload) {
var response = getResponseText(xdr);
_doOnComplete(oncomplete, 200, {}, response);
_handleCollectorResponse(response);
}
function _initDefaults() {
var undefValue;
_urlString = null;
_killSwitch = new KillSwitch();
_paused = false;
_clockSkewManager = new ClockSkewManager();
_useBeacons = false;
_outstandingRequests = 0; // Holds the number of outstanding async requests that have not returned a response yet
_postManager = null;
_logger = null;
_sendInterfaces = null;
_core = null;
_customHttpInterface = true;
_queryStringParameters = [];
_headers = {};
_batchQueue = [];
_serializer = null;
_enableEventTimings = false;
_cookieMgr = null;
_isUnloading = false;
_useHeaders = false;
_xhrTimeout = undefValue;
_disableXhrSync = undefValue;
_disableFetchKeepAlive = undefValue;
_canHaveReducedPayload = undefValue;
_addNoResponse = undefValue;
_unloadHooks = [];
_sendHook = undefValue;
_sendListener = undefValue;
_responseHandlers = [];
_isInitialized = false;
_timeoutWrapper = createTimeoutWrapper();
_excludeCsMetaData = false;
_sendPostMgr = null;
_maxEvtPerBatch = null;
}
function _fetchOnComplete(response, onComplete, resValue, payload) {
var handleResponse = function (status, headerMap, responseText) {
_doOnComplete(onComplete, status, headerMap, responseText);
_handleCollectorResponse(responseText);
};
var headerMap = {};
var headers = response[_DYN_HEADERS /* @min:%2eheaders */];
if (headers) {
headers["forEach"](function (value, name) {
headerMap[name] = value;
});
}
handleResponse(response.status, headerMap, resValue || STR_EMPTY);
}
function _xhrOnComplete(request, oncomplete, payload) {
var response = getResponseText(request);
_doOnComplete(oncomplete, request.status, _getAllResponseHeaders(request, true), response);
_handleCollectorResponse(response);
}
function _doOnComplete(oncomplete, status, headers, response) {
try {
oncomplete(status, headers, response);
}
catch (e) {
_throwInternal(_logger, 2 /* eLoggingSeverity.WARNING */, 518 /* _eExtendedInternalMessageId.SendPostOnCompleteFailure */, dumpObj(e));
}
}
function _onBeaconRetry(payload, onComplete, canSend) {
// Custom headers not supported in sendBeacon payload.headers would be ignored
var internalPayloadData = payload;
var status = 200;
var thePayload = internalPayloadData[_DYN__THE_PAYLOAD /* @min:%2e_thePayload */];
var theUrl = payload.urlString + (_addNoResponse ? _noResponseQs : STR_EMPTY);
try {
var nav_1 = getNavigator();
if (thePayload) {
var persistStorage = !!_core.getPlugin("LocalStorage");
// Failed to send entire payload so try and split data and try to send as much events as possible
var droppedBatches_1 = [];
var sentBatches_1 = [];
arrForEach(thePayload[_DYN_BATCHES /* @min:%2ebatches */], function (theBatch) {
if (droppedBatches_1 && theBatch && theBatch[_DYN_COUNT /* @min:%2ecount */]() > 0) {
var theEvents = theBatch[_DYN_EVENTS /* @min:%2eevents */]();
for (var lp = 0; lp < theEvents[_DYN_LENGTH /* @min:%2elength */]; lp++) {
if (!nav_1.sendBeacon(theUrl, _serializer.getEventBlob(theEvents[lp]))) {
// Can't send anymore, so split the batch and drop the rest
droppedBatches_1[_DYN_PUSH /* @min:%2epush */](theBatch[_DYN_SPLIT /* @min:%2esplit */](lp));
break;
}
else {
sentBatches_1[_DYN_PUSH /* @min:%2epush */](theBatch[lp]);
}
}
}
else {
// Remove all of the events from the existing batch in the payload as the copy includes the original
droppedBatches_1[_DYN_PUSH /* @min:%2epush */](theBatch[_DYN_SPLIT /* @min:%2esplit */](0));
}
});
if (sentBatches_1[_DYN_LENGTH /* @min:%2elength */] > 0) {
// Update the payload with the sent batches
thePayload.sentEvts = sentBatches_1;
}
if (!persistStorage) {
_sendBatchesNotification(droppedBatches_1, 8003 /* EventBatchNotificationReason.SizeLimitExceeded */, thePayload[_DYN_SEND_TYPE /* @min:%2esendType */], true);
}
}
else {
status = 0;
}
}
catch (ex) {
_warnToConsole(_logger, "Failed to send telemetry using sendBeacon API. Ex:" + dumpObj(ex));
status = 0;
}
finally {
_doOnComplete(onComplete, status, {}, STR_EMPTY);
}
}
function _isBeaconPayload(sendType) {
// Sync Fetch has the same payload limitation as sendBeacon -- 64kb limit, so treat both as a beacon send
return sendType === 2 /* EventSendType.SendBeacon */ || sendType === 3 /* EventSendType.SyncFetch */;
}
function _adjustSendType(sendType) {
if (_isUnloading && _isBeaconPayload(sendType)) {
sendType = 2 /* EventSendType.SendBeacon */;
}
return sendType;
}
_self.addHeader = function (name, value) {
_headers[name] = value;
};
_self.removeHeader = function (name) {
delete _headers[name];
};
_self[_DYN_CAN_SEND_REQUEST /* @min:%2ecanSendRequest */] = function () {
return _hasIdleConnection() && _clockSkewManager[_DYN_ALLOW_REQUEST_SENDIN0 /* @min:%2eallowRequestSending */]();
};
_self[_DYN_SEND_QUEUED_REQUESTS /* @min:%2esendQueuedRequests */] = function (sendType, sendReason) {
if (isUndefined(sendType)) {
sendType = 0 /* EventSendType.Batched */;
}
if (_isUnloading) {
sendType = _adjustSendType(sendType);
sendReason = 2 /* SendRequestReason.Unload */;
}
if (_canSendPayload(_batchQueue, sendType, 0)) {
_sendBatches(_clearQueue(), 0, false, sendType, sendReason || 0 /* SendRequestReason.Undefined */);
}
};
_self.isCompletelyIdle = function () {
return !_paused && _outstandingRequests === 0 && _batchQueue[_DYN_LENGTH /* @min:%2elength */] === 0;
};
_self[_DYN_SET_UNLOADING /* @min:%2esetUnloading */] = function (value) {
_isUnloading = value;
};
_self.addBatch = function (theBatch) {
if (theBatch && theBatch[_DYN_COUNT /* @min:%2ecount */]() > 0) {
// Try and kill the event faster
if (_killSwitch.isTenantKilled(theBatch[_DYN_I_KEY /* @min:%2eiKey */]())) {
return false;
}
_batchQueue[_DYN_PUSH /* @min:%2epush */](theBatch);
}
return true;
};
/**
* Queue all the remaining requests to be sent. The requests will be
* sent using HTML5 Beacons if they are available.
*/
_self.teardown = function () {
if (_batchQueue[_DYN_LENGTH /* @min:%2elength */] > 0) {
_sendBatches(_clearQueue(), 0, true, 2 /* EventSendType.SendBeacon */, 2 /* SendRequestReason.Unload */);
}
arrForEach(_unloadHooks, function (hook) {
hook && hook.rm && hook.rm();
});
_unloadHooks = [];
};
/**
* Pause the sending of requests. No new requests will be sent.
*/
_self.pause = function () {
_paused = true;
};
/**
* Resume the sending of requests.
*/
_self.resume = function () {
_paused = false;
_self[_DYN_SEND_QUEUED_REQUESTS /* @min:%2esendQueuedRequests */](0 /* EventSendType.Batched */, 4 /* SendRequestReason.Resumed */);
};
/**
* Sends a request synchronously to the Aria collector. This api is used to send
* a request containing a single immediate event.
*
* @param batch - The request to be sent.
* @param sendReason - The token used to send the request.
*/
_self[_DYN_SEND_SYNCHRONOUS_BAT10 /* @min:%2esendSynchronousBatch */] = function (batch, sendType, sendReason) {
// This will not take into account the max connections restriction. Since this is sync, we can
// only send one of this request at a time and thus should not worry about multiple connections
// being used to send synchronous events.
// Increment active connection since we are still going to use a connection to send the request.
if (batch && batch[_DYN_COUNT /* @min:%2ecount */]() > 0) {
if (isNullOrUndefined(sendType)) {
sendType = 1 /* EventSendType.Synchronous */;
}
if (_isUnloading) {
sendType = _adjustSendType(sendType);
sendReason = 2 /* SendRequestReason.Unload */;
}
// For sync requests we will not wait for the clock skew.
_sendBatches([batch], 0, false, sendType, sendReason || 0 /* SendRequestReason.Undefined */);
}
};
function _hasIdleConnection() {
return !_paused && _outstandingRequests < maxConnections;
}
function _clearQueue() {
var theQueue = _batchQueue;
_batchQueue = [];
return theQueue;
}
function _canSendPayload(theBatches, sendType, retryCnt) {
var result = false;
if (theBatches && theBatches[_DYN_LENGTH /* @min:%2elength */] > 0 && !_paused && _sendInterfaces[sendType] && _serializer) {
// Always attempt to send synchronous events don't wait for idle or clockSkew
// and don't block retry requests if clockSkew is not yet set
result = (sendType !== 0 /* EventSendType.Batched */) || (_hasIdleConnection() && (retryCnt > 0 || _clockSkewManager[_DYN_ALLOW_REQUEST_SENDIN0 /* @min:%2eallowRequestSending */]()));
}
return result;
}
function _createDebugBatches(theBatches) {
var values = {};
if (theBatches) {
arrForEach(theBatches, function (theBatch, idx) {
values[idx] = {
iKey: theBatch[_DYN_I_KEY /* @min:%2eiKey */](),
evts: theBatch[_DYN_EVENTS /* @min:%2eevents */]()
};
});
}
return values;
}
function _sendBatches(theBatches, retryCount, isTeardown, sendType, sendReason) {
if (!theBatches || theBatches[_DYN_LENGTH /* @min:%2elength */] === 0) {
// Nothing to do
return;
}
if (_paused) {
_sendBatchesNotification(theBatches, 1 /* EventBatchNotificationReason.Paused */, sendType);
return;
}
// Make sure that if we are unloading the sendType is a supported version
sendType = _adjustSendType(sendType);
try {
var orgBatches_1 = theBatches;
var isSynchronous_1 = sendType !== 0 /* EventSendType.Batched */;
doPerf(_core, function () { return "HttpManager:_sendBatches"; }, function (perfEvt) {
if (perfEvt) {
// Perf Monitoring is enabled, so create a "Quick" copy of the original batches so we still report
// the original values as part of the perfEvent. This is because theBatches uses .shift() to remove each
// batch as they are processed - removing from the original array, so by the time the _createDebugBatches()
// function is called the passed in value has changed and therefore the reported value for the perfEvent is incorrect
theBatches = theBatches.slice(0);
}
var droppedBatches = [];
var thePayload = null;
var serializationStart = getTime();
var sendInterface = _sendInterfaces[sendType] || (isSynchronous_1 ? _sendInterfaces[1 /* EventSendType.Synchronous */] : _sendInterfaces[0 /* EventSendType.Batched */]);
var sendTransport = sendInterface && sendInterface[_DYN__TRANSPORT /* @min:%2e_transport */];
// Sync Fetch has the same payload limitation as sendBeacon -- 64kb limit
var isReducedPayload = _canHaveReducedPayload && (_isUnloading || _isBeaconPayload(sendType) || (sendTransport === 3 /* TransportType.Beacon */ || (sendInterface._isSync && sendTransport === 2 /* TransportType.Fetch */)));
while (_canSendPayload(theBatches, sendType, retryCount)) {
var theBatch = theBatches.shift();
if (theBatch && theBatch[_DYN_COUNT /* @min:%2ecount */]() > 0) {
if (!_killSwitch.isTenantKilled(theBatch[_DYN_I_KEY /* @min:%2eiKey */]())) {
// Make sure we have a payload object
thePayload = thePayload || _serializer[_DYN_CREATE_PAYLOAD /* @min:%2ecreatePayload */](retryCount, isTeardown, isSynchronous_1, isReducedPayload, sendReason, sendType);
// Add the batch to the current payload
if (!_serializer.appendPayload(thePayload, theBatch, _maxEvtPerBatch)) {
// Entire batch was not added so send the payload and retry adding this batch
_doPayloadSend(thePayload, serializationStart, getTime(), sendReason);
serializationStart = getTime();
theBatches = [theBatch][_DYN_CONCAT /* @min:%2econcat */](theBatches);
thePayload = null;
}
else if (thePayload.overflow !== null) {
// Total Payload size was exceeded so send the payload and add the unsent as the next batch to send
theBatches = [thePayload.overflow][_DYN_CONCAT /* @min:%2econcat */](theBatches);
thePayload.overflow = null;
_doPayloadSend(thePayload, serializationStart, getTime(), sendReason);
serializationStart = getTime();
thePayload = null;
}
}
else {
droppedBatches[_DYN_PUSH /* @min:%2epush */](theBatch);
}
}
}
// Make sure to flush any remaining payload
if (thePayload) {
_doPayloadSend(thePayload, serializationStart, getTime(), sendReason);
}
if (theBatches[_DYN_LENGTH /* @min:%2elength */] > 0) {
// Add any unsent batches back to the head of the queue
_batchQueue = theBatches[_DYN_CONCAT /* @min:%2econcat */](_batchQueue);
}
// Now send notification about any dropped events
_sendBatchesNotification(droppedBatches, 8004 /* EventBatchNotificationReason.KillSwitch */, sendType);
}, function () { return ({ batches: _createDebugBatches(orgBatches_1), retryCount: retryCount, isTeardown: isTeardown, isSynchronous: isSynchronous_1, sendReason: sendReason, useSendBeacon: _isBeaconPayload(sendType), sendType: sendType }); }, !isSynchronous_1);
}
catch (ex) {
_throwInternal(_logger, 2 /* eLoggingSeverity.WARNING */, 48 /* _eInternalMessageId.CannotSerializeObject */, "Unexpected Exception sending batch: " + dumpObj(ex));
}
}
function _buildRequestDetails(thePayload, useHeaders) {
var requestDetails = {
url: _urlString,
hdrs: {},
useHdrs: false // Assume no headers
};
if (!useHeaders) {
// Attempt to map headers to a query string if possible
objForEachKey(_headers, function (name, value) {
if (_collectorHeaderToQs[name]) {
_addRequestDetails(requestDetails, _collectorHeaderToQs[name], value, false);
}
else {
// No mapping, so just include in the headers anyway (may not get sent if using sendBeacon())
requestDetails[_DYN_HDRS /* @min:%2ehdrs */][name] = value;
requestDetails[_DYN_USE_HDRS /* @min:%2euseHdrs */] = true;
}
});
}
else {
// Copy the pre-defined headers into the payload headers
requestDetails[_DYN_HDRS /* @min:%2ehdrs */] = extend(requestDetails[_DYN_HDRS /* @min:%2ehdrs */], _headers);
requestDetails.useHdrs = (objKeys(requestDetails.hdrs)[_DYN_LENGTH /* @min:%2elength */] > 0);
}
_addRequestDetails(requestDetails, STR_CLIENT_ID, "NO_AUTH", useHeaders);
_addRequestDetails(requestDetails, STR_CLIENT_VERSION, FullVersionString, useHeaders);
var apiQsKeys = STR_EMPTY;
arrForEach(thePayload.apiKeys, function (apiKey) {
if (apiQsKeys[_DYN_LENGTH /* @min:%2elength */] > 0) {
apiQsKeys += ",";
}
apiQsKeys += apiKey;
});
_addRequestDetails(requestDetails, STR_API_KEY, apiQsKeys, useHeaders);
_addRequestDetails(requestDetails, STR_UPLOAD_TIME, dateNow().toString(), useHeaders);
var msfpc = _getMsfpc(thePayload);
if (isValueAssigned(msfpc)) {
requestDetails.url += "&ext.intweb.msfpc=" + msfpc;
}
if (_clockSkewManager[_DYN_SHOULD_ADD_CLOCK_SKE1 /* @min:%2eshouldAddClockSkewHeaders */]()) {
_addRequestDetails(requestDetails, STR_TIME_DELTA_TO_APPLY, _clockSkewManager[_DYN_GET_CLOCK_SKEW_HEADE2 /* @min:%2egetClockSkewHeaderValue */](), useHeaders);
}
if (_core[_DYN_GET_WPARAM /* @min:%2egetWParam */]) {
var wParam = _core[_DYN_GET_WPARAM /* @min:%2egetWParam */]();
if (wParam >= 0) {
requestDetails.url += "&w=" + wParam;
}
}
for (var i = 0; i < _queryStringParameters[_DYN_LENGTH /* @min:%2elength */]; i++) {
requestDetails.url += "&" + _queryStringParameters[i].name + "=" + _queryStringParameters[i].value;
}
return requestDetails;
}
function _setTimingValue(timings, name, value) {
timings[name] = timings[name] || {};
timings[name][_postManager.identifier] = value;
}
function _doPayloadSend(thePayload, serializationStart, serializationCompleted, sendReason) {
if (thePayload && thePayload.payloadBlob && thePayload.payloadBlob[_DYN_LENGTH /* @min:%2elength */] > 0) {
var useSendHook_1 = !!_sendHook;
var sendInterface_1 = _sendInterfaces[thePayload.sendType];
// Send all data using a beacon style transport if closing mode is on or channel was teared down
if (!_isBeaconPayload(thePayload[_DYN_SEND_TYPE /* @min:%2esendType */]) && thePayload[_DYN_IS_BEACON /* @min:%2eisBeacon */] && thePayload.sendReason === 2 /* SendRequestReason.Unload */) {
sendInterface_1 = _sendInterfaces[2 /* EventSendType.SendBeacon */] || _sendInterfaces[3 /* EventSendType.SyncFetch */] || sendInterface_1;
}
var useHeaders_1 = _useHeaders;
// Disable header usage if we know we are using sendBeacon as additional headers are not supported
if (thePayload.isBeacon || sendInterface_1[_DYN__TRANSPORT /* @min:%2e_transport */] === 3 /* TransportType.Beacon */) {
useHeaders_1 = false;
}
var requestDetails_1 = _buildRequestDetails(thePayload, useHeaders_1);
useHeaders_1 = useHeaders_1 || requestDetails_1[_DYN_USE_HDRS /* @min:%2euseHdrs */];
var sendEventStart_1 = getTime();
doPerf(_core, function () { return "HttpManager:_doPayloadSend"; }, function () {
// Increment the send attempt count and add timings after packaging (So it's not serialized in the 1st attempt)
for (var batchLp = 0; batchLp < thePayload.batches[_DYN_LENGTH /* @min:%2elength */]; batchLp++) {
var theBatch = thePayload[_DYN_BATCHES /* @min:%2ebatches */][batchLp];
var theEvents = theBatch[_DYN_EVENTS /* @min:%2eevents */]();
for (var evtLp = 0; evtLp < theEvents[_DYN_LENGTH /* @min:%2elength */]; evtLp++) {
var telemetryItem = theEvents[evtLp];
if (_enableEventTimings) {
var timings = telemetryItem[_DYN_TIMINGS /* @min:%2etimings */] = telemetryItem[_DYN_TIMINGS /* @min:%2etimings */] || {};
_setTimingValue(timings, "sendEventStart", sendEventStart_1);
_setTimingValue(timings, "serializationStart", serializationStart);
_setTimingValue(timings, "serializationCompleted", serializationCompleted);
}
telemetryItem[strSendAttempt] > 0 ? telemetryItem[strSendAttempt]++ : telemetryItem[strSendAttempt] = 1;
}
}
// Note: always sending this notification in a synchronous manner.
_sendBatchesNotification(thePayload[_DYN_BATCHES /* @min:%2ebatches */], (1000 /* EventBatchNotificationReason.SendingUndefined */ + (sendReason || 0 /* SendRequestReason.Undefined */)), thePayload[_DYN_SEND_TYPE /* @min:%2esendType */], true);
// Disabling the use of const because of Issue:
// - Task 9227844: [1DS] Some environments and packagers automatically "freeze" objects which are defined as const which causes any mutations to throw
// eslint-disable-next-line prefer-const
var orgPayloadData = {
data: