| 14:07 | <smaug> | How should one interpret https://html.spec.whatwg.org/#active-parser "has not yet been stopped ". That stopped is a long algorithm spinning event loop and what not. Does "stopping" happen when that algorithm is about to be called, is being called or has been called? |
| 14:09 | <sfarre> | and follow up, sort of related question to ^ - if we have a page whose load event has not been fired yet, we navigate away, then back, restore from bfcache, should the load event be fired then? |
| 14:18 | <sfarre> | what I am referring to here, is an example where chrome puts a page in bfcache before the load event, and upon restore, does not fire a load event |
| 14:23 | <annevk> | I suspect instrumenting Claude with that question and telling it to write a bunch of tests would be a good start to figuring out what the solution will have to look like. These definitions are probably Hixie-era. (Looking at blame and trying to figure out what Hixie modeled it after might also give some clues.) |
| 14:23 | <sfarre> | It was that, that led me here :) |
| 14:24 | <sfarre> | #!/usr/bin/env python3
"""
Serve two pages to manually test BFCache with a static in-flight image.
Usage:
python3 bfcache-static-img-test.py
Open http://localhost:8383/page1, click the link to page2, then press Back.
The page will show whether it was restored from BFCache.
"""
import http.server
import struct
import time
import zlib
PORT = 8383
def make_png(width=128, height=128):
def chunk(ctype, data):
c = ctype + data
return struct.pack(">I", len(data)) + c + struct.pack(">I", zlib.crc32(c) & 0xFFFFFFFF)
raw = b""
for y in range(height):
raw += b"\x00" + b"\xff\x00\x00" * width
return (
b"\x89PNG\r\n\x1a\n"
+ chunk(b"IHDR", struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0))
+ chunk(b"IDAT", zlib.compress(raw))
+ chunk(b"IEND", b"")
)
IMAGE_PNG = make_png()
PAGE1 = b"""\
<!DOCTYPE html>
<html>
<head><title>Page 1 - static image loading</title></head>
<body>
<p>readyState: <span id="rs"></span></p>
<div id="result"></div>
<img src="/slow-image">
<p><a href="/page2">Navigate to page 2</a></p>
<script>
const rs = document.getElementById('rs');
const update = () => rs.textContent = document.readyState;
update();
document.onreadystatechange = update;
window.addEventListener('load', () => {
document.getElementById('result').textContent += 'load event fired\\n';
});
window.addEventListener('pageshow', e => {
if (e.persisted) {
document.getElementById('result').textContent += 'RESTORED FROM BFCACHE\\n';
document.getElementById('result').style.cssText =
'background:green;color:white;padding:1em;font-size:1.5em';
}
});
</script>
</body>
</html>
"""
PAGE2 = b"""\
<!DOCTYPE html>
<html>
<head><title>Page 2</title></head>
<body>
<p>Now press Back.</p>
</body>
</html>
"""
class Handler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/page1':
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.send_header('Content-Length', str(len(PAGE1)))
self.end_headers()
self.wfile.write(PAGE1)
elif self.path == '/page2':
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.send_header('Content-Length', str(len(PAGE2)))
self.end_headers()
self.wfile.write(PAGE2)
elif self.path == '/slow-image':
self.send_response(200)
self.send_header('Content-Type', 'image/png')
self.send_header('Content-Length', str(len(IMAGE_PNG)))
self.send_header('Cache-Control', 'no-store')
self.end_headers()
self.wfile.flush()
print(' [slow-image] headers sent, stalling 120s...')
time.sleep(10)
self.wfile.write(IMAGE_PNG)
print(' [slow-image] body sent')
else:
self.send_response(404)
self.end_headers()
def log_message(self, fmt, *args):
print(f' {fmt % args}')
if __name__ == '__main__':
server = http.server.ThreadingHTTPServer(('127.0.0.1', PORT), Handler)
print(f'http://localhost:{PORT}/page1')
try:
server.serve_forever()
except KeyboardInterrupt:
print()
simple python example
|
| 14:24 | <sfarre> | and i am expanding gecko behavior and realized I was also doing what chrome was doing, but I am not sure if thats right. dropping a load event seems iffy |
| 14:27 | <annevk> | So what I would do is find more cases where this is observable and make sure you have tests for all of them. Then contemplate what (a) good model(s) would look like and judge how likely they are/that is to be web-compatible and how it/they would fare against all the tests. |
| 14:28 | <smaug> | yeah, some .tentative tests would be good. |
| 14:28 | <Noam Rosenthal> | smaug: I read it as the first line of stopping/aborting the parser is to make it "not active". From a quick glance at the code that's what blink does but it's complex enough to miss some cases |
| 14:28 | <smaug> | (not firing load event at all does feel like a major bug) |
| 14:30 | <sfarre> | ok, I have a bunch of bfcache tests written, I'll make them tentative wpt instead of gecko local only and I'll see if I can whip up a tentative test for this as well |
| 14:35 | <annevk> | sfarre: sounds good; and link them from a specification issue. And if you're interested in taking it even further and proposing changes, that'd be most welcome too. |
| 14:43 | <sfarre> | thanks, I'll do that |
| 14:58 | <Noam Rosenthal> | https://github.com/whatwg/html/commit/0d896522e78a705d7a86563f71bd424ae037d495#diff-1bc04b5291c26a46d918139138b992d2de976d6851d0893b0476b85bfbdfc6e6R2659-R2672 has more of a note about it |