This file is indexed.

/usr/share/doc/lua-apr-doc/examples/async-webserver.lua is in lua-apr-doc 0.23.2.dfsg-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
--[[

  Example: Asynchronous webserver

  Author: Peter Odding <peter@peterodding.com>
  Last Change: November 6, 2011
  Homepage: http://peterodding.com/code/lua/apr/
  License: MIT

  We can do even better than the performance of the multi threaded webserver by
  using the [APR pollset module] [pollset_module]. The following webserver uses
  asynchronous network communication to process requests from multiple clients
  'in parallel' without using multiple threads or processes. Here is a
  benchmark of the asynchronous code listed below (again using [ApacheBench]
  [ab] with the `-c` argument):

      $ CONCURRENCY=4
      $ POLLSET_SIZE=10
      $ lua examples/async-webserver.lua $POLLSET_SIZE 8080 cheat &
      $ ab -qt5 -c$CONCURRENCY http://localhost:8080/ | grep 'Requests per second\|Transfer rate'
      Requests per second:    11312.64 [#/sec] (mean)
      Transfer rate:          6219.74 [Kbytes/sec] received

  The [single threaded webserver] [simple_server] handled 3670 requests per
  second, the [multi threaded webserver] [threaded_server] handled 9210
  requests per second and the asynchronous webserver below can handle 11310
  requests per second. Actually in the above benchmark I may have cheated a bit
  (depending on whether your goal is correct usage or performance). When I
  started writing this asynchronous server example I didn't bother to add
  writable sockets to the pollset, instead I handled the request and response
  once the client socket was reported as readable by the pollset. Later on I
  changed the code to handle writing using the pollset and I noticed that the
  performance dropped. This is probably because the example is so contrived.
  Anyway here's the performance without cheating:

      $ lua examples/async-webserver.lua $POLLSET_SIZE 8080 &
      $ ab -qt5 -c$CONCURRENCY http://localhost:8888/ | grep 'Requests per second\|Transfer rate'
      Requests per second:    9867.17 [#/sec] (mean)
      Transfer rate:          5425.03 [Kbytes/sec] received

  Now follows the implementation of the asynchronous webserver example:

  [pollset_module]: #pollset
  [ab]: http://en.wikipedia.org/wiki/ApacheBench
  [simple_server]: #example_single_threaded_webserver
  [threaded_server]: #example_multi_threaded_webserver

]]

local pollset_size = tonumber(arg[1]) or 10
local port_number = tonumber(arg[2]) or 8080
local cheat = arg[3] == 'cheat' -- cheat to make it faster?

local template = [[
<html>
  <head>
    <title>Hello from Lua/APR!</title>
    <style type="text/css">
      body { font-family: sans-serif; }
      dt { font-weight: bold; }
      dd { font-family: monospace; margin: -1.4em 0 0 14em; }
    </style>
  </head>
  <body>
    <h1>Hello from Lua/APR!</h1>
    <p>The headers provided by your web browser:</p>
    <dl>%s</dl>
  </body>
</html>
]]

-- Load the Lua/APR binding.
local apr = require 'apr'

-- Initialize the server socket.
local server = assert(apr.socket_create())
assert(server:bind('*', port_number))
assert(server:listen(pollset_size))

-- Create the pollset.
local pollset = assert(apr.pollset(pollset_size))
assert(pollset:add(server, 'input'))

-- Use a table indexed with socket objects to keep track of "sessions".
local sessions = setmetatable({}, {__mode='k'})

-- Enter the I/O loop.
print("Running webserver on http://localhost:" .. port_number .. " ..")
while true do
  local readable, writable = assert(pollset:poll(-1))
  -- Process requests.
  for _, socket in ipairs(readable) do
    if socket == server then
      local client = assert(server:accept())
      assert(pollset:add(client, 'input'))
    else
      local request = assert(socket:read(), "Failed to receive request from client!")
      local method, location, protocol = assert(request:match '^(%w+)%s+(%S+)%s+(%S+)')
      local headers = {}
      for line in socket:lines() do
        local name, value = line:match '^(%S+):%s+(.-)$'
        if not name then
          break
        end
        table.insert(headers, '<dt>' .. name .. ':</dt><dd>' .. value .. '</dd>')
      end
      table.sort(headers)
      local content = template:format(table.concat(headers))
      assert(socket:write(
        protocol, ' 200 OK\r\n',
        'Content-Type: text/html\r\n',
        'Content-Length: ', #content, '\r\n',
        'Connection: close\r\n',
        '\r\n'))
      if cheat then
        assert(socket:write(content))
        assert(pollset:remove(socket))
        assert(socket:close())
      else
        sessions[socket] = content
        assert(pollset:remove(socket))
        assert(pollset:add(socket, 'output'))
      end
    end
  end
  if not cheat then
    -- Process responses.
    for _, socket in ipairs(writable) do
      assert(socket:write(sessions[socket]))
      -- I don't like that when I switch the order of these
      -- calls, it breaks... Seems like a fairly big gotcha.
      assert(pollset:remove(socket))
      assert(socket:close())
    end
  end
end

-- vim: ts=2 sw=2 et