We also encountered this problem with GWT 2.4. To complete previous messages, we also noticed that it depends on the calling context. But when the calling context is an event handler, all browsers don't have the same behavior (we have the expected behavior on all browsers but IE any version).
It sounds like the problem comes from the fact that GWT code is in an iframe and relative path resolution is done using the calling context whereas we could expect GWT to resolve it in the main window context since the fact that code is in a iframe is hidden to user.
Here is a GWT code snippet that shows the problem:
public class IERedirectBug
implements EntryPoint
{
@Override
public void onModuleLoad()
{
final Button redirectButton = new Button("Relative Redirection");
RootPanel.get().add(redirectButton);
redirectButton.addClickHandler(new ClickHandler()
{
@Override
public void onClick(ClickEvent event)
{
// Works with all browsers but IE
Location.assign("target.html");
}
});
}
}
To investigate the problem we did several test cases in pure Javascript.
In the first case, we use a frame that is in a subfolder and that contains a function (as the GWT frame contains code) that does the main page redirection (window.parent.location.assign()). If we call this code from the main window (case #1), all browsers resolve correctly relative paths. If this code is called from the iframe (next to the function declaration, case #2), all browsers resolve the relative path according to the iframe location and not the main page location. This shows that calling context impacts relative path resolution and all browsers seem to have the same behavior (at least Google Chrome and IE 8 & 9 on which we really tested).
Main window (test.html):
<!DOCTYPE html>
<html>
<head></head>
<body>
<iframe src="folder/frame.html" id="frame"> </iframe>
<h1>main</h1>
<button>redirect</button>
</body>
</html>
Iframe (folder/frame.html):
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>test2</h1>
<script type="text/javascript">
function redirect()
{
window.parent.location.assign('target.html');
}
</script>
</body>
</html>
In case #1, we add to the button declaration in test.html the call to the redirect function:
<button onclick="document.getElementById('frame').contentWindow.redirect()">redirect</button>. This redirects to target.html on any browser, the expected behavior.
In case #2, we call the redirect function from the frame, just after its declaration:
function redirect()
{
window.parent.location.assign('target.html');
}
redirect();
It redirects to folder/target.html on any browser.
These examples simply confirm that calling context impacts relative path resolution but don't explain why IE hasn't the same behavior as other browsers in our GWT case.
So we tried to reproduce in a pure Javascript example the way GWT handles events (through the global handler), case #3. This way enabled us to reproduce the problem. For modern browsers and IE9, the standard global event handling system is used throw
$wnd.addEventListener(). For IE 8 it's a specific code (case #4). But whatever global event handling system is used,
Location.replace() and
Location.assign() don't have the expected behaviour with relative paths on IE.
In case #3, we use this code (just after redirect function declaration):
// Works on any browser but IE9
window.parent.addEventListener('click', function(e) { redirect(); }, true);
In case #4 (IE8), we use this code:
window.parent.document.body.attachEvent('onclick', function(e) { redirect(); });
Cases #3 and #4 show that with global handler, IE has the same behavior as case #2 while other browsers work as in case #1, which is the expected behavior.
Even if the problem can be solved by API users using
GWT.getModuleBaseURL(), don't you think it sould be fixed in GWT itself since it doesn't respect the GWT "execution doesn't depend on browser" principle?
I guess it could be solved by analyzing the parameter given to the assign() method. If it starts neither with a protocol (http:// for instance) nor with a slash, we can consider it's a relative path (unless I forget cases) and thus prefix it with
GWT.getModuleBaseUrl().