From unknown Sat Sep 13 00:21:47 2025 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Mailer: MIME-tools 5.509 (Entity 5.509) Content-Type: text/plain; charset=utf-8 From: bug#78984 <78984@debbugs.gnu.org> To: bug#78984 <78984@debbugs.gnu.org> Subject: Status: 31.0.50; `url-build-query-string' fails to escape a literal `%' in keys and values Reply-To: bug#78984 <78984@debbugs.gnu.org> Date: Sat, 13 Sep 2025 07:21:47 +0000 retitle 78984 31.0.50; `url-build-query-string' fails to escape a literal `= %' in keys and values reassign 78984 emacs submitter 78984 Steven Allen severity 78984 normal thanks From debbugs-submit-bounces@debbugs.gnu.org Wed Jul 09 17:29:54 2025 Received: (at submit) by debbugs.gnu.org; 9 Jul 2025 21:29:54 +0000 Received: from localhost ([127.0.0.1]:52809 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uZcMM-0004ta-R3 for submit@debbugs.gnu.org; Wed, 09 Jul 2025 17:29:53 -0400 Received: from lists.gnu.org ([2001:470:142::17]:56656) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uZcMB-0004qW-2t for submit@debbugs.gnu.org; Wed, 09 Jul 2025 17:29:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uZcM3-0002sz-4S for bug-gnu-emacs@gnu.org; Wed, 09 Jul 2025 17:29:28 -0400 Received: from fout-b1-smtp.messagingengine.com ([202.12.124.144]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uZcLy-0007ro-Uu for bug-gnu-emacs@gnu.org; Wed, 09 Jul 2025 17:29:26 -0400 Received: from phl-compute-06.internal (phl-compute-06.phl.internal [10.202.2.46]) by mailfout.stl.internal (Postfix) with ESMTP id A0A191D00132 for ; Wed, 9 Jul 2025 17:29:19 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-06.internal (MEProxy); Wed, 09 Jul 2025 17:29:19 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=stebalien.com; h=cc:content-type:content-type:date:date:from:from:in-reply-to :message-id:mime-version:reply-to:subject:subject:to:to; s=fm1; t=1752096559; x=1752182959; bh=ecONgWbtadZrZoPbWcZfYmn2rDdguUkl OzdYx8FEhKM=; b=YoRdJxSA9tTIxSjbXwaYykP7966REQwPwaY2IoQnFkmP5+vk ypawjWfXN0za1CdcgYhgNPgc8yaJcfY2sFMr4r24ue+Kot8s1wvvqRMGQSvDSHUE 7DmSDXZai0QXjCln9ouTxUIDaZ3KZlQXq7nSNmuV23rLHIRzjTWDj3FvCE9gHmAr H6/X3/K7b7xVs42hGhR30G6aArO0nOHvPJ6srfmVGFrjJaX1RiM4HgFCUSWDLR+D tqct98D+TwPVr3u3QwTY1k2hlD1xeV/ZffrxZ56QWnJwlh0JqBjvxMROBj25U1e7 zbr5awryNNWkq2Kt/7siIeOt8j0sUubYNCYUeA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:message-id :mime-version:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t=1752096559; x= 1752182959; bh=ecONgWbtadZrZoPbWcZfYmn2rDdguUklOzdYx8FEhKM=; b=T TVOepyah5+tlCX3EMpIIzOgNxZHCgCQ2Hwlmz47MNrBPCsIUXtU4Ghb7ObRUbGpA jPtxhgAi9QSySRVaa2TjH8WP1lHSYM1zke0lNm/OZQZf0UOKgA4M8/P+0/LsE+bI 7nSPaQHB/um1dywZV87o1Hlw/Tdrwz5btgss0lD9yrRMYK1cS63bKQDNlTiHvgvW ZHAFKKwlISnFS0cZb4r2JioDbhpm1qHzNssSh6sDX1cd/EUIpmMcso5Wob7A/9r6 nlLwe3CFN2QU7KeoqgugN8TUheywu5oJtigq6KeCkRztQba/DcPZGFE7GcIl1zK0 y4xjQQPdsVhTYv1DMidVQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdefkeeigecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecunecujfgurhephffvufffkfggtgesthdtredttddttdenuc fhrhhomhepufhtvghvvghnucetlhhlvghnuceoshhtvghvvghnsehsthgvsggrlhhivghn rdgtohhmqeenucggtffrrghtthgvrhhnpeefkedtuddttefhgeektedtgeegjeegvddute ehhfethfevleefveehhffhvdffjeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgr mhepmhgrihhlfhhrohhmpehsthgvvhgvnhesshhtvggsrghlihgvnhdrtghomhdpnhgspg hrtghpthhtohepuddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtohepsghughdqghhn uhdqvghmrggtshesghhnuhdrohhrgh X-ME-Proxy: Feedback-ID: ie8a146a7:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA for ; Wed, 9 Jul 2025 17:29:18 -0400 (EDT) From: Steven Allen To: bug-gnu-emacs@gnu.org Subject: 31.0.50; `url-build-query-string' fails to escape a literal `%' in keys and values X-Debbugs-Cc: Date: Wed, 09 Jul 2025 14:29:17 -0700 Message-ID: <87ecupxdci.fsf@stebalien.com> MIME-Version: 1.0 Content-Type: text/plain Received-SPF: pass client-ip=202.12.124.144; envelope-from=steven@stebalien.com; helo=fout-b1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: 0.7 (/) X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.3 (/) `url-build-query-string' fails to escape literal `%' characters and keys and values. To reproduce, run the following and note that it's encoded as "%%3D" when it should be encoded as "%25%3D". emacs --batch --eval '(message "%s" (url-build-query-string (list (list "key" "%="))))' The root cause appears to be that `%' is explicitly allowed in `url-host-allowed-chars' (inherited by `url-query-key-value-allowed-chars'), apparently to avoid re-encoding %-encoded sequences. Unfortunately, changing this will definitely break things (e.g., `url-encode-url' will no longer round-trip). The direct/simple fix would be to forbid `%' in `url-query-key-value-allowed-chars'. This issue also appears to affect Eglot's `eglot-path-to-uri' function (`eglot--uri-path-allowed-chars' allows `%' in path-names), but I haven't been able to find a stand-alone reproducer. In GNU Emacs 31.0.50 (build 1, x86_64-pc-linux-gnu, cairo version 1.18.4) of 2025-07-04 built on Laptop Repository revision: 5afff7ed67633864562e014feabc670f156df5b4 Repository branch: makepkg Windowing system distributor 'The X.Org Foundation', version 11.0.12101018 System Description: Arch Linux Configured using: 'configure 'CPPFLAGS=-I/run/user/1000/build/emacs-git/src/mps-git/build/include ' 'LDFLAGS=-L/run/user/1000/build/emacs-git/src/mps-git/build/lib -Wl,-O1 -Wl,--sort-common -Wl,--as-needed -Wl,-z,relro -Wl,-z,now -Wl,-z,pack-relative-relocs -flto=auto' --prefix=/usr --sysconfdir=/etc --libexecdir=/usr/lib --localstatedir=/var --mandir=/usr/share/man --with-gameuser=:games --with-modules --without-m17n-flt --without-selinux --without-pop --without-gconf --disable-gc-mark-trace --with-mps=yes --enable-link-time-optimization --with-native-compilation=yes --with-xinput2 --with-x-toolkit=no --without-toolkit-scroll-bars --without-xaw3d --without-gsettings --with-cairo-xcb --without-xft --with-sound=no --with-tree-sitter --without-gpm --without-compress-install '--program-transform-name=s/\([ec]tags\)/\1.emacs/' 'CFLAGS=-march=native -mtune=native -O3 -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=3 -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection -fomit-frame-pointer -fno-math-errno -fno-trapping-math -fno-math-errno -fno-trapping-math -flto=auto'' Configured features: ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS HARFBUZZ JPEG LCMS2 LIBOTF LIBSYSTEMD LIBXML2 MODULES MPS NATIVE_COMP NOTIFY INOTIFY OLDXMENU PDUMPER PNG RSVG SECCOMP SQLITE3 THREADS TIFF TREE_SITTER WEBP X11 XDBE XIM XINERAMA XINPUT2 XPM XRANDR ZLIB Important settings: value of $LANG: en_US.UTF-8 locale-coding-system: utf-8-unix Major mode: Elisp/l Minor modes in effect: hexl-follow-ascii: t windmove-mode: t rainbow-mode: t rainbow-delimiters-mode: t global-atomic-chrome-edit-mode: t iwd-agent-mode: t i3bar-mode: t ednc-mode: t exwm-xsettings-mode: t exwm-background-mode: t exwm-systemtray-mode: t exwm-randr-mode: t exwm-wm-mode: t mlscroll-mode: t ligature-mode: t stripspace-local-mode: t simple-auto-compile-mode: t save-place-mode: t savehist-mode: t global-org-modern-mode: t notmuch-bookmarks-mode: t goto-address-prog-mode: t eat-eshell-mode: t bug-reference-prog-mode: t magit-todos-mode: t nerd-icons-grep-mode: t global-git-commit-mode: t dired-async-mode: t server-mode: t llama-fontify-mode: t yas-global-mode: t yas-minor-mode: t ultra-scroll-mode: t pixel-scroll-precision-mode: t global-hl-todo-mode: t hl-todo-mode: t marginalia-mode: t nerd-icons-completion-mode: t global-jinx-mode: t visual-replace-global-mode: t vertico-multiform-mode: t vertico-mode: t corfu-popupinfo-mode: t global-corfu-mode: t corfu-mode: t isearch-mb-mode: t evil-goggles-mode: t global-evil-surround-mode: t evil-surround-mode: t recentf-mode: t editorconfig-mode: t page-break-mode: t global-auto-revert-mode: t minibuffer-depth-indicate-mode: t minibuffer-electric-default-mode: t evil-mode: t evil-local-mode: t desktop-environment-mode: t elpaca-use-package-mode: t override-global-mode: t global-eldoc-mode: t eldoc-mode: t show-paren-mode: t electric-indent-mode: t mouse-wheel-mode: t prettify-symbols-mode: t tab-bar-history-mode: t tab-bar-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t window-divider-mode: t minibuffer-regexp-mode: t column-number-mode: t line-number-mode: t transient-mark-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t Load-path shadows: /home/steb/.config/emacs/elpaca/builds/package-lint-flymake/package-lint-flymake hides /home/steb/.config/emacs/elpaca/builds/package-lint/package-lint-flymake /home/steb/.config/emacs/elpaca/builds/transient/transient hides /usr/share/emacs/31.0.50/lisp/transient /home/steb/.config/emacs/elpaca/builds/org/ox hides /usr/share/emacs/31.0.50/lisp/org/ox /home/steb/.config/emacs/elpaca/builds/org/ox-texinfo hides /usr/share/emacs/31.0.50/lisp/org/ox-texinfo /home/steb/.config/emacs/elpaca/builds/org/ox-publish hides /usr/share/emacs/31.0.50/lisp/org/ox-publish /home/steb/.config/emacs/elpaca/builds/org/ox-org hides /usr/share/emacs/31.0.50/lisp/org/ox-org /home/steb/.config/emacs/elpaca/builds/org/ox-odt hides /usr/share/emacs/31.0.50/lisp/org/ox-odt /home/steb/.config/emacs/elpaca/builds/org/ox-md hides /usr/share/emacs/31.0.50/lisp/org/ox-md /home/steb/.config/emacs/elpaca/builds/org/ox-man hides /usr/share/emacs/31.0.50/lisp/org/ox-man /home/steb/.config/emacs/elpaca/builds/org/ox-latex hides /usr/share/emacs/31.0.50/lisp/org/ox-latex /home/steb/.config/emacs/elpaca/builds/org/ox-koma-letter hides /usr/share/emacs/31.0.50/lisp/org/ox-koma-letter /home/steb/.config/emacs/elpaca/builds/org/ox-icalendar hides /usr/share/emacs/31.0.50/lisp/org/ox-icalendar /home/steb/.config/emacs/elpaca/builds/org/ox-html hides /usr/share/emacs/31.0.50/lisp/org/ox-html /home/steb/.config/emacs/elpaca/builds/org/ox-beamer hides /usr/share/emacs/31.0.50/lisp/org/ox-beamer /home/steb/.config/emacs/elpaca/builds/org/ox-ascii hides /usr/share/emacs/31.0.50/lisp/org/ox-ascii /home/steb/.config/emacs/elpaca/builds/org/org hides /usr/share/emacs/31.0.50/lisp/org/org /home/steb/.config/emacs/elpaca/builds/org/org-version hides /usr/share/emacs/31.0.50/lisp/org/org-version /home/steb/.config/emacs/elpaca/builds/org/org-timer hides /usr/share/emacs/31.0.50/lisp/org/org-timer /home/steb/.config/emacs/elpaca/builds/org/org-tempo hides /usr/share/emacs/31.0.50/lisp/org/org-tempo /home/steb/.config/emacs/elpaca/builds/org/org-table hides /usr/share/emacs/31.0.50/lisp/org/org-table /home/steb/.config/emacs/elpaca/builds/org/org-src hides /usr/share/emacs/31.0.50/lisp/org/org-src /home/steb/.config/emacs/elpaca/builds/org/org-refile hides /usr/share/emacs/31.0.50/lisp/org/org-refile /home/steb/.config/emacs/elpaca/builds/org/org-protocol hides /usr/share/emacs/31.0.50/lisp/org/org-protocol /home/steb/.config/emacs/elpaca/builds/org/org-plot hides /usr/share/emacs/31.0.50/lisp/org/org-plot /home/steb/.config/emacs/elpaca/builds/org/org-persist hides /usr/share/emacs/31.0.50/lisp/org/org-persist /home/steb/.config/emacs/elpaca/builds/org/org-pcomplete hides /usr/share/emacs/31.0.50/lisp/org/org-pcomplete /home/steb/.config/emacs/elpaca/builds/org/org-num hides /usr/share/emacs/31.0.50/lisp/org/org-num /home/steb/.config/emacs/elpaca/builds/org/org-mouse hides /usr/share/emacs/31.0.50/lisp/org/org-mouse /home/steb/.config/emacs/elpaca/builds/org/org-mobile hides /usr/share/emacs/31.0.50/lisp/org/org-mobile /home/steb/.config/emacs/elpaca/builds/org/org-macs hides /usr/share/emacs/31.0.50/lisp/org/org-macs /home/steb/.config/emacs/elpaca/builds/org/org-macro hides /usr/share/emacs/31.0.50/lisp/org/org-macro /home/steb/.config/emacs/elpaca/builds/org/org-loaddefs hides /usr/share/emacs/31.0.50/lisp/org/org-loaddefs /home/steb/.config/emacs/elpaca/builds/org/org-list hides /usr/share/emacs/31.0.50/lisp/org/org-list /home/steb/.config/emacs/elpaca/builds/org/org-lint hides /usr/share/emacs/31.0.50/lisp/org/org-lint /home/steb/.config/emacs/elpaca/builds/org/org-keys hides /usr/share/emacs/31.0.50/lisp/org/org-keys /home/steb/.config/emacs/elpaca/builds/org/org-inlinetask hides /usr/share/emacs/31.0.50/lisp/org/org-inlinetask /home/steb/.config/emacs/elpaca/builds/org/org-indent hides /usr/share/emacs/31.0.50/lisp/org/org-indent /home/steb/.config/emacs/elpaca/builds/org/org-id hides /usr/share/emacs/31.0.50/lisp/org/org-id /home/steb/.config/emacs/elpaca/builds/org/org-habit hides /usr/share/emacs/31.0.50/lisp/org/org-habit /home/steb/.config/emacs/elpaca/builds/org/org-goto hides /usr/share/emacs/31.0.50/lisp/org/org-goto /home/steb/.config/emacs/elpaca/builds/org/org-footnote hides /usr/share/emacs/31.0.50/lisp/org/org-footnote /home/steb/.config/emacs/elpaca/builds/org/org-fold hides /usr/share/emacs/31.0.50/lisp/org/org-fold /home/steb/.config/emacs/elpaca/builds/org/org-fold-core hides /usr/share/emacs/31.0.50/lisp/org/org-fold-core /home/steb/.config/emacs/elpaca/builds/org/org-feed hides /usr/share/emacs/31.0.50/lisp/org/org-feed /home/steb/.config/emacs/elpaca/builds/org/org-faces hides /usr/share/emacs/31.0.50/lisp/org/org-faces /home/steb/.config/emacs/elpaca/builds/org/org-entities hides /usr/share/emacs/31.0.50/lisp/org/org-entities /home/steb/.config/emacs/elpaca/builds/org/org-element hides /usr/share/emacs/31.0.50/lisp/org/org-element /home/steb/.config/emacs/elpaca/builds/org/org-element-ast hides /usr/share/emacs/31.0.50/lisp/org/org-element-ast /home/steb/.config/emacs/elpaca/builds/org/org-duration hides /usr/share/emacs/31.0.50/lisp/org/org-duration /home/steb/.config/emacs/elpaca/builds/org/org-datetree hides /usr/share/emacs/31.0.50/lisp/org/org-datetree /home/steb/.config/emacs/elpaca/builds/org/org-cycle hides /usr/share/emacs/31.0.50/lisp/org/org-cycle /home/steb/.config/emacs/elpaca/builds/org/org-ctags hides /usr/share/emacs/31.0.50/lisp/org/org-ctags /home/steb/.config/emacs/elpaca/builds/org/org-crypt hides /usr/share/emacs/31.0.50/lisp/org/org-crypt /home/steb/.config/emacs/elpaca/builds/org/org-compat hides /usr/share/emacs/31.0.50/lisp/org/org-compat /home/steb/.config/emacs/elpaca/builds/org/org-colview hides /usr/share/emacs/31.0.50/lisp/org/org-colview /home/steb/.config/emacs/elpaca/builds/org/org-clock hides /usr/share/emacs/31.0.50/lisp/org/org-clock /home/steb/.config/emacs/elpaca/builds/org/org-capture hides /usr/share/emacs/31.0.50/lisp/org/org-capture /home/steb/.config/emacs/elpaca/builds/org/org-attach hides /usr/share/emacs/31.0.50/lisp/org/org-attach /home/steb/.config/emacs/elpaca/builds/org/org-attach-git hides /usr/share/emacs/31.0.50/lisp/org/org-attach-git /home/steb/.config/emacs/elpaca/builds/org/org-archive hides /usr/share/emacs/31.0.50/lisp/org/org-archive /home/steb/.config/emacs/elpaca/builds/org/org-agenda hides /usr/share/emacs/31.0.50/lisp/org/org-agenda /home/steb/.config/emacs/elpaca/builds/org/ol hides /usr/share/emacs/31.0.50/lisp/org/ol /home/steb/.config/emacs/elpaca/builds/org/ol-w3m hides /usr/share/emacs/31.0.50/lisp/org/ol-w3m /home/steb/.config/emacs/elpaca/builds/org/ol-rmail hides /usr/share/emacs/31.0.50/lisp/org/ol-rmail /home/steb/.config/emacs/elpaca/builds/org/ol-mhe hides /usr/share/emacs/31.0.50/lisp/org/ol-mhe /home/steb/.config/emacs/elpaca/builds/org/ol-man hides /usr/share/emacs/31.0.50/lisp/org/ol-man /home/steb/.config/emacs/elpaca/builds/org/ol-irc hides /usr/share/emacs/31.0.50/lisp/org/ol-irc /home/steb/.config/emacs/elpaca/builds/org/ol-info hides /usr/share/emacs/31.0.50/lisp/org/ol-info /home/steb/.config/emacs/elpaca/builds/org/ol-gnus hides /usr/share/emacs/31.0.50/lisp/org/ol-gnus /home/steb/.config/emacs/elpaca/builds/org/ol-eww hides /usr/share/emacs/31.0.50/lisp/org/ol-eww /home/steb/.config/emacs/elpaca/builds/org/ol-eshell hides /usr/share/emacs/31.0.50/lisp/org/ol-eshell /home/steb/.config/emacs/elpaca/builds/org/ol-doi hides /usr/share/emacs/31.0.50/lisp/org/ol-doi /home/steb/.config/emacs/elpaca/builds/org/ol-docview hides /usr/share/emacs/31.0.50/lisp/org/ol-docview /home/steb/.config/emacs/elpaca/builds/org/ol-bibtex hides /usr/share/emacs/31.0.50/lisp/org/ol-bibtex /home/steb/.config/emacs/elpaca/builds/org/ol-bbdb hides /usr/share/emacs/31.0.50/lisp/org/ol-bbdb /home/steb/.config/emacs/elpaca/builds/org/oc hides /usr/share/emacs/31.0.50/lisp/org/oc /home/steb/.config/emacs/elpaca/builds/org/oc-natbib hides /usr/share/emacs/31.0.50/lisp/org/oc-natbib /home/steb/.config/emacs/elpaca/builds/org/oc-csl hides /usr/share/emacs/31.0.50/lisp/org/oc-csl /home/steb/.config/emacs/elpaca/builds/org/oc-bibtex hides /usr/share/emacs/31.0.50/lisp/org/oc-bibtex /home/steb/.config/emacs/elpaca/builds/org/oc-biblatex hides /usr/share/emacs/31.0.50/lisp/org/oc-biblatex /home/steb/.config/emacs/elpaca/builds/org/oc-basic hides /usr/share/emacs/31.0.50/lisp/org/oc-basic /home/steb/.config/emacs/elpaca/builds/org/ob hides /usr/share/emacs/31.0.50/lisp/org/ob /home/steb/.config/emacs/elpaca/builds/org/ob-tangle hides /usr/share/emacs/31.0.50/lisp/org/ob-tangle /home/steb/.config/emacs/elpaca/builds/org/ob-table hides /usr/share/emacs/31.0.50/lisp/org/ob-table /home/steb/.config/emacs/elpaca/builds/org/ob-sqlite hides /usr/share/emacs/31.0.50/lisp/org/ob-sqlite /home/steb/.config/emacs/elpaca/builds/org/ob-sql hides /usr/share/emacs/31.0.50/lisp/org/ob-sql /home/steb/.config/emacs/elpaca/builds/org/ob-shell hides /usr/share/emacs/31.0.50/lisp/org/ob-shell /home/steb/.config/emacs/elpaca/builds/org/ob-sed hides /usr/share/emacs/31.0.50/lisp/org/ob-sed /home/steb/.config/emacs/elpaca/builds/org/ob-screen hides /usr/share/emacs/31.0.50/lisp/org/ob-screen /home/steb/.config/emacs/elpaca/builds/org/ob-scheme hides /usr/share/emacs/31.0.50/lisp/org/ob-scheme /home/steb/.config/emacs/elpaca/builds/org/ob-sass hides /usr/share/emacs/31.0.50/lisp/org/ob-sass /home/steb/.config/emacs/elpaca/builds/org/ob-ruby hides /usr/share/emacs/31.0.50/lisp/org/ob-ruby /home/steb/.config/emacs/elpaca/builds/org/ob-ref hides /usr/share/emacs/31.0.50/lisp/org/ob-ref /home/steb/.config/emacs/elpaca/builds/org/ob-python hides /usr/share/emacs/31.0.50/lisp/org/ob-python /home/steb/.config/emacs/elpaca/builds/org/ob-processing hides /usr/share/emacs/31.0.50/lisp/org/ob-processing /home/steb/.config/emacs/elpaca/builds/org/ob-plantuml hides /usr/share/emacs/31.0.50/lisp/org/ob-plantuml /home/steb/.config/emacs/elpaca/builds/org/ob-perl hides /usr/share/emacs/31.0.50/lisp/org/ob-perl /home/steb/.config/emacs/elpaca/builds/org/ob-org hides /usr/share/emacs/31.0.50/lisp/org/ob-org /home/steb/.config/emacs/elpaca/builds/org/ob-octave hides /usr/share/emacs/31.0.50/lisp/org/ob-octave /home/steb/.config/emacs/elpaca/builds/org/ob-ocaml hides /usr/share/emacs/31.0.50/lisp/org/ob-ocaml /home/steb/.config/emacs/elpaca/builds/org/ob-maxima hides /usr/share/emacs/31.0.50/lisp/org/ob-maxima /home/steb/.config/emacs/elpaca/builds/org/ob-matlab hides /usr/share/emacs/31.0.50/lisp/org/ob-matlab /home/steb/.config/emacs/elpaca/builds/org/ob-makefile hides /usr/share/emacs/31.0.50/lisp/org/ob-makefile /home/steb/.config/emacs/elpaca/builds/org/ob-lua hides /usr/share/emacs/31.0.50/lisp/org/ob-lua /home/steb/.config/emacs/elpaca/builds/org/ob-lob hides /usr/share/emacs/31.0.50/lisp/org/ob-lob /home/steb/.config/emacs/elpaca/builds/org/ob-lisp hides /usr/share/emacs/31.0.50/lisp/org/ob-lisp /home/steb/.config/emacs/elpaca/builds/org/ob-lilypond hides /usr/share/emacs/31.0.50/lisp/org/ob-lilypond /home/steb/.config/emacs/elpaca/builds/org/ob-latex hides /usr/share/emacs/31.0.50/lisp/org/ob-latex /home/steb/.config/emacs/elpaca/builds/org/ob-julia hides /usr/share/emacs/31.0.50/lisp/org/ob-julia /home/steb/.config/emacs/elpaca/builds/org/ob-js hides /usr/share/emacs/31.0.50/lisp/org/ob-js /home/steb/.config/emacs/elpaca/builds/org/ob-java hides /usr/share/emacs/31.0.50/lisp/org/ob-java /home/steb/.config/emacs/elpaca/builds/org/ob-haskell hides /usr/share/emacs/31.0.50/lisp/org/ob-haskell /home/steb/.config/emacs/elpaca/builds/org/ob-groovy hides /usr/share/emacs/31.0.50/lisp/org/ob-groovy /home/steb/.config/emacs/elpaca/builds/org/ob-gnuplot hides /usr/share/emacs/31.0.50/lisp/org/ob-gnuplot /home/steb/.config/emacs/elpaca/builds/org/ob-fortran hides /usr/share/emacs/31.0.50/lisp/org/ob-fortran /home/steb/.config/emacs/elpaca/builds/org/ob-forth hides /usr/share/emacs/31.0.50/lisp/org/ob-forth /home/steb/.config/emacs/elpaca/builds/org/ob-exp hides /usr/share/emacs/31.0.50/lisp/org/ob-exp /home/steb/.config/emacs/elpaca/builds/org/ob-eval hides /usr/share/emacs/31.0.50/lisp/org/ob-eval /home/steb/.config/emacs/elpaca/builds/org/ob-eshell hides /usr/share/emacs/31.0.50/lisp/org/ob-eshell /home/steb/.config/emacs/elpaca/builds/org/ob-emacs-lisp hides /usr/share/emacs/31.0.50/lisp/org/ob-emacs-lisp /home/steb/.config/emacs/elpaca/builds/org/ob-dot hides /usr/share/emacs/31.0.50/lisp/org/ob-dot /home/steb/.config/emacs/elpaca/builds/org/ob-ditaa hides /usr/share/emacs/31.0.50/lisp/org/ob-ditaa /home/steb/.config/emacs/elpaca/builds/org/ob-css hides /usr/share/emacs/31.0.50/lisp/org/ob-css /home/steb/.config/emacs/elpaca/builds/org/ob-core hides /usr/share/emacs/31.0.50/lisp/org/ob-core /home/steb/.config/emacs/elpaca/builds/org/ob-comint hides /usr/share/emacs/31.0.50/lisp/org/ob-comint /home/steb/.config/emacs/elpaca/builds/org/ob-clojure hides /usr/share/emacs/31.0.50/lisp/org/ob-clojure /home/steb/.config/emacs/elpaca/builds/org/ob-calc hides /usr/share/emacs/31.0.50/lisp/org/ob-calc /home/steb/.config/emacs/elpaca/builds/org/ob-awk hides /usr/share/emacs/31.0.50/lisp/org/ob-awk /home/steb/.config/emacs/elpaca/builds/org/ob-R hides /usr/share/emacs/31.0.50/lisp/org/ob-R /home/steb/.config/emacs/elpaca/builds/org/ob-C hides /usr/share/emacs/31.0.50/lisp/org/ob-C Features: (shadow sort mail-extr emacsbug hexl consult-flymake cape-char cape consult-org evil-collection-dictionary dictionary dictionary-connection nerd-icons-dired diredfl dired-filter dired-hacks-utils dired-x evil-collection-embark embark-org embark-consult embark evil-collection-eglot eglot external-completion jsonrpc evil-collection-ert ert ewoc web-mode bash-completion app-launcher display-line-numbers ffap tabify evil-collection-man man evil-collection-proced proced eshell-syntax-highlighting em-elecslash em-ls em-glob em-extpipe em-dirs em-basic em-alias consult-xref evil-collection-xref xref misearch multi-isearch vc-hg vc-bzr vc-src vc-sccs vc-svn vc-cvs vc-rcs evil-collection-log-view log-view info-colors evil-collection-helpful helpful cc-langs cc-vars cc-defs trace evil-collection-edebug edebug evil-collection-debug debug backtrace info-look evil-collection-info info help-fns radix-tree evil-collection-elisp-refs elisp-refs checkdoc package-lint-flymake package-lint evil-collection-finder finder finder-inf lisp-mnt vc windmove conf-mode mule-util vertico-sort tramp-cmds rainbow-mode rainbow-delimiters network-stream url-cache evil-collection-vc-git vc-git vc-dispatcher vertico-repeat evil-collection-consult consult tramp-cache time-stamp filechooser pinentry evil-collection-atomic-chrome atomic-chrome websocket bindat iwd hex-util i3bar ednc exwm-xsettings xcb-xsettings exwm-background exwm-systemtray xcb-systemtray xcb-xembed exwm-randr xcb-randr exwm exwm-input xcb-keysyms xcb-xkb exwm-manage exwm-floating xcb-cursor xcb-render exwm-layout exwm-workspace exwm-core xcb-ewmh xcb-icccm xcb xcb-xproto xcb-types xcb-debug mlscroll visual-fill-column org-contacts org-capture evil-org-agenda org-agenda gnus-art mm-uu mml2015 gnus-sum shr pixel-fill kinsoku url-file svg dom gnus-group gnus-undo gnus-start gnus-dbus gnus-cloud nnimap nnmail mail-source utf7 nnoo gnus-spec gnus-int gnus-range gnus-win evil-collection-gnus gnus nnheader range ligature org-appear stripspace flymake-languagetool evil-collection-flymake flymake oc-basic bibtex ol-man ol-info ol-docview evil-collection-doc-view doc-view jka-compr evil-collection-image image-mode exif simple-auto-compile saveplace savehist show-font org-protocol org-bookmark-heading evil-org org-modern ob-dot ob-latex ob-python evil-collection-python python ob-gnuplot ob-calc calc-store calc-trail calc-ext evil-collection-calc calc calc-loaddefs calc-macs ob-shell edraw-org edraw-util edraw-msg cl-print org-element org-persist org-id org-refile avl-tree evil-collection-org org-crypt org ob ob-tangle ob-ref ob-lob ob-table ob-exp org-macro org-src evil-collection-sh-script sh-script smie treesit executable ob-comint org-element-ast inline org-pcomplete org-list org-footnote org-faces org-entities ob-emacs-lisp ob-core ob-eval org-cycle org-table ol org-fold org-fold-core org-keys oc org-compat org-version org-macs notmuch-addr notmuch-bookmarks evil-collection-notmuch notmuch notmuch-tree notmuch-jump notmuch-hello notmuch-show notmuch-print notmuch-crypto notmuch-mua notmuch-message notmuch-draft notmuch-maildir-fcc notmuch-address notmuch-company notmuch-parser notmuch-wash coolj goto-addr icalendar diary-lib diary-loaddefs evil-collection-calendar cal-menu calendar cal-loaddefs notmuch-tag notmuch-lib notmuch-compat mm-view mml-smime smime dig evil-collection-eat eat term/xterm xterm tramp-sh tramp trampver tramp-integration tramp-message tramp-compat tramp-loaddefs evil-collection-term term ehelp evil-collection-forge forge-repos forge-tablist hl-line forge-topics forge-commands forge-semi forge-bitbucket forge-gogs forge-gitea forge-gitlab forge-github forge-forgejo forge-notify forge-revnote forge-pullreq forge-issue forge-discussion forge-topic yaml parse-time iso8601 eieio-custom bug-reference magit-bookmark evil-collection-bookmark bookmark forge-post evil-collection-markdown-mode markdown-mode edit-indirect evil-collection-outline noutline outline forge-repo forge forge-core ghub-graphql treepy gsexp ghub url-http url-gw nsm url-auth let-alist gnutls forge-db closql emacsql-sqlite emacsql emacsql-compiler eieio-base evil-collection-magit-todos magit-todos pcre2el rxt advice re-builder f s dash nerd-icons-grep evil-collection-grep grep evil-collection-magit magit-submodule magit-blame magit-stash magit-reflog magit-bisect magit-push magit-pull magit-fetch magit-clone magit-remote gptel-commit gptel-gh secrets dbus posframe evil-collection-compile compile xml gptel-ollama evil-collection-gptel gptel gptel-openai magit-commit magit-sequence magit-notes magit-worktree magit-tag magit-merge magit-branch magit-reset magit-files magit-refs magit-status magit evil-collection-package-menu package url-handlers evil-collection-magit-repos magit-repos magit-apply magit-wip magit-log which-func evil-collection-imenu imenu magit-diff evil-collection-smerge-mode smerge-mode diff diff-mode track-changes git-commit evil-collection-log-edit log-edit message sendmail yank-media puny dired-async async dired-aux evil-collection-dired dired dired-loaddefs rfc822 mml mml-sec evil-collection-epa epa epg rfc6068 epg-config gnus-util time-date mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045 mm-util ietf-drums mail-prsvr mailabbrev mail-utils gmm-utils mailheader pcvs-util add-log magit-core magit-autorevert magit-margin magit-transient magit-process evil-collection-with-editor with-editor shell server magit-mode transient browse-url benchmark magit-git magit-base evil-collection-magit-section magit-section format-spec cursor-sensor crm llama yasnippet evil-collection-ultra-scroll ultra-scroll pixel-scroll cua-base hl-todo marginalia nerd-icons-corfu nerd-icons-completion nerd-icons nerd-icons-faces nerd-icons-data nerd-icons-data-mdicon nerd-icons-data-flicon nerd-icons-data-codicon nerd-icons-data-devicon nerd-icons-data-sucicon nerd-icons-data-wicon nerd-icons-data-faicon nerd-icons-data-powerline nerd-icons-data-octicon nerd-icons-data-pomicon nerd-icons-data-ipsicon jinx visual-replace evil-collection-which-key which-key vertico-multiform vertico corfu-popupinfo evil-collection-corfu corfu orderless isearch-mb evil-goggles pulse face-remap color evil-args evil-surround evil-collection-tabulated-list evil-collection-tab-bar evil-collection-simple evil-collection-replace evil-collection-process-menu evil-collection-kmacro evil-collection-indent evil-collection-help evil-collection-elisp-mode evil-collection-eldoc evil-collection-elpaca evil-collection-custom evil-collection-comint evil-collection-buff-menu evil-collection annalist ednc-autoloads i3bar-autoloads discomfort-autoloads debase-autoloads iwd-autoloads bluetooth-autoloads app-launcher-autoloads atomic-chrome-autoloads websocket-autoloads pinentry-autoloads playerctl-autoloads exwm-autoloads xelb-autoloads ol-notmuch-autoloads microdata-autoloads notmuch-addr-autoloads eshell-syntax-highlighting-autoloads eat-autoloads git-link-autoloads pr-review-autoloads igist-autoloads magit-todos-autoloads wgrep-autoloads watch-autoloads tmr-autoloads syncthing-autoloads pcre2el-autoloads qrencode-autoloads password-store-menu-autoloads password-store-autoloads named-pipe-autoloads elpher-autoloads info-colors-autoloads helpful-autoloads elisp-refs-autoloads devdocs-autoloads whisper-autoloads gptel-commit-autoloads gptel-autoloads copilot-autoloads journalctl-autoloads systemctl-autoloads proced-narrow-autoloads show-font-autoloads dbus-explore-autoloads disk-usage-autoloads dired-filter-autoloads dired-hacks-utils-autoloads f-autoloads s-autoloads dash-autoloads diredfl-autoloads org-bookmark-heading-autoloads notmuch-bookmarks-autoloads pdf-tools-autoloads tablist-autoloads nov-autoloads esxml-autoloads calibre-autoloads vcard-autoloads org-contacts-autoloads calfw-autoloads orgit-forge-autoloads forge-autoloads closql-autoloads emacsql-autoloads ghub-autoloads treepy-autoloads yaml-autoloads orgit-autoloads magit-autoloads magit-section-autoloads with-editor-autoloads evil-org-autoloads org-download-autoloads async-autoloads org-appear-autoloads org-modern-autoloads org-loaddefs edit-indirect-autoloads markdown-mode-autoloads web-mode-autoloads wat-ts-mode-autoloads comint-mime-autoloads mathjax-autoloads flymake-ruff-autoloads package-lint-flymake-autoloads package-lint-autoloads eff-autoloads pkgbuild-mode-autoloads gnuplot-autoloads graphviz-dot-mode-autoloads edraw-autoloads csv-mode-autoloads udev-mode-autoloads systemd-autoloads ssh-config-mode-autoloads nftables-mode-autoloads git-modes-autoloads rmsbolt-autoloads rust-playground-autoloads flymake-languagetool-autoloads consult-eglot-autoloads dape-autoloads casual-autoloads notmuch-transient-autoloads transient-autoloads bash-completion-autoloads cape-autoloads yasnippet-autoloads iwindow-autoloads consult-project-extra-autoloads mlscroll-autoloads ultra-scroll-autoloads ligature-autoloads hl-todo-autoloads rainbow-mode-autoloads marginalia-autoloads posframe-autoloads rainbow-delimiters-autoloads visual-fill-column-autoloads nerd-icons-grep-autoloads nerd-icons-corfu-autoloads nerd-icons-ibuffer-autoloads nerd-icons-completion-autoloads nerd-icons-dired-autoloads nerd-icons-autoloads link-hint-autoloads avy-autoloads snapshot-timemachine-autoloads stripspace-autoloads vundo-autoloads jinx-autoloads visual-replace-autoloads vertico-autoloads corfu-autoloads orderless-autoloads isearch-mb-autoloads embark-consult-autoloads consult-autoloads embark-autoloads evil-goggles-autoloads evil-nerd-commenter-autoloads evil-args-autoloads evil-surround-autoloads evil-collection-autoloads annalist-autoloads filechooser-autoloads em-prompt text-property-search em-hist em-unix em-pred esh-mode esh-var eshell esh-cmd generator esh-ext esh-proc esh-opt esh-io esh-arg pcomplete comint ansi-osc ansi-color esh-module esh-module-loaddefs esh-util help-at-pt files-x recentf tree-widget editorconfig editorconfig-core editorconfig-core-handle editorconfig-fnmatch project disp-table modus-vivendi-theme modus-themes derived pcase autorevert filenotify mb-depth minibuf-eldef evil evil-integration evil-maps evil-commands reveal evil-jumps evil-command-window evil-types evil-search evil-ex evil-macros evil-repeat evil-states evil-core comp-run evil-common thingatpt rect evil-vars ring edmacro kmacro evil-autoloads goto-chg-autoloads general general-autoloads llama-autoloads simple-auto-compile-autoloads mode-local find-func elpaca-menu-elpa no-littering compat no-littering-autoloads elpaca-menu-melpa elpaca-menu-org elpaca-use-package use-package use-package-ensure use-package-delight use-package-diminish use-package-bind-key bind-key easy-mmode use-package-core elpaca-use-package-autoloads elpaca-log elpaca-ui url url-proxy url-privacy url-expand url-methods url-history url-cookie generate-lisp-file url-domsuf url-util url-parse auth-source eieio eieio-core cl-macs password-cache json map byte-opt url-vars mailcap elpaca elpaca-process elpaca-autoloads notmuch-version comp cl-seq comp-cstr cl-extra help-mode comp-common warnings subr-x rx gv bytecomp byte-compile xdg cus-edit pp cus-start cus-load icons wid-edit cl-loaddefs cl-lib rmc iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win term/common-win x-dnd touch-screen tool-bar dnd fontset image regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic indonesian philippine cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp files window text-properties overlay sha1 md5 base64 format env code-pages mule custom widget keymap hashtable-print-readable backquote threads dbusbind inotify lcms2 dynamic-setting font-render-setting cairo xinput2 x multi-tty move-toolbar make-network-process tty-child-frames native-compile mps emacs) Memory information: ((conses 24 0 0) (symbols 56 0 0) (strings 40 0 0) (string-bytes 1 0) (vectors 24 0) (vector-slots 8 0 0) (floats 24 0 0) (intervals 64 0 0) (buffers 1072 0)) From debbugs-submit-bounces@debbugs.gnu.org Sat Jul 12 05:07:13 2025 Received: (at 78984) by debbugs.gnu.org; 12 Jul 2025 09:07:13 +0000 Received: from localhost ([127.0.0.1]:43834 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uaWCP-0006AC-7x for submit@debbugs.gnu.org; Sat, 12 Jul 2025 05:07:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:41436) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uaWCM-00069i-GC for 78984@debbugs.gnu.org; Sat, 12 Jul 2025 05:07:10 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uaWC8-00012G-My; Sat, 12 Jul 2025 05:07:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=jRHwn5HxsQXW9VacGSO0//70OD9YizQYfyFUzmC+IXc=; b=ixJCSeR+LHqN VmAKfU4Bv6BEdbV731fUxVngBR5/QbJX4vE+RQglOP2bJkXYAJrj/P3Jd8axu+tio8cGxgY1WFXnN pX2GGx2KksFDL0P354HFA+foZehNAOjQB7rx59Fci9KH2rQJXkV/Aov4v0lGK+uShLfS94/J4WQ0d WPOHMsZcj5Xb9VqPZrUZKzFogLDom4jjIr+i15JyIorJ7EWl9yCP7UcVbf/iyepaOmxavtTa8gWkZ /5nJZgIAImO/MhBsl78mpb2wmw5gjCIh1z1plJtAiLEZL0Rvz6R/HZtSpJtpMePvk3aR9V1h/XWcP tniFDXX9dY9i0eymoslRUQ==; Date: Sat, 12 Jul 2025 12:06:52 +0300 Message-Id: <86o6tpeq1f.fsf@gnu.org> From: Eli Zaretskii To: Steven Allen In-Reply-To: <87ecupxdci.fsf@stebalien.com> (bug-gnu-emacs@gnu.org) Subject: Re: bug#78984: 31.0.50; `url-build-query-string' fails to escape a literal `%' in keys and values References: <87ecupxdci.fsf@stebalien.com> X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 78984 Cc: 78984@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > Date: Wed, 09 Jul 2025 14:29:17 -0700 > From: Steven Allen via "Bug reports for GNU Emacs, > the Swiss army knife of text editors" > > > `url-build-query-string' fails to escape literal `%' characters and keys > and values. To reproduce, run the following and note that it's encoded > as "%%3D" when it should be encoded as "%25%3D". > > emacs --batch --eval '(message "%s" (url-build-query-string (list (list "key" "%="))))' > > The root cause appears to be that `%' is explicitly allowed in > `url-host-allowed-chars' (inherited by > `url-query-key-value-allowed-chars'), apparently to avoid re-encoding > %-encoded sequences. Unfortunately, changing this will definitely break > things (e.g., `url-encode-url' will no longer round-trip). > > The direct/simple fix would be to forbid `%' in > `url-query-key-value-allowed-chars'. > > This issue also appears to affect Eglot's `eglot-path-to-uri' function > (`eglot--uri-path-allowed-chars' allows `%' in path-names), > but I haven't been able to find a stand-alone reproducer. How about documenting that url-build-query-string should already have any literal % characters encoded as %25, and changing all the callers to abide by that requirement? From debbugs-submit-bounces@debbugs.gnu.org Sat Jul 12 11:51:50 2025 Received: (at 78984) by debbugs.gnu.org; 12 Jul 2025 15:51:50 +0000 Received: from localhost ([127.0.0.1]:46871 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uacVy-0004wv-2J for submit@debbugs.gnu.org; Sat, 12 Jul 2025 11:51:50 -0400 Received: from fhigh-b7-smtp.messagingengine.com ([202.12.124.158]:37213) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uacVu-0004wU-PR for 78984@debbugs.gnu.org; Sat, 12 Jul 2025 11:51:47 -0400 Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfhigh.stl.internal (Postfix) with ESMTP id 33A557A0054; Sat, 12 Jul 2025 11:51:41 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-01.internal (MEProxy); Sat, 12 Jul 2025 11:51:41 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=stebalien.com; h=cc:cc:content-type:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1752335501; x= 1752421901; bh=/BPv0nCx+i870QNgSACX9Hx0BZPjVvp6IxU0sHxn0vk=; b=V D+B4Y6or1F7XzslnSfhBmIHF8A9JpBf7jR2USo2mTlJMeF37hcMu6V9NY9SlR/S7 hpTi7vgAO/PPluGIrPrZHPZ5woaVUKt7zRQtTwFiauHFmP7P6uyL2gPJHnFCk2En UbzOX8vv1iTR8Gi9kfZimiS24mBqMRmFjzXpiQFWR/RW2rEFYvXmW98EsTHWS3Wv 5EKsMx91dsyxJ+eNpMkpjla05zzsNnyc4hm8iR0ISZT3ERijavhDLGOs8nKtCvfm 4p3YPBylmdOM7W30Fb3akKu7P0aEEghVOhgxtzBk7cNrqo0UE7yEv+2ZZWcsTCa8 HJbykUNhpYzf91BUEK7ZA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t= 1752335501; x=1752421901; bh=/BPv0nCx+i870QNgSACX9Hx0BZPjVvp6IxU 0sHxn0vk=; b=oJ09t1xZIpf78U9W8V8nhtINZHaCbVMQfhmlqimVlTH/2uNvvV4 Imz8LVe5zcYnJlS1diR1KvzssWj5wynzXVTUUFFmsjD0YykqJtJnYH9GdeBDzTDT UAeylVFnkdowaqAGJaf1GbVsRzery6+WdvTemkAB8FRRLWSmu1JlKSSWuk9Cg9JR kqGxLvk//Pm308oS+ahjpU/D6emWSpXeNCrAZmjc9JkNMjzFt0ZJaOc9funshYfP 6vMxRagewtPvsaPcvZzSbUjQULvzGh9p6EAbLKgMTCLjeA9PaAjZjab1NNjW/j+l bpgY9Xpi1Ucua/mUtsFKIlVjHpCGLmUQ9zw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdegieeiudcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufgjfhffkfggtgesthdtredttddttdenucfhrhhomhepufhtvghvvghnucet lhhlvghnuceoshhtvghvvghnsehsthgvsggrlhhivghnrdgtohhmqeenucggtffrrghtth gvrhhnpedvkeehkeegleehheeggfduleektefhhffgueffteekgedtvdefuddutddtjeej vdenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehsth gvvhgvnhesshhtvggsrghlihgvnhdrtghomhdpnhgspghrtghpthhtohepvddpmhhouggv pehsmhhtphhouhhtpdhrtghpthhtohepvghlihiisehgnhhurdhorhhgpdhrtghpthhtoh epjeekleekgeesuggvsggsuhhgshdrghhnuhdrohhrgh X-ME-Proxy: Feedback-ID: ie8a146a7:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sat, 12 Jul 2025 11:51:40 -0400 (EDT) From: Steven Allen To: Eli Zaretskii Subject: Re: bug#78984: 31.0.50; `url-build-query-string' fails to escape a literal `%' in keys and values In-Reply-To: <86o6tpeq1f.fsf@gnu.org> References: <87ecupxdci.fsf@stebalien.com> <86o6tpeq1f.fsf@gnu.org> Date: Sat, 12 Jul 2025 08:51:38 -0700 Message-ID: <87y0stif05.fsf@stebalien.com> MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 78984 Cc: 78984@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) Eli Zaretskii writes: >> Date: Wed, 09 Jul 2025 14:29:17 -0700 >> From: Steven Allen via "Bug reports for GNU Emacs, >> the Swiss army knife of text editors" >> >> >> `url-build-query-string' fails to escape literal `%' characters and keys >> and values. To reproduce, run the following and note that it's encoded >> as "%%3D" when it should be encoded as "%25%3D". >> >> emacs --batch --eval '(message "%s" (url-build-query-string (list (list "key" "%="))))' >> >> The root cause appears to be that `%' is explicitly allowed in >> `url-host-allowed-chars' (inherited by >> `url-query-key-value-allowed-chars'), apparently to avoid re-encoding >> %-encoded sequences. Unfortunately, changing this will definitely break >> things (e.g., `url-encode-url' will no longer round-trip). >> >> The direct/simple fix would be to forbid `%' in >> `url-query-key-value-allowed-chars'. >> >> This issue also appears to affect Eglot's `eglot-path-to-uri' function >> (`eglot--uri-path-allowed-chars' allows `%' in path-names), >> but I haven't been able to find a stand-alone reproducer. > > How about documenting that url-build-query-string should already have > any literal % characters encoded as %25, and changing all the callers > to abide by that requirement? That sounds like a reasonable solution for `url-host-allowed-chars', `url-path-allowed-chars', `url-query-allowed-chars', and `url-query-key-value-allowed-chars': 1. Allowing `%' is "correct" as `%' is, in fact, allowed in URLs. 2. These variables are used in conjunction with `url-hexify-string' to escape strings that may already be partially %-encoded. 3. From what I can tell, the documentation in these cases is technically correct already, if a bit misleading. However, IMO, `url-build-query-string' should escape everything, including literal `%' characters: 1. `url-parse-query-string', the inverse of `url-build-query-string', decodes %-encoded strings. In order for these two functions to round-trip, `url-build-query-string' needs to escape `%'. Specifically, the following test should pass: (ert-deftest url-query-string-round-trips () (let* ((query-string "foo=%25%3D") (parsed-query (url-parse-query-string query-string)) (round-trip (url-build-query-string parsed-query))) (should (equal round-trip query-string)))) 2. `url-build-query-string' is a higher-level tool to transform structured data into a query string. IMO, the user shouldn't ahve to think about pre-escaping their strings here. I'm happy to provide patches (both to improve the docs and fix this issue) if you think this is a reasonable approach. From debbugs-submit-bounces@debbugs.gnu.org Thu Jul 17 02:34:52 2025 Received: (at 78984) by debbugs.gnu.org; 17 Jul 2025 06:34:52 +0000 Received: from localhost ([127.0.0.1]:52663 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ucICh-0003A8-GV for submit@debbugs.gnu.org; Thu, 17 Jul 2025 02:34:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:54746) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1ucICe-00039r-Lj for 78984@debbugs.gnu.org; Thu, 17 Jul 2025 02:34:49 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ucICZ-0000RX-5J; Thu, 17 Jul 2025 02:34:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=vk87kre0RZJP1dFSueiE6PO0czv9lDsZZuuwrf28SpI=; b=irHQJtvkRj5I /xUw7EVPuBbvI5oobAMGBy0M0Bdfm41HsxbAiBNSPpWMf/kBHcWk68azZoQKlrmgZzKwb804ZEh7g W0WE5c6muUBpxqMVMtbzssdcpDqQEJyvMKHzm77hppmbuXSzhYpTV7iyrLW9i+Lg+7O4Jaa1jvbJb vbEoP6H4tvUcEpKZxemiQhPEvflabh1cl5V/vmyvJP/CPLYhG1dRAyF1+mjAE6tUqwUuzBREtcPqK FLLGHM+0Nv7Gb8TzZSD6/z1N3zeKMpIZ7YsNZU1m2gzOzPUMiG/DO4gcMpt7m9NxR4mnCdRyo7GOB YjglaoljC8YYLMKeDwNa6Q==; Date: Thu, 17 Jul 2025 09:34:39 +0300 Message-Id: <86v7nrgwao.fsf@gnu.org> From: Eli Zaretskii To: Steven Allen In-Reply-To: <87y0stif05.fsf@stebalien.com> (message from Steven Allen on Sat, 12 Jul 2025 08:51:38 -0700) Subject: Re: bug#78984: 31.0.50; `url-build-query-string' fails to escape a literal `%' in keys and values References: <87ecupxdci.fsf@stebalien.com> <86o6tpeq1f.fsf@gnu.org> <87y0stif05.fsf@stebalien.com> X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 78984 Cc: 78984@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Steven Allen > Cc: 78984@debbugs.gnu.org > Date: Sat, 12 Jul 2025 08:51:38 -0700 > > Eli Zaretskii writes: > > >> Date: Wed, 09 Jul 2025 14:29:17 -0700 > >> From: Steven Allen via "Bug reports for GNU Emacs, > >> the Swiss army knife of text editors" > >> > >> > >> `url-build-query-string' fails to escape literal `%' characters and keys > >> and values. To reproduce, run the following and note that it's encoded > >> as "%%3D" when it should be encoded as "%25%3D". > >> > >> emacs --batch --eval '(message "%s" (url-build-query-string (list (list "key" "%="))))' > >> > >> The root cause appears to be that `%' is explicitly allowed in > >> `url-host-allowed-chars' (inherited by > >> `url-query-key-value-allowed-chars'), apparently to avoid re-encoding > >> %-encoded sequences. Unfortunately, changing this will definitely break > >> things (e.g., `url-encode-url' will no longer round-trip). > >> > >> The direct/simple fix would be to forbid `%' in > >> `url-query-key-value-allowed-chars'. > >> > >> This issue also appears to affect Eglot's `eglot-path-to-uri' function > >> (`eglot--uri-path-allowed-chars' allows `%' in path-names), > >> but I haven't been able to find a stand-alone reproducer. > > > > How about documenting that url-build-query-string should already have > > any literal % characters encoded as %25, and changing all the callers > > to abide by that requirement? > > That sounds like a reasonable solution for `url-host-allowed-chars', > `url-path-allowed-chars', `url-query-allowed-chars', and > `url-query-key-value-allowed-chars': > > 1. Allowing `%' is "correct" as `%' is, in fact, allowed in URLs. > > 2. These variables are used in conjunction with `url-hexify-string' to > escape strings that may already be partially %-encoded. > > 3. From what I can tell, the documentation in these cases is technically > correct already, if a bit misleading. > > However, IMO, `url-build-query-string' should escape everything, > including literal `%' characters: > > 1. `url-parse-query-string', the inverse of `url-build-query-string', > decodes %-encoded strings. In order for these two functions to > round-trip, `url-build-query-string' needs to escape `%'. Specifically, > the following test should pass: > > (ert-deftest url-query-string-round-trips () > (let* ((query-string "foo=%25%3D") > (parsed-query (url-parse-query-string query-string)) > (round-trip (url-build-query-string parsed-query))) > (should (equal round-trip query-string)))) > > 2. `url-build-query-string' is a higher-level tool to transform structured > data into a query string. IMO, the user shouldn't ahve to think about > pre-escaping their strings here. > > I'm happy to provide patches (both to improve the docs and fix this > issue) if you think this is a reasonable approach. The situation you described sounds like a contradiction to me: some use cases need url-build-query-string to have literal % encoded as %25, and others need the literal % NOT encoded. In particular, you originally said that the root cause of the problem was that url-path-allowed-chars allows '%', but now you say that url-build-query-string should encode literal '%', although url-path-allowed-chars is okay as it is? So I don't understand what kind of a solution you have in mind; perhaps I'm missing something? I guess I'm confused. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Thu Jul 17 16:02:03 2025 Received: (at 78984) by debbugs.gnu.org; 17 Jul 2025 20:02:04 +0000 Received: from localhost ([127.0.0.1]:57034 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ucUnl-0001dh-Pf for submit@debbugs.gnu.org; Thu, 17 Jul 2025 16:02:03 -0400 Received: from fhigh-a4-smtp.messagingengine.com ([103.168.172.155]:35465) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1ucUnh-0001cl-KH for 78984@debbugs.gnu.org; Thu, 17 Jul 2025 16:01:55 -0400 Received: from phl-compute-10.internal (phl-compute-10.phl.internal [10.202.2.50]) by mailfhigh.phl.internal (Postfix) with ESMTP id A337C140008A; Thu, 17 Jul 2025 16:01:47 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-10.internal (MEProxy); Thu, 17 Jul 2025 16:01:47 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=stebalien.com; h=cc:cc:content-type:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1752782507; x= 1752868907; bh=aGIgpyN7bTO0GJpOSaxbhVV1b8IoxO9J/gTB26gW+H0=; b=l owbOX8fjjCrQhaKTvzMiOiSusYatsUQDZo6SewD39HoP2yutH2PiOXXX4vnFwrjp ccDZKSM8dZGCBQ8YuPLrpAyesVBIyj6gxNsyfPaLzfq73MAxq7HzHUTDcsqlRAf8 SPieWORM8CZ44XqAu1t3jC7DT8RB2xxoHvGJV5AXQ76sflmRY0bpemcJeXhcegEY 3h9TMz027+pmY5fCoBKU5cebfZ5L8k2PSsaoEBJlLyqjy7FMJ+hRNev/KhlPMKJG OppPWWbp3pW3oTWx0I2sa4nbpZdac2gHJKg2PD+ywhqR4jto+OayXlURCuo+wV47 W+um6MmA3Cuegp6VifwLg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t= 1752782507; x=1752868907; bh=aGIgpyN7bTO0GJpOSaxbhVV1b8IoxO9J/gT B26gW+H0=; b=mi+J9ZaruvG4xETffumLWVP/QG/zCaEwbtPzbBTYrHrz7H+GO9C UZ/3a7n7DxmP/b6ere+6svr8wF9O8BBPm4Gu/niojBwWeqYUb025PX9cqYFINX7X gTUYaKx6MMYwb9QBJpopejRwvBjQgvHVSSJqU+OiNVY+vB9PcY8bXjP9OVUzeVmF cHhbtKYAHjYBxPXL6fCrGo5gU0itEEtua5SP+913wq5vagjcoCX5NnphHf1KMEIu ABTfYgUyIlU0yXB/ci4PLtgctQBnDYnAz9BYKCjJ5Jswt4UKwhOAYS0BTCVe3Jcp ASIw2WmDuMpGUyO4Xiq02HKD/Xr95C6+07g== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdeiudeglecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufgjfhffkfggtgesmhdtreertddttdenucfhrhhomhepufhtvghvvghnucet lhhlvghnuceoshhtvghvvghnsehsthgvsggrlhhivghnrdgtohhmqeenucggtffrrghtth gvrhhnpeejudefvdeijeeukedttdegudegffevjeehheeiueelgfffhfelffehfeevhfdv geenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehsth gvvhgvnhesshhtvggsrghlihgvnhdrtghomhdpnhgspghrtghpthhtohepvddpmhhouggv pehsmhhtphhouhhtpdhrtghpthhtohepvghlihiisehgnhhurdhorhhgpdhrtghpthhtoh epjeekleekgeesuggvsggsuhhgshdrghhnuhdrohhrgh X-ME-Proxy: Feedback-ID: ie8a146a7:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 17 Jul 2025 16:01:46 -0400 (EDT) From: Steven Allen To: Eli Zaretskii Subject: Re: bug#78984: 31.0.50; `url-build-query-string' fails to escape a literal `%' in keys and values In-Reply-To: <86v7nrgwao.fsf@gnu.org> References: <87ecupxdci.fsf@stebalien.com> <86o6tpeq1f.fsf@gnu.org> <87y0stif05.fsf@stebalien.com> <86v7nrgwao.fsf@gnu.org> Date: Thu, 17 Jul 2025 13:01:45 -0700 Message-ID: <877c06oac6.fsf@stebalien.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 78984 Cc: 78984@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) --=-=-= Content-Type: text/plain Eli Zaretskii writes: >> That sounds like a reasonable solution for `url-host-allowed-chars', >> `url-path-allowed-chars', `url-query-allowed-chars', and >> `url-query-key-value-allowed-chars': >> >> 1. Allowing `%' is "correct" as `%' is, in fact, allowed in URLs. >> >> 2. These variables are used in conjunction with `url-hexify-string' to >> escape strings that may already be partially %-encoded. >> >> 3. From what I can tell, the documentation in these cases is technically >> correct already, if a bit misleading. >> >> However, IMO, `url-build-query-string' should escape everything, >> including literal `%' characters: >> >> 1. `url-parse-query-string', the inverse of `url-build-query-string', >> decodes %-encoded strings. In order for these two functions to >> round-trip, `url-build-query-string' needs to escape `%'. Specifically, >> the following test should pass: >> >> (ert-deftest url-query-string-round-trips () >> (let* ((query-string "foo=%25%3D") >> (parsed-query (url-parse-query-string query-string)) >> (round-trip (url-build-query-string parsed-query))) >> (should (equal round-trip query-string)))) >> >> 2. `url-build-query-string' is a higher-level tool to transform structured >> data into a query string. IMO, the user shouldn't ahve to think about >> pre-escaping their strings here. >> >> I'm happy to provide patches (both to improve the docs and fix this >> issue) if you think this is a reasonable approach. > > The situation you described sounds like a contradiction to me: some > use cases need url-build-query-string to have literal % encoded as > %25, and others need the literal % NOT encoded. In particular, you > originally said that the root cause of the problem was that > url-path-allowed-chars allows '%', but now you say that > url-build-query-string should encode literal '%', although > url-path-allowed-chars is okay as it is? So I don't understand what > kind of a solution you have in mind; perhaps I'm missing something? > > I guess I'm confused. > > Thanks. I apologize, I shouldn't have called that the root cause. `url-path-allowed-chars' allowing % isn't incorrect, it's just the ultimate reason `url-build-query-string' passes through literal % characters without encoding them. As a matter of fact, this (`url-path-allowed-chars') cannot be changed without breaking `url-path-and-query' and `url-encode-url' as I will explain below: First, `url-path-and-query' must not %-decode the path and the query as that would make it impossible to parse them correctly. E.g., "/some%2fpath" must not be decoded as "/some/path" before splitting the path into components and the same goes for query strings with respect to & and =. Specifically, I'm referring to the following in `url-encode-url': (let* ... (path-and-query (url-path-and-query obj)) Therefore, `url-encode-url' must not %-encode literal % characters when encoding the path and query because they were not (nor could they have been) %-decoded by `url-path-and-query'. Specifically, I'm referring to the following in `url-encode-url': (if path (setq path (url-hexify-string path url-path-allowed-chars))) (if query (setq query (url-hexify-string query url-query-allowed-chars))) That's why `url-path-allowed-chars' and `url-query-allowed-chars' must allow literal % characters without re-encoding them. However, `url-build-query-string' and `url-parse-query-string' are different. Unlike `url-path-and-query', `url-parse-query-string' decodes the query into a structured object (a key/values alist) and can (and does) completely %-decode the keys & values. That means the inverse, `url-build-query-string', should assume that its inputs are not already %-encoded and should %-encode literal % characters. I've attached a patch to show you what I mean. In this patch, I introduced a new `url--query-key-value-preserved-chars' constant, separate from `url-query-key-value-allowed-chars', to keep `url-query-key-value-allowed-chars' consistent with the other `-allowed-chars' constants. That is, while % is ALLOWED to appear in encoded query keys and values, it shouldn't be PRESERVED when %-escaping them. (I'm also happy to change `url-query-key-value-allowed-chars' directly if that's what you'd prefer) --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-encode-literal-characters-when-building-query-string.patch >From 613098b7718d7e8b48f6c40bbcdffb0cb850a347 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 17 Jul 2025 11:14:45 -0700 Subject: [PATCH] %-encode literal % characters when building query strings When building a query string via `url-build-query-string', %-encode literal % characters appearing in both the keys and the values. * lisp/url/url-util.el (url--query-key-value-preserved-chars): Define a new constant based on `url-query-key-value-allowed-chars' specifying the characters that should be preserved when %-encoding query-string keys and values. (url-build-query-string): Use the new constant (fixes Bug#78984). * test/lisp/url-url-test-tests.el (url-util-tests): Add a test. --- lisp/url/url-util.el | 9 ++++++++- test/lisp/url/url-util-tests.el | 8 ++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lisp/url/url-util.el b/lisp/url/url-util.el index 8435114bbc2..47ef8811c5e 100644 --- a/lisp/url/url-util.el +++ b/lisp/url/url-util.el @@ -409,6 +409,13 @@ url-encode-url (url-hexify-string frag url-query-allowed-chars))) (url-recreate-url obj))) +(defconst url--query-key-value-preserved-chars + (let ((vec (copy-sequence url-query-key-value-allowed-chars))) + (aset vec ?% nil) + vec) + "Byte mask used for %-encoding keys and values in the query segment of a URI. +`url-query-key-value-allowed-chars' minus '%'.") + ;;;###autoload (defun url-build-query-string (query &optional semicolons keep-empty) "Build a query-string. @@ -436,7 +443,7 @@ url-build-query-string (let ((escaped (mapcar (lambda (sym) (url-hexify-string (format "%s" sym) - url-query-key-value-allowed-chars)) + url--query-key-value-preserved-chars)) key-vals))) (mapconcat (lambda (val) (let ((vprint (format "%s" val)) diff --git a/test/lisp/url/url-util-tests.el b/test/lisp/url/url-util-tests.el index d34bfc8509c..6e79a798333 100644 --- a/test/lisp/url/url-util-tests.el +++ b/test/lisp/url/url-util-tests.el @@ -33,10 +33,10 @@ url-util-tests ((key1 "val1") (key2 val2) (key3 val1 val2) ("key4") (key5 "")) t) ("key1=val1;key2=val2;key3=val1;key3=val2;key4=;key5=" ((key1 val1) (key2 val2) ("key3" val1 val2) (key4) (key5 "")) t t) - ("key1=val/slash;key2=val%3Bsemi;key3=val%26amp;key4=val%3Deq" - ((key1 "val/slash") (key2 "val;semi") (key3 "val&") (key4 "val=eq")) t) - ("key%3Deq=val1;key%3Bsemi=val2;key%26amp=val3" - (("key=eq" val1) ("key;semi" val2) ("key&" val3)) t))) + ("key1=val/slash;key2=val%3Bsemi;key3=val%26amp;key4=val%3Deq;key5=val%25perc" + ((key1 "val/slash") (key2 "val;semi") (key3 "val&") (key4 "val=eq") (key5 "val%perc")) t) + ("key%3Deq=val1;key%3Bsemi=val2;key%26amp=val3;key%25perc=val4" + (("key=eq" val1) ("key;semi" val2) ("key&" val3) ("key%perc" val4)) t))) test) (while tests (setq test (car tests) -- 2.50.1 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Sat Jul 26 05:05:48 2025 Received: (at 78984) by debbugs.gnu.org; 26 Jul 2025 09:05:48 +0000 Received: from localhost ([127.0.0.1]:39867 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ufaqi-0002Di-2M for submit@debbugs.gnu.org; Sat, 26 Jul 2025 05:05:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:41628) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1ufaqg-0002DJ-9y for 78984@debbugs.gnu.org; Sat, 26 Jul 2025 05:05:46 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ufaqa-0000xO-T8; Sat, 26 Jul 2025 05:05:40 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=QhULeVu+RVuEAx7alraDTTTmv5NUVevAThYw2Dwtju8=; b=EKGiUxpzZyrh 6L++Tvk/8v5iqzJSb+aQnpJm3qdLXF2ob6Y5qDMz+bmkg7HsF/NSX9Rzk8cpG+z5YKrxRnpDlJHEO zVtcLpFossw22i9r4GTVuU5HzOjhUcjNMGoP4cEP88athBWagsI3YWJiwdk6W0RC8Pgz/rBycgA7N M1ilFL2wqaLn/j1H+VYpoiKJZbbCg41WOZhCjS7ToyufMbY+uOJeeB3w1SShpMmK+Nk73hmPofctI hiangoKhYnNhyf1NDHaO5aBSeMnwi2FQcCZNtU09A/qBJAbUvhxN2hk/kt1REcdetFGDeMUSLyLtX BOE1+Z8U1gJp4j64NdXqCA==; Date: Sat, 26 Jul 2025 12:05:32 +0300 Message-Id: <86ldob1fvn.fsf@gnu.org> From: Eli Zaretskii To: Steven Allen In-Reply-To: <877c06oac6.fsf@stebalien.com> (message from Steven Allen on Thu, 17 Jul 2025 13:01:45 -0700) Subject: Re: bug#78984: 31.0.50; `url-build-query-string' fails to escape a literal `%' in keys and values References: <87ecupxdci.fsf@stebalien.com> <86o6tpeq1f.fsf@gnu.org> <87y0stif05.fsf@stebalien.com> <86v7nrgwao.fsf@gnu.org> <877c06oac6.fsf@stebalien.com> X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 78984 Cc: 78984@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Steven Allen > Cc: 78984@debbugs.gnu.org > Date: Thu, 17 Jul 2025 13:01:45 -0700 > > Eli Zaretskii writes: > > I guess I'm confused. > > > > Thanks. > > I apologize, I shouldn't have called that the root cause. > `url-path-allowed-chars' allowing % isn't incorrect, it's just the > ultimate reason `url-build-query-string' passes through literal % > characters without encoding them. As a matter of fact, this > (`url-path-allowed-chars') cannot be changed without breaking > `url-path-and-query' and `url-encode-url' as I will explain below: > > First, `url-path-and-query' must not %-decode the path and the query as > that would make it impossible to parse them correctly. E.g., > "/some%2fpath" must not be decoded as "/some/path" before splitting the > path into components and the same goes for query strings with respect to > & and =. Specifically, I'm referring to the following in `url-encode-url': > > (let* ... > (path-and-query (url-path-and-query obj)) > > Therefore, `url-encode-url' must not %-encode literal % characters when > encoding the path and query because they were not (nor could they have > been) %-decoded by `url-path-and-query'. Specifically, I'm referring to > the following in `url-encode-url': > > (if path > (setq path (url-hexify-string path url-path-allowed-chars))) > (if query > (setq query (url-hexify-string query url-query-allowed-chars))) > > That's why `url-path-allowed-chars' and `url-query-allowed-chars' must > allow literal % characters without re-encoding them. > > However, `url-build-query-string' and `url-parse-query-string' are > different. Unlike `url-path-and-query', `url-parse-query-string' decodes > the query into a structured object (a key/values alist) and can (and > does) completely %-decode the keys & values. That means the inverse, > `url-build-query-string', should assume that its inputs are not > already %-encoded and should %-encode literal % characters. > > I've attached a patch to show you what I mean. In this patch, I > introduced a new `url--query-key-value-preserved-chars' constant, > separate from `url-query-key-value-allowed-chars', to keep > `url-query-key-value-allowed-chars' consistent with the other > `-allowed-chars' constants. That is, while % is ALLOWED to appear in > encoded query keys and values, it shouldn't be PRESERVED when %-escaping > them. This patch is fine. If it is a final version and passes all the tests, I will install it. If you have further updates, please post, and I will install then. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Sat Jul 26 16:02:31 2025 Received: (at 78984) by debbugs.gnu.org; 26 Jul 2025 20:02:32 +0000 Received: from localhost ([127.0.0.1]:45295 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ufl6F-00019h-D1 for submit@debbugs.gnu.org; Sat, 26 Jul 2025 16:02:31 -0400 Received: from fout-b6-smtp.messagingengine.com ([202.12.124.149]:38461) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1ufl6C-00019C-3F for 78984@debbugs.gnu.org; Sat, 26 Jul 2025 16:02:28 -0400 Received: from phl-compute-10.internal (phl-compute-10.phl.internal [10.202.2.50]) by mailfout.stl.internal (Postfix) with ESMTP id AC9421D0009E; Sat, 26 Jul 2025 16:02:22 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-10.internal (MEProxy); Sat, 26 Jul 2025 16:02:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=stebalien.com; h=cc:cc:content-type:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm2; t=1753560142; x= 1753646542; bh=YmPF9rPx0w35c6M0xzXxLNgG2fsto6oJOZxe12D0Veg=; b=u CoAgQRIZBPqaZsXQkUGOZ8tPDLiPAHb/xcrVpAr6HkgTCerklsLRE7QCt4M67X4J aaGeegiIJ74lXrldJ8dTiiUMtmYVjB2N5IYN3qBqd7PFdjV9rSzlhaLeNenwPK1d /11PR2qbFHjfDtPpb8+4pmRQBW0Hf8amdTevGi6IGC2FmCBK0YOO9lrga6cPaSbg mFwje1YgEYrjPTwTyengaK5sCBwP7KFy+tSJXKYoPA4F4yOKZB4CWlYQvu4Gq0K+ eB3XXxuzx0qCW2lY/36rHOEMex01Kw4SnZ0dUwO2ZfNX0EfjAcbH/UCAP8/CEXuT HCfYWbufU1lKYa7noOLvw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t= 1753560142; x=1753646542; bh=YmPF9rPx0w35c6M0xzXxLNgG2fsto6oJOZx e12D0Veg=; b=CHfay23C7BU/6cJWjxpLoTTO/0YoKSP6rR0+guGWcqda+S1raYs Ukh99mFhqyF3EWrDJKmfccZncUxckwaFyd+BNMWoCPmII+qifk0geWPu99di31Kr 2Z9LRUzv4w8pMMEjX+5Wq157dODgfeGX/CFZRnk4bhUtDIQgxZOCHAduB0r4wdFa oU6q0L697H85doyIM/2e1p7X+tnIyfT8oUb1SZSuZngMK/504cwzNUu3BID0Y+sk YBSvCZUPYBazZXXBA8EwjCyG3viPmL8fH2eec+yWFN/aMvuUcqs3bmPOdFkUZ1/T kAfphsh2c+PbhCn2MbvmiIrEx7zPanM3F9A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdekjeefvdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufgjfhffkfggtgesthdtredttddttdenucfhrhhomhepufhtvghvvghnucet lhhlvghnuceoshhtvghvvghnsehsthgvsggrlhhivghnrdgtohhmqeenucggtffrrghtth gvrhhnpedvkeehkeegleehheeggfduleektefhhffgueffteekgedtvdefuddutddtjeej vdenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehsth gvvhgvnhesshhtvggsrghlihgvnhdrtghomhdpnhgspghrtghpthhtohepvddpmhhouggv pehsmhhtphhouhhtpdhrtghpthhtohepvghlihiisehgnhhurdhorhhgpdhrtghpthhtoh epjeekleekgeesuggvsggsuhhgshdrghhnuhdrohhrgh X-ME-Proxy: Feedback-ID: ie8a146a7:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sat, 26 Jul 2025 16:02:21 -0400 (EDT) From: Steven Allen To: Eli Zaretskii Subject: Re: bug#78984: 31.0.50; `url-build-query-string' fails to escape a literal `%' in keys and values In-Reply-To: <86ldob1fvn.fsf@gnu.org> References: <87ecupxdci.fsf@stebalien.com> <86o6tpeq1f.fsf@gnu.org> <87y0stif05.fsf@stebalien.com> <86v7nrgwao.fsf@gnu.org> <877c06oac6.fsf@stebalien.com> <86ldob1fvn.fsf@gnu.org> Date: Sat, 26 Jul 2025 13:02:20 -0700 Message-ID: <87y0sag1pv.fsf@stebalien.com> MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 78984 Cc: 78984@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) Eli Zaretskii writes: > > This patch is fine. If it is a final version and passes all the > tests, I will install it. If you have further updates, please post, > and I will install then. > > Thanks. The tests pass and I'm happy with the patch as-is. From debbugs-submit-bounces@debbugs.gnu.org Sat Aug 02 09:52:06 2025 Received: (at 78984-done) by debbugs.gnu.org; 2 Aug 2025 13:52:06 +0000 Received: from localhost ([127.0.0.1]:35196 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uiCec-000741-3A for submit@debbugs.gnu.org; Sat, 02 Aug 2025 09:52:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:49810) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uiCea-00073M-80 for 78984-done@debbugs.gnu.org; Sat, 02 Aug 2025 09:52:04 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uiCeU-0004z7-Rz; Sat, 02 Aug 2025 09:51:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=3E5e+HxsaJa+ZTQzQsA58v8/F0voe2Vn3vVdp/OgNu0=; b=TSaEieLkCzVA W/C2/DNYsZ2tqo3eZsjTlH6Ljc2N27g4ZBk1FZCIsE+A22OqA+8h+8Qz2b8U1IbUI1LjYU80VUdXp ygcMX5Ws+nsAkgnjqsf5J3x3i/A4++1sdSXQzUTnYgqRKfGRiWqcTwRBagyaaMQJIDWyAAfkTEEPX pBjmArFQrsISJcypeW3MPVP20OlGCmTRx/lwEro6Aikbvj78JYUbKWV7CiDV3Qmv8qveHgjxQdTsM pB6yzgCMWfYKaQPFqnSJmkBbr2zyKYfaRmqe62MxTzylq27K4KRI6dVmph8J7PMUrwqaH02slepxt +Aq/xY3T5goOzriCIlUHhA==; Date: Sat, 02 Aug 2025 16:51:57 +0300 Message-Id: <86zfchrfuq.fsf@gnu.org> From: Eli Zaretskii To: Steven Allen In-Reply-To: <87y0sag1pv.fsf@stebalien.com> (message from Steven Allen on Sat, 26 Jul 2025 13:02:20 -0700) Subject: Re: bug#78984: 31.0.50; `url-build-query-string' fails to escape a literal `%' in keys and values References: <87ecupxdci.fsf@stebalien.com> <86o6tpeq1f.fsf@gnu.org> <87y0stif05.fsf@stebalien.com> <86v7nrgwao.fsf@gnu.org> <877c06oac6.fsf@stebalien.com> <86ldob1fvn.fsf@gnu.org> <87y0sag1pv.fsf@stebalien.com> X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 78984-done Cc: 78984-done@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Steven Allen > Cc: 78984@debbugs.gnu.org > Date: Sat, 26 Jul 2025 13:02:20 -0700 > > Eli Zaretskii writes: > > > > This patch is fine. If it is a final version and passes all the > > tests, I will install it. If you have further updates, please post, > > and I will install then. > > > > Thanks. > > The tests pass and I'm happy with the patch as-is. Thanks, now installed on master, and closing the bug. From unknown Sat Sep 13 00:21:47 2025 Received: (at fakecontrol) by fakecontrolmessage; To: internal_control@debbugs.gnu.org From: Debbugs Internal Request Subject: Internal Control Message-Id: bug archived. Date: Sun, 31 Aug 2025 11:24:18 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator