![]() |
IPv4 Sockets support for the Lua language |
home · download · what is · introduction · functions · modules · index
Besides IPv4 transport layer support, the LuaSocket toolkit offers straightforward support for the HTTP, SMTP and FTP protocols. The support is implemented in the Lua language and is distributed in source code as three separate modules.
HTTP and FTP transfers sometimes involve large amounts of information. Sometimes an application needs to generate outgoing data in real time, or needs to process incoming information as it is being received. To address these problems, LuaSocket allows HTTP message bodies and FTP file contents to be received or sent through the callback mechanism outlined below.
Instead of returning the whole contents of a FTP file or HTTP message body as strings to the Lua application, the library allows the user to provide a receive callback that will be called with successive chunks of data, as the data becomes available:
receive_cb(chunk, err)Instead of forcing the Lua application to pass the whole FTP file contents or the HTTP request message body as a string to the library, the library allows the user to provide a send callback that will be called repeatedly to return successive parts of the information needed by the library:The callback provided by the user will be repeatedly called by the library whenever new data is available. Each time it is called, the callback receives successive chunks of downloaded data. When the transmission is over, the function is called with an empty string (i.e. "") as the chunk. If an error occurs, the function receives a nil chunk and an error message as the err argument. The callback can abort transmission by returning nil as its first return value. In that case, it can also return an error message. Any non-nil return value proceeds with the transmission.
Examples:
-- saves incoming file to disk, receiving chunk by chunk local file = openfile(tmpname(), "wb") -- open temp file for writing local receive_cb = function(chunk, err) if chunk and chunk ~= "" then local res, err = write(%file, chunk) -- try to write to disk if not res then return nil, err -- woops! abort with error message else return 1 end -- all is ok, please go on else closefile(%file) end -- we are done end -- print throughput feedback while receiving data local aux = { start = _time(), got = 0 } -- auxiliar table local receive_cb = function(chunk, err) local dt = _time() - %aux.start -- elapsed time since start if not chunk or chunk == "" then return end %aux.got = %aux.got + strlen(chunk) -- total bytes received if dt < 0.1 then return 1 end -- not enough time for estimate local rate = %aux.got / dt -- get download rate write("\r" .. format("%.2f", rate)) -- print estimate return 1 -- ready for more end
send_cb()The callback provided by the user will be repeatedly called whenever the library needs more data to be sent. Each time the callback is called, it should return the next part of the information the library is expecting, followed by the total number of bytes to be sent. The callback can abort the process at any time by returning nil followed by an optional error message.
Obs: The need for the second return value comes from the fact that, with the HTTP protocol for instance, the library needs to know in advance the total number of bytes that will be sent.
Examples:
-- sends data from file, in blocks of 4096 bytes local file = openfile("words", "rb") -- open file for reading local size = seek(file, "end") -- get file size seek(file, "set") local send_cb = function() local chunk = read(%file, 4096) -- try to read chunk if not chunk then -- are we done? closefile(%file) return "", %size else return chunk, %size end -- if not, send what we got end -- sends everything in the first call local file = openfile("words", "rb") -- open file for reading local data = read(file, "*a") closefile(file) local send_cb = function() return %data, strlen(%data) -- return everything end
HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange information between web-browsers and servers. The http.lua module offers support for the client side of the HTTP protocol (i.e., the facilities that would be used by a web-browser implementation). The implementation conforms to the HTTP/1.1 standard, RFC 2616.
URLs MUST conform to RFC 1738, that is, an URL is a string in the form:
The module exports functions that provide HTTP functionality in different levels of abstraction, from a simple HTTP.get, to a complete callback oriented HTTP.request_cb.
MIME Headers are represented as a table in the form:[http://][<user>[:<password>]@]<>[:<port>][/<path>]
Field names are case insensitive (as specified by the standard) and all API functions work with lowercase field names. Field values are left unmodified.headers = { ["field-1-name"] = "field-1-value", ["field-2-name"] = "field-2-value", ["field-3-name"] = "field-3-value", ... ... ["field-n-name"] = "field-n-value" }
HTTP.get(url) or
HTTP.get{
url = string,
headers = header table,
user = string,
password = string,
stay = bool,
}
Performs method 'GET' on url. The function can be called either directly with a url or with a request table. The use of a request table allows complete control over the components of the request. Values passed explicitly in the request table override those given by the url.
The function returns the response message body, the mime headers, the status code and an error message if any. In case of failure, the function returns all information it managed to gather.
Note: The function is trivially implemented with the use of the HTTP.request function.
Examples:
HTTP.post(url, body) or-- connect to server "www.tecgraf.puc-rio.br" and retrieves this manual -- file from "~diego/luasocket/mod.html" b, h, c, e = HTTP.get("http://www.tecgraf.puc-rio.br/~diego/luasocket/manual.html") -- connect to server "www.tecgraf.puc-rio.br" and tries to retrieve -- "~diego/auth/index.html". Fails because authentication is needed. b, h, c, e = HTTP.get("http://www.tecgraf.puc-rio.br/~diego/mark/index.html") -- b returns some useless page, h returns authentication information -- and c returns with value 401 (Authentication Required) -- tries to connect to server "wrong.host" to retrieve "/" -- and fails because the host does not exist. b, h, c, e = HTTP.get("http://wrong.host/") -- b, h, c are nil, and e returns with value "host not found"
Same as HTTP.get, except the method used is 'POST' and the request message body is sent along with the request.
Performs the generic HTTP request using method on url sending the request headers and request body in the request message. If authentication information is provided, the function uses the Basic Authentication Scheme (see note) to retrieve the document. User and password provided explicitly override those given by the url. The stay parameter, when set to anything but nil, prevents the function from automatically following 301 or 302 server redirect messages.
The function returns a table with all components of the response message it managed to retrieve. The response table has the following form:
response = {Note: Even when there was failure (URL not found, for example), the function may succeed retrieving a message body (a web page informing the URL was not found or some other useless page). To make sure the operation was successful, check the returned status code. For a list of the possible values and their meanings, refer to RFC 2616.
body = string,
headers = header table,
status = string,
code = number,
error = string,
}
Example:
Authentication Note: Some URLs are protected by their servers from anonymous download. For those URLs, the server must receive some sort of authentication along with the request or it will deny download and return status "401 Authentication Required".-- request information about a document, without downloading it. -- useful, for example, if you want to display a download gauge and need -- to know the size of the document in advance response = HTTP.request { method = "HEAD", url = "http://www.tecgraf.puc-rio.br/~diego" } -- would return the following headers: -- response.headers = { -- date = "Tue, 18 Sep 2001 20:42:21 GMT", -- server = "Apache/1.3.12 (Unix) (Red Hat/Linux)", -- ["last-modified"] = "Wed, 05 Sep 2001 06:11:20 GMT", -- etag = '"c1513-3d24-3b95c208"', -- ["accept-ranges"] = "bytes", -- ["content-length"] = 15652, -- ["connection"] = "close", -- ["content-Type"] = "text/html" -- }
The HTTP/1.1 standard defines two authentication methods: the Basic Authentication Scheme and the Digest Authentication Scheme, both explained in detail in RFC 2068.
The Basic Authentication Scheme sends <user> and <password> unencrypted to the server and is therefore considered unsafe. Unfortunately, by the time of this implementation, the wide majority of servers and browsers support the Basic Scheme only. Therefore, this is the method used by the toolkit whenever authentication is required.
Authentication Example:
HTTP.request_cb(request, response)-- connect to server "www.tecgraf.puc-rio.br" and tries to retrieve -- "~diego/auth/index.html", using the provided name and password to -- authenticate the request response = HTTP.request{ url = "http://www.tecgraf.puc-rio.br/~diego/auth/index.html", user = "diego", password = "password" } -- alternatively, one could fill the appropriate header and authenticate -- the request directly. headers = { authentication = "Basic " .. Code.base64("diego:password") } response = HTTP.request { url = "http://www.tecgraf.puc-rio.br/~diego/auth/index.html", headers = headers }
Performs the generic HTTP request using method on url sending the request.headers along with the request. The request message body is sent with the use of the send callback request.body_cb. If authentication information is provided, the function uses the Basic Authentication Scheme (see note) to retrieve the document. User and password provided explicitly override those given by the url. The stay parameter, when set to anything but nil, prevents the function from automatically following 301 or 302 server redirect messages.
The function returns the same response table as that returned by the HTTP.request function, except the response message body is returned to the receive callback given by the response.body_cb field.
Note: for more information on callbacks, refer to Streaming with callbacks.
Examples:
-- The implementation of the HTTP.request function function Public.request(request) local response = {} if request.body then request.body_cb = function() return %request.body, strlen(%request.body) end end local cat = Concat.create() response.body_cb = function(chunk, err) if chunk then %cat:addstring(chunk) end return 1 end response = %Public.request_cb(request, response) response.body = cat:getresult() response.body_cb = nil return response end
FTP (File Transfer Protocol) is a protocol used to transfer files between hosts. The module ftp.lua offers simple FTP support, allowing applications to download and upload files, and list directory contents. The implementation conforms to RFC 959.
URLs MUST conform to RFC 1738, that is, an URL is a string in the form:
[ftp://][<user>[:<password>]@]<>[:<port>][/<path>][type=a|i|d]FTP.get(url) or
Downloads the URL url and returns it as a string. The function can be called either directly with a url or with a request table. Values passed explicitly in the request table override those given by the url.
The parameter type can receive values 'a' (ASCII, the default), 'i' (binary) or 'd' (directory listing) and determines the transfer type. If <path> ends with a '/' or type is 'd', a directory listing of <path> is returned. If successful, the function returns the file contents as a string. In case of error, the function returns nil and an error message describing the error.
If no user is provided in the url or explicitly, the function tries to log in as user 'anonymous'.
Examples:
FTP.put(url, content) or-- log as user "anonymous" on server "ftp.tecgraf.puc-rio.br" -- go to directory "pub/lua" and get file "lua.tar.gz" as binary. f, e = FTP.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i") -- log as user "anonymous" on server "ftp.tecgraf.puc-rio.br" -- go to director "pub" and retrieve directory listing of directory "lua" f, e = FTP.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua;type=d") -- log as user "diego", password "nehab", on server "derain.tecgraf.puc-rio.br" -- go to directory "tec/luasocket/bin" and retrieve file "luasocket.exe" -- (actually, fails because of wrong password :-) f, e = FTP.get{ url = "ftp://derain.tecgraf.puc-rio.br/tec/luasocket/bin/luasocket.exe", user = "diego", password = "nehab", type = "i" } -- f returns nil, and e returns an appropriate error message
Stores a file at url with contents given by the string content. The function can be called directly with a url and content parameters, or with a request table. Values passed explicitly in the request table override those given by the url. The parameter type receive values 'a' (ASCII, the default) or 'i' (binary) and determines the transfer type. If no user is provided, the function tries to log in as 'anonymous'.
If successful, the function returns nil. In case of error, the function returns a string describing the error.
Examples:
FTP.get_cb{-- log as user "anonymous" on server "ftp.free.org" and store file -- "hello" with contents "hello world!" on current directory, using binary -- mode for the transfer e = FTP.put("ftp://ftp.free.org/hello;type=i", "hello world!\n") -- does exactly the same, but logging in as diego e = FTP.put{ url = "ftp://ftp.free.org/hello", type = "i", user = "diego", content = "hello world\n" }
Same as FTP.get, but the library returns the contents of the downloaded file to the receive callback content_cb.
Note: for more information on callbacks, refer to Streaming with callbacks.
Same as FTP.put, but the library obtains the contents of the file to be uploaded using the send callback content_cb.
Note: for more information on callbacks, refer to Streaming with callbacks.
The module smtp.lua provides functionality to send e-mail messages to a SMTP mail server. The implementation conforms to RFC 821.
MIME Headers are represented as a table in the form:
SMTP.mail{headers = { ["field-1-name"] = "field-1-value", ["field-2-name"] = "field-2-value", ["field-3-name"] = "field-3-value", ... ... ["field-n-name"] = "field-n-value" }
Sends a message to recipient list rcpt, a lua table. The sender is given by the e-mail address from. The message is composed by the optional MIME Headers headers and text body. The message is sent using the server server. If successful, the function returns nil, otherwise an error message is returned.
Examples:
mail{headers = { to = "fulano@tecgraf.puc-rio.br, beltrano@tecgraf.puc-rio.br", subject = "LuaSocket test message" } from = "luasocket@tecgraf.puc-rio.br" rcpt = { "fulano@tecgraf.puc-rio.br", "beltrano@tecgraf.puc-rio.br", "sicrano@tecgraf.puc-rio.br" } body = "This is a test message. Please ignore." server = "local" -- connects to server "local" and sends a message to users -- "fulano@tecgraf.puc-rio.br" and "beltrano@tecgraf.puc-rio.br". -- "sicrano@tecgraf.puc-rio.br" receives a 'blind carbon copy' of the message. e = SMTP.mail(from, rcpt, headers, body, server)
The module cl-compat.lua implements a function mail that is compatible with the interface used by CGILua 3.2.
to: A comma-separated list of the e-mails of the recipients of the message. from: The email of the sender. subject: Optional message subject. message: Optional message body. cc: An optional comma-separated list of the e-mails of "carbon-copy" recipients. bcc: An optional comma-separated list of the e-mails of the "blind carbon-copy" recipients. mailserver: Address of SMTP server to be used.
The function returns nil if the message was sent successfully. In case of error, an error message is returned.
During the development of the HTTP, FTP and SMTP modules, some support routines became useful enough that they deserved to be placed in separate modules. The two modules described below are now supported on their own and will also be improved with time.
The module url.lua provides functions to parse, protect, and compose URLs, as well as functions to build absolute URLs from base and relative URLs, according to RFC 2396.
Returns a table with url parsed into all its components. A url is defined by the following grammar:
<url> ::= [<scheme>:][//<authority>][/<path>][;<params>][?<query>][#<fragment>]The returned table is of the form:
<authority> ::= [<userinfo>@]<host>[:<port>]
<userinfo> ::= <user>[:<password>]
<path> ::= {<segment>/}<segment>
parsed_url = {Examples:
url = string,
scheme = string,
authority = string,
path = string,
params = string,
query = string,
fragment = string,
userinfo = string,
host = string,
port = string,
user = string,
password = string
}
URL.build_url(parsed_url)parsed_url = URL.parse_url("http://www.puc-rio.br/~diego/index.lua?a=2#there") -- parsed_url = { -- scheme = "http", -- authority = "www.puc-rio.br", -- path = "/~diego/index.lua" -- query = "a=2", -- fragment = "there", -- host = "www.puc-rio.br", -- } parsed_url = URL.parse_url("ftp://root:passwd@unsafe.org/pub/virus.exe;type=i") -- parsed_url = { -- scheme = "ftp", -- authority = "root:passwd@unsafe.org", -- path = "/pub/virus.exe", -- params = "type=i", -- userinfo = "root:passwd", -- host = "unsafe.org", -- user = "root", -- password = "passwd", -- }
Rebuilds an URL from its parts. The lower level components, if specified take precedence over hight level components of the URL grammar. The accepted components are the same components returned by URL.parse_url, that is:
<url> ::= [<scheme>:][//<authority>][/<path>][;<params>][?<query>][#<fragment>]The function receives a table with the parsed_url to be reassembled and returns the corresponding URL as a result.
<authority> ::= [<userinfo>@]<host>[:<port>]
<userinfo> ::= <user>[:<password>]
<path> ::= {<segment>/}<segment>
URL.build_absolute(base, relative)
Builds an absolute URL from a base URL and a relative URL. The rules that govern the composition are fairly complex, and are described in detail in RFC 2396. The following examples come from the RFC and should give an idea of the rules.
Examples:
Within an object with a well-defined base URI ofURL.parse_path(path)http://a/b/c/d;p?qthe relative URI would be resolved as follows:g:h = g:h g = http://a/b/c/g ./g = http://a/b/c/g g/ = http://a/b/c/g/ /g = http://a/g //g = http://g ?y = http://a/b/c/?y g?y = http://a/b/c/g?y #s = http://a/b/c/d;p?q#s g#s = http://a/b/c/g#s g?y#s = http://a/b/c/g?y#s ;x = http://a/b/c/;x g;x = http://a/b/c/g;x g;x?y#s = http://a/b/c/g;x?y#s . = http://a/b/c/ ./ = http://a/b/c/ .. = http://a/b/ ../ = http://a/b/ ../g = http://a/b/g ../.. = http://a/ ../../ = http://a/ ../../g = http://a/g
Parses a path component into all its segments. Since some characters are reserved in URLs, their occurrences in the <path> component of a URL must be escaped. After parsing the segments, the function unescapes all of them, returning a list with all segments.
URL.build_path(segments, unsafe)
Builds a path component from a list of path segments. Before composition, any reserved characters found in a segment are escaped into their protected form, so that the resulting path is a valid URL path component. If unsafe is anything but nil, reserved characters are left untouched. The function returns the built <path> component.
The code.lua module offers routines to convert back and forth some common types of content encoding, including Base 64 and URL escaping. Base 64 is described in RFC 2045, URL escaping is described in RFC 2396.
Applies the Base 64 content coding to the string content. The result is a string with 76 characters maximum length lines. If the parameter single is set to anything but nil, the output is returned as a single line.
Examples:
Code.unbase64(content)code = Code.base64("diego:password") -- code = "ZGllZ286cGFzc3dvcmQ="
Removes the Base 64 content coding from the string content, and returns the result as a string.
Applies the URL escaping content coding to the string content. Each byte in content is encoded as a percent character followed by its two byte hexadecimal representation.
Examples:
Code.unescape(content)code = Code.escape("/#?;") -- code = "%2f%23%3f%3b"
Removes the URL escaping content coding from the string content, and returns the result as a string.
Applies the hexadecimal content coding to the string content. Each byte in content is encoded as its two byte hexadecimal representation.
Examples:
Code.unhexa(content)code = Code.hexa("\16\32\255") -- code = "1020ff"
Removes the hexadecimal content coding from the string content, and returns the result as a string.
home · download · what is · introduction · functions · modules · index
![]() | and | ![]() |
Last modified by Diego Nehab on Thu Sep 27 16:18:27 EST 2001 |