Brief
You are building a web browser in Python — small, slow, incomplete, and real. Given a URL, your program fetches the page, parses its HTML and CSS, computes a layout, paints it into a window, and eventually runs its JavaScript. Web Browser Engineering (Panchekha & Harrelson) is the guide; this subject states what each stage must deliver and how to prove it, so the book keeps the prose and you keep the checklist.
Instructions
Work the stages in order; each leaves a browser that runs.
Stage 1 — URL to pixels
- Parse a URL into scheme/host/port/path yourself. Open a TCP socket, wrap it in TLS for
https, send an HTTP/1.1 GET withHost, and split the response into status line, headers, body. - Strip tags naively and draw the text in a desktop window (Tkinter canvas), wrapping at the window edge, with working scroll (keys and/or wheel).
Stage 2 — Trees
- HTML lexer/parser: tokenize into tags and text, then build a DOM tree. Handle attributes, comments, and the malformed-markup reality: implicit tags and unclosed elements must not crash the parse.
- Layout tree: build a tree of layout objects mirroring the DOM's block structure;
compute each box's
x,y,width,height— block layout stacking vertically, text laid out into lines within blocks. Painting now walks the layout tree via a display list, not the token stream.
Stage 3 — Style
- Parse CSS (selectors + declarations) from both the browser default stylesheet and linked/author sheets.
- Implement selector matching, specificity-ordered cascade, and inheritance for
inheritable properties; resolve a computed style per DOM node and drive layout/paint
from it (
<b>bolds because a rule says so, not a hardcoded tag check).
Stage 4 — Browser chrome
- Draw chrome around the page: an address bar you can type a URL into, and back navigation over a history stack.
- Make links clickable: map a click's coordinates back through the layout tree to the
element, follow the
href. - Forms: input fields you can focus and type into, submit buttons that build and send an HTTP POST request body.
Stage 5 — JavaScript
- Embed a JS engine (DukPy), expose DOM bindings (
document.querySelectorAll, attribute/content access, basic mutation) as your registered functions bridging into Python. - Run inline and linked scripts; wire event handlers (
click,keydown, formsubmitwithpreventDefault) so a page's script can react to and cancel user actions — the single-threaded event loop, seen from the implementer's side.
Constraints
- Python throughout; standard library plus Tkinter and (for stage 5) DukPy — no
requests, no HTML/CSS parsing libraries, no layout engine imports. - Write every line yourself; the book's code is reference, not a paste source.
- Keep each stage's browser runnable end to end — no "it will work again after stage N+1".
Acceptance
Mapped one-to-one onto the exercise's milestones:
- Bytes on screen —
python browser.py https://example.org/opens a window showing the page text; a page taller than the window scrolls; bothhttpandhttpsfetch. - Trees — a nested test page renders with correct block positions; a deliberately
malformed page (unclosed
<p>, stray</b>) still parses to a sensible DOM; dumping the layout tree shows computed sizes/positions for every box. - Style — an author stylesheet changes rendering without code changes; a
more-specific selector beats a less-specific one; a child inherits
colorfrom its parent; default styling comes from the browser stylesheet, not tag-name conditionals. - A real browser — you can type a URL in the address bar, click a link, go back, and submit a form whose POST reaches the server (verify against a local echo server).
- JavaScript — a page whose script mutates the DOM re-renders to show the change;
a
clickhandler fires; a form'ssubmithandler can cancel submission.
Related
- Toy browser engine — the exercise this is the subject of.
- Web Browser Engineering — the book carrying the prose, chapter by chapter, for every stage above.