askiiart-net/blog/300.html
2024-03-06 23:42:03 -06:00

137 lines
8.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta content="width=device-width, initial-scale=1" charset="utf-8" />
<link rel="icon" href="/assets/askiiart.gif" type="image/icon">
<title>300</title>
<link href="/style.css" type="text/css" rel="stylesheet" />
<link href="/prism.css" rel="stylesheet" />
</head>
<body class="line-numbers">
<h1 id="section">300</h1>
<p>No, not the movie. I'm a nerd who's spent half their day so
far configuring nginx, it should be obvious at this point.</p>
<hr />
<p>Since I have my code 1) <a
href="https://git.askiiart.net/askiiart/askiiart-net">on my
Gitea (now Forgejo) instance</a>, and 2) <a
href="https://github.com/askiiart/askiiart.github.io">mirrored</a>
on GitHub, I didn't just want to set up a simple <a
href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308">308
Permanent Redirect</a> from <a href="/.git">/.git</a> to my code
in one place. I wanted users to be able to see both options,
both Gitea and GitHub, and apparently there's actually a thing
for that already, I can just use that!</p>
<h2 id="ok-but-how">ok but how?</h2>
<p>300 seems great, but there's no standardized way to use it.
The number, and the <code>Location</code> header as the
preferred choice is all that's actually standardized. Straight
from <a
href="https://httpwg.org/specs/rfc9110.html#status.300">RFC
9110</a>:</p>
<blockquote>
<p>If the server has a preferred choice, the server
<em>SHOULD</em> generate a Location header field containing a
preferred choice's URI reference. The user agent MAY use the
Location field value for automatic redirection.</p>
<p>For request methods other than HEAD, the server
<em>SHOULD</em> generate content in the 300 response containing
a list of representation metadata and URI reference(s) from
which the user or user agent can choose the one most
preferred.</p>
</blockquote>
<p>Does this mean to return some HTML? A JSON dict? YAML? An
image of a pickle with that info overlaid on top of it!?
<em>Nobody knows!</em> And from the Mozilla docs:</p>
<blockquote>
<p>As there is no standardized way of choosing one of the
responses, this response code is very rarely used.</p>
</blockquote>
<p>Very helpful.</p>
<h2 id="ok-but-actually-how">ok but actually how?</h2>
<p>After a bit of Googling, I found <a
href="https://stackoverflow.com/questions/8905545/what-is-the-exact-response-structure-for-http-status-code-300-multiple-choices">this
Stack Overflow thread</a>, which just says
this<sup>[<a href="#browser-specific-info">note</a>]</sup>:</p>
<blockquote>
<p>The "multiple choices" are done by sending the links in
hypertext (HTML) content and let the <em>user</em> pick.</p>
</blockquote>
<p>Well, that's boring. Guess I'll do that then.</p>
<pre class="language-nginx"><code> location /.git {
add_header Location &quot;https://git.askiiart.net/askiiart/askiiart-net&quot;;
return 300 &#39;&lt;!DOCTYPE html&gt;&lt;html lang=&quot;en&quot;&gt;&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;/head&gt;&lt;body&gt;&lt;a href=&quot;https://git.askiiart.net/askiiart/askiiart-net&quot;&gt;Self-hosted&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://github.com/askiiart/askiiart.github.io&quot;&gt;GitHub&lt;/a&gt;&lt;/body&gt;&lt;/html&gt;&#39;;
}</code></pre>
<h2 id="nginx-is-hard">nginx is hard</h2>
<p>That config looks fine, right? It just sets the
<code>Location</code> header and returns this basic menu to pick
from. But it won't open in any browsers, Firefox displays
nothing, and has <code>NS_ERROR_WONT_HANDLE_CONTENT</code> in
the developer tools, and Chrome shows a
<code>ERR_INVALID_RESPONSE</code> error. Running
<code>curl -I https://askiiart.net</code>, and...</p>
<div class="sourceCode" id="cb2"><pre
class="language-sh"><code class="language-bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">HTTP/1.1</span> 300 </span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">Server:</span> nginx/1.25.3</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Date:</span> Wed, 06 Dec 2023 16:36:01 GMT</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="ex">Content-Type:</span> application/octet-stream</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="ex">Content-Length:</span> 223</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="ex">Connection:</span> keep-alive</span></code></pre></div>
<p>There's no Location header there! And the browsers are
probably refusing to show it because of the wrong
<code>Content-Type</code> and no, adding a header with
<code>add_header</code> doesn't work for that one, either.</p>
<p>Turns out in order to be able to use <code>add_header</code>,
you first need to set <code>default_type</code> (which sets a
default <code>Content-Type</code>). I could've set that in the
<code>location /.git</code> block, but I just decided to make it
global.</p>
<p>So here's the fixed config:</p>
<pre class="language-nginx"><code> # actually much higher in file
default_type &quot;text/html&quot;;
location /.git {
add_header Location &quot;https://git.askiiart.net/askiiart/askiiart-net&quot;;
return 300 &#39;&lt;!DOCTYPE html&gt;&lt;html lang=&quot;en&quot;&gt;&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;/head&gt;&lt;body&gt;&lt;a href=&quot;https://git.askiiart.net/askiiart/askiiart-net&quot;&gt;Self-hosted&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://github.com/askiiart/askiiart-net&quot;&gt;GitHub&lt;/a&gt;&lt;/body&gt;&lt;/html&gt;&#39;;
}</code></pre>
<p>Yep, that works! I had set up my IP address pages the same
way, so let's fix that:</p>
<pre class="language-nginx"><code> location /ip {
default_type text/plain;
return 200 &quot;$remote_addr&quot;;
}
location /ip/json {
default_type application/json;
return 200 &#39;{&quot;ip&quot;:&quot;$remote_addr&quot;}&#39;;
}</code></pre>
<p>These still don't work, they just return my reverse proxy
container's gateway's address, but that's for another time.</p>
<h2 id="open-your-eyes...-wake-up-link">Open your eyes... wake
up, <em>Link</em></h2>
<p>Turns out might be a standard way to do it! From <a
href="https://httpwg.org/specs/rfc9110.html#status.300">RFC
9110</a>, again:</p>
<blockquote>
<p>It is possible to communicate the list using a set of Link
header fields <a
href="https://httpwg.org/specs/rfc9110.html#RFC8288">RFC5988</a>,
each with a relationship of "alternate", though deployment is a
chicken-and-egg problem.</p>
</blockquote>
<p>I'll probably figure out the <code>Link</code> header some
other time and will add this later, at which point I'll post an
addendum. Until then, bye I guess!</p>
<h2 id="footnotes-and-stuff">Footnotes and stuff</h2>
<h4 id="browser-specific-info">browser-specific info</h4>
<p>Elsewhere in the Quora thread it says, in short, that Firefox
and Chrome just displays the HTML, and Safari will follow the
<code>Location</code> header. Edit: Apparently I forgot to link
the Quora thread, so I've got no idea what I'm referencing here.
Sorry! [<a href="#ok-but-actually-how">Back</a>]</p>
<script src="/prism.js"></script>
</body>
<footer>
<p><a href="https://git.askiiart.net/askiiart/askiiart-net">code</a> (<a href="https://github.com/askiiart/askiiart.github.io">mirror</a>)&emsp;<a href="/feed.xml">rss</a>&emsp;<a href="/pubkey.asc">pubkey</a></p>
</footer>
</html>