�ɲɾ�����ӯ�����һ��ˣ��������С���˴��ͣ�������P���ҹ��ñ˽��ά�Բ��������˸߸ԣ�������ơ��ҹ��ñ�����ά�Բ���ˡ���˳^�ӣ������ӡ� ���ͯj�ӣ��ƺ���ӣ� ? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!PK;1]ξffdns.htmlnu[ LuaSocket: DNS support

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


DNS

IPv4 name resolution functions dns.toip and dns.tohostname return all information obtained from the resolver in a table of the form:

resolved4 = {
  name = canonic-name,
  alias = alias-list,
  ip = ip-address-list
}

Note that the alias list can be empty.

The more general name resolution function dns.getaddrinfo, which supports both IPv6 and IPv4, returns all information obtained from the resolver in a table of the form:

resolved6 = {
  [1] = {
    family = family-name-1,
    addr = address-1
  },
  ...
  [n] = {
    family = family-name-n,
    addr = address-n
  }
}

Here, family contains the string "inet" for IPv4 addresses, and "inet6" for IPv6 addresses.

socket.dns.getaddrinfo(address)

Converts from host name to address.

Address can be an IPv4 or IPv6 address or host name.

The function returns a table with all information returned by the resolver. In case of error, the function returns nil followed by an error message.

socket.dns.gethostname()

Returns the standard host name for the machine as a string.

socket.dns.tohostname(address)

Converts from IPv4 address to host name.

Address can be an IP address or host name.

The function returns a string with the canonic host name of the given address, followed by a table with all information returned by the resolver. In case of error, the function returns nil followed by an error message.

socket.dns.toip(address)

Converts from host name to IPv4 address.

Address can be an IP address or host name.

Returns a string with the first IP address found for address, followed by a table with all information returned by the resolver. In case of error, the function returns nil followed by an error message.

PK;1]>- index.htmlnu[ LuaSocket: Network support for the Lua language

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


What is LuaSocket?

LuaSocket is a Lua extension library that is composed by two parts: a C core that provides support for the TCP and UDP transport layers, and a set of Lua modules that add support for functionality commonly needed by applications that deal with the Internet.

The core support has been implemented so that it is both efficient and simple to use. It is available to any Lua application once it has been properly initialized by the interpreter in use. The code has been tested and runs well on several Windows and UNIX platforms.

Among the support modules, the most commonly used implement the SMTP (sending e-mails), HTTP (WWW access) and FTP (uploading and downloading files) client protocols. These provide a very natural and generic interface to the functionality defined by each protocol. In addition, you will find that the MIME (common encodings), URL (anything you could possible want to do with one) and LTN12 (filters, sinks, sources and pumps) modules can be very handy.

The library is available under the same terms and conditions as the Lua language, the MIT license. The idea is that if you can use Lua in a project, you should also be able to use LuaSocket.

Copyright © 1999-2013 Diego Nehab. All rights reserved.
Author: Diego Nehab

Download

LuaSocket version 3.0-rc1 is now available for download! It is compatible with Lua 5.1 and 5.2, and has been tested on Windows XP, Linux, and Mac OS X. Chances are it works well on most UNIX distributions and Windows flavors.

The current version of the library can be found at the LuaSocket project page on GitHub. Besides the full C and Lua source code for the library, the distribution contains several examples, this user's manual and basic test procedures.

Take a look at the installation section of the manual to find out how to properly install the library.

Special thanks

This marks the first release of LuaSocket that wholeheartedly embraces the open-source development philosophy. After a long hiatus, Matthew Wild finally convinced me it was time for a release including IPv6 and Lua 5.2 support. It was more work than we anticipated. Special thanks to Sam Roberts, Florian Zeitz, and Paul Aurich, Liam Devine, Alexey Melnichuk, and everybody else that has helped bring this library back to life.

What's New

Main changes for LuaSocket 3.0-rc1 are IPv6 support and Lua 5.2 compatibility.

Old Versions

All previous versions of the LuaSocket library can be downloaded here. Although these versions are no longer supported, they are still available for those that have compatibility issues.

PK;1]b]%]%ftp.htmlnu[ LuaSocket: FTP support

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


FTP

FTP (File Transfer Protocol) is a protocol used to transfer files between hosts. The ftp namespace offers thorough support to FTP, under a simple interface. The implementation conforms to RFC 959.

High level functions are provided supporting the most common operations. These high level functions are implemented on top of a lower level interface. Using the low-level interface, users can easily create their own functions to access any operation supported by the FTP protocol. For that, check the implementation.

To really benefit from this module, a good understanding of LTN012, Filters sources and sinks is necessary.

To obtain the ftp namespace, run:

-- loads the FTP module and any libraries it requires
local ftp = require("socket.ftp")

URLs MUST conform to RFC 1738, that is, an URL is a string in the form:

[ftp://][<user>[:<password>]@]<host>[:<port>][/<path>][type=a|i]

The following constants in the namespace can be set to control the default behavior of the FTP module:

ftp.get(url)
ftp.get{
  host = string,
  sink = LTN12 sink,
  argument or path = string,
  [user = string,]
  [password = string]
  [command = string,]
  [port = number,]
  [type = string,]
  [step = LTN12 pump step,]
  [create = function]
}

The get function has two forms. The simple form has fixed functionality: it downloads the contents of a URL and returns it as a string. The generic form allows a lot more control, as explained below.

If the argument of the get function is a table, the function expects at least the fields host, sink, and one of argument or path (argument takes precedence). Host is the server to connect to. Sink is the simple LTN12 sink that will receive the downloaded data. Argument or path give the target path to the resource in the server. The optional arguments are the following:

If successful, the simple version returns the URL contents as a string, and the generic function returns 1. In case of error, both functions return nil and an error message describing the error.

-- load the ftp support
local ftp = require("socket.ftp")

-- Log as user "anonymous" on server "ftp.tecgraf.puc-rio.br",
-- and get file "lua.tar.gz" from directory "pub/lua" as binary.
f, e = ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i")
-- load needed modules
local ftp = require("socket.ftp")
local ltn12 = require("ltn12")
local url = require("socket.url")

-- a function that returns a directory listing
function nlst(u)
    local t = {}
    local p = url.parse(u)
    p.command = "nlst"
    p.sink = ltn12.sink.table(t)
    local r, e = ftp.get(p)
    return r and table.concat(t), e
end

ftp.put(url, content)
ftp.put{
  host = string,
  source = LTN12 sink,
  argument or path = string,
  [user = string,]
  [password = string]
  [command = string,]
  [port = number,]
  [type = string,]
  [step = LTN12 pump step,]
  [create = function]
}

The put function has two forms. The simple form has fixed functionality: it uploads a string of content into a URL. The generic form allows a lot more control, as explained below.

If the argument of the put function is a table, the function expects at least the fields host, source, and one of argument or path (argument takes precedence). Host is the server to connect to. Source is the simple LTN12 source that will provide the contents to be uploaded. Argument or path give the target path to the resource in the server. The optional arguments are the following:

Both functions return 1 if successful, or nil and an error message describing the reason for failure.

-- load the ftp support
local ftp = require("socket.ftp")

-- Log as user "fulano" on server "ftp.example.com",
-- using password "silva", and store a file "README" with contents 
-- "wrong password, of course"
f, e = ftp.put("ftp://fulano:silva@ftp.example.com/README", 
    "wrong password, of course")
-- load the ftp support
local ftp = require("socket.ftp")
local ltn12 = require("ltn12")

-- Log as user "fulano" on server "ftp.example.com",
-- using password "silva", and append to the remote file "LOG", sending the
-- contents of the local file "LOCAL-LOG"
f, e = ftp.put{
  host = "ftp.example.com", 
  user = "fulano",
  password = "silva",
  command = "appe",
  argument = "LOG",
  source = ltn12.source.file(io.open("LOCAL-LOG", "r"))
}
PK;1]I00introduction.htmlnu[ LuaSocket: Introduction to the core

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


Introduction

LuaSocket is a Lua extension library that is composed by two parts: a C core that provides support for the TCP and UDP transport layers, and a set of Lua modules that add support for the SMTP (sending e-mails), HTTP (WWW access) and FTP (uploading and downloading files) protocols and other functionality commonly needed by applications that deal with the Internet. This introduction is about the C core.

Communication in LuaSocket is performed via I/O objects. These can represent different network domains. Currently, support is provided for TCP and UDP, but nothing prevents other developers from implementing SSL, Local Domain, Pipes, File Descriptors etc. I/O objects provide a standard interface to I/O across different domains and operating systems.

The API design had two goals in mind. First, users experienced with the C API to sockets should feel comfortable using LuaSocket. Second, the simplicity and the feel of the Lua language should be preserved. To achieve these goals, the LuaSocket API keeps the function names and semantics the C API whenever possible, but their usage in Lua has been greatly simplified.

One of the simplifications is the receive pattern capability. Applications can read data from stream domains (such as TCP) line by line, block by block, or until the connection is closed. All I/O reads are buffered and the performance differences between different receive patterns are negligible.

Another advantage is the flexible timeout control mechanism. As in C, all I/O operations are blocking by default. For example, the send, receive and accept methods of the TCP domain will block the caller application until the operation is completed (if ever!). However, with a call to the settimeout method, an application can specify upper limits on the time it can be blocked by LuaSocket (the "total" timeout), on the time LuaSocket can internally be blocked by any OS call (the "block" timeout) or a combination of the two. Each LuaSocket call might perform several OS calls, so that the two timeout values are not equivalent.

Finally, the host name resolution is transparent, meaning that most functions and methods accept both IP addresses and host names. In case a host name is given, the library queries the system's resolver and tries the main IP address returned. Note that direct use of IP addresses is more efficient, of course. The toip and tohostname functions from the DNS module are provided to convert between host names and IP addresses.

Together, these changes make network programming in LuaSocket much simpler than it is in C, as the following sections will show.

TCP

TCP (Transfer Control Protocol) is reliable stream protocol. In other words, applications communicating through TCP can send and receive data as an error free stream of bytes. Data is split in one end and reassembled transparently on the other end. There are no boundaries in the data transfers. The library allows users to read data from the sockets in several different granularities: patterns are available for lines, arbitrary sized blocks or "read up to connection closed", all with good performance.

The library distinguishes three types of TCP sockets: master, client and server sockets.

Master sockets are newly created TCP sockets returned by the function socket.tcp. A master socket is transformed into a server socket after it is associated with a local address by a call to the bind method followed by a call to the listen. Conversely, a master socket can be changed into a client socket with the method connect, which associates it with a remote address.

On server sockets, applications can use the accept method to wait for a client connection. Once a connection is established, a client socket object is returned representing this connection. The other methods available for server socket objects are getsockname, setoption, settimeout, and close.

Client sockets are used to exchange data between two applications over the Internet. Applications can call the methods send and receive to send and receive data. The other methods available for client socket objects are getsockname, getpeername, setoption, settimeout, shutdown, and close.

Example:

A simple echo server, using LuaSocket. The program binds to an ephemeral port (one that is chosen by the operating system) on the local host and awaits client connections on that port. When a connection is established, the program reads a line from the remote end and sends it back, closing the connection immediately. You can test it using the telnet program.

-- load namespace
local socket = require("socket")
-- create a TCP socket and bind it to the local host, at any port
local server = assert(socket.bind("*", 0))
-- find out which port the OS chose for us
local ip, port = server:getsockname()
-- print a message informing what's up
print("Please telnet to localhost on port " .. port)
print("After connecting, you have 10s to enter a line to be echoed")
-- loop forever waiting for clients
while 1 do
  -- wait for a connection from any client
  local client = server:accept()
  -- make sure we don't block waiting for this client's line
  client:settimeout(10)
  -- receive the line
  local line, err = client:receive()
  -- if there was no error, send it back to the client
  if not err then client:send(line .. "\n") end
  -- done with client, close the object
  client:close()
end

UDP

UDP (User Datagram Protocol) is a non-reliable datagram protocol. In other words, applications communicating through UDP send and receive data as independent blocks, which are not guaranteed to reach the other end. Even when they do reach the other end, they are not guaranteed to be error free. Data transfers are atomic, one datagram at a time. Reading only part of a datagram discards the rest, so that the following read operation will act on the next datagram. The advantages are in simplicity (no connection setup) and performance (no error checking or error correction).

Note that although no guarantees are made, these days networks are so good that, under normal circumstances, few errors happen in practice.

An UDP socket object is created by the socket.udp function. UDP sockets do not need to be connected before use. The method sendto can be used immediately after creation to send a datagram to IP address and port. Host names are not allowed because performing name resolution for each packet would be forbiddingly slow. Methods receive and receivefrom can be used to retrieve datagrams, the latter returning the IP and port of the sender as extra return values (thus being slightly less efficient).

When communication is performed repeatedly with a single peer, an application should call the setpeername method to specify a permanent partner. Methods sendto and receivefrom can no longer be used, but the method send can be used to send data directly to the peer, and the method receive will only return datagrams originating from that peer. There is about 30% performance gain due to this practice.

To associate an UDP socket with a local address, an application calls the setsockname method before sending any datagrams. Otherwise, the socket is automatically bound to an ephemeral address before the first data transmission and once bound the local address cannot be changed. The other methods available for UDP sockets are getpeername, getsockname, settimeout, setoption and close.

Example:

A simple daytime client, using LuaSocket. The program connects to a remote server and tries to retrieve the daytime, printing the answer it got or an error message.

-- change here to the host an port you want to contact
local host, port = "localhost", 13
-- load namespace
local socket = require("socket")
-- convert host name to ip address
local ip = assert(socket.dns.toip(host))
-- create a new UDP object
local udp = assert(socket.udp())
-- contact daytime host
assert(udp:sendto("anything", ip, port))
-- retrieve the answer and print results
io.write(assert(udp:receive()))

Support modules

Although not covered in the introduction, LuaSocket offers much more than TCP and UDP functionality. As the library evolved, support for HTTP, FTP, and SMTP were built on top of these. These modules and many others are covered by the reference manual.

PK;1]ߝreference.htmlnu[ LuaSocket: Index to reference manual

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


Reference

DNS (in socket)
getaddrinfo, gethostname, tohostname, toip.
FTP
get, put.
HTTP
request.
LTN12
filter: chain, cycle.
pump: all, step.
sink: chain, error, file, null, simplify, table.
source: cat, chain, empty, error, file, simplify, string.
MIME
high-level: decode, encode, normalize, stuff, wrap.
low-level: b64, dot, eol, qp, qpwrp, unb64, unqp, wrp.
SMTP
message, send.
Socket
bind, connect, connect4, connect6, _DEBUG, dns, gettime, headers.canonic, newtry, protect, select, sink, skip, sleep, _SETSIZE, source, tcp, tcp6, try, udp, udp6, _VERSION.
TCP (in socket)
accept, bind, close, connect, dirty, getfd, getoption, getpeername, getsockname, getstats, listen, receive, send, setfd, setoption, setstats, settimeout, shutdown.
UDP (in socket)
close, getoption, getpeername, getsockname, receive, receivefrom, send, sendto, setpeername, setsockname, setoption, settimeout.
URL
absolute, build, build_path, escape, parse, parse_path, unescape.
PK;1]l-- luasocket.pngnu[PNG  IHDRL\-SIDATx}ytTEkFJB Q>uqA~:Χ~93Ό 0Dp?$ Q%İ$$BHBJI,^UѝtBH{t^Wު{oݭ~~$@?Ïg ?G3H~;Cp߾ S=Fqw{cO!탽%&p:ހ||w\|xb#`A)B|H/XSٳRp8t:?l2cWX,X,mAK߉E=!lJMŁ 4DDtq_,H;ߵB円 .?~`dY6LcHQvn[֟'/VTqR9U4709璄[Z;wm^_S[" ]tt@ZZ}7/Q'2co Pb"ƍe.]$)**JcgϞI&F_8}@^_]} Hpd4thk͹JB Z"rEEE\\$I'Eq*4Fc!322L&JxSP m}4ZFGQeqVZ9֮s@sBP\y#Tg֥Ko^^^>wܩS wXo:݋ե:lMMOV#" Vs_Y)Κ5K?>YvFHwٚ[tc93gϜnwZ%GJT}޴/)6iE@AA-s߁D̙K.Mh%(221&$V5A0F`PO2m/^qF`W͐kbRXXh6U-ljŻPtURlJeժm mmmA@'&nSXߠA11IScNm6PdS8焐Gn޼9##Cj8*F K/B!T_ߚ[ycǪΝkRP<$@"D2qb)b1+pa ~~IS,0عs?ydU#aŭh>ȑJ @ XY!?)eW*+L`AʂC y" >>H׀1m ;ye˖=Ze;]^1F#Y{_W%6[ aL11 0o?~^OI*;_nDpIBg29yI%ʕ+W\ILLb# x# Ӎ!QJzuӫ}jF&kkj`' 1b>iR#+m7p\!!! `_h""|#}m51 dRN)@06;WrÇ~}@VƘb‚ h' N<{</d.vWZ'/|=>#cXrr {-*Yy>)$?E}9]m錳f%-\2qbTtlQʚl]۲! !=c$(Jĉ@@"d+٬s^Y6 @m{lz,;ׅ >g pﳊۋ^xB̔r.h0mZ޽ =47 P/1>m amkkk;պ)G_1hع[''RvW2%SV>J(TaW]:]Jat:R_o _u7DgڵKN z`#2,>pa,SX~A:{.lذWSj9iu_GT oooߵkWIII؇nwlڴ)99yڴi΀&I83c贁`{!T-͜9E9G0ƆΦF1Pl㽘\RPPtVN8QSS3g u'>@wׄr1pG9T{Gso^DiqSOoEE$a/o6//O @sM0abߠGwWU5/7e5k)e:R@^  ]]]~e ?~B]G-֩(|0J޲fBL!Ĺ=3sɢ3' hKزsg!&)m~xevBu c5s% 75^x! @r*}玔oOB LA; )__E`=x]@}}׿f9Qѧ̜9X#U}ؠ cTR9!?uGN8vQqApyy;0n\ cbbbcct1>Dcc!N;"PT lLHV>ϋ@)tA{,**:t(x#$anT:l" |x;.^a߷˒=c@rrrQQh{KZx8o)-*EH__`kn 59 q瀱KYY%Y.rSSSv^:66 x^l24vAiӦEEEAWM88"0D#yE3!~V}܍t0?Ib75!FI>ne \Xʔ)SԜ wֶ8_Q֮OcRLseZ]H @--f]~$]1`pA FN7bޢ Z~~~ESqqAqqAnU A`C^0. 0}O^|q-" ιM$UKBb_n݊+=8J QZZ=AQYc&>tbb,zWv!J>!QmΝ Uq.GEYY:j@aAUUʫeeg6_N);r1E)Ϝ9:XrLm6bJLL ㏟|Iq 7b4<%QǍ˻xn/DІ 5fSFXNʫlP0ȑ>FE)u8%((:""bȑϟx А .~ΐ+T̔vJwR% sOJ^^BF$H? J'7/F}BqS`("]w (NJwpiJ9s "rccl5 OLJJJNN32y..cii1דj/gHS&27G Dqq-C 4hԩ"'44T.~L@0 }T zOX=Y`2Iw-.**eysX"s9\9{͚t)kC !(,5kȜ9 ^<+I$C3f ەIZ67/FQXBB/~1f޼Dظ஻CCPw!11Tڵ?Om;SWעד R3`ۍFhD_Fnk St"X`+ pY>?q΢?/|7=qƌ \ܚ_{ cη 5_TF9I11Pmꬬ+0c FsO$UUYZ$cs|Rl*B t:YO:uԩzٜ.#Nn ߺu%K&)VWOVʼniV9AABl-n=qQ>99N"8!z'F#]1ztZ TFill|뭷VXA)u?ǂO)JKhhO>-b(lذW^`s1 ]O>.aq%ɟ3!&!:5ϢGΧL?N 1#$?ajwర0 ŽM](I߽)ƈNdD !~{JV5#`^  4!79r$%%f91c,\н[Vx"R=tuM@tϱ/JGF殈 Cڽ{9sfС .z+<<<00d2 NGbٜY5 3 ;xœ9dY gѠXVֲٳRbeeݻKKKǏ_QQ`dmmNսq~[tJgMa"Yxƭt:\ȹ={.TDGGXbŊhii*.Nng 9|pSS3C8`EcF=MzV$ Q?޹jUH4>۱cGQQѤIMSTTecccEg}!)U#c>J0Ɯ_?LT^8;f,{IOO;MНwy劷@.=$Ĵb1![R7eJ;,^r'쫆^/2XT59q™({o&e.SwX㏏GKp"bY$ tʉL]9ϔhmmϊtӧ.p6Q-q$aYs&?ĉ\}1!(-c?]w% !b;l6ᇢRjw[ 2/.]Rd2y:Do(,$ĴlXdg\!D=Gc9]z',8_x^$)77w_PP ߎo$H5nذj>*meq`8eŊݧO#dXr!wFJ)RRb׭:Pcc),++琐/@e??{ĈZ+M!ЫWqqqK.JU5ەw9 סb |V _ | !˗/?tժUv= @5vtbaÆٳŋGb-;FݩSc- ?uf %`zw ~~+ӷlY54r0GlQQAS 7/qĘhiƿ/sOZZ6&Ş7|3!!t/ɓo}L E(///"""::;!)];]ᇆ￯+,zReYs&:8/&2lXXjjQÆ 0tZjdgg8pw:B---&)::>PeĈ/^|G !.Лgʻim۶-[,%%E] Y(1zt8t}lkn77l6ET(-CPejĩZ|0 MMM9rfQJLxgy&77!!!{] W ⋯;={ף7<#@D/E~,TMP%՝ 7`%&&744DEEM0aȐ!eee۷o/~1v.-C-9sfK,5jjo=UdUwv}PuuufffsssBBĉE4iݺuK,QE,Ӡ`0t: Ԫ%]k} ZkՒ$ߎ#ͽ:2Mu~חj8ڽ+w&ɲ̝gJtСɓ'S8M![ZN\裏0 Q8$КuA3ZWW̞=;55ի{"##=mDSsii_|QQQ1vYf#Ψ\UFg`k׮\ɤ(JXXXFFFll }U2={vǎIII-r&^Q-//=ztzznsҥਨ(9ZފPǣVbTEQ.+cTcVGܐճ*v{NNN~~~}}}BBw}#,6M @Sgf[vb0aBRR8rBhgӻ)."o+11;)#.BŽ(Gq={ɓ'ϟ?oZ222zwQ"477WVV?>!!Aez*BM[Zpwj$IÆ >|(ΝsG4hP``b  -cPJE#u'cY !.=QU>upZ NF"Iرcfɲrh1ׯ_"+WahȐ!Bހ٪whveVV:`m BӠXp2=-DOw!G=mgn-Zkd߲CW~RJ/ LuaSocket: The socket namespace

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


The socket namespace

The socket namespace contains the core functionality of LuaSocket.

To obtain the socket namespace, run:

-- loads the socket module 
local socket = require("socket")

socket.bind(address, port [, backlog])

This function is a shortcut that creates and returns a TCP server object bound to a local address and port, ready to accept client connections. Optionally, user can also specify the backlog argument to the listen method (defaults to 32).

Note: The server object returned will have the option "reuseaddr" set to true.

socket.connect[46](address, port [, locaddr] [, locport] [, family])

This function is a shortcut that creates and returns a TCP client object connected to a remote address at a given port. Optionally, the user can also specify the local address and port to bind (locaddr and locport), or restrict the socket family to "inet" or "inet6". Without specifying family to connect, whether a tcp or tcp6 connection is created depends on your system configuration. Two variations of connect are defined as simple helper functions that restrict the family, socket.connect4 and socket.connect6.

socket._DEBUG

This constant is set to true if the library was compiled with debug support.

socket.gettime()

Returns the time in seconds, relative to the origin of the universe. You should subtract the values returned by this function to get meaningful values.

t = socket.gettime()
-- do stuff
print(socket.gettime() - t .. " seconds elapsed")

socket.headers.canonic

The socket.headers.canonic table is used by the HTTP and SMTP modules to translate from lowercase field names back into their canonic capitalization. When a lowercase field name exists as a key in this table, the associated value is substituted in whenever the field name is sent out.

You can obtain the headers namespace if case run-time modifications are required by running:

-- loads the headers module 
local headers = require("headers")

socket.newtry(finalizer)

Creates and returns a clean try function that allows for cleanup before the exception is raised.

Finalizer is a function that will be called before try throws the exception. It will be called in protected mode.

The function returns your customized try function.

Note: This idea saved a lot of work with the implementation of protocols in LuaSocket:

foo = socket.protect(function()
    -- connect somewhere
    local c = socket.try(socket.connect("somewhere", 42))
    -- create a try function that closes 'c' on error
    local try = socket.newtry(function() c:close() end)
    -- do everything reassured c will be closed 
    try(c:send("hello there?\r\n"))
    local answer = try(c:receive())
    ...
    try(c:send("good bye\r\n"))
    c:close()
end)

socket.protect(func)

Converts a function that throws exceptions into a safe function. This function only catches exceptions thrown by the try and newtry functions. It does not catch normal Lua errors.

Func is a function that calls try (or assert, or error) to throw exceptions.

Returns an equivalent function that instead of throwing exceptions, returns nil followed by an error message.

Note: Beware that if your function performs some illegal operation that raises an error, the protected function will catch the error and return it as a string. This is because the try function uses errors as the mechanism to throw exceptions.

socket.select(recvt, sendt [, timeout])

Waits for a number of sockets to change status.

Recvt is an array with the sockets to test for characters available for reading. Sockets in the sendt array are watched to see if it is OK to immediately write on them. Timeout is the maximum amount of time (in seconds) to wait for a change in status. A nil, negative or omitted timeout value allows the function to block indefinitely. Recvt and sendt can also be empty tables or nil. Non-socket values (or values with non-numeric indices) in the arrays will be silently ignored.

The function returns a list with the sockets ready for reading, a list with the sockets ready for writing and an error message. The error message is "timeout" if a timeout condition was met and nil otherwise. The returned tables are doubly keyed both by integers and also by the sockets themselves, to simplify the test if a specific socket has changed status.

Note: : select can monitor a limited number of sockets, as defined by the constant socket._SETSIZE. This number may be as high as 1024 or as low as 64 by default, depending on the system. It is usually possible to change this at compile time. Invoking select with a larger number of sockets will raise an error.

Important note: a known bug in WinSock causes select to fail on non-blocking TCP sockets. The function may return a socket as writable even though the socket is not ready for sending.

Another important note: calling select with a server socket in the receive parameter before a call to accept does not guarantee accept will return immediately. Use the settimeout method or accept might block forever.

Yet another note: If you close a socket and pass it to select, it will be ignored.

Using select with non-socket objects: Any object that implements getfd and dirty can be used with select, allowing objects from other libraries to be used within a socket.select driven loop.

socket.sink(mode, socket)

Creates an LTN12 sink from a stream socket object.

Mode defines the behavior of the sink. The following options are available:

  • "http-chunked": sends data through socket after applying the chunked transfer coding, closing the socket when done;
  • "close-when-done": sends all received data through the socket, closing the socket when done;
  • "keep-open": sends all received data through the socket, leaving it open when done.

Socket is the stream socket object used to send the data.

The function returns a sink with the appropriate behavior.

socket.skip(d [, ret1, ret2 ... retN])

Drops a number of arguments and returns the remaining.

D is the number of arguments to drop. Ret1 to retN are the arguments.

The function returns retd+1 to retN.

Note: This function is useful to avoid creation of dummy variables:

-- get the status code and separator from SMTP server reply 
local code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))

socket.sleep(time)

Freezes the program execution during a given amount of time.

Time is the number of seconds to sleep for. If time is negative, the function returns immediately.

socket.source(mode, socket [, length])

Creates an LTN12 source from a stream socket object.

Mode defines the behavior of the source. The following options are available:

  • "http-chunked": receives data from socket and removes the chunked transfer coding before returning the data;
  • "by-length": receives a fixed number of bytes from the socket. This mode requires the extra argument length;
  • "until-closed": receives data from a socket until the other side closes the connection.

Socket is the stream socket object used to receive the data.

The function returns a source with the appropriate behavior.

socket._SETSIZE

The maximum number of sockets that the select function can handle.

socket.try(ret1 [, ret2 ... retN])

Throws an exception in case of error. The exception can only be caught by the protect function. It does not explode into an error message.

Ret1 to retN can be arbitrary arguments, but are usually the return values of a function call nested with try.

The function returns ret1 to retN if ret1 is not nil. Otherwise, it calls error passing ret2.

-- connects or throws an exception with the appropriate error message
c = socket.try(socket.connect("localhost", 80))

socket._VERSION

This constant has a string describing the current LuaSocket version.

PK;1]=]aڸ** ltn12.htmlnu[ LuaSocket: LTN12 module

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


LTN12

The ltn12 namespace implements the ideas described in LTN012, Filters sources and sinks. This manual simply describes the functions. Please refer to the LTN for a deeper explanation of the functionality provided by this module.

To obtain the ltn12 namespace, run:

-- loads the LTN21 module
local ltn12 = require("ltn12")

Filters

ltn12.filter.chain(filter1, filter2 [, ... filterN])

Returns a filter that passes all data it receives through each of a series of given filters.

Filter1 to filterN are simple filters.

The function returns the chained filter.

The nesting of filters can be arbitrary. For instance, the useless filter below doesn't do anything but return the data that was passed to it, unaltered.

-- load required modules
local ltn12 = require("ltn12")
local mime = require("mime")

-- create a silly identity filter
id = ltn12.filter.chain(
  mime.encode("quoted-printable"),
  mime.encode("base64"),
  mime.decode("base64"),
  mime.decode("quoted-printable")
)

ltn12.filter.cycle(low [, ctx, extra])

Returns a high-level filter that cycles though a low-level filter by passing it each chunk and updating a context between calls.

Low is the low-level filter to be cycled, ctx is the initial context and extra is any extra argument the low-level filter might take.

The function returns the high-level filter.

-- load the ltn12 module
local ltn12 = require("ltn12")

-- the base64 mime filter factory
encodet['base64'] = function()
    return ltn12.filter.cycle(b64, "")
end

Pumps

ltn12.pump.all(source, sink)

Pumps all data from a source to a sink.

If successful, the function returns a value that evaluates to true. In case of error, the function returns a false value, followed by an error message.

ltn12.pump.step(source, sink)

Pumps one chunk of data from a source to a sink.

If successful, the function returns a value that evaluates to true. In case of error, the function returns a false value, followed by an error message.

Sinks

ltn12.sink.chain(filter, sink)

Creates and returns a new sink that passes data through a filter before sending it to a given sink.

ltn12.sink.error(message)

Creates and returns a sink that aborts transmission with the error message.

ltn12.sink.file(handle, message)

Creates a sink that sends data to a file.

Handle is a file handle. If handle is nil, message should give the reason for failure.

The function returns a sink that sends all data to the given handle and closes the file when done, or a sink that aborts the transmission with the error message

In the following example, notice how the prototype is designed to fit nicely with the io.open function.

-- load the ltn12 module
local ltn12 = require("ltn12")

-- copy a file
ltn12.pump.all(
  ltn12.source.file(io.open("original.png", "rb")),
  ltn12.sink.file(io.open("copy.png", "wb"))
)

ltn12.sink.null()

Returns a sink that ignores all data it receives.

ltn12.sink.simplify(sink)

Creates and returns a simple sink given a fancy sink.

ltn12.sink.table([table])

Creates a sink that stores all chunks in a table. The chunks can later be efficiently concatenated into a single string.

Table is used to hold the chunks. If nil, the function creates its own table.

The function returns the sink and the table used to store the chunks.

-- load needed modules
local http = require("socket.http")
local ltn12 = require("ltn12")

-- a simplified http.get function
function http.get(u)
  local t = {}
  local respt = request{
    url = u,
    sink = ltn12.sink.table(t)
  }
  return table.concat(t), respt.headers, respt.code
end

Sources

ltn12.source.cat(source1 [, source2, ..., sourceN])

Creates a new source that produces the concatenation of the data produced by a number of sources.

Source1 to sourceN are the original sources.

The function returns the new source.

ltn12.source.chain(source, filter)

Creates a new source that passes data through a filter before returning it.

The function returns the new source.

ltn12.source.empty()

Creates and returns an empty source.

ltn12.source.error(message)

Creates and returns a source that aborts transmission with the error message.

ltn12.source.file(handle, message)

Creates a source that produces the contents of a file.

Handle is a file handle. If handle is nil, message should give the reason for failure.

The function returns a source that reads chunks of data from given handle and returns it to the user, closing the file when done, or a source that aborts the transmission with the error message

In the following example, notice how the prototype is designed to fit nicely with the io.open function.

-- load the ltn12 module
local ltn12 = require("ltn12")

-- copy a file
ltn12.pump.all(
  ltn12.source.file(io.open("original.png", "rb")),
  ltn12.sink.file(io.open("copy.png", "wb"))
)

ltn12.source.simplify(source)

Creates and returns a simple source given a fancy source.

ltn12.source.string(string)

Creates and returns a source that produces the contents of a string, chunk by chunk.

PK;1]~@P7P7 mime.htmlnu[ LuaSocket: MIME module

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


MIME

The mime namespace offers filters that apply and remove common content transfer encodings, such as Base64 and Quoted-Printable. It also provides functions to break text into lines and change the end-of-line convention. MIME is described mainly in RFC 2045, 2046, 2047, 2048, and 2049.

All functionality provided by the MIME module follows the ideas presented in LTN012, Filters sources and sinks.

To obtain the mime namespace, run:

-- loads the MIME module and everything it requires
local mime = require("mime")

High-level filters

mime.normalize([marker])

Converts most common end-of-line markers to a specific given marker.

Marker is the new marker. It defaults to CRLF, the canonic end-of-line marker defined by the MIME standard.

The function returns a filter that performs the conversion.

Note: There is no perfect solution to this problem. Different end-of-line markers are an evil that will probably plague developers forever. This function, however, will work perfectly for text created with any of the most common end-of-line markers, i.e. the Mac OS (CR), the Unix (LF), or the DOS (CRLF) conventions. Even if the data has mixed end-of-line markers, the function will still work well, although it doesn't guarantee that the number of empty lines will be correct.

mime.decode("base64")
mime.decode("quoted-printable")

Returns a filter that decodes data from a given transfer content encoding.

mime.encode("base64")
mime.encode("quoted-printable" [, mode])

Returns a filter that encodes data according to a given transfer content encoding.

In the Quoted-Printable case, the user can specify whether the data is textual or binary, by passing the mode strings "text" or "binary". Mode defaults to "text".

Although both transfer content encodings specify a limit for the line length, the encoding filters do not break text into lines (for added flexibility). Below is a filter that converts binary data to the Base64 transfer content encoding and breaks it into lines of the correct size.

base64 = ltn12.filter.chain(
  mime.encode("base64"),
  mime.wrap("base64")
)

Note: Text data has to be converted to canonic form before being encoded.

base64 = ltn12.filter.chain(
  mime.normalize(),
  mime.encode("base64"),
  mime.wrap("base64")
)

mime.stuff()

Creates and returns a filter that performs stuffing of SMTP messages.

Note: The smtp.send function uses this filter automatically. You don't need to chain it with your source, or apply it to your message body.

mime.wrap("text" [, length])
mime.wrap("base64")
mime.wrap("quoted-printable")

Returns a filter that breaks data into lines.

The "text" line-wrap filter simply breaks text into lines by inserting CRLF end-of-line markers at appropriate positions. Length defaults 76. The "base64" line-wrap filter works just like the default "text" line-wrap filter with default length. The function can also wrap "quoted-printable" lines, taking care not to break lines in the middle of an escaped character. In that case, the line length is fixed at 76.

For example, to create an encoding filter for the Quoted-Printable transfer content encoding of text data, do the following:

qp = ltn12.filter.chain(
  mime.normalize(),
  mime.encode("quoted-printable"),
  mime.wrap("quoted-printable")
)

Note: To break into lines with a different end-of-line convention, apply a normalization filter after the line break filter.

Low-level filters

A, B = mime.b64(C [, D])

Low-level filter to perform Base64 encoding.

A is the encoded version of the largest prefix of C..D that can be encoded unambiguously. B has the remaining bytes of C..D, before encoding. If D is nil, A is padded with the encoding of the remaining bytes of C.

Note: The simplest use of this function is to encode a string into it's Base64 transfer content encoding. Notice the extra parenthesis around the call to mime.b64, to discard the second return value.

print((mime.b64("diego:password")))
--> ZGllZ286cGFzc3dvcmQ=

A, n = mime.dot(m [, B])

Low-level filter to perform SMTP stuffing and enable transmission of messages containing the sequence "CRLF.CRLF".

A is the stuffed version of B. 'n' gives the number of characters from the sequence CRLF seen in the end of B. 'm' should tell the same, but for the previous chunk.

Note: The message body is defined to begin with an implicit CRLF. Therefore, to stuff a message correctly, the first m should have the value 2.

print((string.gsub(mime.dot(2, ".\r\nStuffing the message.\r\n.\r\n."), "\r\n", "\\n")))
--> ..\nStuffing the message.\n..\n..

Note: The smtp.send function uses this filter automatically. You don't need to apply it again.

A, B = mime.eol(C [, D, marker])

Low-level filter to perform end-of-line marker translation. For each chunk, the function needs to know if the last character of the previous chunk could be part of an end-of-line marker or not. This is the context the function receives besides the chunk. An updated version of the context is returned after each new chunk.

A is the translated version of D. C is the ASCII value of the last character of the previous chunk, if it was a candidate for line break, or 0 otherwise. B is the same as C, but for the current chunk. Marker gives the new end-of-line marker and defaults to CRLF.

-- translates the end-of-line marker to UNIX
unix = mime.eol(0, dos, "\n") 

A, B = mime.qp(C [, D, marker])

Low-level filter to perform Quoted-Printable encoding.

A is the encoded version of the largest prefix of C..D that can be encoded unambiguously. B has the remaining bytes of C..D, before encoding. If D is nil, A is padded with the encoding of the remaining bytes of C. Throughout encoding, occurrences of CRLF are replaced by the marker, which itself defaults to CRLF.

Note: The simplest use of this function is to encode a string into it's Quoted-Printable transfer content encoding. Notice the extra parenthesis around the call to mime.qp, to discard the second return value.

print((mime.qp("ma")))
--> ma=E7=E3=

A, m = mime.qpwrp(n [, B, length])

Low-level filter to break Quoted-Printable text into lines.

A is a copy of B, broken into lines of at most length bytes (defaults to 76). 'n' should tell how many bytes are left for the first line of B and 'm' returns the number of bytes left in the last line of A.

Note: Besides breaking text into lines, this function makes sure the line breaks don't fall in the middle of an escaped character combination. Also, this function only breaks lines that are bigger than length bytes.

A, B = mime.unb64(C [, D])

Low-level filter to perform Base64 decoding.

A is the decoded version of the largest prefix of C..D that can be decoded unambiguously. B has the remaining bytes of C..D, before decoding. If D is nil, A is the empty string and B returns whatever couldn't be decoded.

Note: The simplest use of this function is to decode a string from it's Base64 transfer content encoding. Notice the extra parenthesis around the call to mime.unqp, to discard the second return value.

print((mime.unb64("ZGllZ286cGFzc3dvcmQ=")))
--> diego:password

A, B = mime.unqp(C [, D])

Low-level filter to remove the Quoted-Printable transfer content encoding from data.

A is the decoded version of the largest prefix of C..D that can be decoded unambiguously. B has the remaining bytes of C..D, before decoding. If D is nil, A is augmented with the encoding of the remaining bytes of C.

Note: The simplest use of this function is to decode a string from it's Quoted-Printable transfer content encoding. Notice the extra parenthesis around the call to mime.unqp, to discard the second return value.

print((mime.qp("ma=E7=E3=")))
--> ma

A, m = mime.wrp(n [, B, length])

Low-level filter to break text into lines with CRLF marker. Text is assumed to be in the normalize form.

A is a copy of B, broken into lines of at most length bytes (defaults to 76). 'n' should tell how many bytes are left for the first line of B and 'm' returns the number of bytes left in the last line of A.

Note: This function only breaks lines that are bigger than length bytes. The resulting line length does not include the CRLF marker.

PK;1]4;BBudp.htmlnu[ LuaSocket: UDP support

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


UDP

socket.udp()

Creates and returns an unconnected IPv4 UDP object. Unconnected objects support the sendto, receive, receivefrom, getoption, getsockname, setoption, settimeout, setpeername, setsockname, and close. The setpeername is used to connect the object.

In case of success, a new unconnected UDP object returned. In case of error, nil is returned, followed by an error message.

socket.udp6()

Creates and returns an unconnected IPv6 UDP object. Unconnected objects support the sendto, receive, receivefrom, getoption, getsockname, setoption, settimeout, setpeername, setsockname, and close. The setpeername is used to connect the object.

In case of success, a new unconnected UDP object returned. In case of error, nil is returned, followed by an error message.

Note: The TCP object returned will have the option "ipv6-v6only" set to true.

connected:close()
unconnected:close()

Closes a UDP object. The internal socket used by the object is closed and the local address to which the object was bound is made available to other applications. No further operations (except for further calls to the close method) are allowed on a closed socket.

Note: It is important to close all used sockets once they are not needed, since, in many systems, each socket uses a file descriptor, which are limited system resources. Garbage-collected objects are automatically closed before destruction, though.

connected:getpeername()

Retrieves information about the peer associated with a connected UDP object.

Returns a string with the IP address of the peer, the port number that peer is using for the connection, and a string with the family ("inet" or "inet6"). In case of error, the method returns nil.

Note: It makes no sense to call this method on unconnected objects.

connected:getsockname()
unconnected:getsockname()

Returns the local address information associated to the object.

The method returns a string with local IP address, a number with the local port, and a string with the family ("inet" or "inet6"). In case of error, the method returns nil.

Note: UDP sockets are not bound to any address until the setsockname or the sendto method is called for the first time (in which case it is bound to an ephemeral port and the wild-card address).

connected:receive([size])
unconnected:receive([size])

Receives a datagram from the UDP object. If the UDP object is connected, only datagrams coming from the peer are accepted. Otherwise, the returned datagram can come from any host.

The optional size parameter specifies the maximum size of the datagram to be retrieved. If there are more than size bytes available in the datagram, the excess bytes are discarded. If there are less then size bytes available in the current datagram, the available bytes are returned. If size is omitted, the maximum datagram size is used (which is currently limited by the implementation to 8192 bytes).

In case of success, the method returns the received datagram. In case of timeout, the method returns nil followed by the string 'timeout'.

unconnected:receivefrom([size])

Works exactly as the receive method, except it returns the IP address and port as extra return values (and is therefore slightly less efficient).

connected:getoption()
unconnected:getoption()

Gets an option value from the UDP object. See setoption for description of the option names and values.

Option is a string with the option name.

  • 'dontroute'
  • 'broadcast'
  • 'reuseaddr'
  • 'reuseport'
  • 'ip-multicast-loop'
  • 'ipv6-v6only'
  • 'ip-multicast-if'
  • 'ip-multicast-ttl'
  • 'ip-add-membership'
  • 'ip-drop-membership'

The method returns the option value in case of success, or nil followed by an error message otherwise.

connected:send(datagram)

Sends a datagram to the UDP peer of a connected object.

Datagram is a string with the datagram contents. The maximum datagram size for UDP is 64K minus IP layer overhead. However datagrams larger than the link layer packet size will be fragmented, which may deteriorate performance and/or reliability.

If successful, the method returns 1. In case of error, the method returns nil followed by an error message.

Note: In UDP, the send method never blocks and the only way it can fail is if the underlying transport layer refuses to send a message to the specified address (i.e. no interface accepts the address).

unconnected:sendto(datagram, ip, port)

Sends a datagram to the specified IP address and port number.

Datagram is a string with the datagram contents. The maximum datagram size for UDP is 64K minus IP layer overhead. However datagrams larger than the link layer packet size will be fragmented, which may deteriorate performance and/or reliability. Ip is the IP address of the recipient. Host names are not allowed for performance reasons. Port is the port number at the recipient.

If successful, the method returns 1. In case of error, the method returns nil followed by an error message.

Note: In UDP, the send method never blocks and the only way it can fail is if the underlying transport layer refuses to send a message to the specified address (i.e. no interface accepts the address).

connected:setpeername('*')
unconnected:setpeername(address, port)

Changes the peer of a UDP object. This method turns an unconnected UDP object into a connected UDP object or vice versa.

For connected objects, outgoing datagrams will be sent to the specified peer, and datagrams received from other peers will be discarded by the OS. Connected UDP objects must use the send and receive methods instead of sendto and receivefrom.

Address can be an IP address or a host name. Port is the port number. If address is '*' and the object is connected, the peer association is removed and the object becomes an unconnected object again. In that case, the port argument is ignored.

In case of error the method returns nil followed by an error message. In case of success, the method returns 1.

Note: Since the address of the peer does not have to be passed to and from the OS, the use of connected UDP objects is recommended when the same peer is used for several transmissions and can result in up to 30% performance gains.

Note: Starting with LuaSocket 3.0, the host name resolution depends on whether the socket was created by socket.udp or socket.udp6. Addresses from the appropriate family are tried in succession until the first success or until the last failure.

unconnected:setsockname(address, port)

Binds the UDP object to a local address.

Address can be an IP address or a host name. If address is '*' the system binds to all local interfaces using the constant INADDR_ANY. If port is 0, the system chooses an ephemeral port.

If successful, the method returns 1. In case of error, the method returns nil followed by an error message.

Note: This method can only be called before any datagram is sent through the UDP object, and only once. Otherwise, the system automatically binds the object to all local interfaces and chooses an ephemeral port as soon as the first datagram is sent. After the local address is set, either automatically by the system or explicitly by setsockname, it cannot be changed.

connected:setoption(option [, value])
unconnected:setoption(option [, value])

Sets options for the UDP object. Options are only needed by low-level or time-critical applications. You should only modify an option if you are sure you need it.

Option is a string with the option name, and value depends on the option being set:

  • 'dontroute': Indicates that outgoing messages should bypass the standard routing facilities. Receives a boolean value;
  • 'broadcast': Requests permission to send broadcast datagrams on the socket. Receives a boolean value;
  • 'reuseaddr': Indicates that the rules used in validating addresses supplied in a bind() call should allow reuse of local addresses. Receives a boolean value;
  • 'reuseport': Allows completely duplicate bindings by multiple processes if they all set 'reuseport' before binding the port. Receives a boolean value;
  • 'ip-multicast-loop': Specifies whether or not a copy of an outgoing multicast datagram is delivered to the sending host as long as it is a member of the multicast group. Receives a boolean value;
  • 'ipv6-v6only': Specifies whether to restrict inet6 sockets to sending and receiving only IPv6 packets. Receive a boolean value;
  • 'ip-multicast-if': Sets the interface over which outgoing multicast datagrams are sent. Receives an IP address;
  • 'ip-multicast-ttl': Sets the Time To Live in the IP header for outgoing multicast datagrams. Receives a number;
  • 'ip-add-membership': Joins the multicast group specified. Receives a table with fields multiaddr and interface, each containing an IP address;
  • 'ip-drop-membership': Leaves the multicast group specified. Receives a table with fields multiaddr and interface, each containing an IP address.

The method returns 1 in case of success, or nil followed by an error message otherwise.

Note: The descriptions above come from the man pages.

connected:settimeout(value)
unconnected:settimeout(value)

Changes the timeout values for the object. By default, the receive and receivefrom operations are blocking. That is, any call to the methods will block indefinitely, until data arrives. The settimeout function defines a limit on the amount of time the functions can block. When a timeout is set and the specified amount of time has elapsed, the affected methods give up and fail with an error code.

The amount of time to wait is specified as the value parameter, in seconds. The nil timeout value allows operations to block indefinitely. Negative timeout values have the same effect.

Note: In UDP, the send and sendto methods never block (the datagram is just passed to the OS and the call returns immediately). Therefore, the settimeout method has no effect on them.

Note: The old timeout method is deprecated. The name has been changed for sake of uniformity, since all other method names already contained verbs making their imperative nature obvious.

PK;1]sif,, http.htmlnu[ LuaSocket: HTTP support

LuaSocket
Network support for the Lua language

home · download · introduction · introduction · reference


HTTP

HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange information between web-browsers and servers. The http namespace offers full 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.

The module exports functions that provide HTTP functionality in different levels of abstraction. From the simple string oriented requests, through generic LTN12 based, down to even lower-level if you bother to look through the source code.

To obtain the http namespace, run:

-- loads the HTTP module and any libraries it requires
local http = require("socket.http")

URLs must conform to RFC 1738, that is, an URL is a string in the form:

[http://][<user>[:<password>]@]<host>[:<port>][/<path>] 

MIME headers are represented as a Lua table in the form:

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
}

Field names are case insensitive (as specified by the standard) and all functions work with lowercase field names (but see socket.headers.canonic). Field values are left unmodified.

Note: MIME headers are independent of order. Therefore, there is no problem in representing them in a Lua table.

The following constants can be set to control the default behavior of the HTTP module:

  • PORT: default port used for connections;
  • PROXY: default proxy used for connections;
  • TIMEOUT: sets the timeout for all I/O operations;
  • USERAGENT: default user agent reported to server.

http.request(url [, body])
http.request{
  url = string,
  [sink = LTN12 sink,]
  [method = string,]
  [headers = header-table,]
  [source = LTN12 source],
  [step = LTN12 pump step,]
  [proxy = string,]
  [redirect = boolean,]
  [create = function]
}

The request function has two forms. The simple form downloads a URL using the GET or POST method and is based on strings. The generic form performs any HTTP method and is LTN12 based.

If the first argument of the request function is a string, it should be an url. In that case, if a body is provided as a string, the function will perform a POST method in the url. Otherwise, it performs a GET in the url

If the first argument is instead a table, the most important fields are the url and the simple LTN12 sink that will receive the downloaded content. Any part of the url can be overridden by including the appropriate field in the request table. If authentication information is provided, the function uses the Basic Authentication Scheme (see note) to retrieve the document. If sink is nil, the function discards the downloaded data. The optional parameters are the following:

  • method: The HTTP request method. Defaults to "GET";
  • headers: Any additional HTTP headers to send with the request;
  • source: simple LTN12 source to provide the request body. If there is a body, you need to provide an appropriate "content-length" request header field, or the function will attempt to send the body as "chunked" (something few servers support). Defaults to the empty source;
  • step: LTN12 pump step function used to move data. Defaults to the LTN12 pump.step function.
  • proxy: The URL of a proxy server to use. Defaults to no proxy;
  • redirect: Set to false to prevent the function from automatically following 301 or 302 server redirect messages;
  • create: An optional function to be used instead of socket.tcp when the communications socket is created.

In case of failure, the function returns nil followed by an error message. If successful, the simple form returns the response body as a string, followed by the response status code, the response headers and the response status line. The generic function returns the same information, except the first return value is just the number 1 (the body goes to the sink).

Even when the server fails to provide the contents of the requested URL (URL not found, for example), it usually returns 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.

Here are a few examples with the simple interface:

-- load the http module
local io = require("io")
local http = require("socket.http")
local ltn12 = require("ltn12")

-- connect to server "www.cs.princeton.edu" and retrieves this manual
-- file from "~diego/professional/luasocket/http.html" and print it to stdout
http.request{ 
    url = "http://www.cs.princeton.edu/~diego/professional/luasocket/http.html", 
    sink = ltn12.sink.file(io.stdout)
}

-- connect to server "www.example.com" and tries to retrieve
-- "/private/index.html". Fails because authentication is needed.
b, c, h = http.request("http://www.example.com/private/index.html")
-- b returns some useless page telling about the denied access, 
-- 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.
r, e = http.request("http://wrong.host/")
-- r is nil, and e returns with value "host not found"

And here is an example using the generic interface:

-- load the http module
http = require("socket.http")

-- Requests 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
r, c, h = http.request {
  method = "HEAD",
  url = "http://www.tecgraf.puc-rio.br/~diego"
}
-- r is 1, c is 200, and h would return the following headers:
-- h = {
--   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",
--   ["content-length"] = 15652,
--   ["connection"] = "close",
--   ["content-Type"] = "text/html"
-- }

Note: When sending a POST request, simple interface adds a "Content-type: application/x-www-form-urlencoded" header to the request. This is the type used by HTML forms. If you need another type, use the generic interface.

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".

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.

-- load required modules
http = require("socket.http")
mime = require("mime")

-- Connect to server "www.example.com" and tries to retrieve
-- "/private/index.html", using the provided name and password to
-- authenticate the request
b, c, h = http.request("http://fulano:silva@www.example.com/private/index.html")

-- Alternatively, one could fill the appropriate header and authenticate
-- the request directly.
r, c = http.request {
  url = "http://www.example.com/private/index.html",
  headers = { authorization = "Basic " .. (mime.b64("fulano:silva")) }
}
PK;1]ef88 smtp.htmlnu[ LuaSocket: SMTP support

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


SMTP

The smtp namespace provides functionality to send e-mail messages. The high-level API consists of two functions: one to define an e-mail message, and another to actually send the message. Although almost all users will find that these functions provide more than enough functionality, the underlying implementation allows for even more control (if you bother to read the code).

The implementation conforms to the Simple Mail Transfer Protocol, RFC 2821. Another RFC of interest is RFC 2822, which governs the Internet Message Format. Multipart messages (those that contain attachments) are part of the MIME standard, but described mainly in RFC 2046

In the description below, good understanding of LTN012, Filters sources and sinks and the MIME module is assumed. In fact, the SMTP module was the main reason for their creation.

To obtain the smtp namespace, run:

-- loads the SMTP module and everything it requires
local smtp = require("socket.smtp")

MIME headers are represented as a Lua table in the form:

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
}

Field names are case insensitive (as specified by the standard) and all functions work with lowercase field names (but see socket.headers.canonic). Field values are left unmodified.

Note: MIME headers are independent of order. Therefore, there is no problem in representing them in a Lua table.

The following constants can be set to control the default behavior of the SMTP module:

  • DOMAIN: domain used to greet the server;
  • PORT: default port used for the connection;
  • SERVER: default server used for the connection;
  • TIMEOUT: default timeout for all I/O operations;
  • ZONE: default time zone.

smtp.send{
  from = string,
  rcpt = string or string-table,
  source = LTN12 source,
  [user = string,]
  [password = string,]
  [server = string,]
  [port = number,]
  [domain = string,]
  [step = LTN12 pump step,]
  [create = function]
}

Sends a message to a recipient list. Since sending messages is not as simple as downloading an URL from a FTP or HTTP server, this function doesn't have a simple interface. However, see the message source factory for a very powerful way to define the message contents.

The sender is given by the e-mail address in the from field. Rcpt is a Lua table with one entry for each recipient e-mail address, or a string in case there is just one recipient. The contents of the message are given by a simple LTN12 source. Several arguments are optional:

  • user, password: User and password for authentication. The function will attempt LOGIN and PLAIN authentication methods if supported by the server (both are unsafe);
  • server: Server to connect to. Defaults to "localhost";
  • port: Port to connect to. Defaults to 25;
  • domain: Domain name used to greet the server; Defaults to the local machine host name;
  • step: LTN12 pump step function used to pass data from the source to the server. Defaults to the LTN12 pump.step function;
  • create: An optional function to be used instead of socket.tcp when the communications socket is created.

If successful, the function returns 1. Otherwise, the function returns nil followed by an error message.

Note: SMTP servers can be very picky with the format of e-mail addresses. To be safe, use only addresses of the form "<fulano@example.com>" in the from and rcpt arguments to the send function. In headers, e-mail addresses can take whatever form you like.

Big note: There is a good deal of misconception with the use of the destination address field headers, i.e., the 'To', 'Cc', and, more importantly, the 'Bcc' headers. Do not add a 'Bcc' header to your messages because it will probably do the exact opposite of what you expect.

Only recipients specified in the rcpt list will receive a copy of the message. Each recipient of an SMTP mail message receives a copy of the message body along with the headers, and nothing more. The headers are part of the message and should be produced by the LTN12 source function. The rcpt list is not part of the message and will not be sent to anyone.

RFC 2822 has two important and short sections, "3.6.3. Destination address fields" and "5. Security considerations", explaining the proper use of these headers. Here is a summary of what it says:

  • To: contains the address(es) of the primary recipient(s) of the message;
  • Cc: (where the "Cc" means "Carbon Copy" in the sense of making a copy on a typewriter using carbon paper) contains the addresses of others who are to receive the message, though the content of the message may not be directed at them;
  • Bcc: (where the "Bcc" means "Blind Carbon Copy") contains addresses of recipients of the message whose addresses are not to be revealed to other recipients of the message.

The LuaSocket send function does not care or interpret the headers you send, but it gives you full control over what is sent and to whom it is sent:

  • If someone is to receive the message, the e-mail address has to be in the recipient list. This is the only parameter that controls who gets a copy of the message;
  • If there are multiple recipients, none of them will automatically know that someone else got that message. That is, the default behavior is similar to the Bcc field of popular e-mail clients;
  • It is up to you to add the To header with the list of primary recipients so that other recipients can see it;
  • It is also up to you to add the Cc header with the list of additional recipients so that everyone else sees it;
  • Adding a header Bcc is nonsense, unless it is empty. Otherwise, everyone receiving the message will see it and that is exactly what you don't want to happen!

I hope this clarifies the issue. Otherwise, please refer to RFC 2821 and RFC 2822.

-- load the smtp support
local smtp = require("socket.smtp")

-- Connects to server "localhost" and sends a message to users
-- "fulano@example.com",  "beltrano@example.com", 
-- and "sicrano@example.com".
-- Note that "fulano" is the primary recipient, "beltrano" receives a
-- carbon copy and neither of them knows that "sicrano" received a blind
-- carbon copy of the message.
from = "<luasocket@example.com>"

rcpt = {
  "<fulano@example.com>",
  "<beltrano@example.com>",
  "<sicrano@example.com>"
}

mesgt = {
  headers = {
    to = "Fulano da Silva <fulano@example.com>",
    cc = '"Beltrano F. Nunes" <beltrano@example.com>',
    subject = "My first message"
  },
  body = "I hope this works. If it does, I can send you another 1000 copies."
}

r, e = smtp.send{
  from = from,
  rcpt = rcpt, 
  source = smtp.message(mesgt)
}

smtp.message(mesgt)

Returns a simple LTN12 source that sends an SMTP message body, possibly multipart (arbitrarily deep).

The only parameter of the function is a table describing the message. Mesgt has the following form (notice the recursive structure):

mesgt = {
  headers = header-table,
  body = LTN12 source or string or multipart-mesgt
}
 
multipart-mesgt = {
  [preamble = string,]
  [1] = mesgt,
  [2] = mesgt,
  ...
  [n] = mesgt,
  [epilogue = string,]
}

For a simple message, all that is needed is a set of headers and the body. The message body can be given as a string or as a simple LTN12 source. For multipart messages, the body is a table that recursively defines each part as an independent message, plus an optional preamble and epilogue.

The function returns a simple LTN12 source that produces the message contents as defined by mesgt, chunk by chunk. Hopefully, the following example will make things clear. When in doubt, refer to the appropriate RFC as listed in the introduction.

-- load the smtp support and its friends
local smtp = require("socket.smtp")
local mime = require("mime")
local ltn12 = require("ltn12")

-- creates a source to send a message with two parts. The first part is 
-- plain text, the second part is a PNG image, encoded as base64.
source = smtp.message{
  headers = {
     -- Remember that headers are *ignored* by smtp.send. 
     from = "Sicrano de Oliveira <sicrano@example.com>",
     to = "Fulano da Silva <fulano@example.com>",
     subject = "Here is a message with attachments"
  },
  body = {
    preamble = "If your client doesn't understand attachments, \r\n" ..
               "it will still display the preamble and the epilogue.\r\n" ..
               "Preamble will probably appear even in a MIME enabled client.",
    -- first part: no headers means plain text, us-ascii.
    -- The mime.eol low-level filter normalizes end-of-line markers.
    [1] = { 
      body = mime.eol(0, [[
        Lines in a message body should always end with CRLF. 
        The smtp module will *NOT* perform translation. However, the 
        send function *DOES* perform SMTP stuffing, whereas the message
        function does *NOT*.
      ]])
    },
    -- second part: headers describe content to be a png image, 
    -- sent under the base64 transfer content encoding.
    -- notice that nothing happens until the message is actually sent. 
    -- small chunks are loaded into memory right before transmission and 
    -- translation happens on the fly.
    [2] = { 
      headers = {
        ["content-type"] = 'image/png; name="image.png"',
        ["content-disposition"] = 'attachment; filename="image.png"',
        ["content-description"] = 'a beautiful image',
        ["content-transfer-encoding"] = "BASE64"
      },
      body = ltn12.source.chain(
        ltn12.source.file(io.open("image.png", "rb")),
        ltn12.filter.chain(
          mime.encode("base64"),
          mime.wrap()
        )
      )
    },
    epilogue = "This might also show up, but after the attachments"
  }
}

-- finally send it
r, e = smtp.send{
    from = "<sicrano@example.com>",
    rcpt = "<fulano@example.com>",
    source = source,
}
PK;1])READMEnu[This is the LuaSocket 3.0-rc1. It has been tested on Windows 7, Mac OS X, and Linux. Please use the project page at GitHub https://github.com/diegonehab/luasocket to file bug reports or propose changes. Have fun, Diego Nehab. PK;1]4SStcp.htmlnu[ LuaSocket: TCP/IP support

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


TCP

socket.tcp()

Creates and returns an IPv4 TCP master object. A master object can be transformed into a server object with the method listen (after a call to bind) or into a client object with the method connect. The only other method supported by a master object is the close method.

In case of success, a new master object is returned. In case of error, nil is returned, followed by an error message.

socket.tcp6()

Creates and returns an IPv6 TCP master object. A master object can be transformed into a server object with the method listen (after a call to bind) or into a client object with the method connect. The only other method supported by a master object is the close method.

In case of success, a new master object is returned. In case of error, nil is returned, followed by an error message.

Note: The TCP object returned will have the option "ipv6-v6only" set to true.

server:accept()

Waits for a remote connection on the server object and returns a client object representing that connection.

If a connection is successfully initiated, a client object is returned. If a timeout condition is met, the method returns nil followed by the error string 'timeout'. Other errors are reported by nil followed by a message describing the error.

Note: calling socket.select with a server object in the recvt parameter before a call to accept does not guarantee accept will return immediately. Use the settimeout method or accept might block until another client shows up.

master:bind(address, port)

Binds a master object to address and port on the local host.

Address can be an IP address or a host name. Port must be an integer number in the range [0..64K). If address is '*', the system binds to all local interfaces using the INADDR_ANY constant or IN6ADDR_ANY_INIT, according to the family. If port is 0, the system automatically chooses an ephemeral port.

In case of success, the method returns 1. In case of error, the method returns nil followed by an error message.

Note: The function socket.bind is available and is a shortcut for the creation of server sockets.

master:close()
client:close()
server:close()

Closes a TCP object. The internal socket used by the object is closed and the local address to which the object was bound is made available to other applications. No further operations (except for further calls to the close method) are allowed on a closed socket.

Note: It is important to close all used sockets once they are not needed, since, in many systems, each socket uses a file descriptor, which are limited system resources. Garbage-collected objects are automatically closed before destruction, though.

master:connect(address, port)

Attempts to connect a master object to a remote host, transforming it into a client object. Client objects support methods send, receive, getsockname, getpeername, settimeout, and close.

Address can be an IP address or a host name. Port must be an integer number in the range [1..64K).

In case of error, the method returns nil followed by a string describing the error. In case of success, the method returns 1.

Note: The function socket.connect is available and is a shortcut for the creation of client sockets.

Note: Starting with LuaSocket 2.0, the settimeout method affects the behavior of connect, causing it to return with an error in case of a timeout. If that happens, you can still call socket.select with the socket in the sendt table. The socket will be writable when the connection is established.

Note: Starting with LuaSocket 3.0, the host name resolution depends on whether the socket was created by socket.tcp or socket.tcp6. Addresses from the appropriate family are tried in succession until the first success or until the last failure.

client:getpeername()

Returns information about the remote side of a connected client object.

Returns a string with the IP address of the peer, the port number that peer is using for the connection, and a string with the family ("inet" or "inet6"). In case of error, the method returns nil.

Note: It makes no sense to call this method on server objects.

master:getsockname()
client:getsockname()
server:getsockname()

Returns the local address information associated to the object.

The method returns a string with local IP address, a number with the local port, and a string with the family ("inet" or "inet6"). In case of error, the method returns nil.

master:getstats()
client:getstats()
server:getstats()

Returns accounting information on the socket, useful for throttling of bandwidth.

The method returns the number of bytes received, the number of bytes sent, and the age of the socket object in seconds.

master:listen(backlog)

Specifies the socket is willing to receive connections, transforming the object into a server object. Server objects support the accept, getsockname, setoption, settimeout, and close methods.

The parameter backlog specifies the number of client connections that can be queued waiting for service. If the queue is full and another client attempts connection, the connection is refused.

In case of success, the method returns 1. In case of error, the method returns nil followed by an error message.

client:receive([pattern [, prefix]])

Reads data from a client object, according to the specified read pattern. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.

Pattern can be any of the following:

  • '*a': reads from the socket until the connection is closed. No end-of-line translation is performed;
  • '*l': reads a line of text from the socket. The line is terminated by a LF character (ASCII 10), optionally preceded by a CR character (ASCII 13). The CR and LF characters are not included in the returned line. In fact, all CR characters are ignored by the pattern. This is the default pattern;
  • number: causes the method to read a specified number of bytes from the socket.

Prefix is an optional string to be concatenated to the beginning of any received data before return.

If successful, the method returns the received pattern. In case of error, the method returns nil followed by an error message, followed by a (possibly empty) string containing the partial that was received. The error message can be the string 'closed' in case the connection was closed before the transmission was completed or the string 'timeout' in case there was a timeout during the operation.

Important note: This function was changed severely. It used to support multiple patterns (but I have never seen this feature used) and now it doesn't anymore. Partial results used to be returned in the same way as successful results. This last feature violated the idea that all functions should return nil on error. Thus it was changed too.

client:send(data [, i [, j]])

Sends data through client object.

Data is the string to be sent. The optional arguments i and j work exactly like the standard string.sub Lua function to allow the selection of a substring to be sent.

If successful, the method returns the index of the last byte within [i, j] that has been sent. Notice that, if i is 1 or absent, this is effectively the total number of bytes sent. In case of error, the method returns nil, followed by an error message, followed by the index of the last byte within [i, j] that has been sent. You might want to try again from the byte following that. The error message can be 'closed' in case the connection was closed before the transmission was completed or the string 'timeout' in case there was a timeout during the operation.

Note: Output is not buffered. For small strings, it is always better to concatenate them in Lua (with the '..' operator) and send the result in one call instead of calling the method several times.

client:setoption(option [, value])
server:setoption(option [, value])

Sets options for the TCP object. Options are only needed by low-level or time-critical applications. You should only modify an option if you are sure you need it.

Option is a string with the option name, and value depends on the option being set:

  • 'keepalive': Setting this option to true enables the periodic transmission of messages on a connected socket. Should the connected party fail to respond to these messages, the connection is considered broken and processes using the socket are notified;
  • 'linger': Controls the action taken when unsent data are queued on a socket and a close is performed. The value is a table with a boolean entry 'on' and a numeric entry for the time interval 'timeout' in seconds. If the 'on' field is set to true, the system will block the process on the close attempt until it is able to transmit the data or until 'timeout' has passed. If 'on' is false and a close is issued, the system will process the close in a manner that allows the process to continue as quickly as possible. I do not advise you to set this to anything other than zero;
  • 'reuseaddr': Setting this option indicates that the rules used in validating addresses supplied in a call to bind should allow reuse of local addresses;
  • 'tcp-nodelay': Setting this option to true disables the Nagle's algorithm for the connection;
  • 'ipv6-v6only': Setting this option to true restricts an inet6 socket to sending and receiving only IPv6 packets.

The method returns 1 in case of success, or nil followed by an error message otherwise.

Note: The descriptions above come from the man pages.

client:getoption(option)
server:getoption(option)

Gets options for the TCP object. See setoption for description of the option names and values.

Option is a string with the option name.

  • 'keepalive'
  • 'linger'
  • 'reuseaddr'
  • 'tcp-nodelay'

The method returns the option value in case of success, or nil followed by an error message otherwise.

master:setstats(received, sent, age)
client:setstats(received, sent, age)
server:setstats(received, sent, age)

Resets accounting information on the socket, useful for throttling of bandwidth.

Received is a number with the new number of bytes received. Sent is a number with the new number of bytes sent. Age is the new age in seconds.

The method returns 1 in case of success and nil otherwise.

master:settimeout(value [, mode])
client:settimeout(value [, mode])
server:settimeout(value [, mode])

Changes the timeout values for the object. By default, all I/O operations are blocking. That is, any call to the methods send, receive, and accept will block indefinitely, until the operation completes. The settimeout method defines a limit on the amount of time the I/O methods can block. When a timeout is set and the specified amount of time has elapsed, the affected methods give up and fail with an error code.

The amount of time to wait is specified as the value parameter, in seconds. There are two timeout modes and both can be used together for fine tuning:

  • 'b': block timeout. Specifies the upper limit on the amount of time LuaSocket can be blocked by the operating system while waiting for completion of any single I/O operation. This is the default mode;
  • 't': total timeout. Specifies the upper limit on the amount of time LuaSocket can block a Lua script before returning from a call.

The nil timeout value allows operations to block indefinitely. Negative timeout values have the same effect.

Note: although timeout values have millisecond precision in LuaSocket, large blocks can cause I/O functions not to respect timeout values due to the time the library takes to transfer blocks to and from the OS and to and from the Lua interpreter. Also, function that accept host names and perform automatic name resolution might be blocked by the resolver for longer than the specified timeout value.

Note: The old timeout method is deprecated. The name has been changed for sake of uniformity, since all other method names already contained verbs making their imperative nature obvious.

client:shutdown(mode)

Shuts down part of a full-duplex connection.

Mode tells which way of the connection should be shut down and can take the value:

  • "both": disallow further sends and receives on the object. This is the default mode;
  • "send": disallow further sends on the object;
  • "receive": disallow further receives on the object.

This function returns 1.

master:dirty()
client:dirty()
server:dirty()

Check the read buffer status.

Returns true if there is any data in the read buffer, false otherwise.

Note: This is an internal method, any use is unlikely to be portable.

master:getfd()
client:getfd()
server:getfd()

Returns the underling socket descriptor or handle associated to the object.

The descriptor or handle. In case the object has been closed, the return will be -1.

Note: This is an internal method, any use is unlikely to be portable.

master:setfd(fd)
client:setfd(fd)
server:setfd(fd)

Sets the underling socket descriptor or handle associated to the object. The current one is simply replaced, not closed, and no other change to the object state is made.

No return value.

Note: This is an internal method, any use is unlikely to be portable.

PK;1] Rj url.htmlnu[ LuaSocket: URL support

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


URL

The url namespace provides functions to parse, protect, and build URLs, as well as functions to compose absolute URLs from base and relative URLs, according to RFC 2396.

To obtain the url namespace, run:

-- loads the URL module 
local url = require("socket.url")

An URL is defined by the following grammar:

<url> ::= [<scheme>:][//<authority>][/<path>][;<params>][?<query>][#<fragment>]
<authority> ::= [<userinfo>@]<host>[:<port>]
<userinfo> ::= <user>[:<password>]
<path> ::= {<segment>/}<segment>

url.absolute(base, relative)

Builds an absolute URL from a base URL and a relative URL.

Base is a string with the base URL or a parsed URL table. Relative is a string with the relative URL.

The function returns a string with the absolute URL.

Note: The rules that govern the composition are fairly complex, and are described in detail in RFC 2396. The example bellow should give an idea of what the rules are.

http://a/b/c/d;p?q

+

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

url.build(parsed_url)

Rebuilds an URL from its parts.

Parsed_url is a table with same components returned by parse. Lower level components, if specified, take precedence over high level components of the URL grammar.

The function returns a string with the built URL.

url.build_path(segments, unsafe)

Builds a <path> component from a list of <segment> parts. 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.

Segments is a list of strings with the <segment> parts. If unsafe is anything but nil, reserved characters are left untouched.

The function returns a string with the built <path> component.

url.escape(content)

Applies the URL escaping content coding to a string Each byte is encoded as a percent character followed by the two byte hexadecimal representation of its integer value.

Content is the string to be encoded.

The function returns the encoded string.

-- load url module
url = require("socket.url")

code = url.escape("/#?;")
-- code = "%2f%23%3f%3b"

url.parse(url, default)

Parses an URL given as a string into a Lua table with its components.

Url is the URL to be parsed. If the default table is present, it is used to store the parsed fields. Only fields present in the URL are overwritten. Therefore, this table can be used to pass default values for each field.

The function returns a table with all the URL components:

parsed_url = {
  url = string,
  scheme = string,
  authority = string,
  path = string,
  params = string,
  query = string,
  fragment = string,
  userinfo = string,
  host = string,
  port = string,
  user = string,
  password = string
}
-- load url module
url = require("socket.url")

parsed_url = url.parse("http://www.example.com/cgilua/index.lua?a=2#there")
-- parsed_url = {
--   scheme = "http",
--   authority = "www.example.com",
--   path = "/cgilua/index.lua"
--   query = "a=2",
--   fragment = "there",
--   host = "www.puc-rio.br",
-- }

parsed_url = url.parse("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",
-- }

url.parse_path(path)

Breaks a <path> URL component into all its <segment> parts.

Path is a string with the path to be parsed.

Since some characters are reserved in URLs, they must be escaped whenever present in a <path> component. Therefore, before returning a list with all the parsed segments, the function removes escaping from all of them.

url.unescape(content)

Removes the URL escaping content coding from a string.

Content is the string to be decoded.

The function returns the decoded string.

PK;1]޶j reference.cssnu[body { margin-left: 1em; margin-right: 1em; font-family: "Verdana", sans-serif; } tt { font-family: "Andale Mono", monospace; } h1, h2, h3, h4 { margin-left: 0em; } h3 { padding-top: 1em; } p { margin-left: 1em; } p.name { font-family: "Andale Mono", monospace; padding-top: 1em; margin-left: 0em; } a[href] { color: #00007f; } blockquote { margin-left: 3em; } pre.example { background: #ccc; padding: 1em; margin-left: 1em; font-family: "Andale Mono", monospace; font-size: small; } hr { margin-left: 0em; background: #00007f; border: 0px; height: 1px; } ul { list-style-type: disc; } table.index { border: 1px #00007f; } table.index td { text-align: left; vertical-align: top; } table.index ul { padding-top: 0em; margin-top: 0em; } h1:first-letter, h2:first-letter, h2:first-letter, h3:first-letter { color: #00007f; } div.header, div.footer { margin-left: 0em; } PK;1]-) D++installation.htmlnu[ LuaSocket: Installation

LuaSocket
Network support for the Lua language

home · download · installation · introduction · reference


Installation

Here we describe the standard distribution. If the standard doesn't meet your needs, we refer you to the Lua discussion list, where any question about the package scheme will likely already have been answered.

Directory structure

On Unix systems, the standard distribution uses two base directories, one for system dependent files, and another for system independent files. Let's call these directories <CDIR> and <LDIR>, respectively. For example, in my laptp, Lua 5.1 is configured to use '/usr/local/lib/lua/5.1' for <CDIR> and '/usr/local/share/lua/5.1' for <LDIR>. On Windows, <CDIR> usually points to the directory where the Lua executable is found, and <LDIR> points to a lua/ directory inside <CDIR>. (These settings can be overridden by environment variables LUA_PATH and LUA_CPATH. See the Lua documentation for details.) Here is the standard LuaSocket distribution directory structure:

<LDIR>/ltn12.lua
<LDIR>/socket.lua
<CDIR>/socket/core.dll
<LDIR>/socket/http.lua
<LDIR>/socket/tp.lua
<LDIR>/socket/ftp.lua
<LDIR>/socket/smtp.lua
<LDIR>/socket/url.lua
<LDIR>/mime.lua
<CDIR>/mime/core.dll

Naturally, on Unix systems, core.dll would be replaced by core.so.

Using LuaSocket

With the above setup, and an interpreter with shared library support, it should be easy to use LuaSocket. Just fire the interpreter and use the require function to gain access to whatever module you need:

Lua 5.2.2  Copyright (C) 1994-2013 Lua.org, PUC-Rio
> socket = require("socket")
> print(socket._VERSION)
--> LuaSocket 3.0-rc1

Each module loads their dependencies automatically, so you only need to load the modules you directly depend upon:

Lua 5.2.2  Copyright (C) 1994-2013 Lua.org, PUC-Rio
> http = require("socket.http")
> print(http.request("http://www.impa.br/~diego/software/luasocket"))
--> homepage gets dumped to terminal
PK;1]TX lua05.pptnu[ࡱ>   @n?" dd@  @@`` q7    7%  .      "$&. 2 0 3 !4#%'/156(),-*+?$$b$:@X\&#NZ  0AAp@Ng*@ʚ;62ʚ;g4ddddnppp@ <4d(  F/ 0|DArial00wb IW@\P^\!DTimes00wb IW@\P^\! DCourier Newb IW@\P^\!0DWingdingswb IW@\P^\!@D-3 00000wb IW@\P^\! ` .n:@X\&#NZ PNG  IHDR0X pHYs  tIME ; xޥr IDATxY$u&x{{DR+ A,$HD#EQܴ)Q⦑4y~鶑iآ( ̈p{Y6&,2ܿ8^^^^^^/" " }7,,B9K.B)jf;@ćP0P86gfsv]cDaB9%aF$GEp1s#9Tlǩvp\jMkmfuU[VaEۇT&lg>Խ[g; P`>:sL`r&bwgq%q^zv U@"Nyjkg@Vnǥ+j{7^#]>BfJe89o{c>s4 @6O׉U"TH$2 @5 8Q.\=™m2ۓ@n-[K/?{xuyr>d%P|^K/={ۛbryy8!]]/w@Ԉ~YvMI~8 0<ܣa䜘9":s@!3:f>t1;zѣz8Z]>m'_x>z&wpy٦x5͵6m{DRZO($p"s@ 73@ff UC"Dt4"ȹ0zp &&7(*_˷駗8"imo}3~c<̭r%z}׶,Wt5/8qfAе#{vL"ƌ Dj DhnJ)B!C:: 2ys}o?x[ǫjWXȒo?s‹3Oآ9b@u=Ц8Oe].̙#@U{WUED3`CD@`DDf" I3@3E0{DZGDD$"ps@`~G${WϽ=qk`$wVK]-=|hnDDD4L{"23 FĎ"b*"H#2,)3Vt}M" DD nf "@.AO?C`T9}/~KoosN\ ֙o}qJ),23C@!ݕ7ՎnH$(1!2 Ï?~uz%>/Oϟ~o?[wvfrfuUr|w_,󬪺V* @0P%Ƙݯ!kacB 4,R2SB@DB@wGrfffBdX_J]{k#"D"E @!@ 5)oDDi(H<ǯӿ7_*s/ʧ>kg(LmDBL"0prqqǗU+P[["ufѨn>zI݈x̄=Fj 2AZF8sp""A"[E ;eǟ=ڿ_fV3}<1rŏ_^͞B"#&SD`LWpu4ϵNIUSg&ICH d!у@< #Y I ACu%h\*>$&ʪn9K8{wp뙉!=!FwNo=}?|w;?+σRn'l>#` /׿ 55T{2_\?|Σ}cQ.7}_ϾrfM|:oO|{7nGeͭv3wPծZ;(H11JݭkwsB $2$90&DI'I( lܔjT\&պ$轻{ 2"Si34l< Sٲ̽͸H:?xt:*o7ӳOБoe7슅۳>[#m?k쪧x~zQTq狇 fDHH֙ q%Q@ĈBA,fXY:̂S{yxxXW7uH"E#3D903cɉ7CPr PU p C`⒓ZÀL-;}x~܇ٿS`!3}GHxyqξy򅏽̽[eY4jTU##"#Hק DHDDD()%b`X0 , 憀9e"333{@DfFL ɜ2p8R03a0%InH%ᄀ)\;Yb%hnfxwOܽvy4`qx7o}d;yCFO< /<{ |Zһ>xoܿ:x]Ý3'Bpu pJN)9pͣBEIBbrֺ ! 9)!103EP qp%И, 'Ffʂ) Ly|*D|"|ӟ~` RV?Jۓ~o+/31AxjP06_]]^<8C]i(wǮnDXRJ6W؄{U񈕂 "fD"p$$$!`X]_9sʉMw $Uv&U5w@DADK"R21v5$L9Rzw r$dfN+P 3$1 2>=s9Qz8W;-*"iW!R]puuj^wu S̜E&zT"DJ)3H9%0qa^kKUYWu@wg B "LYZp , A䒶m.V'p`!D9ϽLzqyt?>"<_~[_ē#X3 sj?L44<-LH DBD93ZD"@\fGD|#GDdJ>,< YsERn6ϭEW e )"3'f`a9LDR%޺9v"`&r]6V1l!"Vl!KLdn+i’R3W7DU[ԖiV!l6 `H%GDh ( sݴg_Þ}S;{ ,tO|g?qbJ.Rlܝ"tX4/.//sνik0YD2 d$sUPnT7"ADlP$ٌcJٌ8Y_u(эp(i:a꭛vRӕB, Nb<-"!3qD czSU7Ufq@r4aH$,zmʡ8Cxt{}7pխXg|/Wn)ֶRّ0`H. jΗԦ„u@p)eSƕt6"W3:P@pَ)')CmfS%Ąj4󴴮lfH,Dی5:# B!`FHbPuG]LanHLĪzw=XD]0X6UWscbHXV}3@ʔR (>ҋտgg:_/gn( aG7>u$[20/|zñ91P]eiNHd0yV7 O%5fja`!9m6n%vۓR0l}ͫ $./5n"eܨY1p8 A$?N@jkha+{w5ƃ"T:W't)eZ&7Du݈u,pF&`̹ `mK29~􉏿9;of{"Nyw?od3 x<P4ei|upq޻*F!@šGJx$ڃx܍CN B"vWS`$8A0p@dvwH%^;=Y$XҺ##8uu¯=#,  f!`N)cÁܬŪ$dA7zQpWOk_|r[F8R5NnY7b3UL_l[2$B_.ڻm7cWuDR 5S3bRS3 @ĻIz4 XXM{$2KmBy(1P@s\23jG"$$uH wW3` 2 57uyZhjfaq n[fP֜b @3ϥ0 C0C!#x]7pSo\N~/Xg;?W9<="b=]zmADAh)ӳP0-˴.j譵Y$spbp7\M)EvMN%ao6O-S4Hytu EBY!9p.EKN)DZ{8fF9lí[wD᪮Q[0-Ńqǰ$J1KڎIs"3B̩ v7 B]Z̐(XRJ%Ex{u@īk%zMf2@@F `ֻzEn4#z# ݛ;~♟ӻoAXӟwO?u6#ǁVͬL$<ZsiJYK "i5?13"Cɛ!1;"&e\n޺= eSM(׹.sWmM~u8εj*Gx;ڈhlXDyѮ)Vt?_~v$)f%ڑ(zޭ{7BJB`r_]KO󲴥U.C]_y0BX 'pw1'tɌm:y0е/˲fLwU$s<KޞM"NCNICxjp5mBԛ"nī"da~DE2EtͬkWTiO M5K=3"<"INoymo_ XD_z@0nv[֖eRZSS tZqJ].{%I)91aX!,[X Iy4 q:yZe鶴ĭ7#PH%mvdmO0p](z[u^Rrj!*-#VsNo}ݥvw@Ufd@TnixvSkSJfK=z1CG͟!%v61Et5s@ òD`xwG`&5lγ'sFCJͮRJۓ8 {D၀jf80zצqk2{0*2+ :c910 q3EJRzm" IDATXy48n7)˺O,RDnM2AМ9|=K:iyp[naxCNRYb:pgZҪ 3je_ap,v BW]Z$D^ $PpJBĔ!4k)s&)#8 6"0$nY9' FPZ7bsdDSLDCVOo(̉@c&Bw'NDeM ,94119JZ LnA$faeXHœNݽԛFv ,t~/{/9My>χ fjw$}i]) rNsa-Jn$4<3%Y&bs[9d"pwdYd}f6#<bP f,nQXT͈0DL@KwE$Jar̫SpJLk| @NLE " YX)eN (Bٞ3+B7'J~`!i@JNBL'gO}jyZD`?wffS 5NeCIK=^N#~gZ /~ €]T:&w3ޕ$K*D7XJ_fjAE) mY}xqXuzbFARJy-Ih} Ă) 12k=H%UUB ˪ծ$I9d\sk`N!c\Za?9Yvjm@{[Zǜ$ƜxaJ$DAI)֓)Q ք^7"&َfi0zɖ8Hn]Uz!$I%,$$9ɍ;'?䩗?Oݽ.a t5v3b`V)msR{ǔK.9e1;.e0S7'BD@$Z89g꭫"d<;ۥ`kJk'ı植cZjRuO0 3y @$92 aMU{ jfږx唺vw5X0q[B=, R,&Uʞ*1Hy6[S-s)s6f([prH\L6ُkoqsSVՎL)'I ֔ u{SsGߝ9%f,`}sjaJ9HbI,"ER)9Dzq~>`Q_—~/)hkhj9qh{˒o]#>̬ g3& !?@?6 X-HWs|,9˲,Z9V@Ra) x w@@fӢH$<4$qhQ^͢K˵ .ZA8YZkzQԥR9TPeQXo~Wc/Dooǒh}=3! *udYxyhgd~?vߏhO0Z|w_ \`,`f̢z>~/O>c ~y™,3‚s2RTZ2`'i[^b!2Zo=$DKY.af}XwR3eF 9Zu]Z YK f KX@p>__QD^N,6:CG$fQ9Ły#̘pp9gI?HYEj) l1)ZH EBE6%"_.,ķo1#0Q2û@ZTdnl{lld~nc_!,br<}'U#)"WjΉ׀HL: sO@ ̂8)(":" >DU.3e&b-3`A„B ,\ʊb9LEt:_F/o P|7z09F.*ᑨ,Zʲk ޺!c<ɂկ* dU&H"PT&Fbe~zi`˲} aB0(&Tx6`xgHpߚаlDrLÜX@pHk$6=2q3. "01,HFy&AfKbVEzٷ"zZ<.K9DY Gk y`$ "'{?zKYa|?T8p=K .e&€"YkmALZ4!Q1݌ `XOxPRs";"Ry:-hH4,I۽oeXD%7o{`hef2w8 '?˿ bZh{@d+#겜N'~ɱo}"'39s}TfRLGW]1vHr#  =}k231,25(!2"QϑCRkD1aͭRu=өE_[R_A)˂OoRkzF+sIWd@Htp̺eY/2}eɷ[~mPL 3đ+n{i8F ]Q`)zLIK0~?z{Շݺ?  Ӛm)foRֲͥm۰@.SPka"Z0Jezɛ?w&"絞J]u1pfQQF֚Jmӹ+N O"L,nD k{4s E4GD42-RDOӺ.Ȕ !9{U\ G߶ 1#e `"\"3'fBGYs2OI03 C3e2 eZKFp~__4dOk?uaHL drC~߷) cx ìn}ЈR=2<͆ ^o>=>=˾>zk[n:0TT= !68A ʹ-.uY2yXz93~8z)^<#"12Tѕ<^qz%`:2`)30SHS-"%3TpZ 9<^1gJ*|u؎ 0뙰Z}e.Ky30 K(O?/??g0fLGV6k9=dm7DTsێmo=)g>^d~`7_|h龜l뺔RJo拷vY=fn$@|: )J0=܉@JXEq#Ya# h;Z}'~,*AoS"r_֊2íaGDLpLS8(N07D 80I)><1"[޷AiE*M ؠpQ{?џ/ҥ7ΧoIc(hzALi{גB}kH\L}Z@D &RuՔ\Tz>@u? "#ӠR3Ta-{{OQ$NPUABB)"c"}_^^2 e?8zim RxYtY*"2Rx#&$H RpwָNYLI4lQ!# ` !dj+m$xd~[o_~璇0<FÌGo61#(0[6GS] (KM0ԅUض)E8ckǺ.GNG@<3rNo_2ڼ#2. H9pa9ƨ 콥{^L%f|`[y\k9]Q[YCD Q80i!HE2EPIKq0A#DQ7"dE4 K-r~0"GfRk(3!Hp$aw,LSzc ׿5zxR[l"٘"ctn޿ BnctZL@!R>_Z ,裏2ERu]>=>N+ [鯉zZPTz:RʲZDH@n6T%mѠ3prM4Dlg7gEZ.C&r&Zj]5=ȉDPTX I"#k\%N\ry>~c1Z;sMD0{C0@`z.#GoBH#,!ɇ?k_N,9_s05qt --},0yKe xju]EmG0FƬ,VVfZ֚ ih!]T03 $$R"xf!1nn 3fƬn%.*2f uy'gL!"c7!~xVyk{[cQi-U!^ZO ZTV"pn*REkGȵ>܈қE')i] A@x"an_#= 'jF{[ DUϗK&Hn $ x]Uܧ{m> (LILYTvևarZtI CFxBfя}p93Dza)ޏ #[<}/o]Xɯ|O A}^v4 038Kݗ뛢|@nr^ͬ #r>/cO{doMRf}ݣ{;8s1eb80Rd]T LRcHp#}"*_k lo; =<<~SfN)+2^3p]VoJo.iwF| -K}x23GYD1Mф$D* e2zij$QYzZ,K?<TJxpzfZ r=R|oByY#3e)dv*4lXۭE"Z"13K f7#_zDQJZʌywSTS;X"d_1#ܦ'{o"ʅ3osI 2ͯ|JaݺgBp u]2 Md $Eog P-VfEŽ-PUqoR\D*JH+}YW"H'ea{ZR6a}v ќwψGr^G7`EF/Rh0#b0,I/p.ꊌL""HPfљ Y#Y0CP&S8f0Y%"):ɗVٻc B3q?xf c"7O@Df4N>|W +>6FK*9I k3Lc "j ˲0s\˚f"3ͶZJ qusYRU+Ø߿"!}:54XZO'w[!0w256|; ԥ̅R+6] 2}62! iZ}RǾ{G,Z5e* _ b)!mĒjDwDHa^[zD  N&y33E91ˇ㗟igo8e #8J\kEi>SYyQSA,Za\J rXN{F)\WֺOe%[sǧǶ~?;88V>D@X|/[mt -+#1"#D!3HwU=HEe~ILJv~XD$8@6*3U!ZYFw)zT$XXю8MH"22`>\LjcJEN'"JGOlG"f,j~m,ѣ>.s5B]>Z~?XOLO>zZ ZOBf"rK4 H4lN"Y"sL(P)ƈяv}om .7Er5RU|9 ̉L`=h@8_N@Y۶Y$!-""DBbdA@B920gjfՑiG;hAPj$ JJ "$A @r%Rf1tyPe)/J/MR;Y}7 r˺i"I)u9m{ы.{(U>{eE$pHOrZ?zV<} 64fBov%#G;@]jEfHBb=,gvC f9z5fĜ 5"R6v73D !D|E&>8-=} bZ 6|Ǿo6#E$e)r>=i{Zk,uFDiY ˘4}ԡiI9Nuo='Y#Fz0+b Tycth e Dt> *Eeaf1DL:s [ ,PJRQixH'U}c3w`]JoNOqa پo6ZJh^{6>c}zX7R9yZhaD$" "kwyȆ P*-K}l[h(Y><<=>|޾p#"3Y *R͛7FҾ~ذHCbc/މRXdJU::FJ `q4`z nVR GTJE)"~?2 뺪 URi(O3fd8h*hTb !]Z?UXzǡ0g 3a x& ;j|Û/?c~B||˕kށ@BZD ADZBO! j!H~Z2ݷcJ),Z>3ֻ`CaJ}tDH܊vc$.Oo߈zcߎc{DEZOz:j]^U Df1P23֞?|RtRS.Z4 aY;WDL-@ 1m7bzXp߷ "$eDZ6ɕ5׺LDa)RqG MA%^ץۇHjm 5]n#4DP$! nv9}\XLϞ֒61:'RYaޏs" DB4+@rg=_m;pus2><щrv؎9-ݑqߎ(Z5*ldo C|}Mm)|^ÅX}t"ILZDLp~{o=<.gaRt:]2ݙ"|]0DP032F7 Rd"°b 6Djnu!& bX8vl$)?sxoa7ƨU=\er|v? 2[km>leZnᔰ@~h}oRXӧ-c? 3!yx)(!&"UZ 0J {UJaB^NLdnct62{Eb#i@mHzmsO8̇@  [K3Zf,XhlGH8?Rd=j]۶owa\".$*z>UC FR#LD X#%|l*Assc8c Id؟.DZ)oE,T"4FyDk1yI `CQR$&K(!}-)ž]_|D[1eآgn>"j9ZuYXu"V\DYohBiQ<Ç$nic1Otw?{3Pqxxy] ` "2 dpfGs+GzDz#@d:72\^˘,UCEd=]:Eohh\=8_jEGovZ`ed;&oYG1ZǁcrK},瓪>D%o|z|{#,-s. $#KeaNc8hRDL $02)Z2*Z[TUqÇ[ocR7LyYfz "2t萢XJ99$ EL,U"'huYY"[t3Zu,Wmzۙ o`(tּdє382,E=Fb +vxgn[~aZ qJ6"_QK}DpD ɂ@̷ ezbO^^Y"0zZx[ksLQE2SmXOEU0b# f!n\I]ǘf$!a"$|e~mL)J"R* [0bmˆ4uj'"2c}c?l桅qcf&"izM(c p}@ -UM,ƒ^pf{HD.v fG%ؙϖ/XO>0LL} PΤ\Ph hh)‘Hl-u%8Yt}z|?EÚEN_6<`=>}c+ZֲDHu]k-rY-EU_Cu&7ό}60eq4ѭ=P̿0`V&Rzw{q5Ù'SgNV#boLnV͛Tu:m1fSH8@Œ ? #5l^wc/ޥY%[y9@6Y4)2M6ɮ* ̈p H$'+y=boo 1n[۫XGD02Zk49'$;cduΈKڽm\cϏu;_~!`J!9m3D麎uY9'S-_c>88}IY138PF{k2=gMw"zy $ ?X۶nEf f"Vz>g~o+ oQQ2EbzB1SYU>y*U̠Pշ7xΔ$^wVWf^׵kir*,,QU}'Q39r=:Y*W:9yLVcED57ӍAb/vfSrmhuMbW'b\b ʊ ̄\DfzFDQUU̜\Eqf&CBç/ l10#ʘ1Ds"/oIJ ,BMPbEU,DQxsZ"P[1\nd6Ӗᕮ̧gA}>$WY!q\Slg"Y˸pT@aA,fcpu^qfդy[bHQ]܂v`FW.Z'mﭿ10:ueD8JzbR/o|z?1じ,>zWV>+baLTEz((V!^i٘N&FcT (0{uMIʄW’$&iQQ~լ+o~ӯ__-2E96}c8irFH VT"~3 "fqxDFu*Z 9D3Rj1UUrFӛko7-`- D~ͯݲ&\d δ%DJKxZ9&RUI9(0m}r/"Җ|-A>:H_PZ?3")EoZy[kq>R39rߵo*"}*BĭX2.c<.)FU% 3|NEEX&+^Jd yx}5(m=dstL0F3ɦfi#+#J/bjB1Adtx<cŪU%%BҔ2W8U@3 g,WjlzT^Rf޺uœ~Ӻn*oկ>㼮Ki}oȔϟ?߶a%&QrV(UƯc*PL2| jMfӌX{&*j Is Yzcfn}nfBsvOqׯΏ!\E af&[DYu,⢅\t #<%q%D8#ܣl*)2ETX[1D+8:+YHII f0aTu߶VېD'&UEH1Qĕ%^YcH @T\9ޘww$HҦ}ڬU֙m͚pTlXy IDATZbΠ,VLjBEZ~_gT1|foVy[3a3;1zZ&c|z\WEc"1yPXw%BQUƒMG`a,mˊ,Vj].oq֑gUDAp|.O٤yW3`uS*+8ϋHTT=|6!#`UE~9m_ڞLuyQʫ02:~HeIF.)MkL5S[`zĖzV% Q $+D,AsD#1"#UwiWD7Ȍ<ӝ<~x-<:r։Tdr]\f1PI(958sE4rQ1 o}U &6Ȅ$b=bRq ɠy|Pwh#8hϭIkbTu9#jDGT VH08T9** ƙ1}E*'ɦڒVY%<_ }{$"r5ezY#C@l%^8cxy]M^'wf#VbfBDg:KrId(ڽAPDyzI|6 ڈr=*1Ix>y4Jij< qтD(E͢JUf"b0CM{ϿLUiၪ UD,{\MڬUDl Ek)1i;##L5{'Lc0+E1@=#]d=n@"}᩠k$t{~4i) 53W~WU<'mgb-bI" RA5BsN9HZu"auD`JܪDyͳ%+cmxyk&tۛ03Ed!|^@/TVai%S_^TT"9 Ă 3RR!k$e@&G*y?_2w,gʢFku#(c\Lm}!f!n<33.Lv#&jY5@USMkϟ?zfΑ1ZΘETpzD,tp$H\Vv`!@TV^ #X羑ȧ"xBh|EDTLdH:=Δ{z& )X<=KG -x~LfUq >`/aqBNdzqruU'DR,"2(Y6b!DxbQT9VY+K3 32HP6G49kDqEPfFd0ED$ ZaAr&ZMI[7Z'u]sN&*OZ!5$2ʘykΙ57c1HD.;2v~|6}=|+-@ʜ9,-2UBU~p 1MwwQb3hHʶsLg.b&,}x㝠 N[D=q<:7N mf*k?s &%x[b9Fx+b5qzPIBP(SUD^*5QLTH繚Y.0_ HFj,r1+K Pf*cYklԗQrݨ*Y VVkĜU5}1笘IL[fy~&xu߲q~\,dbak wdCRu̞kʔ%mv1Ix>M1fVHJ?`]35Nxw2%ǷqVDIyRxV?#K LMEMI5Zgb! +|J+;ϑP39 1!$ED9< OAƨ/y %Ԙ"k`7LTLPkĸXUzkF%R}"ygD`An#L)#&q*3QeLXƜuzƬk$~OV5Y@x( /,h " )dRs[̳193oҌJbwUU^d,d Wŷ(Pix||}Ϗ?b= H%a_@ȵW$&ۭ}%K[ބ4#<§m}+ y|<6|=+~\ʜBT8u5$hk"f,&̢j;.mH}֘ U~9 W$1I℀Ԕ6ICy~x|}ZgٶVΑ(ePDTѾLtmK̷}b⬈#K*mP&(GP͝71F"w32gF(z/Њ6c )ˁDWE3Q~}qxDE͙_=bk5tyB.F!Q0b#T& +XߪY1Yh Hequ/?-3 u@4@M_N_q߾Kmk^ǙIk\@NdHW*$LepeE WsfLD6b3%IoR(-$ s"Zon}nDxKM^Xs',TҒ_̈99##FfxO_:q#+1eȫ`)B2;9DUL%Li̽o?*"X3VVVmIL3ƭnQ3:}{E:SKax &"#XDzSU*J. 35L{f(Ѧz3DgU9#dogJ:@-veTskzOwNTy?3DؒruR"d1lWU d~rMU AeT SeP>OOgUs*Unܧr*˺ի,n1_cK "Y`&sVBgE*JE遗_syGV]וnf*\'9+Y۞Y"J+,moo۶'O?iۈML[Q3~qKNmyu90C8qedZـ5rpe1 $"X ,^܈ D,Rb>̀ }E Ql_U̢Vq C QM_NcY^*`"X1F}nMYc]%uNgFd5">kG:D/Qua^U#[ b{&e&= _~ (TΘ @fOoHoUU{ X;K[z\ TUJe- ںNQ"K1+|^(Ex)۾_$9]ÿ`oߦ}'JE̙BH1@Yj "b؈@%UTEJIW2+#UMsf8, 0EkoSu;_XjƸӧm1bPeT5Qkxeq= .rf*=*Q>|mlۖfYѣ`X#W#|zx| ׈mEcͬZo4Q: ֬u᷷69x0kzy>Ff|$Sa _ "Qj)CиtB~o۞˧ۯχ|Hc}{ҷϭB2T(n_~j9=)\4ē0DPr{:?q^B;oq7BUte}_1q]2#BUbZ1/ZТEU9U0_ሥWY0&Ejӫ*Ps,slJ^&DD EDx>sD3#sTIT5Τ?ED-eu[I" <1z?Us^e#*Pan <)ց"HUA+=C"QMuo&*.f/_mQU%( A*H(dRQNsuBkP0!2FĕWq>~_ގkwb7,3ڻ<χm7Z NA.*ӯQD .*9JHյ f"pLizYn]W!288@&VqMj*ZϘ^w!CMu]R֥o9s]z㒇dqfiIm$(fD=I+=>|&XHf[Wm`JIB!*TL۶ ŴإIs LoedB~_CZJ2 g(ңCOg*:8#kXs7&w=I2Q)Te> _g*B1=QIQ>9 *F̖AZ\gxֿ&+7'ۿ/KI8ݝJHhVTydQʈ~΁mmj E5#dbqqy*  6h\QTq_ 2 F"BTWU1CD2H$ң*S1/ntXbAyDH@ܲ({x$"YHk+{\Ӊ_T}M+=gU01T8\*iD*75~r5s(6cPm5,>93bTINF SŊ D—YHԲtIlL縦k߳ooT% [2/`3pGSMU jU*b/0HܧK0-̈́bdz05UD IDATscLOp׏u($"jzs_;b%- 9c1y11,D$5#FF]usN~||K̹IT/._exe="(֞j&Q?䚋b -EDU1+IT@U@5U^Yy`fD$U8NKqsxLq?ʚ7o n֙8s.B_;SanZyq*kctu]~4!DTetW =PYUgd Xd]-HGULf3H9Wa$U)U[(rX-bFVt!FkuFD)ʧ_c^cĸy|qocIr}TqmvljhZ @FM4Y\X{fvqwoӅ$Y]mdFoLS-N n` J\'u-Lr(fH!bK`D$L*3RFYo۶4ՙ궯> 7_,?gXM{_?)uݼ Mj@ B4sL*D{vaDBf4 OC4=t7"40T75BHi THmH 9OXAb2%"1N" 3TTP"X3 a.2^NԈrPj$!ka~U(!BeXr&DkƀԂnMa2G2a3r755X$H"lĉ!\%\#3XTHf"; ׌$Sܛ9/*DB,$2y0_"2!+";xPFĥA1!ƀm oD_'x( $DBs>F$4W)C\X#<gF12|lqAdbEx'@xhwSOJUq뺩d&޺U Dbw}7bUIZxnfcp3z@ eTB9dwcC)3Um:%55LIxxڧ_EO KW[`*5 9 O^"M}Q#P.n[G`!*Hyw${'`BAVC!(q"bz`  9שj/!=2r-#S?!F~ %DZoµ2'P#@强[&%b7Á PmnѴ72nŒ0ڷ<Ȝ,>=1 00F\$ENV3#\=l۶DDޛtyZyL<r2w*Lƀfe<׏gD 4'r_+6Zt3=FlPgOڞ7gzHh{T8"GO@[ojڿ'_<ǟKAkȃ~32sp&p{7H֞^IՔKo(2 xlL@"y hDDc5轧 sq A+kS ~z>'e}k )u&|s{2M(0 Oo_z|ۚkM@[/,ȼ_~OsfAqPhP7HWi<"U@ޣoCIx$j QD"B#pkOe&.Ydrdpm6ZxɄ47!$ U!G@Œ(EJmlO (Dg2s۶ku_-ں@4@"dMjM-ݝ SFӈx<d2FddoLP'tz:=>EOk23r!BtN$&"pQ7|ΗE){oˮn_?pyj-YsP0PM20cLM<C-¯#{U 3ܪHC$0 e)!#bsI&^ra&B"‰@\nlXscBik33CZeԪ"=ƔkePDL@mı@ 4LL/]&/o㋃0R,s嶇`s#I{k DPҁOO};mɬeXx``7_/~kֿ`}wջO9 "13 _Jȡ!")93"i$ٮ04U@ȼZG23F0#90frz[dkӼ,Kf0DܢCBXM0h(ã؃xg"H ,c 73L WO#ٮ@=2d=æL@a2T̈T05#R}ȈsW;i7q:~7S2 е!IFjg&L5u ;]X,ytH`ψR>Oo3W,Hg9*T2*b$S+1!dK)WW0s1S#X#J7 NTČV^R*"B12~ ND "!}^sߧ29Ȳ?pJ-wǻRZy!ioV)ĕG̝d *u{۶F7U59}x/??} ӯ/~B; ۷BH`eT[@>%a1LUH̥3fYxA", K- BaͼL aT/fjur.&BbD(TA~+0!XoAT[mЋt[;jFDt(< C.eɇÁE"t9'@prP3)yYF9!"2~WuIÁdպkJ: jDV@$&MxuýnM/KGlû`}__~o+ @jCdv5 ˠ 3aG̬"&b "iM&tXh=לq)RJ)LL'%A2SfrpF2&b&p=Ѐ3!wo" MUGz},0Ղt\yC/_-˴}-y+\ه iwĄLp&qψRrx; JLA DBKP͆Jj7w@2.P$PYnnnHa{o;H0kEg~7ZX=>O#tLB”є3#3dlhztd&Zʰ*\(ljF <ÑjԖ2`WsS5" 4G6̀$J\CN֓ L0cԝqmOWf$1M#,z _oۖ,"SfD# Z&* w/==OMpdf[.B"2 I @zLrEJB8A&W"bR TOϧGvHdjz{sn_}oIkO/ZybL187w9vO3F`pc5Hh(L ep9"{o0ױ=M_RPoDRdPdfI5|ٞcu9&0I:YvݷaMy_aRKCr2M≈<{_Ƹ?H$n8ls Xjޛ9!fջO%W,O~pSݶs&jf(jRfn{k[|_V/,}NT1|LF5mp $,S9NU4,="92wi&IezPjᒞ,L8ZL4RDDSDQ՘% 30} 5 /kkm]MUu`rL "s;??82f3Dqp4XxgDo=3Ǚ.%OqݚG*02Maob+Dps8Zes ylۺ>by7p)h#,uB3*dghR)NSbcPIa勗ǻՋ7uZyӢ[/nkxpLﵰvoL`f[xwU3WU@HfnI\VaD&&$NK w!RaĂ5p 6daJZEDXj)\BP)=MxtL@ZX( %@BfZ[}9.a @=3YKbSǰZJ YTγp' n{ US%2Wbul&FYqmQGrMC!T4uDBJ1{ŹP@0$R$ &P͵@DzorktLdl`[=[k+0/2kj-\ƭl&ba@lᙐ8ֻ!e@>>><ߌi 3,TRBM*V)20]?lfBŨ)/BƚI2&mfzn`)"Etu̫ sŁ2y-mJդˮM]{Zx4kBE(ۥQMh Q`]<K=9ߜ?t{xm.Wra@??խA JHRJb} 0qA= Ji(".WDn(ʠ졄³o9a*ٷ r#A\#?nEPZxn~U>G8HhZNk ޭ86kmy}*j/Y\U~ae~?}B W*QwUYu4HG TiA]=z,B\0#RXLSdtC 3{$'ZF_A",HD1H "̭iF/_:ۨ9* DǛL9 fg&`U|]9 IDATp`ۺ==i"b/ra|>YLȀ.PPF)\Ec=O֚ZCDs;FB(LNǵDL8jOoJwwyfZoo Ub  q WI@EZf 9*QA$upc<&ؓ"2 FDfX8sx io] 1Lf*Ⱥns+AWL`B\kr2zޞ*Rʧҕ 1ci" y\«aNIdk{x>?׶۶^w3=<F:S)3*cg^/EVf2oxs>~g_CXXۺn^ J*m`e5`@Wk6K %H@& tbdD XP\2)\ M!rf${y8XEH@I::Mw抌0 ",E +S8eRet{:=Gئ1"SPa$Ef/T*֭Nۛ[n=={kaİ" 92ށ2v:8",HH&N wMD$)uZ2ӻr hSBd23f)՜#Јedj=2|0q8 3!,9h\=3QM\{_[no޼{w>Ǐt~HPz `"6G6" L3Szs{)<yɱaU[ۻwRʼ&YM#i="Pjs V2M);}%"r7S톑,ű>=<4YJDx`#\,jj~ #/P2t7U{77ww ? "2`K2 p.F΀Hضnۥ?/~꓏O}{I8ž6E)r =LIKq@qy.$nyU0@9LR FBB{/uur".id@}H4\=`l̷x.rfz9[7c@nW/ 0( ;l[HaDkU ^ի:HH~Y׳SՋRiziP Fr?{ӏ><<)o 2ֳL*/_({9i$j5!KMD`f ,Bz cVL&/1ohDD"#(iNDbdW0"tv=#{}N2i5$nwTpBd趭6_"<{k" "g9@ |u=N@n{dQ)2Vj>*1hL q}DЁ[\ukǏW_~![P P-r3Ȅ 2)d%|Fj*2",B:LKRVd"s߷#XX`Dba{ޑƿ"mcZM۾ﭛ9a0H$N|YߛiH&Dә [۹놐,<ȏDn#0KD00|8*'{  GPµ ֬Xdp'*a!Hn?p9`mfuo?~WVmtSò/^uJHbP DV5WMB]v 75b"ZQ̺1isF31GX"32x)t{sexy!̇5W;,_p@.i?|BU `jA*5uz{:ܜ>-OmY<:~-TZzn?}{ͥ}piW$dљ!%5N懘^4bn>g\󑆪$)?dJ10k9bjz2ju ͬkmZ ×Zt yh 1g&f5W_@ߑc8u)\Ԃ禸3|u:M}[޾U5իe~Y M)3paduk3aH3zsK{"L9yi!k.HH w 3fʵD.32Ôvc1Ɗ S=*[k!":ć6]dжm>TApN1=Pb&WV#ŗ 1eL4:#Ǿ'r32[ uغ=~|L}{Ý>^?{QZ/?_ ڶ/Kr)4<ގ 02cAhxE>G" q 8.j)1'FDK)̄D!65H)g uOMho"]EO֒ 5CFF,̉)\#@$Ĝ8OS%1y91lJ%>]tbv0mԻypYv6y>_!&_~_ mt ꌔR219|CB=ܷ}{S`3X\U铉;G"9uo]'9|(= "sNԒrJ)Tz@ $74@sD^^vs#r:fhM&oDGkNy!8ĉ~6EL)%b)ĉs-))jfΔ!0ֺu{,׶{x̀j /dս/חoUo&۶zʩΧ1tU0DDlbch3+ s $IܥCFPuMD 1(Q `"˔r)3qR311L1L1Q Elo7GDJF"D{ﻃ!:#`s<W@&"M@@<]) ghS&5۸?>}x]_Tm*ۮcmO&?WniRr`faD.c GLvD_L0|ʳL)"232{PZs .9ZS.SΉ;F3~*h]z[[o 1r &7Z!Cezxx0ұ9'"J)᫽;3jxwNwehe][-}tSb F/˲~z~yǏC XǺ7:l$ZQ8P;y0er7<<!8 8!ba@.gH%s) N<4;Ý78˲G !;n[۾\qLjќ ~EꭋsJK.䜋#! i[3imr@ 4͜r.-1 P>T@$ (La҇>LqJՃԣu_SP(&dT ֵww~~/įH'Rr#źK9O(RS.dswsc@4572_82jQ.t?z"@w1B>LJrGn$ʌ2\jMUD rJ_F͗W*uT\.`s31) pUpCQ 5k`Ĕs0q."xtDĩ a ۺm7QרwGx\TJ bm(p%>,2:ה՜/KNK%TTS>]4ML4֙/rxNx>Oib<ͻ[ [e]_n޾~|_Erݚ&)s 懅"1Hst^k#Kbpp m߻ >TEEB,SrR~."4Ms tӜs9]3Oa+QRjTSOf8AνuPIR̓z B6bۺ!֟o_>|ꗡ&-=ۧ/<|sWT FI)Kyk>r1!sjADLl H `2!Sy~B`,jS!"5gumϷ1ϵgbӑ>SxJ9#Tj1|.ЕCمT5T4Wte>Bw-|,#|r?~z]_ֿWSXѷ<|z^& >FWMZ7r9TD]͕- OuB@:S)sqt?t@( #^s.H99qbf)!&vpdթui}s@l]!LBa>[{ wxYn/y}_XǶ(ݖ.g !&@A,ۑh39H(CU5/Dy\sfJ@*&omt 7U88 ."&öm7. xY͇ؾmYeٖe[;203'@PS"P}L$g^MMɧ|{| }#ulkzۮe@\ eNm[ f3 S7b Uއx@fcBZǟˤs_KÇܞo5뭜.<<76s)cY٦H)[)!E1{Os.2we̠ ]sR8 JASJTfNX*w`LrRbQZKeƈT/w9m Dsuum%bq̞009e׽9@(u+8{ID`)!2#RC,"P-v qT.f0_PuuӔmtOoOڇ [$/|͛7K4].4WxGyyN (bsS5|W!&n)hW3%Nj&MCC0|| ᡠJ}s ?~T_ nyΗ9kN8w)MuʹDȄ* PJ.SA"HJ-}[M-jʡjD10:Uo{3?<9t|0#DsZ}LR*OO|Z>=2?_VX٢pww9/SJܧ4TĜԣNSIvSJS={h9q{180 Z轫*"8f9} VwDՒ?NDL%ePN\jabQ#@\O3 *"CTrwWk8d\R "ș%#55xk,em?>}[]IDAT'|J9\Nr>RJ œkb,93333橸}P`ӌUBA-М8%S;1\\C-ֽ_[Dܿ9[޻-.򲽼g6: ;lO/*;;hS=]i*K=7:rJ4%ħ5SԚi@d.[Z33!'' ffધӄl!{6m(#,[p.&:z{ 7'_!ʥi* 250 ... Sender ok rcpt to: 250 ... Recipient ok data 354 Enter mail, end with "." on a line by itself Subject: World domination: instructions. Commence stage two. . 250 RAA10452 Message accepted for delivery quit 221 tecgraf.puc-rio.br closing connection"pnPZ02 6  $*$/  1$$@((+,,00)4488,   "    !Protocol abstraction status, error = smtp.send { from = "", rcpt = "", body = "Subject: World domination: instructions.\r\n\r\n" .. "Comence stage two." }dP'Cc C c C6ccc C $$                 U & LTN12 sources function ltn12.source.file(handle) return function() local chunk = handle:read(BLOCKSIZE) if not chunk then handle:close() end return chunk end end,#dFC ' Using sources status, message = smtp.send { from = "", rcpt = "", body = ltn12.source.file(io.open("/mail/body", "r")) }dP)Cc C c (CcC                 ( ,Message Format (RFC2822),! | From: Roberto Ierusalimschy To: Diego Nehab Subject: World domination: roadmap. Content-Type: multipart/mixed; boundary=part This message contains attachments --part Content-Type: text/plain Please see attached roadmap. --part Content-Type: text/html; name="roadmap.html" ... --part--0}PCC)C C CCCC  C  $C$!(C(,c,0C04C48C8SMTP dependencies  A Error checking DFunction return convention Return nil, followed by message on error;Bd*dA  EBLTN13 exceptions try = newtry(finalizer): factory; On success, try returns all arguments; On failure, throws the second argument; Calls finalizer before raising the exception. foo = protect(bar): factory; foo executes bar in a protected environment; Returns nil followed by any thrown error. "d}ddXdgc` `  `e`.`  a $`$(g(,c, 0`04e4 8`8?" dd@%t?" nn@ @` n?" dd@   @@``PR    @ ` ` p>>'I $(  $ $ Z 11ȜȜ? @  > T Click to edit Master title style! ! $ 6 ?  > RClick to edit Master text styles Second level Third level Fourth level Fifth level!     S`B $ s *D1"X $ C "A moon" `H $ 0޽h ? ffb3D<___PPT10..&@ Custom Design    P* ( j`j   0A| P   >0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  P*    0`J|    >0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  R*  d  c $ ?  >  0Q|  @ > RClick to edit Master text styles Second level Third level Fourth level Fifth level!     S  6@\| `P  >0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  P*    6b| `  >0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  R*  H  0޽h ? 3380___PPT10.qZ  `(  ` ` 0O  P   > X*  ` 0 O     > Z*  ` 6O  _P  > X*  ` 6O  _  > Z* H ` 0޽h ? 3380___PPT10.P]O'O 0$L(  x  c $P =$x  > r  S `;$ `  > R " s *p@`B # s *D1"XXX $ C "A moon" f H  0޽h ? Of3b3___PPT10u. "z+D=' ̐= @B + O'O `H$( .1@ Hr H S 0$ @   > r H S $  > H H 0޽h ? Of3b3___PPT10u. "z+D=' ̐= @B + O'O @$(  @r @ S `$ @   > r @ S @Q$  > H @ 0޽h ? Of3b3___PPT10u. "z+D=' = @B + O'O -( k   l , C `۸$ @   > l - C ܸ$  > H  0޽h ? ffb3___PPT10u. q+D=' ̐= @B + O'O ( {5 l  C }$ @   > l  C  $  > H  0޽h ? ffb3___PPT10u. q+D=' ̐= @B + O'O ME (  !     $D,PH___PPT2001$@F  0" XPH___PPT2001$@Fw  <@'  0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  3 David Burgess   0"`,$D,  0"8x$D,PH___PPT2001$@Fl  C F$ @   > l  C G$  > H  0޽h ? ffb3. & ___PPT10 .qk^z+bkD ' E= @B D ' = @BA?%,( < +O%,( < +D4' =%(D' =%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<*%(D' =%(Df' =%(D' =4@BBBB%(D' =1:Bhidden*o3>+B#style.visibility<*%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =%(Df' =%(D' =4@BBBB%(D' =1:Bhidden*o3>+B#style.visibility<* %(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<*%(+ O'O 8$( A 8r 8 S $ @   > r 8 S P$  > H 8 0޽h ? Of3b3___PPT10u. "z+D=' ̐= @B +l O'O    f ( ff l 4# <#,$D,  6"PXPH___PPT2001$DF   <4#0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  Ffrom l {  { ,$D,   6"h XPH___PPT2001$DF   <-{ 0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  Frcpt fl X h  X h ,$D,t   6"X h n  <  0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  *body r  S $ @   > r  S p$ > H  0޽h ? ffb3___PPT10.q"r+D' E= @B Du' = @BA?%,( < +O%,( <  8 H@ x     P+D4' =%(D' =%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<*%(D4' =%(D' =%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<*%(D4' =%(D' =%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<*%(+# O'O \( A$  l  C p$ @   >    < $  >   60 ?P ,$, ~What if body is large?:d  H  0޽h ? ffb3___PPT10.qh+]%DO' E= @B D ' = @BA?%,( < +O%,( < +DA' =%(D' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*%(+8+0+ +  O'O  0( .p1 l  C &$ @   >    <0( $P (<$D< Π   60 ?( h`P___PPT100(v___PPT9XP___PPTMac11\T   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography  pUse callback function that produces data; Returns one chunk each time called; Signals termination returning nil.LqZNE E  qH  0޽h ? ffb3___PPT10.1q+YDO' E= @B D ' = @BA?%,( < +O%,( < +DA' =%(D' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*%(+8+0+ +{   O'O $0( 0B0A0B l  C $ @   >    < $h  > p  6 ? hh$,4H___PPT10( f___PPT9H@n___PPTMac11H@   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography  What if body is complicated?Bd` d`  H  0޽h ? ffb3___PPT10.3qF+'DO' E= @B D ' = @BA?%,( < +O%,( < +DA' =%(D' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*%(+8+0+ +9  O'O .&@ @(      6",$@,   6"$@,PH___PPT2001$@ F   B"D$,0___PPT106___PPT9H___PPT2001$FB___PPTMac11   hnamd` Arial&Monotype Typography  -headers r   S $    >    0" X8 ,$@,   s *"X$@ ,PH___PPT2001$DF   6" Mm ,$@,   0"4 M ,$@,r   S $ >    <  x $,0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  -headers    <, r $,0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  *body    <@tXlD$ ,0___PPT106___PPT9H___PPT2001$FB___PPTMac11   hnamd` Arial&Monotype Typography  ,part 2    <  D$,0___PPT106___PPT9H___PPT2001$FB___PPTMac11   hnamd` Arial&Monotype Typography  *body    <`e tXL D$ ,0___PPT106___PPT9H___PPT2001$ FB___PPTMac11   hnamd` Arial&Monotype Typography  ,part 1 H   0޽h ? ffb3!!___PPT10!.3qFS+fDd' E= @B D' = @BA?%,( < +O%,( < +D' =%(D' =%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<* %(D ' =%(DR ' =%(D' =A@BBBB0B%(D' =1:Bhidden*o3>+B#style.visibility<* %(D' =A@BBBB0B%(D' =1:Bhidden*o3>+B#style.visibility<* %(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =4@BBBB%(D' =1:Bhidden*o3>+B#style.visibility<* %(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<* %(D ' =%(DR ' =%(D' =A@BBBB0B%(D' =1:Bhidden*o3>+B#style.visibility<* %(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<* %(D' =A@BBBB0B%(D' =1:Bhidden*o3>+B#style.visibility<* %(D' =4@BBBB%(D' =1:Bhidden*o3>+B#style.visibility<* %(+0+0+  ++0+  ++0+  ++0+  ++0+  ++0+  ++0+  ++0+  ++0+  ++0+  +  O'O P(H(  (r ( S  $ @   >  (  BP $ > H ( 0޽h ? ffb3___PPT10u.3qF+D=' ̐= @B +  O'O `0(  0r 0 S @ $ @   >  0  Bp  $H  > ? 0 6  ? X@___PPT10 V___PPT980Z___PPTMac114,   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography  UTransform declaration into an LTN12 source; Pass source as body to sending function.0Vd-`(`U H 0 0޽h ? ffb3___PPT10u.3qF+D=' n= @B + O'O (  l  C  $    > l  C 0 $  > H  0޽h ? ffb3___PPT10u. q꾖+D=' ̐= @B +c O'O VNpP( +R Pr P S  $ @   >  P Zд  ?$X  > ~ P 6  ? <4H___PPT10( f___PPT9H@n___PPTMac11H@   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography  ZWould like to send PDF; Binary data has to be encoded (Base64); Want to encode on-the-fly.>[d`(`` Z H P 0޽h ? ffb3___PPT10u. q+D=' n= @B + O'O X$(  Xx X c $A $ @   > l X C PC $  > H X 0޽h ? ffb3___PPT10u. q+D=' ̐= @B +  O'O \6(  \r \ S 0 $ @   >  \ <`  ?4,___PPT10     v___PPT9XP     ___PPTMac11 tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  [2] = { headers = { ["content-type"] = 'application/pdf; name="roadmap.pdf"', ["content-disposition"] = 'attachment; filename ="roadmap.pdf"', ["content-description"] = 'Detailed world domination plan', ["content-transfer-encoding"] = 'BASE64' }, body = ltn12.source.chain( ltn12.source.file(io.open("/plans/roadmap.pdf", "r")), ltn12.filter.chain( mime.encode("base64"), mime.wrap("base64") ) ) }dFCC C9 c IcCccc) c $C$(c(,c,*0c04c4#8c8    <y ?H$D,8___PPT10F___PPT9( R___PPTMac11,$ tnamdlCourier New&Monotype Typography  Ufunction ltn12.filter.cycle(low, ctx, extra) return function(chunk) local ret ret, ctx = low(ctx, chunk, extra) return ret end end function mime.normalize(marker) return ltn12.filter.cycle(mime.eol, 0, marker) end.PCC  A  6^ ?H @___PPT10 V___PPT980j___PPTMac11D<   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography  MChunks can be broken arbitrarily; Filters have to keep context between calls;4Nd"`+``N H  0޽h ? ffb3___PPT10. q꾖+YDO' E= @B D ' = @BA?%,( < +O%,( < +DA' =%(D' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*%(+8+0+ +&  O'O _(  x  c $0I$ @   >   <@ʓ ?$D,8___PPT10F___PPT9( R___PPTMac11,$ tnamdlCourier New&Monotype Typography  int eol(lua_State *L) { int ctx = luaL_checkint(L, 1); size_t isize = 0; const char *input = luaL_optlstring(L, 2, NULL, &isize); const char *last = input + isize; const char *marker = luaL_optstring(L, 3, CRLF); luaL_Buffer buffer; luaL_buffinit(L, &buffer); while (input < last) ctx = translate(*input++, ctx, marker, &buffer); luaL_pushresult(&buffer); lua_pushnumber(L, ctx); return 2; }.FCC  H  0޽h ? ffb3___PPT10. q꾖+YDO' E= @B D ' = @BA?%,( < +O%,( < +DA' =%(D' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*%(+8+0+ +  O'O `L(  x  c $ $ @   >   <+ ?$D,8___PPT10F___PPT9( R___PPTMac11,$ tnamdlCourier New&Monotype Typography  #define candidate(c) (c == CR || c == LF) int translate(int c, int last, const char *mark, luaL_Buffer *buffer) { if (candidate(c)) { if (candidate(last)) { if (c == last) luaL_addstring(buffer, mark); return 0; } else { luaL_addstring(buffer, mark); return c; } } else { luaL_putchar(buffer, c); return 0; } }<*FqACC  H  0޽h ? ffb3___PPT10. q꾖+YDO' E= @B D ' = @BA?%,( < +O%,( < +DA' =%(D' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*%(+8+0+ +V% O'O  d(  dx d c $` $ @   >  d < "  0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  Hsocket  d <p " @@$@,0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  Fmime  d < "` @@p $@,0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  Fsmtp  d < "@@$@,0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  Dtp   d < "` ``p 0___PPT106___PPT9B___PPTMac11   hnamd` Arial&Monotype Typography  Gltn12   d 0 @,$@,  d 0@ @ ` ,$D , d 0p @ @ ,$@, d@ 0h @`h ,$@ ,B d 6D@`` ,$D,B d@ 6Dp @` ,$D,H d 0޽h ?Odd ddd dddd ddd ffb31)___PPT10 . q꾖+,fD)' E= @B D' = @BA?%,( < +O%,( < +DY' =%(D' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*d%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<* d%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<*d%(D' =%(Du' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*d%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<*d%(D' =%(D' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*d%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<*d%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<*d%(D' =4@BBBB%(D' =1:Bvisible*o3>+B#style.visibility<* d%(++0+d ++0+d ++0+d + O'O x(  xl x C 0d $ @   > l x C e $                "X > w x <pq  ?@$D,l___PPT10x     ___PPT9      ___PPTMac11x p  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  cfunction metat.__index:greet(domain) local r, e = self.tp:check("2..") if not r then return nil, e end r, e = self.tp:command("HELO", domain) if not r then return nil, e end return self.tp:check("2..") end Z%CCc C CcCC C $c$ (c($,c,0c04c48C8RD  T   x 6}  ?p $,8___PPT10F___PPT9( F___PPTMac11    hnamd` Arial&Monotype Typography  -Tedious, error prone, virotic, not finalized.".d-`- H x 0޽h ? ffb3h`___PPT10@. q꾖+{ D' E= @B DS' = @BA?%,( < +O%,( < +DA' =%(D' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*x%(DA' =%(D' =%(D' =A@BBBB0B%(D' =1:Bvisible*o3>+B#style.visibility<*x%(+p+0+x ++0+x + O'O t(  tl t C !$ @   > l t C #$  > H t 0޽h ? ffb3___PPT10u. q꾖+D=' ̐= @B +,  O'O   | (  |r | S c$ @   >   | <0n ?- \Tx___PPT10XP ___PPT9 ___PPTMac11 tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  function metat.__index:greet(domain) self.try(self.tp:check("2..")) self.try(self.tp:command("HELO", domain)) return self.try(self.tp:check("2..")) endZ%CCc C Cc c)c c $C$:@ ; l | C 2$   > H | 0޽h ? ffb3___PPT10u. q꾖+D=' = @B + O'O  (  r  S =$ @   > l  C m8$  > H  0޽h ? ffb3___PPT10u. q꾖+D=' ̐= @B + nf@( @ R  3    >l  C | @  > H  0޽h ? 3380___PPT10.qZ  tl(  R  3    >r  #  @  >  H  0޽h ? 3380___PPT10.qT6  tl(  R  3    >r  # @R @  >  H  0޽h ? 3380___PPT10.qT6  (  p` R  3    >  C p  @X  >@P___PPT100(v___PPT9XPb___PPTMac11<4   hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography   YDavid, who lives in Melbourne, knows RFCs by experience, whereas I only read them. First FTP server written back in 89... My inbox has about 700 messages from him. He wrote all of them while being upside-down, which always strikes me as odd.:S&+M  H  0޽h ? 3380___PPT10.qT6  sk(  ) ) R  3    >q  C >I  @  >@___PPT10 V___PPT980J___PPTMac11$   hnamd` Arial&Monotype Typography   What is SMTP anyways. Text mode protocol. Send commands, read back replies. FTP also uses the same underlying command structure, and the implementation of the two modules share a subsystem.&5s H  0޽h ? 3380___PPT10.qT6*  0:(  R  3    >  C 0`  @  >|X___PPT1080___PPT9h`___PPTMac11`X   hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography   6Here is the simplest interface we can come up with. We can add some sugar, such as the multiple-recipient list, passed as a table. It works well for small, static messages. But what if the content is large. Messages with attachments can be several megabytes long. We don't want to load all that up into memory.H7*[ (`"( H  0޽h ? 3380___PPT10.qU  ^ V @ (   R   3    >\   C #`  @  >___PPT10`X  ___PPT9  ___PPTMac11d\   hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography    The idea we use in LuaSocket is to pass a function instead of a string. This function will be repeatedly called whenever the SMTP module needs data to send. The protocol to these so called "source" functions is formalized by LTN12. As an example, consider a source that produces the contents of a file. This is actually a factory: a function that creates and returns custom functions. Hail Lua, where functions are first class citizens. Here we are also taking advantage of Lua's lexical scoping to store the context between calls (file handle)~!HT!* ` GR3) $`$A((:*  AH   0޽h ? 3380___PPT10.q, ZRP(  R  3    >X  C 0Y`  @H  >0P___PPT100(v___PPT9XPR___PPTMac11,$   hnamd` Arial&Monotype Typography   <Here is how we can use a file source with the SMTP module. Nothing is really loaded into memory until the module needs data to be sent. Even then, the source can control the granularity. But what if the message is complicated? We don't want our users to be forced to know all the details and write a file to be sent.>=;.S ` "S H  0޽h ? 3380___PPT10.q, RJ`$(  $X $C    >J $S n`  @  >lX___PPT1080___PPT9h`v___PPTMac11PH   hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography   pHow complicated can it be? Here is an example of multipart message. <> We want to be able to describe a message like this, without creating it in memory. Roberto would never send me a message with an HTML file attached, but bear with me. DDS T H $ 0޽h ? 3380___PPT10.q,, p,<(  ,X ,C    > ,S 0`  @,  >H___PPT10( f___PPT9H@N___PPTMac11(    hnamd` Arial&Monotype Typography   "Good thing Lua was designed as a description language. Notice the ltn12 source doesn't load anything into memory. But how to send the message we have just declared?8)`m` " H , 0޽h ? 3380___PPT10.q,  4(  4X 4C    > 4S `  @  >  H 4 0޽h ? 3380___PPT10.q,  <(  <X <C    > <S $  @  >  H < 0޽h ? 3380___PPT10.qZU  De(  DX DC    > DS  @p  >X`___PPT10@8___PPT9xpJ___PPTMac11$ x   x   x     hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography   We start with a few historical notes on LuaSocket Then we move on to our case study which is the SMTP support shipping with the newest versions. We will focus on little details of Lua that enables us to taylor a very elegant interface to sending e-mail messages. I realize my abstract mentioned more stuff. For some reason I had in mind it would be a longer talk, so I had to downsize.N2_v r (\H D 0޽h ? 3380___PPT10.qZ zrpL ( @ LX LC    >r LS `O~ @  > H L 0޽h ? 3380___PPT10.qZ9 I(  R  3    >  C P,a  @H  >0P___PPT100(v___PPT9XPR___PPTMac11,$   hnamd` Arial&Monotype Typography   The solution LuaSocket adopts is given by LTN13. We use Lua's error reporting to implement an exception mechanism with two tiny helper function factories.>2_ ` "<_ H  0޽h ? 3380___PPT10.qI." >(  R  3    >  C a  @  > L&About 100 lines of nice, modular code. 'H  0޽h ? 3380___PPT10. qO! _(  R  3    >  C 8a  @  > mGAll SMTP code, with error checking fits in 100 lines of clean Lua code. HH  0޽h ? 3380___PPT10. qqO  (  R  3    >   C 0`  @h  >PP___PPT100(v___PPT9XPr___PPTMac11LD   hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography   QRoberto would actually send me a PDF; But PDF files are binary, and SMTP is text mode. Need to encode as BASE64 before sending. Want to do everything on the fly, with the same requirements: not allowed to load everything into memory.:&1)i  H  0޽h ? 3380___PPT10.qGr. >(  R  3    >  C `  @  > L&Introducing LTN12 filters and chains.  'H  0޽h ? 3380___PPT10.qGr C;( {5v R  3    >A  C 0`  @  >8___PPT10F___PPT9( V___PPTMac110(   hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography   Once again, nothing happens until this message is sent. And even then, things happen chunk by chunk. Filters are great to use, but how hard is it to write filters?e? H  0޽h ? 3380___PPT10.qGrv  ( {5 R  3    >  C a  @  >|X___PPT1080___PPT9h`___PPTMac11`X   hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography   Two of the involved modules have no depencencies. Socket and LTN12. Socket implements the core comunications capabilities. LTN12 implements that technical note functionality. The tp module implements the command/response structure common to SMTP and FTP (and not by HTTP) The MIME module implements the encodings commonly used by SMTP The SMTP implements the message abstraction, and message sending functionality.D2}a? O H  0޽h ? 3380___PPT10.qGrx  (  R  3    >  C %a  @h  >PP___PPT100(v___PPT9XPr___PPTMac11LD   hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography     hnamd` Arial&Monotype Typography   >This is the error convention has been adopted throughout LuaSocket and many other libraries. If a function succeeds, it returns whatever it is that it should return. If it fails, it returns nil, followed by an error message. I subscribe to this idea, but it can be challenging to implement code that conforms to it. The reason is that each function might perform many operations, and there can be several layers of functions. There would be a lot of code like the above.:]n,  H  0޽h ? 3380___PPT10.qGr # 0(  X C    > S Z @  >  H  0޽h ? 3380___PPT10. qqO$ A9P(  X C    >9 S 0 @  >@___PPT10 V___PPT980J___PPTMac11$   hnamd` Arial&Monotype Typography   LTN12 describes a series of tricks on how to implement these ideas. We see here the code for an end-of-line marker translator. &D: H  0޽h ? 3380___PPT10.qGr|% p(  X C    > S & @  > hWe talked about lots of different modules, so lat zoom out a little and take a look at the dependencies. iH  0޽h ? 3380___PPT10.qGrX& h(  X C    > S P @  > jDLTN12 describes a series of tricks on how to implement these ideas.  EH  0޽h ? 3380___PPT10.qGrcxp^RЀ3ÿ lHbP  @AL G@;b `B&V\Ap/O2)jI J?^Af!Vٰ(  F/ 0|DArial00w I@\P^\!DTimes00w I@\P^\! DCourier New I@\P^\!0DWingdingsw I@\P^\!@D-3 00000w I@\P^\! ` .  P @     !P Oh+'0T hp  'Slide 1 Steve Overbyb}) Diego Nehab75Microsoft PowerPoint@L@ @VMX&G<PICT4 HH HH  tL7 8GQVTI:(  >LTZXM>,  :DKPOG9(C1}h`cfimmfT(8ze`cgjonhV-8jXTX[^ba\M+O"smf__jxrs{i))xjd__jxqsxn0'ry^VSS^t}legktd/ULy_aecgp|{vW  St\`dcgnzys~` ReRTWU[amtlho~^ X_cfdgr}yptwszue{`ccgs{}vortqu~ajTYWYflmhbfhber{\Vuhffyvxtspkf{p^odcdv|uwspnicuy^aWilfjhea\Ubwa?~lkl|{vpjhhQGǺzggiwxsmife{]FİykZZ\iwv|{lha\XVi`gĺ|ru|yspqty umqw}upmmot)f]cjsnhd`^_c{-gsw||xw|~Ɏzp{yxtswxÙvvuycmxqztjjfeggpm&Önj|vy-,hevp||}~~sz8,XYgamolynnogknu=miqztol|zu~lu]pyldv{r~prx{s~{{  {xx ~wqrumjjus$||)*x}x2*zwzrs{x{qjni|y2sA|}}{|zIFvww}v|wtSEgfgmv~xhqvjfer~tSs^Ŭ|wtvioq~ddsqzp}rdkjwoaeajvwbndU\\fsostϽ|prr{_zƳ~xknmtivqouj[^]co}gspǵλǷwrqrLwıqmmn}Vvɺxa]]_l{SsdȽƾzvlje|3møȼysifaw<mڿmfYWRfp9sI˼¹p]]ei}!RļͿp_\cgx)TŲfTQWYg&s(ɿfbcb| /¾ȼgaca|0Žt]VWTmtrýųe]\_pZ ¿e][^nb ¼tYRPQ`wZmbžεyqgZUh0lǼƯvneZUe8lj`WNHV5mªta^a%¾s^[g &fRPn|] gfǹŰzpzzw)rĴvmuzv0ti_fpg}x-f rulX_IosnX^QorscepaLPsKa,h^[[MbY 5h]ZZK__ 3rZQLnxN?QV [-k]WWxpU5j]XUunZ4]QLJrwf`QU2skdctkmF:phbbrknL7zsqa[VTe_aER\}yph[1b{}vnh^5Zsymnyj`\R1I"Ouxz{nY3%Twxy{n\8"LjwylkodS2< 7Thqng`VG, ;XluqidZM2 6Pclg`ZRF-+       V835T SM835T SM835T SM^;6>^2ӱT h;6>^2ӱT h;X>m\T8o;6-FX'=!/xyQT;}N;6-FX'=!/xyQT;}N4;j)FX'iGb8xyQTQ;}l ;6-OhG(^efQR9Ts!.T͈@{ ;6-OhG(^efQR9Ts!.T͈@{ 5;l*i$nQJ~mx W^[lzAR\4,Ѝ8\T%;6Rok'H*>$ T xh;6Rok'H*>$ T xh6;m*{-:yLQ'`795ǺZK6(4eJ=!D3;[//&s]mEd( WG-W wDT%܍2v3;[//&s]mEd( WG-W wDT%܍2v5;Q5&;.ħۏY`T N-Xd;.ħۏY`T N-Xd;0 ǹA߮8vP ?5l)fPtVa<$      6FOGD;9H>FB;G>L;.MDJ= 3FA?$DAAI#$B 'KCA@K* D/     7:)=R??RY?,???n^\HJ\\Z\Z<?HV^_% B\_ B28THB\__.S^27AU^__ B\__KV^:         C7^O ՜.+,00    On-screen Show6F  ArialTimes Courier New WingdingsMS PゴシックCustom DesignLuaSocket behind the scenes Short BioOutline of talkHistorical notesHistorical notesCurrent versionOutline of talkSMTP (RFC2821)Protocol abstractionLTN12 sourcesUsing sourcesMessage Format (RFC2822)Message abstractionOur message APIHow hard is it?Zoom in on attachmentsLTN12 filters and chainsZoom in on attachmentsCreating filters: high-levelCreating filters: low-levelCreating filters: low-levelSMTP dependenciesError checkingLTN13 exceptionsNo 'if' statements Conclusions  #0 ___PPT9  P pRdO);6PicturesPowerPoint Document(SummaryInformation(      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnoprstuvwxyz{|}~quf  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdeghijklmnopqrstvwxyz{|}~DocumentSummaryInformation8`Current UserA  Fonts UsedDesign Template Slide Titles#_ǫ "DDiego NehabDiego Nehab                        "   `     ! #`h___PPT2001D<4X___PPTMac11’@f   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography D   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography `   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography  <   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography  t   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography `   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography   tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPtnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography D tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography T tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography "    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography $  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography  tnamdlCourier New&Monotype Typography @   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography !   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography #H   hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography    hnamd` Arial&Monotype Typography ( ʚ;&)ʚ;dd? %_3LuaSocket behind the scenes6 )    Diego Nehab  4 Short Bio Graduated from PUC in CS & E, 1999; Worked in Tecgraf 1995-2002; MSc in PL with Roberto, 2001; 3rd year PhD candidate at Princeton; Computer Graphics.DA%  5Outline of talk ~A few historical notes Case study: SMTP support Protocol abstraction Message abstraction Implementation highlights Conclusionsp0C     Historical notes 1.0, 1999, 1.5k C, 200 man 1.1, 2000, 1.5k C, 1.3k Lua, 500 man added protocol support for HTTP, SMTP, FTP 1.2, 2001, 2k C, 1.3k Lua, 900 man buffered input and non-blocking I/O UDP support object oriented syntaxN@+#G@+#G 23KQ Historical notes 1.3, 2001, 2.3k C, 1.6k Lua, 1.2k man streaming with callbacks added select function 1.4, 2001-2, 2.2k C, 2.2k Lua, 1.9k man LTN7 added URL module named parametersl&/('&/( o2 Current version 2.0, 2005, 4.6k C, 2.5k Lua, 4.7k man Extensible C architecture, split in modules LTN12 (sources, sinks and filters) MIME support (partial but honest) Multipart messages support LTN13 (finalized exceptions) Package proposal Improved non-blocking code, robust to signals...p&dd&,#"  6Outline of talk ~A few historical notes Case study: SMTP support Protocol abstraction Message abstraction Implementation highlights Conclusionsp0C     SMTP (RFC2821)D!!  ! [lua:roberto] telnet mail.tecgraf.puc-rio.br 25 220 tecgraf.puc-rio.br ESMTP Sendmail 8.9.3/8.9.3 helo lua 250 tecgraf.puc-rio.br Hello lua, pleased to meet you mail from: 250 ... Sender ok rcpt to: 250 ... Recipient ok data 354 Enter mail, end with "." on a line by itself Subject: World domination: instructions. Commence stage two. . 250 RAA10452 Message accepted for delivery quit 221 tecgraf.puc-rio.br closing connection"pnPZ02 6  $*$/  1$$@((+,,00)4488,   "    !Protocol abstraction status, error = smtp.send { from = "", rcpt = "", body = "Subject: World domination: instructions.\r\n\r\n" .. "Comence stage two." }dP'Cc C c C6ccc C $$                 U & LTN12 sources function ltn12.source.file(handle) return function() local chunk = handle:read(BLOCKSIZE) if not chunk then handle:close() end return chunk end end,#dFC ' Using sources status, message = smtp.send { from = "", rcpt = "", body = ltn12.source.file(io.open("/mail/body", "r")) }dP)Cc C c (CcC                 ( ,Message Format (RFC2822),! | From: Roberto Ierusalimschy To: Diego Nehab Subject: World domination: roadmap. Content-Type: multipart/mixed; boundary=part This message contains attachments --part Content-Type: text/plain Please see attached roadmap. --part Content-Type: text/html; name="roadmap.html" ... --part--0}PCC)C C CCCC  C  $C$!(C(,c,0C04C48C8SMTP dependencies  A Error checking DFunction return convention Return nil, followed by message on error;Bd*dA  EBLTN13 exceptions try = newtry(finalizer): factory; On success, try returns all arguments; On failure, throws the second argument; Calls finalizer before raising the exception. foo = protect(bar): factory; foo executes bar in a protected environment; Returns nil followed by any thrown error. "d}ddXdgc` `  `e`.`  a $`$(g(,c, 0`04e4 8`8- index.htmlnu[PK;1]b]%]%i0ftp.htmlnu[PK;1]I00Uintroduction.htmlnu[PK;1]ߝІreference.htmlnu[PK;1]l-- luasocket.pngnu[PK;1]*6*6 socket.htmlnu[PK;1]=]aڸ** # ltn12.htmlnu[PK;1]~@P7P7 4mime.htmlnu[PK;1]4;BBkudp.htmlnu[PK;1]sif,, http.htmlnu[PK;1]ef88 smtp.htmlnu[PK;1])READMEnu[PK;1]4SStcp.htmlnu[PK;1] Rj hurl.htmlnu[PK;1]޶j reference.cssnu[PK;1]-) D++installation.htmlnu[PK;1]TX slua05.pptnu[PKn1]99ALICENSEnu[PKF