Remove meta from reply_html_page

Hello,

I am working on updating the SWI-Prolog entry to FrameworkBenchmark: FrameworkBenchmarks/frameworks/Prolog/SWI-Prolog at master · TechEmpower/FrameworkBenchmarks · GitHub

According to the FrameworkBenchmark’s specification, the endpoint /fortunes should respond with a very specific response. For one, the head cannot have a meta tag. Also, the endpoint must send back Content-Length header. Hence my questions.

Question 1: How do I remove the meta tag that is automatically inserted by reply_html_page ?

reply_html_page(
    [title('Fortunes')],
    [table([
        ...
    ])]
).

The generated code looks like this:

<!DOCTYPE html>
<HTML>
  <head>
    <title>Fortunes</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    ...
  </body>
</html>

Question 2: Is there a way to send the Content-Length header with the response generated by reply_html_page?

Question 3: As I am new to Prolog, I will appreciate any feedback on the code in question.

Cross-Post: prolog - Remove meta from reply_html_page - Stack Overflow

1 Like

I will take a look but am just learning this stuff myself so no promises on an answer.

The tutorial by Anne is one of the best for learning about Creating Web Applications in SWI-Prolog and might be of help.

1 Like

I find that to be confusing. One of the points of the meta tag is to have the content type so that the specification of the page is known, think syntax checking or even at times type checking. reply_html_page/2 makes some knowledge of the content type.

So I am thinking that if there is no content type then reply_html_page/2 should not be used and something at a lower level from SWI-Prolog should be used in constructing the response. :thinking:

If that is the case then also should not an entire Prolog module be created similar to reply_html_page/2 that knows of the specifics of the response needed for /fortunes? library(quasi_quotations): Define Quasi Quotation syntax comes to mind, See: Is there a way to go from HTML to the Prolog representation of the HTML?

The reason I state this is that in reading about html_set_options/1 with content_type(+ContentType) it seems that removing the meta tag for reply_html_page/2 is not something that should be done.

Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.27)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- html_current_option(Option).
ERROR: Unknown procedure: html_current_option/1 (DWIM could not correct goal)

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

?- html_current_option(Option).
Option = dialect(html5) ;
Option = doctype(html) ;
Option = content_type('text/html; charset=UTF-8').

Thanks, is there an example for quasi_quotations explaining how to use it with lists, Unicode and HTML entities? Are those handled transparently?

More specifically I need to get from something like:

Rows = [row(1, 'こんにちは'), row(2, '<alert>Good bye</alert>')]

to

<html>
<head><title>Fortunes</title></head>
<body>
<table>
  <tr>
    <td>1</td>
    <td>こんにちは</td>
  </tr>
  <tr>
    <td>2</td>
    <td>&lt;alert&gt;Good bye&lt;/alert&gt;</td>
   </tr>
</table>
</body>
</html>

Very odd … Reading the source, something along these lines should work (not tested and you must fill in the …):

reply(_Request) :-
    phrase(page([head(...), body(...)]), Tokens),
    print_html(Tokens).

Question 2: Is there a way to send the Content-Length header with the response generated by reply_html_page ?

The content length is added by the HTTP server.

Before writing code based on your example is the only thing that is likely to change the row elements?

The reason I ask is that while quasiquotations will work, they might be overkill.

For the static part using DCGs, format/2 or even simple unification of a variable into an atom using atomic_list_concat/2 might be better.

For generating the table I am thinking something like apropos_rows/1 from Examples for using the HTML write library.

Here is something that works:

:- use_module(library(http/http_server)).
:- use_module(library(http/html_write)).
:- use_module(library(dcg/high_order)).

run :-
    http_server([port(8080)]).

:- http_handler(root(.), reply, []).

reply(_Request) :-
    findall(row(N,C), row(N,C), Rows),
    phrase(page([ head(title('Fortunes')),
                  body(table(\sequence(row, Rows)))
                ]),
           Tokens),
    format('Content-type: text/html~n~n'),
    print_html(Tokens).

row(row(N, C)) -->
    html(tr([td(N), td(C)])).

% data
row(1, 'こんにちは').
row(2, '<alert>Good bye</alert>').

And here is the output:

$ curl -D hdr http://localhost:8080/
<!DOCTYPE html>
<html>
<head>
<title>Fortunes</title>

</head>
<body>

<table>
<tr><td>1</td><td>こんにちは</td></tr>
<tr><td>2</td><td>&lt;alert&gt;Good bye&lt;/alert&gt;</td></tr>
</table>

</body>
</html>
$ cat hdr
HTTP/1.1 200 OK
Date: Fri, 23 Jul 2021 12:30:22 GMT
Content-Type: text/html; charset=UTF-8
Connection: Keep-Alive
Content-Length: 213

Edit: may require 8.3.x. Not sure when sequence//2 was added to the library.

2 Likes

Yes, the only thing coming from the DB are the rows. The rest is static.

To clarify, in FrameworkBenchmark there are plenty of submissions out there that are trying to squeeze every last drop of performance out of respective platforms with the sole goal of winning the benchmark. I think such submissions miss the point somewhat. The idea of the FrameworkBenchmark is not to produce the fastest code (i.e. just use rust/c++, why bother?) but to show the platform’s idiomatic way of solving a predefined set of test problems, and to weigh readability, elegance, structure, patterns etc. against performance penalty.

2 Likes

It does. Thank you very much!

That is a concept that is foreign to me and maybe others here.

Is this a correct link?

It is. Here are few more:

1 Like

That depends on some conditions. I don’t recall the details, but yes, Transfer-encoding: chunked is supported.

1 Like

The code uses a PostgreSQL database.

Prolog is homoiconic so by many in the Prolog community Prolog is also the database.

Is FrameworksBenchmarks requiring that another database be used? If so how much data is being stored? One can store a lot in Prolog without needing another SQL or NoSQL database. (ref)

If the data can be stored with SWI-Prolog using library(persistency) then I would personally consider that they are saddling Prolog with an artificial constraint and that any results for Prolog should not be considered valid. I do understand that there are times when the data is an external database and so Prolog needs to access it as such but if given the choice of using Prolog as the database and using Prolog with an another database I will choose using Prolog as the database. :slightly_smiling_face:

I wouldn’t see it that way. This is a benchmark for web apps, and these days the web apps almost exclusively distributed, cloud based, with stateless web fronts and a managed database behind, acting as source of truth.

In fact, if you wish to suffer some philosophising on my side, I’d say emphasis on:

  • docker
  • serverless
  • integration (with other managed services like DBs, cache fronts, cloud APIs, message queues)
  • monitoring

is the best option for Prolog to see more adoption.

But this is a completely separate discussion I am not fully equipped to have right now.

1 Like

Not sure why, but I received emails with replies from Mostowski Collapse, but I don’t see any of them here. Nonetheless, I’d like to address a comment about HTTP/2 in one of them:

The FB is a GCD among way too many different frameworks. It’s not perfect, no doubt. But moving such a huge blob forward is a monumental job. In any case, HTTP/2 tests are in the pipeline:

I’ve added a short how-to about FB, in case you feel like contributing: What is FrameworkBenchmark and how to contribute

2 Likes