package integration; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.IOUtils; import org.eclipse.jetty.server.*; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.ssl.SslContextFactory; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.ConcurrentSkipListSet; import java.util.logging.Logger; import static com.google.common.base.Joiner.on; import static java.lang.Thread.currentThread; import static java.util.logging.Level.SEVERE; import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; import static javax.servlet.http.HttpServletResponse.SC_OK; import static org.junit.Assert.assertTrue; public class LocalHttpServer { private static final Logger log = Logger.getLogger(LocalHttpServer.class.getName()); private final Server server; /** * @param port * @param ssl * @throws IOException */ public LocalHttpServer(int port, boolean ssl) throws IOException { server = new Server(); if (ssl) { configureHttps(port); } else { ServerConnector connector = new ServerConnector(server); connector.setPort(port); server.setConnectors(new Connector[]{connector}); } ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/"); server.setHandler(context); context.addServlet(new ServletHolder(new FileDownloadHandler()), "/files/*"); context.addServlet(new ServletHolder(new FileUploadHandler()), "/upload"); context.addServlet(new ServletHolder(new FileHandler()), "/*"); } // Configure Jetty to listen both http and https port // as described here: http://java.dzone.com/articles/adding-ssl-support-embedded private void configureHttps(int port) { HttpConfiguration https = new HttpConfiguration(); https.addCustomizer(new SecureRequestCustomizer()); SslContextFactory sslContextFactory = new SslContextFactory(); // created with "keytool -genkey -alias test.selenide.org -keyalg RSA -keystore test-selenide.jks -keysize 2048" sslContextFactory.setKeyStorePath(getClass().getResource("/test-selenide.jks").toExternalForm()); sslContextFactory.setKeyStorePassword("selenide.rulez"); sslContextFactory.setKeyManagerPassword("selenide.rulez"); ServerConnector sslConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"), new HttpConnectionFactory(https)); sslConnector.setPort(port); server.setConnectors(new Connector[] {sslConnector}); } public LocalHttpServer start() throws Exception { server.start(); return this; } private void logRequest(HttpServletRequest request, Object response, long startTime) { String time = new SimpleDateFormat("hh:MM:ss:SSS").format(new Date()); log.info(time + " " + on('?').skipNulls().join(request.getRequestURL(), request.getQueryString()) + " -> " + response + " " + (System.nanoTime() - startTime) / 1000000 + " ms"); } private Set<String> sessions = new ConcurrentSkipListSet<>(); private class FileHandler extends HttpServlet { @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long start = System.nanoTime(); byte[] fileContent = readFileContent(request); if (fileContent == null) { response.setStatus(SC_NOT_FOUND); logRequest(request, "NOT_FOUND", start); return; } generateSessionId(response); response.setStatus(SC_OK); response.setContentLength(fileContent.length); printResponse(response, fileContent); logRequest(request, "ok", start); } private void generateSessionId(HttpServletResponse http) { String sessionId = "" + System.currentTimeMillis(); Cookie cookie = new Cookie("session_id", sessionId); cookie.setMaxAge(-1); // cookie.setDomain("localhost"); cookie.setPath("/"); http.addCookie(cookie); sessions.add(sessionId); } } private class FileDownloadHandler extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long start = System.nanoTime(); String sessionId = getSessionId(request); assertTrue(sessions.contains(sessionId)); byte[] fileContent = readFileContent(request); if (fileContent == null) { response.setStatus(SC_NOT_FOUND); logRequest(request, "NOT_FOUND", start); return; } response.setStatus(SC_OK); response.setContentLength(fileContent.length); response.setHeader("content-disposition", "attachment; filename=" + request.getPathInfo()); printResponse(response, fileContent); logRequest(request, "ok", start); } } public final List<FileItem> uploadedFiles = new ArrayList<>(2); private class FileUploadHandler extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long start = System.nanoTime(); DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setRepository(new File(System.getProperty("java.io.tmpdir"))); ServletFileUpload upload = new ServletFileUpload(factory); try { List<FileItem> items = upload.parseRequest(request); for (FileItem item : items) { if (item.getSize() > 0) { uploadedFiles.add(item); } } String message = "<h3>Uploaded " + uploadedFiles.size() + " files</h3>" + items; printResponse(response, message.getBytes("UTF-8")); logRequest(request, message, start); } catch (FileUploadException e) { logRequest(request, e.getMessage(), start); log.log(SEVERE, e.getMessage(), e); } } } private String getSessionId(HttpServletRequest request) { if (request.getCookies() != null) { for (Cookie cookie : request.getCookies()) { if ("session_id".equals(cookie.getName())) { return cookie.getValue(); } } } throw new IllegalArgumentException("No cookie 'session_id' found: " + Arrays.toString(request.getCookies())); } static byte[] readFileContent(HttpServletRequest request) throws IOException { String fileName = request.getPathInfo().replaceFirst("\\/(.*)", "$1"); InputStream in = currentThread().getContextClassLoader().getResourceAsStream(fileName); if (in == null) return null; try { return IOUtils.toByteArray(in); } finally { in.close(); } } static void printResponse(HttpServletResponse http, byte[] fileContent) throws IOException { http.setContentType("text/html"); try (OutputStream os = http.getOutputStream()) { os.write(fileContent); } } /** * Method may be used to locally run test server used by Selenide own tests * * @param args not used */ public static void main(String[] args) throws Exception { LocalHttpServer server = new LocalHttpServer(8080, false).start(); Thread.currentThread().join(); } }