package org.eclipse.aether.connector.async;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.HttpMethods;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.AbstractHandler;
import org.mortbay.jetty.handler.DefaultHandler;
import org.mortbay.jetty.handler.HandlerList;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.security.B64Code;
import org.mortbay.jetty.security.Constraint;
import org.mortbay.jetty.security.ConstraintMapping;
import org.mortbay.jetty.security.HashUserRealm;
import org.mortbay.jetty.security.SecurityHandler;
import org.mortbay.jetty.security.SslSocketConnector;
import org.mortbay.util.IO;
import org.mortbay.util.URIUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@SuppressWarnings( "synthetic-access" )
{
private Server server;
private int httpPort;
private int httpsPort = -1;
private String keyStoreLocation;
private String keyStorePassword;
private String trustStoreLocation;
private String trustStorePassword;
private boolean needClientAuth;
private String proxyUsername;
private String proxyPassword;
private boolean redirectToHttps;
private long latency;
private Map<String, String> userPasswords = new HashMap<String, String>();
private Map<String, String[]> userRoles = new HashMap<String, String[]>();
private Map<String, String[]> securedRealms = new HashMap<String, String[]>();
private Map<String, File> resourceDirs = new TreeMap<String, File>( Collections.reverseOrder() );
private Map<String, String[]> resourceFilters = new HashMap<String, String[]>();
private Map<String, String> filterTokens = new HashMap<String, String>();
private Collection<String> recordedPatterns = new HashSet<String>();
private List<String> recordedRequests = new ArrayList<String>();
private Map<String, Map<String, String>> recordedHeaders = new HashMap<String, Map<String, String>>();
{
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort( httpPort );
return connector;
}
{
SslSocketConnector connector = new SslSocketConnector();
connector.setPort( httpsPort );
connector.setKeystore( new File( keyStoreLocation ).getAbsolutePath() );
connector.setPassword( keyStorePassword );
connector.setKeyPassword( keyStorePassword );
connector.setTruststore( new File( trustStoreLocation ).getAbsolutePath() );
connector.setTrustPassword( trustStorePassword );
connector.setNeedClientAuth( needClientAuth );
return connector;
}
{
this.httpPort = httpPort;
return this;
}
{
if ( httpPort >= 0 && server != null && server.isRunning() )
{
return server.getConnectors()[0].getLocalPort();
}
return httpPort;
}
{
return "http://localhost:" + getHttpPort();
}
{
this.httpsPort = httpsPort;
return this;
}
{
if ( httpsPort >= 0 && server != null && server.isRunning() )
{
return server.getConnectors()[( httpPort < 0 ) ? 0 : 1].getLocalPort();
}
return httpsPort;
}
{
return "https://localhost:" + getHttpsPort();
}
public HttpServer
setKeyStore( String path, String password )
{
keyStoreLocation = path;
keyStorePassword = password;
return this;
}
{
trustStoreLocation = path;
trustStorePassword = password;
return this;
}
{
this.needClientAuth = needClientAuth;
return this;
}
public HttpServer
setProxyAuth( String username, String password )
{
this.proxyUsername = username;
this.proxyPassword = password;
return this;
}
{
return new AbstractHandler()
{
public void handle( String target, HttpServletRequest request, HttpServletResponse response,
int dispatch )
throws IOException
{
String auth = request.getHeader( "Proxy-Authorization" );
if ( auth != null )
{
auth = auth.substring( auth.indexOf( ' ' ) + 1 ).trim();
auth = B64Code.decode( auth );
}
if ( !( proxyUsername + ':' + proxyPassword ).equals( auth ) )
{
response.setStatus( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED );
response.addHeader( "Proxy-Authenticate", "Basic realm=\"Squid proxy-caching web server\"" );
response.getWriter().println( "Proxy authentication required" );
( (Request) request ).setHandled( true );
}
}
};
}
{
this.redirectToHttps = redirectToHttps;
return this;
}
{
return new AbstractHandler()
{
public void handle( String target, HttpServletRequest request, HttpServletResponse response,
int dispatch )
{
int httpsPort = getHttpsPort();
if ( !( (Request) request ).isHandled() && request.getServerPort() != httpsPort )
{
String url = "https://" + request.getServerName() + ":" + httpsPort + request.getRequestURI();
response.setStatus( HttpServletResponse.SC_MOVED_PERMANENTLY );
response.setHeader( "Location", url );
( (Request) request ).setHandled( true );
}
}
};
}
public HttpServer
addUser( String username, String password, String... roles )
{
userPasswords.put( username, password );
userRoles.put( username, ( roles == null ) ? new String[0] : roles );
return this;
}
{
securedRealms.put( pathSpec, ( roles == null ) ? new String[0] : roles );
return this;
}
{
List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
for ( String pathSpec : securedRealms.keySet() )
{
String[] roles = securedRealms.get( pathSpec );
Constraint constraint = new Constraint();
constraint.setName( Constraint.__BASIC_AUTH );
constraint.setRoles( roles );
constraint.setAuthenticate( true );
ConstraintMapping constraintMapping = new ConstraintMapping();
constraintMapping.setConstraint( constraint );
constraintMapping.setPathSpec( pathSpec );
mappings.add( constraintMapping );
}
HashUserRealm userRealm = new HashUserRealm( "TestRealm" );
for ( String username : userPasswords.keySet() )
{
String password = userPasswords.get( username );
String[] roles = userRoles.get( username );
userRealm.put( username, password );
if ( roles != null )
{
for ( String role : roles )
{
userRealm.addUserToRole( username, role );
}
}
}
SecurityHandler securityHandler = new SecurityHandler();
securityHandler.setUserRealm( userRealm );
securityHandler.setConstraintMappings( mappings.toArray( new ConstraintMapping[mappings.size()] ) );
return securityHandler;
}
public HttpServer
addResources( String contextRoot, String baseDirectory, String... filteredExtensions )
{
contextRoot = normalizeContextRoot( contextRoot );
File basedir = new File( baseDirectory ).getAbsoluteFile();
resourceDirs.put( contextRoot, basedir );
resourceFilters.put( contextRoot, ( filteredExtensions == null ) ? new String[0] : filteredExtensions );
return this;
}
{
for ( String pattern : patterns )
{
recordedPatterns.add( pattern );
}
return this;
}
{
return recordedRequests;
}
public Map<String, String> ( String uri )
{
return recordedHeaders.get( uri );
}
{
if ( value == null )
{
filterTokens.remove( token );
}
else
{
filterTokens.put( token, value );
}
return this;
}
{
return new ResHandler();
}
{
this.latency = millis;
return this;
}
{
return new AbstractHandler()
{
public void handle( String target, HttpServletRequest request, HttpServletResponse response,
int dispatch )
{
if ( millis >= 0 )
{
try
{
Thread.sleep( millis );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
else
{
synchronized ( this )
{
try
{
wait();
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
}
}
};
}
public HttpServer
start()
throws Exception
{
if ( server != null )
{
return this;
}
recordedRequests.clear();
List<Connector> connectors = new ArrayList<Connector>();
if ( httpPort >= 0 )
{
connectors.add( newHttpConnector() );
}
if ( httpsPort >= 0 && keyStoreLocation != null )
{
connectors.add( newHttpsConnector() );
}
HandlerList handlerList = new HandlerList();
if ( !recordedPatterns.isEmpty() )
{
handlerList.addHandler( new RecordingHandler() );
}
if ( latency != 0 )
{
handlerList.addHandler( newSleepHandler( latency ) );
}
if ( redirectToHttps )
{
handlerList.addHandler( newSslRedirectHandler() );
}
if ( proxyUsername != null && proxyPassword != null )
{
handlerList.addHandler( newProxyHandler() );
}
if ( !securedRealms.isEmpty() )
{
handlerList.addHandler( newSecurityHandler() );
}
if ( !resourceDirs.isEmpty() )
{
handlerList.addHandler( newResourceHandler() );
}
handlerList.addHandler( new DefaultHandler() );
server = new Server( 0 );
server.setHandler( handlerList );
server.setConnectors( connectors.toArray( new Connector[connectors.size()] ) );
server.start();
waitForConnectors();
addDefaultFilterTokens();
return this;
}
throws Exception
{
List<Connector> badConnectors = new ArrayList<Connector>( 2 );
for ( int r = 10; r > 0; r-- )
{
for ( int i = 200; i > 0; i-- )
{
badConnectors.clear();
for ( Connector connector : server.getConnectors() )
{
if ( connector.getLocalPort() < 0 )
{
badConnectors.add( connector );
}
}
if ( badConnectors.isEmpty() )
{
return;
}
try
{
Thread.sleep( 15 );
}
catch ( InterruptedException e )
{
return;
}
}
System.err.println( "WARNING: " + badConnectors + " did not start properly, restarting" );
for ( Connector connector : badConnectors )
{
connector.stop();
connector.start();
}
}
}
{
if ( !filterTokens.containsKey( "@basedir@" ) )
{
filterTokens.put( "@basedir@", new File( "" ).getAbsolutePath() );
}
if ( !filterTokens.containsKey( "@baseurl@" ) )
{
String baseurl = "file://" + new File( "" ).toURI().getPath();
if ( baseurl.endsWith( "/" ) )
{
baseurl = baseurl.substring( 0, baseurl.length() - 1 );
}
filterTokens.put( "@baseurl@", baseurl );
}
if ( !filterTokens.containsKey( "@baseuri@" ) )
{
String baseuri = "file://" + new File( "" ).toURI().getRawPath();
if ( baseuri.endsWith( "/" ) )
{
baseuri = baseuri.substring( 0, baseuri.length() - 1 );
}
filterTokens.put( "@baseuri@", baseuri );
}
if ( !filterTokens.containsKey( "@port.http@" ) )
{
filterTokens.put( "@port.http@", Integer.toString( getHttpPort() ) );
}
if ( !filterTokens.containsKey( "@port.https@" ) )
{
filterTokens.put( "@port.https@", Integer.toString( getHttpsPort() ) );
}
}
{
if ( server != null )
{
try
{
server.stop();
}
catch ( Exception e )
{
e.printStackTrace();
}
server = null;
}
}
extends AbstractHandler
{
public void handle( String target, HttpServletRequest request, HttpServletResponse response,
int dispatch )
throws IOException
{
String uri = request.getRequestURI();
for ( String contextRoot : resourceDirs.keySet() )
{
String path = URIUtil.decodePath( trimContextRoot( uri, contextRoot ) );
if ( path != null )
{
File basedir = resourceDirs.get( contextRoot );
File file = new File( basedir, path );
if ( HttpMethods.HEAD.equals( request.getMethod() ) )
{
if ( file.exists() )
{
response.setStatus( HttpServletResponse.SC_OK );
}
else
{
response.setStatus( HttpServletResponse.SC_NOT_FOUND );
}
( (Request) request ).setHandled( true );
return;
}
else if ( HttpMethods.PUT.equals( request.getMethod() )
|| HttpMethods.POST.equals( request.getMethod() ) )
{
int i = 0;
while ( !file.getParentFile().exists() && !file.getParentFile().mkdirs() )
{
if ( i++ > 5 )
{
break;
}
}
FileOutputStream os = new FileOutputStream( file );
try
{
IO.copy( request.getInputStream(), os );
}
finally
{
os.close();
}
response.setStatus( HttpServletResponse.SC_CREATED );
( (Request) request ).setHandled( true );
}
else if ( file.isFile() )
{
FileInputStream is = new FileInputStream( file );
try
{
String filterEncoding = getFilterEncoding( path, resourceFilters.get( contextRoot ) );
if ( filterEncoding == null )
{
IO.copy( is, response.getOutputStream() );
}
else
{
String text = IO.toString( is, filterEncoding );
text = filter( text, filterTokens );
response.getOutputStream().write( text.getBytes( filterEncoding ) );
}
}
finally
{
is.close();
}
response.setStatus( HttpServletResponse.SC_OK );
( (Request) request ).setHandled( true );
}
break;
}
}
}
{
return path.substring( path.lastIndexOf( '.' ) + 1 );
}
{
String ext = getExtension( path );
if ( filteredExtensions != null )
{
for ( String filteredExtension : filteredExtensions )
{
if ( filteredExtension.startsWith( "." ) )
{
filteredExtension = filteredExtension.substring( 1 );
}
if ( filteredExtension.equalsIgnoreCase( ext ) )
{
return "properties".equalsIgnoreCase( ext ) ? "ISO-8859-1" : "UTF-8";
}
}
}
return null;
}
private String
filter( String str, Map<String, String> tokens )
{
for ( String token : tokens.keySet() )
{
str = str.replace( token, tokens.get( token ) );
}
return str;
}
}
extends AbstractHandler
{
public void handle( String target, HttpServletRequest request, HttpServletResponse response,
int dispatch )
{
String uri = request.getRequestURI();
for ( String pattern : recordedPatterns )
{
if ( uri.matches( pattern ) )
{
String req = request.getMethod() + " " + uri;
recordedRequests.add( req );
Map<String, String> headers = new HashMap<String, String>();
recordedHeaders.put( uri, headers );
for ( @SuppressWarnings( "unchecked" )
Enumeration<String> h = request.getHeaderNames(); h.hasMoreElements(); )
{
String headername = h.nextElement();
headers.put( headername, request.getHeader( headername ) );
}
}
}
}
}
{
if ( contextRoot.endsWith( "/" ) )
{
contextRoot = contextRoot.substring( 0, contextRoot.length() - 1 );
}
if ( !contextRoot.startsWith( "/" ) )
{
contextRoot = "/" + contextRoot;
}
return contextRoot;
}
{
if ( uri.startsWith( contextRoot ) )
{
if ( contextRoot.length() == 1 )
{
return uri.substring( 1 );
}
else if ( uri.length() > contextRoot.length() && uri.charAt( contextRoot.length() ) == '/' )
{
return uri.substring( contextRoot.length() + 1 );
}
}
return null;
}
}