From d8fb7a64d7a839cb5a45cf3e00f206898e91cb1f Mon Sep 17 00:00:00 2001 From: Lucian Mogosanu Date: Tue, 16 Jul 2019 18:50:31 +0300 Subject: [PATCH] drafts, hunchentoot-ii: Add full draft --- drafts/000-hunchentoot-ii.markdown | 104 ++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/drafts/000-hunchentoot-ii.markdown b/drafts/000-hunchentoot-ii.markdown index bd7699c..94964c7 100644 --- a/drafts/000-hunchentoot-ii.markdown +++ b/drafts/000-hunchentoot-ii.markdown @@ -50,6 +50,90 @@ Now that we have the basics in place, let's take a look at the abstractions exposed by our particular H, which for historical reasons we've decided to christen Hunchentoot. +In Hunchentoot, the entity that makes a HTTP server (bound to a port, +etc.) come to life is called an **[acceptor][ht-acceptor]**. Acceptors +encapsulate the port, IP address, listening socket, etc. plus some +state and some basic server configuration data, such as the document +root for serving static files and paths to logfiles -- in other words, +all the data needed to perform at least (a), (b) and (c) +above. Moreover, the user can extend acceptor functionality to define +custom handlers for URLs, as illustrated by the +[easy-acceptor][ht-easy-acceptor] subclass. + +However, acceptors don't have any say in *when* connections (the Cs +above) and requests (the Rqs above) are handled, i.e. how tasks are +distributed among workers, and if there are any dedicated worker +threads at all. Work management is done through the +**[taskmaster][ht-taskmaster]** abstraction. A very broad sketch of +how this works: after listening (i.e. (b)) is complete, the acceptor +calls the taskmaster via [execute-acceptor][ht-execute-acceptor], in +order to establish when connections are accepted (i.e. (c)) and where +and when requests are handled (i.e. (d) to (f)). When the taskmaster +is ready for (c), it calls the acceptor's +[accept-connections][ht-accept-connections], which performs the accept +and gives back control to the taskmaster +([handle-incoming-connection][ht-handle-incoming-connection]), which +at some point calls back into the acceptor +([process-connection][ht-process-connection]) to let it perform (d), +(e) and (f). + +The keen reader will by now wonder what's the point to all this +dancing around between taskmasters and acceptors. For one, each +acceptor has a taskmaster, and the other way around; for another, all +this "execute, then accept, then handle, then process" seems +arbitrarily assigned to either the acceptor or the taskmaster, so +really, what the fuck? + +The main reasoning behind this acceptor-taskmaster separation is the +following: acceptors do useful work, which is mainly accepting +connections and handling the requests sent via the former; meanwhile, +taskmasters are hooked immediately before this useful work occurs, so +that they obey a decision made apriori by the user whether said work +will be scheduled on a new thread or performed on the same one. In +other words, we're given [flexibility][s-xml] at the cost of extra +lines of code. Given my lack of direct experience with Hunchentoot, +I'm not sure yet whether this cost is worth it or not, but if it +proves to be more trouble than it's worth, I will personally carve the +thing out. + +Moving on to other abstractions, the next on the list are +**[request][ht-request]** and **[reply][ht-reply]** objects. These, as +the name suggests, encapsulate HTTP request/reply data, such as the +URL, headers, cookies, return codes and so on. To continue on the +previous thread: once the acceptor starts [processing +connections][ht-process-connection] (i.e. (d)), it will create request +objects and process each of them -- +[process-request][ht-process-request] will call +[handle-request][ht-handle-request] (i.e. (e)), which will call +[acceptor-dispatch-request][ht-acceptor-dispatch-request], which can +be customized by the user via e.g. subclassing, to perform request +processing and, finally, step (f). + +I will gloss over **[session][ht-session]** objects for the moment, as +they are less relevant to the overall architecture. It's sufficient to +say that they serve as an abstraction for "stateful shit over this +stateless protocol", which is something I'd be happy to see die a +gruesome death. + +I was going to make a diagram and show some examples of Hunchentoot at +work, but I am well over the one thousand word limit, so I will stop +this episode here. We can now put the next [couple of +weeks][w30-31-work] in perspective, though: + +* I believe there is some merit to making a visual representation of + what I've just written. Procedural programming was designed to + provide separation between logical units of work, but so far + everything here is looking like a tangled mess[^2]. +* All this discussion isn't of much value without some examples of + Hunchentoot in action. Speaking of which: this is perhaps a small + project in itself, but it would be fun to find out and document this + proggy's breaking points. +* I need to dig deeper into coad and start owning it, and the first + victim will be our star child, the acceptor implementation. At the + moment it's hard to give an estimate of how long this will take, but + I'll make sure to look at this before I set out to climb the + mountain. + [^1]: Quick likbez on how Unix and TCP make the whole thing work: In (a), the operating system binds a socket S owned by H to P, @@ -71,9 +155,29 @@ we've decided to christen Hunchentoot. been beaten to death in [the logs][tcp]. Either way, there's no way around this pile of shit for nodes talking to the heathen WWW. +[^2]: I remember reading the same words somewhere else, and I even + know [where][eulora]. I'm not the first, nor even the second in + line to look at large open sores coads, you see. + [cl-www]: /posts/y05/090-tmsr-work-ii.html#selection-108.0-108.17 [m7-work]: /posts/y05/094-tmsr-work-iii.html [hunchentoot-i]: /posts/y05/093-hunchentoot-i.html [edicl-hunch]: http://archive.is/MP2bT [rfc-793]: http://archive.is/hFcq3 [tcp]: http://btcbase.org/log-search?q=tcp +[ht-acceptor]: http://coad.thetarpit.org/hunchentoot/c-acceptor.lisp.html#L42 +[ht-easy-acceptor]: http://coad.thetarpit.org/hunchentoot/c-easy-handlers.lisp.html#L330 +[ht-taskmaster]: http://coad.thetarpit.org/hunchentoot/c-taskmaster.lisp.html#L31 +[ht-execute-acceptor]: http://coad.thetarpit.org/hunchentoot/c-taskmaster.lisp.html#L40 +[ht-accept-connections]: http://coad.thetarpit.org/hunchentoot/c-acceptor.lisp.html#L251 +[ht-handle-incoming-connection]: http://coad.thetarpit.org/hunchentoot/c-taskmaster.lisp.html#L47 +[ht-process-connection]: http://coad.thetarpit.org/hunchentoot/c-acceptor.lisp.html#L272 +[s-xml]: /posts/y05/086-s-xml.html#selection-109.0-109.109 +[ht-request]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L31 +[ht-reply]: http://coad.thetarpit.org/hunchentoot/c-reply.lisp.html#L31 +[ht-process-request]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L105 +[ht-handle-request]: http://coad.thetarpit.org/hunchentoot/c-acceptor.lisp.html#L284 +[ht-acceptor-dispatch-request]: http://coad.thetarpit.org/hunchentoot/c-acceptor.lisp.html#L293 +[ht-session]: http://coad.thetarpit.org/hunchentoot/c-session.lisp.html#L83 +[w30-31-work]: /posts/y05/094-tmsr-work-iii.html#selection-150.0-150.5 +[eulora]: http://ossasepia.com/2019/06/18/euloran-blus-and-boos/#selection-25.1-35.40 -- 1.7.10.4