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.23.1 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="//peterodding.com/code/lua/apr/docs/'</span> <span style="color:#2239A8;font-weight:bold">.. 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.
TODO Support for transaction objects that have query(), select(), prepare() methods?
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 [, random_access]) → prepared_statement
Prepare an SQL statement. On success a prepared statement object is returned, otherwise a nil followed by an error message is returned. The string sql gives the query to prepare. If the optional argument random_access is true, result sets created by the prepared statement will support random access.
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(...) → 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.
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.filepath_executable(path) → is_executable
Check whether the file pointed to by path is executable. Returns true when the file is executable, false otherwise.
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_truncate(path [, offset]) → status
Truncate the file’s length to the specified offset (defaults to 0). On success true is returned, otherwise a nil followed by an error message is returned.
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:truncate([offset]) → status
Truncate the file’s length to the specified offset (defaults to 0). On success true is returned, otherwise a nil followed by an error message is returned. Note that the read/write file offset is repositioned to the selected offset.
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.
To get started with network programming using the Lua/APR binding, have a look at any of the following examples:
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:recvfrom([bufsize]) → address, data
Read data from an UDP socket that has been bound to an interface and/or port. On success two values are returned: A table with the address of the peer from which the data was sent and a string with the received data. If the call fails it returns nil followed by an error message.
By default bufsize is 1024, this means the resulting data string will be truncated to a maximum of 1024 bytes. If you want to receive larger messages, pass a larger bufsize.
The returned address table contains the following fields:
address
is the IP address (a string)port
is the port numberfamily
is one of the strings 'inet'
, 'inet6'
or 'unspec'
This function is binary safe.
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().
The Lightweight Directory Access Protocol (LDAP) enables querying and modifying data hosted on directory servers. LDAP databases are similar to relational databases in the sense that both types of databases store records with attributes and allow clients to search records based on those attributes. Notable differences between LDAP and relational databases are that LDAP stores all records in a hierarchy and records can have an arbitrary number of attributes. LDAP is frequently used by (large) organizations to provide a centralized address book for all employees and to store system account information like user names and passwords in a central place (one piece of the puzzle towards roaming profiles).
This module is based on LuaLDAP by Roberto Ierusalimschy, André Carregal and Tomás Guisasola.
apr.ldap([url [, secure ]]) → ldap_conn
Create an LDAP connection. The url argument is a URL string with the following components:
ldap://
(the default) or ldaps://
(for secure
connections)If secure is true the connection will use STARTTLS even if the
URL scheme is ldap://
. On success an LDAP connection object is returned,
otherwise a nil followed by an error message is returned.
apr.ldap_info() → string
This function returns a string describing the LDAP SDK (library) currently in use. On success a string is returned, otherwise a nil followed by an error message is returned. The resulting string is intended to be displayed to the user, it’s not meant to be parsed (although you can of course decide to do this :-). According to apr_ldap.h the following LDAP SDKs can be used:
apr.ldap_url_parse(string) → table
Parse an LDAP URL into a table of URL components. On success a table is returned, otherwise a nil followed by an error message and one of the following strings is returned:
ldap://
, ldapi://
or ldaps://
>
LDAP URLs look like this:
ldap[is]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]]
Where:
For example:
> = apr.ldap_url_parse 'ldap://root.openldap.org/dc=openldap,dc=org' { scheme = 'ldap', host = 'root.openldap.org', port = 389, scope = 'sub', dn = 'dc=openldap,dc=org', crit_exts = 0, }
apr.ldap_url_check(url) → type
Checks whether the given URL is an LDAP URL. On success one of the strings below is returned, otherwise nil is returned:
ldap://
)ldapi://
)ldaps://
)ldap_conn:bind([who [, passwd]]) → status
Bind to the LDAP directory. If no arguments are given an anonymous bind is
attempted, otherwise who should be a string with the relative distinguished
name (RDN) of the user in the form 'cn=admin,dc=example,dc=com'
. On
success true is returned, otherwise a nil followed by an error message is
returned.
ldap_conn:unbind() → status
Unbind from the directory. On success true is returned, otherwise a nil followed by an error message is returned.
ldap_conn:option_get(name) → value
Get an LDAP option by its name (one of the strings documented below). On success the option value is returned, otherwise a nil followed by an error message is returned. These are the supported LDAP options:
ldap_conn:option_set(name, value) → status
Set the LDAP option name (one of the strings documented for ldap_conn:option_get()) to value. On success true is returned, otherwise a nil followed by an error message is returned.
ldap_conn:rebind_add([who [, password]]) → status
LDAP servers can return referrals to other servers for requests the server itself will not/can not serve. This function creates a cross reference entry for the specified LDAP connection. The rebind callback function will look up this LDAP connection so it can retrieve the who and password fields for use in any binds while referrals are being chased.
On success true is returned, otherwise a nil followed by an error message is returned.
When the LDAP connection is garbage collected the cross reference entry is automatically removed, alternatively ldap_conn:rebind_remove() can be called to explicitly remove the entry.
ldap_conn:rebind_remove() → status
Explicitly remove an LDAP cross reference entry (also done automatically when the LDAP connection is garbage collected). On success true is returned, otherwise a nil followed by an error message is returned.
ldap_conn:search(parameters) → iterator
The implementation of this method is based on LuaLDAP and the following documentation was based on the LuaLDAP manual:
Performs a search operation on the directory. The parameters are described below. The search method will return a search iterator which is a function that requires no arguments. The search iterator is used to get the search result and will return a string representing the distinguished name and a table of attributes as returned by the search request.
Supported parameters:
attrs: a string or a list of attribute names to be retrieved (default is to retrieve all attributes)
attrsonly: a boolean value that must be either false (default) if both attribute names and values are to be retrieved, or true if only names are wanted
base: The distinguished name of the entry at which to start the search
filter: A string representing the search filter as described in The String Representation of LDAP Search Filters (RFC 2254)
scope: A string indicating the scope of the search. The valid strings are: base, one and sub. The empty string and nil will be treated as the default scope
sizelimit: The maximum number of entries to return (default is no limit)
timeout: The timeout in seconds (default is no timeout). The precision is microseconds
ldap_conn:add(dn, attrs) → future
Add a new entry to the directory. The string dn is the distinguished name of the new entry. The table attrs contains the attributes and values. Returns a function to process the LDAP result.
This function is not binary safe.
ldap_conn:compare(dn, attr, value) → future
Compare a value against an entry. The string dn contains the distinguished name of the entry, the string attr is the name of the attribute to compare and the string value is the value to compare against. Returns a function to process the LDAP result.
This function is not binary safe.
ldap_conn:delete(dn) → future
Delete an entry. The string dn is the distinguished name of the entry to delete. Returns a function to process the LDAP result.
This function is not binary safe.
ldap_conn:modify(dn, mods [, ...]) → future
Modify an entry. The string dn is the distinguished name of the entry to modify. The table mods contains modifications to apply. You can pass any number of additional tables with modifications to apply. On success true is returned, otherwise a nil followed by an error message is returned.
This function is not binary safe.
ldap_conn:rename(dn, new_rdn [, new_parent [, delete]]) → future
Change the distinguished name of an entry. The string dn is the distinguished name of the entry to rename. The string new_rdn gives the new root distinguished name. The optional string new_parent gives the distinguished name of the new parent for the entry. If the optional argument delete is true the entry is removed from it’s old parent. Returns a function to process the LDAP result.
This function is not binary safe.
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.
The pollset module enables asynchronous I/O which can improve throughput, latency and/or responsiveness. It works as follows:
You can keep adding and removing sockets from the pollset at runtime, just keep in mind that the size given to apr.pollset() is a hard limit. There is an example of a simple asynchronous webserver that uses a pollset.
apr.pollset(size) → pollset
Create a pollset object. The number size is the maximum number of sockets that the pollset can hold. On success a pollset object is returned, otherwise a nil followed by an error message is returned.
pollset:add(socket, flag [, ...]) → status
Add a network socket to the pollset. On success true is returned, otherwise a nil followed by an error message is returned. One or two of the following flags should be provided:
'input'
indicates that the socket can be read without blocking'output'
indicates that the socket can be written without blockingIf the socket is already in the pollset the flags of the existing entry in the pollset will be combined with the new flags. If you want to change a socket from readable to writable or the other way around, you have to first remove the socket from the pollset and then add it back with the new flag.
pollset:remove(socket) → status
Remove a socket from the pollset. On success true is returned, otherwise a nil followed by an error message is returned. It is not an error if the socket is not contained in the pollset.
pollset:poll(timeout) → readable, writable
Block for activity on the descriptor(s) in a pollset. The timeout argument gives the amount of time in microseconds to wait. This is a maximum, not a minimum. If a descriptor is signaled, we will wake up before this time. A negative number means wait until a descriptor is signaled. On success a table with sockets waiting to be read followed by a table with sockets waiting to be written is returned, otherwise a nil followed by an error message is returned.
pollset:destroy() → status
Destroy a pollset. On success true is returned, otherwise a nil followed by an error message is returned. Note that pollset objects are automatically destroyed when they are garbage collected.
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. For details about supported Lua values see the documentation of the serialization module.
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(f [, ...]) → thread
Execute the Lua function f in a dedicated Lua state and operating system thread. Any extra arguments are passed onto the function. 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 the return values of the thread function.
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 under the serialization module. The example of a multi threaded webserver uses a thread queue to pass sockets between the main server thread and several worker threads.
apr.thread_queue([capacity]) → queue
Create a [FIFO] [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.
The capacity of a thread queue cannot be changed after construction.
queue:push(value [, ...]) → status
Add a tuple of one or more Lua 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 one or more Lua values 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 Lua 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 a tuple of Lua values 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).
The Lua/APR binding contains a serialization function based on the Metalua table-to-source serializer extended to support function upvalues and userdata objects created by the Lua/APR binding. The following Lua values can be serialized:
Restrictions:
Metatables and environments aren’t saved; this might or might not be what you want.
If multiple functions share a scalar upvalue they will each get their own copy. Because it is impossible to join upvalues of multiple functions in Lua 5.1 this won’t be fixed any time soon.
The following functions in the Lua/APR binding internally use serialization to transfer Lua functions and other values between operating system threads:
apr.serialize(...) → string
Serialize any number of Lua values (a tuple) into a source code string. When passed to apr.unserialize() this string results in a tuple of values that is structurally identical to the original tuple.
apr.unserialize(string) → ...
Unserialize a source code string into one or more Lua values.
apr.ref(object) → uuid
Prepare the Lua/APR userdata object so that it can be referenced from another Lua state in the same operating system process and associate a UUID with the object. The UUID is returned as a string. When you pass this UUID to apr.deref() you’ll get the same object back. This only works once, but of course you’re free to generate another UUID for the same object.
apr.deref(uuid) → object
Convert a UUID that was previously returned by apr.ref() into a userdata object and return the object. You can only dereference a UUID once, but of course you’re free to generate another UUID for the same object.
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 network sockets. 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! For more complex webservers see the multi threaded and asynchronous webserver examples.
Note that all benchmarks are 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 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 code
listed below (again using ApacheBench, but now with the -c
argument):
$ CONCURRENCY=4 $ lua examples/threaded-webserver.lua $CONCURRENCY & $ ab -qt5 -c$CONCURRENCY 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. If you want to know how we can make it even faster, have a look at the asynchronous webserver example.
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
We can do even better than the performance of the multi threaded webserver by
using the APR pollset module. The following webserver uses
asynchronous network communication to process requests from multiple clients
‘in parallel’ without using multiple threads or processes. Here is a
benchmark of the asynchronous code listed below (again using ApacheBench with the -c
argument):
$ CONCURRENCY=4 $ POLLSET_SIZE=10 $ lua examples/async-webserver.lua $POLLSET_SIZE 8080 cheat & $ ab -qt5 -c$CONCURRENCY http://localhost:8080/ | grep 'Requests per second\|Transfer rate' Requests per second: 11312.64 [#/sec] (mean) Transfer rate: 6219.74 [Kbytes/sec] received
The single threaded webserver handled 3670 requests per second, the multi threaded webserver handled 9210 requests per second and the asynchronous webserver below can handle 11310 requests per second. Actually in the above benchmark I may have cheated a bit (depending on whether your goal is correct usage or performance). When I started writing this asynchronous server example I didn’t bother to add writable sockets to the pollset, instead I handled the request and response once the client socket was reported as readable by the pollset. Later on I changed the code to handle writing using the pollset and I noticed that the performance dropped. This is probably because the example is so contrived. Anyway here’s the performance without cheating:
$ lua examples/async-webserver.lua $POLLSET_SIZE 8080 & $ ab -qt5 -c$CONCURRENCY http://localhost:8888/ | grep 'Requests per second\|Transfer rate' Requests per second: 9867.17 [#/sec] (mean) Transfer rate: 5425.03 [Kbytes/sec] received
Now follows the implementation of the asynchronous webserver example:
local pollset_size = tonumber(arg[1]) or 10 local port_number = tonumber(arg[2]) or 8080 local cheat = arg[3] == 'cheat' -- cheat to make it faster? 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>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(pollset_size)) -- Create the pollset. local pollset = assert(apr.pollset(pollset_size)) assert(pollset:add(server, 'input')) -- Use a table indexed with socket objects to keep track of "sessions". local sessions = setmetatable({}, {__mode='k'}) -- Enter the I/O loop. print("Running webserver on http://localhost:" .. port_number .. " ..") while true do local readable, writable = assert(pollset:poll(-1)) -- Process requests. for _, socket in ipairs(readable) do if socket == server then local client = assert(server:accept()) assert(pollset:add(client, 'input')) else local request = assert(socket:read(), "Failed to receive request from client!") local method, location, protocol = assert(request:match '^(%w+)%s+(%S+)%s+(%S+)') local headers = {} for line in socket: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(table.concat(headers)) assert(socket:write( protocol, ' 200 OK\r\n', 'Content-Type: text/html\r\n', 'Content-Length: ', #content, '\r\n', 'Connection: close\r\n', '\r\n')) if cheat then assert(socket:write(content)) assert(pollset:remove(socket)) assert(socket:close()) else sessions[socket] = content assert(pollset:remove(socket)) assert(pollset:add(socket, 'output')) end end end if not cheat then -- Process responses. for _, socket in ipairs(writable) do assert(socket:write(sessions[socket])) -- I don't like that when I switch the order of these -- calls, it breaks... Seems like a fairly big gotcha. assert(pollset:remove(socket)) assert(socket:close()) end end end -- vim: ts=2 sw=2 et
Last updated Tue Dec 06 20:08:32 UTC 2011.