You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
net::http::server went from a loopback harness to something that routes,
caches, ranges and serves a directory (#217-#227). The next thing it wants is a program: jhttpd, a web server you could point at a port and leave running.
This issue is the shape of that, and an honest assessment of the stretch goals,
because one of them is not like the others.
What the library already gives it
Most of a static server, in fact:
request parsing against the pasted RFC 9112 grammar, refusing both smuggling
primitives
keep-alive with three separate timeouts, chunked output, HEAD, 405 with Allow, conditional requests, byte ranges
files() -- containment by realpath, streamed a block at a time, counted
rather than chunked, weak validators from stat
route patterns with captures and a most-specific-wins rule
TLS, and an async server where a connection is a coroutine rather than a
thread
What it needs before anyone should run it
Roughly in the order that matters:
Logging. Nothing logs a request. An access log in a known format
(Combined, so existing tools read it) and an error log. This is first because
a server you cannot see is a server you cannot operate.
Something dynamic: reverse proxy, FastCGI, or CGI. Without one it serves
files and nothing else.
Each of those is an issue of its own when somebody starts; listing them here so
the size is visible.
The stretch goals
Reading nginx and Apache config -- achievable, and a lot of work
Both are custom formats and both are parseable. nginx's is a small grammar --
blocks, directives, semicolons -- and jlib has an ABNF engine that would eat
it. Apache's is line-oriented with <Section> containers.
Parsing is the easy half. nginx has several hundred directives across its
core modules; Apache has more. A config file is only "read" to the extent the
directives in it are implemented, and a server that parses gzip on; and
ignores it is worse than one that refuses the file, because the operator
believes something untrue.
So the useful version is bounded: a stated subset -- listen, server_name, root, location, index, try_files, ssl_certificate, access_log --
that covers a static site, and a hard error on any directive not
implemented. That is genuinely useful and honest. "Reads nginx.conf" without
that qualifier is not a goal that can be met.
Apache modules -- not reachable, and worth saying why
An Apache module is a shared object compiled against Apache's headers. Loading
one means providing, binary-compatibly:
APR (Apache Portable Runtime) and APR-util -- pools, tables, buckets,
a whole allocator discipline the module calls into constantly
the hook system: ap_hook_handler, ap_hook_translate_name, ap_hook_fixups and a few dozen more, each with its ordering semantics
request_rec, conn_rec, server_rec -- large structs whose layout is the
ABI
bucket brigades, which is how every output filter works
That is not a feature of a web server; it is a reimplementation of Apache's
internals with byte-compatible structures. mod_perl and mod_php are written
against it in detail. This one should be dropped, and what replaces it is
worth having:
A jlib-native module interface.dlopen a shared object exporting a known
entry point, hand it a chance to register routes and filters against jlib's own
types. That gets the actual value -- third-party code extending the server
without recompiling it -- with an interface this tree can define and document,
instead of one it would have to reverse-engineer and could never quite match.
"Drop-in replacement" -- worth restating as something achievable
For a static site, this is realistic: same config subset, same document
root, same TLS certificates, same log format. Somebody could stop nginx, start
jhttpd, and not notice.
For anything with modules, rewrite rules, FastCGI pools or .htaccess, it is
not, and pursuing it would turn a personal library into a compatibility project
with an unbounded surface.
The thing this changes upstream
http_server.hh says "It is not hardened for a public port", and sys/server.hh says the same. Those sentences were load-bearing -- they are
the reason several features were deliberately left out.
jhttpd is a decision to face a public port. That does not make the sentences
false today, but it means they stop being a scope statement and become a list of work: the things they excuse are exactly #237, #238, and the
hardening above. Whoever starts jhttpd should update both headers in the same
branch, or the code will claim a modesty the program no longer has.
net::http::serverwent from a loopback harness to something that routes,caches, ranges and serves a directory (#217-#227). The next thing it wants is a
program:
jhttpd, a web server you could point at a port and leave running.This issue is the shape of that, and an honest assessment of the stretch goals,
because one of them is not like the others.
What the library already gives it
Most of a static server, in fact:
primitives
Allow, conditional requests, byte rangesfiles()-- containment byrealpath, streamed a block at a time, countedrather than chunked, weak validators from
statthread
What it needs before anyone should run it
Roughly in the order that matters:
(Combined, so existing tools read it) and an error log. This is first because
a server you cannot see is a server you cannot operate.
Host, which the router does not currentlyconsider -- it matches method and path only.
sys::tls_contextholds one certificate; a server with twonames needs one per name, chosen during the handshake.
survives a crash.
which
sys::server::stop(drain)half exists for already.files()deliberately refuses to decide(net: serve a directory, and refuse everything outside it by resolving the path rather than inspecting it #225), and MIME types from
/etc/mime.typesrather than the built-intable.
files and nothing else.
Each of those is an issue of its own when somebody starts; listing them here so
the size is visible.
The stretch goals
Reading nginx and Apache config -- achievable, and a lot of work
Both are custom formats and both are parseable. nginx's is a small grammar --
blocks, directives, semicolons -- and jlib has an ABNF engine that would eat
it. Apache's is line-oriented with
<Section>containers.Parsing is the easy half. nginx has several hundred directives across its
core modules; Apache has more. A config file is only "read" to the extent the
directives in it are implemented, and a server that parses
gzip on;andignores it is worse than one that refuses the file, because the operator
believes something untrue.
So the useful version is bounded: a stated subset --
listen,server_name,root,location,index,try_files,ssl_certificate,access_log--that covers a static site, and a hard error on any directive not
implemented. That is genuinely useful and honest. "Reads nginx.conf" without
that qualifier is not a goal that can be met.
Apache modules -- not reachable, and worth saying why
An Apache module is a shared object compiled against Apache's headers. Loading
one means providing, binary-compatibly:
a whole allocator discipline the module calls into constantly
ap_hook_handler,ap_hook_translate_name,ap_hook_fixupsand a few dozen more, each with its ordering semanticsrequest_rec,conn_rec,server_rec-- large structs whose layout is theABI
That is not a feature of a web server; it is a reimplementation of Apache's
internals with byte-compatible structures. mod_perl and mod_php are written
against it in detail. This one should be dropped, and what replaces it is
worth having:
A jlib-native module interface.
dlopena shared object exporting a knownentry point, hand it a chance to register routes and filters against jlib's own
types. That gets the actual value -- third-party code extending the server
without recompiling it -- with an interface this tree can define and document,
instead of one it would have to reverse-engineer and could never quite match.
"Drop-in replacement" -- worth restating as something achievable
For a static site, this is realistic: same config subset, same document
root, same TLS certificates, same log format. Somebody could stop nginx, start
jhttpd, and not notice.
For anything with modules, rewrite rules, FastCGI pools or
.htaccess, it isnot, and pursuing it would turn a personal library into a compatibility project
with an unbounded surface.
The thing this changes upstream
http_server.hhsays "It is not hardened for a public port", andsys/server.hhsays the same. Those sentences were load-bearing -- they arethe reason several features were deliberately left out.
jhttpd is a decision to face a public port. That does not make the sentences
false today, but it means they stop being a scope statement and become a
list of work: the things they excuse are exactly #237, #238, and the
hardening above. Whoever starts jhttpd should update both headers in the same
branch, or the code will claim a modesty the program no longer has.