diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml new file mode 100644 index 0000000..a350569 --- /dev/null +++ b/.github/workflows/makefile.yml @@ -0,0 +1,153 @@ +name: Build + +on: + push: + branches: [master] + tags: + - 'v*' + pull_request: + branches: [master] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-os3: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Build mcc + uses: docker://sacredbanana/amiga-compiler:m68k-amigaos + with: + args: sh -c "cd mcc && make clean && make OS=os3" + - name: Build mcp + uses: docker://sacredbanana/amiga-compiler:m68k-amigaos + with: + args: sh -c "cd mcp && make clean && make OS=os3" + - name: Verify build products + run: | + set -e + ls mcc/bin_os3/HTMLview.mcc + ls mcc/bin_os3/SimpleTest + ls mcc/bin_os3/LibLoad_Test + ls mcp/bin_os3/HTMLview.mcp + - name: Upload artifacts + uses: actions/upload-artifact@v7 + with: + name: htmlview-os3-${{ github.sha }} + if-no-files-found: error + path: | + mcc/bin_os3/*.mcc + mcc/bin_os3/SimpleTest + mcc/bin_os3/LibLoad_Test + mcp/bin_os3/*.mcp + + build-os4: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Build mcc + uses: docker://sacredbanana/amiga-compiler:ppc-amigaos + with: + args: sh -c "cd mcc && make clean && make OS=os4" + - name: Build mcp + uses: docker://sacredbanana/amiga-compiler:ppc-amigaos + with: + args: sh -c "cd mcp && make clean && make OS=os4" + - name: Verify build products + run: | + set -e + ls mcc/bin_os4/HTMLview.mcc + ls mcc/bin_os4/SimpleTest + ls mcc/bin_os4/LibLoad_Test + ls mcp/bin_os4/HTMLview.mcp + - name: Upload artifacts + uses: actions/upload-artifact@v7 + with: + name: htmlview-os4-${{ github.sha }} + if-no-files-found: error + path: | + mcc/bin_os4/*.mcc + mcc/bin_os4/SimpleTest + mcc/bin_os4/LibLoad_Test + mcp/bin_os4/*.mcp + + build-morphos: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Build mcc + uses: docker://sacredbanana/amiga-compiler:ppc-morphos + with: + args: sh -c "cd mcc && make clean && make OS=mos" + - name: Build mcp + uses: docker://sacredbanana/amiga-compiler:ppc-morphos + with: + args: sh -c "cd mcp && make clean && make OS=mos" + - name: Verify build products + run: | + set -e + ls mcc/bin_mos/HTMLview.mcc + ls mcc/bin_mos/SimpleTest + ls mcc/bin_mos/LibLoad_Test + ls mcp/bin_mos/HTMLview.mcp + - name: Upload artifacts + uses: actions/upload-artifact@v7 + with: + name: htmlview-morphos-${{ github.sha }} + if-no-files-found: error + path: | + mcc/bin_mos/*.mcc + mcc/bin_mos/SimpleTest + mcc/bin_mos/LibLoad_Test + mcp/bin_mos/*.mcp + + release: + needs: [build-os3, build-os4, build-morphos] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + permissions: + contents: write + steps: + - uses: actions/checkout@v5 + - name: Download all artifacts + uses: actions/download-artifact@v7 + with: + pattern: htmlview-* + path: artifacts/ + - name: Package release archives + run: | + set -euo pipefail + tag="${GITHUB_REF##*/}" + mkdir -p release + for platform in os3 os4 morphos; do + case "$platform" in + os3) bindir=bin_os3 ;; + os4) bindir=bin_os4 ;; + morphos) bindir=bin_mos ;; + esac + src="artifacts/htmlview-${platform}-${GITHUB_SHA}" + if [ ! -d "$src" ]; then + echo "Missing artifact for $platform at $src" >&2 + exit 1 + fi + pkg="HTMLview-${tag}-${platform}" + mkdir -p "release/${pkg}/mcc" "release/${pkg}/mcp" + cp "$src/mcc/${bindir}"/*.mcc "release/${pkg}/mcc/" + cp "$src/mcc/${bindir}"/SimpleTest "release/${pkg}/mcc/" + cp "$src/mcc/${bindir}"/LibLoad_Test "release/${pkg}/mcc/" + cp "$src/mcp/${bindir}"/*.mcp "release/${pkg}/mcp/" + for doc in README COPYING ChangeLog AUTHORS; do + [ -f "$doc" ] && cp "$doc" "release/${pkg}/" + done + (cd release && zip -r "${pkg}.zip" "${pkg}") + done + ls -la release/ + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + files: release/*.zip + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 6734284..76c1e67 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ bin_* .obj_* mcp/locale.* +MEMORY.md +.DS_Store +mcc/amissl_sdk/ diff --git a/AUTHORS b/AUTHORS index ee21782..d4ddfd4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,7 +2,7 @@ HTMLview.mcc - HTMLview MUI Custom Class Copyright (C) 1997-2000 Allan Odgaard - Copyright (C) 2005-2010 by HTMLview.mcc Open Source Team + Copyright (C) 2023-2026 Dimitris Panokostas This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,7 @@ design provided by the following people: Alfonso Ranieri Allan Odgaard +Dimitris Panokostas Dwight Meese Ilkka Lehtoranta Jens Langner diff --git a/ChangeLog b/ChangeLog index f5fc9ea..a65d9e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,13 +5,104 @@ MUI HTMLview MCC class - ChangeLog $Id$ $URL$ -2016-07-29 Thore Böckelmann +2026-05-01 Dimitris Panokostas + + * mcc/library.c: register ScrollGroupClass and StringClass via + CPPDISPATCHERENTRY() instead of bare ENTRY(). On AmigaOS 3 the + bare form passes the raw C++ dispatcher pointer to MUI, which then + calls it with cl/obj/msg in registers a0/a2/a1 -- a calling + convention the C++ function does not have. The result was a + register-convention mismatch that crashed inside intuition.library + with PC=0x2C2 the moment any caller tried to instantiate either + private class via NewObject(mcc_Class, ...). The main HTMLview + class was unaffected because mccinit.c already uses + CPPDISPATCHERENTRY for it. + * mcc/Dispatcher.cpp: harden the OM_NEW failure path. When + AllocSignal(-1) returns -1 we used to call CoerceMethod(cl, obj, + OM_DISPOSE), which re-enters our class's OM_DISPOSE against an + instance whose parse thread, message port and ParseThreadName are + not yet initialised. That tour of uninitialised state was harmless- + ish on MUI 3.x but rebooted MUI 4/5 reliably. We now free only + what the partial OM_NEW actually allocated (the SharedData) and + defer to cl->cl_Super OM_DISPOSE, mirroring the pattern already + used a few lines earlier for the SharedData allocation failure. + Surfaces as "Error creating MOAI object" instead of a hard reset + on signal-saturated tasks. + * mcc/Dispatcher.cpp: MUIA_HTMLview_Scrollbars no longer wraps the + gadget in a private ScrollGroupClass instance. Class-introspecting + callers (RapaGUI / Hollywood) treat the OM_NEW return as "the + HTMLview" and only translate their "Contents"/"URL"/etc. + properties to MUIA_HTMLview_* when the object actually looks like + one. The wrapper broke that detection, silently dropping property + writes. Returning the bare gadget always lets the caller's + introspection succeed. Apps that previously relied on us auto- + wrapping should now wrap externally with MUIC_Scrollgroup; see + mcc/SimpleTest.c for the canonical pattern. ScrollGroupClass is + still registered for callers that wire it up directly via + NewObject(mcc_Class, ...). + * mcc/Debug.cpp, mcc/Makefile: DEBUG=1 builds on OS3 used to fail to + link with a "multiple definition of kprintf" error -- Debug.cpp + defined its own kprintf and -ldebug pulled in another. Guard the + Debug.cpp definition with #ifndef DEBUG so it only compiles into + release builds, where -ldebug is not linked. + * mcc/RapaguiPattern_Test.c: new self-contained test program that + mimics the bare creation pattern used by MOAI / RapaGUI hosts + (no LoadHook tags, optionally signal-saturated via -burn N, and + optionally creating multiple gadgets via -many N). Used during + triage to reproduce the AllocSignal-failure path independently of + Hollywood. Wired into the OS3/OS4/MorphOS Makefile alongside + SimpleTest and LibLoad_Test. + +2026-04-20 Dimitris Panokostas + + * Release 13.6. + * mcc/rev.h, mcp/rev.h: bumped LIB_REVISION to 6, LIB_DATE to + 20.04.2026, and copyright range to 2005-2026. + * .github/workflows/makefile.yml: release job now packages each + platform's mcc/mcp binaries into a single versioned zip + (HTMLview--.zip) instead of uploading loose + files that collided across platforms via merge-multiple. + Debug/map artefacts and the test.png are stripped from the + release bundle; README, COPYING, ChangeLog and AUTHORS are + included. + +2026-04-18 Dimitris Panokostas + + * mcc/test_image_hook.h: HTTPS support via AmiSSL. The shared test-program + image hook now handles https:// URLs and follows http->https redirects + (up to five hops). TLS is wrapped through amisslmaster.library + + amissl.library (jens-maus AmiSSL 5.27 SDK), using the inline macros + against task-local library bases -- no stub lib link and no global + AmiSSLBase symbol required. Certificate verification is currently + VERIFY_NONE; CA bundle wiring is a follow-up. + * mcc/test_image_hook.h: Replaced unbounded sprintf into log buffers with + snprintf; a long Location: header or redirect target could otherwise + overflow the stack log buffer. + * mcc/Makefile: On-demand AmiSSL SDK download (lha xq). HTTPS is enabled + for OS3 and OS4 builds; MorphOS stays on plain HTTP. + * mcc/SimpleTest.c, mcc/LibLoad_Test.c: Added network-image test entries + (plain HTTP from aminet, http->https redirect on amigaworld, direct + HTTPS from aminet). + * mcc/LibLoad_Test.c: New test program that exercises the same hook as + SimpleTest but through dlopen-style library loading, making it easier + to verify the shipped HTMLview.mcc on each platform. + +2026-04-17 Dimitris Panokostas + + * mcc: Fix MorphOS MCP and OS4 MCC build issues; OS4 build now makes + -ldebug conditional and stubs kprintf when not building with DEBUG=1; + enabled all three platform builds (OS3, OS4, MorphOS) in CI. + * mcc/ImageManager.cpp, mcc/IM_Render.cpp, mcc/Dispatcher.cpp: Local + image rendering fixes uncovered by the new test programs (decoder + handshake, frame cleanup, hook dispatcher wiring on OS4). + +2016-07-29 Thore B�ckelmann * mcc: lots of changes to get this beast buildable with our Linux based cross compiler again with a mixture of C and C++ code plus explicit 68k register definitions which the g++ doesn't know. -2010-09-17 Pär Boberg +2010-09-17 P�r Boberg * mcp/locale/swedish.ct: new file generated by FlexCat 2.7. @@ -19,7 +110,7 @@ $URL$ * AUTHORS: added translators section (please check and update missing persons). -2010-05-19 Thore Böckelmann +2010-05-19 Thore B�ckelmann * mcp/locale: set some properties. @@ -37,11 +128,11 @@ $URL$ * include/mccinit.c: RTF_EXTENDED was not set for the MorphOS build making revision number ineffective. -2008-03-06 Pär Boberg +2008-03-06 P�r Boberg * mcp/locale/swedish.ct: added swedish translation. -2008-02-19 Thore Böckelmann +2008-02-19 Thore B�ckelmann * Debug.h: replaced all abort() usages in our ASSERT() macros with the respective calls to assert(). This should prevent the MorphOS compile @@ -60,7 +151,7 @@ $URL$ annoying if you are using HTMLview in a multitabs application. It seems that simply passing a SigBit allocated in the main application and letting all the HTMLview MsgPorts using it, - solve the whole problem. I tested it in strangé for some days + solve the whole problem. I tested it in strang� for some days and it works. It needed, of course to define a new tag. * I left a very high stack values used to run parsing threads @@ -180,7 +271,7 @@ $URL$ * mcc: fixed broken compilation due to recent changes. -2007-07-25 Thore Böckelmann +2007-07-25 Thore B�ckelmann * #?/library.c: now really uses the 3 parameter version of GETINTERFACE() defined in mccinit.c instead of the old obsolete version in mcc_common.h. @@ -193,7 +284,7 @@ $URL$ * include/mccinit.c: updated to latest 1.7 version -2007-07-24 Thore Böckelmann +2007-07-24 Thore B�ckelmann * include/mccinit.c: updated to latest 1.6 version which fixes an unbalanced if statement. @@ -208,7 +299,7 @@ $URL$ * include/mccinit.c: updated to latest 1.4 version and adapted all our library.c files to make use out of the new stack enforcing mechanisms. -2007-06-13 Thore Böckelmann +2007-06-13 Thore B�ckelmann * #?/Debug.c: unified the _DPRINTF() functions for all platforms. @@ -220,7 +311,7 @@ $URL$ 2007-06-10 Jens Langner * mcp: adapted source to compile with new mccinit.c instead of mccheader.c - * misc: integrated a large patch kindly provided by Jörg Strohmayer. Beside + * misc: integrated a large patch kindly provided by J�rg Strohmayer. Beside cleaning up the C++/C linkage some cleanups in the library init code should make htmlview.mcc less error prone. In addition, some fixes should finally enable us to build a running version which we can base our future changes @@ -228,13 +319,13 @@ $URL$ as well as integrating Gunther Nikl's image decoders source code into the repository as well. -2007-05-29 Thore Böckelmann +2007-05-29 Thore B�ckelmann * include/mccheader.c: reworked the LibOpen() and LibClose() functions to increment/decrement the lib_Open counter before obtaining the semaphore to prevent a possible race condition with LibExpunge(). -2007-03-23 Thore Böckelmann +2007-03-23 Thore B�ckelmann * #?/Debug.c: fixed wrong final output of debug classes and flags. @@ -294,7 +385,7 @@ $URL$ cleanly before we begin to hunt bugs. * mcc/mcp: replaced all GetAttrs()/get() uses with xget() -2007-03-12 Thore Böckelmann +2007-03-12 Thore B�ckelmann * #?/Debug.c: disabling a debug flag was not possible due to a check for the '!' at a wrong index. diff --git a/IMPROVEMENTS.md b/IMPROVEMENTS.md new file mode 100644 index 0000000..b14b032 --- /dev/null +++ b/IMPROVEMENTS.md @@ -0,0 +1,284 @@ +# HTMLview.mcc Improvement Plan + +Multi-session plan. Each phase is independently mergeable. Work top-down +unless a later phase is explicitly marked as dependency-free. + +**Status legend:** `[ ]` not started · `[~]` in progress · `[x]` done + +--- + +## Phase 1 — Extract net hook into reusable static library `[x]` + +**Goal.** Every consumer currently has to copy the ~600-line hook out of +`mcc/test_image_hook.h`. Move it into a proper library so bug fixes +propagate and later phases (TLS verify, cache, gzip, cookies) land in one +place. + +**Touches.** +- New: `mcc/net_hook/htmlview_nethook.h` — public API. +- New: `mcc/net_hook/htmlview_nethook.c` — implementation (code moved + from `test_image_hook.h`, no behavioural change). +- `mcc/Makefile` — add `libhtmlview_nethook.a` per-OS; link test programs + against it. +- `mcc/SimpleTest.c`, `mcc/LibLoad_Test.c` — drop `#include + "test_image_hook.h"`, call the new API. +- Delete `mcc/test_image_hook.h`. + +**Public API (initial).** +```c +ULONG HTMLviewNet_HookFunc(struct Hook *hook, APTR obj, + struct HTMLview_LoadMsg *msg); +void HTMLviewNet_InitHook(struct Hook *hook); /* sets h_Entry per-platform */ +``` + +**Acceptance.** +- OS3, OS4, MorphOS build clean via the Docker images in `MEMORY.md`. +- SimpleTest + LibLoad_Test still load local images, plain HTTP, HTTPS on + OS3/OS4 (MorphOS: HTTP only, unchanged). +- `libhtmlview_nethook.a` present in `bin_/` after a build. + +**Notes for the next session.** +- The hook already uses task-local bsdsocket bases; the host task never + needs to open bsdsocket. Drop those `OpenLibrary("bsdsocket.library")` + calls from both test programs. +- `HAVE_AMISSL` should be a per-object compile flag on the lib's `.o`, not + on every caller. Keep `AMISSL_SDK_READY` depending on the lib. + +--- + +## Phase 2 — Certificate verification `[x]` + +**Depends on:** Phase 1. + +**Goal.** Current TLS uses `SSL_VERIFY_NONE`. Anyone on the network can +MITM. Wire a CA bundle and flip to `VERIFY_PEER`. + +**Delivered.** +- `HTMLviewNet_SetCABundle(path)` — NULL restores auto-discovery. +- `HTMLviewNet_SetVerifyMode(mode)` — `AUTO` (default), `NONE`, `PEER`. +- AUTO discovers from: user override → `AmiSSL:Certs/curl-ca-bundle.crt` + → `ENVARC:AmiSSL/Certs/...` → `ENV:AmiSSL/Certs/...` + → `SYS:Storage/AmiSSL/Certs/...`. +- When verifying: `SSL_CTX_load_verify_locations` + `SSL_VERIFY_PEER` + and hostname check via `SSL_set1_host` (RFC 6125). +- Failure diagnostics log `X509_verify_cert_error_string()` so the user + can tell a cert issue from a handshake issue. +- Setters compile in non-AmiSSL builds too (MorphOS) to keep + cross-platform callers link-clean. + +**Notes for next session.** +- Cert store is re-loaded per-request (each transfer builds its own + SSL_CTX). Cheap enough for now; revisit if latency matters. +- `T:htmlview_hook.log` carries the verify decision ("CA bundle loaded + from …" or "no CA bundle found, continuing without verification"). + +--- + +## Phase 3 — On-disk image/page cache `[x]` (v1) + +**Depends on:** Phase 1. + +**Goal.** The hook refetches every image on every reload. On Amiga +networking, this is painful; a tiny keyed cache gives huge wins. + +**Delivered (v1).** +- `HTMLviewNet_SetCacheDir(path)` / `HTMLviewNet_SetCacheTTL(secs)`. +- Disabled by default; `SetCacheDir(NULL)` clears. +- Key = 16-char hex FNV-1a-64 of URL; entries stored as `.body` + + `.meta` file pairs in the configured directory. +- Meta format: `URL=\nExpires=\n`. +- Read path: if body+meta exist and `now < Expires`, serve the body file + directly (opened as `st->file`) with no network I/O. +- Write path: on 200 with Content-Length <= 8 MB and not chunked, drain + the whole body, persist body+meta with TTL = `HVN_CacheTTL`. +- Log entries: `cache: HIT`, `cache: STORE`, size-skip reasons. + +**Deferred to v2.** +- `ETag` / `Last-Modified` capture + `If-None-Match`/`If-Modified-Since` + revalidation (serve 304 cheaply). +- `Cache-Control: max-age=` + `Expires` server hints. +- Chunked-transfer caching. +- Eviction policy (cache dir currently grows unbounded). + +**Acceptance.** `SetCacheDir("T:htmlcache/")`, reload a page, look for +`cache: HIT` in `T:htmlview_hook.log` on the second fetch. + +--- + +## Phase 4 — UTF-8 / charset handling `[ ]` + +**Goal.** Pages with `` or HTTP `Content-Type: +text/html; charset=utf-8` currently render mojibake. Minimum viable: +detect charset, transliterate UTF-8 → Latin-1 (replacing unrepresentable +codepoints with `?` or the nearest entity). + +**Touches.** +- `mcc/Entities.cpp`, `mcc/ParseMessage.cpp` most likely. +- Possibly new `mcc/Charset.cpp` for the transliteration table. +- Hook contract gains: net hook passes the `Content-Type` charset hint + into the parser (either via `HTMLview_LoadMsg` extension or side-channel + tag — needs a small design call). + +**Acceptance.** A UTF-8 page with `© é ñ` renders them as the Latin-1 +byte equivalents, not as two-byte sequences. + +--- + +## Phase 5 — CSS subset `[ ]` + +**Goal.** Stop dropping `style=` on the floor. Scope: inline + `