diff --git a/Cargo.lock b/Cargo.lock index 8ccf6c0..51b2751 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,12 +137,6 @@ dependencies = [ "syn", ] -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - [[package]] name = "arrayvec" version = "0.7.6" @@ -151,9 +145,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-compression" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" dependencies = [ "brotli", "flate2", @@ -237,7 +231,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", "tower 0.5.1", "tower-layer", @@ -259,7 +253,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", ] @@ -357,9 +351,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" [[package]] name = "byteorder" @@ -505,15 +499,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core_maths" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b02505ccb8c50b0aa21ace0fc08c3e53adebd4e58caa18a36152803c7709a3" -dependencies = [ - "libm", -] - [[package]] name = "crc32fast" version = "1.4.2" @@ -543,12 +528,6 @@ dependencies = [ "parking_lot_core", ] -[[package]] -name = "data-url" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" - [[package]] name = "displaydoc" version = "0.2.5" @@ -639,12 +618,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" - [[package]] name = "fnv" version = "1.0.7" @@ -657,29 +630,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" -[[package]] -name = "fontconfig-parser" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" -dependencies = [ - "roxmltree", -] - -[[package]] -name = "fontdb" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" -dependencies = [ - "fontconfig-parser", - "log", - "memmap2", - "slotmap", - "tinyvec", - "ttf-parser", -] - [[package]] name = "foreign-types" version = "0.3.2" @@ -845,9 +795,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", @@ -949,9 +899,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", @@ -1188,12 +1138,6 @@ dependencies = [ "quick-error", ] -[[package]] -name = "imagesize" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" - [[package]] name = "imgref" version = "1.11.0" @@ -1244,9 +1188,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" [[package]] name = "jobserver" @@ -1266,16 +1210,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kurbo" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f" -dependencies = [ - "arrayvec", - "smallvec", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -1298,12 +1232,6 @@ dependencies = [ "cc", ] -[[package]] -name = "libm" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" - [[package]] name = "libwebp-sys" version = "0.9.6" @@ -1322,9 +1250,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" @@ -1381,15 +1309,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memmap2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" -dependencies = [ - "libc", -] - [[package]] name = "mime" version = "0.3.17" @@ -1619,12 +1538,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pico-args" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" - [[package]] name = "pin-project" version = "1.1.7" @@ -1678,9 +1591,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "ppv-lite86" @@ -1693,9 +1606,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1937,7 +1850,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "system-configuration", "tokio", "tokio-native-tls", @@ -1951,30 +1864,11 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "resvg" -version = "0.44.0" -source = "git+https://github.com/linebender/resvg?rev=ac767218d791fa42bb6da3a8cc85f0a4454685f1#ac767218d791fa42bb6da3a8cc85f0a4454685f1" -dependencies = [ - "gif", - "image-webp", - "log", - "pico-args", - "rgb", - "svgtypes", - "tiny-skia", - "usvg", - "zune-jpeg", -] - [[package]] name = "rgb" version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" -dependencies = [ - "bytemuck", -] [[package]] name = "ring" @@ -1991,12 +1885,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "roxmltree" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2018,9 +1906,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.17" +version = "0.23.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e" +checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" dependencies = [ "once_cell", "rustls-pki-types", @@ -2061,24 +1949,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" -[[package]] -name = "rustybuzz" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" -dependencies = [ - "bitflags 2.6.0", - "bytemuck", - "core_maths", - "log", - "smallvec", - "ttf-parser", - "unicode-bidi-mirroring", - "unicode-ccc", - "unicode-properties", - "unicode-script", -] - [[package]] name = "ryu" version = "1.0.18" @@ -2087,9 +1957,9 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -2238,15 +2108,6 @@ dependencies = [ "quote", ] -[[package]] -name = "simplecss" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a11be7c62927d9427e9f40f3444d5499d868648e2edbc4e2116de69e7ec0e89d" -dependencies = [ - "log", -] - [[package]] name = "siphasher" version = "1.0.1" @@ -2262,15 +2123,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "slotmap" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" -dependencies = [ - "version_check", -] - [[package]] name = "smallvec" version = "1.13.2" @@ -2321,15 +2173,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "strict-num" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" -dependencies = [ - "float-cmp", -] - [[package]] name = "strsim" version = "0.11.1" @@ -2342,21 +2185,11 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "svgtypes" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794de53cc48eaabeed0ab6a3404a65f40b3e38c067e4435883a65d2aa4ca000e" -dependencies = [ - "kurbo", - "siphasher", -] - [[package]] name = "syn" -version = "2.0.87" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", @@ -2371,9 +2204,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -2482,32 +2315,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tiny-skia" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" -dependencies = [ - "arrayref", - "arrayvec", - "bytemuck", - "cfg-if", - "log", - "png", - "tiny-skia-path", -] - -[[package]] -name = "tiny-skia-path" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" -dependencies = [ - "arrayref", - "bytemuck", - "strict-num", -] - [[package]] name = "tinystr" version = "0.7.6" @@ -2518,21 +2325,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" version = "1.41.1" @@ -2716,56 +2508,11 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "ttf-parser" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e" -dependencies = [ - "core_maths", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - -[[package]] -name = "unicode-bidi-mirroring" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" - -[[package]] -name = "unicode-ccc" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" - [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-properties" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" - -[[package]] -name = "unicode-script" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" - -[[package]] -name = "unicode-vo" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "untrusted" @@ -2775,41 +2522,15 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] -[[package]] -name = "usvg" -version = "0.44.0" -source = "git+https://github.com/linebender/resvg?rev=ac767218d791fa42bb6da3a8cc85f0a4454685f1#ac767218d791fa42bb6da3a8cc85f0a4454685f1" -dependencies = [ - "base64", - "data-url", - "flate2", - "fontdb", - "imagesize", - "kurbo", - "log", - "pico-args", - "roxmltree", - "rustybuzz", - "simplecss", - "siphasher", - "strict-num", - "svgtypes", - "tiny-skia-path", - "unicode-bidi", - "unicode-script", - "unicode-vo", - "xmlwriter", -] - [[package]] name = "utf16_iter" version = "1.0.5" @@ -3209,16 +2930,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] -name = "xmlwriter" -version = "0.1.0" +name = "xml" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" +checksum = "ede1c99c55b4b3ad0349018ef0eccbe954ce9c342334410707ee87177fcf2ab4" +dependencies = [ + "xml-rs", +] + +[[package]] +name = "xml-rs" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af310deaae937e48a26602b730250b4949e125f468f11e6990be3e5304ddd96f" [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -3228,9 +2958,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", @@ -3249,7 +2979,6 @@ dependencies = [ "console_error_panic_hook", "dashmap", "env_logger", - "fontdb", "futures", "getrandom", "governor", @@ -3260,7 +2989,6 @@ dependencies = [ "prometheus", "quote", "reqwest", - "resvg", "serde", "serde_json", "siphasher", @@ -3274,6 +3002,7 @@ dependencies = [ "webp", "worker", "worker-macros", + "xml", ] [[package]] @@ -3299,18 +3028,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index f9665b2..984de3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,10 +37,8 @@ env-local = ["axum/http1", "axum/http2", "lossy-webp", "tower-http", "metrics", - "svg-text", "resvg/system-fonts", "resvg/raster-images", "fontdb/fontconfig" ] -cf-worker = ["dep:worker", "dep:worker-macros", "dep:wasm-bindgen"] -cf-worker-paid = ["cf-worker", "resvg/raster-images", "resvg/text", "image/ico", "panic-console-error"] +cf-worker = ["dep:worker", "dep:worker-macros", "dep:wasm-bindgen", "image/ico", "panic-console-error"] # Observability and tracing features panic-console-error = ["dep:console_error_panic_hook"] @@ -48,7 +46,6 @@ metrics = ["prometheus"] prometheus = ["dep:prometheus"] # Processing capabilities -svg-text = ["resvg/text", "dep:fontdb"] lossy-webp = ["dep:webp"] # Server runtime features @@ -81,23 +78,18 @@ toml = { version = "0.8", optional = true } log = "0.4" env_logger = { version = "0.11", optional = true } governor = { version = "0.7.0", features = ["dashmap"], optional = true } -resvg = { version = "0.44.0", default-features = false, features = ["gif", "image-webp"] } thiserror = "2.0" serde_json = "1" wasm-bindgen = { version = "0.2", optional = true } libc = { version = "0.2.162", optional = true } axum-server = { version = "0.7.1", optional = true } -fontdb = { version = "0.23", optional = true } webp = { version = "0.3.0", optional = true } url = { version = "2", optional = true } tower-http = { version = "0.6.2", features = ["catch-panic", "timeout"], optional = true } dashmap = "6.1.0" lru = "0.12.5" prometheus = { version = "0.13.4", optional = true } - -[patch.crates-io] -# licensing and webp dependencies -resvg = { git = "https://github.com/linebender/resvg", rev = "ac767218d791fa42bb6da3a8cc85f0a4454685f1" } +xml = "0.8.20" [build-dependencies] chumsky = "0.9.3" diff --git a/README.md b/README.md index 63cd98a..5163e29 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,6 @@ It has been deployed on my instance for since 11/14 under the AppArmor deploymen Currently to do: - [X] Content-Type sniffing -- [X] SVG rendering - - [ ] Font rendering (will not run on Cloudflare Workers Free plan) - [X] Preset image resizing - [X] Opportunistic Redirection on large video files - [X] RFC9110 compliant proxy loop detection with defensive programming against known vulnerable proxies @@ -30,7 +28,7 @@ This project is designed to match the upstream [specification](https://github.co - We will not honor remote `Content-Disposition` headers but instead reply with the actual filename in the request URL. - Remote `Content-Type` headers will only be used as a hint rather than authoritative, and resniffing is unconditionally performed. -- SVG rasterization is planned to be removed from the proxy in favor of sanitization and CSP enforcement. +- SVG rasterization is removed from the proxy in favor of sanitization and CSP enforcement. ## Demo @@ -51,8 +49,6 @@ Image: ### SVG rendering -(font rendering disabled due to size restrictions) - CF Worker: [https://yumechi-no-kuni-proxy-worker.eternal-flame-ad.workers.dev/proxy/static.webp?url=https://upload.wikimedia.org/wikipedia/commons/a/ad/AES-AddRoundKey.svg](https://yumechi-no-kuni-proxy-worker.eternal-flame-ad.workers.dev/proxy/static.webp?url=https://upload.wikimedia.org/wikipedia/commons/a/ad/AES-AddRoundKey.svg) Local: [https://mproxy.mi.yumechi.jp/proxy/static.webp?url=https://upload.wikimedia.org/wikipedia/commons/a/ad/AES-AddRoundKey.svg](https://mproxy.mi.yumechi.jp/proxy/static.webp?url=https://upload.wikimedia.org/wikipedia/commons/a/ad/AES-AddRoundKey.svg) @@ -80,9 +76,7 @@ Local: [https://mproxy.mi.yumechi.jp/proxy/static.webp?url=https://upload.wikime IF deploying to Cloudflare Workers: - Firstly I don't recommend deploying using the free plan because there are much faster implementations that do not or almost do not perform any Image processing. I have this feature mainly because I don't want to pay for a Cloudflare Workers plan just to support this. - - The reported CPU time by Cloudflare is consistently over the free plan limit (which is only 10ms! probably not even enough for decoding an image) and will likely be throttled or terminated once you deploy it to real workloads. The paid plan is recommended for this worker. + Firstly I don't recommend deploying using the free plan because there are much faster implementations that do not or almost do not perform any Image processing. The reported CPU time by Cloudflare is consistently over the free plan limit (which is only 10ms! probably not even enough for decoding an image) and will likely be throttled or terminated once you deploy it to real workloads. The paid plan is recommended for this worker. 5. Add the wasm target with `rustup +$(cat rust-toolchain) target add wasm32-unknown-unknown`. @@ -90,7 +84,7 @@ Local: [https://mproxy.mi.yumechi.jp/proxy/static.webp?url=https://upload.wikime 7. Install `wrangler` with you JS package manager of choice. See /. `npx` also works. - 8. Edit `wrangler.toml` to your liking. Everything in the `[vars]` section maps directly into the `config` section of the TOML configuration file. There is a `cf-worker-paid` feature set which enable some additional features that will never fit in the free plan, mainly SVG font rendering and some debugging features. + 8. Edit `wrangler.toml` to your liking. Everything in the `[vars]` section maps directly into the `config` section of the TOML configuration file. 9. Test locally with `wrangler dev`. diff --git a/deny.toml b/deny.toml index e698995..bee8a85 100644 --- a/deny.toml +++ b/deny.toml @@ -92,7 +92,6 @@ allow = [ "CC0-1.0", "MIT", "Apache-2.0", - "Unicode-DFS-2016", "ISC", "Unicode-3.0", "BSD-3-Clause", diff --git a/local.toml b/local.toml index 9b21503..193f118 100644 --- a/local.toml +++ b/local.toml @@ -4,10 +4,7 @@ index_redirect = { permanent = false, url = "https://mi.yumechi.jp/" } allow_unknown = false max_x_forwarded_for = 0 -# you need AppArmor and the policy loaded to use this -[sandbox.apparmor] -serve = "yumechi-no-kuni-proxy-worker//serve" -image_hat = "image" + [fetch] addr_family = "both" diff --git a/mac/apparmor/yumechi-no-kuni-proxy-worker b/mac/apparmor/yumechi-no-kuni-proxy-worker index eb65d3e..7f1a2f9 100644 --- a/mac/apparmor/yumechi-no-kuni-proxy-worker +++ b/mac/apparmor/yumechi-no-kuni-proxy-worker @@ -81,7 +81,6 @@ profile yumechi-no-kuni-proxy-worker @{prog_path} { ^image { include include - include deny capability, deny network, diff --git a/src/lib.rs b/src/lib.rs index e27e25a..c59d848 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,8 @@ use lru::LruCache; use post_process::{CompressionLevel, MediaResponse}; use sandbox::Sandboxing; +#[cfg(feature = "cf-worker")] +use crate::config::CfConfigError; use serde::Deserialize; #[cfg(feature = "cf-worker")] use worker::{event, Context, Env, HttpRequest, Result as WorkerResult}; diff --git a/src/post_process/image_processing.rs b/src/post_process/image_processing.rs index 9c7e764..ca1fd94 100644 --- a/src/post_process/image_processing.rs +++ b/src/post_process/image_processing.rs @@ -1,4 +1,4 @@ -use std::io::Cursor; +use std::io::{BufReader, Cursor}; use image::{ codecs::{png::PngDecoder, webp::WebPDecoder}, @@ -86,81 +86,167 @@ pub fn postprocess_png_image(data: &[u8], opt: &ImageOptions) -> ImageResult>, - #[cfg(not(feature = "svg-text"))] _font_data: Option<()>, opt: &ImageOptions, -) -> Result { - use resvg::{ - tiny_skia::Pixmap, - usvg::{self, Transform}, - }; +) -> Result, SvgPostprocessError> { + let static_ = opt.static_ == Some(true); + let rdr = BufReader::new(Cursor::new(data)); + let tree = xml::EventReader::new(rdr); + let mut out = Vec::new(); + let mut wtr = xml::EventWriter::new(&mut out); - let svg = usvg::Tree::from_data( - data, - &usvg::Options { - default_size: usvg::Size::from_wh(256., 256.).unwrap(), - text_rendering: usvg::TextRendering::OptimizeLegibility, - image_rendering: usvg::ImageRendering::OptimizeSpeed, - #[cfg(feature = "svg-text")] - fontdb: { - let mut db = usvg::fontdb::Database::new(); - #[cfg(not(target_arch = "wasm32"))] - db.load_system_fonts(); - - if let Some(font_data) = font_data { - db.load_font_data(font_data); + let mut complexity = 0; + let mut ignore_stack = None; + for r in tree { + match r { + Ok(o) => match o { + xml::reader::XmlEvent::StartDocument { .. } => { + complexity += 1; + wtr.write( + o.as_writer_event() + .ok_or(SvgPostprocessError::Unsupported)?, + )?; } + xml::reader::XmlEvent::EndDocument => { + break; + } + xml::reader::XmlEvent::ProcessingInstruction { ref name, .. } => { + complexity += 1 + name.len(); + if ignore_stack.is_some() { + continue; + } + if name != "xml" { + return Err(SvgPostprocessError::DisallowedContent); + } - std::sync::Arc::new(db) + wtr.write( + o.as_writer_event() + .ok_or(SvgPostprocessError::Unsupported)?, + )?; + } + xml::reader::XmlEvent::StartElement { + name, + mut attributes, + namespace, + } => { + complexity += 1 + attributes.len() + namespace.0.len(); + + if ignore_stack.is_some() { + ignore_stack = ignore_stack.map(|v| v + 1); + continue; + } + + let name_str = name.local_name.to_ascii_lowercase(); + if name_str.contains("script") { + return Err(SvgPostprocessError::DisallowedContent); + } + + if static_ { + if name_str == "set" || name_str.starts_with("animate") { + ignore_stack = Some(0); + continue; + } + } + attributes.retain(|attr| { + let lname = attr.name.local_name.to_ascii_lowercase(); + if lname.starts_with("on") { + return false; + } + + if lname.ends_with("src") || lname.ends_with("href") { + if !attr.value.starts_with("data:image/") + && !attr.value.contains("svg") + && !attr.value.contains("xml") + { + return false; + } + } + + if lname.eq_ignore_ascii_case("style") { + let style = attr.value.as_str(); + if style.to_ascii_lowercase().contains("url") { + return false; + } + } + return true; + }); + + wtr.write( + xml::reader::XmlEvent::StartElement { + name, + attributes, + namespace, + } + .as_writer_event() + .ok_or(SvgPostprocessError::Unsupported)?, + )?; + } + xml::reader::XmlEvent::EndElement { .. } => { + complexity += 1; + if ignore_stack.is_some() { + ignore_stack = ignore_stack.map(|v| v - 1); + if ignore_stack == Some(0) { + ignore_stack = None; + } + continue; + } + wtr.write( + o.as_writer_event() + .ok_or(SvgPostprocessError::Unsupported)?, + )?; + } + xml::reader::XmlEvent::CData(ref s) => { + complexity += 1 + s.len() / 32; + if ignore_stack.is_some() { + continue; + } + wtr.write( + o.as_writer_event() + .ok_or(SvgPostprocessError::Unsupported)?, + )?; + } + xml::reader::XmlEvent::Comment(s) => complexity += 1 + s.len() / 64, + xml::reader::XmlEvent::Characters(ref s) => { + complexity += 1 + s.len() / 32; + if ignore_stack.is_some() { + continue; + } + wtr.write( + o.as_writer_event() + .ok_or(SvgPostprocessError::Unsupported)?, + )?; + } + xml::reader::XmlEvent::Whitespace(s) => complexity += 1 + s.len() / 64, }, - ..Default::default() - }, - )?; - let complexity = svg.clip_paths().len() - + svg.filters().len() - + svg.linear_gradients().len() - + svg.radial_gradients().len() - + svg.patterns().len() - + (svg.size().width() * svg.size().height()) as usize / 1000; + Err(e) => return Err(SvgPostprocessError::XmlRead(e)), + } - if complexity > 25535 { - return Err(SvgPostprocessError::LimitExceeded(complexity)); + if complexity > 65536 { + return Err(SvgPostprocessError::LimitExceeded); + } } - let size = svg.size(); - let clamped = clamp_dimensions((size.width() as u32, size.height() as u32), 800, 800); - - let transform = Transform::from_scale( - clamped.0 as f32 / size.width(), - clamped.1 as f32 / size.height(), - ); - - let mut pm = Pixmap::new(clamped.0 as _, clamped.1 as _).unwrap(); - - resvg::render(&svg, transform, &mut pm.as_mut()); - - let image = - image::RgbaImage::from_vec(pm.width() as _, pm.height() as _, pm.data().to_vec()).unwrap(); - - Ok(process_static_image_impl( - DynamicImage::ImageRgba8(image), - opt, - )) + Ok(out) } fn default_limits() -> Limits { diff --git a/src/post_process/mod.rs b/src/post_process/mod.rs index f860f55..24c136b 100644 --- a/src/post_process/mod.rs +++ b/src/post_process/mod.rs @@ -197,15 +197,13 @@ where buf.extend_from_slice(bytes.as_ref()); } - let img = sandboxed!(sandbox => image_processing::postprocess_svg_image(&buf, None, &options) + let img = sandboxed!(sandbox => image_processing::postprocess_svg_image(&buf, &options) .map_err(|e| ErrorResponse::postprocess_failed(e.to_string().into())))?; - Ok(MediaResponse::ProcessedStaticImage(StaticImage { + Ok(MediaResponse::Buffer { data: img, - format: ImageFormat::WebP, - compression: options.compression_level(), - is_https, - }) + content_type: Some("image/svg+xml".into()), + } .with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb) .with_opt_timing_info(SLURP_TIMING_KEY, None) .with_timing_info(TIMING_KEY, begin.elapsed()))