Skip to content

Commit

Permalink
Some requests are returning a CORB error for responses containing tex…
Browse files Browse the repository at this point in the history
…t content type #1653 (#1658)

- Use fetch with keepalive support during unload by default (Main CORB fix)
- Fix fetch usage to stop tracking the track call
- Minification and minor performance improvements
  • Loading branch information
MSNev committed Sep 8, 2021
1 parent 58971c0 commit fcef0e0
Show file tree
Hide file tree
Showing 25 changed files with 914 additions and 739 deletions.
2 changes: 1 addition & 1 deletion AISKU/Tests/AISKUSize.Tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class AISKUSizeCheck extends TestClass {
return;
} else {
return response.text().then(text => {
let size = Math.ceil(pako.deflate(text).length/1024);
let size = Math.ceil((pako.deflate(text).length/1024) * 100) / 100.0;
Assert.ok(size <= this.MAX_DEFLATE_SIZE ,`max ${this.MAX_DEFLATE_SIZE} KB, current deflate size is: ${size} KB`);
}).catch((error: Error) => {
Assert.ok(false, `AISKU${postfix} response error: ${error}`);
Expand Down
2 changes: 2 additions & 0 deletions AISKU/Tests/Selenium/appinsights-sdk.tests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AISKUSizeCheck } from "../AISKUSize.Tests";
import { ApplicationInsightsTests } from '../applicationinsights.e2e.tests';
import { ApplicationInsightsFetchTests } from '../applicationinsights.e2e.fetch.tests';
import { SanitizerE2ETests } from '../sanitizer.e2e.tests';
import { ValidateE2ETests } from '../validate.e2e.tests';
import { SenderE2ETests } from '../sender.e2e.tests';
Expand All @@ -10,6 +11,7 @@ import { SnippetInitializationTests } from '../SnippetInitialization.Tests';

new AISKUSizeCheck().registerTests();
new ApplicationInsightsTests().registerTests();
new ApplicationInsightsFetchTests().registerTests();
new ApplicationInsightsDeprecatedTests().registerTests();
new SanitizerE2ETests().registerTests();
new ValidateE2ETests().registerTests();
Expand Down
30 changes: 30 additions & 0 deletions AISKU/Tests/applicationinsights.e2e.fetch.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { DistributedTracingModes } from '@microsoft/applicationinsights-common';
import { ApplicationInsightsTests } from './applicationinsights.e2e.tests';

const _instrumentationKey = 'b7170927-2d1c-44f1-acec-59f4e1751c11';
const _connectionString = `InstrumentationKey=${_instrumentationKey}`;

export class ApplicationInsightsFetchTests extends ApplicationInsightsTests {

constructor() {
super("ApplicationInsightsFetchTests-XHR Disabled");
}

protected _getTestConfig(sessionPrefix: string) {
return {
connectionString: _connectionString,
disableAjaxTracking: false,
disableFetchTracking: false,
disableXhr: true, // Disable XHR support
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true,
maxBatchInterval: 2500,
disableExceptionTracking: false,
namePrefix: sessionPrefix,
enableCorsCorrelation: true,
distributedTracingMode: DistributedTracingModes.AI_AND_W3C,
samplingPercentage: 50,
convertUndefined: "test-value"
};
}
}
38 changes: 21 additions & 17 deletions AISKU/Tests/applicationinsights.e2e.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class ApplicationInsightsTests extends TestClass {
private successSpy: SinonSpy;
private loggingSpy: SinonSpy;
private userSpy: SinonSpy;
private sessionPrefix: string = Util.newId();
private _sessionPrefix: string = Util.newId();
private trackSpy: SinonSpy;
private envelopeConstructorSpy: SinonSpy;

Expand All @@ -52,28 +52,32 @@ export class ApplicationInsightsTests extends TestClass {
private _config;
private _appId: string;

constructor() {
super("ApplicationInsightsTests");
constructor(testName?: string) {
super(testName || "ApplicationInsightsTests");
}

protected _getTestConfig(sessionPrefix: string) {
return {
connectionString: ApplicationInsightsTests._connectionString,
disableAjaxTracking: false,
disableFetchTracking: false,
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true,
maxBatchInterval: 2500,
disableExceptionTracking: false,
namePrefix: sessionPrefix,
enableCorsCorrelation: true,
distributedTracingMode: DistributedTracingModes.AI_AND_W3C,
samplingPercentage: 50,
convertUndefined: "test-value"
};
}

public testInitialize() {
try {
this.isFetchPolyfill = fetch["polyfill"];
this.useFakeServer = false;
this._config = {
connectionString: ApplicationInsightsTests._connectionString,
disableAjaxTracking: false,
disableFetchTracking: false,
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true,
maxBatchInterval: 2500,
disableExceptionTracking: false,
namePrefix: this.sessionPrefix,
enableCorsCorrelation: true,
distributedTracingMode: DistributedTracingModes.AI_AND_W3C,
samplingPercentage: 50,
convertUndefined: "test-value"
};
this._config = this._getTestConfig(this._sessionPrefix);

const init = new ApplicationInsights({
config: this._config
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,9 @@ Most configuration fields are named such that they can be defaulted to falsey. A
| isRetryDisabled | boolean | false | Default false. If false, retry on 206 (partial success), 408 (timeout), 429 (too many requests), 500 (internal server error), 503 (service unavailable), and 0 (offline, only if detected) |
| isStorageUseDisabled | boolean | false | If true, the SDK will not store or read any data from local and session storage. Default is false. |
| isBeaconApiDisabled | boolean | true | If false, the SDK will send all telemetry using the [Beacon API](https://www.w3.org/TR/beacon) |
| disableXhr | boolean | false | Don't use XMLHttpRequest or XDomainRequest (for IE < 9) by default instead attempt to use fetch() or sendBeacon. If no other transport is available it will still use XMLHttpRequest |
| onunloadDisableBeacon | boolean | false | Default false. when tab is closed, the SDK will send all remaining telemetry using the [Beacon API](https://www.w3.org/TR/beacon) |
| onunloadDisableFetch | boolean | false | If fetch keepalive is supported do not use it for sending events during unload, it may still fallback to fetch() without keepalive |
| sdkExtension | string | null | Sets the sdk extension name. Only alphabetic characters are allowed. The extension name is added as a prefix to the 'ai.internal.sdkVersion' tag (e.g. 'ext_javascript:2.0.0'). Default is null. |
| isBrowserLinkTrackingEnabled | boolean | false | Default is false. If true, the SDK will track all [Browser Link](https://docs.microsoft.com/en-us/aspnet/core/client-side/using-browserlink) requests. |
| appId | string | null | AppId is used for the correlation between AJAX dependencies happening on the client-side with the server-side requests. When Beacon API is enabled, it cannot be used automatically, but can be set manually in the configuration. Default is null |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,54 @@ export class SenderTests extends AITestClass {
}
});

this.testCase({
name: 'FetchAPI is used when isBeaconApiDisabled flag is true and disableXhr flag is true , use fetch sender.',
test: () => {
let window = getGlobalInst("window");
let fakeXMLHttpRequest = (window as any).XMLHttpRequest;
let fetchstub = this.sandbox.stub((window as any), "fetch");

let sendBeaconCalled = false;
this.hookSendBeacon((url: string) => {
sendBeaconCalled = true;
return false;
});

const sender = new Sender();
const cr = new AppInsightsCore();

sender.initialize({
instrumentationKey: 'abc',
isBeaconApiDisabled: true,
disableXhr: true
}, cr, []);

const telemetryItem: ITelemetryItem = {
name: 'fake item',
iKey: 'iKey',
baseType: 'some type',
baseData: {}
};

QUnit.assert.ok(Util.IsBeaconApiSupported(), "Beacon API is supported");
QUnit.assert.equal(false, sendBeaconCalled, "Beacon API was not called before");
QUnit.assert.equal(0, this._getXhrRequests().length, "xhr sender was not called before");

try {
sender.processTelemetry(telemetryItem, null);
sender.flush();
} catch(e) {
QUnit.assert.ok(false);
}

QUnit.assert.equal(false, sendBeaconCalled, "Beacon API is disabled, Beacon API is not called");
QUnit.assert.equal(0, this._getXhrRequests().length, "xhr sender is not called");
QUnit.assert.ok(fetchstub.called, "fetch sender is called");
// store it back
(window as any).XMLHttpRequest = fakeXMLHttpRequest;
}
});

this.testCase({
name: 'FetchAPI is used when isBeaconApiDisabled flag is true and XMLHttpRequest is not supported, use fetch sender.',
test: () => {
Expand Down
Loading

0 comments on commit fcef0e0

Please sign in to comment.