Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/app/core/auth/auth.effects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
throwError as observableThrow,
} from 'rxjs';

import { environment } from '../../../environments/environment';
import {
AppState,
storeModuleConfig,
Expand Down Expand Up @@ -52,6 +53,7 @@ import {
RetrieveAuthMethodsErrorAction,
RetrieveAuthMethodsSuccessAction,
RetrieveTokenAction,
SetUserAsIdleAction,
} from './auth.actions';
import { AuthEffects } from './auth.effects';
import { authReducer } from './auth.reducer';
Expand Down Expand Up @@ -107,6 +109,28 @@ describe('AuthEffects', () => {
store = TestBed.inject(Store as any);
});

describe('trackIdleness$', () => {
let emitted: any[];

beforeEach(() => {
emitted = [];
actions = of({ type: StoreActionTypes.REHYDRATE });
});

it('should set the user as idle when the timer runs out in the browser', fakeAsync(() => {
authEffects.trackIdleness$.subscribe((action) => emitted.push(action));
tick(environment.auth.ui.timeUntilIdle);
expect(emitted).toEqual([new SetUserAsIdleAction()]);
}));

it('should not start the timer on the server', fakeAsync(() => {
(authEffects as any).platformId = 'server';
authEffects.trackIdleness$.subscribe((action) => emitted.push(action));
tick(environment.auth.ui.timeUntilIdle);
expect(emitted).toEqual([]);
}));
});

describe('authenticate$', () => {
describe('when credentials are correct', () => {
it('should return a AUTHENTICATE_SUCCESS action in response to a AUTHENTICATE action', () => {
Expand Down
9 changes: 8 additions & 1 deletion src/app/core/auth/auth.effects.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { isPlatformBrowser } from '@angular/common';
import {
Inject,
Injectable,
NgZone,
PLATFORM_ID,
Type,
} from '@angular/core';
// import @ngrx
Expand Down Expand Up @@ -304,6 +307,8 @@ export class AuthEffects {
* @method trackIdleness
*/
public trackIdleness$: Observable<Action> = createEffect(() => this.actions$.pipe(
// Only in the browser: on the server this timer keeps an unfinished render in memory until it fires
filter(() => isPlatformBrowser(this.platformId)),
filter((action: Action) => !IDLE_TIMER_IGNORE_TYPES.includes(action.type)),
// Using switchMap the effect will stop subscribing to the previous timer if a new action comes
// in, and start a new timer
Expand All @@ -323,11 +328,13 @@ export class AuthEffects {
* @param {AuthorizationDataService} authorizationsService
* @param {AuthService} authService
* @param {Store} store
* @param {object} platformId
*/
constructor(private actions$: Actions,
private zone: NgZone,
private authorizationsService: AuthorizationDataService,
private authService: AuthService,
private store: Store<AppState>) {
private store: Store<AppState>,
@Inject(PLATFORM_ID) private platformId: object) {
}
}
13 changes: 13 additions & 0 deletions src/app/core/services/server-xhr.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ const agentOptions: HttpAgentOptions = {
const httpAgent = new HttpAgent(agentOptions);
const httpsAgent = new HttpsAgent(agentOptions);

// The status codes xhr2 follows on its own.
const REDIRECT_STATUSES = [301, 302, 303, 307, 308];

/**
* Constructs the XMLHttpRequest instances used for all HttpClient requests.
* Emulated by https://github.com/pwnall/node-xhr2 on the server.
Expand All @@ -43,6 +46,8 @@ const httpsAgent = new HttpsAgent(agentOptions);
* This was added to be able to perform a working XSRF request from the node server, as it needs to set a cookie for the XSRF token.
* - Override NodeJS HTTP(S) agents to keep sessions alive between requests.
* This improves SSR performance by reducing REST request overhead on the server.
* - Read and discard the body of redirect responses that xhr2 follows. Otherwise their socket stays busy
* until the REST server closes it, and keeps the SSR app that made the request in memory.
*
* Note that this must be provided in ServerAppModule;
* it doesn't work when added as a Universal engine provider.
Expand All @@ -60,6 +65,14 @@ export class ServerXhrService implements XhrFactory {
httpsAgent,
});

const onHttpResponse = (xhr as any)._onHttpResponse;
(xhr as any)._onHttpResponse = function(request, response) {
if (REDIRECT_STATUSES.includes(response.statusCode)) {
response.resume();
}
return onHttpResponse.call(this, request, response);
};

return xhr;
}
}
Loading