drafts, hunchentoot-vib: Discuss most interface methods
authorLucian Mogosanu <lucian@mogosanu.ro>
Mon, 26 Aug 2019 15:58:46 +0000 (18:58 +0300)
committerLucian Mogosanu <lucian@mogosanu.ro>
Mon, 26 Aug 2019 15:58:46 +0000 (18:58 +0300)
drafts/000-hunchentoot-vib.markdown

index f7a390a..d7733fb 100644 (file)
@@ -6,88 +6,88 @@ author: Lucian MogoČ™anu
 tags: tech, tmsr
 ---
 
-<a name="pr" href="#pr">[pr]</a> [**process-request**][ht-pr]: This
-function is on the main request processing/handling path, and is
-called by [process-connection][ht-pc] whenever a new HTTP request is
-available. It does a bunch of more or less related things, let's take
-'em one by one.
+This post is part of a series on [Common Lisp WWWism][cl-www], more
+specifically a continuation of "[Hunchentoot: requests and
+replies][hunchentoot-via]". In this second part of "requests and
+replies" we will dissect "replies" and what remains of "requests", in
+precisely the reverse order.
 
-a\. the first part of the function a1. defines and binds some special
-variables, e.g. the current \*request\* being processed, and a2. wraps
-everything into some condition handling code, namely: a2i. it "maps"
-all [conditions][ht-wmc][^1]; a2ii. wraps this in an
-[unwind-protect][clhs-unwind-protect][^2]; a2iii. all this wrapped in
-a [catch][clhs-catch][^3].
+We ended [last time][hunchentoot-via] with a look at code that parses
+GET and POST requests. This time we will look (in the following order)
+at: a set of "interface methods" aimed to be employed by the user when
+implementing request handlers; the [process-request](#pr) method; and,
+last but not least, at the methods exposed by the "reply" component in
+this orchestra.
 
-b\. the code at (a) wraps a b1. local procedure definition,
-report-error-to-client, which [logs][ht-lms] an error and returns a
-http-internal-error, i.e. [start-output][ht-so] on the result of an
-[acceptor-status-message][ht-asm]; and b2. a call to
-[handle-request][ht-hr] wrapped in a catch for "handler-done"[^4],
-with the return values for handle-request bound to "contents", "error"
-and "backtrace"; b3. if "error", then report-error-to-client; b4. if
-headers are not yet sent, [start-output][ht-so] with the return code
-of \*reply\* and whatever contents we have; b4. if no contents are
-set, then get a default page from [acceptor-status-message][ht-asm];
-b5. if an error occurs during (b4), then call report-error-to-client.
+First, we notice that most request accessors come with wrapper methods
+whose names end in a "star", which, by some arbitrary convention,
+means that they implicitly bind their current "request" parameter to
+the special variable \*request\*[^1]. Let's take a look at a few of
+these:
 
-c\. this occurs on the "cleanup-form" part of the unwind-protect at
-(a2ii): if there are any temporary files that were set up during the
-function, delete them.
+<a name="sns" href="#sns">[sns]</a> [**script-name\***][ht-sns]
 
-This function is all over the fucking place, owing mainly to the
-pretense of "modularity" and separation between requests and replies
--- I did say they're part of the same logical unit, didn't I? Just
-look at it: "request processing" calls "start output" -- which by the
-way, is part of "headers", right? but this same "start output" is the
-one which actually delivers a response to the client, which response
-delivery oughta be part of "reply"!! So to conclude: this whole shit
-is in dire need of refactoring and ultimately a complete
-rewrite. No-no, this time I'm pretty damn sure it's not the protocol's
-fault for this abomination.
+<a name="qss" href="#qss">[qss]</a> [**query-string\***][ht-qss]
 
-<a name="wrp" href="#wrp">[wrp]</a> [**within-request-p**][ht-wrp]:
+<a name="gps" href="#gps">[gps]</a> [**get-parameters\***][ht-gps]
 
-<a name="rrp" href="#rrp">[rrp]</a>
-[**recompute-request-parameters**][ht-rrp]:
+<a name="his" href="#his">[his]</a> [**headers-in\***][ht-his]
 
-<a name="sns" href="#sns">[sns]</a> [**script-name\***][ht-sns]:
+<a name="cis" href="#cis">[cis]</a> [**cookies-in\***][ht-cis]
 
-<a name="qss" href="#qss">[qss]</a> [**query-string\***][ht-qss]:
+<a name="ras" href="#ras">[ras]</a> [**remote-addr\***][ht-ras]
 
-<a name="gps" href="#gps">[gps]</a> [**get-parameters\***][ht-gps]:
+<a name="rps" href="#rps">[rps]</a> [**remote-port\***][ht-rps]
 
-<a name="pp" href="#pp">[pp]</a> [**post-parameters**][ht-pp]:
+<a name="las" href="#las">[las]</a> [**local-addr\***][ht-las]
 
-<a name="pps" href="#pps">[pps]</a> [**post-parameters\***][ht-pps]:
+<a name="lps" href="#lps">[lps]</a> [**local-port\***][ht-lps]
 
-<a name="his" href="#his">[his]</a> [**headers-in\***][ht-his]:
+<a name="rus" href="#rus">[rus]</a> [**request-uri\***][ht-rus]
 
-<a name="cis" href="#cis">[cis]</a> [**cookies-in\***][ht-cis]:
+<a name="rms" href="#rms">[rms]</a> [**request-method\***][ht-rms]
 
-<a name="hi" href="#hi">[hi]</a> [**header-in**][ht-hi]:
+<a name="sps" href="#sps">[sps]</a> [**server-protocol\***][ht-sps]
 
-<a name="his2" href="#his2">[his2]</a> [**header-in\***][ht-his2]:
+The implementation of these functions is, as can be readily observed,
+trivial, and the meaning should be easily deducible from the name;
+thus I won't bother the reader with redundant details. However,
+there's also:
 
-<a name="a" href="#a">[a]</a> [**authorization**][ht-a]:
+<a name="pps" href="#pps">[pps]</a> [**post-parameters\***][ht-pps]:
+This one calls [post-parameters](#pp), which:
 
-<a name="ras" href="#ras">[ras]</a> [**remote-addr\***][ht-ras]:
+<a name="pp" href="#pp">[pp]</a> [**post-parameters**][ht-pp]: Running
+":before" more specific implementations of this method are called;
+given a request, it calls [maybe-read-post-parameters][ht-mrpp]. If
+the post-parameters [slot][ht-pp-slot] is nil, then set the force
+parameter to true.
 
-<a name="rps" href="#rps">[rps]</a> [**remote-port\***][ht-rps]:
+Similarly:
 
-<a name="las" href="#las">[las]</a> [**local-addr\***][ht-las]:
+<a name="rrp" href="#rrp">[rrp]</a>
+[**recompute-request-parameters**][ht-rrp]: Calls
+[maybe-read-post-parameters][ht-mrpp] with the force argument always
+set to true. Also, set the [get-parameters][ht-gp-slot] to the
+[re-parsed][ht-fuelta] value of [query-string][ht-qs-slot].
 
-<a name="lps" href="#lps">[lps]</a> [**local-port\***][ht-lps]:
+However, we also have:
 
-<a name="rra" href="#rra">[rra]</a> [**real-remote-addr**][ht-rra]:
+<a name="hi" href="#hi">[hi]</a> [**header-in**][ht-hi]: Gets a
+specific header from the [headers-in][ht-hi-slot] slot.
 
-<a name="h" href="#h">[h]</a> [**host**][ht-h]:
+<a name="his2" href="#his2">[his2]</a> [**header-in\***][ht-his2]: The
+same as [header-in](#hi), with the request parameter bound to
+\*request\*.
 
-<a name="rus" href="#rus">[rus]</a> [**request-uri\***][ht-rus]:
+And there's also these methods which dynamically bind \*request\*,
+although their name doesn't end in "star":
 
-<a name="rms" href="#rms">[rms]</a> [**request-method\***][ht-rms]:
+<a name="a" href="#a">[a]</a> [**authorization**][ht-a]:
 
-<a name="sps" href="#sps">[sps]</a> [**server-protocol\***][ht-sps]:
+<a name="rra" href="#rra">[rra]</a> [**real-remote-addr**][ht-rra]:
+
+<a name="h" href="#h">[h]</a> [**host**][ht-h]:
 
 <a name="ua" href="#ua">[ua]</a> [**user-agent**][ht-ua]:
 
@@ -109,21 +109,81 @@ fault for this abomination.
 
 <a name="darv" href="#darv">[darv]</a> [**delete-aux-request-value**][ht-darv]:
 
+<a name="rp" href="#rp">[rp]</a> [**request-pathname**][ht-rp]:
+
 <a name="pp3" href="#pp3">[pp3]</a> [**parse-path**][ht-pp3]:
 
-<a name="rp" href="#rp">[rp]</a> [**request-pathname**][ht-rp]:
+TODO: transition to process-request.
+
+<a name="wrp" href="#wrp">[wrp]</a> [**within-request-p**][ht-wrp]:
+
+TODO: another transition to process-request.
+
+<a name="pr" href="#pr">[pr]</a> [**process-request**][ht-pr]: This
+function is on the main request processing/handling path, and is
+called by [process-connection][ht-pc] whenever a new HTTP request is
+available. It does a bunch of more or less related things, let's take
+'em one by one.
+
+a\. the first part of the function a1. defines and binds some special
+variables, e.g. the current \*request\* being processed, and a2. wraps
+everything into some condition handling code, namely: a2i. it "maps"
+all [conditions][ht-wmc][^2]; a2ii. wraps this in an
+[unwind-protect][clhs-unwind-protect][^3]; a2iii. all this wrapped in
+a [catch][clhs-catch][^4].
+
+b\. the code at (a) wraps a b1. local procedure definition,
+report-error-to-client, which [logs][ht-lms] an error and returns a
+http-internal-error, i.e. [start-output][ht-so] on the result of an
+[acceptor-status-message][ht-asm]; and b2. a call to
+[handle-request][ht-hr] wrapped in a catch for "handler-done"[^5],
+with the return values for handle-request bound to "contents", "error"
+and "backtrace"; b3. if "error", then report-error-to-client; b4. if
+headers are not yet sent, [start-output][ht-so] with the return code
+of \*reply\* and whatever contents we have; b4. if no contents are
+set, then get a default page from [acceptor-status-message][ht-asm];
+b5. if an error occurs during (b4), then call report-error-to-client.
+
+c\. this occurs on the "cleanup-form" part of the unwind-protect at
+(a2ii): if there are any temporary files that were set up during the
+function, delete them.
+
+This function is all over the fucking place, owing mainly to the
+pretense of "modularity" and separation between requests and replies
+-- I did say they're part of the same logical unit, didn't I? Just
+look at it: "request processing" calls "start output" -- which by the
+way, is part of "headers", right? but this same "start output" is the
+one which actually delivers a response to the client, which response
+delivery oughta be part of "reply"!! So to conclude: this whole shit
+is in dire need of refactoring and ultimately a complete
+rewrite. No-no, this time I'm pretty damn sure it's not the protocol's
+fault for this abomination.
 
-[^1]: with-mapped-conditions is actually a [usocket][usocket-wmc]
+[^1]: Special variables have a [special meaning][cltl-special] in
+    Common Lisp -- see what I did there? Namely, a special variable
+    may be declared globally and "bound dynamically", i.e. its value
+    may depend on its current execution context, such as, say, the
+    function or the thread where execution takes place, if it's been
+    bound this way using e.g. a let -- the naive me, who started his
+    adventure in Lisp programming in Scheme, thought let can only be
+    used for lexical bindings, and yet... look! Now, *if* there is no
+    such "dynamic binding" for that variable, then the variable's
+    *global* binding is used, which binding is shared between
+    execution contexts.
+
+       Yeah, what can I say... I didn't write this language, okay?
+
+[^2]: with-mapped-conditions is actually a [usocket][usocket-wmc]
     macro which, annoyingly enough, is not documented. Long story
     short, it can be used to define a context in which all usocket
     conditions are safely handled. (TODO: add reference to usocket
     coad?)
 
-[^2]: Which ensures that the code at the end of the function (TODO add
+[^3]: Which ensures that the code at the end of the function (TODO add
     reference) gets executed no matter what conditions occur during
     execution.
 
-[^3]: More precisely, the "request-processed" throw is caught here,
+[^4]: More precisely, the "request-processed" throw is caught here,
     which, as the comment describes, is thrown by
     [start-output][ht-so] after responding to a HEAD
     request. Basically, what this does is exit process-request once
@@ -132,7 +192,7 @@ fault for this abomination.
 
        More details about this later.
 
-[^4]: We get there via [abort-request-handler][ht-arh], basically.
+[^5]: We get there via [abort-request-handler][ht-arh], basically.
 
 [ht-pr]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L219
 [ht-wrp]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L262
@@ -169,13 +229,20 @@ fault for this abomination.
 [ht-darv]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L576
 [ht-pp3]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L585
 [ht-rp]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L613
+[ht-mrpp]: /posts/y06/09c-hunchentoot-via.html#mrpp
 [ht-pc]: http://thetarpit.org/posts/y06/098-hunchentoot-iv.html#pc
 [ht-wmc]: http://coad.thetarpit.org/hunchentoot/c-util.lisp.html#L353
 [ht-so]: http://coad.thetarpit.org/hunchentoot/c-headers.lisp.html#L67
-[ht-lms]: http://thetarpit.org/posts/y06/098-hunchentoot-iv.html#lms
-[ht-asm]: http://thetarpit.org/posts/y06/098-hunchentoot-iv.html#asm
-[ht-hr]: http://thetarpit.org/posts/y06/098-hunchentoot-iv.html#hr
+[ht-lms]: /posts/y06/098-hunchentoot-iv.html#lms
+[ht-asm]: /posts/y06/098-hunchentoot-iv.html#asm
+[ht-hr]: /posts/y06/098-hunchentoot-iv.html#hr
+[ht-pp-slot]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L75
+[ht-gp-slot]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L71
+[ht-qs-slot]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L83
+[ht-fuelta]: /posts/y06/09c-hunchentoot-via.html#fn5
+[ht-hi-slot]: http://coad.thetarpit.org/hunchentoot/c-request.lisp.html#L36
 [ht-arh]: /posts/y06/098-hunchentoot-iv.html#selection-762.0-762.5
+[cltl-special]: https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node58.html
 [usocket-wmc]: https://quickref.common-lisp.net/usocket.html#go-to-the-USOCKET_003ccolon_003e_003ccolon_003eWITH_002dMAPPED_002dCONDITIONS-macro
 [clhs-catch]: http://www.lispworks.com/documentation/HyperSpec/Body/s_catch.htm
 [clhs-unwind-protect]: http://www.lispworks.com/documentation/HyperSpec/Body/s_unwind.htm