View Javadoc
1   package org.apache.maven.it;
2   
3   import com.google.common.io.ByteStreams;
4   import org.eclipse.jetty.security.ConstraintMapping;
5   import org.eclipse.jetty.security.ConstraintSecurityHandler;
6   import org.eclipse.jetty.security.HashLoginService;
7   import org.eclipse.jetty.security.authentication.BasicAuthenticator;
8   import org.eclipse.jetty.server.Connector;
9   import org.eclipse.jetty.server.NetworkConnector;
10  import org.eclipse.jetty.server.Request;
11  import org.eclipse.jetty.server.Server;
12  import org.eclipse.jetty.server.ServerConnector;
13  import org.eclipse.jetty.server.handler.AbstractHandler;
14  import org.eclipse.jetty.util.security.Constraint;
15  import org.eclipse.jetty.util.security.Password;
16  import org.eclipse.jetty.util.thread.QueuedThreadPool;
17  import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
18  
19  import javax.servlet.ServletException;
20  import javax.servlet.http.HttpServletRequest;
21  import javax.servlet.http.HttpServletResponse;
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.net.URL;
28  import java.util.Collections;
29  
30  /**
31   * An HTTP server that handles all requests on a given port from a specified source, optionally secured using BASIC auth
32   * by providing a username and password. The source can either be a URL or a directory. When a request is made the
33   * request is satisfied from the provided source.
34   *
35   * @author Jason van Zyl
36   */
37  public class HttpServer
38  {
39  
40      private final Server server;
41  
42      private final StreamSource source;
43  
44      private final String username;
45  
46      private final String password;
47  
48      public HttpServer( int port, String username, String password, StreamSource source )
49      {
50          this.username = username;
51          this.password = password;
52          this.source = source;
53          this.server = server( port );
54      }
55  
56      public void start()
57          throws Exception
58      {
59          server.start();
60          // server.join();
61      }
62  
63      public void stop()
64          throws Exception
65      {
66          server.stop();
67      }
68  
69      public int port()
70      {
71          return ( (NetworkConnector) server.getConnectors()[0] ).getLocalPort();
72      }
73  
74      private Server server( int port )
75      {
76          QueuedThreadPool threadPool = new QueuedThreadPool();
77          threadPool.setMaxThreads( 500 );
78          Server server = new Server( threadPool );
79          server.setConnectors( new Connector[]{ new ServerConnector( server ) } );
80          server.addBean( new ScheduledExecutorScheduler() );
81  
82          ServerConnector connector = (ServerConnector) server.getConnectors()[0];
83          connector.setIdleTimeout( 30_000L );
84          connector.setPort( port );
85  
86          StreamSourceHandler handler = new StreamSourceHandler( source );
87  
88          if ( username != null && password != null )
89          {
90              HashLoginService loginService = new HashLoginService( "Test Server" );
91              loginService.putUser( username, new Password( password ), new String[]{ "user" } );
92              server.addBean( loginService );
93  
94              ConstraintSecurityHandler security = new ConstraintSecurityHandler();
95              server.setHandler( security );
96  
97              Constraint constraint = new Constraint();
98              constraint.setName( "auth" );
99              constraint.setAuthenticate( true );
100             constraint.setRoles( new String[]{ "user", "admin" } );
101 
102             ConstraintMapping mapping = new ConstraintMapping();
103             mapping.setPathSpec( "/*" );
104             mapping.setConstraint( constraint );
105 
106             security.setConstraintMappings( Collections.singletonList( mapping ) );
107             security.setAuthenticator( new BasicAuthenticator() );
108             security.setLoginService( loginService );
109             security.setHandler( handler );
110         }
111         else
112         {
113             server.setHandler( handler );
114         }
115         return server;
116     }
117 
118     public static HttpServerBuilder builder()
119     {
120         return new HttpServerBuilder();
121     }
122 
123     public static class HttpServerBuilder
124     {
125 
126         private int port;
127 
128         private String username;
129 
130         private String password;
131 
132         private StreamSource source;
133 
134         public HttpServerBuilder port( int port )
135         {
136             this.port = port;
137             return this;
138         }
139 
140         public HttpServerBuilder username( String username )
141         {
142             this.username = username;
143             return this;
144         }
145 
146         public HttpServerBuilder password( String password )
147         {
148             this.password = password;
149             return this;
150         }
151 
152         public HttpServerBuilder source( final String source )
153         {
154             this.source = new StreamSource()
155             {
156                 @Override
157                 public InputStream stream( String path )
158                     throws IOException
159                 {
160                     return new URL( String.format( "%s/%s", source, path ) ).openStream();
161                 }
162             };
163             return this;
164         }
165 
166         public HttpServerBuilder source( final File source )
167         {
168             this.source = new StreamSource()
169             {
170                 @Override
171                 public InputStream stream( String path )
172                     throws IOException
173                 {
174                     return new FileInputStream( new File( source, path ) );
175                 }
176             };
177             return this;
178         }
179 
180         public HttpServer build()
181         {
182             return new HttpServer( port, username, password, source );
183         }
184     }
185 
186     public interface StreamSource
187     {
188         InputStream stream( String path )
189             throws IOException;
190     }
191 
192     public static class StreamSourceHandler
193         extends AbstractHandler
194     {
195 
196         private final StreamSource source;
197 
198         public StreamSourceHandler( StreamSource source )
199         {
200             this.source = source;
201         }
202 
203         @Override
204         public void handle( String target, Request baseRequest, HttpServletRequest request,
205                             HttpServletResponse response )
206             throws IOException, ServletException
207         {
208             response.setContentType( "application/octet-stream" );
209             response.setStatus( HttpServletResponse.SC_OK );
210             try ( InputStream in = source.stream(
211                 target.substring( 1 ) ); OutputStream out = response.getOutputStream() )
212             {
213                 ByteStreams.copy( in, out );
214             }
215             baseRequest.setHandled( true );
216         }
217     }
218 
219     public static void main( String[] args )
220         throws Exception
221     {
222         HttpServer server = HttpServer.builder() //
223             .port( 0 ) //
224             .username( "maven" ) //
225             .password( "secret" ) //
226             .source( new File( "/tmp/repo" ) ) //
227             .build();
228         server.start();
229     }
230 }