satya, 12-Apr-06.
CSS SSL offloader sendRedirect problem https becomes http servlet filter HttpServletResponseWrapper
When "sendRedirect" is used, some times the relative url is being translated into an absolute url using wrong scheme (http vs https). This articles explores the problem and a possible solution using servlet filters.
The call "sendRedirect" on an "HttpServletRequest" has had a history of being iffy and very dependent on the servlet container. About 4 to 5 years ago I have seen an issue where an incoming https when redirected using "sendredirect" will become an "http". The possible variations on a sendredirect forced me to abstract out the sendredirect into a pluggable interface with three implementations.
ClientsideRedirect SendRedirect ServersideRedirect
In this strategy the target url and the parameters are sent to the browser in a response. The response includes a javasript that will take the url and redirects the browser using document.location. It also removes the current url from the browser history so that the back button will work.
Some times I call this a "defaultredirect" essentially preserving the "sendredirect" functionality where the browser is told to redirect using a redirect header.
This strategy uses a "forward" of the servlet api there by including the response as part of the original url. Although this assures the fastest response time, has the draw back of repeating a "state" change on the server if a user were to refresh the page.
Although a browser may be thinking that it is talking with its target server, there may be a number of servers enroute to the target servers doing such things as load balancing, encrypting, decrypting, etc. Usually this is not a problem. But there is case in which something called an "ssl offloader" is introduced into the pipeline of servers. These guys decode the "https" data and send the decoded data as "http" to the target server. At this point the target server thinks that the data is coming on an "http". Any sendredirect issued inside the server, especially relative urls, will be tagged with the protocol and the web server address. In this case the protocol will become "http".
Some web servers seem to deal with well, by recognizing that there is an offloader in the pipeline. This is typically done in association with the offloader where the offloader could be introducing an http header indicating that ssl offloading took place for a certain request.
Here is a symptom of this problem
first url from the browser
https://host:port/webapp/dir/page1.jsp
url by the time it reached the server
http://host:port/webapp/dir/page1.jsp
servelet redirects it to using sendredirect
/webapp/dir/page2.jsp
server sends a redirect to the browser by translating this to an absolute url
http://host:port/webapp/dir/page2.jsp
Notice how the "https" has become "http" in translating the relative url to an absolute url. This is because the webserver wrongly concluded that the incoming protocol is http.
if you are lucky and have enough time before production you can pursue with the vendor to see if they have fix for this in their web server.
Thanks to the servelet filtering architecture, it is surprisingly simple to fix it using a servelet filter. A servlet filter allows you to intercept all urls into a servlet container and alter the response related properties. The following code shows how easy it is to change the behavior of "sendredirect" for the whole web application while keeping its fundamental behavior intact.
public class AbsoluteSendRedirectFilter implements Filter
{
public void init(FilterConfig filterConfig)
throws ServletException
{
}
public void destroy()
{
}
public void doFilter(ServletRequest request
, ServletResponse response
, FilterChain chain)
throws IOException, ServletException
{
//continue the request
chain.doFilter(request,response);
}
}
<filter>
<filter-name>AbsoluteSendRedirectFilter</filter-name>
<display-name>AbsoluteSendRedirectFilter</display-name>
<description>filter for transferring relative to absolute urls</description>
<filter-class>AbsoluteSendRedirectFilter</filter-class>
<init-param>
<param-name>parm1</param-name>
<param-value>parm1value</param-value>
<description>description</description>
</init-param>
</filter>
<filter-mapping>
<filter-name>AbsoluteSendRedirectFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
class SendRedirectOverloadedResponse extends HttpServletResponseWrapper
{
private HttpServletRequest m_request;
private String prefix = null;
public SendRedirectOverloadedResponse(HttpServletRequest inRequest
, HttpServletResponse response)
{
super(response);
m_request = inRequest;
prefix = getPrefix(inRequest);
}
public void sendRedirect(String location) throws IOException
{
Log.trace("Going originally to:" + location);
String finalurl = null;
if (isUrlAbsolute(location))
{
Log.trace("This url is absolute. No scheme changes will be attempted");
finalurl = location;
}
else
{
finalurl = fixForScheme(prefix + location);
Log.trace("Going to absolute url:" + finalurl);
}
super.sendRedirect(finalurl);
}
public boolean isUrlAbsolute(String url)
{
String lowercaseurl = url.toLowerCase();
if (lowercaseurl.startsWith("http") == true)
{
return true;
}
else
{
return false;
}
}
public String fixForScheme(String url)
{
//alter the url here if you were to change the scheme
return url;
}
public String getPrefix(HttpServletRequest request)
{
StringBuffer str = request.getRequestURL();
String url = str.toString();
String uri = request.getRequestURI();
Log.trace("requesturl:" + url);
Log.trace("uri:" + uri);
int offset = url.indexOf(uri);
String prefix = url.substring(0,offset);
Log.trace("prefix:" + prefix);
return prefix;
}
}
public class AbsoluteSendRedirectFilter implements Filter
{
public void init(FilterConfig filterConfig)
throws ServletException
{
}
public void destroy()
{
}
public void doFilter(ServletRequest request
, ServletResponse response
, FilterChain chain)
throws IOException, ServletException
{
//continue the request
chain.doFilter(request
,new SendRedirectOverloadedResponse(request,response));
}
}
1. Java Server Side api ver 1.6
2. Look up just servlet package classes
>> Wednesday, April 12, 2006 1:54:49 PM - Comments by satya
What is suggested here is not a comprehensive solution. A comprehensive solution perhaps take additional things into consideration as documented below.
See some additional notes on java.net on this topic.