The Lua/APR binding aims to bring most of the functionality in the Apache Portable Runtime (APR) to the small and flexible programming language Lua. This document contains the documentation for the Lua/APR binding. Some notes about this documentation:
Most of the documentation is based on the official APR documentation but I've had to consult the APR source code here and there when the official documentation didn’t suffice. If anything seems amiss please let me know.
The entries for all functions are automatically generated from the C and Lua source code of the binding to prevent that documentation and implementation become out of sync.
This document was generated from the Lua/APR 0.19.8 source code.
The functions in this module can be used to encode strings in base64 and to
decode base64 encoded strings. The base64 format uses the printable
characters A-Z
, a-z
, 0-9
, +
and /
to encode binary data. This can
be useful when your data is used in a context that isn’t 8-bit clean, for
example in e-mail attachments and data: URLs. You can read
more about base64 encoding in this Wikipedia article.
apr.base64_encode(plain) → coded
Encode the string plain using base64 encoding. On success the coded string is returned, otherwise a nil followed by an error message is returned. As an example, here is how to convert an image file into a data: URL:
> image = io.open 'lua-logo.png'
> encoded_data = apr.base64_encode(image:read '*a')
> data_url = 'data:image/png;base64,' .. encoded_data
> = '<img src="' .. url .. '" width=16 height=16 alt="Lua logo">'
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAm5JREFUOMt9k01LW0EUhp+Z5CaxatSbljRioaQgmCIKoUo3XXRRF241tUuhIEgWIgRSKzhtNLZbKf0BulL6C1x234WgoS0otIoWP4Ji48ed3Dtd9CoSW18YBs45z8uZjyOokVKqGQgBzZZlHQshHM/zGqrVaiCRSGyOjOwmhXDngZgxjAUvwLm5uXC5XI5Ho9G98fHxQ2AXVNS3/QFQLBZjdXXuu7MzegCE4IO4CiulfoK6LSUTxvAcaPX9t4Vg0fMoSskbYxj14ysBgN7e3oRSahPepoUwn4FnQONFd11d8cZstvexbUderq0dKCk5iUTEL63lqCgWi3eklE4+fxYWghXg7tU7aWmJsLExRlNTGIC+voWD5eWtDqUcY9v2sXRdtyGfzx9JyataGKCtLXoJA7S3x2JSOhNKqf1yuXxPuq57DGAML/iHVld3WVpaA6BU2mNxce2yNhgMnkrLsgIw2wLEC4Wn1wyMgaGhT9j2ezo7P7K/fwIQB2VXq9VT6XleFIRXC05OPrncM5mHDAykGB19dLXEC4VCASml/A35I2CL/+jkRHN6qkkm7YvQFqhDx3GapNZa+59iIRAQZLM9DA93U6k4DA6miMVukU4n0NrDtusIhQIIwfyFt1BKtaVSqZ1MptQoBF+AJDdrwxjSs7NhEQwGHamU2iqVSg9AHRpDP7B+A7xuDP3GTB2dn5/X53K5ivQH6HuhUOgA9dUYuo3hNbAKaH+tGiMm/uamvk1PT99PpVI7AKJmEpPAtlLqzH9EPy8MwMzMTEJrHfh75Ix7zcA3abUsy9VaG8AGDgEHiNbX1+/lcrnK1fo/txYAMvuVJrYAAAAASUVORK5CYII=" width=16 height=16 alt="Lua logo">
This is what the result looks like (might not work in older web browsers):
This function is binary safe.
apr.base64_decode(coded) → plain
Decode the base64 encoded string coded. On success the decoded string is returned, otherwise a nil followed by an error message is returned.
This function is binary safe.
These functions support the MD5 and SHA1 cryptographic hash functions. You can also use them to encrypt plain text passwords using a salt, validate plain text passwords against their encrypted, salted digest and read passwords from standard input while masking the characters typed by the user.
The MD5 and SHA1 functions can be used to hash binary data. This is useful because the hash is only 16 or 32 bytes long, yet it still changes significantly when the binary data changes by just one byte.
If that doesn’t look useful consider the following scenario: The Lua authors have just finished a new release of Lua and are about to publish the source code on http://lua.org. Before they publish the tarball they first calculate its MD5 and SHA1 hashes. They then publish the archive and hashes on the downloads page. When a user downloads the tarball they can verify whether it was corrupted or manipulated since it was published on http://lua.org by comparing the published hash against the hash of the tarball they just downloaded:
> handle = io.open('lua-5.1.4.tar.gz', 'rb')
> data = handle:read('*a'); handle:close()
> = apr.md5(data) == 'd0870f2de55d59c1c8419f36e8fac150'
true
> = apr.sha1(data) == '2b11c8e60306efb7f0734b747588f57995493db7'
true
apr.md5(input [, binary]) → digest
Calculate the MD5 message digest of the string input. On success the digest is returned as a string of 32 hexadecimal characters, or a string of 16 bytes if binary evaluates to true. Otherwise a nil followed by an error message is returned.
This function is binary safe.
apr.md5_encode(password, salt) → digest
Encode the string password using the MD5 algorithm and a salt string. On success the digest is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.password_validate(password, digest) → valid
Validate the string password against a digest created by one of the APR-supported algorithms (MD5 and SHA1). On success true is returned, otherwise a nil followed by an error message is returned.
Hashes created by crypt are supported only on platforms that provide crypt(3), so don’t rely on that function unless you know that your application will be run only on platforms that support it. On platforms that don’t support crypt(3), this falls back to a clear text string comparison.
This function is not binary safe.
apr.password_get(prompt) → password
Display the string prompt on the command-line prompt and read in a password
from standard input. If your platform allows it, the typed password will be
masked by a placeholder like *
. On success the password is returned,
otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.md5_init() → md5_context
Create and return an object that can be used to calculate MD5 message digests in steps. If an error occurs a nil followed by an error message is returned. This can be useful when you want to calculate message digests of large inputs, for example files like ISO images and backups:
> function md5_file(path, binary)
>> local handle = assert(io.open(path, 'rb'))
>> local context = assert(apr.md5_init())
>> while true do
>> local block = handle:read(1024 * 1024)
>> if not block then break end
>> assert(context:update(block))
>> end
>> return context:digest(binary)
>> end
>
> md5_file 'ubuntu-10.04-desktop-i386.iso'
'd044a2a0c8103fc3e5b7e18b0f7de1c8'
md5_context:update(input) → status
Continue an MD5 message digest operation by processing another message block and updating the context. On success true is returned, otherwise a nil followed by an error message is returned.
This function is binary safe.
md5_context:digest([binary]) → digest
End an MD5 message digest operation. On success the digest is returned as a string of 32 hexadecimal characters, or a string of 16 bytes if binary evaluates to true. Otherwise a nil followed by an error message is returned.
If you want to re-use the context object after calling this method see md5_context:reset().
md5_context:reset() → status
Use this method to reset the context after calling md5_context:digest(). This enables you to re-use the same context to perform another message digest calculation. On success true is returned, otherwise a nil followed by an error message is returned.
apr.sha1(input [, binary]) → digest
Calculate the SHA1 message digest of the string input. On success the digest is returned as a string of 40 hexadecimal characters, or a string of 20 bytes if binary evaluates to true. Otherwise a nil followed by an error message is returned.
This function is binary safe.
apr.sha1_init() → sha1_context
Create and return an object that can be used to calculate SHA1 message digests in steps. See also the example for apr.md5_init().
sha1_context:update(input) → status
Continue an SHA1 message digest operation by processing another message block and updating the context.
This function is binary safe.
sha1_context:digest([binary]) → digest
End an SHA1 message digest operation. On success the digest is returned as a string of 40 hexadecimal characters, or a string of 20 bytes if binary evaluates to true. Otherwise a nil followed by an error message is returned.
If you want to re-use the context object after calling this method see sha1_context:reset().
sha1_context:reset() → status
Use this method to reset the context after calling sha1_context:digest(). This enables you to re-use the same context to perform another message digest calculation.
apr.date_parse_http(string) → time
Parses an HTTP date in one of three standard forms:
'Sun, 06 Nov 1994 08:49:37 GMT'
– RFC 822, updated by RFC 1123'Sunday, 06-Nov-94 08:49:37 GMT'
– RFC 850, obsoleted by RFC 1036'Sun Nov 6 08:49:37 1994'
– ANSI C’s asctime() formatOn success the date is returned as a number like documented under time routines. If the date string is out of range or invalid nil is returned.
This function is not binary safe.
apr.date_parse_rfc(string) → time
Parses a string resembling an RFC 822 date. This is meant to be lenient in its parsing of dates and hence will parse a wider range of dates than apr.date_parse_http().
The prominent mailer (or poster, if mailer is unknown) that has been seen in the wild is included for the unknown formats:
'Sun, 06 Nov 1994 08:49:37 GMT'
– RFC 822, updated by RFC 1123'Sunday, 06-Nov-94 08:49:37 GMT'
– RFC 850, obsoleted by RFC 1036'Sun Nov 6 08:49:37 1994'
– ANSI C’s asctime() format'Sun, 6 Nov 1994 08:49:37 GMT'
– RFC 822, updated by RFC 1123'Sun, 06 Nov 94 08:49:37 GMT'
– RFC 822'Sun, 6 Nov 94 08:49:37 GMT'
– RFC 822'Sun, 06 Nov 94 08:49 GMT'
– Unknown [drtr@ast.cam.ac.uk]'Sun, 6 Nov 94 08:49 GMT'
– Unknown [drtr@ast.cam.ac.uk]'Sun, 06 Nov 94 8:49:37 GMT'
– Unknown [Elm 70.85]'Sun, 6 Nov 94 8:49:37 GMT'
– Unknown [Elm 70.85]On success the date is returned as a number like documented under time routines. If the date string is out of range or invalid nil is returned.
This function is not binary safe.
The APR DBD module makes it possible to query relational database engines like SQLite, MySQL, PostgreSQL, Oracle, ODBC and FreeTDS. This module currently has some drawbacks which appear to be unavoidable given the design of the Apache Portable Runtime DBD framework:
Booleans and numbers are returned as strings because result set types are not known to the Lua/APR binding (and type guessing is too error prone)
String arguments and results are not binary safe, this means they will be truncated at the first zero byte (see the apr-dev mailing list thread “current dbd initiatives” for discussion about this limitation of APR)
Note that if you control the data going into the database you can overcome the second limitation by using APR’s built in support for Base64 encoding.
On Debian/Ubuntu Linux you can install one or more of the following packages to enable support for the corresponding database driver (dependencies will be installed automatically by the package management system):
In my initial tests on Ubuntu I installed libaprutil1-dbd-sqlite3 but kept getting an error when trying to load the driver:
$ lua -e "print(require('apr').dbd('sqlite3'))"
nil DSO load failed EDSOOPEN
After a while I found the problem using LD_DEBUG:
$ LD_DEBUG=libs lua -e "require('apr').dbd('sqlite3')" 2>&1 | grep undefined
/usr/lib/apr-util-1/apr_dbd_sqlite3-1.so: error: symbol lookup error: undefined symbol: apr_pool_cleanup_null (fatal)
Having identified the problem, finding a workaround was easy:
$ export LD_PRELOAD='/usr/lib/libapr-1.so.0:/usr/lib/libaprutil-1.so.0'
$ lua -e "print(require('apr').dbd('sqlite3'))"
database driver (0x853bdfc)
apr.dbd(name) → driver
Create a database driver object. The string name decides which database engine to use. On success the driver object is returned, otherwise a nil followed by an error message is returned. Currently supported engines include:
'mysql'
'pgsql'
'sqlite3'
'sqlite2'
'oracle'
'freetds'
'odbc'
Note that in its default configuration the Apache Portable Runtime uses dynamic loading to load database drivers which means apr.dbd() can fail because a driver can’t be loaded.
driver:open(params) → status
Open a connection to a backend. The string params contains the arguments to the driver (implementation-dependent). On success true is returned, otherwise a nil followed by an error message is returned. The syntax of params is as follows:
PostgreSQL: params is passed directly to the PQconnectdb() function, check the PostgreSQL documentation for more details on the syntax
SQLite2: params is split on a colon, with the first part used as the filename and the second part converted to an integer and used as the file mode
SQLite3: params is passed directly to the sqlite3_open() function as a filename to be opened, check the SQLite3
documentation for more details (hint: if params is ':memory:'
a
private, temporary in-memory database is created for the connection)
Oracle: params can have ‘user’, ‘pass’, ‘dbname’ and ‘server’ keys, each followed by an equal sign and a value. Such key/value pairs can be delimited by space, CR, LF, tab, semicolon, vertical bar or comma
MySQL: params can have ‘host’, ‘port’, ‘user’, ‘pass’, ‘dbname’,
‘sock’, ‘flags’ ‘fldsz’, ‘group’ and ‘reconnect’ keys, each followed by
an equal sign and a value. Such key/value pairs can be delimited by
space, CR, LF, tab, semicolon, vertical bar or comma. For now, ‘flags’
can only recognize CLIENT_FOUND_ROWS
(check MySQL manual for details).
The value associated with ‘fldsz’ determines maximum amount of memory (in
bytes) for each of the fields in the result set of prepared statements.
By default, this value is 1 MB. The value associated with ‘group’
determines which group from configuration file to use (see
MYSQL_READ_DEFAULT_GROUP
option of mysql_options() in
MySQL manual). Reconnect is set to 1 by default (i.e. true)
FreeTDS: params can have ‘username’, ‘password’, ‘appname’, ‘dbname’, ‘host’, ‘charset’, ‘lang’ and ‘server’ keys, each followed by an equal sign and a value
This function is not binary safe.
driver:dbname(name) → status
Select the database name. On succes true is returned, otherwise a nil followed by an error message is returned. Not supported for all drivers (e.g. SQLite by definition only knows a single database).
This function is not binary safe.
driver:driver() → name
Get the name of the database driver. Returns one of the strings listed for apr.dbd().
driver:check() → status
Check the status of the database connection. When the connection is still alive true is returned, otherwise a nil followed by an error message is returned.
driver:query(sql) → status, affected_rows
Execute an SQL query that doesn’t return a result set. On success true followed by the number of affected rows is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
driver:select(sql [, random_access]) → result_set
Execute an SQL query that returns a result set. On success a result set object is returned, otherwise a nil followed by an error message is returned. To enable support for random access you can pass the optional argument random_access as true.
This function is not binary safe.
driver:transaction_start() → status
Start a transaction. May be a no-op. On success true is returned, otherwise a nil followed by an error message is returned.
Note that transaction modes, set by calling driver:transaction_mode(),
will affect all query/select calls within a transaction. By default, any
error in query/select during a transaction will cause the transaction to
inherit the error code and any further query/select calls will fail
immediately. Put transaction in 'ignore-errors'
mode to avoid that. Use
'rollback'
mode to do explicit rollback.
driver:transaction_end() → status
End a transaction (commit on success, rollback on error). May be a no-op. On success true is returned, otherwise a nil followed by an error message is returned.
driver:transaction_mode([mode]) → mode
Get or set the transaction mode, one of:
'commit'
: commit the transaction'rollback'
: rollback the transaction'ignore-errors'
: ignore transaction errorsOn success the new transaction mode is returned, otherwise a nil followed by an error message is returned.
driver:prepare(sql) → prepared_statement
Prepare a statement. On success a prepared statement object is returned, otherwise a nil followed by an error message is returned.
To specify parameters of the prepared query, use %s
, %d
etc. (see below
for full list) in place of database specific parameter syntax (e.g. for
PostgreSQL, this would be $1
, $2
, for SQLite3 this would be ?
, etc.).
For instance: SELECT name FROM customers WHERE name = %s
would be a query
that this function understands. Here is the list of supported format
specifiers and what they map to in SQL (generally you'll only need the types
marked in bold text):
%hhd
: TINY INT%hhu
: UNSIGNED TINY INT%hd
: SHORT%hu
: UNSIGNED SHORT%d
: INT%u
: UNSIGNED INT%ld
: LONG%lu
: UNSIGNED LONG%lld
: LONG LONG%llu
: UNSIGNED LONG LONG%f
: FLOAT, REAL%lf
: DOUBLE PRECISION%s
: VARCHAR%pDt
: TEXT%pDi
: TIME%pDd
: DATE%pDa
: DATETIME%pDs
: TIMESTAMP%pDz
: TIMESTAMP WITH TIME ZONE%pDn
: NULLThis function is not binary safe.
prepared_statement:query(...) → status
Using a prepared statement, execute an SQL query that doesn’t return a result set. On success true followed by the number of affected rows is returned, otherwise a nil followed by an error message is returned.
If you pass a list then the values in the list become query parameters, otherwise all function arguments become query parameters.
This function is not binary safe.
prepared_statement:select(random_access, ...) → result_set
Using a prepared statement, execute an SQL query that returns a result set. On success a result set object is returned, otherwise a nil followed by an error message is returned. To enable support for random access pass random_access as true, otherwise pass it as false.
If you pass a list then the values in the list become query parameters, otherwise all function arguments after random_access become query parameters.
TODO Make the random_access argument an attribute of the prepared statement object so that we can get rid of the argument here?!
This function is not binary safe.
result_set:columns([num]) → name [, ...]
If no arguments are given return the names of all columns in the result set, otherwise return the name of the column with index num (counting from one). For example:
> driver = assert(apr.dbd 'sqlite3')
> assert(driver:open ':memory:')
> results = assert(driver:select [[ SELECT 1 AS col1, 2 AS col2 ]])
> = assert(results:columns())
{ 'col1', 'col2' }
This function is not binary safe.
result_set:row(num) → row
Return a table with named fields for the next row in the result set or the row with index rownum if given. When there are no more rows nothing is returned, in case of an error a nil followed by an error message is returned.
This function is not binary safe.
result_set:rows() → iterator
Return an iterator that produces a table with named fields for each (remaining) row in the result set.
In Lua 5.2 you can also use pairs(result_set)
.
This function is not binary safe.
result_set:tuple([rownum]) → value [, ...]
Return a tuple for the next row in the result set or the row with index rownum if given. If more than one value is returned, the return values will be in the same order as the column list in the SQL query. When there are no more rows nothing is returned, in case of an error a nil followed by an error message is returned.
This function is not binary safe.
result_set:tuples() → iterator
Return an iterator that produces a tuple for each (remaining) row in the result set. The tuples produced by the iterator are in the same order as the column list in the SQL query, for example:
> driver = assert(apr.dbd 'sqlite3')
> assert(driver:open 'quotes.sqlite3')
> results = assert(driver:select [[ SELECT author, quote FROM quotes ]])
> for author, quote in results:tuples() do
>> print(author, 'wrote:')
>> print(quote)
>> print()
>> end
This function is not binary safe.
result_set:pairs() → iterator
Return an iterator that produces a row number and a table with named fields for each (remaining) row in the result set.
In Lua 5.2 you can also use ipairs(result_set)
.
This function is not binary safe.
#result_set → num_tuples
Get the number of rows in a result set of a synchronous select. If the results are asynchronous -1 is returned.
driver:close() → status
Close a connection to a backend.
This module enables the creation and manipulation of dbm databases. If you've never heard of dbm before you can think of it as a Lua table that only supports string keys and values but is backed by a file, so that you can stop and restart your application and find the exact same contents. This module supports the following libraries/implementations:
'db'
for Berkeley DB files'gdbm'
for GDBM files'ndbm'
for NDBM files'sdbm'
for SDBM files (the default)The SDBM format is the default database format for Lua/APR because APR has built-in support for SDBM while the other libraries need to be separately installed. This is why not all types may be available at run time.
apr.dbm_open(path [, mode [, permissions [, type ]]]) → dbm object
Open a dbm file by path. On success a database object is returned, otherwise a nil followed by an error message is returned. The following mode strings are supported:
'r'
to open an existing database for reading only (this is the default)'w'
to open an existing database for reading and writing'c'
to open a database for reading and writing, creating it if it
doesn’t exist'n'
to open a database for reading and writing, truncating it if it
already existsThe permissions string is documented elsewhere. Valid values for type are listed in the introductory text for this module. Also note that the path string may not be a real file name, as many dbm packages append suffixes for separate data and index files (see also apr.dbm_getnames()).
This function is not binary safe.
apr.dbm_getnames(path [, type]) → used1 [, used2]
If the specified path were passed to apr.dbm_open(), return the actual pathnames which would be (created and) used. At most, two files may be used; used2 is nil if only one file is used. The dbm file(s) don’t need to exist because this function only manipulates the pathnames. Valid values for type are listed in the introductory text for this module.
This function is not binary safe.
dbm:exists(key) → status
Check whether the dbm record with the given string key exists.
This function is binary safe.
dbm:fetch(key) → value
Fetch the dbm record with the given string key. On success the fetched value is returned as a string, if the key doesn’t exist nothing is returned and on error a nil followed by an error message is returned.
This function is binary safe.
dbm:store(key, value) → status
Store the dbm record value (a string) by the given string key. On success true is returned, otherwise a nil followed by an error message is returned.
This function is binary safe.
dbm:delete(key) → status
Delete the dbm record with the given string key. On success true is returned, otherwise a nil followed by an error message is returned.
This function is binary safe.
dbm:firstkey() → key
Retrieve the first record key from a dbm. On success the first key is returned as a string, when there are no keys nothing is returned. In case of error a nil followed by an error message is returned.
This function is binary safe.
dbm:nextkey(key1) → key2
Retrieve the next record key from a dbm. This function works just like Lua’s next() function: On success the next key is returned as a string, when there are no more keys nothing is returned. In case of error a nil followed by an error message is returned.
This function is binary safe.
dbm:close() → status
Close a dbm database handle and return true (this can’t fail).
Operating systems organize tasks into processes. One of the simplest means of communication between processes is the use of environment variables. If you're not familiar with environment variables, picture every process on your computer having an associated Lua table with string key/value pairs. When a process creates or overwrites a key/value pair only the table of that process changes. When the process spawns a child process the child gets a copy of the table which from that point onwards is no longer associated with the parent process.
apr.env_get(name) → value
Get the value of the environment variable name. On success the string value is returned. If the variable does not exist nothing is returned. Otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.env_set(name, value) → status
Set the value of the environment variable name to the string value. On success true is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.env_delete(name) → status
Delete the environment variable name. On success true is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.filepath_root(path [, option, ...]) → root, path
Extract the root from the file path path. On success the extracted root and the relative path following the root are returned, otherwise a nil followed by an error message is returned. Either or both of the following options may be given after path:
'true-name'
verifies that the root exists and resolves its true case.
If the root does not exist, a nil followed by an error message is
returned'native'
uses the file system’s native path format (e.g. path delimiters
of :
on MacOS9, \
on Win32, etc.) in the resulting rootThese options only influence the resulting root. The path after the root is returned as is. If you want to convert a whole file path to its true case and/or native format use apr.filepath_merge() instead.
This function is not binary safe.
apr.filepath_parent(path [, option, ...]) → parent, filename
Split the file path path into its parent path and filename. This function
supports the same options as apr.filepath_root(). If any options are given
they're applied to path before it is split, so the options influence both
of the resulting values. If path is a filename and the 'true-name'
option
isn’t given then the returned parent path will be an empty string.
This function is not binary safe.
apr.filepath_name(path [, split]) → filename [, extension]
Extract the filename (the final element) from the file path path. If split evaluates true then the extension will be split from the filename and returned separately. Some examples of what is considered a filename or an extension:
> -- regular file path
> = apr.filepath_name('/usr/bin/lua', true)
'lua', ''
> -- hidden file on UNIX
> = apr.filepath_name('/home/xolox/.vimrc', true)
'.vimrc', ''
> -- multiple extensions
> = apr.filepath_name('index.html.en', true)
'index.html', '.en'
This function is not binary safe.
apr.filepath_merge(root, path [, option, ...]) → merged
Merge the file paths root and path. On success the merged file path is returned, otherwise a nil followed by an error message is returned. Any combination of one or more of the following options may be given:
'true-name'
resolves the true case of existing elements in path,
resolving any aliases on Windows, and appends a trailing slash if the
final element is a directory'native'
uses the file system’s native path format (e.g. path delimiters
of :
on MacOS9, \
on Win32, etc.)'not-above-root'
fails if path is above root, e.g. if root is
/foo/bar
and path is ../baz
'not-absolute'
fails if the merged path is absolute'not-relative'
fails if the merged path is relative'secure-root'
fails if path is above root, even given the root
/foo/bar
and the path ../bar/bash
This function can be used to generate absolute file paths as follows:
apr.filepath_merge('.', 'filepath.c', 'not-relative')
-- the above is equivalent to the below:
apr.filepath_merge(apr.filepath_get(), 'filepath.c', 'not-relative')
This function is not binary safe.
apr.filepath_list_split(searchpath) → components
Split a search path string into a table of separate components. On success the table of components is returned, otherwise a nil followed by an error message is returned. Empty elements do not become part of the returned table.
An example of a search path is the $PATH environment variable available in UNIX and Windows operating systems which controls the way program names are resolved to absolute pathnames (see apr.filepath_which()).
This function is not binary safe.
apr.filepath_list_merge(components) → searchpath
Merge a table of search path components into a single search path string. On success the table of components is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.filepath_get([native]) → path
Get the default filepath for relative filenames. If native evaluates true the file system’s native path format is used. On success the filepath is returned, otherwise a nil followed by an error message is returned.
On at least Windows and UNIX the default file path for relative file names is the current working directory. Because some operating systems supported by APR don’t use this convention Lua/APR uses the term ‘default filepath’ instead.
This function is not binary safe.
apr.filepath_set(path) → status
Set the default file path for relative file names to the string path. On success true is returned, otherwise a nil followed by an error message is returned. Also see the notes for apr.filepath_get().
This function is not binary safe.
apr.filepath_which(program [, find_all]) → pathname
Find the full pathname of program by searching the directories in the $PATH environment variable and return the pathname of the first program that’s found. If find_all is true then a list with the pathnames of all matching programs is returned instead.
apr.fnmatch(pattern, input [, ignorecase]) → status
Try to match a string against a filename pattern. When the string matches the pattern true is returned, otherwise false. The supported pattern items are the following subset of shell wild cards:
?
matches one character (any character)*
matches zero or more characters (any character)\x
escapes the special meaning of the character x
[set]
matches one character within set. A range of characters can be
specified by separating the characters of the range with a
-
character[^set]
matches the complement of set, where set is defined as aboveIf the optional argument ignorecase is true, characters are compared case-insensitively.
This function is not binary safe.
apr.fnmatch_test(pattern) → status
Determine if a file path pattern contains one or more of the wild cards that are supported by apr.fnmatch(). On success true is returned, otherwise false.
This function is not binary safe.
apr.glob(pattern [, ignorecase]) → iterator
Split pattern into a directory path and a filename pattern and return an iterator which returns all filenames in the directory that match the extracted filename pattern. The apr.fnmatch() function is used for filename matching so the documentation there applies.
This function is not binary safe.
apr.temp_dir_get() → path
Find an existing directory suitable as a temporary storage location. On success the directory file path is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.dir_make(path [, permissions]) → status
Create the directory path on the file system. On success true is returned, otherwise a nil followed by an error message is returned. See the documentation on permissions for the optional second argument.
This function is not binary safe.
apr.dir_make_recursive(path [, permissions]) → status
Create the directory path on the file system, creating intermediate directories as required. On success true is returned, otherwise a nil followed by an error message is returned. See the documentation on permissions for the optional second argument.
This function is not binary safe.
apr.dir_remove(path) → status
Remove the empty directory path from the file system. On success true is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.dir_remove_recursive(path) → status
Remove the directory path and all its contents from the file system. On success true is returned, otherwise a nil followed by an error message is returned.
Note: This function isn’t part of the Apache Portable Runtime but has been implemented on top of it by the author of the Lua/APR binding. It also hasn’t been properly tested yet.
This function is not binary safe.
apr.dir_open(path) → directory handle
Open the directory path for reading. On success a directory object is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
directory:read([property, ...]) → value, ...
Return the requested properties for the next directory entry. On success the requested properties are returned, otherwise a nil followed by an error message is returned. This function implements the same interface as apr.stat().
directory:rewind() → status
Rewind the directory handle to start from the first entry. On success true is returned, otherwise a nil followed by an error message is returned.
directory:entries([property, ...]) → iterator, directory handle
Return a function that iterates over the (remaining) directory entries and returns the requested properties for each entry. If you don’t request any properties, a table with the available properties will be returned for each directory entry:
> directory = apr.dir_open 'examples'
> for info in directory:entries() do print(info) end
{
type = 'file', name = 'webserver.lua',
user = 'peter', group = 'peter', protection = 'rw-r--r--',
size = 2789, csize = 4096, inode = 12455648, dev = 64514, nlink = 1,
path = '/home/peter/Development/Lua/APR/examples/webserver.lua',
mtime = 1293753884.3382, atime = 1293994993.3855, ctime = 1293753884.3382,
}
{
type = 'file', name = 'download.lua',
user = 'peter' group = 'peter', protection = 'rw-r--r--',
size = 2580, csize = 4096, inode = 12455598, dev = 64514, nlink = 1,
path = '/home/peter/Development/Lua/APR/examples/download.lua',
mtime = 1293753884.3382, atime = 1293994993.3855, ctime = 1293753884.3382,
}
This function implements the same interface as apr.stat() with one exception: If you pass property names to directory:entries() that are not available they will be returned as false instead of nil because of a technical limitation in the Lua iterator protocol:
“On each iteration, the iterator function is called to produce a new value, stopping when this new value is nil.”
directory:close() → status
Close the directory handle. On success true is returned, otherwise a nil followed by an error message is returned.
apr.file_link(source, target) → status
Create a hard link to the specified file. On success true is returned, otherwise a nil followed by an error message is returned. Both files must reside on the same device.
Please note that this function will only be available when the Lua/APR binding is compiled against APR 1.4 or newer because the apr_file_link() function wasn’t available in earlier releases.
This function is not binary safe.
apr.file_copy(source, target [, permissions]) → status
Copy the file source to target. On success true is returned, otherwise a nil followed by an error message is returned. The permissions argument is documented elsewhere. The new file does not need to exist, it will be created if required. If the new file already exists, its contents will be overwritten.
This function is not binary safe.
apr.file_append(source, target [, permissions]) → status
Append the file source to target. On success true is returned, otherwise a nil followed by an error message is returned. The permissions argument is documented elsewhere. The new file does not need to exist, it will be created if required.
This function is not binary safe.
apr.file_rename(source, target) → status
Rename the file source to target. On success true is returned, otherwise a nil followed by an error message is returned. If a file exists at the new location, then it will be overwritten. Moving files or directories across devices may not be possible.
This function is not binary safe.
apr.file_remove(path) → status
Delete the file pointed to by path. On success true is returned, otherwise a nil followed by an error message is returned. If the file is open, it won’t be removed until all instances of the file are closed.
This function is not binary safe.
apr.file_mtime_set(path, mtime) → status
Set the last modified time of the file pointed to by path to mtime. On success true is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.file_attrs_set(path, attributes) → status
Set the attributes of the file pointed to by path. On success true is returned, otherwise a nil followed by an error message is returned.
The table attributes should consist of string keys and boolean values. The
supported attributes are readonly
, hidden
and executable
.
This function should be used in preference to explicit manipulation of the file permissions, because the operations to provide these attributes are platform specific and may involve more than simply setting permission bits.
This function is not binary safe.
apr.file_perms_set(path, permissions) → status
Set the permissions of the file specified by path. On success true is returned, otherwise a nil followed by an error message is returned.
Warning: Some platforms may not be able to apply all of the available
permission bits, in this case a third value 'INCOMPLETE'
is returned (see
error handling).
This function is not binary safe.
apr.stat(path [, property, ...]) → value, ...
Get the status of the file pointed to by path. On success, if no properties are given a table of property name/value pairs is returned, otherwise the named properties are returned in the same order as the arguments. On failure a nil followed by an error message is returned.
The following fields are supported:
name
is a string containing the name of the file in proper casepath
is a string containing the absolute pathname of the filetype
is one of the strings 'directory'
, 'file'
, 'link'
, 'pipe'
,
'socket'
, 'block device'
, 'character device'
or 'unknown'
user
is a string containing the name of user that owns the filegroup
is a string containing the name of the group that owns the filesize
is a number containing the size of the file in bytescsize
is a number containing the storage size consumed by the filectime
is the time the file was created, or the inode was last changedatime
is the time the file was last accessedmtime
is the time the file was last modifiednlink
is the number of hard links to the fileinode
is a unique number within the file system on which the file
residesdev
is a number identifying the device on which the file is storedprotection
is a 9 character string with the file system permissionslink
is a special flag that does not return a field, instead it is
used to signal that symbolic links should not be followed, i.e. the
status of the link itself should be returnedHere are some examples:
> -- Here's an example of a table with all properties:
> = apr.stat('lua-5.1.4.tar.gz')
{
name = 'lua-5.1.4.tar.gz',
path = 'lua-5.1.4.tar.gz',
type = 'file',
user = 'peter',
group = 'peter',
size = 216679,
csize = 217088,
ctime = 1284159662.7264,
atime = 1287954158.6019,
mtime = 1279317348.194,
nlink = 1,
inode = 1838576,
dev = 64514,
protection = 'rw-r--r--',
}
> -- To check whether a directory exists:
> function isdir(p) return apr.stat(p, 'type') == 'directory' end
> = isdir('.')
true
> -- To get a file's size in bytes:
> function filesize(p) return apr.stat(p, 'size') end
> = filesize('lua-5.1.4.tar.gz')
216679
This function is not binary safe.
apr.file_open(path [, mode [, permissions]]) → file
This function imitates Lua’s io.open() function with one exception: On UNIX you can pass a file descriptor (number) instead of a path string (see also file:fd_get()). Now follows the documentation for io.open():
This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message. The mode string can be any of the following:
'r'
: read mode (the default)'w'
: write mode'a'
: append mode'r+'
: update mode, all previous data is preserved'w+'
: update mode, all previous data is erased'a+'
: append update mode, previous data is preserved, writing is only
allowed at the end of fileThe mode string may also have a b
at the end, which is needed in some
systems to open the file in binary mode. This string is exactly what is used
in the standard C function fopen(). The permissions argument is
documented elsewhere.
This function is not binary safe.
file:stat([field, ...]) → value, ...
This method works like apr.stat() except that it uses a file handle instead of a filepath to access the file.
file:lines() → iterator
This function implements the interface of the file:lines() function described in the Lua 5.1 reference manual. Here is the description from the reference manual:
Return an iterator function that, each time it is called, returns a new line read from the file. Therefore, the construction
for line in file:lines() do body end
will iterate over all lines. This function does not close the file when the loop ends.
file:read([format, ...]) → mixed value, ...
This function implements the interface of the file:read() function described in the Lua 5.1 reference manual. Here is the description from the reference manual:
Read from file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below).
The available formats are:
'*n'
: reads a number; this is the only format that returns a number instead of a string'*a'
: reads all data from the file, starting at the current position. On end of input, it returns the empty string'*l'
: reads the next line (skipping the end of line), returning nil on end of input (this is the default format)number
: reads a string with up to this number of characters, returning nil on end of input. If number is zero, it reads nothing and returns an empty string, or nil on end of inputfile:write(value [, ...]) → status
This function implements the interface of the file:write() function described in the Lua 5.1 reference manual. Here is the description from the reference manual:
Write the value of each argument to file. The arguments must be strings or numbers. To write other values, use tostring() or string.format() before this function.
file:seek([whence [, offset]]) → offset
This function implements the interface of the file:seek() function described in the Lua 5.1 reference manual. Here is the description from the reference manual:
Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence, as follows:
'set'
: base is position 0 (beginning of the file)'cur'
: base is current position'end'
: base is end of fileIn case of success, function seek
returns the final file position, measured
in bytes from the beginning of the file. If this function fails, it returns
nil, plus a string describing the error.
The default value for whence is 'cur'
, and for offset is 0. Therefore, the
call file:seek() returns the current file position, without changing it; the
call file:seek('set')
sets the position to the beginning of the file (and
returns 0); and the call file:seek('end')
sets the position to the end of the
file, and returns its size.
file:flush() → status
Saves any written data to file. On success true is returned, otherwise a nil followed by an error message is returned.
file:lock(type [, nonblocking ]) → status
Establish a lock on the open file file. On success true is returned, otherwise a nil followed by an error message is returned. The type must be one of:
'shared'
: Shared lock. More than one process or thread can hold a
shared lock at any given time. Essentially, this is a “read lock”,
preventing writers from establishing an exclusive lock'exclusive'
: Exclusive lock. Only one process may hold an exclusive
lock at any given time. This is analogous to a “write lock”If nonblocking is true the call will not block while acquiring the file lock.
The lock may be advisory or mandatory, at the discretion of the platform. The lock applies to the file as a whole, rather than a specific range. Locks are established on a per-thread/process basis; a second lock by the same thread will not block.
file:unlock() → status
Remove any outstanding locks on the file. On success true is returned, otherwise a nil followed by an error message is returned.
pipe:timeout_get() → timeout
Get the timeout value or blocking state of pipe. On success the timeout value is returned, otherwise a nil followed by an error message is returned.
The timeout true means wait forever, false means don’t wait at all and a number is the microseconds to wait.
pipe:timeout_set(timeout) → status
Set the timeout value or blocking state of pipe. On success true is returned, otherwise a nil followed by an error message is returned.
The timeout true means wait forever, false means don’t wait at all and a number is the microseconds to wait. For example:
-- Configure read end of pipe to block for a maximum of 5 seconds.
pipe:timeout_set(1000000 * 5)
for line in pipe:lines() do
print(line)
end
file:fd_get() → fd
Get the underlying file descriptor for this file. On success a number is returned, otherwise a nil followed by an error message is returned.
To convert a file descriptor into a Lua/APR file object you can pass the file descriptor (number) to apr.file_open() instead of the pathname.
Note that this function is only available on platforms where file descriptors are numbers (this includes UNIX and excludes Windows).
file:inherit_set() → status
Set a file to be inherited by child processes. By default, file descriptors will not be inherited by child processes created by apr.proc_create().
At the time of writing this seems to only apply to UNIX where APR will close all open file handles after performing a fork() unless you explicitly set your files to be inheritable.
file:inherit_unset() → status
Unset a file from being inherited by child processes.
file:close() → status
Close file. On success true is returned, otherwise a nil followed by an error message is returned.
apr.socket_create([protocol [, family]]) → socket
Create a network socket. On success the new socket object is returned, otherwise a nil followed by an error message is returned. Valid values for the protocol argument are:
These are the valid values for the family argument:
'inet'
to create a socket using the IPv4 address family (this
is the default)'inet6'
to create a socket using the IPv6 address family'unspec'
to pick the system default typeNote that 'inet6'
is only supported when apr.socket_supports_ipv6
is
true.
apr.hostname_get() → name
Get the name of the current machine. On success the host name string is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.host_to_addr(hostname [, family]) → ip_address
Resolve a host name to an IP-address. On success the IP-address is returned as a string, otherwise a nil followed by an error message is returned. The optional family argument is documented under apr.socket_create().
> = apr.host_to_addr 'www.lua.org'
'89.238.129.35'
This function is not binary safe.
apr.addr_to_host(ip_address [, family]) → hostname
Look up the host name from an IP-address (also known as a reverse DNS lookup). On success the host name is returned as a string, otherwise a nil followed by an error message is returned. The optional family argument is documented under apr.socket_create().
> = apr.addr_to_host '89.238.129.35'
'flounder.pepperfish.net'
This function is not binary safe.
socket:connect(host, port) → status
Issue a connection request to a socket either on the same machine or a different one, as indicated by the host string and port number. On success true is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
socket:bind(host, port) → status
Bind the socket to the given host string and port number. On success true
is returned, otherwise a nil followed by an error message is returned. The
special host value '*'
can be used to select the default ‘any’ address.
For example if you want to create a web server you can start with the
following:
-- Basic single threaded server
server = assert(apr.socket_create())
assert(server:bind('*', 80))
assert(server:listen(10))
while true do
local client = assert(server:accept())
-- Here you can receive data from the client by calling client:read()
-- and send data to the client by calling client:write()
end
This function can fail if you try to bind a port below 1000 without superuser privileges or if another process is already bound to the given port number.
This function is not binary safe.
socket:listen(backlog) → status
To listen for incoming network connections three steps must be performed:
On success true is returned, otherwise a nil followed by an error message is
returned. The backlog argument indicates the number of outstanding
connections allowed in the socket’s listen queue. If this value is less than
zero, the listen queue size is set to zero. As a special case, if you pass
the string 'max'
as backlog then a platform specific maximum value is
chosen based on the compile time constant SOMAXCONN.
socket:accept() → client_socket
Accept a connection request on a server socket. On success a socket is returned which forms the connection to the client, otherwise a nil followed by an error message is returned. This function blocks until a client connects.
socket:read([format, ...]) → mixed value, ...
This function implements the interface of the file:read() function described in the Lua 5.1 reference manual. Here is the description from the reference manual:
Read from socket, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below).
The available formats are:
'*n'
: reads a number; this is the only format that returns a number instead of a string'*a'
: reads all data from the socket, starting at the current position. On end of input, it returns the empty string'*l'
: reads the next line (skipping the end of line), returning nil on end of input (this is the default format)number
: reads a string with up to this number of characters, returning nil on end of input. If number is zero, it reads nothing and returns an empty string, or nil on end of inputsocket:write(value [, ...]) → status
This function implements the interface of the file:write() function described in the Lua 5.1 reference manual. Here is the description from the reference manual:
Write the value of each argument to socket. The arguments must be strings or numbers. To write other values, use tostring() or string.format() before this function.
socket:lines() → iterator
This function implements the interface of the file:lines() function described in the Lua 5.1 reference manual. Here is the description from the reference manual:
Return an iterator function that, each time it is called, returns a new line read from the socket. Therefore, the construction
for line in socket:lines() do body end
will iterate over all lines. This function does not close the socket when the loop ends.
socket:timeout_get() → timeout
Get the timeout value or blocking state of socket. On success the timeout value is returned, otherwise a nil followed by an error message is returned.
The timeout true means wait forever, false means don’t wait at all and a number is the microseconds to wait.
socket:timeout_set(timeout) → status
Set the timeout value or blocking state of socket. On success true is returned, otherwise a nil followed by an error message is returned.
The timeout true means wait forever, false means don’t wait at all and a number is the microseconds to wait.
socket:opt_get(name) → value
Query socket options for the specified socket. Valid values for name are:
'debug'
: turn on debugging information'keep-alive'
: keep connections active'linger'
: lingers on close if data is present'non-block'
: turns blocking on/off for socket'reuse-addr'
: the rules used in validating addresses supplied to bind
should allow reuse of local addresses'sndbuf'
: set the send buffer size'rcvbuf'
: set the receive buffer size'disconnected'
: query the disconnected state of the socket (currently only used on Windows)The 'sndbuf'
and 'rcvbuf'
options have integer values, all other options
have a boolean value.
socket:opt_set(name, value) → status
Setup socket options for the specified socket. Valid values for name are documented under socket:opt_get(), value should be a boolean or integer value. On success true is returned, otherwise a nil followed by an error message is returned.
socket:addr_get([type]) → ip_address, port [, hostname]
Get one of the IP-address / port pairs associated with socket, according to type:
'local'
to get the address/port to which the socket is bound locally'remote'
to get the address/port of the peer to which the socket is
connected (this is the default)On success the local or remote IP-address (a string) and the port (a number) are returned, otherwise a nil followed by an error message is returned. If a host name is available that will be returned as the third value.
This function is not binary safe.
socket:fd_get() → fd
Get the underlying file descriptor for this socket. On success a number is returned, otherwise a nil followed by an error message is returned.
socket:fd_set(fd) → status
Set the underlying file descriptor (a number) of an existing socket. On success true is returned, otherwise a nil followed by an error message is returned.
socket:shutdown(mode) → status
Shutdown either reading, writing, or both sides of a socket. On success true is returned, otherwise a nil followed by an error message is returned. Valid values for mode are:
'read'
: no longer allow read requests'write'
: no longer allow write requests'both'
: no longer allow read or write requestsThis does not actually close the socket descriptor, it just controls which calls are still valid on the socket. To close sockets see socket:close().
socket:close() → status
Close socket. On success true is returned, otherwise a nil followed by an error message is returned.
Lua/APR represents pipes as files just like Lua’s standard library function io.popen() does because it works fairly well, however there are some differences between files and pipes which impact the API:
File objects implement pipe:timeout_get() and pipe:timeout_set() even though these methods only make sense for pipe objects
Pipe objects implement file:seek() but don’t support it
One of the reasons that file/pipe support is so interwoven in APR and thus Lua/APR is that you can create a named pipe with apr.namedpipe_create() and access it using apr.file_open() and APR won’t know or even care that you're reading/writing a pipe instead of a file.
apr.pipe_open_stdin() → pipe
Open standard input as a pipe. On success the pipe is returned, otherwise a nil followed by an error message is returned.
apr.pipe_open_stdout() → pipe
Open standard output as a pipe. On success the pipe is returned, otherwise a nil followed by an error message is returned.
apr.pipe_open_stderr() → pipe
Open standard error as a pipe. On success the pipe is returned, otherwise a nil followed by an error message is returned.
apr.namedpipe_create(name [, permissions]) → status
Create a named pipe. On success true is returned, otherwise a nil followed by an error message is returned. The permissions argument is documented elsewhere.
Named pipes can be used for interprocess communication:
Note that APR supports named pipes on UNIX but not on Windows. If you try anyhow the error message “This function has not been implemented on this platform” is returned.
This function is not binary safe.
apr.pipe_create() → input, output
Create an anonymous pipe. On success the write and read ends of the pipe are returned, otherwise a nil followed by an error message is returned. There’s an example use of this function in the documentation for process:in_set().
Memcached is a “distributed memory object caching system”. It’s designed as an in-memory key-value store for small chunks of arbitrary data (strings, objects) from results of database calls, API calls, or page rendering. The memcached client module makes it possible to read from and write to one or more memcached servers over a network socket in Lua.
To-do: Find out if “flags” can be any 32 bits value and how useful it is to Lua.
apr.memcache([max_servers]) → mc_client
Create a memcached client. The optional argument max_servers determines the maximum number of memcached servers supported by the client (defaults to 10). On success the client object is returned, otherwise nil followed by an error message is returned.
mc_client:hash(str) → hash
Create a CRC32 hash used to split keys between servers. The hash is not compatible with old memcached clients.
This function is binary safe.
mc_client:find_server_hash(hash) → mc_server
Picks a server based on a hash. Returns the info of the server that controls the specified hash.
mc_client:add_server(host, port [, min [, smax [, max [, ttl]]]]) → mc_server
Create a new server object and add it to the client object. On success the server object is returned, otherwise a nil followed by an error message is returned. The parameters have the following meaning:
Note that min, smax and max are only used when APR was compiled with threads. Also a word of caution: Changing servers after startup may cause keys to go to different servers.
mc_client:find_server(host, port) → mc_server
Finds a server object based on a (hostname, port) pair. On success the server with matching host name and port is returned, otherwise nothing is returned.
mc_client:enable_server(mc_server) → status
Enable a server for use again after disabling the server with mc_client:disable_server(). On success true is returned, otherwise nil followed by an error message is returned.
mc_client:disable_server(mc_server) → status
Disable a server. On success true is returned, otherwise nil followed by an error message is returned.
mc_client:get(key [, ...]) → status, value [, ...]
Get one or more values from the server. On success true is returned followed by the retrieved value(s), otherwise nil followed by an error message is returned. The keys are null terminated strings and the return values are binary safe strings. Keys that don’t have an associated value result in nil.
mc_client:set(key, value [, timeout]) → status
Sets a value by key on the server. If the key already exists the old value will be overwritten. The key is a null terminated string, the value is a binary safe string and timeout is the time in seconds for the data to live on the server (a number, defaults to 60 seconds). On success true is returned, otherwise nil followed by an error message is returned.
mc_client:add(key, value [, timeout]) → status
Adds a value by key on the server. If the key already exists this call will fail and the old value will be preserved. The arguments and return values are documented under mc_client:set().
mc_client:replace(key, value [, timeout]) → status
Replace a value by key on the server. If the key doesn’t exist no value will be set. The arguments and return values are documented under mc_client:set().
mc_client:delete(key [, timeout]) → status
Delete a key from the server. The key is a null terminated string and timeout is the time in seconds for the delete to stop other clients from adding (a number, defaults to 10 seconds). On success true is returned, otherwise nil followed by an error message is returned.
mc_client:incr(key [, number]) → value
Increment a value. The key is a null terminated string and the optional argument number is the number to increment by (defaults to 1). On success the new value after incrementing is returned, otherwise nil followed by an error message is returned.
mc_client:decr(key [, number]) → value
Decrement a value. The key is a null terminated string and the optional argument number is the number to decrement by (defaults to 1). On success the new value after decrementing is returned, otherwise nil followed by an error message is returned.
mc_client:version(mc_server) → version
Query a server’s version. On success the version string is returned, otherwise nil followed by an error message is returned.
mc_client:stats() → statistics
Query a server for statistics. On success a table with information is returned, otherwise nil followed by an error message is returned. The following fields are supported:
apr.getopt(usage [, config ]) → options, arguments
Parse the command line arguments according to the option letters and/or long options defined in the string usage (see the example below) and return a table with the matched options and a table with any remaining positional arguments. When an option is matched multiple times, the resulting value in options depends on the following context:
If the option doesn’t take an argument, the value will be a number indicating the number of times that the option was matched
If the option takes an argument and only one option/argument pair is matched, the value will be the argument (a string). When more than one pair is matched for the same option letter/name, the values will be collected in a table
The optional config table can be used to change the following defaults:
When usage mentions -h
or --help
and either of these options is
matched in the arguments, apr.getopt() will print the usage message
and call os.exit(). To avoid this set config.show_usage
to false
(not nil!)
When an error is encountered during argument parsing, apr.getopt() will
print a warning about the invalid argument and call os.exit(). To avoid
this set config.handle_errors
to false (not nil!)
By default the arguments in the global variable arg will
be used, but you can set config.args
to a table of arguments to be
used instead
Here is a short example of a valid Lua script that doesn’t really do anything useful but demonstrates the use of apr.getopt():
apr = require 'apr'
opts, args = apr.getopt [[
Usage: echo.lua [OPTIONS] ARG...
-h, --help show this message and exit
-v, --verbose make more noise
--version print version and exit
]]
if opts.version then
print "This is version 0.1"
else
if opts.verbose then
print("Got", #args, "arguments")
end
if opts.verbose >= 2 then
print "Here they are:"
end
for i = 1, #args do print(args[i]) end
end
The apr.getopt() function is very similar to Lapp by Steve Donovan although Lapp is more full featured, for example it validates and converts argument types.
This module is an experimental binding to the apreq2 library which enables HTTP request parsing of query strings, headers and multipart messages. Some general notes about the functions in this module:
None of the extracted strings (except maybe for request bodies) are binary safe because (AFAIK) HTTP headers are not binary safe
Parsed name/value pairs are converted to a Lua table using two rules: names without a value get the value true and duplicate names result in a table that collects all values for the given name
When a parse error is encountered after successfully parsing part of the input, the results of the function are followed by an error message and error code (see below)
The functions in this module return three values on error: a nil followed by an error message and an error code. This module defines the following error codes (in addition to the generic Lua/APR error codes):
'EBADARG'
: bad arguments'GENERAL'
: internal apreq2 error'TAINTED'
: attempted to perform unsafe action with tainted data'INTERRUPT'
: parsing interrupted'BADDATA'
: invalid input data'BADCHAR'
: invalid character'BADSEQ'
: invalid byte sequence'BADATTR'
: invalid attribute'BADHEADER'
: invalid header'BADUTF8'
: invalid UTF-8 encoding'NODATA'
: missing input data'NOTOKEN'
: missing required token'NOATTR'
: missing attribute'NOHEADER'
: missing header'NOPARSER'
: missing parser'MISMATCH'
: conflicting information'OVERLIMIT'
: exceeds configured maximum limit'UNDERLIMIT'
: below configured minimum limit'NOTEMPTY'
: setting already configuredapr.parse_headers(request) → headers, body
Parse the headers in a HTTP request string according to RFC 822. On success a table of header name/value pairs and the request body string are returned, otherwise nil followed by an error message is returned.
There are some gotchas in using this function:
It will fail if anything comes before the headers, so be sure to strip the status line from the request string before calling this function
If the request string doesn’t contain an empty line to separate the headers from the body, the last header might be silently discarded
apr.parse_multipart(request, enctype [, limit [, tempdir]]) → parts
Parse a multipart/form-data or multipart/related HTTP request body according to RFC 2388 and the boundary string in enctype. On success the table with parameter name/value pairs is returned, otherwise a nil followed by an error message is returned.
The optional number limit gives the maximum in-memory bytes that the data structure used to parse the request may use (it defaults to 1024 KB), but be aware that because of internal copying apr.parse_multipart() can use more than double this amount of memory while parsing a request.
The optional string tempdir is the directory used for temporary storage of large uploads.
apr.parse_cookie_header(header) → cookies
Parse a cookie header and store the cookies in a Lua table. On success the table with cookie name/value pairs is returned, otherwise nil followed by an error message and error code is returned.
apr.parse_query_string(query_string) → parameters
Parse a URL encoded string into a Lua table. On success the table with parameter name/value pairs is returned, otherwise nil followed by an error message and error code is returned.
This function uses &
and ;
as the set of tokens to delineate words, and
will treat a word without =
as a name/value pair with the value true.
apr.header_attribute(header, name) → value
Search a header string for the value of a particular named attribute. On success the matched value is returned, otherwise nil followed by an error message is returned.
This function is not binary safe.
apr.uri_encode(string) → encoded
Encode unsafe bytes in string using percent-encoding so that the string can be embedded in a URI query string.
This function is not binary safe.
apr.uri_decode(encoded) → string
Decode all percent-encoded bytes in the string encoded.
This function is binary safe.
apr.proc_create(program) → process
Create a child process that will execute the given program when started. Once you've called this function you still need to execute the process using the process:exec() function. Here’s a simple example that emulates Lua’s os.execute() function:
function execute(command)
local arguments = apr.tokenize_to_argv(command)
local progname = table.remove(arguments, 1)
local process = apr.proc_create(progname)
process:cmdtype_set('shellcmd/env')
process:exec(arguments)
local done, code, why = process:wait(true)
return code
end
execute 'echo This can be any process...'
This function is not binary safe.
apr.proc_detach(daemonize) → status
Detach the current process from the controlling terminal. If daemonize evaluates to true the process will daemonize and become a background process, otherwise it will stay in the foreground. On success true is returned, otherwise a nil followed by an error message is returned.
apr.proc_fork() → process, context
This is currently the only non-portable function in APR and by extension
Lua/APR. It performs a standard UNIX fork. If the fork succeeds a
process object and context string ('parent'
or 'child'
) are returned,
otherwise a nil followed by an error message is returned. The parent process
can use the returned process object to wait for the child process to die:
if apr.proc_fork then -- forking supported?
process, context = assert(apr.proc_fork())
if context == 'parent' then
print "Parent waiting for child.."
process:wait(true)
print "Parent is done!"
else -- context == 'child'
print "Child simulating activity.."
apr.sleep(10)
print "Child is done!"
end
end
As the above example implies the apr.proc_fork() function will only be defined when forking is supported on the current platform.
process:addrspace_set(separate) → status
If separate evaluates to true the child process will start in its own address space, otherwise the child process executes in the current address space from its parent. On success true is returned, otherwise a nil followed by an error message is returned. The default is no on NetWare and yes on other platforms.
process:user_set(username [, password]) → status
Set the user under which the child process will run. On success true is returned, otherwise a nil followed by an error message is returned.
On Windows and other platforms where apr.user_set_requires_password
is
true this method requires a password.
This function is not binary safe.
process:group_set(groupname) → status
Set the group under which the child process will run. On success true is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
process:cmdtype_set(type) → status
Set what type of command the child process will execute. On success true is returned, otherwise a nil followed by an error message is returned. The argument type must be one of:
'shellcmd'
: Use the shell to invoke the program'shellcmd/env'
: Use the shell to invoke the program, replicating our environment'program'
: Invoke the program directly, without copying the environment'program/env'
: Invoke the program directly, replicating our environment'program/env/path'
: Find program in $PATH
, replicating our environmentprocess:env_set(environment) → status
Set the environment variables of the child process to the key/value pairs in the table environment. On success true is returned, otherwise a nil followed by an error message is returned.
Please note that the environment table is ignored for the command types
'shellcmd/env'
, 'program/env'
and 'program/env/path'
(set using the
process:cmdtype_set() method).
This function is not binary safe.
process:dir_set(path) → status
Set which directory the child process should start executing in. On success true is returned, otherwise a nil followed by an error message is returned.
By default child processes inherit this directory from their parent process at the moment when the process:exec() call is made. To find out the current directory see the apr.filepath_get() function.
This function is not binary safe.
process:detach_set(detach) → status
Determine if the child should start in detached state. On success true is returned, otherwise a nil followed by an error message is returned. Default is no.
process:error_check_set(enabled) → nothing
Specify that process:exec() should do whatever it can to report failures directly, rather than find out in the child that something is wrong. This leads to extra overhead in the calling process, but it may help you handle these errors more gracefully.
Note that this option is only useful on platforms where fork() is used.
process:io_set(stdin, stdout, stderr) → status
Determine if the child process should be linked to its parent through one or more pipes. On success true is returned, otherwise a nil followed by an error message is returned.
Each argument gives the blocking mode of a pipe, which can be one of the following strings:
'none'
: Don’t create a pipe'full-block'
: Create a pipe that blocks until the child process writes to the pipe or dies'full-nonblock'
: Create a pipe that doesn’t block'parent-block'
: Create a pipe that only blocks on the parent’s end'child-block'
: Create a pipe that only blocks on the child’s endOnce the child process has been started with process:exec(), the pipes can be accessed with the methods process:in_get(), process:out_get() and process:err_get().
Here’s an example that executes the external command tr a-z A-Z
to
translate some characters to uppercase:
> p = apr.proc_create 'tr'
> p:cmdtype_set('shellcmd/env')
> p:io_set('child-block', 'parent-block', 'none')
> p:exec{'a-z', 'A-Z'}
> input = p:in_get()
> output = p:out_get()
> input:write('Testing, 1, 2, 3\n')
> input:close()
> print(output:read())
TESTING, 1, 2, 3
> output:close()
> p:wait(true)
process:in_set(child_in [, parent_in]) → status
Initialize the standard input pipe of the child process to an existing pipe or a pair of pipes. This can be useful if you have already opened a pipe (or multiple files) that you wish to use, perhaps persistently across multiple process invocations – such as a log file. On success true is returned, otherwise a nil followed by an error message is returned. Here’s a basic example that connects two processes using an anonymous pipe:
-- Create a gzip process to decompress the Lua source code archive.
gzip = apr.proc_create 'gunzip'
gzip:cmdtype_set 'shellcmd/env'
gzip:in_set(apr.file_open('lua-5.1.4.tar.gz', 'rb'))
-- Create a tar process to list the files in the decompressed archive.
tar = apr.proc_create 'tar'
tar:cmdtype_set 'shellcmd/env'
tar:out_set(apr.pipe_open_stdout())
-- Connect the two processes using an anonymous pipe.
input, output = assert(apr.pipe_create())
gzip:out_set(output)
tar:in_set(input)
-- Start the pipeline by executing both processes.
gzip:exec()
tar:exec{'-t'}
process:out_set(child_out [, parent_out]) → status
Initialize the standard output pipe of the child process to an existing pipe or a pair of pipes. This can be useful if you have already opened a pipe (or multiple files) that you wish to use, perhaps persistently across multiple process invocations – such as a log file. On success true is returned, otherwise a nil followed by an error message is returned.
process:err_set(child_err [, parent_err]) → status
Initialize the standard error pipe of the child process to an existing pipe or a pair of pipes. This can be useful if you have already opened a pipe (or multiple files) that you wish to use, perhaps persistently across multiple process invocations – such as a log file. On success true is returned, otherwise a nil followed by an error message is returned.
process:in_get() → pipe
Get the parent end of the standard input pipe (a writable pipe).
process:out_get() → pipe
Get the parent end of the standard output pipe (a readable pipe).
process:err_get() → pipe
Get the parent end of the standard error pipe (a readable pipe).
process:exec([args]) → status
Create the child process and execute a program or shell command inside it.
On success true is returned, otherwise a nil followed by an error message is
returned. If the args array is given the contained strings become the
command line arguments to the child process. The program name
for the child process defaults to the name passed into apr.proc_create(),
but you can change it by setting args[0]
.
This function is not binary safe.
process:wait(how) → done [, why, code]
Wait for the child process to die. If how is true the call blocks until the process dies, otherwise the call returns immediately regardless of if the process is dead or not. The first return value is false if the process isn’t dead yet. If it’s true the process died and two more return values are available. The second return value is the reason the process died, which is one of:
'exit'
: Process exited normally'signal'
: Process exited due to a signal'signal/core'
: Process exited and dumped a core fileThe third return value is the exit code of the process. If an error occurs a nil followed by an error message is returned.
process:kill(how) → status
Terminate a running child process. On success true is returned, otherwise a nil followed by an error message is returned. The parameter how must be one of:
'never'
: The process is never sent any signals'always'
: The process is sent the SIGKILL signal when its
Lua userdata is garbage collected'timeout'
: Send the SIGTERM signal, wait for 3 seconds,
then send the SIGKILL signal'wait'
: Wait forever for the process to complete'once'
: Send the SIGTERM signal and then waitShared memory is memory that may be simultaneously accessed by multiple programs with an intent to provide communication among them. The Lua/APR binding represents shared memory as file objects through the shm:read(), shm:write() and shm:seek() methods.
apr.shm_create(filename, size) → shm object
Create and make accessible a shared memory segment. The filename argument is the file to use for shared memory on platforms that require it. The size argument is the desired size of the segment.
A note about anonymous vs. named shared memory segments: Not all platforms
support anonymous shared memory segments, but in some cases it is preferred
over other types of shared memory implementations. Passing a nil filename
parameter to this function will cause the subsystem to use anonymous shared
memory segments. If such a system is not available, the error 'ENOTIMPL'
is returned as the third return value (the first and second being nil and an
error message string).
This function is not binary safe.
apr.shm_attach(filename) → shm object
Attach to a shared memory segment that was created by another process. The filename argument is the file used to create the original segment (this must match the original filename). On success a shared memory object is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.shm_remove(filename) → status
Remove the named resource associated with a shared memory segment, preventing attachments to the resource, but not destroying it. On success true is returned, otherwise a nil followed by an error message is returned.
This function is only supported on platforms which support name-based shared
memory segments, and will return the error code 'ENOTIMPL'
on platforms
without such support. Removing the file while the shared memory is in use is
not entirely portable, caller may use this to enhance obscurity of the
resource, but be prepared for the the call to fail, and for concurrent
attempts to create a resource of the same name to also fail.
Note that the named resource is also removed when a shared memory object created by apr.shm_create() is garbage collected.
This function is not binary safe.
shm:read([format, ...]) → mixed value, ...
This function implements the interface of the file:read() function described in the Lua 5.1 reference manual. Here is the description from the reference manual:
Read from shared memory, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below).
The available formats are:
'*n'
: reads a number; this is the only format that returns a number instead of a string'*a'
: reads all data from the shared memory, starting at the current position. On end of input, it returns the empty string'*l'
: reads the next line (skipping the end of line), returning nil on end of input (this is the default format)number
: reads a string with up to this number of characters, returning nil on end of input. If number is zero, it reads nothing and returns an empty string, or nil on end of inputshm:write(value [, ...]) → status
This function implements the interface of the file:write() function described in the Lua 5.1 reference manual. Here is the description from the reference manual:
Write the value of each argument to shared memory. The arguments must be strings or numbers. To write other values, use tostring() or string.format() before this function.
shm:seek([whence [, offset]]) → offset
This function implements the interface of the file:seek() function described in the Lua 5.1 reference manual. Here is the description from the reference manual:
Sets and gets the shared memory position, measured from the beginning of the shared memory, to the position given by offset plus a base specified by the string whence, as follows:
'set'
: base is position 0 (beginning of the shared memory)'cur'
: base is current position'end'
: base is end of shared memoryIn case of success, function seek
returns the final shared memory position, measured
in bytes from the beginning of the shared memory. If this function fails, it returns
nil, plus a string describing the error.
The default value for whence is 'cur'
, and for offset is 0. Therefore, the
call shm:seek() returns the current shared memory position, without changing it; the
call shm:seek('set')
sets the position to the beginning of the shared memory (and
returns 0); and the call shm:seek('end')
sets the position to the end of the
shared memory, and returns its size.
shm:detach() → status
Detach from a shared memory segment without destroying it. On success true is returned, otherwise a nil followed by an error message is returned.
shm:destroy() → status
Destroy a shared memory segment and associated memory. On success true is returned, otherwise a nil followed by an error message is returned. Note that this will be done automatically when the shared memory object is garbage collected and has not already been destroyed.
Signals provide a limited form of inter-process communication. On UNIX they are for example used to communicate to daemons that they should reload their configuration or stop gracefully. This module works on Linux and most if not all UNIX systems but it’s not very useful on Windows, because Windows has poor support for signals:
SIGINT
is not supported for any Win32 application, including Windows 98/Me and Windows NT/2000/XP. When a CTRL+C interrupt occurs, Win32 operating systems generate a new thread to specifically handle that interrupt. This can cause a single-thread application such as UNIX, to become multithreaded, resulting in unexpected behavior.
…
TheSIGILL
,SIGSEGV
, andSIGTERM
signals are not generated under Windows NT. They are included for ANSI compatibility. Thus you can set signal handlers for these signals with signal(), and you can also explicitly generate these signals by calling raise().
The following signal related functionality is not exposed by the Lua/APR binding because the Apache Portable Runtime doesn’t wrap the required functions:
APR doesn’t expose kill() except through process:kill() which
only supports two signals (SIGTERM
and SIGKILL
) which means users of
the Lua/APR binding cannot send arbitrary signals to processes (use
luaposix instead)
APR doesn’t expose alarm() and Windows doesn’t support it which
means the SIGALRM
signal is useless (use lalarm instead)
apr.signal(name [, handler]) → status
Set the signal handler function for a given signal. The argument name must be a string with the name of the signal to handle (apr.signal_names() returns a table of available names on your platform). The argument handler must be of type function, unless it is nil in which case default handling is restored for the given signal. On success true is returned, otherwise a nil followed by an error message is returned.
apr.signal_raise(name) → status
Send a signal to the current process. The result is true when the call succeeded, false otherwise. This function is useful to test your own signal handlers:
> = apr.signal('SIGSEGV', function() print 'almost crashed :-)' end)
true
> = apr.signal_raise('SIGSEGV')
almost crashed :-)
true
> = apr.signal('SIGSEGV', nil)
true
> = apr.signal_raise('SIGSEGV')
zsh: segmentation fault lua
apr.signal_block(name) → status
Block the delivery of a particular signal. On success true is returned, otherwise a nil followed by an error message is returned.
apr.signal_unblock(name) → status
Enable the delivery of a particular signal. On success true is returned, otherwise a nil followed by an error message is returned.
apr.signal_names() → names
Return a table with available signal names on your platform. The keys of the table are the names of the signals and the values are the integer codes associated with the signals.
As the previous paragraph implies the result of this function can differ depending on your operating system and processor architecture. For example on my Ubuntu Linux 10.04 installation I get these results:
> signals = {}
> for k, v in pairs(apr.signal_names()) do
>> table.insert(signals, { name = k, value = v })
>> end
> table.sort(signals, function(a, b)
>> return a.value < b.value
>> end)
> for _, s in ipairs(signals) do
>> print(string.format('% 2i: %s', s.value, s.name))
>> end
1: SIGHUP
2: SIGINT
3: SIGQUIT
4: SIGILL
5: SIGTRAP
6: SIGIOT
6: SIGABRT
7: SIGBUS
8: SIGFPE
9: SIGKILL
10: SIGUSR1
11: SIGSEGV
12: SIGUSR2
13: SIGPIPE
14: SIGALRM
15: SIGTERM
16: SIGSTKFLT
17: SIGCHLD
17: SIGCLD
18: SIGCONT
19: SIGSTOP
20: SIGTSTP
21: SIGTTIN
22: SIGTTOU
23: SIGURG
24: SIGXCPU
25: SIGXFSZ
26: SIGVTALRM
27: SIGPROF
28: SIGWINCH
29: SIGPOLL
29: SIGIO
30: SIGPWR
31: SIGSYS
After creating the above table I was surprised to see several numbers which have two names in the above output, but after looking up the names it turns out that these are just synonyms.
Note that just because a signal is included in this table doesn’t necessarily mean the signal is usable from Lua! For example SIGALRM is only useful when you can call the alarm() function defined by POSIX but that function isn’t exposed by the Apache Portable Runtime (you can use lalarm instead in this case).
apr.strnatcmp(left, right) → status
Do a natural order comparison of two strings. Returns true when the left string is less than the right string, false otherwise. This function can be used as a callback for Lua’s standard library function table.sort().
> -- the canonical example:
> list = { 'rfc1.txt', 'rfc2086.txt', 'rfc822.txt' }
> -- collate order:
> table.sort(list)
> for _, name in ipairs(list) do print(name) end
rfc1.txt
rfc2086.txt
rfc822.txt
> -- natural order:
> table.sort(list, apr.strnatcmp)
> for _, name in ipairs(list) do print(name) end
rfc1.txt
rfc822.txt
rfc2086.txt
This function is not binary safe.
apr.strnatcasecmp(left, right) → status
Like apr.strnatcmp(), but ignores the case of the strings.
This function is not binary safe.
apr.strfsize(number [, padding]) → readable
Format a binary size positive number to a compacted human readable string. If the optional padding argument evaluates to true the resulting string will be padded with spaces to make it four characters wide, otherwise no padding will be applied.
> = apr.strfsize(1024)
'1.0K'
> = apr.strfsize(1024 ^ 2)
'1.0M'
> = apr.strfsize(1024 ^ 3)
'1.0G'
Here’s a simplified implementation of the UNIX command ls -l
--human-readable
which makes use of the padding argument to nicely line up
the fields following the size:
function ls(dirpath)
local directory = assert(apr.dir_open(dirpath))
for info in directory:entries() do
io.write(info.protection, ' ')
io.write(info.user, ' ')
io.write(info.group, ' ')
io.write(apr.strfsize(info.size, true), ' ')
io.write(apr.time_format('%Y-%m-%d %H:%I', info.ctime), ' ')
io.write(info.name, '\n')
end
assert(directory:close())
end
This is what the result looks like for the source code directory of the Lua/APR project:
> ls 'lua-apr/src'
rw-r--r-- peter peter 5.4K 2011-01-02 22:10 apr.lua
rw-r--r-- peter peter 4.7K 2011-01-02 06:06 base64.c
rw-r--r-- peter peter 11K 2010-10-27 13:01 buffer.c
rw-r--r-- peter peter 13K 2011-01-02 21:09 crypt.c
rw-r--r-- peter peter 2.8K 2010-12-31 01:01 date.c
rw-r--r-- peter peter 9.4K 2011-01-01 16:04 dbm.c
rw-r--r-- peter peter 2.5K 2010-09-25 23:11 env.c
rw-r--r-- peter peter 17K 2011-01-02 22:10 errno.c
rw-r--r-- peter peter 10K 2011-01-02 22:10 filepath.c
rw-r--r-- peter peter 1.9K 2011-01-02 04:04 fnmatch.c
rw-r--r-- peter peter 12K 2010-12-31 01:01 io_dir.c
rw-r--r-- peter peter 25K 2011-01-02 04:04 io_file.c
rw-r--r-- peter peter 17K 2010-12-31 01:01 io_net.c
rw-r--r-- peter peter 4.6K 2011-01-02 22:10 io_pipe.c
rw-r--r-- peter peter 11K 2011-01-02 11:11 lua_apr.c
rw-r--r-- peter peter 9.0K 2011-01-02 11:11 lua_apr.h
rw-r--r-- peter peter 6.9K 2010-12-29 14:02 permissions.c
rw-r--r-- peter peter 26K 2011-01-02 22:10 proc.c
rw-r--r-- peter peter 866 2010-10-23 00:12 refpool.c
rw-r--r-- peter peter 4.8K 2010-12-29 14:02 stat.c
rw-r--r-- peter peter 3.5K 2011-01-02 22:10 str.c
rw-r--r-- peter peter 9.8K 2010-12-31 01:01 time.c
rw-r--r-- peter peter 4.7K 2010-09-25 23:11 uri.c
rw-r--r-- peter peter 2.5K 2010-09-25 23:11 user.c
rw-r--r-- peter peter 2.9K 2010-10-22 19:07 uuid.c
rw-r--r-- peter peter 3.8K 2011-01-02 04:04 xlate.c
Note: It seems that apr.strfsize() doesn’t support terabyte range sizes.
apr.tokenize_to_argv(cmdline) → arguments
Convert the string cmdline to a table of arguments. On success the table of arguments is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
This is an experimental multi threading module that makes it possible to execute Lua functions in dedicated Lua states and operating system threads. When you create a thread you can pass it any number of arguments and when a thread exits it can return any number of return values. In both cases the following types are valid:
Please consider the following issues when using this module:
When you pass a userdata object to another thread you shouldn’t use it from the original thread after that, because the Lua/APR binding doesn’t protect object access with a thread safe lock. This will probably be fixed in the near future (hey, I said it was experimental)
When you start a thread and let it get garbage collected without having called thread:join(), the thread will be joined for you (because failing to do so while the main thread is terminating can crash the process)
apr.thread(body [, arg, ...]) → thread
Shortcut for apr.thread_create() that supports actual functions as body by converting them to byte code using string.dump(). This means you don’t lose syntax highlighting and debug information. This also calls assert() on the results of apr.thread_create(). This function won’t work in Lua implementations like LuaJIT 2 where string.dump() is not available.
apr.thread_create(code [, ...]) → thread
Execute the Lua code in the string argument code in a dedicated Lua state
and operating system thread. Any extra arguments are passed onto the Lua
code (where they can be accessed with the expression ...
). On success a
thread object is returned, otherwise a nil followed by an error message is
returned. You can use thread:join() to wait for the thread to finish and
get its return values.
This function is binary safe.
apr.thread_yield() → nothing
Force the current thread to yield the processor. This causes the currently executing thread to temporarily pause and allow other threads to execute.
thread:status() → status
Returns a string describing the state of the thread:
'running'
: the thread is currently running'done'
: the thread terminated successfully'error'
: the thread encountered an errorthread:join() → status [, result, ...]
Block until a thread stops executing and return its result. If the thread terminated with an error a nil followed by an error message is returned, otherwise true is returned, followed by any return values of the thread function.
This function is binary safe.
The valid types that can be transported through thread queues are documented in the multi threading module.
apr.thread_queue([capacity]) → queue
Create a FIFO queue. The optional argument capacity controls the maximum size of the queue and defaults to 1. On success the queue object is returned, otherwise a nil followed by an error message is returned.
queue:push(value [, ...]) → status
Add a tuple of one or more values to the queue. This call will block if the queue is full. On success true is returned, otherwise a nil followed by an error message and error code is returned:
'EINTR'
: the blocking was interrupted (try again)'EOF'
: the queue has been terminatedThis function is binary safe.
queue:pop() → value [, ...]
Get an object from the queue. This call will block if the queue is empty. On success true is returned, otherwise a nil followed by an error message and error code is returned:
'EINTR'
: the blocking was interrupted (try again)'EOF'
: the queue has been terminatedThis function is binary safe.
queue:trypush(value [, ...]) → status
Add a tuple of one or more values to the queue. This call doesn’t block if the queue is full. On success true is returned, otherwise a nil followed by an error message and error code is returned:
'EINTR'
: the blocking was interrupted (try again)'EAGAIN'
: the queue is full'EOF'
: the queue has been terminatedThis function is binary safe.
queue:trypop() → value [, ...]
Get an object from the queue. This call doesn’t block if the queue is empty. On success true is returned, otherwise a nil followed by an error message and error code is returned:
'EINTR'
: the blocking was interrupted (try again)'EAGAIN'
: the queue is empty'EOF'
: the queue has been terminatedThis function is binary safe.
queue:interrupt() → status
Interrupt all the threads blocking on this queue. On success true is returned, otherwise a nil followed by an error message is returned.
queue:terminate() → status
Terminate the queue, sending an interrupt to all the blocking threads. On success true is returned, otherwise a nil followed by an error message is returned.
queue:close() → status
Close the handle queue and (if no other threads are using the queue) destroy the queue and release the associated memory. This function always returns true (it cannot fail).
This will be done automatically when the queue object is garbage collected which means you don’t need to call this unless you want to reclaim memory as soon as possible.
Lua represents dates as numbers though the meaning of these numbers is not specified. The manual does state (in the documentation for os.time()) that on POSIX, Windows and some other systems these numbers count the number of seconds since some given start time called the epoch. This epoch is 00:00:00 January 1, 1970 UTC. The Apache Portable Runtime represents dates as the number of microseconds since that same epoch. As a compromise between the two units Lua/APR uses seconds but supports sub-second resolution in the decimal part of floating point numbers (see this thread on lua-l for discussion about the API).
apr.sleep(seconds) → nothing
Sleep for the specified number of seconds. Sub-second resolution is supported so you can for example give 0.5 to sleep for half a second. This function may sleep for longer than the specified time because of platform limitations.
apr.time_now() → time
Get the current time as the number of seconds since 00:00:00 January 1, 1970 UTC. If Lua is compiled with floating point support then more precision will be available in the decimal part of the returned number.
apr.time_explode([time [, timezone]]) → components
Convert the numeric value time (current time if none given) to its human readable components. If timezone isn’t given or evaluates to false the local timezone is used. If its a number then this number is used as the offset in seconds from GMT. The value true is treated the same as 0, i.e. GMT. On success the table of components is returned, otherwise a nil followed by an error message is returned. The resulting table contains the following fields:
usec
is the number of microseconds past sec
sec
is the number of seconds past min
(0-61)min
is the number of minutes past hour
(0-59)hour
is the number of hours past midnight (0-23)day
is the day of the month (1-31)month
is the month of the year (0-11).year
is the year since 1900wday
is the number of days since Sunday (0-6)yday
is the number of days since January 1 (0-365)gmtoff
is the number of seconds east of UTCisdst
is true when daylight saving time is in effectAll of these fields are numbers except for isdst
which is a boolean.
Here’s an example of the output returned by apr.time_explode():
> -- Note that numeric dates are always in UTC while tables with
> -- date components are in the local timezone by default.
> components = apr.time_explode(1032030336.18671)
> = components
{
usec = 186710,
sec = 36,
min = 5,
hour = 21,
day = 14,
month = 9,
year = 2002,
wday = 7,
yday = 257,
gmtoff = 7200, -- my local timezone
isdst = true,
}
> -- To convert a table of date components back into a number
> -- you can use the apr.time_implode() function as follows:
> = apr.time_implode(components)
1032030336.18671
apr.time_implode(components) → time
Convert a table of time components to its numeric value. On success the time is returned, otherwise a nil followed by an error message is returned. See apr.time_explode() for a list of supported components.
apr.time_format(format [, time]) → formatted
Format time (current time if none given) according to string format. On
success the formatted time is returned, otherwise a nil followed by an error
message is returned. The two special formats 'ctime'
and 'rfc822'
result
in a fixed length string of 24 or 29 characters in length. The time
argument may be either a number or a table with components like those
returned by apr.time_explode().
> = apr.time_format('%Y-%m-%d %H:%I:%S', apr.time_now())
'2010-09-25 17:05:08'
> = apr.time_format('ctime', apr.time_now())
'Sat Sep 25 17:26:22 2010'
> = apr.time_format('rfc822', apr.time_now())
'Sat, 25 Sep 2010 15:26:36 GMT'
This function is not binary safe.
apr.uri_parse(uri) → components
Parse the Uniform Resource Identifier uri. On success a table of components is returned, otherwise a nil followed by an error message is returned. The table of components can have the following fields, all strings:
scheme
is the part of the URI before ://
(as in http
, ftp
, etc.)user
is the user name, as in scheme://user:pass@host:port/
password
is the password, as in scheme://user:pass@host:port/
hostinfo
is the combined [user[:password]@]hostname[:port]
hostname
is the host name or IP addressport
is the port numberpath
is the request path (/
if only scheme://hostname
was given)query
is everything after a ?
in the path, if presentfragment
is the trailing #fragment
string, if presentThis function is not binary safe.
apr.uri_unparse(components [, option]) → uri
Convert a table of URI components into a URI string. On success the URI string is returned, otherwise a nil followed by an error message is returned. The list of fields in the components table is available in the documentation for apr.uri_parse(). The argument option may be one of the following:
hostinfo
to unparse the components [user[:password]@]hostname[:port]
pathinfo
to unparse the components path[?query[#fragment]]
This function is not binary safe.
apr.uri_port_of_scheme(scheme) → port
Return the default port for the given URI scheme string. Since at
least APR 1.2.8 the following schemes are supported: acap
,
ftp
, gopher
, http
, https
, imap
, ldap
, nfs
, nntp
, pop
,
prospero
, rtsp
, sip
, snews
, ssh
, telnet
, tip
, wais
,
z39.50r
and z39.50s
.
apr.user_get() → username, groupname
Get the username and groupname of the calling process. On success the username and groupname are returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
apr.user_homepath_get(username) → homepath
Get the home directory for the named user. On success the directory pathname is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
Universally unique identifiers are a standard for generating unique strings that are specific to the machine on which they are generated and/or the time at which they are generated. They can be used as primary keys in databases and are used to uniquely identify file system types and instances on modern operating systems. This is what a standard format UUID looks like:
> = apr.uuid_format(apr.uuid_get())
'0ad5d4a4-591e-41f7-8be4-07d7961a8079'
apr.uuid_get() → binary
Generate and return a UUID as a binary string of 16 bytes.
apr.uuid_format(binary) → formatted
Format a UUID of 16 bytes following the standard format of 32 hexadecimal
digits, displayed in 5 groups separated by hyphens, in the form 8-4-4-4-12
for a total of 36 characters, like f5dc3464-6c8f-654e-a407-b15b7a30f038
.
On success the formatted UUID is returned, otherwise a nil followed by an
error message is returned.
apr.uuid_parse(formatted) → binary
Parse a standard format UUID and return its 16-byte equivalent. On success the parsed UUID is returned, otherwise a nil followed by an error message is returned.
apr.xlate(input, from, to) → translated
Translate a string of text from one character encoding to
another. The from and to arguments are strings identifying the source and
target character encoding. The special value 'locale'
indicates the
character set of the current locale. On success the translated
string is returned, otherwise a nil followed by an error message is
returned.
Which character encodings are supported by apr.xlate() is system dependent because APR can use both the system’s iconv implementation and the bundled library apr-iconv. To get a list of valid character encoding names you can look through the apr-iconv/ccs and apr-iconv/ces directories (those are links to the web interface of the apr-iconv repository).
This function is binary safe.
This module enables parsing of XML documents. Unlike LuaExpat the parsers returned by apr.xml() don’t use callbacks, instead they parse XML into a document object model which is then exposed to Lua. Because of this you can’t use apr.xml() for incremental parsing. To parse an XML document you follow these steps:
Right now the only way to get the parse information is by calling xml_parser:getinfo() which converts the information to a Lua table following the Lua object model defined by LuaExpat. The Lua object model is a mapping of XML to Lua tables that’s not 100% complete (e.g. it doesn’t include namespaces) but makes it a lot easier to deal with XML in Lua.
In the future this module might expose the full XML parse tree to Lua as userdata objects, so that Lua has access to all parse information. This would also make it possible to expose the apr_xml_to_text() function.
apr.xml([filename]) → xml_parser
Create an XML parser. If the optional string filename is given, the file pointed to by filename will be parsed. On success the parser object is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
xml_parser:feed(input) → status
Feed the string input into the XML parser. On success true is returned, otherwise a nil followed by an error message is returned.
This function is binary safe.
xml_parser:done() → status
Terminate the parsing and save the resulting parse information. On success true is returned, otherwise a nil followed by an error message is returned.
xml_parser:geterror() → message
Fetch additional error information from the parser after one of its methods has failed.
xml_parser:getinfo() → table
Convert the parse information to a Lua table following the Lua Object Model defined by LuaExpat.
xml_parser:close() → status
Close the XML parser and destroy any parse information. This will be done automatically when the xml_parser object is garbage collected which means you don’t need to call this unless you want to reclaim memory as soon as possible (e.g. because you just parsed a large XML document).
apr.platform_get() → name
Get the name of the platform for which the Lua/APR binding was compiled. Returns one of the following strings:
'UNIX'
'WIN32'
'NETWARE'
'OS2'
Please note that the labels returned by apr.platform_get() don’t imply that these platforms are fully supported; the author of the Lua/APR binding doesn’t have NETWARE and OS2 environments available for testing.
apr.version_get() → versions_table
Get the versions of the libraries used by the Lua/APR binding. Returns a table with one or more of the following fields:
apr: The version of the Apache Portable Runtime library. This field is always available.
aprutil: The version of the APR utility library. This field is only available when Lua/APR is compiled against APR and APR-util 1.x because in version 2.x the utility library has been absorbed back into the APR library; there is no longer a distinction between the APR core and APR utility libraries.
apreq: The version of the HTTP request parsing library. This field is only available when the libapreq2 library is installed.
Each field is a string containing three numbers separated by dots. These numbers have the following meaning:
Major API changes that can cause compatibility problems between the Lua/APR binding and APR library
Minor API changes that shouldn’t impact existing functionality in the Lua/APR binding
Used exclusively for bug fixes
This function can be useful when you want to know whether a certain bug fix has been applied to APR and/or APR-util or if you want to report a bug in APR, APR-util or the Lua/APR binding.
If you're looking for the version of the Lua/APR binding you can use the
apr._VERSION
string, but note that Lua/APR currently does not adhere to
the above versioning rules.
apr.os_default_encoding() → name
Get the name of the system default character set as a string.
apr.os_locale_encoding() → name
Get the name of the current locale character set as a string. If the current locale’s data cannot be retrieved on this system, the name of the system default character set is returned instead.
apr.type(object) → name
Return the type of a userdata object created by the Lua/APR binding. If object is of a known type one of the following strings will be returned, otherwise nothing is returned:
'file'
'directory'
'socket'
'thread'
'process'
'dbm'
'database driver'
'prepared statement'
'result set'
'memcache client'
'memcache server'
'md5 context'
'sha1 context'
'xml parser'
The Apache Portable Runtime represents file system permissions somewhat similar to those of UNIX. There are three categories of permissions: the user, the group and everyone else (the world). Each category supports read and write permission bits while the meaning of the third permission bit differs between categories.
The Lua/APR binding uses a string of 9 characters to represent file system permissions such as those returned by apr.stat(). Here’s an example:
> = apr.stat('.', 'protection')
'rwxr-xr-x'
This is the syntax of these permissions strings:
r
if the user has read permissions, -
otherwisew
if the user has write permissions, -
otherwisex
if the user has execute permissions, S
if the user
has set user id permissions or s
if the user has both permissionsx
if the world has execute permissions, T
if the world
has sticky permissions or t
if the world has both permissionsAs an example, rwxrwx---
means the user and group have full permissions
while the world has none. Another example: r-xr-xr-x
means no-one has
write permissions.
When you need to request file system permissions for an operation like reading or copying a file there are two string formats you can use. The first format is a string of nine characters that lists each permission explicitly. This is the format documented above.
The second format is very flexible and is one of the formats accepted by the
Linux command line program chmod. The permissions are split in
three groups with a one-letter code: user is u
, group is g
and world is
o
(for “others”). One or more permissions can then be assigned to one or
more of these groups. Here’s an example that requests read permission for
user, group and others: ugo=r
. Now when you also need write permission for
user and group, you can use ugo=r,ug=w
.
Most functions in the Lua/APR binding follow the Lua idiom of returning nil followed by an error message string. These functions also return a third argument which is the symbolic name of the error (or the error code in case a symbolic name cannot be determined). The following symbolic names are currently defined (there’s actually a lot more but they shouldn’t be relevant when working in Lua):
'ENOSTAT'
: APR was unable to perform a stat on the file'EBADDATE'
: APR was given an invalid date'EINVALSOCK'
: APR was given an invalid socket'ENOPROC'
: APR was not given a process structure'ENOTIME'
: APR was not given a time structure'ENODIR'
: APR was not given a directory structure'ENOTHREAD'
: APR was not given a thread structure'EBADIP'
: the specified IP address is invalid'EBADMASK'
: the specified netmask is invalid'EDSOOPEN'
: APR was unable to open the DSO object'EABSOLUTE'
: the given path was absolute'ERELATIVE'
: the given path was relative'EINCOMPLETE'
: the given path was neither relative nor absolute'EABOVEROOT'
: the given path was above the root path'EBADPATH'
: the given path was bad'EPATHWILD'
: the given path contained wildcards'ESYMNOTFOUND'
: could not find the requested symbol'EPROC_UNKNOWN'
: the given process was not recognized by APR'ENOTENOUGHENTROPY'
: APR could not gather enough entropy to continue'TIMEUP'
: the operation did not finish before the timeout'INCOMPLETE'
: the operation was incomplete although some processing was performed and the results are partially valid'EOF'
: APR has encountered the end of the file'ENOTIMPL'
: the APR function has not been implemented on this platform, either because nobody has gotten to it yet, or the function is impossible on this platform'EMISMATCH'
: two passwords do not match'EACCES'
: permission denied'EEXIST'
: file exists'ENAMETOOLONG'
: path name is too long'ENOENT'
: no such file or directory'ENOTDIR'
: not a directory'ENOSPC'
: no space left on device'ENOMEM'
: not enough memory'EMFILE'
: too many open files'ENFILE'
: file table overflow'EBADF'
: bad file number'EINVAL'
: invalid argument'ESPIPE'
: illegal seek'EAGAIN'
: operation would block'EINTR'
: interrupted system call'ENOTSOCK'
: socket operation on a non-socket'ECONNREFUSED'
: connection refused'EINPROGRESS'
: operation now in progress'ECONNABORTED'
: software caused connection abort'ECONNRESET'
: connection Reset by peer'ETIMEDOUT'
: operation timed out (deprecated)'EHOSTUNREACH'
: no route to host'ENETUNREACH'
: network is unreachable'EFTYPE'
: inappropriate file type or format'EPIPE'
: broken pipe'EXDEV'
: cross device link'ENOTEMPTY'
: directory not empty'EAFNOSUPPORT'
: address family not supportedNote that the error descriptions above were copied verbatim from apr_errno.h.
The following Lua script implements a minimal HTTP client which can be used to download a given URL on the command line (comparable to wget and curl):
$ FILE=lua-5.1.4.tar.gz
$ URL=http://www.lua.org/ftp/$FILE
$ time curl -s $URL > $FILE
0,01s user 0,02s system 6% cpu 0,465 total
$ time lua examples/download.lua $URL > $FILE
0,03s user 0,02s system 9% cpu 0,549 total
Note that this script and Lua/APR in general are a bit handicapped in that they don’t support HTTPS because the Apache Portable Runtime does not support encrypted network communication.
local apr = require 'apr'
-- Report errors without stack traces.
local function assert(...)
local status, message = ...
if not status then
io.stderr:write('Error: ', message or '(no message)', '\n')
os.exit(1)
end
return ...
end
local function getpage(url)
local components = assert(apr.uri_parse(url))
assert(components.scheme == 'http', "invalid protocol!")
local port = assert(components.port or apr.uri_port_of_scheme(components.scheme))
local socket = assert(apr.socket_create())
assert(socket:connect(components.hostname, port))
local pathinfo = assert(apr.uri_unparse(components, 'pathinfo'))
assert(socket:write('GET ', pathinfo, ' HTTP/1.0\r\n',
'Host: ', components.hostname, '\r\n',
'\r\n'))
local statusline = assert(socket:read(), 'HTTP response missing status line!')
local protocol, statuscode, reason = assert(statusline:match '^(%S+)%s+(%S+)%s+(.-)$')
local redirect = statuscode:find '^30[123]$'
for line in socket:lines() do
local name, value = line:match '^(%S+):%s+(.-)\r?$'
if name and value then
if redirect and name:lower() == 'location' then
io.stderr:write("Following redirect to ", value, " ..\n")
return getpage(value)
end
else
return (assert(socket:read '*a', 'HTTP response missing body?!'))
end
end
if statuscode ~= '200' then error(reason) end
end
local usage = "Please provide a URL to download as argument"
io.write(getpage(assert(arg and arg[1], usage)))
-- vim: ts=2 sw=2 et
The following script implements a minimalistic webserver on top of Lua/APR. It should work out of the box on Windows and UNIX, although you might get a prompt from your firewall. Once the server is running you can open http://localhost:8080 in your web browser to see the server in action. Because the server is single threaded I was curious how bad it would perform, so I tested it with ApacheBench:
$ lua examples/webserver.lua &
$ ab -qt5 http://localhost:8080/ | grep 'Requests per second\|Transfer rate'
Requests per second: 3672.19 [#/sec] (mean)
Transfer rate: 2201.88 [Kbytes/sec] received
That’s not too bad for 40 lines of code! Here is the script:
local port_number = tonumber(arg[1]) or 8080
local bind_address = arg[2] or '*'
-- Load the Lua/APR binding.
local apr = require 'apr'
-- Initialize the server socket.
local server = assert(apr.socket_create())
assert(server:bind(bind_address, port_number))
assert(server:listen(1))
print("Running webserver on http://" .. bind_address .. ":" .. port_number .. " ..")
-- Wait for clients to serve.
local visitor = 1
local template = [[
<html>
<head>
<title>Hello from Lua/APR!</title>
<style type="text/css">
body { font-family: sans-serif; }
dt { font-weight: bold; }
dd { font-family: monospace; margin: -1.4em 0 0 14em; }
</style>
</head>
<body>
<h1>Hello from Lua/APR!</h1>
<p><em>You are visitor number %010i.</em></p>
<p>The headers provided by your web browser:</p>
<dl>%s</dl>
</body>
</html>
]]
while true do
local status, message = pcall(function()
local client = assert(server:accept())
-- Read the HTTP request so that the client can receive data.
local request = assert(client:read(), "Failed to receive request from client!")
local method, location, protocol = assert(request:match '^(%w+)%s+(%S+)%s+(%S+)')
local headers = {}
for line in client:lines() do
local name, value = line:match '^(%S+):%s+(.-)$'
if not name then break end
table.insert(headers, '<dt>' .. name .. ':</dt><dd>' .. value .. '</dd>')
end
-- Generate the HTTP response.
table.sort(headers)
content = template:format(visitor, table.concat(headers))
client:write(protocol, ' 200 OK\r\n',
'Content-Type: text/html\r\n',
'Content-Length: ' .. #content .. '\r\n',
'Connection: close\r\n',
'\r\n',
content)
assert(client:close())
visitor = visitor + 1
end)
if not status then
print('Error while serving request:', message)
end
end
-- vim: ts=2 sw=2 et
Thanks to the multi threading and thread queue modules in the Apache Portable Runtime it is possible to
improve the performance of the single threaded webserver from the previous
example. Here is a benchmark of the multi threaded implementation listed
below (again using ApacheBench, but now with the -c
argument):
$ NUM_THREADS=4
$ lua examples/threaded-webserver.lua $NUM_THREADS &
$ ab -qt5 -c$NUM_THREADS http://localhost:8080/ | grep 'Requests per second\|Transfer rate'
Requests per second: 9210.72 [#/sec] (mean)
Transfer rate: 5594.79 [Kbytes/sec] received
Comparing these numbers to the benchmark of the single threaded webserver we can see that the number of requests per second went from 3670 to 9210, more than doubling the throughput of the webserver on a dual core processor.
Note that both benchmarks were run on my Compaq Presario CQ60 laptop (which features an Intel Core 2 Duo T5800 processor clocked at 2 GHz and 3 GB of RAM) and that the Lua/APR binding was compiled without debugging symbols.
local num_threads = tonumber(arg[1]) or 2
local port_number = tonumber(arg[2]) or 8080
local template = [[
<html>
<head>
<title>Hello from Lua/APR!</title>
<style type="text/css">
body { font-family: sans-serif; }
dt { font-weight: bold; }
dd { font-family: monospace; margin: -1.4em 0 0 14em; }
</style>
</head>
<body>
<h1>Hello from Lua/APR!</h1>
<p><em>This web page was served by worker %i.</em></p>
<p>The headers provided by your web browser:</p>
<dl>%s</dl>
</body>
</html>
]]
-- Load the Lua/APR binding.
local apr = require 'apr'
-- Initialize the server socket.
local server = assert(apr.socket_create())
assert(server:bind('*', port_number))
assert(server:listen(num_threads * 2))
print("Running webserver with " .. num_threads .. " client threads on http://localhost:" .. port_number .. " ..")
-- Create the thread queue (used to pass sockets between threads).
local queue = apr.thread_queue(num_threads)
-- Define the function to execute in each child thread.
function worker(thread_id, queue, template)
pcall(require, 'luarocks.require')
local apr = require 'apr'
while true do
local client, msg, code = queue:pop()
assert(client or code == 'EINTR', msg)
if client then
local status, message = pcall(function()
local request = assert(client:read(), "Failed to receive request from client!")
local method, location, protocol = assert(request:match '^(%w+)%s+(%S+)%s+(%S+)')
local headers = {}
for line in client:lines() do
local name, value = line:match '^(%S+):%s+(.-)$'
if not name then
break
end
table.insert(headers, '<dt>' .. name .. ':</dt><dd>' .. value .. '</dd>')
end
table.sort(headers)
local content = template:format(thread_id, table.concat(headers))
client:write(protocol, ' 200 OK\r\n',
'Content-Type: text/html\r\n',
'Content-Length: ' .. #content .. '\r\n',
'Connection: close\r\n',
'\r\n',
content)
assert(client:close())
end)
if not status then
print('Error while serving request:', message)
end
end
end
end
-- Create the child threads and keep them around in a table (so that they are
-- not garbage collected while we are still using them).
local pool = {}
for i = 1, num_threads do
table.insert(pool, apr.thread(worker, i, queue, template))
end
-- Enter the accept() loop in the parent thread.
while true do
local status, message = pcall(function()
local client = assert(server:accept())
assert(queue:push(client))
end)
if not status then
print('Error while serving request:', message)
end
end
-- vim: ts=2 sw=2 et