HTTP request handler / middleware SRFI Lassi Kortela (05 Apr 2019 11:34 UTC)
Re: HTTP request handler / middleware SRFI Shiro Kawai (05 Apr 2019 12:05 UTC)
Re: HTTP request handler / middleware SRFI Lassi Kortela (05 Apr 2019 12:24 UTC)
Re: HTTP request handler / middleware SRFI Shiro Kawai (05 Apr 2019 17:45 UTC)
Re: HTTP request handler / middleware SRFI Peter Bex (05 Apr 2019 14:02 UTC)
Re: HTTP request handler / middleware SRFI Lassi Kortela (05 Apr 2019 15:50 UTC)
Re: HTTP request handler / middleware SRFI Peter Bex (05 Apr 2019 15:58 UTC)
Re: HTTP request handler / middleware SRFI Lassi Kortela (05 Apr 2019 16:19 UTC)
Re: HTTP request handler / middleware SRFI Peter (05 Apr 2019 16:47 UTC)
Re: HTTP request handler / middleware SRFI Peter Bex (05 Apr 2019 20:14 UTC)
Re: HTTP request handler / middleware SRFI Lassi Kortela (05 Apr 2019 21:51 UTC)
Re: HTTP request handler / middleware SRFI Shiro Kawai (05 Apr 2019 19:02 UTC)
Re: HTTP request handler / middleware SRFI Lassi Kortela (05 Apr 2019 13:11 UTC)
Re: HTTP request handler / middleware SRFI Peter (05 Apr 2019 13:20 UTC)
Re: HTTP request handler / middleware SRFI Lassi Kortela (05 Apr 2019 13:38 UTC)
Re: HTTP request handler / middleware SRFI Peter (05 Apr 2019 13:58 UTC)
Re: HTTP request handler / middleware SRFI Lassi Kortela (05 Apr 2019 15:18 UTC)
Re: HTTP request handler / middleware SRFI Arthur A. Gleckler (05 Apr 2019 21:19 UTC)
Re: HTTP request handler / middleware SRFI Lassi Kortela (06 Apr 2019 00:08 UTC)
(missing)
Re: HTTP request handler / middleware SRFI Arthur A. Gleckler (06 Apr 2019 05:31 UTC)
Re: HTTP request handler / middleware SRFI Peter (06 Apr 2019 07:30 UTC)
Re: HTTP request handler / middleware SRFI Arthur A. Gleckler (06 Apr 2019 20:20 UTC)
Re: HTTP request handler / middleware SRFI John Cowan (06 Apr 2019 23:10 UTC)
Re: HTTP request handler / middleware SRFI Duy Nguyen (10 Sep 2019 14:12 UTC)
Re: HTTP request handler / middleware SRFI Arthur A. Gleckler (10 Sep 2019 14:18 UTC)
Re: HTTP request handler / middleware SRFI Peter Bex (06 Apr 2019 08:24 UTC)

Re: HTTP request handler / middleware SRFI Peter Bex 06 Apr 2019 08:24 UTC
On Fri, Apr 05, 2019 at 02:19:47PM -0700, Arthur A. Gleckler wrote:
> A "dispatcher" defines how each request is handled.  To add a new dispatcher
> to a server, one calls:
>
>  (web-server/add-dispatchers! web-server . web-dispatchers)

The original version of Spiffy had something like this as well.
It is very user-friendly and convenient, but it makes it quite difficult
to remove dispatchers.  It also makes it impossible to run multiple
servers in different threads in the same process, which handle different
applications.

The current version of Spiffy uses a vhost map (which turns out to be
a needless distraction) which is a ((host . handler) ...) alist in
a SRFI-39 / R7RS parameter.

The handler receives the "previous" handler (a sort of continuation),
which initially is just a thing that renders a minimal 404 page.

Then, when you add a new handler, it can inspect the path and query
parameters and so on to determine if this is handled by it, and if not,
it calls the continuation (which may be a chain of existing handlers
already).

What I like about this approach is that the request *dispatching* is
completely separated from the request/response *handling*.  There are in
fact multiple libraries which implement dispatching.  But in practice,
most people either do it by hand or use the uri-dispatch egg[1].

After thinking about this, I think the vhost can also be part of the
handler instead.  It can just look at the "host" header (or the host in
the URL, if it's absolute and we're in HTTP 1.0) and decide if it wants
to handle this particular host.

> Dispatchers are created using the macro `make-web-dispatcher', which
> defines:
>
> * which incoming requests this dispatcher handles
>
> * how to parse variable elements of the path, e.g. <month> and <year> in
> "/calendar/<year>/<month>"
>
> * how to parse query parameters

I like the fact you can handle query parameters like this.  It's probably
smart to add header dispatching too.  That way, you can for example have
different handlers for different content types, or for different host
headers.

> * `Request' is the name of a variable which will be bound to the
> `http-request' object in `body'.  Here's the definition of `http-request',
> slightly simplified:
>
>  (define-record-type http-request ...)

This record looks a lot like intarweb's request object.  I think that
means we're on the right track :)

>  * Paths are matched by patterns that contain strings, which must  match
> exactly, and variables, expressed as `(? variable)', which  match anything
> between slashes.

In Intarweb, we parse URI paths as lists, so matching like this becomes
quite trivial; it is quite common to use Andrew Wright's "match" macro to
match path components, which is of course very similar to your path
matching syntax.

> Every handler should return three values:
>
>  code: response code, a number, e.g. 200 for HTTP OK
>
>  headers: an alist of headers beyond the basic headers  Content-Length and
> Content-Type

In Spiffy, we use a "response" record type.  It is quite similar to the
http-request record, but contains different fields like the response
status code, headers and the port to write to.  The response object
is initially populated by the web server, and the user can manipulate
it to add headers etc.

The annoying bit is you have to write the response object manually which
will serialize the response line and headers.  Then you can write the
response body (if any) and close the port to indicate when you're done.

Because this is a bit obnoxious, for convenience, there's a
"send-response" helper procedure that accepts headers, a response body,
status code and so on which will write the response headers and then
the body and close the port.

>  output: a thunk that will write the output, or false if there is  no
> output.  Content-Length will be computed from this  automatically.

That's a nice way to do it.  Does it support streamed responses of
unknown length?  In Spiffy, you have to manually set a few headers
and write the response object manually and then you can write the
content body.  Depending on some magic, the response will automatically
be chunked.  I really dislike how this works (I always forget how it
works, even though I came up with it), so perhaps we can come up with a
different way.

I think streamed responses are important, because it makes web socket
support and "long polling" possible, as is the ability to send large
files (which do have a known length of course).

Perhaps you can return either a string which will be returned directly,
or a "writer" procedure which receives a port which, when written to,
sends the payload wrapped in a "chunk" of a chunked encoding response.

I'm not sure this is the perfect solution, because you ideally want to
automatically support HEAD and Range requests too.  And if possible,
the caching headers should be set automatically as well.

> I'm excited by the idea of standardizing web request handlers.  It would be
> great to make it easy for Scheme hackers to share web code across Scheme
> implementations and web servers.

Yeah!

Cheers,
Peter

[1] https://wiki.call-cc.org/eggref/4/uri-match