Send a rendering of the whole page with a capture, where the server keeps one #2

Open
opened 2026-09-29 12:34:22 +00:00 by tiagoagueda · 1 comment
Owner

Postulo can now keep the page a capture was read from (postulo/postulo#256, landed as 1527130dd): the source, and a rendering, a picture of the whole page. The server can draw a rendering from the kept source, but only the words, laid out with scripts and the network off. What only the browser can make is the page as the person was seeing it, signed in or behind bot protection. This issue is that half.

What the server already does with what the extension sends

  • Nothing changes for the source. The extension already sends html to POST /api/v1/captures, and it is kept wherever the instance and the account both keep sources (both off by default). To not keep it for one capture, add "keep": {"source": false}. keep has no other member and cannot switch keeping on.
  • Every capture in an answer carries page, in the 201 of POST /captures and on each row of GET /captures:
    source, rendering, rendering_type, accepts_rendering, rendering_url, rendering_types, rendering_max_bytes, note.

What the extension should do

  1. After a capture is made, read page. If accepts_rendering is false, or page is missing (an older server), send nothing more.
  2. Otherwise draw the whole page, not the viewport, as one of rendering_types (image/png, image/jpeg, image/webp, application/pdf), no larger than rendering_max_bytes. Ask before drawing, so nothing is drawn only to be refused.
  3. PUT it to rendering_url with the same bearer token (captures scope): the raw bytes as the body, Content-Type set to its type, and a Content-Length. Not JSON, not a form.
  4. Batches: send no rendering for the captures made from a results page.
Answer Meaning
201 Kept
200 Those exact bytes were already kept, so a retry after a lost reply is safe
409 #not-kept reason is switched-off, decided, already-kept or no-room: do not retry
413 #too-large Larger than max_bytes; said before the body was read
415 #unsupported-media-type Not one of accepted
411 No Content-Length
422 The first bytes are not what the type says
401 / 403 / 429 As on every call

Decisions for this repository

  • How to draw the whole page. chrome.tabs.captureVisibleTab gives the viewport only. The whole page means scrolling and stitching (which moves the page under the person and misdraws fixed headers), or the DevTools protocol's Page.captureScreenshot with captureBeyondViewport through the debugger permission, which shows a warning bar and is a permission worth refusing. Firefox's tabs.captureTab takes a rect in page coordinates. Each browser may need its own answer; the Firefox package is assembled from this one (postulo/postulo-firefox).
  • Size. A long page as a PNG can pass rendering_max_bytes (10 MB by default). JPEG or WebP at a stated quality, or a downscale, before sending; never send what rendering_max_bytes refuses.
  • Asking the person. A rendering is a picture of their screen, signed in or not, and it is kept on the server. The instance and the account have both said yes before accepts_rendering is true, but the popup should still say that a picture is being sent, and offer to skip it for this capture.
  • The popup's corrections go with the capture as today; the rendering is sent after the capture exists, never before.

Done when

  • A capture from a page longer than the window, against a server that accepts renderings, arrives with a rendering of the whole page, and the capture's page on the server shows it.
  • Against a server that does not, or an older one, the extension sends exactly what it sends today.
Postulo can now keep the page a capture was read from (postulo/postulo#256, landed as 1527130dd): the source, and a **rendering**, a picture of the whole page. The server can draw a rendering from the kept source, but only the words, laid out with scripts and the network off. What only the browser can make is the page **as the person was seeing it**, signed in or behind bot protection. This issue is that half. ## What the server already does with what the extension sends - **Nothing changes for the source.** The extension already sends `html` to `POST /api/v1/captures`, and it is kept wherever the instance and the account both keep sources (both off by default). To not keep it for one capture, add `"keep": {"source": false}`. `keep` has no other member and cannot switch keeping on. - **Every capture in an answer carries `page`**, in the `201` of `POST /captures` and on each row of `GET /captures`: `source`, `rendering`, `rendering_type`, `accepts_rendering`, `rendering_url`, `rendering_types`, `rendering_max_bytes`, `note`. ## What the extension should do 1. After a capture is made, read `page`. **If `accepts_rendering` is false, or `page` is missing** (an older server), send nothing more. 2. Otherwise draw **the whole page, not the viewport**, as one of `rendering_types` (`image/png`, `image/jpeg`, `image/webp`, `application/pdf`), no larger than `rendering_max_bytes`. Ask before drawing, so nothing is drawn only to be refused. 3. `PUT` it to `rendering_url` with the same bearer token (`captures` scope): the raw bytes as the body, `Content-Type` set to its type, and a `Content-Length`. Not JSON, not a form. 4. **Batches**: send no rendering for the captures made from a results page. | Answer | Meaning | | --- | --- | | `201` | Kept | | `200` | Those exact bytes were already kept, so a retry after a lost reply is safe | | `409` `#not-kept` | `reason` is `switched-off`, `decided`, `already-kept` or `no-room`: do not retry | | `413` `#too-large` | Larger than `max_bytes`; said before the body was read | | `415` `#unsupported-media-type` | Not one of `accepted` | | `411` | No `Content-Length` | | `422` | The first bytes are not what the type says | | `401` / `403` / `429` | As on every call | ## Decisions for this repository - **How to draw the whole page.** `chrome.tabs.captureVisibleTab` gives the viewport only. The whole page means scrolling and stitching (which moves the page under the person and misdraws fixed headers), or the DevTools protocol's `Page.captureScreenshot` with `captureBeyondViewport` through the `debugger` permission, which shows a warning bar and is a permission worth refusing. Firefox's `tabs.captureTab` takes a `rect` in page coordinates. Each browser may need its own answer; the Firefox package is assembled from this one (postulo/postulo-firefox). - **Size.** A long page as a PNG can pass `rendering_max_bytes` (10 MB by default). JPEG or WebP at a stated quality, or a downscale, before sending; never send what `rendering_max_bytes` refuses. - **Asking the person.** A rendering is a picture of their screen, signed in or not, and it is kept on the server. The instance and the account have both said yes before `accepts_rendering` is true, but the popup should still say that a picture is being sent, and offer to skip it for this capture. - **The popup's corrections** go with the capture as today; the rendering is sent after the capture exists, never before. ## Done when - A capture from a page longer than the window, against a server that accepts renderings, arrives with a rendering of the whole page, and the capture's page on the server shows it. - Against a server that does not, or an older one, the extension sends exactly what it sends today.
Author
Owner

Landed (5c7743d) except what needs a browser: src/lib/picture.js draws the whole page (captureTab with a rect on Firefox; scrolling and stitching on Chromium, no debugger permission) and the person is asked before it is sent. Never run for real, so the first Done when (a rendering visible on the server) is unconfirmed. See the manual-check issue.

Landed (`5c7743d`) except what needs a browser: `src/lib/picture.js` draws the whole page (`captureTab` with a rect on Firefox; scrolling and stitching on Chromium, no `debugger` permission) and the person is asked before it is sent. Never run for real, so the first *Done when* (a rendering visible on the server) is unconfirmed. See the manual-check issue.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo-chromium#2
No description provided.