LuaSocket
Network support for the Lua language

home · download · introduction · reference


Streaming with Callbacks

HTTP, FTP, and SMTP transfers sometimes involve large amounts of information. Sometimes an application needs to generate outgoing data in real time, or needs to process incoming information as it is being received. To address these problems, LuaSocket allows HTTP and SMTP message bodies and FTP file contents to be received or sent through the callback mechanism outlined below.

Instead of returning the entire contents of an entity as strings to the Lua application, the library allows the user to provide a receive callback that will be called with successive chunks of data, as the data becomes available. Conversely, the send callbacks can be used when the application wants to incrementally provide LuaSocket with the data to be sent.

ret, err_or_f = receive_cb(chunk, err)

The callback provided by the user will be repeatedly called by the library whenever new data is available. Each time it is called, the callback receives successive chunks of downloaded data.

Chunk contains the current chunk of data. When the transmission is over, the function is called with an empty string (i.e. "") as the chunk. If an error occurs, the function receives nil as chunk and an error message in err.

The callback can abort transmission by returning nil as its first return value, and an optional error message as the second return value. If the application wants to continue receiving data, the function should return non-nil as it's first return value. In this case, the function can optionally return a new callback function, to replace itself, as the second return value.

Note: The callback module provides several standard receive callbacks, including the following:

function receive.concat(concat)
    concat = concat or socket.concat.create()
    local callback = function(chunk, err)
        -- if not finished, add chunk
        if chunk and chunk ~= "" then
            concat:addstring(chunk)
            return 1
        end
    end
    return callback, concat
end

This function creates a new receive callback that concatenates all received chunks into a the same concat object, which can later be queried for its contents.

chunk, err_or_r = send_cb()

The callback provided by the user will be repeatedly called whenever the library needs more data to be sent.

Each time the callback is called, it should return the next chunk of data. It can optionally return, as it's second return value, a new callback to replace itself. The callback can abort the process at any time by returning nil followed by an optional error message.

Note: Below is the implementation of the callback.send.file function. Given an open file handle, it returns a send callback that will send the contents of that file, chunk by chunk.

function send.file(file, io_err)
    -- if successful, return the callback that reads from the file
    if file then
        return function()
            -- send next block of data
            return (file:read(BLOCKSIZE)) or ""
        end
    -- else, return a callback that just aborts the transfer
    else return fail(io_err or "unable to open file") end
end

Predefined Callbacks

The module callback.lua provides several predefined callbacks to perform the most common input/output operations. Callbacks are provided that send and receive contents of files and strings. Furthermore, composition functions are provided to chain callbacks with filters, such as the filters defined in the mime.lua module.

send.file(file, io_err)

This function creates a send callback that will return the contents of a the file, until the file has been entirely sent. When done, the callback closes the file.

File is a file open for reading. If file is nil, io_err can contain an error message and the returned callback just aborts transmission with the error message.

Returns a send callback for the file.

Note: The function is designed so that it directly accepts the return values of the io.open function.

send.string(str)

This function creates a send callback that will send the contents of a string.

Str is the string to be sent.

Returns a send callback for the string, or nil if the string is nil.

Note: If any function in the LuaSocket API receives a nil send callback, it assumes there is nothing to be sent.

send.chain(send_cb, filter)

This function creates a send callback that will send all data that it gets from another callback, after passing the data through a filter.

Send_cb is the send callback to be chained to filter.

Returns a callback chained with the filter.

(write a note!)