<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-AU" xml:base="https://chrismorgan.info/">
	<id>https://chrismorgan.info/dev.feed</id>
	<author>
		<name>Chris Morgan</name>
		<uri>https://chrismorgan.info</uri>
		<email>me@chrismorgan.info</email>
	</author>
	<updated>2026-05-08T20:00:01+05:30</updated>
	<link href="/dev.feed" rel="self" type="application/atom+xml"/>
	<link href="/dev"/>
	<title type="html">Chris Morgan’s pages tagged Dev</title>
	<subtitle type="html">(elopment, of software)</subtitle>
	<entry>
		<title type="html">I’ve banned query strings</title>
		<published>2026-05-08T20:00:01+05:30</published>
		<updated>2026-05-08T20:00:01+05:30</updated>
		<link href="no-query-strings" type="text/html"/>
		<id>https://chrismorgan.info/no-query-strings</id>
		<content type="html"><![CDATA[<p>I don’t like people adding tracking stuff to URLs.
<br class=w>Still less do I like people adding tracking stuff to <em>my</em> URLs.

<p><span class=path>https://chrismorgan.info<wbr>/no-query-strings<wbr><mark>?ref=example.com</mark></span>? Did I ask?
<br class=w>If I wanted to know I’d look at the <code>Referer</code> header;
and if it isn’t there, it’s probably for a good reason.
<br class=w>You abuse your users by adding that to the link.

<p><span class=path>https://chrismorgan.info<wbr>/no-query-strings<wbr><mark>?utm_source=example&amp;utm_<i class=unimportant>&c.</i></mark></span>?
<br class=w>Hey! That one’s even worse, <a href=https://en.wikipedia.org/wiki/UTM_parameters>UTM parameters</a> are for <em>me</em> to use, not <em>you</em>.
<br class=w>Leave my URLs alone.

<p>So I’ve decided to try a blanket ban for this site:
<strong>no unauthorised query strings</strong>.

<p>At present I don’t use any query strings.
<br class=w>If I ever start using any query strings, I’ll allow only known parameters.
<br class=w>(In past times I used <span class=path>?t=…</span> and <span class=path>?h=…</span> cache-busting URLs for stylesheet URLs;
<br class=w>and I decided I’m okay breaking such requests; there shouldn’t be any legitimate ones.)

<p>Want to see what happens if you add a query string<a href=?>?</a>
Go ahead, try it.
<!-- One fun idea for an *empty* query: serve the original file, but with all text . and ! changed to ? -->

<p>It’s my website: I can do what I want with it.
<p>And you can do what you want with yours!

<p><em>This is currently implemented <a href=Caddyfile#?>in my Caddyfile</a>.</em>

<aside>
	<h2>Aside: this page’s URL</h2>
	<p>It was <em>very</em> tempting to publish this at <span class=path>https://chrismorgan.info/?</span>
	(path «<span class=path></span>», query <span class=path></span><!-- Despite what many tools may assume, empty string ≠ null -->).

	<p>This would have broken a lot of common but incorrect assumptions, and made some tools cry:
	<br class=w><code>curl</code>, for example, seems to illegitimately strip a trailing question mark
	<br class=w>(could be only for the command line, didn’t test library usage).

	<p>In the end, I decided to respect the notion of path and have mercy on people.
	<br class=w>Myself most of all;
	I’m already pushing Caddy in enough directions it’s not happy with.

	<p>My next plan was to publish it at <span class=path>/%3F</span>
	(path «<span class=path>?</span>», query null),
	<br class=w>but I guess no one has ever tried doing such stupid things with Caddy before;
	<br class=w><a href=https://github.com/caddyserver/caddy/issues/7678 title="Caddy issue #7678: try_files mangles paths containing characters like ? and % (whereas file_server without the rewrite works properly)">if <code><b>try_files</b></code> rewriting is involved it can’t cope</a>.

	<p>So <span class=path>/no-query-strings</span> will do.
	<br class=w>I’ll probably use <span class=path>/?</span> or <span class=path>/%3F</span> later for something <em>else</em> about query strings.
</aside>]]></content>
		<category term="web" label="Web"/>
		<category term="opinions" label="Opinions"/>
		<category term="meta=only" label="Meta only"/>
	</entry>
</feed>
