diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-03 09:43:07 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-04 12:52:53 +0200 |
| commit | 2ca7ba8642e81e400a8f3145a15e3f6328b36a28 (patch) | |
| tree | c3a13b6238c411c8b965a5cdc652b6871e942a13 /src/requestinterceptor.cpp | |
| parent | cf8edbf6bc5a3d9131fb095f573cbef70d61202e (diff) | |
| download | qtmaildir-2ca7ba8642e81e400a8f3145a15e3f6328b36a28.tar.gz qtmaildir-2ca7ba8642e81e400a8f3145a15e3f6328b36a28.zip | |
fix: render the message pane at all
Clicking a thread left the pane blank. Two independent bugs, both from the
same false premise: that setHtml() navigates to the base URL it is given.
It does not. setHtml() navigates to a data: URL carrying the markup and
applies the base URL afterwards, purely as the document's origin. Verified
empirically on Qt 6.11.
Built on that wrong assumption were:
- MessagePage::acceptNavigationRequest compared the navigation's URL
against documentUrl() and rejected everything else, so the document load
was refused. It now accepts a typed main-frame navigation, which is one
we initiated ourselves.
- RequestInterceptor exempted exactly the qtmaildir: base URL and denied
everything else, so the data: document load was blocked too.
The interceptor fix is scoped to ResourceTypeMainFrame rather than allowing
the data: scheme outright. A blanket allow would have been a real hole: a
message body can write <img src="data:..."> or an iframe, and the existing
dataSchemeBlocked test in test_interceptor.cpp was right to fail when that
was tried. Sub-resource data: URLs remain denied.
Note this was never working. The drafted version had the same defect in a
different spelling (it compared url.scheme() rather than the whole URL, and
would have rejected the data: navigation just the same), and task 11 shipped
with no runtime test to catch it. test_messageview.cpp now pins all three
facts: the document loads, its text reaches the page, and a data: image
inside a hostile body stays blocked.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/requestinterceptor.cpp')
| -rw-r--r-- | src/requestinterceptor.cpp | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/src/requestinterceptor.cpp b/src/requestinterceptor.cpp index 8fd2419..6267b64 100644 --- a/src/requestinterceptor.cpp +++ b/src/requestinterceptor.cpp @@ -14,8 +14,13 @@ bool RequestInterceptor::shouldAllow(const QUrl &url) // by unusual casing, in either the allow or the deny direction. const QString scheme = url.scheme(); - // The document itself is loaded via setHtml() with a qtmaildir: base URL, - // so a request for exactly that URL must pass or nothing renders at all. + // data: is never allowed here. It is permitted for the main-frame + // document only, which is handled in interceptRequest() where the resource + // type is known: a message body can put data: in <img src> or + // <iframe src>, and those must stay blocked. + + // The document's origin is the qtmaildir: base URL, so requests can still + // arrive on that scheme once the document is live. // This is the ONLY trusted qtmaildir: URL: everything else on this scheme // is denied, including sub-paths of it. A hostile message body can put // arbitrary qtmaildir: URLs in <img src>, <link href>, etc., so this @@ -64,6 +69,23 @@ bool RequestInterceptor::shouldAllow(const QUrl &url) void RequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) { + // The main-frame document arrives as a data: URL, because setHtml() does + // not fetch the base URL it is given: it navigates to a data: URL carrying + // the markup and applies the base URL afterwards as the document's origin. + // (Verified empirically on Qt 6.11. The qtmaildir: rule in shouldAllow() + // was written on the opposite assumption, and until this was found every + // document load was blocked and the pane rendered blank.) + // + // Scoping this to ResourceTypeMainFrame is what keeps it from being a + // hole: those bytes are the ones HtmlBuilder produced a moment earlier and + // they arrive in the navigation itself rather than over any transport, + // while a data: URL written into a message body reaches this function as + // an image, stylesheet or subframe and is still denied by shouldAllow(). + if (info.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeMainFrame + && info.requestUrl().scheme() == QLatin1String("data")) { + return; + } + if (!shouldAllow(info.requestUrl())) info.block(true); } |
