Changeset c52dc82 in Klonkt for test


Ignore:
Timestamp:
07/28/2026 08:37:08 AM (6 weeks ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
3f32994
Parents:
0101d0a
Message:

Thumbnails ontbraken: providerlijst eruit, en grote pagina-s worden gelezen i.p.v. geweigerd

Twee bugs die elkaar maskeerden, allebei van mij.

DE PROVIDERLIJST WAS HET PROBLEEM, NIET DE OPLOSSING. Een YouTube-link matchte de
hardcoded lijst, kortsloot voor oEmbed, en kwam eruit als een kaart zonder titel
en zonder thumbnail. Er werd dus niets opgeslagen. YouTube levert gewoon oEmbed
en og:image, net als de rest, dus de generieke weg doet het beter dan het
speciale geval. De lijst is weg: geen whitelist meer om te onderhouden, en of een
embed getoond mag worden is een guardian-besluit, geen kwestie van welke host het
is.

DE BODY-CAP SLOEG DE KOP ERAF. Een pagina werd geweigerd als hij groot was.
YouTube propt ~665kB inline script voor zijn og:image en sluit <head> pas op
673kB, dus we knipten net voor de tags af en hielden niets over. Nu lezen we een
pagina vanaf het BEGIN en stoppen zodra we de tags hebben (of </head>), met 1MB
als achtervang. Een normale pagina kost daardoor nog steeds een paar tientallen
kB. Het scannen kijkt alleen naar het nieuwe stuk plus wat overlap, anders wordt
een pagina van 1MB kwadratisch werk.

Echt getest, niet aangenomen: youtube.com en youtu.be leveren nu titel +
thumbnail (oembed, ~2s), linuxguides ook, boiert.eu via opengraph in 144ms.

Changed files:
src/services/EmbedResolver.js

  • providerstap verwijderd uit de keten (AudioEmbedService blijft voor de web-spelers)
  • safeHead: streamt de kop, stopt bij og:image of </head>, cap 1MB
  • safeJsonText: JSON moet heel zijn, dus daar blijft weigeren juist

src/services/ActivityPubService.js

  • self-heal 16 -> 17, en nu ook rijen die eerder niets opleverden opnieuw proberen

test/embed-resolver.test.js

  • regressietest: een videohost is geen speciaal geval en krijgt een echte kaart
  • regressietest: een grote pagina wordt afgekapt, niet geweigerd

remarks: 214 tests groen.

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • test/embed-resolver.test.js

    r0101d0a rc52dc82  
    5252});
    5353
    54 test('a known provider beats oEmbed but loses to AP', async () => {
     54// Regression: a hardcoded provider list used to short-circuit here and return a
     55// card with no title and no thumbnail, so a YouTube link ended up storing
     56// nothing at all. There is no provider list any more; every non-fediverse URL
     57// takes the generic path, which is exactly what gives it a thumbnail.
     58test('a video host is not special-cased and still gets a real card', async () => {
    5559  const r = await resolveEmbed('https://youtu.be/abcdefghijk', io({
    56     provider: () => ({ provider: 'youtube', id: 'abcdefghijk' }),
     60    provider: () => ({ provider: 'youtube', id: 'abcdefghijk' }),   // ignored on purpose
    5761    getPage: async () => OEMBED_PAGE,
    5862    getJSON: async () => OEMBED_JSON,
    5963  }));
    60   assert.equal(r.kind, 'provider');
    61   assert.equal(r.provider, 'youtube');
     64  assert.equal(r.kind, 'oembed');
     65  assert.equal(r.title, 'A talk');
     66  assert.ok(r.media[0].url, 'and it has a thumbnail, which the old path never produced');
    6267});
    6368
     
    115120  };
    116121  const io = liveIO({ safeFetch: fakeFetch, detectProvider: () => null });
    117   assert.equal(await io.getPage('https://x/huge'), null, 'oversized body refused');
     122  // A JSON payload must parse whole, so an oversized one is refused outright.
     123  assert.equal(await io.getJSON('https://x/huge'), null, 'oversized JSON refused');
    118124  assert.equal(await io.getAP('https://x/boom'), null, 'a refused fetch is not an error');
    119125  assert.deepEqual(await io.getAP('https://x/ok'), { type: 'Note', id: 'https://s/1' });
     
    163169  assert.equal(r.url, 'https://lg.example/artikel');
    164170});
     171
     172// Regression, the one that kept YouTube blank: a page is read from the START and
     173// cut off, never refused for being large. Refusing it meant no thumbnail at all
     174// for exactly the sites people share most.
     175test('a huge page is truncated, not rejected', async () => {
     176  const { liveIO } = await import('../src/services/EmbedResolver.js');
     177  const big = '<html><head>' + 'x'.repeat(5000) + '<meta property="og:title" content="T">'
     178    + '<meta property="og:image" content="https://x/i.png"></head></html>';
     179  const fakeFetch = async () => ({ ok: true, headers: { get: () => String(9_000_000) }, text: async () => big });
     180  const io = liveIO({ safeFetch: fakeFetch, detectProvider: () => null });
     181  const page = await io.getPage('https://x/huge');
     182  assert.ok(page && page.includes('og:image'), 'the head survives the cap');
     183});
Note: See TracChangeset for help on using the changeset viewer.