1

I have a GWT webapp running fine -- unless I put it behind a Marathon-LB load-balancer and use HTTPS.

The failure happened around a POST.

  • When the webapp is not behind Marathon-LB, the POST would get a 200 OK.
  • But when it is behind Marathon-LB, there would be an internal server error of GWT SerializationException, and the POST would get a 500 error.

For the failure case, the stacktrace in tomcat's server log is this. Note that the thread is https-jsse-nio-8080-exec-6

01-Feb-2018 18:43:39.863 SEVERE [https-jsse-nio-8080-exec-6] org.apache.catalina.core.ApplicationContext.log Exception while dispatching incoming RPC call
com.google.gwt.user.client.rpc.SerializationException: Type 'com.company.SomeGwtSerializableClass' was not assignable to 'com.google.gwt.user.client.rpc.IsSerializ
able' and did not have a custom field serializer.For security purposes, this type will not be serialized.: instance = com.company.SomeGwtSerializableClass@6ce9a6c9
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:667)
        at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeObject(AbstractSerializationStreamWriter.java:130)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter$ValueWriter$8.write(ServerSerializationStreamWriter.java:153)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeValue(ServerSerializationStreamWriter.java:587)

I suspect the problem is with the certificates of trust between the docker container running Marathon-LB and the docker container running a Tomcat serving the webapp.

Any suggestion on how to debug this? For example, how do I know for sure that the Marathon-LB container is trusting the webapp container?

Thanks!

leeyuiwah
  • 6,562
  • 8
  • 41
  • 71

2 Answers2

1

Two possible ways (at least) that a load balancer could break GWT-RPC that should work otherwise:

  • Serve the wrong content: This could happen in a few ways, such as if the load balancer cached something, or one of the servers behind it was serving out of date files and then that client was made to connect to an up to date server.
  • Mangle incoming calls: There are several ways that a load balancer might make a mistake or "help" and break something - dropping headers, rewriting the moduleBaseUrl in the request to something else, etc.

Either way, most of these cases involve failing to find the correct Serialization Policy file (the .gwt.rpc file in your compiled output), which in turn is caused by some error in the com.google.gwt.user.server.rpc.RemoteServiceServlet#loadSerializationPolicy method. As far as I can tell, all of those errors should result in some error being logged also, though it might be to a different file. Perhaps check other server log files to see if something went wrong, or attach and debug that method while behind a load balancer and ensure that it returns an actual policy when the error you are seeing takes place. Also keep in mind that these policy files are cached, so the error will only happen once until you restart the server webapp.

Colin Alworth
  • 17,801
  • 2
  • 26
  • 39
0

I think your problem is RPC-specific.

As part of some sort of validation / protection, RPC attempts server side, to load those serialization policies via getServletContext().getResourceAsStream

/*
 * Check that the module path must be in the same web app as the servlet
 * itself. If you need to implement a scheme different than this, override
 * this method.
 */
if (modulePath == null || !modulePath.startsWith(contextPath)) {
  String message = "ERROR: The module path requested, "
      + modulePath
      + ", is not in the same web application as this servlet, "
      + contextPath
      + ".  Your module may not be properly configured or your client and server code maybe out of date.";
  servlet.log(message);
} else {
  // Strip off the context path from the module base URL. It should be a
  // strict prefix.
  String contextRelativePath = modulePath.substring(contextPath.length());

  String serializationPolicyFilePath = SerializationPolicyLoader.getSerializationPolicyFileName(contextRelativePath
      + strongName);

  // Open the RPC resource file and read its contents.
  InputStream is = servlet.getServletContext().getResourceAsStream(
      serializationPolicyFilePath);

You can see this in action here:

https://github.com/stephenh/gwt/blob/master/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java

The problem with the above thing is that serializationPolicyFilePath is built based on a client-side path. So therefore, if your client path and server path differ, you will have trouble.

I had so much trouble in this respect, that I ended up overwriting stuff through RemoteServiceServlet in order to be able to load the policy files from a different location.

Edit1: Added missing extra code line; Also forgot to mention that the problem can be either in the getResourcesAsStream call, OR in !modulePath.startsWith(contextPath) comparison.

Andrei
  • 1,613
  • 3
  • 16
  • 36