Skip to content

#33547 fix(confluence): stop fetching external DTD in repairPageContent#10

Open
micharoesler wants to merge 1 commit into
mainfrom
fix/33547
Open

#33547 fix(confluence): stop fetching external DTD in repairPageContent#10
micharoesler wants to merge 1 commit into
mainfrom
fix/33547

Conversation

@micharoesler

Copy link
Copy Markdown
Contributor

Zusammenfassung

Behebt die PHP-Warnung aus artemeon/core-ng#33547:

DOMDocument::validate(http://www.w3.org/TR/REC-html40/loose.dtd): Failed to open stream: HTTP request failed!

Problem

Beim Herunterladen von Seiteninhalten normalisiert ConfluencePageContentDownloader::repairPageContent() das HTML mittels DOMDocument. Dabei wurde DOMDocument::validate() aufgerufen. Diese Methode validiert das Dokument gegen die im Doctype referenzierte DTD – bei Confluence-Inhalten ist das die HTML-4.0-Transitional-DTD unter der URL http://www.w3.org/TR/REC-html40/loose.dtd.

Dadurch löste jeder Seiten-Download einen ausgehenden HTTP-Request an w3.org aus, um diese DTD (~45 KB) zu laden. In abgeschotteten Umgebungen ohne ausgehenden Internetzugang (z. B. beim betroffenen Kunden DZ Privatbank) schlägt dieser Request fehl, und PHP gibt die oben genannte Warnung aus. libxml_use_internal_errors(true) unterdrückt das nicht, da es sich um eine Warnung des PHP-Stream-Wrappers und nicht um einen libxml-Fehler handelt.

Warum wir den Code ändern und nicht die Umgebung

Es handelt sich nicht um ein reines Umgebungsproblem, sondern um einen Fehler im Code:

  • Der validate()-Aufruf hat hier keinen funktionalen Nutzen. Sein Rückgabewert steuerte lediglich, ob der Body-Inhalt extrahiert wird. Confluence-Storage-Format ist nie gültiges HTML 4.0 (es enthält eigene <ac:...>-Tags), daher lieferte validate() faktisch immer false und der Extraktions-Zweig lief ohnehin. Das Entfernen ist für alle realen Eingaben verhaltensneutral.
  • Der Aufruf erzeugt einen unnötigen Netzwerk-Request ins öffentliche Internet bei jedem Seiten-Download – ein Defekt unabhängig von der Umgebung. Auch mit Internetzugang bedeutet das zusätzliche Latenz und eine externe Abhängigkeit von der Verfügbarkeit von w3.org.

Die fehlende Netzwerkverbindung in der Kundenumgebung legt den latenten Fehler lediglich offen. Eine Umgebungslösung (Freischaltung von w3.org) würde die überflüssige Abhängigkeit nur kaschieren – die falsche Ebene. Eine Offline-HTML-Bereinigung darf keinen Internetzugang voraussetzen.

Änderungen

  • DOMDocument::validate() entfernt; der Dokument-Wrapper wird nun immer auf das Body-Inner-HTML reduziert (das Verhalten, das bisher faktisch ohnehin lief).
  • Leerer Inhalt wird abgefangen – er löste zuvor eine nicht abgefangene ValueError aus loadHTML('') aus (separater latenter Fehler in derselben Methode).
  • LIBXML_NONET beim Parsen als zusätzliche Absicherung gegen Netzwerkzugriffe.
  • Offline-Regressionstest ergänzt, der einen vollständig gewrappten HTML-Inhalt (inkl. Doctype mit loose.dtd) auf das Body-Inner-HTML reduziert.

Alle Tests grün (22 Tests, 55 Assertions), PHPStan ohne Fehler.

Nach dem Merge

Jede:r aus dem Team kann diesen PR mergen – muss danach aber auch die folgenden Schritte durchführen (mit dem Merge allein ist es nicht getan).

Der eigentliche Fehler liegt in dieser Library (artemeon/confluence), nicht in artemeon/core-ng. core-ng konsumiert diese Library als Composer-Abhängigkeit. Daher nach dem Merge in dieser Reihenfolge:

  • Neue Version von artemeon/confluence taggen
  • Version releasen
  • Danach die Abhängigkeit in artemeon/core-ng aktualisieren, damit der Fix dort greift

Closes artemeon/core-ng#33547

DOMDocument::validate() validated the page content against the HTML 4.0
loose DTD referenced in its doctype, forcing an outbound HTTP request to
w3.org on every page download. In environments without outbound internet
access that request failed and PHP emitted:

  DOMDocument::validate(http://www.w3.org/TR/REC-html40/loose.dtd):
  Failed to open stream: HTTP request failed!

The validation had no functional value (Confluence storage format is never
valid HTML 4.0, so it always returned false and the body-extraction branch
ran regardless). Remove the validate() call and always strip the document
wrapper to the body inner HTML, eliminating the spurious network dependency
and the warning. Also guard empty content, which otherwise threw an
uncaught ValueError from loadHTML(), and pass LIBXML_NONET as defence in
depth. Adds an offline regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants