mattcasters opened a new issue, #8297:
URL: https://github.com/apache/hop/issues/8297

   ### Apache Hop version?
   
   2.20.0
   
   ### Java version?
   
   OpenJDK 21
   
   ### Operating system
   
   Docker
   
   ### What happened?
   
   ## Description
   
   Opening any `.html` / `.htm` file in the **File explorer** perspective on 
**Hop Web** shows the markup but not the site. Stylesheets, images, scripts, 
and relative links do not load.
   
   This is not a bug in the HTML files. Desktop Hop GUI is fine (`file:` URLs 
resolve against the file on disk). Hop Web injects the file with RAP 
`Browser.setText()`, which has **no document URL**, so the browser resolves 
relative references against the Hop Web UI origin.
   
   Typical 404s in the browser network tab:
   
   ```
   https://<hop-web-host>/ui/assets/css/hop-doc.css
   https://<hop-web-host>/assets/css/hop-doc.css
   https://<hop-web-host>/ui/images/logo.png
   ```
   
   The files live next to the HTML on the **Tomcat host**, not under the RAP 
entry point. Self-contained documentation sets (external CSS/JS, nested pages, 
relative `../` links) are unusable in explorer. Plugin help HTML with relative 
images/links has the same problem.
   
   `http://` / `https://` filenames already call `Browser.setUrl()` and work. 
Local / VFS files do not.
   
   ## Environment
   
   - Hop 2.19.x / 2.20.0-SNAPSHOT
   - Hop Web (RAP) behind a TLS reverse proxy (Caddy/nginx) is the production 
case; same failure on a direct `http://localhost:8080/ui` for relative assets
   - Reproduced by opening any multi-file HTML tree from explorer (project 
docs, plugin docs, a folder with `index.html` + `assets/css/…`)
   
   ## Steps to reproduce
   
   1. Start Hop Web.
   2. Open a project that contains an HTML file with a relative stylesheet, for 
example:
   
   ```html
   <!DOCTYPE html>
   <html>
   <head>
     <link rel="stylesheet" href="assets/css/site.css">
   </head>
   <body>
     <h1>Hello</h1>
     <p>This should be styled.</p>
     <p><a href="other.html">other page</a></p>
   </body>
   </html>
   ```
   
   with `assets/css/site.css` next to it (or one directory up with 
`../assets/css/site.css`).
   
   3. In **File explorer**, double-click the HTML file.
   4. Optionally open DevTools → Network.
   
   ## Expected
   
   The page renders with its CSS, images, and in-page links, as it does when 
the same folder is opened in a desktop browser via `file:` / `http:`.
   
   ## Actual
   
   Unstyled HTML. CSS/image requests go to the Hop Web UI origin and 404. 
Clicking a relative link leaves the RAP app or 404s. Nested pages with 
`../../assets/css/…` fail the same way; fixing the number of `../` segments in 
the generator does not help.
   
   ## Root cause
   
   `HtmlExplorerFileTypeHandler.reload()`:
   
   ```java
   // plugins/transforms/textfile/.../HtmlExplorerFileTypeHandler.java
   if (filename starts with http:// or https://) {
     wBrowser.setUrl(filename);
     return;
   }
   String htmlContent = readTextFileContent(UTF_8);
   wBrowser.setText(htmlContent);  // no document base
   ```
   
   On RAP, `Browser.setText()` puts markup in an iframe without a URL for that 
document. Relative `href` / `src` resolve against `https://<host>/ui/…` (or 
`/`). The HTML on disk is never used as the base.
   
   A `<base href="file:…">` tag would not help on Hop Web: the files are on the 
server, and the user’s browser cannot read `file:` URLs on Tomcat.
   
   ## Related (same class of bug)
   
   `PdfExplorerFileTypeHandler` uses 
`wBrowser.setUrl(HopVfs.getFileObject(filename).getURL())`, i.e. `file://` on 
the server. That also cannot work in the user’s browser on Hop Web.
   
   Markdown preview that `setText()`s generated HTML with relative assets would 
hit the same limit.
   
   ## What does *not* work as a plugin workaround
   
   A plugin can register a RAP `ServiceHandler` and try 
`Browser.setUrl(handlerUrl)` for its own docs. That is incomplete:
   
   1. Explorer still binds `*.html` to `HtmlExplorerFileType`. A custom type 
that only claims a fake extension never wins on double-click.
   2. Paint-listener swaps of `TreeItemFolder.fileType` are racy (`asyncExec`, 
and listeners run before `setTreeItemData`).
   3. Turning `RWT.getServiceManager().getServiceHandlerUrl(id)` into an 
**absolute** URL via `HttpServletRequest.getRequestURL()` breaks behind 
TLS-terminating reverse proxies. Hop already documents this in 
`RapHopWebUrlUpdater`: the browser origin is `https://…` while 
`getRequestURL()` is often `http://<upstream-host>/ui`, so the explorer if
   rame is mixed-content-blocked.
   
   Hop’s canvas already does this correctly with a **relative** handler URL:
   
   ```javascript
   // rap/.../canvas-svg.js
   connection.getUrl()
     + "?servicehandler=" + encodeURIComponent(serviceId)
     + "&cid=" + encodeURIComponent(connection.getConnectionId());
   ```
   
   registered from `HopWeb` as `application.addServiceHandler("canvasRender", 
…)`.
   
   ## Proposed fix
   
   Add a Hop Web **explorer file** RAP `ServiceHandler` (same pattern as 
`CanvasRenderServiceHandler`) and use it from the HTML (and PDF) explorer 
handlers when `EnvironmentUtils.getInstance().isWeb()`.
   
   Suggested shape:
   
   - Register once from `HopWeb` / RAP application config, e.g. 
`servicehandler=explorerFile`.
   - Query parameters: current RAP `cid` plus a **relative** file path (or an 
opaque, session-scoped token — not a raw filesystem path in the URL if that is 
a concern).
   - Handler reads the file through `HopVfs` from the **current project / 
last-opened explorer root** (or a session map of allowed roots registered when 
the tab opens).
   - Reject `..`, absolute paths, and unknown extensions. Allow a small set: 
`html`, `htm`, `css`, `js`, `png`, `jpg`, `svg`, `gif`, `webp`, `ico`, `woff`, 
`woff2`, `ttf`, `pdf`, …
   - Set `Content-Type` correctly (`text/html`, `text/css`, 
`application/javascript`, `application/pdf`, image types).
   - For HTML/CSS responses, either:
     - **A (preferred):** `Browser.setUrl(relativeHandlerUrl + "&file=" + 
encodedRelativePath)` so the iframe **has** a document URL. Relative 
`href`/`src` then resolve against the handler; nested `../assets/css/foo.css` 
just works; **or**
     - **B:** rewrite relative `href`/`src`/`url()` in HTML/CSS to handler URLs 
before writing the response (needed if the iframe URL cannot preserve a 
directory base).
   
   **URL construction must stay relative** (path + query, including `cid`). Do 
not absolutize with `request.getRequestURL()`. If a public absolute URL is ever 
needed, follow `RapHopWebUrlUpdater.publicOrigin()` (`X-Forwarded-Proto` / 
`X-Forwarded-Host`).
   
   Desktop SWT path stays as today (`setText` is acceptable there only if SWT 
WebKit still resolves against `file:`; otherwise desktop can keep using `file:` 
via `setUrl`).
   
   ## Security
   
   The handler is reachable from the user’s browser. It must not become an 
arbitrary file read:
   
   - Scope to the Hop project folder / explorer root for that RAP session.
   - Canonicalize and reject paths that escape the root.
   - Allow-list extensions.
   - Require a valid RAP connection id (`cid`), same as `canvasRender`.
   
   ## Tests
   
   - Unit: path sandbox (reject `../`, absolute, unknown extension); 
content-type map; relative URL join for nested HTML 
(`workflows/workflows/page.html` + `../../assets/css/x.css` → 
`assets/css/x.css`).
   - Unit: handler URL is relative (starts with `?` or `/ui?`, never `http://`).
   - Hop Web IT (if feasible): open an HTML fixture with a sibling CSS file 
from explorer; assert the stylesheet request hits `servicehandler=explorerFile` 
and returns 200.
   
   ## Workaround
   
   Open the same HTML in a real browser (desktop `file:`, or copy the folder to 
a static HTTP root). The Hop Web explorer tab cannot host a multi-file HTML 
site until this lands.
   
   
   ### Issue Priority
   
   Priority: 2
   
   ### Issue Component
   
   Component: Hop Web


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to