Web server.I can't figure out how to do it

Tell me how you can give the entire page with the files included in it. My web server serves a static page, while it was pure HTML there were no problems, I output the file via format, but now I have scripts, they are in a subdirectory of the main page, how can I organize the delivery of all the files that the page requests?

A web server will deliver those files if they are referenced in the page correctly. e.g. CSS links or script links. You should go over this tutorial to get familiar with the HTTP libraries
.

As I understand it, it all works if you create a page on swi-prolog, I just output the page from a file.

    absolute_file_name('static/index.html', Index, [access(read)]),
    read_file_to_string(Index, Reply, []),
    format('Content-type: text/html~n~n'),
    format(Reply).

when a request for a page with a script arrives, the server does not know this.

See section 10.1 serving static files in the tutorial.

Web server. I can’t figure out how to do it.

I know what you mean.

This may help.

Note: I have published a few variations over a few years but the example in the link is the last one I published that uses Cytoscape.js with SWI-Prolog.

HTH

Do not forget http_reply_from_files/3, which simply serves static files from a whole directory tree. That is what you would typically use, unless you have a dedicated server that only needs to serve a few files.

For an example of how to serve static pages using http_reply_from_files/3, look at GitHub - kamahen/swipl-server-js-client: Sample SWI-Prolog server with JavaScript client

simple_server.pl has this line:

:- http_handler(static(.),
                http_reply_from_files(static_dir(.), [cache(true)]),
                [prefix]).

and there are 4 static files in the static directory:

  • favicon.ico
  • simple_client.css
  • simple_client.html
  • simple_client.js

When the server is first accessed, the root(.) handler redirects to the static directory, which is used to fetch the 4 static files:

:- http_handler(root(.),
                http_handler_redirect(
                    moved, % or 'moved_temporary', for easier debugging
                    static('simple_client.html')),
                []).

%! http_handler_redirect(+How:atom, +To, +Request) is det.
% This is used to output some debug information before
% calling http_redirect/3.
http_handler_redirect(How, To, Request) :-
    memberchk(path(Base), Request),
    memberchk(request_uri(RequestURI), Request),
    http_absolute_location(To, ToURL, [relative_to(Base)]),
    uri_components(RequestURI, URI),
    uri_data(path, URI, ToURL, ToURI),
    uri_components(NewTo, ToURI),
    debug(redirect_log, 'Redirect: ~q', [[how:How, to:To, toURL:ToURL, requestURI:RequestURI, uri:URI, toURI:ToURI, newTo: NewTo]]),
    http_redirect(How, NewTo, Request).

with debug logging turned on, the request http://localhost:9999 produces this trace:

% static dir: static
% Started server at http://localhost:9999/
% Starting REPL ...
?- 
% [Thread httpd@9999_4] [1] get / ...
% [Thread httpd@9999_4] Redirect: [how:moved,to:static('simple_client.html'),toURL:'/static/simple_client.html',requestURI:(/),uri:uri_components(_16038,_16040,/,_16044,_16046),toURI:uri_components(_16038,_16040,'/static/simple_client.html',_16044,_16046),newTo:'/static/simple_client.html']
% [Thread httpd@9999_4] [1] 301 moved(/static/simple_client.html); 366 bytes
% [Thread httpd@9999_1] [2] get /static/simple_client.html ...
% [Thread httpd@9999_1] [2] 200 file(text/html; charset=UTF-8,/home/peter/src/swipl-server-js-client/static/simple_client.html); 2,038 bytes
% [Thread httpd@9999_4] [3] get /static/simple_client.css ...
% [Thread httpd@9999_4] [3] 200 file(text/css; charset=UTF-8,/home/peter/src/swipl-server-js-client/static/simple_client.css); 402 bytes
% [Thread httpd@9999_2] [4] get /static/simple_client.js ...
% [Thread httpd@9999_2] [4] 200 file(text/javascript; charset=UTF-8,/home/peter/src/swipl-server-js-client/static/simple_client.js); 4,474 bytes
% [Thread httpd@9999_5] [5] get /static/favicon.ico ...
% [Thread httpd@9999_5] [5] 200 file(image/x-ico,/home/peter/src/swipl-server-js-client/static/favicon.ico); 32,038 bytes

The request for /static/simple_client.html is from the redirect; the other requests are from these lines in simple_client.html:

<link rel="shortcut icon" type="image/x-icon" href="favicon.ico"/>
<link rel="stylesheet" href="simple_client.css"/>
<script src="simple_client.js" defer="defer"></script>

Why not simply http_redirect/3? And note there is since not-too-long uri_edit/3 which simplifies the rewriting a lot.

I still can’t understand, you are doing a redirect, but I don’t need a redirect. I have a website in the static folder. I just want that if they access the /run path, then the files should be loaded from the static folder, if they access /_app/, then the files should be loaded from this folder

I managed to launch the application, but there are errors that I do not understand.

[Thread httpsd8083_1] [1] 200 file(text/html; charset=UTF-8,/home/oper/Programs/ptasker/static/index.html); 1,054 bytes
Warning: [Thread httpsd8083_5] Illegal HTTP request: AUTH_ID=2de655d985e62541b678ce09c010d&AUTH_EXPIRES=3600&REFRESH_ID=487b8d650068f16005ff42739684a93723f089&member_id=bf771deb0c0&status=L&PLACEMENT=MENU&PLACEMENT_OPTIONS=%7B%22ID%22%3A%221015091%22%7DGET /_app/immutable/entry/start.2113177d.js HTTP/1.1 (in_http_request)
% [Thread httpsd8083_5] [0] 400 ERROR: Illegal HTTP request: AUTH_ID=58fc65650068f1de655d985e62541b678ce09c010d&AUTH_EXPIRES=3600&REFRESH_ID=487b8d650ff42739684a93723f089&member_id=bf778c79b61deb0c0&status=L&PLACEMENT=MENU&PLACEMENT_OPTIONS=%7B%22ID%22%3A%221015091%22%7DGET /_app/immutable/entry/start.2113177d.js HTTP/1.1 (in_http_request)

Getting an initial SWI-Prolog web site up and not understanding the errors, how to get more information and how to fix it can be hard.

I passed the log info you noted to ChatGPT and it noted that you did get a valid index.html reply but that the second request was malformed. Without seeing your code not much more can be done. I am not asking to see your code and debug your problem but others might, so posting it could help.

Often what I have to fall back to in getting a site up is to start with a good working example and then modify it with small steps at a time until it is what I need.

Before LLMs such as ChatGPT came along this was really hard but I have found that ChatGPT can give some ideas for the Prolog, but that the exact Prolog code is often wrong, and help with other parts such as the JavaScript, HTML, CSS and such and that is often of a higher quality but still may have some errors. Also if LLM gives you something wrong, take the error from that and give it back to the LLM and it might give you a better reply. After about five feedbacks, it then becomes of no value so you have to resort to other methods or restart with a new problem or new question.

HTH

If tells you that the HTTP request could not be parsed. Now this may be an issue with http_read_request/2. I don’t recall to ever have seen that message unless creating a request by hand. You can inspect the full negotiation using

?- debug(http(_)).

Or trace the execution using

?- tspy(http_read_request/2).

Which tool/browser is creating the request?

1 Like
% [Thread httpsd8083_5] [1] 200 file(text/html; charset=UTF-8,/home/oper/Programs/ptasker/static/index.html); 1,054 bytes
% [Thread httpsd8083_5] 4 waiting for work; ok
% [Thread httpsd8083_1] Waiting for a job ...
% [Thread httpsd8083_1] Got job requeue(<stream>(0x253f500),<stream>(0x253f400),server_rpc:http_dispatch,[protocol(https),peer(ip(79,105,116,32
)),pool(client(httpsd8083,server_rpc:http_dispatch,<stream>(0x253f500),<stream>(0x253f400)))])
% [Thread httpsd8083_1] Waiting for keep-alive ...
% [Thread httpsd8083_1]         re-using keep-alive connection
% [Thread httpsd8083_1] Running server goal server_rpc:http_dispatch on <stream>(0x253f500) -> <stream>(0x253f400)
% [Thread httpsd8083_1] First line: AUTH_ID=ae7d66650068f16014ecb9e8957971f38b&AUTH_EXPIRES=3600&REFRESH_ID=9efc8d650068f160002c465e19e97e6892ed8&member_id=bf778c71deb0c0&status=L&PLACEMENT=MENU&PLACEMENT_OPTIONS=%7B%22ID%22%3A%221015105%22%7DGET /_app/immutable/entry/start.2113177d.js HTTP/1.1
% [Thread httpsd8083_1] Header = 
Host: v.hopto.org:8083
Connection: keep-alive
sec-ch-ua: "Not)A;Brand";v="24", "Chromium";v="116"
Origin: https://v.hopto.org:8083
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
sec-ch-ua-platform: "Linux"
Accept: */*
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: script
Referer: https://v.hopto.org:8083/courier?DOMAIN=v.ru&PROTOCOL=1&LANG=ru&APP_SID=9e09edf6182ce00f39e05e9d320c0953
Accept-Encoding: gzip, deflate, br
Accept-Language: ru,en;q=0.9,ru-RU;q=0.8,en-US;q=0.7
Cookie: cotonic-sid=86c7eb02-5cea-66c2-738a-8083fb861056



% [Thread httpsd8083_1] Field: [host('v.hopto.org'),port(8083),connection('keep-alive'),sec_ch_ua('"Not)A;Brand";v="24", "Chromium";v="116"'),origin('https://v.hopto.org:8083'),sec_ch_ua_mobile('?0'),user_agent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'),sec_ch_ua_platform('"Linux"'),accept([media(_4312/_4314,[],1.0,[])]),sec_fetch_site('same-origin'),sec_fetch_mode(cors),sec_fetch_dest(script),referer('https://v.hopto.org:8083/courier?DOMAIN=v.ru&PROTOCOL=1&LANG=ru&APP_SID=9e09edf9e05e9d320c0953'),accept_encoding('gzip, deflate, br'),accept_language('ru,en;q=0.9,ru-RU;q=0.8,en-US;q=0.7'),cookie(['cotonic-sid'='86c7eb02-5cea-66c2-738a-8083fb861056'])]
Warning: [Thread httpsd8083_1] Illegal HTTP request: AUTH_ID=ae7d66650068f16ba614ecb9e8957971f38b&AUTH_EXPIRES=3600&REFRESH_ID=9efc8d650068f16049038e7548b365e19e97e6892ed8&member_id=bf778c7d15521619b61deb0c0&status=L&PLACEMENT=MENU&PLACEMENT_OPTIONS=%7B%22ID%22%3A%221015105%22%7DGET /_app/immutable/entry/start.2113177d.js HTTP/1.1 (in_http_request)
% [Thread httpsd8083_1] < HTTP/1.1 400 Bad Request
Date: Tue, 28 Nov 2023 22:54:23 GMT
Connection: close
Content-Length: 716
Content-Type: text/html; charset=UTF-8


% [Thread httpsd8083_1] [0] 400 ERROR: Illegal HTTP request: AUTH_ID=ae7d66650068f1614ecb9e8957971f38b&AUTH_EXPIRES=3600&REFRESH_ID=9efc8d650068f160002c4d40000000b365e19e97e6892ed8&member_id=bf778c7d119b61deb0c0&status=L&PLACEMENT=MENU&PLACEMENT_OPTIONS=%7B%22ID%22%3A%221015105%22%7DGET /_app/immutable/entry/start.2113177d.js HTTP/1.1 (in_http_request)
% [Thread httpsd8083_1] Closing connection from ip(179,115,116,32)
% [Thread https@8083] New HTTPS connection from ip(179,115,116,32)
% [Thread https@8083] 5 waiting for work; ok
% [Thread httpsd8083_5] Waiting for a job ...
% [Thread httpsd8083_5] Got job ssl_client(<ssl_context>(0x1ec33c0),<socket>(0x27c4090),server_rpc:http_dispatch,ip(79,105,116,32))

If you don’t want redirection, you can change the http_handler/3 for root(.) to be what my handler for static(.) does. See also the http:location/3 facts.

I call http_redirect/3 at the end of my http_handler_redirect/3 … looking at the code for http_redirect/3, I see that I’ve duplicated a certain amount of what http_redirect/3 does. I wrote the sample code a while ago, and don’t remember why I didn’t use http_redirect/3 directly … I’ll try to simplify the code and report back here (hopefully, within a day or two).

In RFC 2616, we find

Request-Line   = Method SP Request-URI SP HTTP-Version CRLF

That turns the above to be invalid. Now RFC 2616 is replaced by RFC9110. That is a bit hard to read completely. I didn’t find any evidence of change to this with some searches.

Does anyone have an idea? In theory it could be left over from a previous request as we are looking at a Keep-alive connection. The fact that there is no newline before the GET makes that less likely.

From previous post, it looks like the OP is using the http_client libraries in SWI to call back into itself, so maybe there is a bug in the client libraries where the method ends up not being the first part of the request. Maybe the OP can show the http_get call?

:- http_handler(root(courier), http_reply_from_files(static_dir(.), [cache(true)]), [prefix]).
:- http_handler(root(.), http_reply_from_files(static_dir(.), [cache(true)]),
                [prefix]).

I have this code

We have seen that, but it seems there is an invalid request. What created that? It you want this sorted out, you’ll have to produce a setup that allows others to reproduce what is happening, including the client side in this case as that looks suspicious. Alternatively, use/add the Prolog debugging services, network sniffers, etc. to figure out what is wrong.

This seems a weird issue. It is very hard to debug such things from little bits of information without access to the whole story. It asks others to guess and try to reconstruct the whole picture, which is time consuming and most of the time we’ll get it wrong and make the wrong assumptions.

1 Like

the request comes from an external system. My page is displayed in a frame. Could this be related?

For more details on what can help us please read:

Minimal and reproducible working examples