Java "httplib"

Admin User, created Apr 26. 2025
         
package foreign.misc;
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 nova.*;
import java.io.*;
import java.net.InetSocketAddress;
import java.util.*;
/**
* Foreign functions for library(misc/spin)
* <p/>
* Warranty & Liability
* To the extent permitted by applicable law and unless explicitly
* otherwise agreed upon, XLOG Technologies AG makes no warranties
* regarding the provided information. XLOG Technologies AG assumes
* no liability that any problems might be solved with the information
* provided by XLOG Technologies AG.
* <p/>
* Rights & License
* All industrial property rights regarding the information - copyright
* and patent rights in particular - are the sole property of XLOG
* Technologies AG. If the company was not the originator of some
* excerpts, XLOG Technologies AG has at least obtained the right to
* reproduce, change and translate the information.
* <p/>
* Reproduction is restricted to the whole unaltered document. Reproduction
* of the information is only allowed for non-commercial uses. Selling,
* giving away or letting of the execution of the library is prohibited.
* The library can be distributed as part of your applications and libraries
* for execution provided this comment remains unchanged.
* <p/>
* Restrictions
* Only to be distributed with programs that add significant and primary
* functionality to the library. Not to be distributed with additional
* software intended to replace any components of the library.
* <p/>
* Trademarks
* Jekejeke is a registered trademark of XLOG Technologies AG.
*/
public final class httplib {
/******************************************************************/
/* HTTP Server */
/******************************************************************/
/**
* os_http_server_new(S):
* The predicate succeeds in S with a new http server.
*/
private static boolean test_os_http_server_new(Object[] args) {
try {
HttpServer obj = HttpServer.create(null, 0);
return Machine.exec_unify(args[0], obj);
} catch (IOException err) {
throw Machine.make_error(runtime.map_stream_error(err));
}
}
/**
* os_http_server_on(S, T, C):
* The predicate succeeds. As a side effect the stackfull handler C
* is registered as listener to event T from server S.
*/
private static boolean test_os_http_server_on(Object[] args) {
HttpServer obj = (HttpServer) Machine.deref(Machine.exec_build(args[0]));
Object type = Machine.deref(Machine.exec_build(args[1]));
special.check_atom(type);
Object clause = Machine.deref(Machine.exec_build(args[2]));
runtime.check_clause(clause);
if ("request".equals(type)) {
Machine.Context buf = new Machine.Context();
obj.createContext("/", new BaseHandler(
(paras) -> Machine.task_async(clause, buf, paras)));
}
return true;
}
private static class BaseHandler implements HttpHandler {
private final Tasklet func;
public BaseHandler(Tasklet func) {
this.func = func;
}
public void handle(HttpExchange t) {
new Handler.Coroutine(() -> func.perform(new Object[]{t, t})).async();
}
}
private static interface Tasklet {
public abstract void perform(Object[] paras);
}
/**
* os_http_listen_sync(S, P):
* The predicate succeeds. As a side effect the server S
* starts listening on port P.
*/
private static boolean test_os_http_listen_sync(Object[] args) {
try {
HttpServer obj = (HttpServer) Machine.deref(Machine.exec_build(args[0]));
Object beta = Machine.deref(Machine.exec_build(args[1]));
special.check_integer(beta);
int port = (!special.is_bigint(beta) ? ((Integer) beta).intValue() : -1);
obj.bind(new InetSocketAddress(port), 0);
obj.setExecutor(null);
obj.start();
return true;
} catch (IOException err) {
throw Machine.make_error(runtime.map_stream_error(err));
}
}
/**
* os_http_close_sync(S):
* The predicate succeeds. As a side effect the server S is closed.
*/
private static boolean test_os_http_close_sync(Object[] args) {
HttpServer obj = (HttpServer) Machine.deref(Machine.exec_build(args[0]));
obj.stop(0);
return true;
}
/*******************************************************************/
/* HTTP Request */
/*******************************************************************/
/**
* http_current_method(S, P):
* The predicate succeeds in M with the method of the HTTP request S.
*/
private static boolean test_http_current_method(Object[] args) {
HttpExchange exchange = (HttpExchange) Machine.deref(Machine.exec_build(args[0]));
String res = exchange.getRequestMethod();
return Machine.exec_unify(args[1], res);
}
/**
* http_current_path(S, P):
* The predicate succeeds in P with the path of the HTTP request S.
*/
private static boolean test_http_current_path(Object[] args) {
HttpExchange exchange = (HttpExchange) Machine.deref(Machine.exec_build(args[0]));
String res = exchange.getRequestURI().toString();
return Machine.exec_unify(args[1], res);
}
/**
* os_http_current_headers(S, M):
* The predicate succeeds in M with the headers of the HTTP request S.
*/
private static boolean test_os_http_current_headers(Object[] args) {
HttpExchange exchange = (HttpExchange) Machine.deref(Machine.exec_build(args[0]));
HashMap<String, Object> res = new HashMap<>();
Map<String,List<String>> map = exchange.getRequestHeaders();
Iterator<Map.Entry<String,List<String>>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String,List<String>> entry = it.next();
res.put(entry.getKey().toLowerCase(), entry.getValue().get(0));
}
return Machine.exec_unify(args[1], res);
}
/**
* os_http_input_promise_opts(S, L, R, Q):
* The predicate succeeds in Q with a promise for a new
* text reader R on HTTP request S and option list L.
*/
private static boolean test_os_http_input_promise_opts(Object[] args) {
HttpExchange exchange = (HttpExchange) Machine.deref(Machine.exec_build(args[0]));
HashMap<String, Object> opts = (HashMap<String, Object>) Machine.deref(Machine.exec_build(args[1]));
runtime.Source stream = new runtime.Source();
if (!Machine.exec_unify(args[2], stream))
return false;
Object buf = Machine.ctx;
Handler.Promise prom = http_input_promise_opts(buf, stream, exchange, opts);
return Machine.exec_unify(args[3], prom);
}
private static Handler.Promise http_input_promise_opts(Object buf,
runtime.Source stream, HttpExchange exchange, HashMap<String, Object> opts) {
return new Handler.Promise(() -> {
InputStream input = exchange.getRequestBody();
stream.data = new InputStreamReader(input, runtime.get_encoding(opts));
stream.receive = (Handler.Factory) runtime::file_read_promise;
stream.release = (Handler.Factory) runtime::file_close_promise;
stream.flags |= runtime.MASK_SRC_AREAD;
});
}
/*******************************************************************/
/* HTTP Response */
/*******************************************************************/
/**
* os_http_write_head(S, C, H):
* The predicate succeeds. As a side effect it writes the status
* code C and the headers map H to the HTTP response S.
*/
private static boolean test_os_http_write_head(Object[] args) {
try {
HttpExchange exchange = (HttpExchange) Machine.deref(Machine.exec_build(args[0]));
Object code = Machine.deref(Machine.exec_build(args[1]));
special.check_integer(code);
Object assoc = Machine.deref(Machine.exec_build(args[2]));
int status = (!special.is_bigint(code) ? ((Integer) code).intValue() : -1);
Headers headers = exchange.getResponseHeaders();
Iterator<Map.Entry<String, Object>> it = ((HashMap<String, Object>) assoc).entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Object> entry = it.next();
headers.set(entry.getKey(), (String) entry.getValue());
}
if (!"HEAD".equals(exchange.getRequestMethod()) && status != 304) {
exchange.sendResponseHeaders(status, 0);
} else {
exchange.sendResponseHeaders(status, -1);
}
return true;
} catch (IOException err) {
throw Machine.make_error(runtime.map_stream_error(err));
}
}
/**
* os_http_output_opts(S, L, W):
* The predicate succeeds in W with a new text writer for
* the HTTP response S and the option list L.
*/
private static boolean test_os_http_output_opts(Object[] args) {
HttpExchange exchange = (HttpExchange) Machine.deref(Machine.exec_build(args[0]));
HashMap<String, Object> opts = (HashMap<String, Object>) Machine.deref(Machine.exec_build(args[1]));
runtime.Sink dst = new runtime.Sink();
OutputStream output = exchange.getResponseBody();
dst.data = new OutputStreamWriter(output, runtime.get_encoding(opts));
dst.send = runtime::file_write;
dst.release = runtime::file_close;
dst.notify = runtime::file_flush;
return Machine.exec_unify(args[2], dst);
}
/******************************************************************/
/* HTTP Lib Init */
/******************************************************************/
public static void main() {
Store.add("os_http_server_new", 1, special.make_check(httplib::test_os_http_server_new));
Store.add("os_http_server_on", 3, special.make_check(httplib::test_os_http_server_on));
Store.add("os_http_listen_sync", 2, special.make_check(httplib::test_os_http_listen_sync));
Store.add("os_http_close_sync", 1, special.make_check(httplib::test_os_http_close_sync));
Store.add("http_current_method", 2, special.make_check(httplib::test_http_current_method));
Store.add("http_current_path", 2, special.make_check(httplib::test_http_current_path));
Store.add("os_http_current_headers", 2, special.make_check(httplib::test_os_http_current_headers));
Store.add("os_http_input_promise_opts", 4, special.make_check(httplib::test_os_http_input_promise_opts));
Store.add("os_http_write_head", 3, special.make_check(httplib::test_os_http_write_head));
Store.add("os_http_output_opts", 3, special.make_check(httplib::test_os_http_output_opts));
}
}