Web Prolog ISOBASE Test Cluster - Hack Away, Find Security Bugs

I don’t think that HTTP becomes stateful when keep-alive is used, at least not in any interesting sense. WebSocket, however, is a truly stateful protocol. But I’m glad you asked for source code, because here comes the implementation of the API. It is not exactly the implementation used in the demo nodes (as that’s a bit too hacky to show), but it should give you an idea of how the API can be built on top of pengines.

:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/http_parameters)).

:- http_handler(root(ask), http_actor_manager, [spawn([])]).

:- dynamic cache/3.

http_actor_manager(Request) :-
    http_parameters(Request, [ 
        query(QueryAtom, []),
        offset(Offset, [integer, default(0)]),
        limit(Limit, [integer, default(1)])
    ]),
    read_term_from_atom(QueryAtom, Query, []),
    query_id(Query, QID),
    (   with_mutex(cache, retract(cache(QID, Offset, Pid)))
    ->  self(Self),
        pengine_next(Pid, [
            limit(Limit),
            return_to(Self)
        ])
    ;   pengine_spawn(Pid),
        pengine_ask(Pid, offset(Offset, Query), [
            limit(Limit)
        ])
    ),
    receive({
        failure(Pid) ->
            respond(failure);
        error(Pid, Exception) ->
            respond(error(Exception)) ;
        success(Pid, Solutions, true) ->
            Index is Offset + Limit,
            with_mutex(cache, assertz(cache(QID, Index, Pid))),
            respond(success(Solutions, true));
        success(Pid, Solutions, false) ->
            respond(success(Solutions, false))   
    }).
  
query_id(Query, QID) :-
    copy_term(Query, QID0),
    numbervars(QID0, 0, _),
    term_hash(QID0, QID).

To make it easier to understand, the above code illustrates the main idea of our caching scheme, but leaves out many of the details that are necessary for a fully working node. For example, it does not prune the cache when it has grown too big (that should be done from the top when a max-size has been reached), it does not implement the mechanism that will terminate a pengine when it has run for too long, and it does not implement the format option. Code for handling all of this would be easy to add, and our demonstrator adds it.

I’ll be happy to explain even further, if you want me to. Also, the following illustration might help:

1 Like