OpenBSDのカスタムエラーページ
Published:
By nobCategory: Posts
前提
software | version |
---|---|
OpenBSD | 7.5 -game* |
httpd | builtin |
事象
カスタムエラーページを作成してデプロイするのだがカスタムエラーページが表示されない。
<html>
<head>
<title>
$HTTP_ERROR
</title>
<style type="text/css">
body {
backgroung-image: url(data:image/png;base64,...);
background-size: cover;
background-attachment: fixed;
background-position: center center;
}
</style>
</head>
<body>
<p>
$HTTP_ERROR
</p>
</body>
</html>
Windowsクライアントからcurlでアクセスしてみると、HTMLの転送が中断されたようなログが出力される。
> curl -v https://nobituk.net/abcdefg > test.log
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 160.251.168.158:443...
* Connected to nobituk.net (160.251.168.158) port 443
* schannel: disabled automatic use of client certificate
* ALPN: curl offers http/1.1
* ALPN: server did not agree on a protocol. Uses default.
* using HTTP/1.x
> GET /abcdefg HTTP/1.1
> Host: nobituk.net
> User-Agent: curl/8.4.0
> Accept: */*
>
* schannel: failed to decrypt data, need more data
* schannel: failed to decrypt data, need more data
* schannel: server closed the connection
* HTTP 1.0, assume close after body
< HTTP/1.0 404 Not Found
< Date: Tue, 07 May 2024 16:25:00 GMT
< Server: OpenBSD httpd
< Connection: close
< Content-Type: text/html
< Content-Length: 329269
<
{ [16230 bytes data]
* schannel: server indicated shutdown in a prior call
* transfer closed with 313039 bytes remaining to read
4 321k 4 16230 0 0 98260 0 0:00:03 --:--:-- 0:00:03 98963
* Closing connection
* schannel: shutting down SSL/TLS connection with nobituk.net port 443
curl: (18) transfer closed with 313039 bytes remaining to read
原因
エラーページは一部しか表示されない仕様のようである。
httpd terminates connection in the middle of transferring 404 page
Use the source, luke! :)
The issue lies in how error pages are sent. server_abort_http in server_http.c builds the error page as a long string (it needs to do so because it substitute variables in it) that then is fed to server_dump (see server.c) which in turns just write(2)s it to the socket. Network socket don't have an unbounded buffer associate to them, so only the first part is written. server_dump doesn't care about partial writes and that's how you end up with the truncated page.
Regarding the documentation: it's difficult to document such limit, it depends on exactly how the kernel (or libtls, or both) works.
A possible fix to this would be to rework the later part of server_abort_http so that it uses the request' bufferevent to schedule the write. It's not hard in theory, but it can be tricky as you need to check also the other places that call server_abort_http.
Edit: woops, I noticed u/inco reply only after posting mine, sorry :-)
対策案
未定