소스 검색

throttle calls to replaceState to fix security error when navigating quickly in Safari #3147

hakimel 3 년 전
부모
커밋
fc861fca50
1개의 변경된 파일28개의 추가작업 그리고 2개의 파일을 삭제
  1. 28 2
      js/controllers/location.js

+ 28 - 2
js/controllers/location.js

@@ -3,6 +3,10 @@
  */
 export default class Location {
 
+	// The minimum number of milliseconds that must pass between
+	// calls to history.replaceState
+	MAX_REPLACE_STATE_FREQUENCY = 250
+
 	constructor( Reveal ) {
 
 		this.Reveal = Reveal;
@@ -10,6 +14,8 @@ export default class Location {
 		// Delays updates to the URL due to a Chrome thumbnailer bug
 		this.writeURLTimeout = 0;
 
+		this.replaceStateTimestamp = 0;
+
 		this.onWindowHashChange = this.onWindowHashChange.bind( this );
 
 	}
@@ -142,10 +148,10 @@ export default class Location {
 			else if( config.hash ) {
 				// If the hash is empty, don't add it to the URL
 				if( hash === '/' ) {
-					window.history.replaceState( null, null, window.location.pathname + window.location.search );
+					this.debouncedReplaceState( window.location.pathname + window.location.search );
 				}
 				else {
-					window.history.replaceState( null, null, '#' + hash );
+					this.debouncedReplaceState( '#' + hash );
 				}
 			}
 			// UPDATE: The below nuking of all hash changes breaks
@@ -163,6 +169,26 @@ export default class Location {
 
 	}
 
+	replaceState( url ) {
+
+		window.history.replaceState( null, null, url );
+		this.replaceStateTimestamp = Date.now();
+
+	}
+
+	debouncedReplaceState( url ) {
+
+		clearTimeout( this.replaceStateTimeout );
+
+		if( Date.now() - this.replaceStateTimestamp > this.MAX_REPLACE_STATE_FREQUENCY ) {
+			this.replaceState( url );
+		}
+		else {
+			this.replaceStateTimeout = setTimeout( () => this.replaceState( url ), this.MAX_REPLACE_STATE_FREQUENCY );
+		}
+
+	}
+
 	/**
 	 * Return a hash URL that will resolve to the given slide location.
 	 *