Try to load very large file in jsroot error (Accept-Ranges expected)

I have a minimal webpage in site-content/index.html with

 <script type='module'>
    import { openFile, draw } from 'https://root.cern/js/latest/modules/main.mjs';
    let file = await openFile('example.root');
</script>

I have example.root in the same folder. It is 77MB. I have not problem to open it in ROOT. I get the following error

First block is 1024 bytes but browser does not provides access to header - try to read full file
Try to load very large file 80562913 at once - abort
Fail to load url example.root?stamp=1716326372479
Try to load very large file 80562913 at once - abort
Fail to load url example.root
Uncaught Error: Fail to read with several ranges
    at XMLHttpRequest.read_callback (io.mjs:2830:31)
    at XMLHttpRequest.<anonymous> (core.mjs:890:140)
    at xhr.onreadystatechange (core.mjs:937:28)
    at XMLHttpRequest.<anonymous> (io.mjs:2758:26)

I tried with different web server with the same results.

  1. livepreview from vscode
  2. python -m http.server 8080
  3. docker run -it --rm -p 8080:80 --name web -v ./site-content:/usr/share/nginx/html nginx

I tried with Google Chrome and Firefox. This is the log from nginx

172.17.0.1 - - [21/May/2024:21:23:32 +0000] "GET / HTTP/1.1" 200 425 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" "-"
172.17.0.1 - - [21/May/2024:21:23:33 +0000] "GET /example.root?stamp=1716326613731 HTTP/1.1" 206 1024 "http://localhost:8080/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" "-"
172.17.0.1 - - [21/May/2024:21:23:34 +0000] "GET /example.root?stamp=1716326613731 HTTP/1.1" 200 11442264 "http://localhost:8080/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" "-"
172.17.0.1 - - [21/May/2024:21:23:34 +0000] "GET /example.root HTTP/1.1" 200 14498192 "http://localhost:8080/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" "-"
curl -I http://localhost:8080/example.root
HTTP/1.1 200 OK
Server: nginx/1.25.5
Date: Tue, 21 May 2024 22:50:50 GMT
Content-Type: application/octet-stream
Content-Length: 80562913
Last-Modified: Tue, 21 May 2024 21:12:56 GMT
Connection: keep-alive
ETag: "664d0e58-4cd4ae1"
Accept-Ranges: bytes
curl -I -r 0-1023  http://localhost:8080/example.root
HTTP/1.1 206 Partial Content
Server: nginx/1.25.5
Date: Tue, 21 May 2024 22:54:27 GMT
Content-Type: application/octet-stream
Content-Length: 1024
Last-Modified: Tue, 21 May 2024 21:12:56 GMT
Connection: keep-alive
ETag: "664d0e58-4cd4ae1"
Content-Range: bytes 0-1023/80562913

I am not sure to undertand this code

      if (res && first_req) {
            if (file.fAcceptRanges && !first_req.getResponseHeader('Accept-Ranges')) {
               file.fAcceptRanges = false;
               if (res?.byteLength === place[1]) {
                  // special case with cernbox, let try to get full size content
                  console.warn(`First block is ${place[1]} bytes but browser does not provides access to header - try to read full file`);
                  first_block_retry = true;
                  return send_new_request();
               }
            }

in io.mjs - Documentation

Why Accept-Ranges should be present in the header if the response is 206 Partial Content?
Actually that header is present if I read the full file.

It works with apache, since the response is

curl -I -r 0-1023  http://localhost:8080/example.root
HTTP/1.1 206 Partial Content
Date: Tue, 21 May 2024 23:08:58 GMT
Server: Apache/2.4.59 (Unix)
Last-Modified: Tue, 21 May 2024 21:12:56 GMT
ETag: "4cd4ae1-618fd482c4c5a"
Accept-Ranges: bytes
Content-Length: 1024
Content-Range: bytes 0-1023/80562913

in particular Accept-Ranges: bytes is present.

I don’t know: should one expect Accept-Ranges: bytes to be present even if the response if 206?

Hi,

It is not clearly stated in documentation, but not present in 206 request example.

Actually check in the jsroot code was due to other problem. In some cases browser just block access to any http header making impossible to handle partial requests. I will try to improve it.

Regards,
Sergey

Can you try dev version from https://jsroot.gsi.de/dev/modules/main.mjs

I modify detection of partial http response.

Thank you very much for your prompt reply. It works!

It works with nginx and apache.
Not working python python -m http.server
Not working in vscode live preview

Maybe these last two are too limited. I get

___vscode_liveprevie…injected_script:141 Server response size 80562913 larger than expected 11000000. Abort I/O operation
___vscode_liveprevie…injected_script:141 Try to load very large file 80562913 at once - abort
Fail to load url example.root

Not working python python -m http.server

This is known problem - it does not support multi-range requests.
The only chance to use it - provide settings.MaxRanges = 1 before loading first file.
I have workaround in JSROOT code (for my testing) - but it only activated when firefox browser is used.

Not working in vscode live preview

Looks like vscode does not support ranges requests at all - and jsroot makes failure when reading more than 50MB at once.

I add patch to jsroot 7.7.0 release

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.