Skip to content

Commit

Permalink
BUG Don't double unescape URLs in history.js (fixes #8170)
Browse files Browse the repository at this point in the history
Merged in pull request browserstate/history.js#108.
This has been a serious problem with the library for more than a year,
see browserstate/history.js#228.
  • Loading branch information
chillu committed Jan 15, 2013
1 parent dadd9e1 commit 64d3a3d
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 54 deletions.
41 changes: 33 additions & 8 deletions admin/thirdparty/history-js/scripts/uncompressed/history.html4.js
Expand Up @@ -78,6 +78,19 @@
return isLast;
};

/**
* History.isHashEqual(newHash, oldHash)
* Checks to see if two hashes are functionally equal
* @param {string} newHash
* @param {string} oldHash
* @return {boolean} true
*/
History.isHashEqual = function(newHash, oldHash){
newHash = encodeURIComponent(newHash).replace(/%25/g, "%");
oldHash = encodeURIComponent(oldHash).replace(/%25/g, "%");
return newHash === oldHash;
};

/**
* History.saveHash(newHash)
* Push a Hash
Expand Down Expand Up @@ -300,8 +313,9 @@
checkerRunning = true;

// Fetch
var documentHash = History.getHash()||'',
iframeHash = History.unescapeHash(iframe.contentWindow.document.location.hash)||'';
var
documentHash = History.getHash(),
iframeHash = History.getHash(iframe.contentWindow.document.location);

// The Document Hash has changed (application caused)
if ( documentHash !== lastDocumentHash ) {
Expand Down Expand Up @@ -398,7 +412,7 @@
//History.debug('History.onHashChange', arguments);

// Prepare
var currentUrl = ((event && event.newURL) || document.location.href),
var currentUrl = ((event && event.newURL) || History.getLocationHref()),
currentHash = History.getHashByUrl(currentUrl),
currentState = null,
currentStateHash = null,
Expand Down Expand Up @@ -429,9 +443,10 @@
}

// Create State

// MODIFIED ischommer: URL normalization needs to respect our <base> tag,
// otherwise will go into infinite loops
currentState = History.extractState(History.getFullUrl(currentHash||document.location.href,true),true);
currentState = History.extractState(History.getFullUrl(currentHash||History.getLocationHref(),true),true);
// END MODIFIED

// Check if we are the same state
Expand Down Expand Up @@ -463,7 +478,7 @@

// Push the new HTML5 State
//History.debug('History.onHashChange: success hashchange');
History.pushState(currentState.data,currentState.title,currentState.url,false);
History.pushState(currentState.data,currentState.title,encodeURI(currentState.url),false);

// End onHashChange closure
return true;
Expand All @@ -482,6 +497,11 @@
History.pushState = function(data,title,url,queue){
//History.debug('History.pushState: called', arguments);

// We assume that the URL passed in is URI-encoded, but this makes
// sure that it's fully URI encoded; any '%'s that are encoded are
// converted back into '%'s
url = encodeURI(url).replace(/%25/g, "%");

// Check the State
if ( History.getHashByUrl(url) ) {
throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
Expand Down Expand Up @@ -528,7 +548,7 @@
}

// Update HTML4 Hash
if ( newStateHash !== html4Hash && newStateHash !== History.getShortUrl(document.location.href) ) {
if ( !History.isHashEqual(newStateHash, html4Hash) && !History.isHashEqual(newStateHash, History.getShortUrl(History.getLocationHref())) ) {
//History.debug('History.pushState: update hash', newStateHash, html4Hash);
History.setHash(newStateHash,false);
return false;
Expand Down Expand Up @@ -558,9 +578,14 @@
History.replaceState = function(data,title,url,queue){
//History.debug('History.replaceState: called', arguments);

// We assume that the URL passed in is URI-encoded, but this makes
// sure that it's fully URI encoded; any '%'s that are encoded are
// converted back into '%'s
url = encodeURI(url).replace(/%25/g, "%");

// Check the State
if ( History.getHashByUrl(url) ) {
throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
throw new Error('History.js does not support states with fragment-identifiers (hashes/anchors).');
}

// Handle Queueing
Expand Down Expand Up @@ -621,4 +646,4 @@
History.init();
}

})(window);
})(window);
98 changes: 52 additions & 46 deletions admin/thirdparty/history-js/scripts/uncompressed/history.js
Expand Up @@ -416,7 +416,7 @@
// Fetch
var
State = History.getState(false,false),
stateUrl = (State||{}).url||document.location.href,
stateUrl = (State||{}).url||History.getLocationHref(),
pageUrl;

// Create
Expand All @@ -435,7 +435,7 @@
*/
History.getBasePageUrl = function(){
// Create
var basePageUrl = document.location.href.replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){
var basePageUrl = (History.getLocationHref()).replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){
return (/[^\/]$/).test(part) ? '' : part;
}).replace(/\/+$/,'')+'/';

Expand Down Expand Up @@ -522,6 +522,36 @@
return shortUrl;
};

/**
* History.getLocationHref(document)
* Returns a normalized version of document.location.href
* accounting for browser inconsistencies, etc.
*
* This URL will be URI-encoded and will include the hash
*
* @param {object} document
* @return {string} url
*/
History.getLocationHref = function(doc) {
doc = doc || document;

// most of the time, this will be true
if (doc.URL === doc.location.href)
return doc.location.href;

// some versions of webkit URI-decode document.location.href
// but they leave document.URL in an encoded state
if (doc.location.href === decodeURIComponent(doc.URL))
return doc.URL;

// FF 3.6 only updates document.URL when a page is reloaded
// document.location.href is updated correctly
if (doc.location.hash && decodeURIComponent(doc.location.href.replace(/^[^#]+/, "")) === doc.location.hash)
return doc.location.href;

return doc.URL || doc.location.href;
};


// ====================================================================
// State Storage
Expand Down Expand Up @@ -673,7 +703,7 @@
newState = {};
newState.normalized = true;
newState.title = oldState.title||'';
newState.url = History.getFullUrl(History.unescapeString(oldState.url||document.location.href));
newState.url = History.getFullUrl(oldState.url?decodeURIComponent(oldState.url):(History.getLocationHref()));
newState.hash = History.getShortUrl(newState.url);
newState.data = History.cloneObject(oldState.data);

Expand Down Expand Up @@ -728,7 +758,7 @@
var State = {
'data': data,
'title': title,
'url': url
'url': encodeURIComponent(url||"")
};

// Expand the State
Expand Down Expand Up @@ -1035,36 +1065,15 @@

/**
* History.getHash()
* @param {Location=} location
* Gets the current document hash
* Note: unlike location.hash, this is guaranteed to return the escaped hash in all browsers
* @return {string}
*/
History.getHash = function(){
var hash = History.unescapeHash(document.location.hash);
return hash;
};

/**
* History.unescapeString()
* Unescape a string
* @param {String} str
* @return {string}
*/
History.unescapeString = function(str){
// Prepare
var result = str,
tmp;

// Unescape hash
while ( true ) {
tmp = window.unescape(result);
if ( tmp === result ) {
break;
}
result = tmp;
}

// Return result
return result;
History.getHash = function(location){
if ( !location ) location = document.location;
var href = location.href.replace( /^[^#]*/, "" );
return href.substr(1);
};

/**
Expand All @@ -1078,7 +1087,7 @@
var result = History.normalizeHash(hash);

// Unescape hash
result = History.unescapeString(result);
result = decodeURIComponent(result);

// Return result
return result;
Expand All @@ -1105,7 +1114,7 @@
*/
History.setHash = function(hash,queue){
// Prepare
var adjustedHash, State, pageUrl;
var State, pageUrl;

// Handle Queueing
if ( queue !== false && History.busy() ) {
Expand All @@ -1123,9 +1132,6 @@
// Log
//History.debug('History.setHash: called',hash);

// Prepare
adjustedHash = History.escapeHash(hash);

// Make Busy + Continue
History.busy(true);

Expand All @@ -1138,7 +1144,7 @@
// PushState
History.pushState(State.data,State.title,State.url,false);
}
else if ( document.location.hash !== adjustedHash ) {
else if ( History.getHash() !== hash ) {
// Hash is a proper hash, so apply it

// Handle browser bugs
Expand All @@ -1149,11 +1155,11 @@
pageUrl = History.getPageUrl();

// Safari hash apply
History.pushState(null,null,pageUrl+'#'+adjustedHash,false);
History.pushState(null,null,pageUrl+'#'+hash,false);
}
else {
// Normal hash apply
document.location.hash = adjustedHash;
document.location.hash = hash;
}
}

Expand All @@ -1171,7 +1177,7 @@
var result = History.normalizeHash(hash);

// Escape hash
result = window.escape(result);
result = window.encodeURIComponent(result);

// IE6 Escape Bug
if ( !History.bugs.hashEscape ) {
Expand Down Expand Up @@ -1446,7 +1452,7 @@

// Get the Last State which has the new URL
var
urlState = History.extractState(document.location.href),
urlState = History.extractState(History.getLocationHref()),
newState;

// Check for a difference
Expand Down Expand Up @@ -1617,7 +1623,7 @@
currentHash = History.getHash();
if ( currentHash ) {
// Expand Hash
currentState = History.extractState(currentHash||document.location.href,true);
currentState = History.extractState(currentHash||History.getLocationHref(),true);
if ( currentState ) {
// We were able to parse it, it must be a State!
// Let's forward to replaceState
Expand Down Expand Up @@ -1650,13 +1656,13 @@
}
else {
// Initial State
newState = History.extractState(document.location.href);
newState = History.extractState(History.getLocationHref());
}

// The State did not exist in our store
if ( !newState ) {
// Regenerate the State
newState = History.createStateObject(null,null,document.location.href);
newState = History.createStateObject(null,null,History.getLocationHref());
}

// Clean
Expand Down Expand Up @@ -1836,7 +1842,7 @@
/**
* Create the initial State
*/
History.saveState(History.storeState(History.extractState(document.location.href,true)));
History.saveState(History.storeState(History.extractState(History.getLocationHref(),true)));

/**
* Bind for Saving Store
Expand Down Expand Up @@ -1940,4 +1946,4 @@
// Try and Initialise History
History.init();

})(window);
})(window);

0 comments on commit 64d3a3d

Please sign in to comment.