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