Eric Covener, IBM covener@apache.org, November 2011
Eric Covener
Apache HTTP Server and WebSphere
Application Server Development at IBM.
Contributor to Apache HTTP Server, Apache
Portable Runtime, and Apache OpenWebBeans.
Frequent supporter on freenode #httpd and the HTTPD users mailing list
Introduction to Lua
Introduction to mod_lua
mod_lua recipes for familiar problems
The future
Wrap-up
“Lua is a powerful, fast, lightweight, embeddable scripting language”
• Basic syntax familiar to occasional users of C or interpreted languages such as JavaScript, PHP, PERL,
…
#!/usr/bin/lua io.write("What's your name? ") local name = io.read("*line") print("Hello, ", name)
Lua is used as the scripting engine many popular large applications
World of Warcraft, VLC, Wireshark, RPM
Extensions allow Lua scripts to exploit popular libraries such as memcached, mysql, GD, curl, expat, sockets.
The programs embedding Lua are expected to provide useful routines .
Basic Features:
Simple syntax, C-like control structures, I/O, basic regex
Advanced Features:
Co-routines, closures, OOP
mod_lua allows users to write Lua scripts to extend and modify the webserver
Handling the response in a Lua script
Changing request processing metadata (think
SetEnvIf, RequestHeader, Header, and
RewriteRule)
Implementation of Authentication,
Authorization, Access Control
Much like a compiled Apache HTTP Server module, or scripts written in mod_perl.
Part of Apache HTTP Server 2.3.x (and later)
Must be enabled during build (explicitly, or via – enable-mods-shared=[really]all)
Lua interpreter (and –dev counterpart) must be available at build time
Packaged with most Linux distributions
Source tarball is 200k and has no dependencies
(doesn’t even use autoconf)
The simplest way a traditional module (or a mod_lua script) can participate in a request is by acting as the “handler”, or generator, for the response.
1 function handle(r)
2 r.content_type = "text/html"
3 local query = r:parseargs()
4 if query.name == nil then
5 r:puts("What's your name? “,
6 “<form><input type=\"text\" name=\"name\"/>")
7 else
8 r:puts("Hello, ", r:escape_html(query.name));
9 end
10 end
A few different ways to teach mod_lua about our script
AddHandler lua-script .lua
LuaMapHandler
LuaMapHandler /hello
/path/to/luascripts/hello.lua
LuaQuickHandler
<LuaQuickHandler>
No external script file required, lives in httpd.conf
Crude performance test of a short “Hello, world” page.
Source static mod_php mod_lua
CGI
Requests/second
4300
2900
2400
600
Traditional Apache modules can do more than just generate the response
The participate in designated “hooks” with other modules
Mapping a URI to the filesystem
Performing authentication
Setting mime-types
mod_lua allows Lua scripts to participate the same way
quick_handler
translate_name
URI -> filename
access_checker user-independent access control
check_userid
authentication
auth_checker
authorization
fixups
<LuaHookTranslateName redirect_ssl>
1 require "apache2"
2 function redirect_ssl(r)
3 local https = r:ssl_var_lookup("HTTPS")
4 if (https == nil or https == "" or https == "off") then
5 r.err_headers_out['Location'] = string.gsub(r:construct_url(r.uri),
"http://", "https://")
6 return apache2.HTTP_MOVED_TEMPORARILY
7 end
8 return apache2.DECLINED
9 end
<LuaQuickHandler maint>
1 require "apache2“
2 require “posix"
3
4 function maint(r)
5 if posix.stat(“/tmp/maintenance”) ~= nil then
6 r:puts(“site temporarily unavailable")
7 r.status = 503;
8 return apache2.OK
9 else
10 return apache2.DECLINED
11 end
12 end
</LuaQuickHandler>
<LuaHookTranslateName rewrite_query>
1 function rewrite_query(r)
2 local query = r:parseargs()
3 if query.foo ~= nil and
4 query.bar ~= nil then
5 r.uri = r.uri ..
6 "/" .. query.foo ..
7 "/" .. query.bar
8 end
9 return apache2.DECLINED
10 end
mod_lua in place of mod_rewrite
Pros
Proper programming language with control structures, subroutines
Less baggage
Custom logging
Easier to unit test
Easier/less fragile to extend
Cons
Only basic regular expression by default
Less source material on the web
No htaccess for most recipes
Serving pre-compressed files
LuaHookMapToStorage ...
1 require "apache2"
2 require "posix"
3 function gz(r)
4 local acceptEncoding =
5 r.headers_in['Accept-Encoding']
6 if (r.filename and acceptEncoding and
7 string.find(acceptEncoding, "gzip")) then
8 if posix.stat(r.filename .. ".gz") then
9 r.filename = r.filename .. ".gz"
10 r.headers_out['Vary'] = "Accept-Encoding"
11 end
12 end
13 return apache2.DECLINED
14 end
LuaHookAuthChecker /path/to/authz.lua authz
…
1 require "apache2"
2 require "posix"
3
4 function authz(r)
5 if r.user == "bob" then
6 local hour = tonumber(os.date("%H"))
7 if hour > 8 and hour < 17 then
8 return 403
9 end
10 end
11 return apache2.DECLINED
12 end
LuaHookAuthCheckUserID /path/to/auth.lua \ authn early
1 function authn(r)
2 local user =
3 r:ssl_var_lookup("SSL_CLIENT_S_DN_CN")
4 if user == nil or user == "" then
5 return apache2.DECLINED
6 end
7 r.user = user
8 return apache2.OK
9 end
HTTP Request/Response filters
More Apache API access
Configuration in mod_lua
More mod_lua examples
Join in and help decide!
Flexible alternative to mod_setenvif/mod_rewrite/mod_headers recipes.
Lowers barriers to quickly interact with HTTP Server
API in what would be short modules
Lightweight scripting language for handlers
Input needed from users, tell us what you want to write in Lua!
mod_lua manual
– http://httpd.apache.org/docs/2.3/mod/ mod_lua.html
The Apache Modules Book
– http://www.apachetutor.org/
Programming in Lua
– http://www.lua.org/pil/
Eric Covener
• covener@apache.org