4
-- Sample server using libsoup library. Listens on 1080 port and serves
5
-- local files from current directory. Allows to be terminated by query
6
-- for /quit file (i.e. curl http://localhost:1080/quit)
9
local coroutine = require 'coroutine'
11
local lgi = require 'lgi'
12
local bytes = require 'bytes'
17
local app = Gio.Application { application_id = 'org.lgi.soupsvr' }
18
function app:on_activate()
21
local server = Soup.Server { port = 1080 }
23
-- Set up quit handler.
24
server:add_handler('/quit', function(server, msg, path, query, ctx)
26
msg.response_body:complete()
31
-- Set up file retriever handler.
32
server:add_handler('/', function(server, msg, path, query, ctx)
33
local stream = Gio.File.new_for_path(path:sub(2)):read()
35
-- The whole is send by function running in coroutine.
36
-- Coroutine yields when it waits either for data from the
37
-- disk or signal that chunk was successfully sent.
38
local next_chunk = coroutine.wrap(function()
39
local buffer = bytes.new(4096)
41
-- Read another chunk of data from the source to the
43
stream:read_async(buffer, #buffer, GLib.PRIORITY_DEFAULT, nil,
45
local size = stream.read_finish(coroutine.yield())
47
-- IO error reading disk, this simply shuts our toy
54
-- Send the chunk to the message body.
55
msg.response_body:append(tostring(buffer):sub(1, size))
56
server:unpause_message(msg)
58
-- Wait until soup signalizes that chunk was written.
60
if (size < #buffer) then break end
62
msg.response_body:complete()
65
-- Prepare sending using chunked method.
67
msg.response_headers:set_encoding('CHUNKED')
69
-- When headers are written, start writing body by initial
70
-- resuming of sending coroutine.
71
msg.on_wrote_headers = next_chunk
73
-- When the chunk is sent, resume coroutine so that it starts
74
-- reading and sending another chunk.
75
msg.on_wrote_chunk = next_chunk
77
-- File was not found, send proper code.
79
msg.response_body:complete()
83
-- Start the server running asynchronously.
87
app:run { arg[0], ... }