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

**URL:** <https://swi-prolog.discourse.group/t/web-prolog-isobase-test-cluster-hack-away-find-security-bugs/1425>\
**Category:** Looking for Group\
**Tags:** web-prolog\
**Created:** [October 25, 2019, 3:52pm UTC](https://swi-prolog.discourse.group/t/web-prolog-isobase-test-cluster-hack-away-find-security-bugs/1425 "2019-10-25T15:52:16Z")\
**Posts on this page:** 1\
**Showing post:** 8

<div class="post-metadata">

**Author:** ![torbjorn.lager](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/torbjorn.lager/32/7890_2.png) [@torbjorn.lager](https://swi-prolog.discourse.group/u/torbjorn.lager)\
**Post date:** [October 26, 2019, 12:08pm UTC](https://swi-prolog.discourse.group/t/web-prolog-isobase-test-cluster-hack-away-find-security-bugs/1425/8 "2019-10-26T12:08:40Z")

</div>

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.

```prolog
:- 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:

 ![tiny-prolog-web](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/1X/bc7117248ac2cc25878d006e20a69b7158404b84.png)

---

_[View the full topic](https://swi-prolog.discourse.group/t/web-prolog-isobase-test-cluster-hack-away-find-security-bugs/1425)._
