Pengines.js, Pengine create call - Certain options are ignored?

I’m using: SWI-Prolog version 8.0.2 on Ubuntu Linux 18.04.

I’m having trouble configuring the Pengine instance with certain options that are described in the pengine_create/3 page:

http://www.swi-prolog.org/pldoc/doc_for?object=pengine_create/1

For example, I try to pass an ID to the call yet the Pengine.id property remains null after the call.

I looked at the code for the client side Pengines code (i.e. - the code that makes Ajax calls to a Pengines server instance):

I don’t see where the id property would ever get copied to the client side Pengine instance? There are only two object methods that are involved with these operations during a create call, at least from what I can see: fillDefaultOptions() and copyOptions(). Here is the relevant code:

  // private functions
  function fillDefaultOptions(options) {
    for(let k in Pengine.options) {
      if ( Pengine.options.hasOwnProperty(k) &&
	   options[k] === undefined )
	options[k] = Pengine.options[k];
    }

    return options;
  }

  function copyOptions(to, from, list) {
    for(let i=0; i<list.length; i++) {
      let k = list[i];
      if ( from[k] !== undefined )
		to[k] = from[k];
    }
  }

And here are the calls made to those two methods from the constructor:

  // create instance
  this.options = fillDefaultOptions(options);
  this.id = null;

  // On creation
  let src = this.options.src ? [this.options.src] : [];
  let createOptions = {
    src_text: this.script_sources(src).join('\n')
  };

  copyOptions(createOptions, options,
	      [ "format",
		"application",
		"ask",
		"template",
		"chunk",
		"destroy"
	      ]);

The problem I see when I trace out the code, is that fillDefaultOptions() only copies over properties that already exist in the object and only if the existing property is currently undefined, and copyOptions() only copies over properties that are in the provided property name list, which does not include a list element for the id property. In the end, the id property provided by the caller during the pengine_create/3 call never gets assigned to the id property that exists in the object and when I inspect the Pengine object after the call the id property is null.

Am I wrong in this analysis?

The pengine_create link is for passing options from a prolog client. In particular, the id option is shown as id(-ID) meaning you don’t pass the ID in, its given back to the caller, and indeed in the javascript version of the call, its set when a response is received back from the server e.g. at lines 431, 475 in the linked javascript code.

1 Like

Thank Jan. My apologies. Despite programming in Prolog for several years, I had forgotten what the +/- signs mean in front of terms in a predicate’s call signature. I’ve got it now.

Hello. Has anybody tried passing other options (to http_open) such as these?:

Pengine({ server: PENGINE_URL, authenticate:true, authorization:“basic(user,password)”,
//src_text: le_string,
oncreate: handleCreate,
//onprompt: handlePrompt,
onoutput: handleOutput,
onsuccess: showAnswer,
onfailure: reportFailure
})

I think you are talking JavaScript? If so, have a look at pengines.js in the Prolog distribution. It doesn’t pass such options, but it should be fairly easy to pass such options on (and save them in the Pengine object such that you can also pass them to the other HTTP requests).

I’m happy to handle a PR doing that.

Yes! I changed pengines.js to support those options:

  copyOptions(createOptions, options,
	      [ "format",
		"application",
		"ask",
		"template",
		"chunk",
		"destroy",
    "authorization",
    "authenticate"
	      ]);

and they seem to be passing in:

Pengine create {src_text: '', format: 'json', authorization: 'basic(jacinto,'123')', authenticate: true}

But I still get this error:



Authorization Required


This server could not verify that you are authorized to access the document requested.  Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.

Could it be it runs the initial “create” fine, but you get the issue in subsequent HTTP requests? You’ll need to propagate these settings into those requests as well.

Thank you Jan. I checked. It does not pass the create connection. I tried to test it from another swipl process, like this:

?- use_module(library(http/http_open)).
true.

trying setting the authorization to basic like this:

?- http_set_authorization('http://localhost:3050/pengine/create', basic(jacinto, '123')). 
true.

and then trying:

?- http_open('http://localhost:3050/pengine/create', In, [authorization(basic(jacinto, '123'))]),
   copy_stream_data(In, user_output),
   close(In).
ERROR: Unknown error term: permission_error(url,'http://localhost:3050/pengine/create') (status(401,Authorization Required))
E

Notice that it also produces an error with:

?- http_open('http://localhost:3050/pengine/create', In, [authorization(digest(jacinto, '123'))]),
   copy_stream_data(In, user_output),
   close(In).
ERROR: Domain error: `authorization' expected, found `digest(jacinto,'123')'

The only way I could make it work is by loading:

?- use_module(library(http/http_digest)).
true.

and then trying:

?- http_open('http://localhost:3050/pengine/create', In, [authorization(digest(jacinto, '123'))]),
   copy_stream_data(In, user_output),
   close(In).
create('ca1f5988-820e-4872-8647-8cd17b442842',[slave_limit(3)]).
In = <stream>(0x563e192cccc0,0x563e192cce70).

But can I get the same effect of library(http/http_digest) in JS?

That is a JavaScript question. I can’t imagine there is no way to specify digest authentication. Surely the browser can do it. You can also configure basic authentication in the Prolog server. That is very much deprecated unless you combine it with HTTPS as the password is sent in a trivially coded way over an insecure connection.