~mna/tulip

The tulip.pkg.server module exports the server package.

#Dependencies

  • tulip.pkg.middleware

#Configuration

  • host: string|nil = address to bind to.
  • port: number|nil = port number to use.
  • path: string|nil = path to a UNIX socket.
  • reuseaddr: boolean = set the SO_REUSEADDR flag.
  • reuseport: boolean = set the SO_REUSEPORT flag.
  • error_handler: function|nil = if set, handles errors raised by the web server. For per-request error handling, use handler.recover. Receives the http.server instance, the error context (http.server, http.stream, http.connection, etc.), the operation string (e.g. 'accept'), the error message and the error code. The default handler raises an error.
  • limits.connection_timeout: number = connection timeout in seconds.
  • limits.idle_timeout: number = idle connection timeout in seconds.
  • limits.max_active_connections: number = maximum number of active connections.
  • limits.read_timeout: number = read operations timeout in seconds.
  • limits.write_timeout: number = write operations timeout in seconds.
  • tls.required: boolean = whether HTTPS is required.
  • tls.protocol: string = TLS protocol of the SSL context, e.g. TLSv1_2.
  • tls.certificate_path: string = path to the TLS certificate file.
  • tls.private_key_path: string = path to the TLS private key file.

#API Extensions

Registering this package provides the following method and field extensions.

#ok, err = App:main(cq)

Takes control of the main loop of the App. Starts the web server, calling the App instance with the Request and Response instances for each request.

Args:

  • cq: userdata = the cqueue to use for the loop

Returns:

  • ok: boolean = true on success
  • err: Error|nil = the error message if ok is falsy
#App.server: Server

The http server instance is stored on the App.

#f, Stream = Request:body()

Returns an iterator over the chunks of the body, with the read timeout (if any) applied to reading the whole body (i.e. iterating until the end). Throws an error if the body is already consumed.

Returns:

  • f: function = iterator function
  • Stream: userdata = the Stream instance to get next chunks of the body
#s, err = Request:read_body(mode)

Reads the body based on the mode specified.

  • if mode is a number, read and return up to n bytes
  • if mode is "a", reads the whole body and returns it as a string, and also sets req.raw_body field
  • if mode is "l", read and return the next line, skipping eol
  • if mode is "L", same as "l" but does not skip eol

On error, returns nil and an error message. If mode is "a" and the raw_body field is set, returns it.

Args:

  • mode: string = the read mode, see description above

Returns:

  • s: string = the read value
  • err: Error|nil = the error message if s is falsy
#t, err = Request:decode_body([force_ct])

Decodes the body using the request's content-type or (if provided) force_ct to determine the decoder to use, and returns the resulting table. Also sets self.decoded_body field for future use, and returns it if already set.

Note that this fully reads the body, so if Request:read_body wasn't called yet, it will be called.

Returns nil, error on error.

Args:

  • force_ct: string = the optional content-type to use to decode the body, overriding the request content-type.

Returns:

  • t: table = the decoded body
  • err: Error|nil = the error message if t is falsy
#Request.stream: Stream

The Stream instance of the request, from lua-http.

#Request.remote_addr: string

The address of the request's peer.

#Request.proto: number

The http protocol version.

#Request.authority: string

The authority part of the url.

#Request.headers: Headers

The headers instance of the request, from lua-http.

#Request.cookies: table

The cookies for the request, in name-value pairs.

#Request.method: string

The http method of the request.

#Request.rawurl: string

The request's raw (unparsed, unmodified) url.

#Request.url: table

The request's parsed url, with path, scheme, query fields, etc.

#Request.read_timeout: number

The read timeout as configured on the server package.

#Request.locals: table

A table to store key-value pairs local to the Request.

#ok, err = Response:_write_headers(hdrs[, eos[, deadline]])

Writes the headers. This function should not be called directly, it exists for extensibility (e.g. gzip middleware) to intercept writing headers before the write actually happens but after Response:write has set all expected values. It should return true on success, nil and an error message on error (it must not throw).

Args:

  • hdrs: Headers = the http headers instance to write
  • eos: boolean = flag indicating if this is the end of the stream
  • deadline: number = an absolute deadline time value from which a timeout will be computed.

Returns:

  • ok: boolean = true on success
  • err: Error|nil = error message if ok is falsy
#n, err = Response:_write_body(f[, deadline])

Writes the body. This function should not be called directly, it exists for extensibility (e.g. gzip middleware) to intercept writing the raw body bytes as called from Response:write. It should return the number of bytes written on success, nil and an error message on error (it must not throw).

Args:

  • f: function = function that returns two values on each call, the string to write and a flag that indicates if this is the last chunk. In case of errors it must return nil, err.
  • deadline: number = an absolute deadline time value from which a timeout will be computed for each written chunk.

Returns:

  • n: number = number of bytes written
  • err: Error|nil = the error message if n is falsy
#n, err, started = Response:write(t)

Writes a response. Should not be mixed with calls to the low-level stream object.

If the request method was HEAD, no body gets written, but it does get processed to compute the content-length.

Returns the number of body bytes written on success (which may be 0), or nil and an error message. A third return value indicates if some data (e.g. headers) was written before the failure, by returning true in that case (falsy otherwise).

Args:

  • t: table = The table can have those fields:
    • status (integer), defaults to 200.
    • content_type (string), defaults to 'text/plain' if there's a body.
    • body (string|table|function|file): if it is a table, gets encoded based on the content_type and the registered encoders. If there is no content-type or no known one, an error is returned. If this is a function, it must return an iterator that returns string chunks to write. If it is a file object, behaves as path but does not close it when done sending.
    • context (table): the context for the template specified in path.
    • path (string): a path to a file to write in chunks. If a context field is also present (even if empty), path is rendered as a template with context passed to it.

Returns:

  • n: number = number of body bytes written
  • err: Error|nil = the error message if n is falsy
  • started: boolean = if there was an error, indicates if some bytes were written
#Response.headers: Headers

The headers instance of the response, from lua-http.

#Response.stream: Stream

The Stream instance of the response, from lua-http.

#Response.write_timeout: number

The write timeout as configured on the server package.

#Response.bytes_written: number

The number of body bytes written.

Back to index

About this wiki

commit 3ebfbd288b8e5c95fdf8ce2027a0e94cfa1c8976
Author: Martin Angers <martin.n.angers@gmail.com>
Date:   2021-02-25T14:07:12-05:00

Update to reflect Request:validate_body
Clone this wiki
https://git.sr.ht/~mna/tulip-wiki (read-only)
git@git.sr.ht:~mna/tulip-wiki (read/write)