package art.servers.controller; import art.library.interop.InteropParameter; import art.library.interop.InteropParameters; import art.library.interop.InteropResponse; import art.library.interop.serialization.Serialization; import art.library.interop.serialization.SerializationException; import art.library.utils.licence.Licence; import art.servers.ServerException; import art.servers.Shared; import art.servers.configuration.ConfigurationListenerHttp; import art.servers.types.HttpAuthentication; import com.sun.net.httpserver.BasicAuthenticator; import com.sun.net.httpserver.HttpContext; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.net.InetSocketAddress; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.concurrent.Executors; public class ControllerListenerHttp extends Controller { protected String name = null; protected HttpServer server = null; protected ConfigurationListenerHttp configuration = null; protected ListenerImplementation implementation = null; public ControllerListenerHttp(ConfigurationListenerHttp configuration) { this.name = Shared.getMessage("Listener http"); this.setName(this.getClass().getName() + " : " + name); this.configuration = configuration; start(); } public ListenerImplementation getListenerImplementation() { if (implementation != null) return implementation; return Shared.controllerListener.getListenerImplementation(); } public void setListenerImplementation(ListenerImplementation implementation) { this.implementation = implementation; } public void run() { Shared.traceInformation(name, "Starting"); while ((isInterrupted() == false) && (exit == false)) { try { if (server == null) { connect(); } sleep(1000); } catch (Exception e) { } } Shared.traceInformation(name, "Finishing"); } protected void connect() { try { server = HttpServer.create(new InetSocketAddress(configuration.port), 0); contexts(); server.setExecutor(Executors.newCachedThreadPool()); server.start(); Shared.traceInformation(name, "Disconnecting", Shared.getMessage("Port") + " = " + configuration.port); return; } catch (Exception exception) { Shared.traceError(name, "Disconnecting", Shared.getMessage("Port") + " = " + configuration.port, exception); } } protected void contexts() { HttpContext context1 = server.createContext("/login", new login()); HttpContext context2 = server.createContext("/art", new artic()); HttpContext context3 = server.createContext("/get", new get()); HttpContext context4 = server.createContext("/set", new set()); HttpContext context5 = server.createContext("/session", new session()); HttpContext context6 = server.createContext("/gis", new gis()); HttpContext context7 = server.createContext("/saml", new saml()); HttpContext context8 = server.createContext("/logout", new logout()); if (configuration.readUser != null) { context3.setAuthenticator(new BasicAuthenticator(configuration.readUser) { public boolean checkCredentials(String user, String pwd) { return user.equals(configuration.readUser) && pwd.equals(configuration.readPassword); } }); } if (configuration.writeUser != null) { context4.setAuthenticator(new BasicAuthenticator(configuration.writeUser) { public boolean checkCredentials(String user, String pwd) { return user.equals(configuration.writeUser) && pwd.equals(configuration.writePassword); } }); } } protected class login implements HttpHandler { public void handle(HttpExchange httpExchange) throws IOException { String language = null; try { InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery()); language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : ""; String type = (parameters.hasParameter("type") == true) ? (String)parameters.getParameterValue("type") : "text"; parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange))); InteropResponse response = getListenerImplementation().login(parameters, type, httpExchange.getRemoteAddress().getHostName()); result(httpExchange, response); } catch (Exception e) { result(httpExchange, 400, language, e); } } } protected class logout implements HttpHandler { public void handle(HttpExchange httpExchange) throws IOException { String language = null; try { InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery()); language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : ""; parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange))); InteropResponse response = getListenerImplementation().logout(parameters, httpExchange.getRemoteAddress().getHostName()); result(httpExchange, response); } catch (Exception e) { result(httpExchange, 400, language, e); } } } protected class artic implements HttpHandler { String language = null; public void handle(HttpExchange httpExchange) throws IOException { try { InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery()); language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : ""; parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange))); int tokenStatus = checkToken(parameters, httpExchange.getRemoteAddress().getHostName()); if (tokenStatus != 200) { result(httpExchange, tokenStatus, "Invalid authentication or invalid token"); } InteropResponse response = getListenerImplementation().artic(parameters); result(httpExchange, response); } catch (Exception exception) { Shared.println(Shared.getMessage("Model"), exception); result(httpExchange, 400, language, exception); } } } protected class gis implements HttpHandler { public void handle(HttpExchange httpExchange) throws IOException { try { String uri = httpExchange.getRequestURI().getRawQuery(); InteropResponse response = getListenerImplementation().gis(uri); result(httpExchange, response); } catch (Exception exception) { result(httpExchange, 400, "", exception); } } } protected class saml implements HttpHandler { public void handle(HttpExchange httpExchange) throws IOException { try { InteropParameters parameters = new InteropParameters(); parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange))); InteropResponse response = getListenerImplementation().saml(parameters); result(httpExchange, response); } catch (Exception exception) { result(httpExchange, 400, "", exception); } } } private int checkToken(InteropParameters parameters, String remoteAddress) { try { HttpAuthentication authentication = Serialization.deserialize(HttpAuthentication.class, Licence.decrypt((String)parameters.getParameterValue("token"))); if (authentication.isTokenValid(remoteAddress) == false) { return 401; // Page expired } parameters.addParameter("username", authentication.username); parameters.addParameter("computer", authentication.address); authentication.lastRequestTimestamp = System.currentTimeMillis(); return 200; } catch (Exception e) { } try { String[] login = ((String)parameters.getParameterValue("token")).split(","); String username = login[0]; String password = login[1]; HttpAuthentication authentication = getListenerImplementation().login(username, password, remoteAddress); String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString()); parameters.setParameter("token", token); authentication.lastRequestTimestamp = System.currentTimeMillis(); parameters.addParameter("username", authentication.username); parameters.addParameter("computer", authentication.address); return 200; } catch (Exception exception) { Shared.println(Shared.getMessage("Model"), exception); } return 401; // Invalid token, unauthorized } protected class get implements HttpHandler { String language = null; public void handle(HttpExchange httpExchange) throws IOException { try { InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery()); language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : ""; parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange))); InteropResponse response = getListenerImplementation().get(parameters); result(httpExchange, response); } catch (Exception exception) { result(httpExchange, 400, language, exception); } } } protected class set implements HttpHandler { public void handle(HttpExchange httpExchange) throws IOException { String language = null; try { InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery()); language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : ""; parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange))); InteropResponse response = getListenerImplementation().set(parameters); result(httpExchange, response); } catch (Exception exception) { result(httpExchange, 400, language, exception); } } } protected class session implements HttpHandler { public void handle(HttpExchange httpExchange) throws IOException { String language = null; try { InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery()); language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : ""; String token = (parameters.hasParameter("token") == true) ? (String)parameters.getParameterValue("token") : ""; if (checkToken(language, token) == false) { throw new SerializationException(Shared.getMessage(language, "Invalid session")); } parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange))); InteropResponse response = getListenerImplementation().session(parameters); result(httpExchange, response); } catch (Exception exception) { result(httpExchange, 400, language, exception); } } } private boolean checkToken(String language, String token) { try { InteropParameters parameters = new InteropParameters(); parameters.addParameter(new InteropParameter("service", "transactions")); parameters.addParameter(new InteropParameter("operation", "checkToken")); parameters.addParameter(new InteropParameter("language", language)); parameters.addParameter(new InteropParameter("token", token)); InteropResponse response = Shared.controllerTransactions.set(parameters); boolean result = (Boolean)response.getValue()[0]; if (result == true) return true; } catch (Exception e) { } return false; } // private byte[] getRequestBody(HttpExchange httpExchange) throws Exception { ByteArrayOutputStream bos = null; try { InputStream input = httpExchange.getRequestBody(); bos = new ByteArrayOutputStream(); byte[] buffer = new byte[8196]; int length; while ((length = input.read(buffer)) != -1) { bos.write(buffer, 0, length); } return bos.toByteArray(); } catch (Exception exception) { Shared.println(Shared.getMessage("Model"), exception); throw exception; } finally { try { bos.close(); } catch (Exception ex) {}; httpExchange.getRequestBody().close(); } } // // protected void result(HttpExchange httpExchange, int httpErrorCode, byte[] data) throws Exception { try { httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*"); httpExchange.sendResponseHeaders(httpErrorCode, data.length); httpExchange.getResponseBody().write(data); } catch (Exception e) { e.printStackTrace(); } finally { httpExchange.getResponseBody().close(); } } protected void result(HttpExchange httpExchange, InteropResponse response) { // https://www.sitepoint.com/mime-types-complete-list/ // httpExchange.getResponseHeaders().set("Content-Type", "text/html; charset=" + StandardCharsets.UTF_8); // httpExchange.getResponseHeaders().set("Content-Type", "application/pdf"; charset=" + StandardCharsets.UTF_8); // httpExchange.getResponseHeaders().set("Content-Type", "application/vnd.ms-excel"; charset=" + StandardCharsets.UTF_8); httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*"); if (httpExchange.getRequestMethod().equalsIgnoreCase("OPTIONS")) { httpExchange.getResponseHeaders().add("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); httpExchange.getResponseHeaders().add("Access-Control-Allow-Headers", "Content-Type,Authorization"); try { httpExchange.sendResponseHeaders(204, -1); } catch (Exception e) { } httpExchange.close(); return; } if (response.mime == null) { httpExchange.getResponseHeaders().set("Content-Type", "application/json; charset=" + StandardCharsets.UTF_8); } else { httpExchange.getResponseHeaders().set("Content-Type", response.mime + "; charset=" + StandardCharsets.UTF_8); } // Check if response is a file if (response.name != null) { try { // For filenames with polish characters byte[] filenameBytes = response.name.getBytes("UTF-8"); String filename = ""; for (byte character : filenameBytes) filename += (char)(character & 0xFF); httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + filename + "\""); } catch (Exception e) { httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + response.name + "\""); } } // Check mime text/plain if (response.mime != null) { if (response.mime.equalsIgnoreCase("text/plain")) { try { byte[] data = ((String)response.getValue()[0]).getBytes(); result(httpExchange, 200, data); httpExchange.close(); return; } catch (Exception exception) { manageException(httpExchange, exception); } return; } else if (response.mime.equalsIgnoreCase("application/json")) { try { if (response.array == true) { String message = Serialization.toString(response.getValue()); result(httpExchange, 200, message.getBytes()); } else { String message = Serialization.toString(response.getValue()[0]); result(httpExchange, 200, message.getBytes()); } } catch (Exception e) { manageException(httpExchange, e); } return; } } // Try send raw bytes try { if (response.getValue().length == 0) { String message = Serialization.toString(response.getValue()); result(httpExchange, 200, message.getBytes()); httpExchange.close(); return; } byte[] data = (byte[])response.getValue()[0]; result(httpExchange, 200, data); httpExchange.close(); return; } catch (ClassCastException exception) { } catch (Exception exception) { manageException(httpExchange, exception); } // Default JSON try { if (response.array == false) { String message = Serialization.toString(response.getValue()[0]); result(httpExchange, 200, message.getBytes()); httpExchange.close(); return; } else { if (response.getValue().length == 0) { String message = Serialization.toString(response.getValue()); result(httpExchange, 200, message.getBytes()); httpExchange.close(); return; } else { String message = Serialization.toString(response.getValue()); result(httpExchange, 200, message.getBytes()); httpExchange.close(); return; } } } catch (Exception exception) { manageException(httpExchange, exception); } } protected void result (HttpExchange httpExchange, int httpErrorCode, String language, Exception exception) { if (((exception instanceof SerializationException) || (exception instanceof ServerException)) && (exception.getMessage() != null)) { result(httpExchange, httpErrorCode, Shared.getMessage(language, exception.getMessage())); } else if ((exception instanceof SerializationException) && (((SerializationException)exception).getStackMessage() != null)) { result(httpExchange, httpErrorCode, ((SerializationException)exception).getStackMessage()); } else if ((exception instanceof ServerException) && (((ServerException)exception).getStackMessage() != null)) { result(httpExchange, httpErrorCode, ((ServerException)exception).getStackMessage()); } else { StringWriter sw = new StringWriter(); exception.printStackTrace(new PrintWriter(sw)); String message = sw.toString(); result(httpExchange, httpErrorCode, message); } } protected void result (HttpExchange httpExchange, int httpErrorCode, String message) { try { if (message != null) { result(httpExchange, httpErrorCode, message.getBytes()); } else { result(httpExchange, httpErrorCode, new String().getBytes()); } } catch (Exception e) { manageException(httpExchange, e); } } // // private void manageException (HttpExchange httpExchange, Exception exception) { try { httpExchange.close(); } catch (Exception e) { } if (exception instanceof IOException) { String message = exception.toString().toLowerCase(); if (message.contains("an established connection was aborted by the software in your host machine") == true) { if (server != null) { Shared.traceError(name, "Disconnecting", exception); try{server.stop(10);} catch (Exception ex){}; server = null; connect(); } } } } // }