I've seen a few posts on this, but no real solutions - so here goes...
My solution to this is to write a dummy servlet which you load into the
dev shell (using the <servlet> bit in gwt.xml - this proxies all the
requests on to the real RPC servlet. Here it is:
package CHANGE.THIS.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class ProxyPassServlet extends HttpServlet {
static final String REAL_URL =
"http://localhost:8085/CHANGE/THISSERVICE";
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse
resp) throws ServletException, IOException {
// open up the real URL
URL url=new URL(REAL_URL);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setDoOutput(true);
// write the incoming headers to the real URL
Enumeration e = req.getHeaderNames();
while(e.hasMoreElements()) {
String a = (String)e.nextElement();
conn.setRequestProperty(a,req.getHeader(a));
}
// write the incoming request
int len;
byte b[] = new byte[1000];
InputStream is = req.getInputStream();
OutputStream os = conn.getOutputStream();
while( (len = is.read(b,0,1000)) > 0 ) {
os.write(b,0,len);
}
is.close();
os.close();
// write the output back to the caller, and we're done!
is = conn.getInputStream();
os = resp.getOutputStream();
while( (len = is.read(b,0,1000)) > 0 ) {
os.write(b,0,len);
}
is.close();
os.close();
}
}
We're using the HttpUnit package for our proxy servlet solution. The
WebConversation class,
http://httpunit.sourceforge.net/doc/api/com/meterware/httpunit/WebConversation.html
simulates a web client, from the documentation:
"This class manages cookies used to maintain session context"
Since we're going to have users that are logged in, we depend on a
robust session handling. Would your code also handle sessions? If so, I
would like to switch (and not have to depend on the HttpUnit JAR-files
in the server...)
Thanks for sharing your code,
Björn
For those that need more background on this whole proxying issue, this
page explains the concepts:
http://ajaxpatterns.org/Cross-Domain_Proxy
I think all that is needed is to copy the headers back...
String headerKey, headerValue;
int index = 0;
do {
headerKey = conn.getHeaderFieldKey(index);
headerValue = conn.getHeaderField(index);
System.out.println("copying back header:"+headerKey);
if( headerKey != null && headerValue != null ) {
resp.setHeader(headerKey,headerValue);
index++;
}
} while(headerKey != null && headerValue != null);
or something like that. I don't see any cookies going too and fro
though! but I don't think the GWT RPC uses them - if you're pulling XML
docs back, YMMV.
I'd be interested to see how you are managing sessions - I was thinking
about generating my own session token & passing it in/out with the RPC
calls.
Anyone know if the GWTRPC works over HTTPS OK ?
Note that I've ended up rewriting the Path bit in the set-cookie.
You can get at the persisted stuff from the session in the RPC call
using
public String testMethod(String s) {
String thing =
(String)getThreadLocalRequest().getSession().getAttribute("hat");
System.out.println("got:"+thing);
getThreadLocalRequest().getSession().setAttribute("hat",thing+"+fish");
return "fish:"+s;
}
And it appears to work.
Heres the proxy:
package CHANGE.THIS.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class ProxyPassServlet extends HttpServlet {
static final String REAL_URL = "http://HOST:PORT/APP/XXXService";
static final String REWRITE_COOKIE_PATH_FROM = "Path=/APP";
static final String REWRITE_COOKIE_PATH_TO = "";
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse
resp) throws ServletException, IOException {
// open up the real URL
URL url=new URL(REAL_URL);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setDoOutput(true);
// write the incoming headers to the real URL
Enumeration e = req.getHeaderNames();
while(e.hasMoreElements()) {
String a = (String)e.nextElement();
conn.addRequestProperty(a,req.getHeader(a));
System.out.println("adding header:"+a);
}
// write the incoming request
int len;
byte b[] = new byte[1000];
InputStream is = req.getInputStream();
OutputStream os = conn.getOutputStream();
while( (len = is.read(b,0,1000)) > 0 ) {
os.write(b,0,len);
}
is.close();
os.close();
// copy cookies back
is = conn.getInputStream();
Map<String,List<String>> m = conn.getHeaderFields();
if( m == null ) {
System.out.println("m is null");
} else {
for( String key : m.keySet() ) {
if( key != null ) {
List<String> values = m.get(key);
for( String value : values ) {
if( key.equals("Set-Cookie")) {
value=value.replace(REWRITE_COOKIE_PATH_FROM,REWRITE_COOKIE_PATH_TO);
}
System.out.println("copying back header:"+key+"="+value);
resp.addHeader(key,value);
}
}
}
}
// write the output back to the caller, and we're done!