~xdavidwu/xdavidwu.link

43697718ed495f2ac5e03cc88d839d57b81fa998 — xdavidwu 8 months ago 5866d7e
reproduce-bug-on-safari-without-macos: new post
1 files changed, 93 insertions(+), 0 deletions(-)

A _posts/2023-08-24-reproduce-bug-on-safari-without-macos.md
A _posts/2023-08-24-reproduce-bug-on-safari-without-macos.md => _posts/2023-08-24-reproduce-bug-on-safari-without-macos.md +93 -0
@@ 0,0 1,93 @@
---
title: 不使用 macOS 重現網頁在 Safari 下的 bug
categories:
  - Web
tags:
  - web
  - webkit
  - flatpak
  - containers
  - x11
---

工作遇到有人在 Safari 撞到前端 bug

以此為契機挖出了一連串各種奇妙知識

首先因為工作性質的關係,跟使用者溝通以郵件為主,所以作法上選擇減少溝通成本盡量自行調查,
不過其實這次在仔細調查前對方也先回報換個瀏覽器就沒事了

## 各種版號們與 WebKitGTK

在 access log 中找到了事發的 UA

`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.3 Safari/605.1.15`

第一眼看起來應該就是 Safari,不過也有人測過最新的 Safari 沒問題。
因為這次事件先順勢帶出了缺乏公用 Safari 測試環境的議題,去補充了一下 Safari 的知識,
對 [Safari, macOS, WebKit 版本對應](https://en.wikipedia.org/wiki/Safari_version_history) 有初步的印象,
發現不對勁,WebKit 605.1.15 相對於 macOS 10.15.7, Safari 15.3 也太老了,對應表上的 WebKit 版本實際上是 612.4.9。
到 WebKit GitHub 上搜尋 605.1.15,確實找到在各平台上產 UA strings 都把這個版號寫死,
找到相關的 [tracker item](https://bugs.webkit.org/show_bug.cgi?id=180365),
為了防更多看 UA 特判產生的歪風所以乾脆把版號 freeze 了。
對於實際 Safari 與 WebKit 的版本對應,MDN [有更齊全的表](https://github.com/mdn/browser-compat-data/blob/main/browsers/safari.json),
不過沒有 macOS 版本資訊

對於重現,因為沒有夠新的公用蘋果硬體,加上 macOS EULA 對於 VM 據說也只允許跑在蘋果硬體上,
所以打算放棄 macOS 的環境,採用 WebKitGTK 盡力重現。WebKitGTK 雖然跟 WebKit 活在同一個 repo 下,
版號跟 release cycle 也都是獨立的,勢必要想辦法在找出 WebKitGTK 與 WebKit 間的版本對應。
WebKitGTK 每個 minor 都是從 WebKit 本人再 branch 出去維護,
可以在 [GitHub Wiki](https://github.com/WebKit/WebKit/wiki/GLib-Stable-Branches) 找到整理,
老一些的版本(轉 GitHub 前?)則是整理在 [trac](https://trac.webkit.org/wiki/WebKitGTK/StableRelease#Listofreleases) 上,
在 GitHub 上可以看到 branch 點的 commit 包含在哪些 tags 裡,找最小就可以大略對應到 WebKit 版本

## Take 1: Flatpak

有了以上這些資訊,對於在非 macOS 下重現環境就只差要怎麼獲取與使用特定版本的 WebKitGTK。
使用上我選最知名的 client -- GNOME Web / Epiphany,對於獲取,第一個想法就是 Flatpak,
找到了 Flatpak [安裝特定版本 app 的方法](https://github.com/flatpak/flatpak/wiki/Tips-&-Tricks#downgrading):

```sh
flatpak remote-info --log flathub org.gnome.Epiphany
flatpak update --commit=<desired commit from above> org.gnome.Epiphany
```

再來需要的就是 Epiphany Flatpak package 跟 WebKitGTK 版本對應,
找到了 Flathub 上 [Epiphany 的 manifest](https://github.com/flathub/org.gnome.Epiphany/blob/72326ed920af098fcb45f235ee54de170f06a92f/org.gnome.Epiphany.json),
但上面沒有 WebKitGTK 的影子,往上追發現做在 `org.gnome.Platform`。
[GNOME platform](https://gitlab.gnome.org/GNOME/gnome-build-meta) 的作法比較複雜,
用了 [BuildStream](https://buildstream.build/),WebKitGTK 的引入在 `elements/sdk/webkitgtk.inc`,
在對於各個 GNOME major 的 branch 上看 history 就可以知道哪個 GNOME major 對到哪個 WebKitGTK minor,
Epiphany 的 release 是 follow GNOME 的,所以就是直接找同個 major

對應版號後發現我需要的 WebKitGTK 大概落在 2.32 與 2.34,2.34 再對到 Epiphany Flatpak package 在 40.x,
結果 `flatpak remote-info --log` 一下,發現 Flathub 上已經沒有存這麼久以前的版本了,這次沒那麼簡單

## Take 2: OCI containers

換個傳統一點的想法就是從 stable distribution 去抓套件,但老東西抓 binary 丟上新系統 ABI 大概會接不上死一片,
裝個 VM 又有點累,於是用了 container:

```sh
podman run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY --privileged -it alpine:3.15
```

用 X11 而不是 Wayland 是因為 GTK 不知為何貌似在 Wayland 下會先需要連 DBus,但 DBus 比較難搞定,
socket 丟進去 address 設好後還有 protocol 上的 auth 要處理,所以偷懶用 XWayland / X11。
privileged 則是因為 WebKitGTK 用 Bubblewrap 做 sandboxing,貌似需要些權限去開 namespaces,
但也懶得挖需要哪些 capabilities 了就乾脆丟個 privileged

```sh
apk add epiphany font-noto-cjk mesa-dri-gallium
epiphany
```

跑起來就能測了

有了這些功夫,遇到 Safari 使用者回報問題,大致上也都能用開放的系統重現個大概了

Off-topic 的後記:

這次撞到的是舊版 WebKit JS Date parsing 不吃 `YYYY-MM-DD HH:mm`,
其實在 ECMAScript 下用空格分隔不怎麼標準,不過因為其他 JS 實做有做,
後來[還是做了](https://bugs.webkit.org/show_bug.cgi?id=235468)