
google-web-toolkit - issue #4817
Serializazion policy error when using via Apache proxy
Found in GWT Release: 2.0.3
Encountered on OS / Browser: Kubuntu, FF3
Shortest code snippet which demonstrates issue:
I developed a GWT application that use several remote service. I tested it locally and in a remote application server (Jetty) and it run perfect.
The issue come out when I tried to use this application, using an Apache 2.0 web server as proxy server.
In my application server the application is deployed as: http://www.myserver.com:8080/dogproject and the proxy is setted as: http://www.myserver.com
So, what I want to do is to redirect "/" path to http://www.myserver.com:8080/dogproject
I added these lines to apache configuration files:
<VirtualHost *:80> ServerAdmin my.personal@email.com ServerName www.myserver.com
ProxyRequests Off
ProxyVia Off
ProxyPreserveHost On
<Proxy *>
AddDefaultCharset off
Order deny,allow
Allow from all
</Proxy>
<Location />
Order allow,deny
Allow from all
ProxyPass http://myserver:8080/dogproject/
ProxyPassReverse http://rubi:8080/dogproject/
SetEnv proxy-nokeepalive 1
</Location>
</VirtualHost>
When I try to open the application everything work ok: images are loaded ok, css too, tue only problem is when I try to use a remote services.
Client side I get the message: 500 Internal server error Server side I get the message:
2010-04-05 01:03:40.271:INFO:/dogproject:greetServlet: ERROR: The serialization policy file '/76E1D650870848211ECADADCA565F703.gwt.rpc' was not found; did you forget to include it in this deployment? 2010-04-05 01:03:40.272:WARN:/dogproject:Exception while dispatching incoming RPC call java.lang.NullPointerException at org.mortbay.log.StdErrLog.format(StdErrLog.java:212) at org.mortbay.log.StdErrLog.warn(StdErrLog.java:130) at org.mortbay.jetty.handler.ContextHandler$SContext.log(ContextHandler.java:1423) at javax.servlet.GenericServlet.log(GenericServlet.java:277) at com.google.gwt.user.server.rpc.RemoteServiceServlet.getSerializationPolicy(RemoteServiceServlet.java:144) at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.prepareToRead(ServerSerializationStreamReader.java:445) at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:236) at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:186) at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:224) at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62) at javax.servlet.http.HttpServlet.service(HttpServlet.java:710) at javax.servlet.http.HttpServlet.service(HttpServlet.java:803) at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:390) at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765) at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418) at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114) at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) at org.mortbay.jetty.Server.handle(Server.java:326) at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938) at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755) at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218) at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404) at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409) at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
The problem, I think, is that GWT is not able to find the serialization policy file. This file is present in my war/dogproject directory, but GWT search it in war/ directory (because of Apache proxy rule).
Checking the GWT source code seem to be the problem (if it is a problem) is in file:
com.google.gwt.user.server.rpc.RemoteServiceServlet in method:
static SerializationPolicy loadSerializationPolicy(HttpServlet servlet, HttpServletRequest request, String moduleBaseURL, String strongName)
because it use
> // The request can tell you the path of the web app relative to the > // container root. > String contextPath = request.getContextPath();
this code to get the path of the serialization policy. In my case the request.getContextPath is / and he go to search on the wrong path.
The right thig, I think, it to search on serverlet instances and to don't trust on request instance.
To help you work I developed an little application that can be used to test the issue. You have to deploy it on an application server, and try to use it.
Workaround if you have one:
To move the war/dogproject/** to war/
- DogProject.tar.gz 2.94MB
Comment #1
Posted on Apr 9, 2010 by Grumpy HippoSync from internal issue tracker.
Comment #2
Posted on May 1, 2010 by Massive ElephantThank you to reply to my bug report. If it is not a bug, there is a way to set my custom "serialization policy location"?
Thank you
Comment #3
Posted on May 1, 2010 by Massive ElephantHere there is the solution I found. I extended RemoteServiceServlet to take Serialization Policy file based on Context instead than in Web URL.
Then, in my service, I extended this custom class instead of RemoteServiceServlet.
In this way, GWT application can run in Apache Proxy environment without any problem.
Thank you Michele Renda
- MyRemoteServiceServlet.java 2.24KB
Comment #4
Posted on Sep 22, 2010 by Quick CatMichele,
Thank you for the example servlet to handle this problem. However when I tried to use your approach it worked in the reverse proxy environment but not in my dev mode eclipse environment. After stepping through the code it became clear why. I decided to post my experience here for others to hopefully benefit.
I took an approach that would let me seamlessly move between my dev and prod environments.
As you did I overwrote RemoteServiceServlet but I only replaced following...
@Override
protected SerializationPolicy doGetSerializationPolicy(
HttpServletRequest request, String moduleBaseURL, String strongName) {
//get the base url from the header instead of the body this way
//apache reverse proxy with rewrite on the header can work
String moduleBaseURLHdr = request.getHeader("X-GWT-Module-Base");
if(moduleBaseURLHdr != null){
moduleBaseURL = moduleBaseURLHdr;
}
return super.doGetSerializationPolicy(request, moduleBaseURL, strongName);
}
In my apache config I added...
ProxyPass /app/ ajp://localhost:8009/App-0.0.1-SNAPSHOT/
RequestHeader edit X-GWT-Module-Base ^(.*)/app/(.*)$ $1/App-0.0.1-SNAPSHOT/$2
This approach works in all scenarios and delegates the url "mucking" to apache's proxy settings which is the approach I've always taken.
Comments on this approach are appreciated.
Comment #5
Posted on Nov 11, 2011 by Helpful Wombatkc,
Well done, and thanks for posting this. I was also experiencing this issue, and your fix worked great.
Comment #6
Posted on Jun 23, 2013 by Helpful PandaHi, I have applied your suggestion. Now I don't have error "500 call failed on server" but there is another big problem. In my login service (that extends MyRemoteServiceServlet) I set session data, i.e. user, configuration, etc. When in another service class (that extends MyRemoteServiceServlet) I try to access this session data, they are null. It seem s that session is not managed
Comment #7
Posted on Sep 24, 2013 by Happy CatTo fix the santure... problem, please follow this question: http://stackoverflow.com/questions/9486498/how-to-properly-set-jsessionid-cookie-path-behind-reverse-proxy
The trick is to use the ProxyPassReverseCookiePath and ProxyPassReverseCookieDomain properties.
Comment #8
Posted on Sep 17, 2014 by Massive KangarooHow about this code change? https://gist.github.com/BinaryMuse/476175 It won't break anything.
Status: AsDesigned