blob: c93ec9ff0ec20358f45cc6c48847f1e440022e23 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.it;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Collections;
import com.google.common.io.ByteStreams;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.UserStore;
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.log.StdErrLog;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.security.Password;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
/**
* An HTTP server that handles all requests on a given port from a specified source, optionally secured using BASIC auth
* by providing a username and password. The source can either be a URL or a directory. When a request is made the
* request is satisfied from the provided source.
*
* @author Jason van Zyl
*/
public class HttpServer {
static {
Log.initialized();
Logger rootLogger = Log.getRootLogger();
if (rootLogger instanceof StdErrLog) {
((StdErrLog) rootLogger).setLevel(StdErrLog.LEVEL_WARN);
}
}
private final Server server;
private final StreamSource source;
private final String username;
private final String password;
public HttpServer(int port, String username, String password, StreamSource source) {
this.username = username;
this.password = password;
this.source = source;
this.server = server(port);
}
public void start() throws Exception {
server.start();
// server.join();
}
public boolean isFailed() {
return server.isFailed();
}
public void stop() throws Exception {
server.stop();
}
public void join() throws Exception {
server.join();
}
public int port() {
return ((NetworkConnector) server.getConnectors()[0]).getLocalPort();
}
private Server server(int port) {
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setMaxThreads(500);
Server server = new Server(threadPool);
server.setConnectors(new Connector[] {new ServerConnector(server)});
server.addBean(new ScheduledExecutorScheduler());
ServerConnector connector = (ServerConnector) server.getConnectors()[0];
connector.setIdleTimeout(30_000L);
connector.setPort(port);
StreamSourceHandler handler = new StreamSourceHandler(source);
if (username != null && password != null) {
HashLoginService loginService = new HashLoginService("Test Server");
UserStore userStore = new UserStore();
userStore.addUser(username, new Password(password), new String[] {"user"});
loginService.setUserStore(userStore);
server.addBean(loginService);
ConstraintSecurityHandler security = new ConstraintSecurityHandler();
server.setHandler(security);
Constraint constraint = new Constraint();
constraint.setName("auth");
constraint.setAuthenticate(true);
constraint.setRoles(new String[] {"user", "admin"});
ConstraintMapping mapping = new ConstraintMapping();
mapping.setPathSpec("/*");
mapping.setConstraint(constraint);
security.setConstraintMappings(Collections.singletonList(mapping));
security.setAuthenticator(new BasicAuthenticator());
security.setLoginService(loginService);
security.setHandler(handler);
} else {
server.setHandler(handler);
}
return server;
}
public static HttpServerBuilder builder() {
return new HttpServerBuilder();
}
public static class HttpServerBuilder {
private int port;
private String username;
private String password;
private StreamSource source;
public HttpServerBuilder port(int port) {
this.port = port;
return this;
}
public HttpServerBuilder username(String username) {
this.username = username;
return this;
}
public HttpServerBuilder password(String password) {
this.password = password;
return this;
}
public HttpServerBuilder source(final String source) {
this.source = new StreamSource() {
@Override
public InputStream stream(String path) throws IOException {
return new URL(String.format("%s/%s", source, path)).openStream();
}
};
return this;
}
public HttpServerBuilder source(final File source) {
this.source = new StreamSource() {
@Override
public InputStream stream(String path) throws IOException {
return new FileInputStream(new File(source, path));
}
};
return this;
}
public HttpServer build() {
return new HttpServer(port, username, password, source);
}
}
public interface StreamSource {
InputStream stream(String path) throws IOException;
}
public static class StreamSourceHandler extends AbstractHandler {
private final StreamSource source;
public StreamSourceHandler(StreamSource source) {
this.source = source;
}
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("application/octet-stream");
response.setStatus(HttpServletResponse.SC_OK);
try (InputStream in = source.stream(target.substring(1));
OutputStream out = response.getOutputStream()) {
ByteStreams.copy(in, out);
}
baseRequest.setHandled(true);
}
}
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.builder() //
.port(0) //
.username("maven") //
.password("secret") //
.source(new File("/tmp/repo")) //
.build();
server.start();
}
}