• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

examples/H26-Sep-2017-640418

makiki/H26-Sep-2017-242123

tests/H03-May-2022-196139

DISTH A D26-Sep-20171.1 KiB4429

Makefile.inH A D26-Sep-20171.8 KiB7353

README.mdH A D26-Sep-201728.6 KiB715523

configureH A D26-Sep-20172.6 KiB7260

makiki.scmH A D26-Sep-201736.4 KiB914642

package.scmH A D03-May-2022352 1110

test.scmH A D26-Sep-20178 KiB248194

README.md

1# About Gauche-makiki
2
3## Table of contents
4
5  * [Overview](#overview)
6  * [Getting started](#getting-started)
7  * [Handling requests](#handling-requests)
8     * [Registering handlers](#registering-handlers)
9     * [Request record](#request-record)
10     * [Accessing parameters passed by client](#accessing-parameters-passed-by-client)
11     * [Handling POST/PUT request body](#handling-postput-request-body)
12        * [Form encoded data](#form-encoded-data)
13        * [Json](#json)
14        * [Retrieving raw body](#retrieving-raw-body)
15        * [Roll your own reader](#roll-your-own-reader)
16     * [Response](#response)
17     * [Errors and response](#errors-and-response)
18  * [Built-in handlers](#built-in-handlers)
19     * [Serving files](#serving-files)
20     * [Calling CGI scripts](#calling-cgi-scripts)
21     * [Modifying headers](#modifying-headers)
22  * [Logging and tuning](#logging-and-tuning)
23     * [Logging](#logging)
24     * [Profiling](#profiling)
25  * [Starting and terminating the server](#starting-and-terminating-the-server)
26  * [Add-ons](#add-ons)
27  * [Examples](#examples)
28
29## Overview
30
31Gauche-makiki is a simple multithreaded http server intended for
32applications that want to provide http server capability easily.
33The main functionalities are available by just one file, `makiki.scm`,
34so you can either install it as an ordinary Gauche extension library,
35or you can just copy the file into your application.
36
37You need Gauche 0.9.5 or later to use Gauche-makiki.
38
39
40## Getting started
41
42You'll get the idea by looking at the [minimal server](examples/minimal.scm):
43
44    (use makiki)
45    (define (main args) (start-http-server :port 6789))
46    (define-http-handler "/"
47      (^[req app] (respond/ok req "<h1>It worked!</h1>")))
48
49Basically, you register a handler for a path (or a pattern for a path),
50and the server dispatches matching request to the handler, which is
51expected to return the content.
52
53The `req` argument holds the information of the request, and
54the `app` argument holds the application state you pass to
55`start-http-server`.  (The above example isn't using application
56state.  See [this BBS example](examples/query.scm) for simple
57usage of application state.)
58
59Gauche-makiki isn't an all-in-one framework; rather, we provide
60simple and orthogonal parts that can be combined together
61as needed.
62
63
64## Handling requests
65
66### Registering handlers
67
68To use the server, you should define _http-handler_ using
69`define-http-handler` macro:
70
71    (define-http-handler [METHODS] PATTERN [? GUARD-PROC] HANDLER-PROC)
72
73Or, handlers can be added procedurally using `add-http-handler!`:
74
75    (add-http-handler! PATTERN HANDLER-PROC :optional GUARD-PROC METHODS)
76
77`METHODS` is a list of symbols (`GET`, `POST`, etc.) that this handler
78accepts.  You can define different handler with the same `PATTERN`
79as far as `METHODS` don't overlap.   When omitted,
80`(GET HEAD POST)` is assumed.
81
82`PATTERN` can be a regexp or a string.
83
84For each incoming request, the server matches its path of
85the request uri against `PATTERN`.  If `PATTERN` is a string,
86entire request path must match exactly to the pattern.  If `PATTERN`
87is a regexp, `rxmatch` is used.  When the request path matches,
88the server calls `HANDLER-PROC` with two arguments:
89
90    (handler-proc REQUEST APP-DATA)
91
92`REQUEST` is a request record, explained below.
93`APP-DATA` is an application-specific data given at the time the server
94is started.  Gauche-makiki treats `APP-DATA` as opaque data; it's
95solely up to the application how to use it.
96
97The optional `GUARD-PROC` is a procedure called right after the
98server finds the request path matches `PATTERN`.
99It is called with two arguments,
100`REQUEST` and `APP-DATA`.  If the guard proc returns false,
101the server won't call the corresponding handler and look for
102another match instead.
103It is useful to refine the condition the handler is called.
104
105If the guard procedure returns a non-false value, it is stored in the
106`guard-value` slot of the request record, and available to the
107handler procedure.
108See [examples/session.scm](examples/session.scm) for an example
109of using a guard procedure and the request's `guard-value` slot.
110
111
112### Request record
113
114A request record passed to the handlers and guard procedures
115has the following slots (only public slots are shown):
116
117      line                ; request line
118      socket              ; client socket  (#<socket>)
119      remote-addr         ; remote address (sockaddr)
120      method              ; request method (symbol in upper cases, e.g. GET)
121      uri                 ; request uri
122      http-version        ; requested version (e.g. "1.1")
123      server-host         ; request host (string)
124      server-port         ; request port (integer)
125      path                ; request path (string, url decoded)
126      path-rxmatch        ; #<regmatch> object of matched path
127      guard-value         ; the result of guard procedure
128      query               ; unparsed query string
129      params              ; query parameters (result of cgi-parse-parameters)
130      headers             ; request headers (result of rfc822-read-headers)
131      (response-error)    ; #f if response successfully sent, #<error> otherwise.
132                          ;  set by respond/* procedures.  The handler can check
133                          ;  this slot and take actions in case of an error.
134
135The following convenience procedures are avaiable on the request record.
136
137    (request-iport REQ)     ; input port to read from the client
138    (request-oport REQ)     ; output port to write to the client.
139                            ;  NB: the handler proc shouldn't write
140                            ;  to this port normally---one of the
141                            ;  'respond' procedures below takes care of
142                            ;  writing response line and headers.
143
144    (request-param-ref REQ PARAM-NAME . keys)
145                            ; Retrieve request query-string parameter with
146                            ; PARAM-NAME.  KEYS are a keyward-value list
147                            ; passed to cgi-get-parameter in www.cgi.
148                            ; See also `let-params` below for easier access.
149    (request-header-ref REQ HEADER-NAME :optional (DEFAULT #f))
150                            ; retrieve the value from the request headers.
151                            ; See also `let-params` below for easier access.
152    (request-cookies REQ)   ; returns parsed cookie list (see rfc.cookie)
153                            ; in the request.
154    (request-cookie-ref REQ COOKIE-NAME :optional (DEFAULT #f))
155                            ; returns one entry of the parsed cookie with
156                            ; the given COOKIE-NAME.  The returned value
157                            ; is the result of `parse-cookie-string` of
158                            ; `rfc.cookie`, i.e.
159                            ; `(<name> <value> <cookie-parameters> ...)`
160                            ; See also `let-params` below for easier access.
161
162The handler procedure can set/modify response headers using
163the following procedures.
164
165    (response-header-push! REQ HEADER-NAME VALUE)
166    (response-header-delete! REQ HEADER-NAME)
167    (response-header-replace! REQ HEADER-NAME VALUE)
168    (response-cookie-add! REQ NAME VALUE . COOKIE-OPTIONS)
169    (response-cookie-delete! REQ NAME)
170
171(NB: `response-cookie-delete!` merely removes the named cookie form
172the response message; it does not remove the cookie from the client.)
173
174
175### Accessing parameters passed by client
176
177After a handler is selected according to the request url and method,
178query parameters in the url is parsed and saved in `request-params`.
179(Note: Parameters passed via `POST` request body are not
180parsed automatically; see *Handling POST request body* below.)
181
182It is ofen the case that the server needs to look at several
183different places to see what parameters the client prodives;
184most commonly they are passed via query parameters in url
185or form-encoded in POST body, but can also be via request path
186component (often the case in REST API) or sometimes via cookies
187or even via request headers.   The `let-params` macro provides
188an easy and convenient way to access those parameters.
189
190    (let-params REQ (VAR-SPEC ...) BODY ...)
191
192`REQ` should be the request record.  Each `VAR-SPEC` specify
193a variable and its source, in one of the following forms:
194
195    (var source kv-args ...)
196    (var)
197    var
198
199Where `var` is a symbol (variable name), `source` is a string,
200and `kv-args` is keyword-value list.  This form extracts parameters
201according to `source` and binds its value to `var`, then executes
202`body` ....  The latter two forms are a shorthand for `(var "q")`.
203
204The `source` string can have either `<kind>:<name>` or just `<kind>`,
205where `<kind>` is a single character specifying where the value
206should be taken.
207
208    q  - Query parameters
209    p  - Path regexp matches
210    c  - Cookies
211    h  - Request headers
212
213The optional `<name>` part specifies the parameter's name as sent
214from the client, e.g. query name, cookie name or header name.
215For path regexp match, `<name>` can be a word for named subgroup,
216or an integer for unnamed subgroups.  If `<name>` is omitted, the
217name of `var` is assumed.
218
219The following keyword arguments are accepted in `kv-args`.
220
221    :default <value>    Specifies the default value when the
222                        parameter isn't provided from the client.
223                        The default default value is `#f`, except
224                        for the list query parameters, in which case
225                        the default default value is `()`.
226
227    :convert <proc>     Specifies the converter procedure `<proc>`,
228                        which should take a string and convert
229                        it to suitable type of object.  Note:
230                        if the value isn't provided, `<proc>`
231                        is never called and the default value is
232                        directly used.
233
234    :list <flag>        This is only effective for query parameters.
235                        If `<flag>` is a true value, the client
236                        can specify multiple instances of the same
237                        name of query parameters, and all the values
238                        are gathered to a list.  If `:convert` is
239                        also given, the convert procedure is applied
240                        to each value.  If `:default` is also given,
241                        its value is only used when there's no
242                        parameter for this name is provided.
243
244Suppose you have in the following code:
245
246    (define-http-handler #/^\/resource\/(\d+)\/edit$/
247      (^[req app]
248        (let-params req ([name        "q"]
249                         [comment     "q:c"]
250                         [resource-id "p:1" :convert x->integer]
251                         [sess        "c:sessionid"])
252          ...)))
253
254And if the client sends this request:
255
256     http://..../resource/33525/edit?name=foo&c=bar%20baz
257
258Then the code gets `name` to be bound to `"foo"`, `comment` to
259be bound to `"bar"`, `resource-id` to be bound to 33525.  (`Sess`
260would depend on whether the client send a cookie for `"sessionid"`.)
261
262### Handling POST/PUT request body
263
264A query string in a request url is automatically parsed and
265accessible via `request-query`, `request-params` and `request-param-ref`,
266but the parameters passed via POST/PUT body aren't processed by default.
267
268#### Form encoded data
269
270The following procedure returns a handler that parses POST request body
271and put the parsed result to `request-params`:
272
273    (with-post-parameters INNER-HANDLER :key PART-HANDLERS)
274
275It can handle the body with both `multipart/form-data` and
276`application/x-www-form-urlencoded` content types.
277
278The REQUEST structure the INNER-HANDLER receives got parsed parameters
279(If the original request also has a query string in url, that will be
280overwritten.)
281
282PART-HANDLERS specifies how to handle each parameter is handled
283according to its name.  By default, all parameter values are
284read into strings.  However, you might not want that behavior if
285you're accepting large file updates.  See the documentation of
286[`www.cgi`](http://practical-scheme.net/gauche/man/?p=www.cgi) module
287for the meaning of PART-HANDLERS.
288
289#### Json
290
291For Web APIs, it is convenient to receive request in json.  Here's
292a convenience wrapper:
293
294    (with-post-json INNER-HANDLER :key ON-ERROR)
295
296It parses the request body as json, and set the parsed value in
297`request-params` with the key "json-body".  That is, INNER-HANDLER
298can access the parsed json by `(request-param-ref req "json-body")`.
299If the client didn't pass the body, the "json-body" parameter is `#f`.
300
301Json dictionary becomes an alist, and json array becomes a vector.
302See the documentation of
303[`rfc.json`](http://practical-scheme.net/gauche/man/?p=rfc.json), for
304the details.
305
306ON-ERROR is a procedure that takes three argument, as
307`(on-error req app condition)`, and called when a `<json-parse-error>`
308is raised during parsing.  It must either return an alternative value
309to be used as the value of "json-body", or call `request-error` to
310notify the client the error.  If omitted or `#f`, the procedure
311returns 400 error to the client.
312
313
314#### Retrieving raw body
315
316If you don't use one of the POST handlers above, the request body
317isn't read when the handler is called.  The easiest way to retrieve
318the request body at once is using `read-request-body`:
319
320    (read-request-body req)
321
322This reads the request body into u8vector.  It can return `#f` if
323the request has no body.
324
325If the body has already read (even partially), or ended prematurely
326(i.e. the data is smaller than the size stated by content-length),
327this procedure returns `#<eof>`.
328
329
330#### Roll your own reader
331
332If you need to handle request body specially (for example, if the client
333sends huge binary data, you don't want to read everyhing into memory),
334you can handle it by yourself.  When the handler is called, the request
335body is available to be read from `(request-iport req)`.  Check
336the content-type header first, for it must specify the size of the request
337body in octets.
338
339
340### Response
341
342`HANDER-PROC` should call one of the following respond procedure at
343the tail position.   NB: These must be extended greatly to support
344various types of replies.
345
346    (respond/ok REQ BODY :key CONTENT-TYPE)
347                            ; This returns 200 response to the client,
348                            ; with BODY as the response body.  See below
349                            ; for allowed values in BODY.
350                            ; CONTENT-TYPE argument can override the default
351                            ; content-type inferred from BODY.
352
353    (respond/ng REQ CODE :key BODY CONTENT-TYPE)
354                            ; This returns CODE response to the client.
355                            ; If BODY keyword arg is omitted, the body
356                            ; consists of the description of the HTTP code.
357                            ; See below for allowed values in BODY.
358
359    (respond/redirect REQ URI :optional (CODE 302))
360                            ; Send back a redirection message using Location
361                            ; header.  URI can be an absolute uri or
362                            ; just a path component; in the latter case,
363                            ; protocol, host and port compoents are
364                            ; automatically added.
365
366These procedures return after the entire message is sent.  If an error
367occurs during sending the message (most likely because the client
368has disconnected prematurely), an error condition is stored in
369(request-response-error REQ).
370
371The response body for `respond/ok` and `respond/ng` can be one of
372the following forms.  The content type can be overridden by
373`CONTENT-TYPE` keyword argument.
374
375* _string_ : A string is sent back as `text/plain; charset=utf-8`.
376
377* _text-tree_ : A tree of strings; see `text.tree`.  Concatenated string
378is sent back as `text/plain; charset=utf-8`.
379
380* _u8vector_ : The content of the vector is sent back as
381`application/binary`.
382
383* (`file` _filename_) : The content of the named file is sent back.
384Content-type is determined by the file's extension by default.
385See the description of `file-handler` below for the details of
386content-type handling.
387
388* (`plain` _lisp-object_) : The lisp object is converted to a string
389by `write-to-string`, then sent back as `text/plain; charset=utf-8`.
390
391* (`json` _alist-or-vector_) : The argument is converted to a JSON
392by `construct-json-string` (see `rfc.json`), then sent back as
393`application/json; charset=utf-8`.
394
395* (`sxml` _sxml_) : The SXML tree is rendered by to XML or HTML. (If
396the root node of _sxml_ is `html`, then `sxml:sxml->html` is used to
397render to HTML with content type `text/html; charset=utf-8`.  Otherwise
398`sxml:sxml->xml` is used to render to XML, with conten type
399`application/xml`.
400
401* (`chunks` _string-or-u8vector_ ...) : Chunks are concatenated
402and sent back as `application/octed-stream`.  This form allows
403you to pass a lazy list, so that you can avoid creating entire
404content in memory.
405
406Check out scripts in `examples` directory for some concrete examples.
407
408
409### Errors and response
410
411You can raise a condition `<request-error>` to nofity the client that
412you encounter an error during processign the request.  Use the
413`request-error` procedure to raise the condition:
414
415    (request-error :key status body content-type)
416
417The `status` keyword argument is used as the http response status,
418defaulted by 400.  The `body` and `content-type` arguments are
419the same as in `respond/ok` and `respond/ng`.  This is useful to
420abort the processing of a request deep in the stack.
421
422For example, you can return an error message in JSON form to the
423client as follows:
424
425    (unless (parameter-is-valid?)
426      (request-error :body `(json (("message" . "Invalid parameter")))))
427
428If you raise an unhandled condition other than `<request-error>` from
429the handler, it is captured by makiki and the client receives
430`500 Internal Server Error` response, and the error itself is logged
431to the error log.
432
433
434## Built-in handlers
435
436For typical tasks, we provide convenience procedures to build a
437suitable handler.  The following procedures return a procedure
438that can be directly passed to `define-http-handler`; for example,
439the following handler definition serves files under `document-root`:
440
441    (define-http-handler "/"  (file-handler))
442
443Some handler-builders takes another handler procedure and returns
444a new handler that augments the original handler.
445
446See [examples](examples/) for more usages.
447
448
449### Serving files
450
451For the convenience, file-handler can be used to create a handler
452procedure suitable for define-http-handler to return a file
453on the server.
454
455    (file-handler :key (directory-index '("index.html" #t))
456                       (path-trans request-path)
457                       (root (document-root)))
458
459`PATH-TRANS` should be a procedure that takes `REQUEST` and returns
460the server-side file path.  The returned path should start from
461slash, and the document-root directory passed to the start-http-server
462is prepended to it.  It is not allowed to go above the document
463root directory by `"/../../.."` etc---403 error message would results.
464
465If you need to access files other than document-root, you can specify
466alternative root directory by the `ROOT` keyword argument.
467
468The `DIRECTORY-INDEX` keyword argument specifies the behavior when
469given path is a directory.  It must be a list of either filename or
470`#t`.  The list is examined from left to right; if it is a filename,
471and the named file exists in the directory, the content of the file
472is returned.  If it is a filename but does not exist, next element
473is examined.  If it is `#t`, the list of the entries in the directory
474is returned.
475
476Makiki uses some heuristics to determine `content-type` of the file,
477but that's far from complete.   You can use a parameter `file-mime-type`
478to customize the association of content-type and files; it must be a
479procedure that takes one argument, the pathname of the file, and it
480must return a mime-type in string, or `#f` to delegate the association
481to the makiki's default handler.
482
483    (document-root)
484
485A parameter that holds the current path of the document root (the one
486given to `start-http-server`; `"."` by default.)
487
488The `Last-modified` response header is generated by this handler
489automatically, based on the the timestamp of the file.
490
491
492### Calling CGI scripts
493
494There's an experimental support to call a CGI script written
495in Gauche.  Instead of spawning a child process, we load
496Gauche program and call its main routine "in process".
497You have to `(use makiki.cgi)` to use this feature.
498
499    (cgi-script FILE :key ENTRY-POINT SCRIPT-NAME LOAD-EVERY-TIME)
500
501Loads the cgi script in FILE, and creates and returns a cgi handler that
502calls a procedure named by ENTRY-POINT inside the script (`main` by default).
503
504To avoid interference with makiki itself, the script is loaded
505into an independent, anonymous module.
506
507Loading is done only once unless LOAD-EVERY-TIME is true.
508Usually, loading only once cuts the overhead of script loading for
509repeating requests.  However, if the cgi script sets some global
510state, it should be loaded for every request---a script can
511be executed concurrently by multiple threads, so any code
512relying on a shared mutable global state will fail.
513Note also that we assume the script itself isn't written inside
514a specific module; if it has it's own define-module and
515select-module, the module will be shared for every load, and
516we won't have enough isolation.
517
518The cgi script should access to cgi metavariables through
519`cgi-get-metavariable` (in `www.cgi` module), not directly
520from the environment variables.
521
522SCRIPT-NAME is the path to the script *in the URL*.  That is,
523if the script is accessible via `http://example.com/foo/bar/baz.cgi`,
524then it should be `"/foo/bar/baz.cgi"`.  It doesn't need to be
525related to the actual pathname of the cgi script file.  The value
526becomes the value of `SCRIPT_NAME` CGI metavariable, and also
527used to calculate `PATH_INFO` CGI metavariable.
528
529    (cgi-handler PROC :key SCRIPT-NAME)
530
531This is the low-level procedure that creates an http handler that
532sets up the cgi metavariables and calls PROC, that takes one
533argument (as in `main` procedure of the usual script; though
534most cgi scripts won't use the argument).
535
536PROC would write out the response to its stdout; which will
537be captured by the created handler and returned to the client.
538
539
540
541### Modifying headers
542
543    (with-header-handler inner-handler header value ...)
544
545This returns a handler that first adds extra response headers
546then calls INNER-HANDLER.
547
548Header is a keyword representing the header name; value can
549be a string for header value, a procedure to take request and
550app-data and to return a string header value, or #f to omit the
551header.  For example, the following call returns a handler
552that adds "Cache-control: public" header to the file response.
553
554    (with-header-handler (file-handler) :cache-control "public")
555
556Since that the headers are added before the inner handler is called,
557they may be overwritten by inner-handler.
558
559
560## Logging and tuning
561
562### Logging
563
564If you write out logs inside an http handler, you can use those
565macros:
566
567    (access-log FMT ARGS ...)
568    (error-log FMT ARGS ...)
569
570FMT and ARGS are the same as `log-format` in `gauche.logger`.
571The destination of logs are set by the keyword arguments
572of `start-http-server` described below.
573
574### Profiling
575
576You can run Gauche's built-in sampling profiler during handling
577a request.  There are two ways to do it.
578
579If the environment variable `MAKIKI_PROFILER_OUTPUT` is set
580when `makiki.scm` is loaded, Makiki automatically profiles all
581handlers.  The value of `MAKIKI_PROFILER_OUTPUT` is used as a
582filename to which the profiling result is written out.  If the
583file already exists, the result is appended to it.  Each result is preceded
584by the request path.
585
586Alternatively, you can selectively profile specific handlers
587by wrapping the handler with `with-profiling-handler`:
588
589    (with-profiling-handler OUTPUT-FILE INNER-HANDLER)
590
591This returns a procedure suitable to be a handler.  When called,
592it runs `INNER-HANDLER` with profiler running, and then write out
593the result to `OUTPUT-FILE`.   When `OUTPUT-FILE` already exists,
594the result is appended to it.
595
596You should use either one of the above method, but not both;
597`MAKIKI_PROFILER_OUTPUT` tries to profile every handler, even it
598is already wrapped by `with-post-parameters`.
599
600Note: If multiple handlers run simultaneously in multiple threads,
601the profiling result becomes less reliable, for you don't know
602which thread the sampling picks---the profiling is recorded per thread,
603but the sampling timer is shared.  Make sure to issue one request
604at a time during profiling.
605
606See the [Using profiler](http://practical-scheme.net/gauche/man/?p=Using+profiler) section of the Gauche reference manual
607for the details of Gauche's built-in profiler.
608
609
610## Starting and terminating the server
611
612Finally, to start the server, call `start-http-server`.
613
614    (start-http-server :key host port path document-root num-threads max-backlog
615                            access-log error-log forwarded? app-data
616                            startup-callback shutdown-callback
617                            control-channel)
618
619
620    host (#f or string), port (integer) - Passed to make-server-sockets
621       of gauche.net to open the server socket.  The default values are
622       #f and 8080.
623
624    path (#f or string) - If a string is given, it specifies the path to
625       a Unix-domain socket on which the server listens.  In that case
626       `host` and `port` arguments are ignored.
627
628    document-root - used to specify the root of the document served
629       by file-handler.  The default is the process's working directory.
630
631    num-threads - number of threads to serve the request.  Currently threads
632       are created when the server is started.  The default is 5.
633
634    max-backlog - max number of request queued when all threads are busy.
635       When a request comes while the queue is full, 503 (server busy)
636       response is returned to the client.   The default is 10.
637
638    access-log, error-log - specify the destination of logs.  #f (no log),
639       #t (stdout), string (filename) or <log-drain> object.
640       For access log, <log-drain> is better not to have prefix, for
641       timestamp is included in the message.  The default is #f.
642
643    forwarded? - specify true if you use makiki behind a reverse-proxy httpd,
644       and access-log uses the value of x-forwarded-for header if exists,
645       instead of the client's address.
646
647    app-data - an opaque data passed to the request handler as is.
648
649    startup-callback - a procedure to be called after the server opened
650       sockets, but before start processing any requests.  A list of
651       server sockets are passed as the only argument.  Logging procedures
652       are already active.
653
654    shutdown-callback - a thunk to be called after all the server operations
655       are shut down.  If given, this is the last thing `start-http-server`
656       does before returning.
657
658    control-channel - an opaque object, through which you can request
659       the server loop to shutdown.  See `make-server-control-channel` and
660       `terminate-server-loop` below.
661
662Note that `start-http-server` enters the server loop and won't return
663by default.  There are two ways to shut down the server loop.
664
665* Send `SIGINT` or `SIGTERM`.  By default, signals sent to a Gauche process
666  is handled by the main thread.  So if you called `start-http-server`
667  in the main thread, this is the easiest way.
668* If you run `start-http-server` outside of the main thread, or don't want
669  to rely on signals, you need a bit of setup.  (1) Create a server control
670  channel by `make-server-control-channel` and pass it to `:control-channel`
671  argument of the `start-http-server`.  (2) When you want to request
672  the server loop to shutdown, call `terminate-server-loop` with the
673  control channel.  See below for further description.  See
674  [this test code](tests/termination.scm) as an example.
675
676
677Here's the API for controlling the server loop.
678
679    (make-server-control-channel)
680
681Returns an opaque object through which you can request the server loop to
682shut down.   You need one channel for each server loop, if you have more
683than one loop.
684
685    (terminate-server-loop CHANNEL EXIT-CODE)
686
687Calling this function causes `start-http-server` that has CHANNEL
688to break the loop, does cleaning up (including finishing request that are
689already being processed), and returns EXIT-CODE.
690
691You can pass any object to EXIT-CODE, but the supposed way to call
692`start-http-server` is the tail position of the `main` function; in
693that case, EXIT-CODE becomes the exit code of the server.
694
695    (define (main args)
696       ...
697       (start-http-server ...))
698
699
700## Add-ons
701
702Some less frequently used features are provided in separate modules.
703
704* `makiki.connect`: Handling `CONNECT` http request.
705See [simple proxy example](examples/proxy.scm).
706
707* `makiki.cgi` : Handling CGI scripts.
708
709
710## Examples
711
712The [examples](examples/) directory contains some simple server scripts,
713each one shows how to implement a specific fuctionality.
714
715