Java Source Code: org.mortbay.servlet.ProxyServlet


   1: // ========================================================================
   2: // $Id: ProxyServlet.java 800 2006-08-20 00:01:46Z gregw $
   3: // Copyright 2004-2004 Mort Bay Consulting Pty. Ltd.
   4: // ------------------------------------------------------------------------
   5: // Licensed under the Apache License, Version 2.0 (the "License");
   6: // you may not use this file except in compliance with the License.
   7: // You may obtain a copy of the License at 
   8: // http://www.apache.org/licenses/LICENSE-2.0
   9: // Unless required by applicable law or agreed to in writing, software
  10: // distributed under the License is distributed on an "AS IS" BASIS,
  11: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12: // See the License for the specific language governing permissions and
  13: // limitations under the License.
  14: // ========================================================================
  15: 
  16: package org.mortbay.servlet;
  17: 
  18: import java.io.IOException;
  19: import java.io.InputStream;
  20: import java.io.OutputStream;
  21: import java.net.HttpURLConnection;
  22: import java.net.InetSocketAddress;
  23: import java.net.Socket;
  24: import java.net.URL;
  25: import java.net.URLConnection;
  26: import java.util.Enumeration;
  27: import java.util.HashSet;
  28: 
  29: import javax.servlet.Servlet;
  30: import javax.servlet.ServletConfig;
  31: import javax.servlet.ServletContext;
  32: import javax.servlet.ServletException;
  33: import javax.servlet.ServletRequest;
  34: import javax.servlet.ServletResponse;
  35: import javax.servlet.http.HttpServletRequest;
  36: import javax.servlet.http.HttpServletResponse;
  37: 
  38: import org.mortbay.util.IO;
  39: 
  40: 
  41: 
  42: /**
  43:  * EXPERIMENTAL Proxy servlet.
  44:  * @author gregw
  45:  *
  46:  */
  47: public class ProxyServlet implements Servlet
  48:	  {
  49:    private int _tunnelTimeoutMs=300000;
  50:    
  51:    protected HashSet _DontProxyHeaders = new HashSet();
  52:	      {
  53:        _DontProxyHeaders.add("proxy-connection");
  54:        _DontProxyHeaders.add("connection");
  55:        _DontProxyHeaders.add("keep-alive");
  56:        _DontProxyHeaders.add("transfer-encoding");
  57:        _DontProxyHeaders.add("te");
  58:        _DontProxyHeaders.add("trailer");
  59:        _DontProxyHeaders.add("proxy-authorization");
  60:        _DontProxyHeaders.add("proxy-authenticate");
  61:        _DontProxyHeaders.add("upgrade");
  62:    }
  63:    
  64:    private ServletConfig config;
  65:    private ServletContext context;
  66:    
  67:    /* (non-Javadoc)
  68:     * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
  69:     */
  70:    public void init(ServletConfig config) throws ServletException
  71:	      {
  72:        this.config=config;
  73:        this.context=config.getServletContext();
  74:    }
  75:
  76:    /* (non-Javadoc)
  77:     * @see javax.servlet.Servlet#getServletConfig()
  78:     */
  79:    public ServletConfig getServletConfig()
  80:	      {
  81:        return config;
  82:    }
  83:
  84:    /* (non-Javadoc)
  85:     * @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
  86:     */
  87:    public void service(ServletRequest req, ServletResponse res) throws ServletException,
  88:            IOException
  89:	      {
  90:        HttpServletRequest request = (HttpServletRequest)req;
  91:        HttpServletResponse response = (HttpServletResponse)res;
  92:        if ("CONNECT".equalsIgnoreCase(request.getMethod()))
  93:	          {
  94:            handleConnect(request,response);
  95:        }
  96:        else
  97:	          {
  98:            String uri=request.getRequestURI();
  99:            if (request.getQueryString()!=null)
 100:                uri+="?"+request.getQueryString();
 101:            URL url = new URL(request.getScheme(),
 102:                              request.getServerName(),
 103:                              request.getServerPort(),
 104:                              uri);
 105:            
 106:            context.log("URL="+url);
 107:
 108:            URLConnection connection = url.openConnection();
 109:            connection.setAllowUserInteraction(false);
 110:            
 111:            // Set method
 112:            HttpURLConnection http = null;
 113:            if (connection instanceof HttpURLConnection)
 114:	              {
 115:                http = (HttpURLConnection)connection;
 116:                http.setRequestMethod(request.getMethod());
 117:                http.setInstanceFollowRedirects(false);
 118:            }
 119:
 120:            // check connection header
 121:            String connectionHdr = request.getHeader("Connection");
 122:            if (connectionHdr!=null)
 123:	              {
 124:                connectionHdr=connectionHdr.toLowerCase();
 125:                if (connectionHdr.equals("keep-alive")||
 126:                    connectionHdr.equals("close"))
 127:                    connectionHdr=null;
 128:            }
 129:            
 130:            // copy headers
 131:            boolean xForwardedFor=false;
 132:            boolean hasContent=false;
 133:            Enumeration enm = request.getHeaderNames();
 134:            while (enm.hasMoreElements())
 135:	              {
 136:                // TODO could be better than this!
 137:                String hdr=(String)enm.nextElement();
 138:                String lhdr=hdr.toLowerCase();
 139:
 140:                if (_DontProxyHeaders.contains(lhdr))
 141:                    continue;
 142:                if (connectionHdr!=null && connectionHdr.indexOf(lhdr)>=0)
 143:                    continue;
 144:
 145:                if ("content-type".equals(lhdr))
 146:                    hasContent=true;
 147:
 148:                Enumeration vals = request.getHeaders(hdr);
 149:                while (vals.hasMoreElements())
 150:	                  {
 151:                    String val = (String)vals.nextElement();
 152:                    if (val!=null)
 153:	                      {
 154:                        connection.addRequestProperty(hdr,val);
 155:                        context.log("req "+hdr+": "+val);
 156:                        xForwardedFor|="X-Forwarded-For".equalsIgnoreCase(hdr);
 157:                    }
 158:                }
 159:            }
 160:
 161:            // Proxy headers
 162:            connection.setRequestProperty("Via","1.1 (jetty)");
 163:            if (!xForwardedFor)
 164:                connection.addRequestProperty("X-Forwarded-For",
 165:                                              request.getRemoteAddr());
 166:
 167:            // a little bit of cache control
 168:            String cache_control = request.getHeader("Cache-Control");
 169:            if (cache_control!=null &&
 170:                (cache_control.indexOf("no-cache")>=0 ||
 171:                 cache_control.indexOf("no-store")>=0))
 172:                connection.setUseCaches(false);
 173:
 174:            // customize Connection
 175:            
 176:            try
 177:	              {    
 178:                connection.setDoInput(true);
 179:                
 180:                // do input thang!
 181:                InputStream in=request.getInputStream();
 182:                if (hasContent)
 183:	                  {
 184:                    connection.setDoOutput(true);
 185:                    IO.copy(in,connection.getOutputStream());
 186:                }
 187:                
 188:                // Connect                
 189:                connection.connect();    
 190:            }
 191:            catch (Exception e)
 192:	              {
 193:                context.log("proxy",e);
 194:            }
 195:            
 196:            InputStream proxy_in = null;
 197:
 198:            // handler status codes etc.
 199:            int code=500;
 200:            if (http!=null)
 201:	              {
 202:                proxy_in = http.getErrorStream();
 203:                
 204:                code=http.getResponseCode();
 205:                response.setStatus(code, http.getResponseMessage());
 206:                context.log("response = "+http.getResponseCode());
 207:            }
 208:            
 209:            if (proxy_in==null)
 210:	              {
 211:                try {proxy_in=connection.getInputStream();}
 212:                catch (Exception e)
 213:	                  {
 214:                    context.log("stream",e);
 215:                    proxy_in = http.getErrorStream();
 216:                }
 217:            }
 218:            
 219:            // clear response defaults.
 220:            response.setHeader("Date",null);
 221:            response.setHeader("Server",null);
 222:            
 223:            // set response headers
 224:            int h=0;
 225:            String hdr=connection.getHeaderFieldKey(h);
 226:            String val=connection.getHeaderField(h);
 227:            while(hdr!=null || val!=null)
 228:	              {
 229:                String lhdr = hdr!=null?hdr.toLowerCase():null;
 230:                if (hdr!=null && val!=null && !_DontProxyHeaders.contains(lhdr))
 231:                    response.addHeader(hdr,val);
 232:
 233:                context.log("res "+hdr+": "+val);
 234:                
 235:                h++;
 236:                hdr=connection.getHeaderFieldKey(h);
 237:                val=connection.getHeaderField(h);
 238:            }
 239:            response.addHeader("Via","1.1 (jetty)");
 240:
 241:            // Handle
 242:            if (proxy_in!=null)
 243:                IO.copy(proxy_in,response.getOutputStream());
 244:            
 245:        }
 246:    }
 247:
 248:
 249:    /* ------------------------------------------------------------ */
 250:    public void handleConnect(HttpServletRequest request,
 251:                              HttpServletResponse response)
 252:        throws IOException
 253:	      {
 254:        String uri = request.getRequestURI();
 255:        
 256:        context.log("CONNECT: "+uri);
 257:        
 258:        String port = "";
 259:        String host = "";
 260:        
 261:        int c = uri.indexOf(':');
 262:        if (c>=0)
 263:	          {
 264:            port = uri.substring(c+1);
 265:            host = uri.substring(0,c);
 266:            if (host.indexOf('/')>0)
 267:                host = host.substring(host.indexOf('/')+1);
 268:        }
 269:
 270:        
 271:       
 272:
 273:        InetSocketAddress inetAddress = new InetSocketAddress (host, Integer.parseInt(port));
 274:        
 275:        //if (isForbidden(HttpMessage.__SSL_SCHEME,addrPort.getHost(),addrPort.getPort(),false))
 276:	          //{
 277:        //    sendForbid(request,response,uri);
 278:        //}
 279:        //else
 280:	          {
 281:            InputStream in=request.getInputStream();
 282:            OutputStream out=response.getOutputStream();
 283:            
 284:            Socket socket = new Socket(inetAddress.getAddress(),inetAddress.getPort());
 285:            context.log("Socket: "+socket);
 286:            
 287:            response.setStatus(200);
 288:            response.setHeader("Connection","close");
 289:            response.flushBuffer();
 290:            
 291:            
 292:
 293:            context.log("out<-in");
 294:            IO.copyThread(socket.getInputStream(),out);
 295:            context.log("in->out");
 296:            IO.copy(in,socket.getOutputStream());
 297:        }
 298:    }
 299:    
 300:    
 301:    
 302:    
 303:    /* (non-Javadoc)
 304:     * @see javax.servlet.Servlet#getServletInfo()
 305:     */
 306:    public String getServletInfo()
 307:	      {
 308:        return "Proxy Servlet";
 309:    }
 310:
 311:    /* (non-Javadoc)
 312:     * @see javax.servlet.Servlet#destroy()
 313:     */
 314:    public void destroy()
 315:	      {
 316:
 317:    }
 318:}