![JAR search and dependency download from the Maven repository](/logo.png)
io.github.lab515.utils.WebServer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qray Show documentation
Show all versions of qray Show documentation
remoting ondemand in java
package io.github.lab515.utils;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class WebServer implements HttpHandler {
private String identifier = null;
public WebServer(String identifier){
this.identifier = identifier;
addMe(this);
}
static WebServer[] _all = null;
private static synchronized void addMe(WebServer ws){
if(_all == null){
_all = new WebServer[4];
_all[0] = ws;
}else{
for(int i =0; i < _all.length;i++){
if(_all[i] == null){
_all[i] = ws;
return;
}
}
_all = Arrays.copyOf(_all, _all.length*2);
_all[_all.length/2] = ws;
}
}
public static void stopAll(String filter){
WebServer[] all = _all;
ClassMatcher cm = filter != null && (filter = filter.trim()).length() > 0 ? new ClassMatcher(filter.split("\n"),'.') : null;
if(all != null){
for(WebServer ws : all){
if(ws != null){
if(cm == null || (ws.identifier != null && cm.matchSingle(ws.identifier))) {
ws.stop();
}
}
}
}
}
private class PathConfig{
String pattern;
ClassMatcher cm = null;
String[] headers;
Object resp; // assume no other response
int status;
WebFunc action;
boolean includeQuery;
boolean isFilter;
boolean preOrPost;
Object uo;
PathConfig next;
public PathConfig(String pattern, String[] headers, Object resp, int status, boolean isFilter, boolean preOrPost, Object uo){
this.pattern = pattern;
this.headers = headers;
this.resp = resp;
this.status = status;
this.isFilter = isFilter;
this.preOrPost = preOrPost;
this.uo = uo;
init();
}
public PathConfig(String pattern, WebFunc action, boolean isFilter, boolean preOrPost, Object uo){
this.pattern = pattern;
this.action = action;
this.isFilter = isFilter;
this.preOrPost = preOrPost;
this.uo = uo;
init();
}
private void init(){
includeQuery = pattern.indexOf('?') >= 0;
if(pattern.indexOf('*') >= 0){
cm = new ClassMatcher(pattern.split("\n"),'/');
}
}
public int match(String tar){
if(cm != null)return cm.matchSingle(tar) ? 1 : 0;
else{
return tar.equals(pattern) ? 2 : 0;
}
}
}
private HashMap cachedConfigs = new HashMap<>();
private HttpServer server = null;
private PathConfig pathConfigs;
private String getValidName(String name) {
if (name != null) name = name.trim();//.toLowerCase()
return (name == null || name.length() < 1) ? null : name;
}
private void addPathConfig(PathConfig pc){
PathConfig cur = pathConfigs; // webHandler, beforeFilter, afterFilter
PathConfig prev = null;
while(cur != null){
if(cur.isFilter != pc.isFilter){
if(!cur.isFilter)break;
}else if(cur.isFilter){
if(cur.preOrPost != pc.preOrPost)break;
}
prev = cur;
cur = cur.next;
}
if(prev == null){
pc.next = pathConfigs;
pathConfigs = pc;
}else{
cur = prev.next;
prev.next = pc;
pc.next = cur;
}
}
public void addPathPreResponse(String path, String[] headers, Object response, int status){
if(hasStarted())return;
addPathConfig(new PathConfig(path, headers, response, status, true, true, null));
}
public void addPathPostResponse(String path, String[] headers, Object response, int status){
if(hasStarted())return;
addPathConfig(new PathConfig(path, headers, response, status, true, false,null));
}
public void addPathResponse(String path, String[] headers, Object response, int status){
if(hasStarted())return;
addPathConfig(new PathConfig(path, headers, response, status, false,true, null));
}
public void addPathPreFilter(String path, WebFunc filter, Object uo) {
if(hasStarted())return;
addPathConfig(new PathConfig(path, filter,true,true, uo));
}
public void addPathPostFilter(String path, WebFunc filter, Object uo) {
if(hasStarted())return;
addPathConfig(new PathConfig(path, filter,true,false, uo));
}
public void addPathHandler(String path, WebFunc handler, Object uo){
if(hasStarted())return;
addPathConfig(new PathConfig(path, handler,false,true, uo));
}
private static String getException(Throwable e){
String ee = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream pw = new PrintStream(baos);
try {
e.printStackTrace(pw);
ee = baos.toString("utf-8");
}catch (Exception e2){
ee = "error writing exception: " + e.getMessage() + e.getClass().getName();
}finally {
try {
baos.close();
pw.close();
}catch (Exception e2){}
}
return ee;
}
private void writeResponse(int status, HttpExchange exchange, Object response, List headers) throws IOException {
//Headers rhdrs = exchange.getResponseHeaders();
Map> nhdrs = new LinkedHashMap<>();
boolean ctset = false;
if (headers != null) {
for(int i = 0; i < headers.size()-1;i+=2){
String k = headers.get(i);
String v = headers.get(i+1);
List items = nhdrs.get(k);
if(items == null)nhdrs.put(k, items = new ArrayList<>());
items.add(v);
if (!ctset) ctset = (k.equalsIgnoreCase("Content-Type"));
}
}
if (!ctset) {
ArrayList items = new ArrayList<>();
items.add("text/plain");
nhdrs.put("Content-Type", items);
}
exchange.getResponseHeaders().putAll(nhdrs);
byte[] data = null;
if(response != null){
if(response instanceof byte[])data = (byte[])response;
else data = response.toString().getBytes("utf-8");
}
exchange.sendResponseHeaders(status, data == null ? 0 : data.length);
if (data != null) {
try(OutputStream resp = exchange.getResponseBody()) {
resp.write(data);
resp.flush();
}
}else{
exchange.close();
}
}
public void handle(HttpExchange exchange) throws IOException {
try {
_handle(exchange);
} catch (Exception e) {
writeResponse(500, exchange, "Http Error During Processing: " + getException(e), null);
}
}
private static HashMap getQuery(WebLoad resp) throws IOException{
HashMap ret = new HashMap<>();
String ct = resp.req_headers.get("content-type");
String[] resolves = new String[2];
if(ct != null && ct.toLowerCase().indexOf("application/x-www-form-urlencoded") >= 0){
resolves[0] = resp.req_data;
}
if(resp.req_query != null && resp.req_query.length()> 0) {
resolves[1] = resp.req_query;
}
for(String str : resolves){
if(str == null || str.length() < 1)continue;
for(String ar : str.split("&")) {
int p = ar.indexOf('=');
if (p < 1) continue;
String n = ar.substring(0, p).trim();
if (n.length() < 1) continue;
String v = URLDecoder.decode(ar.substring(p + 1).trim(), "utf-8").trim();
ret.put(n.toLowerCase(), v);
}
}
return ret;
}
private WebLoad processRequest(HttpExchange exchange) throws IOException{
WebLoad ret = new WebLoad();
ret.req_method = exchange.getRequestMethod();// assume encoding only utf-8,
ret.req_host = exchange.getRemoteAddress().getHostName();
ret.req_host = exchange.getRemoteAddress().getAddress().getHostAddress();
Headers hdrs = exchange.getRequestHeaders();
StringBuilder sb = new StringBuilder();
ret.req_headers = new HashMap<>();
for(String key : hdrs.keySet()){
for(String s : hdrs.get(key)){
if(sb.length() > 0)sb.append(";");
sb.append(s);
}
ret.req_headers.put(key.trim().toLowerCase(), sb.toString());
sb.setLength(0);
}
try(InputStream ins = exchange.getRequestBody()) {
try (ByteArrayOutputStream bas = new ByteArrayOutputStream()) {
int len = 0;
byte[] buf = new byte[8192];
while ((len = ins.read(buf, 0, 8192)) > 0) {
bas.write(buf, 0, len);
}
ret.req_data = new String(bas.toByteArray(), "utf-8");
}
}
ret.req_url = exchange.getRequestURI().toString();
int p = ret.req_url.indexOf('?');
if(p > 0) {
ret.req_query = ret.req_url.substring(p+1);
ret.req_url = ret.req_url.substring(0,p);
}else ret.req_query = "";
ret.headers = new ArrayList<>();
ret.url_params = getQuery(ret);
return ret;
}
private WebLoad _handleLoad(PathConfig pc, WebLoad load) throws IOException{
if (pc.action != null) {
load.filtering = pc.isFilter;
load.preOrPost = load.filtering ? pc.preOrPost : true;
return pc.action.execute(load, pc.uo);
} else {
if (!pc.isFilter || load.status > 0) {
load.status = pc.status;
}
if (pc.headers != null) {
for (String aa : pc.headers) load.headers.add(aa);
}
if (pc.resp != null) {
load.data = pc.resp;
}
return load;
}
}
public void _handle(HttpExchange exchange) throws IOException {
WebLoad load = processRequest(exchange);
if (load.req_url.equalsIgnoreCase("/_shutdown")) {
System.out.println("Trying to stop server...");
writeResponse(200, exchange, "shutdown server is in progress now!", null);
stopped = true; // prepare to shutdown
return;
}
String full = load.req_url + load.req_query;
WebLoad processed = null;
WebLoad temp = null;
PathConfig pc = pathConfigs;
PathConfig target = null;
int targetScore = 0;
int score = 0;
while(pc != null){
if(pc.isFilter && target == null)break;
if((score = pc.match(pc.includeQuery ? full : load.req_url)) > 0) {
if (pc.isFilter) {
if (!pc.preOrPost && processed == null) {
processed = _handleLoad(pc, load);
if (processed == null) {
processed = load;
break;
}
load = processed;
}
temp = _handleLoad(pc, load);
if (temp == null) break;
load = temp;
} else {
if (score > targetScore) {
target = pc;
targetScore = score;
}
}
}
pc = pc.next;
}
if(target == null){
load.status = 404;
load.data = "404 not found: good server, but not good enough!";
}else{
if(processed == null){
processed = _handleLoad(target,load);
if(processed != null)load = processed;
}
if(load.status < 0)load.status = 200;
}
writeResponse(load.status, exchange, load.data, load.headers);
}
private ExecutorService threadPool = null;
private volatile boolean stopped = true;
public boolean hasStarted() {
return !stopped;
}
public void start(int port) throws IOException {
if (threadPool != null) return;
stopped = false;
InetSocketAddress addr = new InetSocketAddress(port);
server = HttpServer.create(addr, 0);
server.createContext("/", this);
server.setExecutor(threadPool = Executors.newCachedThreadPool());
server.start();
}
public void stop() {
if (server == null) return;
server.stop(1);
threadPool.shutdownNow();
while (true) {
try {
if (threadPool.awaitTermination(1, TimeUnit.SECONDS)) break;
} catch (InterruptedException e) {
}
}
server = null;
threadPool = null;
stopped = true;
}
private boolean _sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
}
return true;
}
public void loopTillStop(int ms) {
while (!stopped && _sleep(ms)) {
try {
if (System.in.available() > 0) {
if (System.in.read() == '\n') {
break;
}
}
} catch (IOException e) {
}
}
System.out.println("Stopping...");
stop();
System.out.println("Stopped server completed");
}
public void loopTillStop() {
loopTillStop(1000);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy