package org.wso2.carbon.device.mgt.iot.agent.kura.display; import org.apache.http.*; import org.apache.http.entity.ContentType; import org.apache.http.impl.nio.bootstrap.ServerBootstrap; import org.apache.http.impl.nio.reactor.IOReactorConfig; import org.apache.http.nio.entity.NFileEntity; import org.apache.http.nio.protocol.*; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpCoreContext; import org.apache.http.ssl.SSLContexts; import org.wso2.carbon.device.mgt.iot.agent.kura.display.resource.ResourceUtil; import javax.net.ssl.SSLContext; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLConnection; import java.net.URLDecoder; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Locale; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; /** * Embedded HTTP/1.1 file server based on a non-blocking I/O model and capable of direct channel * (zero copy) data transfer. */ public class HttpServer implements Runnable{ private final static Logger log = Logger.getLogger(HttpServer.class.getName()); private File serverDocRoot = null; private int serverPort = 8000; public HttpServer(File serverDocRoot, int serverPort) { this.serverDocRoot = serverDocRoot; this.serverPort = serverPort; } public void run(){ log.info("Starting HttpServer @" + serverDocRoot.getAbsolutePath() + " Port:" + serverPort); SSLContext sslcontext = null; if (serverPort == 8443) { // Initialize SSL context URL url = HttpServer.class.getResource( File.separator + LauncherConstants.CARBON_KEYSTORE_PATH); if (url == null) { System.out.println("Keystore not found"); ResourceUtil.stopBundle(); } try { sslcontext = SSLContexts.custom().loadKeyMaterial(url, LauncherConstants.CARBON_KEYSTORE_SECRET .toCharArray(), LauncherConstants.CARBON_KEYSTORE_SECRET .toCharArray()).build(); } catch (NoSuchAlgorithmException |KeyManagementException|KeyStoreException |UnrecoverableKeyException |CertificateException |IOException e) { log.severe("Error on adding SSL key " + e.getMessage()); } } IOReactorConfig config = IOReactorConfig.custom().setSoTimeout(15000).setTcpNoDelay(true) .build(); final org.apache.http.impl.nio.bootstrap.HttpServer server = ServerBootstrap.bootstrap() .setListenerPort(serverPort).setServerInfo("Test/1.1").setIOReactorConfig(config) .setSslContext(sslcontext).setExceptionLogger(ExceptionLogger.STD_ERR) .registerHandler("*", new HttpFileHandler(serverDocRoot)).create(); try { server.start(); server.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); }catch (IOException |InterruptedException e) { log.severe("Error on server start " + e.getMessage()); } Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { server.shutdown(5, TimeUnit.SECONDS); } }); log.info("HttpServer Started..."); } static class HttpFileHandler implements HttpAsyncRequestHandler<HttpRequest> { private static final String[] DEFAULT_INDEX_FILES_LIST = new String[] { "index.html", "index.htm" }; private final File docRoot; public HttpFileHandler(final File docRoot) { super(); this.docRoot = docRoot; } public HttpAsyncRequestConsumer<HttpRequest> processRequest(final HttpRequest request, final HttpContext context) { // Buffer request content in memory for simplicity return new BasicAsyncRequestConsumer(); } public void handle(final HttpRequest request, final HttpAsyncExchange httpexchange, final HttpContext context) throws HttpException, IOException { HttpResponse response = httpexchange.getResponse(); handleInternal(request, response, context); httpexchange.submitResponse(new BasicAsyncResponseProducer(response)); } private void handleInternal(final HttpRequest request, final HttpResponse response, final HttpContext context) throws HttpException, IOException { String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH); if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) { throw new MethodNotSupportedException(method + " method not supported"); } String target = request.getRequestLine().getUri(); File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8")); if (!file.exists()) { response.setStatusCode(HttpStatus.SC_NOT_FOUND); log.severe("File " + file.getPath() + " not found"); return; } else if (!file.canRead()) { response.setStatusCode(HttpStatus.SC_FORBIDDEN); log.severe("Cannot read file " + file.getPath()); return; } else if (file.isDirectory()) { if (target.endsWith("/")) { boolean isExist = false; for (String index : DEFAULT_INDEX_FILES_LIST) { final File t_file = new File(this.docRoot + File.separator + target, index); if (t_file.exists()) { file = t_file; isExist = true; break; } } if(!isExist)return; } else { //redirect browser - doing basically what apache does response.setStatusCode(HttpStatus.SC_MOVED_PERMANENTLY); String newUrl = target + "/"; response.setHeader("Location", newUrl); return; } } HttpCoreContext coreContext = HttpCoreContext.adapt(context); HttpConnection conn = coreContext.getConnection(HttpConnection.class); response.setStatusCode(HttpStatus.SC_OK); String displayAgentHome = ResourceUtil.getDisplayAgentHome(); System.setProperty("content.types.user.table",displayAgentHome + File.separator + LauncherConstants.CONF_PATH + File.separator + "content-types.properties"); String mimeType= URLConnection.guessContentTypeFromName(file.getName()); NFileEntity body = new NFileEntity(file, ContentType.create(mimeType)); response.setEntity(body); //log.info(conn + ": serving file " + file.getPath()); } } }