View Javadoc

    1   // ========================================================================
    2   // $Id: ProxyServlet.java 3863 2008-10-21 04:35:26Z 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
    50      protected HashSet _DontProxyHeaders = new HashSet();
    51      {
    52          _DontProxyHeaders.add("proxy-connection");
    53          _DontProxyHeaders.add("connection");
    54          _DontProxyHeaders.add("keep-alive");
    55          _DontProxyHeaders.add("transfer-encoding");
    56          _DontProxyHeaders.add("te");
    57          _DontProxyHeaders.add("trailer");
    58          _DontProxyHeaders.add("proxy-authorization");
    59          _DontProxyHeaders.add("proxy-authenticate");
    60          _DontProxyHeaders.add("upgrade");
    61      }
    62
    63      private ServletConfig config;
    64      private ServletContext context;
    65
    66      /* (non-Javadoc)
    67       * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
    68       */
    69      public void init(ServletConfig config) throws ServletException
    70      {
    71          this.config=config;
    72          this.context=config.getServletContext();
    73      }
    74
    75      /* (non-Javadoc)
    76       * @see javax.servlet.Servlet#getServletConfig()
    77       */
    78      public ServletConfig getServletConfig()
    79      {
    80          return config;
    81      }
    82
    83      /* (non-Javadoc)
    84       * @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
    85       */
    86      public void service(ServletRequest req, ServletResponse res) throws ServletException,
    87              IOException
    88      {
    89          HttpServletRequest request = (HttpServletRequest)req;
    90          HttpServletResponse response = (HttpServletResponse)res;
    91          if ("CONNECT".equalsIgnoreCase(request.getMethod()))
    92          {
    93              handleConnect(request,response);
    94          }
    95          else
    96          {
    97              String uri=request.getRequestURI();
    98              if (request.getQueryString()!=null)
    99                  uri+="?"+request.getQueryString();
    100             URL url = new URL(request.getScheme(),
    101                     		  request.getServerName(),
    102                     		  request.getServerPort(),
    103                     		  uri);
    104
    105             context.log("URL="+url);
    106
    107             URLConnection connection = url.openConnection();
    108             connection.setAllowUserInteraction(false);
    109
    110             // Set method
    111             HttpURLConnection http = null;
    112             if (connection instanceof HttpURLConnection)
    113             {
    114                 http = (HttpURLConnection)connection;
    115                 http.setRequestMethod(request.getMethod());
    116                 http.setInstanceFollowRedirects(false);
    117             }
    118
    119             // check connection header
    120             String connectionHdr = request.getHeader("Connection");
    121             if (connectionHdr!=null)
    122             {
    123                 connectionHdr=connectionHdr.toLowerCase();
    124                 if (connectionHdr.equals("keep-alive")||
    125                     connectionHdr.equals("close"))
    126                     connectionHdr=null;
    127             }
    128
    129             // copy headers
    130             boolean xForwardedFor=false;
    131             boolean hasContent=false;
    132             Enumeration enm = request.getHeaderNames();
    133             while (enm.hasMoreElements())
    134             {
    135                 // TODO could be better than this!
    136                 String hdr=(String)enm.nextElement();
    137                 String lhdr=hdr.toLowerCase();
    138
    139                 if (_DontProxyHeaders.contains(lhdr))
    140                     continue;
    141                 if (connectionHdr!=null && connectionHdr.indexOf(lhdr)>=0)
    142                     continue;
    143
    144                 if ("content-type".equals(lhdr))
    145                     hasContent=true;
    146
    147                 Enumeration vals = request.getHeaders(hdr);
    148                 while (vals.hasMoreElements())
    149                 {
    150                     String val = (String)vals.nextElement();
    151                     if (val!=null)
    152                     {
    153                         connection.addRequestProperty(hdr,val);
    154                         context.log("req "+hdr+": "+val);
    155                         xForwardedFor|="X-Forwarded-For".equalsIgnoreCase(hdr);
    156                     }
    157                 }
    158             }
    159
    160             // Proxy headers
    161             connection.setRequestProperty("Via","1.1 (jetty)");
    162             if (!xForwardedFor)
    163                 connection.addRequestProperty("X-Forwarded-For",
    164                                               request.getRemoteAddr());
    165
    166             // a little bit of cache control
    167             String cache_control = request.getHeader("Cache-Control");
    168             if (cache_control!=null &&
    169                 (cache_control.indexOf("no-cache")>=0 ||
    170                  cache_control.indexOf("no-store")>=0))
    171                 connection.setUseCaches(false);
    172
    173             // customize Connection
    174
    175             try
    176             {
    177                 connection.setDoInput(true);
    178
    179                 // do input thang!
    180                 InputStream in=request.getInputStream();
    181                 if (hasContent)
    182                 {
    183                     connection.setDoOutput(true);
    184                     IO.copy(in,connection.getOutputStream());
    185                 }
    186
    187                 // Connect
    188                 connection.connect();
    189             }
    190             catch (Exception e)
    191             {
    192                 context.log("proxy",e);
    193             }
    194
    195             InputStream proxy_in = null;
    196
    197             // handler status codes etc.
    198             int code=500;
    199             if (http!=null)
    200             {
    201                 proxy_in = http.getErrorStream();
    202
    203                 code=http.getResponseCode();
    204                 response.setStatus(code, http.getResponseMessage());
    205                 context.log("response = "+http.getResponseCode());
    206             }
    207
    208             if (proxy_in==null)
    209             {
    210                 try {proxy_in=connection.getInputStream();}
    211                 catch (Exception e)
    212                 {
    213                     context.log("stream",e);
    214                     proxy_in = http.getErrorStream();
    215                 }
    216             }
    217
    218             // clear response defaults.
    219             response.setHeader("Date",null);
    220             response.setHeader("Server",null);
    221
    222             // set response headers
    223             int h=0;
    224             String hdr=connection.getHeaderFieldKey(h);
    225             String val=connection.getHeaderField(h);
    226             while(hdr!=null || val!=null)
    227             {
    228                 String lhdr = hdr!=null?hdr.toLowerCase():null;
    229                 if (hdr!=null && val!=null && !_DontProxyHeaders.contains(lhdr))
    230                     response.addHeader(hdr,val);
    231
    232                 context.log("res "+hdr+": "+val);
    233
    234                 h++;
    235                 hdr=connection.getHeaderFieldKey(h);
    236                 val=connection.getHeaderField(h);
    237             }
    238             response.addHeader("Via","1.1 (jetty)");
    239
    240             // Handle
    241             if (proxy_in!=null)
    242                 IO.copy(proxy_in,response.getOutputStream());
    243
    244         }
    245     }
    246
    247
    248     /* ------------------------------------------------------------ */
    249     public void handleConnect(HttpServletRequest request,
    250                               HttpServletResponse response)
    251         throws IOException
    252     {
    253         String uri = request.getRequestURI();
    254
    255         context.log("CONNECT: "+uri);
    256
    257         String port = "";
    258         String host = "";
    259
    260         int c = uri.indexOf(':');
    261         if (c>=0)
    262         {
    263             port = uri.substring(c+1);
    264             host = uri.substring(0,c);
    265             if (host.indexOf('/')>0)
    266                 host = host.substring(host.indexOf('/')+1);
    267         }
    268
    269
    270
    271
    272         InetSocketAddress inetAddress = new InetSocketAddress (host, Integer.parseInt(port));
    273
    274         //if (isForbidden(HttpMessage.__SSL_SCHEME,addrPort.getHost(),addrPort.getPort(),false))
    275         //{
    276         //    sendForbid(request,response,uri);
    277         //}
    278         //else
    279         {
    280             InputStream in=request.getInputStream();
    281             OutputStream out=response.getOutputStream();
    282
    283             Socket socket = new Socket(inetAddress.getAddress(),inetAddress.getPort());
    284             context.log("Socket: "+socket);
    285
    286             response.setStatus(200);
    287             response.setHeader("Connection","close");
    288             response.flushBuffer();
    289
    290
    291
    292             context.log("out<-in");
    293             IO.copyThread(socket.getInputStream(),out);
    294             context.log("in->out");
    295             IO.copy(in,socket.getOutputStream());
    296         }
    297     }
    298
    299
    300
    301
    302     /* (non-Javadoc)
    303      * @see javax.servlet.Servlet#getServletInfo()
    304      */
    305     public String getServletInfo()
    306     {
    307         return "Proxy Servlet";
    308     }
    309
    310     /* (non-Javadoc)
    311      * @see javax.servlet.Servlet#destroy()
    312      */
    313     public void destroy()
    314     {
    315
    316     }
    317 }