@microsoft/1ds-post-js 3.1.9 → 3.2.0
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/README.md +124 -5
- package/bundle/{ms.post-3.1.9.gbl.js → ms.post-3.2.0.gbl.js} +1706 -825
- package/bundle/ms.post-3.2.0.gbl.js.map +1 -0
- package/bundle/ms.post-3.2.0.gbl.min.js +7 -0
- package/bundle/ms.post-3.2.0.gbl.min.js.map +1 -0
- package/bundle/ms.post-3.2.0.integrity.json +46 -0
- package/bundle/{ms.post-3.1.9.js → ms.post-3.2.0.js} +1706 -825
- package/bundle/ms.post-3.2.0.js.map +1 -0
- package/bundle/ms.post-3.2.0.min.js +7 -0
- package/bundle/ms.post-3.2.0.min.js.map +1 -0
- package/bundle/ms.post.gbl.js +1705 -824
- package/bundle/ms.post.gbl.js.map +1 -1
- package/bundle/ms.post.gbl.min.js +2 -2
- package/bundle/ms.post.gbl.min.js.map +1 -1
- package/bundle/ms.post.integrity.json +17 -17
- package/bundle/ms.post.js +1705 -824
- package/bundle/ms.post.js.map +1 -1
- package/bundle/ms.post.min.js +2 -2
- package/bundle/ms.post.min.js.map +1 -1
- package/dist/ms.post.js +395 -212
- package/dist/ms.post.js.map +1 -1
- package/dist/ms.post.min.js +2 -2
- package/dist/ms.post.min.js.map +1 -1
- package/dist-esm/src/BatchNotificationActions.js +1 -1
- package/dist-esm/src/ClockSkewManager.js +1 -1
- package/dist-esm/src/Constants.d.ts +25 -0
- package/dist-esm/src/Constants.js +31 -0
- package/dist-esm/src/Constants.js.map +1 -0
- package/dist-esm/src/DataModels.d.ts +55 -0
- package/dist-esm/src/DataModels.js +1 -1
- package/dist-esm/src/EventBatch.d.ts +5 -2
- package/dist-esm/src/EventBatch.js +35 -15
- package/dist-esm/src/EventBatch.js.map +1 -1
- package/dist-esm/src/HttpManager.d.ts +2 -2
- package/dist-esm/src/HttpManager.js +186 -94
- package/dist-esm/src/HttpManager.js.map +1 -1
- package/dist-esm/src/Index.js +1 -1
- package/dist-esm/src/KillSwitch.js +1 -1
- package/dist-esm/src/PostChannel.d.ts +0 -4
- package/dist-esm/src/PostChannel.js +175 -107
- package/dist-esm/src/PostChannel.js.map +1 -1
- package/dist-esm/src/RetryPolicy.d.ts +20 -25
- package/dist-esm/src/RetryPolicy.js +35 -44
- package/dist-esm/src/RetryPolicy.js.map +1 -1
- package/dist-esm/src/Serializer.js +1 -1
- package/dist-esm/src/typings/XDomainRequest.js +1 -1
- package/package.json +3 -3
- package/src/Constants.ts +28 -0
- package/src/DataModels.ts +68 -0
- package/src/EventBatch.ts +47 -14
- package/src/HttpManager.ts +216 -98
- package/src/PostChannel.ts +207 -130
- package/src/RetryPolicy.ts +33 -38
- package/bundle/ms.post-3.1.9.gbl.js.map +0 -1
- package/bundle/ms.post-3.1.9.gbl.min.js +0 -7
- package/bundle/ms.post-3.1.9.gbl.min.js.map +0 -1
- package/bundle/ms.post-3.1.9.integrity.json +0 -46
- package/bundle/ms.post-3.1.9.js.map +0 -1
- package/bundle/ms.post-3.1.9.min.js +0 -7
- package/bundle/ms.post-3.1.9.min.js.map +0 -1
package/src/HttpManager.ts
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
import {
|
|
7
7
|
isReactNative, isValueAssigned, isString, getTime, arrForEach, getLocation, strTrim, isFetchSupported, isXhrSupported,
|
|
8
8
|
isBeaconsSupported, FullVersionString, useXDomainRequest, IExtendedAppInsightsCore, IExtendedConfiguration,
|
|
9
|
-
|
|
9
|
+
eLoggingSeverity, _eExtendedInternalMessageId, SendRequestReason, strUndefined, getNavigator, doPerf, IPerfEvent,
|
|
10
10
|
dateNow, isUndefined, isNullOrUndefined, objForEachKey, ICookieMgr, isNumber, isArray, TransportType, dumpObj, objKeys, extend,
|
|
11
|
-
EventSendType, hasOwnProperty, openXhr
|
|
11
|
+
EventSendType, hasOwnProperty, openXhr, _throwInternal, _eInternalMessageId
|
|
12
12
|
} from "@microsoft/1ds-core-js";
|
|
13
13
|
import {
|
|
14
14
|
IXHROverride, IPostTransmissionTelemetryItem, ICollectorResult,
|
|
@@ -18,12 +18,22 @@ import {
|
|
|
18
18
|
import { BatchNotificationAction, BatchNotificationActions } from "./BatchNotificationActions";
|
|
19
19
|
import { EventBatch } from "./EventBatch";
|
|
20
20
|
import { Serializer, ISerializedPayload } from "./Serializer";
|
|
21
|
-
import
|
|
21
|
+
import { retryPolicyGetMillisToBackoffForRetry, retryPolicyShouldRetryForStatus } from "./RetryPolicy";
|
|
22
22
|
import EVTKillSwitch from "./KillSwitch";
|
|
23
23
|
import EVTClockSkewManager from "./ClockSkewManager";
|
|
24
24
|
import dynamicProto from "@microsoft/dynamicproto-js";
|
|
25
25
|
import { IChannelConfiguration } from "./Index";
|
|
26
26
|
import { XDomainRequest as IXDomainRequest } from "./typings/XDomainRequest";
|
|
27
|
+
import {
|
|
28
|
+
defaultCacheControl, defaultContentType, DisabledPropertyName, Method, strApiKey, strAuthXToken, strCacheControl,
|
|
29
|
+
strClientId, strClientVersion, strContentTypeHeader, strDropped, strKillDurationHeader, strKillDurationSecondsHeader,
|
|
30
|
+
strKillTokensHeader, strMsaDeviceTicket, strMsfpc, strNoResponseBody, strOther, strRequeue, strResponseFail, strSending, strTimeDeltaHeader,
|
|
31
|
+
strTimeDeltaToApply, strUploadTime
|
|
32
|
+
} from "./Constants";
|
|
33
|
+
|
|
34
|
+
const strSendAttempt = "sendAttempt";
|
|
35
|
+
|
|
36
|
+
const _noResponseQs = "&" + strNoResponseBody + "=true";
|
|
27
37
|
|
|
28
38
|
// TypeScript removed this interface so we need to declare the global so we can check for it's existence.
|
|
29
39
|
declare var XDomainRequest: {
|
|
@@ -31,23 +41,11 @@ declare var XDomainRequest: {
|
|
|
31
41
|
new(): IXDomainRequest;
|
|
32
42
|
};
|
|
33
43
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const strRequeue = "requeue";
|
|
40
|
-
const strResponseFail = "rspFail";
|
|
41
|
-
const strOther = "oth";
|
|
42
|
-
|
|
43
|
-
const defaultCacheControl = "no-cache, no-store";
|
|
44
|
-
const defaultContentType = "application/x-json-stream";
|
|
45
|
-
const strCacheControl = "cache-control";
|
|
46
|
-
const strContentTypeHeader = "content-type";
|
|
47
|
-
const strKillTokensHeader = "kill-tokens";
|
|
48
|
-
const strKillDurationHeader = "kill-duration";
|
|
49
|
-
const strKillDurationSecondsHeader = "kill-duration-seconds";
|
|
50
|
-
const strTimeDeltaHeader = "time-delta-millis";
|
|
44
|
+
interface IRequestUrlDetails {
|
|
45
|
+
url: string,
|
|
46
|
+
hdrs: { [key: string]: string },
|
|
47
|
+
useHdrs: boolean
|
|
48
|
+
}
|
|
51
49
|
|
|
52
50
|
/**
|
|
53
51
|
* Identifies the default notification reason to the action names
|
|
@@ -60,6 +58,24 @@ const _eventActionMap: any = {
|
|
|
60
58
|
[EventBatchNotificationReason.SizeLimitExceeded]: strDropped
|
|
61
59
|
};
|
|
62
60
|
|
|
61
|
+
const _collectorQsHeaders = { };
|
|
62
|
+
const _collectorHeaderToQs = { };
|
|
63
|
+
|
|
64
|
+
function _addCollectorHeaderQsMapping(qsName: string, headerName: string, allowQs?: boolean) {
|
|
65
|
+
_collectorQsHeaders[qsName] = headerName;
|
|
66
|
+
if (allowQs !== false) {
|
|
67
|
+
_collectorHeaderToQs[headerName] = qsName;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_addCollectorHeaderQsMapping(strMsaDeviceTicket, strMsaDeviceTicket, false);
|
|
72
|
+
_addCollectorHeaderQsMapping(strClientVersion, strClientVersion);
|
|
73
|
+
_addCollectorHeaderQsMapping(strClientId, "Client-Id");
|
|
74
|
+
_addCollectorHeaderQsMapping(strApiKey, strApiKey);
|
|
75
|
+
_addCollectorHeaderQsMapping(strTimeDeltaToApply, strTimeDeltaToApply);
|
|
76
|
+
_addCollectorHeaderQsMapping(strUploadTime, strUploadTime);
|
|
77
|
+
_addCollectorHeaderQsMapping(strAuthXToken, strAuthXToken);
|
|
78
|
+
|
|
63
79
|
type OnCompleteCallback = (status: number, headers: { [headerName: string]: string }, response?: string) => void;
|
|
64
80
|
|
|
65
81
|
function _getResponseText(xhr: XMLHttpRequest | IXDomainRequest) {
|
|
@@ -102,10 +118,21 @@ function _hasHeader(headers: any, header: string) {
|
|
|
102
118
|
return hasHeader;
|
|
103
119
|
}
|
|
104
120
|
|
|
121
|
+
function _addRequestDetails(details: IRequestUrlDetails, name: string, value: string, useHeaders: boolean) {
|
|
122
|
+
if (name && value && value.length > 0) {
|
|
123
|
+
if (useHeaders && _collectorQsHeaders[name]) {
|
|
124
|
+
details.hdrs[_collectorQsHeaders[name]] = value;
|
|
125
|
+
details.useHdrs = true;
|
|
126
|
+
} else {
|
|
127
|
+
details.url += "&" + name + "=" + value;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
105
132
|
/**
|
|
106
133
|
* Class managing the sending of requests.
|
|
107
134
|
*/
|
|
108
|
-
export
|
|
135
|
+
export class HttpManager {
|
|
109
136
|
public sendHook: PayloadPreprocessorFunction | undefined;
|
|
110
137
|
public sendListener: PayloadListenerFunction | undefined;
|
|
111
138
|
public _responseHandlers: Array<(responseText: string) => void> = [];
|
|
@@ -114,9 +141,8 @@ export default class HttpManager {
|
|
|
114
141
|
* @constructor
|
|
115
142
|
* @param requestQueue - The queue that contains the requests to be sent.
|
|
116
143
|
*/
|
|
117
|
-
constructor(maxEventsPerBatch: number, maxConnections: number,
|
|
118
|
-
let _urlString: string = "?cors=true&" + strContentTypeHeader.toLowerCase() + "=" + defaultContentType
|
|
119
|
-
+ FullVersionString;
|
|
144
|
+
constructor(maxEventsPerBatch: number, maxConnections: number, maxRequestRetriesBeforeBackoff: number, actions: BatchNotificationActions) {
|
|
145
|
+
let _urlString: string = "?cors=true&" + strContentTypeHeader.toLowerCase() + "=" + defaultContentType;
|
|
120
146
|
let _killSwitch: EVTKillSwitch = new EVTKillSwitch();
|
|
121
147
|
let _paused = false;
|
|
122
148
|
let _clockSkewManager = new EVTClockSkewManager();
|
|
@@ -133,6 +159,9 @@ export default class HttpManager {
|
|
|
133
159
|
let _enableEventTimings = false;
|
|
134
160
|
let _cookieMgr: ICookieMgr;
|
|
135
161
|
let _isUnloading = false;
|
|
162
|
+
let _useHeaders = false;
|
|
163
|
+
let _xhrTimeout: number;
|
|
164
|
+
let _disableXhrSync: boolean;
|
|
136
165
|
|
|
137
166
|
dynamicProto(HttpManager, this, (_self) => {
|
|
138
167
|
let _sendCredentials = true;
|
|
@@ -149,6 +178,8 @@ export default class HttpManager {
|
|
|
149
178
|
}
|
|
150
179
|
|
|
151
180
|
_urlString = endpointUrl + _urlString;
|
|
181
|
+
|
|
182
|
+
_useHeaders = !isUndefined(channelConfig.avoidOptions) ? !channelConfig.avoidOptions : true;
|
|
152
183
|
_core = core;
|
|
153
184
|
_cookieMgr = core.getCookieMgr();
|
|
154
185
|
_enableEventTimings = !(_core.config as IExtendedConfiguration).disableEventTimings;
|
|
@@ -160,17 +191,15 @@ export default class HttpManager {
|
|
|
160
191
|
enableCompoundKey = !!channelConfig.enableCompoundKey;
|
|
161
192
|
}
|
|
162
193
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
// if (!!channelConfig.disableCacheHeader) {
|
|
166
|
-
// // Stop Chrome from stalling/throttling requests see task #7178858
|
|
167
|
-
// _self.addHeader("Cache-control", "no-cache, no-store");
|
|
168
|
-
// }
|
|
194
|
+
_xhrTimeout = channelConfig.xhrTimeout;
|
|
195
|
+
_disableXhrSync = channelConfig.disableXhrSync;
|
|
169
196
|
|
|
170
197
|
_useBeacons = !isReactNative(); // Only use beacons if not running in React Native
|
|
171
198
|
_serializer = new Serializer(_core, valueSanitizer, stringifyObjects, enableCompoundKey);
|
|
172
199
|
|
|
173
200
|
let syncHttpInterface = httpInterface;
|
|
201
|
+
let beaconHttpInterface: IXHROverride = channelConfig.alwaysUseXhrOverride ? httpInterface : null;
|
|
202
|
+
let fetchSyncHttpInterface: IXHROverride = channelConfig.alwaysUseXhrOverride ? httpInterface : null;
|
|
174
203
|
|
|
175
204
|
if (!httpInterface) {
|
|
176
205
|
_customHttpInterface = false;
|
|
@@ -210,8 +239,8 @@ export default class HttpManager {
|
|
|
210
239
|
_sendInterfaces = {
|
|
211
240
|
[EventSendType.Batched]: httpInterface,
|
|
212
241
|
[EventSendType.Synchronous]: syncHttpInterface || _getSenderInterface([TransportType.Xhr, TransportType.Fetch, TransportType.Beacon], true),
|
|
213
|
-
[EventSendType.SendBeacon]: _getSenderInterface([TransportType.Beacon, TransportType.Fetch, TransportType.Xhr], true)
|
|
214
|
-
[EventSendType.SyncFetch]: _getSenderInterface([TransportType.Fetch, TransportType.Beacon, TransportType.Xhr], true)
|
|
242
|
+
[EventSendType.SendBeacon]: beaconHttpInterface || _getSenderInterface([TransportType.Beacon, TransportType.Fetch], true) || syncHttpInterface || _getSenderInterface([TransportType.Xhr], true),
|
|
243
|
+
[EventSendType.SyncFetch]: fetchSyncHttpInterface || _getSenderInterface([TransportType.Fetch, TransportType.Beacon], true) || syncHttpInterface || _getSenderInterface([TransportType.Xhr], true)
|
|
215
244
|
};
|
|
216
245
|
};
|
|
217
246
|
|
|
@@ -256,6 +285,9 @@ export default class HttpManager {
|
|
|
256
285
|
// It doesn't support custom headers, so no action is taken with current requestHeaders
|
|
257
286
|
let xdr = new XDomainRequest();
|
|
258
287
|
xdr.open(Method, payload.urlString);
|
|
288
|
+
if (payload.timeout) {
|
|
289
|
+
xdr.timeout = payload.timeout;
|
|
290
|
+
}
|
|
259
291
|
|
|
260
292
|
// can't get the status code in xdr.
|
|
261
293
|
xdr.onload = () => {
|
|
@@ -288,6 +320,9 @@ export default class HttpManager {
|
|
|
288
320
|
}
|
|
289
321
|
|
|
290
322
|
function _fetchSendPost(payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) {
|
|
323
|
+
let theUrl = payload.urlString;
|
|
324
|
+
let ignoreResponse = false;
|
|
325
|
+
let responseHandled = false;
|
|
291
326
|
let requestInit: RequestInit = {
|
|
292
327
|
body: payload.data,
|
|
293
328
|
method: Method,
|
|
@@ -296,6 +331,12 @@ export default class HttpManager {
|
|
|
296
331
|
|
|
297
332
|
if (sync) {
|
|
298
333
|
requestInit.keepalive = true;
|
|
334
|
+
if ((payload as IInternalPayloadData)._sendReason === SendRequestReason.Unload) {
|
|
335
|
+
// As a sync request (during unload), it is unlikely that we will get a chance to process the response so
|
|
336
|
+
// just like beacon send assume that the events have been accepted and processed
|
|
337
|
+
ignoreResponse = true;
|
|
338
|
+
theUrl += _noResponseQs;
|
|
339
|
+
}
|
|
299
340
|
}
|
|
300
341
|
|
|
301
342
|
if (_sendCredentials) {
|
|
@@ -308,7 +349,7 @@ export default class HttpManager {
|
|
|
308
349
|
requestInit.headers = payload.headers;
|
|
309
350
|
}
|
|
310
351
|
|
|
311
|
-
fetch(
|
|
352
|
+
fetch(theUrl, requestInit).then((response) => {
|
|
312
353
|
let headerMap = {};
|
|
313
354
|
let responseText = "";
|
|
314
355
|
if (response.headers) {
|
|
@@ -321,16 +362,41 @@ export default class HttpManager {
|
|
|
321
362
|
responseText = text;
|
|
322
363
|
});
|
|
323
364
|
}
|
|
324
|
-
|
|
325
|
-
|
|
365
|
+
|
|
366
|
+
if (!responseHandled) {
|
|
367
|
+
responseHandled = true;
|
|
368
|
+
_doOnComplete(oncomplete, response.status, headerMap, responseText);
|
|
369
|
+
_handleCollectorResponse(responseText);
|
|
370
|
+
}
|
|
326
371
|
}).catch((error) => {
|
|
327
372
|
// In case there is an error in the request. Set the status to 0
|
|
328
373
|
// so that the events can be retried later.
|
|
329
|
-
|
|
374
|
+
if (!responseHandled) {
|
|
375
|
+
responseHandled = true;
|
|
376
|
+
_doOnComplete(oncomplete, 0, {});
|
|
377
|
+
}
|
|
330
378
|
});
|
|
379
|
+
|
|
380
|
+
if (ignoreResponse && !responseHandled) {
|
|
381
|
+
// Assume success during unload processing
|
|
382
|
+
responseHandled = true;
|
|
383
|
+
_doOnComplete(oncomplete, 200, {});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (!responseHandled && payload.timeout > 0) {
|
|
387
|
+
// Simulate timeout
|
|
388
|
+
_postManager._setTimeoutOverride(() => {
|
|
389
|
+
if (!responseHandled) {
|
|
390
|
+
// Assume a 500 response (which will cause a retry)
|
|
391
|
+
responseHandled = true;
|
|
392
|
+
_doOnComplete(oncomplete, 500, {});
|
|
393
|
+
}
|
|
394
|
+
}, payload.timeout);
|
|
395
|
+
}
|
|
331
396
|
}
|
|
332
397
|
|
|
333
398
|
function _xhrSendPost(payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) {
|
|
399
|
+
let theUrl = payload.urlString;
|
|
334
400
|
|
|
335
401
|
function _appendHeader(theHeaders, xhr, name) {
|
|
336
402
|
if (!theHeaders[name] && xhr && xhr.getResponseHeader) {
|
|
@@ -363,33 +429,37 @@ export default class HttpManager {
|
|
|
363
429
|
function xhrComplete(xhr, responseTxt?) {
|
|
364
430
|
_doOnComplete(oncomplete, xhr.status, _getAllResponseHeaders(xhr), responseTxt);
|
|
365
431
|
}
|
|
432
|
+
if (sync && payload.disableXhrSync) {
|
|
433
|
+
sync = false;
|
|
434
|
+
}
|
|
366
435
|
|
|
367
|
-
let
|
|
436
|
+
let xhrRequest = openXhr(Method, theUrl, _sendCredentials, true, sync, payload.timeout);
|
|
368
437
|
|
|
369
438
|
// Set custom headers (e.g. gzip) here (after open())
|
|
370
439
|
objForEachKey(payload.headers, (name, value) => {
|
|
371
|
-
|
|
440
|
+
xhrRequest.setRequestHeader(name, value);
|
|
372
441
|
});
|
|
373
|
-
|
|
374
|
-
let response = _getResponseText(
|
|
375
|
-
xhrComplete(
|
|
442
|
+
xhrRequest.onload = () => {
|
|
443
|
+
let response = _getResponseText(xhrRequest);
|
|
444
|
+
xhrComplete(xhrRequest, response);
|
|
376
445
|
_handleCollectorResponse(response);
|
|
377
446
|
};
|
|
378
|
-
|
|
379
|
-
xhrComplete(
|
|
447
|
+
xhrRequest.onerror = () => {
|
|
448
|
+
xhrComplete(xhrRequest);
|
|
380
449
|
};
|
|
381
|
-
|
|
382
|
-
xhrComplete(
|
|
450
|
+
xhrRequest.ontimeout = () => {
|
|
451
|
+
xhrComplete(xhrRequest);
|
|
383
452
|
};
|
|
384
|
-
|
|
453
|
+
xhrRequest.send(payload.data);
|
|
385
454
|
}
|
|
386
455
|
|
|
387
456
|
function _doOnComplete(oncomplete: OnCompleteCallback, status: number, headers: { [headerName: string]: string }, response?: string) {
|
|
388
457
|
try {
|
|
389
458
|
oncomplete(status, headers, response);
|
|
390
459
|
} catch (e) {
|
|
391
|
-
_postManager.diagLog()
|
|
392
|
-
|
|
460
|
+
_throwInternal(_postManager.diagLog(),
|
|
461
|
+
eLoggingSeverity.WARNING,
|
|
462
|
+
_eExtendedInternalMessageId.SendPostOnCompleteFailure, dumpObj(e));
|
|
393
463
|
}
|
|
394
464
|
}
|
|
395
465
|
|
|
@@ -398,9 +468,11 @@ export default class HttpManager {
|
|
|
398
468
|
let internalPayloadData = payload as IInternalPayloadData;
|
|
399
469
|
let status = 200;
|
|
400
470
|
let thePayload = internalPayloadData._thePayload;
|
|
471
|
+
let theUrl = payload.urlString + _noResponseQs;
|
|
472
|
+
|
|
401
473
|
try {
|
|
402
474
|
let nav = getNavigator();
|
|
403
|
-
if (!nav.sendBeacon(
|
|
475
|
+
if (!nav.sendBeacon(theUrl, payload.data)) {
|
|
404
476
|
if (thePayload) {
|
|
405
477
|
// Failed to send entire payload so try and split data and try to send as much events as possible
|
|
406
478
|
let droppedBatches: EventBatch[] = [];
|
|
@@ -408,7 +480,7 @@ export default class HttpManager {
|
|
|
408
480
|
if (droppedBatches && theBatch && theBatch.count() > 0) {
|
|
409
481
|
let theEvents = theBatch.events();
|
|
410
482
|
for (let lp = 0; lp < theEvents.length; lp++) {
|
|
411
|
-
if (!nav.sendBeacon(
|
|
483
|
+
if (!nav.sendBeacon(theUrl, _serializer.getEventBlob(theEvents[lp]))) {
|
|
412
484
|
// Can't send anymore, so split the batch and drop the rest
|
|
413
485
|
droppedBatches.push(theBatch.split(lp));
|
|
414
486
|
break;
|
|
@@ -427,7 +499,7 @@ export default class HttpManager {
|
|
|
427
499
|
}
|
|
428
500
|
|
|
429
501
|
} catch (ex) {
|
|
430
|
-
_postManager.diagLog().warnToConsole("Failed to send telemetry using sendBeacon API. Ex:" + ex);
|
|
502
|
+
_postManager.diagLog().warnToConsole("Failed to send telemetry using sendBeacon API. Ex:" + dumpObj(ex));
|
|
431
503
|
status = 0;
|
|
432
504
|
} finally {
|
|
433
505
|
_doOnComplete(oncomplete, status, {}, "");
|
|
@@ -665,13 +737,38 @@ export default class HttpManager {
|
|
|
665
737
|
_sendBatchesNotification(droppedBatches, EventBatchNotificationReason.KillSwitch, sendType);
|
|
666
738
|
}, () => ({ batches: _createDebugBatches(orgBatches), retryCount, isTeardown, isSynchronous, sendReason, useSendBeacon: _isBeaconPayload(sendType), sendType }), !isSynchronous);
|
|
667
739
|
} catch (ex) {
|
|
668
|
-
_postManager.diagLog()
|
|
669
|
-
|
|
740
|
+
_throwInternal(_postManager.diagLog(),
|
|
741
|
+
eLoggingSeverity.WARNING,
|
|
742
|
+
_eInternalMessageId.CannotSerializeObject, "Unexpected Exception sending batch: " + dumpObj(ex));
|
|
670
743
|
}
|
|
671
744
|
}
|
|
672
745
|
|
|
673
|
-
function
|
|
674
|
-
let
|
|
746
|
+
function _buildRequestDetails(thePayload: ISerializedPayload, useHeaders: boolean): IRequestUrlDetails {
|
|
747
|
+
let requestDetails: IRequestUrlDetails = {
|
|
748
|
+
url: _urlString,
|
|
749
|
+
hdrs: {},
|
|
750
|
+
useHdrs: false // Assume no headers
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
if (!useHeaders) {
|
|
754
|
+
// Attempt to map headers to a query string if possible
|
|
755
|
+
objForEachKey(_headers, (name, value) => {
|
|
756
|
+
if (_collectorHeaderToQs[name]) {
|
|
757
|
+
_addRequestDetails(requestDetails, _collectorHeaderToQs[name], value, false);
|
|
758
|
+
} else {
|
|
759
|
+
// No mapping, so just include in the headers anyway (may not get sent if using sendBeacon())
|
|
760
|
+
requestDetails.hdrs[name] = value;
|
|
761
|
+
requestDetails.useHdrs = true;
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
} else {
|
|
765
|
+
// Copy the pre-defined headers into the payload headers
|
|
766
|
+
requestDetails.hdrs = extend(requestDetails.hdrs, _headers);
|
|
767
|
+
requestDetails.useHdrs = (objKeys(requestDetails.hdrs).length > 0);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
_addRequestDetails(requestDetails, strClientId, "NO_AUTH", useHeaders);
|
|
771
|
+
_addRequestDetails(requestDetails, strClientVersion, FullVersionString, useHeaders);
|
|
675
772
|
|
|
676
773
|
let apiQsKeys = "";
|
|
677
774
|
arrForEach(thePayload.apiKeys, (apiKey) => {
|
|
@@ -682,33 +779,30 @@ export default class HttpManager {
|
|
|
682
779
|
apiQsKeys += apiKey;
|
|
683
780
|
});
|
|
684
781
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
urlString += "&upload-time=" + dateNow().toString();
|
|
782
|
+
_addRequestDetails(requestDetails, strApiKey, apiQsKeys, useHeaders);
|
|
783
|
+
_addRequestDetails(requestDetails, strUploadTime, dateNow().toString(), useHeaders);
|
|
690
784
|
|
|
691
785
|
let msfpc = _getMsfpc(thePayload);
|
|
692
786
|
if (isValueAssigned(msfpc)) {
|
|
693
|
-
|
|
787
|
+
requestDetails.url += "&ext.intweb.msfpc=" + msfpc;
|
|
694
788
|
}
|
|
695
789
|
|
|
696
790
|
if (_clockSkewManager.shouldAddClockSkewHeaders()) {
|
|
697
|
-
|
|
791
|
+
_addRequestDetails(requestDetails, strTimeDeltaToApply, _clockSkewManager.getClockSkewHeaderValue(), useHeaders);
|
|
698
792
|
}
|
|
699
793
|
|
|
700
794
|
if (_core.getWParam) {
|
|
701
795
|
let wParam = _core.getWParam();
|
|
702
796
|
if (wParam >= 0) {
|
|
703
|
-
|
|
797
|
+
requestDetails.url += "&w=" + wParam;
|
|
704
798
|
}
|
|
705
799
|
}
|
|
706
800
|
|
|
707
801
|
for (let i = 0; i < _queryStringParameters.length; i++) {
|
|
708
|
-
|
|
802
|
+
requestDetails.url += "&" + _queryStringParameters[i].name + "=" + _queryStringParameters[i].value;
|
|
709
803
|
}
|
|
710
804
|
|
|
711
|
-
return
|
|
805
|
+
return requestDetails;
|
|
712
806
|
}
|
|
713
807
|
|
|
714
808
|
function _canUseSendBeaconApi() {
|
|
@@ -723,9 +817,25 @@ export default class HttpManager {
|
|
|
723
817
|
function _doPayloadSend(thePayload: ISerializedPayload, serializationStart: number, serializationCompleted: number, sendReason: SendRequestReason) {
|
|
724
818
|
|
|
725
819
|
if (thePayload && thePayload.payloadBlob && thePayload.payloadBlob.length > 0) {
|
|
726
|
-
let
|
|
820
|
+
let useSendHook = !!_self.sendHook;
|
|
821
|
+
let sendInterface = _sendInterfaces[thePayload.sendType];
|
|
822
|
+
|
|
823
|
+
// Send all data using a beacon style transport if closing mode is on or channel was teared down
|
|
824
|
+
if (!_isBeaconPayload(thePayload.sendType) && thePayload.isBeacon && thePayload.sendReason === SendRequestReason.Unload) {
|
|
825
|
+
sendInterface = _sendInterfaces[EventSendType.SendBeacon] || _sendInterfaces[EventSendType.SyncFetch] || sendInterface;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
let useHeaders = _useHeaders;
|
|
829
|
+
|
|
830
|
+
// Disable header usage if we know we are using sendBeacon as additional headers are not supported
|
|
831
|
+
if (thePayload.isBeacon || sendInterface._transport === TransportType.Beacon) {
|
|
832
|
+
useHeaders = false;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
let requestDetails = _buildRequestDetails(thePayload, useHeaders);
|
|
836
|
+
useHeaders = useHeaders || requestDetails.useHdrs;
|
|
837
|
+
|
|
727
838
|
let sendEventStart = getTime();
|
|
728
|
-
let strSendAttempt = "sendAttempt";
|
|
729
839
|
|
|
730
840
|
doPerf(_core, () => "HttpManager:_doPayloadSend", () => {
|
|
731
841
|
// Increment the send attempt count and add timings after packaging (So it's not serialized in the 1st attempt)
|
|
@@ -757,28 +867,29 @@ export default class HttpManager {
|
|
|
757
867
|
// eslint-disable-next-line prefer-const
|
|
758
868
|
let orgPayloadData: IInternalPayloadData = {
|
|
759
869
|
data: thePayload.payloadBlob,
|
|
760
|
-
urlString:
|
|
761
|
-
headers:
|
|
870
|
+
urlString: requestDetails.url,
|
|
871
|
+
headers: requestDetails.hdrs,
|
|
762
872
|
_thePayload: thePayload,
|
|
763
|
-
_sendReason: sendReason
|
|
873
|
+
_sendReason: sendReason,
|
|
874
|
+
timeout: _xhrTimeout
|
|
764
875
|
};
|
|
765
876
|
|
|
766
|
-
if (!
|
|
767
|
-
orgPayloadData.
|
|
877
|
+
if (!isUndefined(_disableXhrSync)) {
|
|
878
|
+
orgPayloadData.disableXhrSync = !!_disableXhrSync;
|
|
768
879
|
}
|
|
769
880
|
|
|
770
|
-
if
|
|
771
|
-
|
|
881
|
+
// Only automatically add the following headers if already sending headers and we are not attempting to avoid an options call
|
|
882
|
+
if (useHeaders) {
|
|
883
|
+
if (!_hasHeader(orgPayloadData.headers, strCacheControl)) {
|
|
884
|
+
orgPayloadData.headers[strCacheControl] = defaultCacheControl;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
if (!_hasHeader(orgPayloadData.headers, strContentTypeHeader)) {
|
|
888
|
+
orgPayloadData.headers[strContentTypeHeader] = defaultContentType;
|
|
889
|
+
}
|
|
772
890
|
}
|
|
773
891
|
|
|
774
892
|
let sender: (payload: IPayloadData) => void = null;
|
|
775
|
-
let useSendHook = !!_self.sendHook;
|
|
776
|
-
|
|
777
|
-
let sendInterface = _sendInterfaces[thePayload.sendType];
|
|
778
|
-
// Send all data using a beacon style transport if closing mode is on or channel was teared down
|
|
779
|
-
if (!_isBeaconPayload(thePayload.sendType) && thePayload.isBeacon && thePayload.sendReason === SendRequestReason.Unload) {
|
|
780
|
-
sendInterface = _sendInterfaces[EventSendType.SendBeacon] || _sendInterfaces[EventSendType.SyncFetch] || sendInterface;
|
|
781
|
-
}
|
|
782
893
|
|
|
783
894
|
if (sendInterface) {
|
|
784
895
|
// Send sync requests if the request is immediate or we are tearing down telemetry.
|
|
@@ -822,7 +933,9 @@ export default class HttpManager {
|
|
|
822
933
|
let hookData: IPayloadData = {
|
|
823
934
|
data: orgPayloadData.data,
|
|
824
935
|
urlString: orgPayloadData.urlString,
|
|
825
|
-
headers: extend({}, orgPayloadData.headers)
|
|
936
|
+
headers: extend({}, orgPayloadData.headers),
|
|
937
|
+
timeout: orgPayloadData.timeout,
|
|
938
|
+
disableXhrSync: orgPayloadData.disableXhrSync
|
|
826
939
|
};
|
|
827
940
|
|
|
828
941
|
let senderCalled = false;
|
|
@@ -908,13 +1021,13 @@ export default class HttpManager {
|
|
|
908
1021
|
|
|
909
1022
|
// Disabling triple-equals rule to avoid httpOverrides from failing because they are returning a string value
|
|
910
1023
|
// tslint:disable-next-line:triple-equals
|
|
911
|
-
if (status == 200) {
|
|
1024
|
+
if (status == 200 || status == 204) {
|
|
912
1025
|
// Response was successfully sent
|
|
913
1026
|
reason = EventBatchNotificationReason.Complete;
|
|
914
1027
|
return;
|
|
915
1028
|
}
|
|
916
1029
|
|
|
917
|
-
if (!
|
|
1030
|
+
if (!retryPolicyShouldRetryForStatus(status) || thePayload.numEvents <= 0) {
|
|
918
1031
|
// Only retry for specific response codes and if there is still events after kill switch processing
|
|
919
1032
|
shouldRetry = false;
|
|
920
1033
|
}
|
|
@@ -928,7 +1041,8 @@ export default class HttpManager {
|
|
|
928
1041
|
reason = EventBatchNotificationReason.RequeueEvents;
|
|
929
1042
|
let retryCount = thePayload.retryCnt;
|
|
930
1043
|
if (thePayload.sendType === EventSendType.Batched) {
|
|
931
|
-
|
|
1044
|
+
// attempt to resend the entire batch
|
|
1045
|
+
if (retryCount < maxRequestRetriesBeforeBackoff) {
|
|
932
1046
|
isRetrying = true;
|
|
933
1047
|
_doAction(() => {
|
|
934
1048
|
// try to resend the same batches
|
|
@@ -940,9 +1054,14 @@ export default class HttpManager {
|
|
|
940
1054
|
}
|
|
941
1055
|
|
|
942
1056
|
_sendBatches(thePayload.batches, retryCount + 1, thePayload.isTeardown, _isUnloading ? EventSendType.SendBeacon : thePayload.sendType, SendRequestReason.Retry);
|
|
943
|
-
}, _isUnloading,
|
|
1057
|
+
}, _isUnloading, retryPolicyGetMillisToBackoffForRetry(retryCount));
|
|
944
1058
|
} else {
|
|
945
1059
|
backOffTrans = true;
|
|
1060
|
+
if (_isUnloading) {
|
|
1061
|
+
// we are unloading so don't try and requeue the events otherwise let the events get requeued and resent during the backoff sending
|
|
1062
|
+
// This will also cause the events to be purged based on the priority (if necessary)
|
|
1063
|
+
reason = EventBatchNotificationReason.NonRetryableStatus;
|
|
1064
|
+
}
|
|
946
1065
|
}
|
|
947
1066
|
}
|
|
948
1067
|
}
|
|
@@ -1048,12 +1167,9 @@ export default class HttpManager {
|
|
|
1048
1167
|
|
|
1049
1168
|
function _getMsfpc(thePayload: ISerializedPayload): string {
|
|
1050
1169
|
for (let lp = 0; lp < thePayload.batches.length; lp++) {
|
|
1051
|
-
let
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
if (isValueAssigned(intWeb["msfpc"])) {
|
|
1055
|
-
return encodeURIComponent(intWeb["msfpc"]);
|
|
1056
|
-
}
|
|
1170
|
+
let msfpc = thePayload.batches[lp].Msfpc();
|
|
1171
|
+
if (msfpc) {
|
|
1172
|
+
return encodeURIComponent(msfpc);
|
|
1057
1173
|
}
|
|
1058
1174
|
}
|
|
1059
1175
|
|
|
@@ -1067,16 +1183,17 @@ export default class HttpManager {
|
|
|
1067
1183
|
try {
|
|
1068
1184
|
responseHandlers[i](responseText);
|
|
1069
1185
|
} catch (e) {
|
|
1070
|
-
_postManager.diagLog()
|
|
1071
|
-
|
|
1186
|
+
_throwInternal(_postManager.diagLog(),
|
|
1187
|
+
eLoggingSeverity.CRITICAL,
|
|
1188
|
+
_eExtendedInternalMessageId.PostResponseHandler,
|
|
1072
1189
|
"Response handler failed: " + e);
|
|
1073
1190
|
}
|
|
1074
1191
|
}
|
|
1075
1192
|
if (responseText) {
|
|
1076
1193
|
let response = JSON.parse(responseText) as ICollectorResult;
|
|
1077
|
-
if (isValueAssigned(response.webResult) && isValueAssigned(response.webResult
|
|
1194
|
+
if (isValueAssigned(response.webResult) && isValueAssigned(response.webResult[strMsfpc])) {
|
|
1078
1195
|
// Set cookie
|
|
1079
|
-
_cookieMgr.set("MSFPC", response.webResult
|
|
1196
|
+
_cookieMgr.set("MSFPC", response.webResult[strMsfpc], 365 * 86400);
|
|
1080
1197
|
}
|
|
1081
1198
|
}
|
|
1082
1199
|
} catch (ex) {
|
|
@@ -1095,8 +1212,9 @@ export default class HttpManager {
|
|
|
1095
1212
|
try {
|
|
1096
1213
|
theAction.call(actions, theBatches, batchReason, isSyncRequest, sendType);
|
|
1097
1214
|
} catch (e) {
|
|
1098
|
-
_postManager.diagLog()
|
|
1099
|
-
|
|
1215
|
+
_throwInternal(_postManager.diagLog(),
|
|
1216
|
+
eLoggingSeverity.CRITICAL,
|
|
1217
|
+
_eInternalMessageId.NotificationException,
|
|
1100
1218
|
"send request notification failed: " + e);
|
|
1101
1219
|
}
|
|
1102
1220
|
}, sendSync || isSyncRequest, 0);
|