Skip to content
Permalink
Browse files
Support for HTTP request parsing using libapreq2
I've been planning a binding to libapreq2 for a while now but a recent
thread on lua-l* motivated me to dive in. Using etc/apreq_standalone.c
the HTTP request parsing module can be used independently from the rest
of the Lua/APR binding so that other projects can use the request
parsing without dragging in all of Lua/APR.

Note that the UNIX and Windows makefiles enable the libapreq2 binding by
default but you can disable it with "make DISABLE_APREQ=1". If and when
the dependency on libapreq2 turns out not to cause any problems I'll
probably switch it on permanently. I had some trouble getting libapreq2
to build on Windows initially, I've added instructions to NOTES.md.

* http://lua-users.org/lists/lua-l/2011-02/msg01443.html
  • Loading branch information
xolox committed Feb 27, 2011
1 parent 6f73b9b commit d962a7d
Show file tree
Hide file tree
Showing 15 changed files with 985 additions and 99 deletions.
@@ -1,7 +1,7 @@
# This is the UNIX makefile for the Lua/APR binding.
#
# Author: Peter Odding <peter@peterodding.com>
# Last Change: February 20, 2011
# Last Change: February 27, 2011
# Homepage: http://peterodding.com/code/lua/apr/
# License: MIT
#
@@ -16,6 +16,7 @@ LUA_SHAREDIR = $(LUA_DIR)/share/lua/5.1
# Names of source / binary modules to install.
SOURCE_MODULE = src/apr.lua
BINARY_MODULE = core.so
APREQ_BINARY = apreq.so

# Names of source code files to compile & link (the individual lines enable
# automatic rebasing between git feature branches and the master branch).
@@ -52,9 +53,6 @@ SOURCES = src/base64.c \
src/xlate.c \
src/xml.c

# Names of compiled object files.
OBJECTS = $(patsubst %.c,%.o,$(SOURCES))

# If you're building Lua/APR with LuaRocks it should locate the external
# dependencies automatically, otherwise we fall back to `pkg-config'. On
# Debian/Ubuntu the Lua pkg-config file is called "lua5.1", on Arch Linux its
@@ -78,10 +76,23 @@ CFLAGS := $(CFLAGS) -fprofile-arcs -ftest-coverage
LFLAGS := $(LFLAGS) -fprofile-arcs
endif

# Experimental support for HTTP request parsing using libapreq2.
ifndef DISABLE_APREQ
SOURCES := $(SOURCES) src/http.c
CFLAGS := $(CFLAGS) $(shell apreq2-config --includes) -DLUA_APR_ENABLE_APREQ
LFLAGS := $(LFLAGS) $(shell apreq2-config --link-ld)
endif

# Names of compiled object files.
OBJECTS = $(patsubst %.c,%.o,$(SOURCES))

# The build rules.

$(BINARY_MODULE): $(OBJECTS) Makefile
$(CC) -shared -o $(BINARY_MODULE) $(OBJECTS) $(LFLAGS)
$(CC) -shared -o $@ $(OBJECTS) $(LFLAGS)

$(APREQ_BINARY): etc/apreq_standalone.c Makefile
$(CC) -Wall -shared -o $@ $(CFLAGS) -fPIC etc/apreq_standalone.c $(LFLAGS)

$(OBJECTS): %.o: %.c src/lua_apr.h Makefile
$(CC) -Wall -c $(CFLAGS) -fPIC $< -o $@
@@ -95,6 +106,7 @@ install: $(BINARY_MODULE)
cp test/*.lua $(LUA_SHAREDIR)/apr/test
mkdir -p $(LUA_LIBDIR)/apr
cp $(BINARY_MODULE) $(LUA_LIBDIR)/apr/$(BINARY_MODULE)
if [ -e $(APREQ_BINARY) ]; then cp $(APREQ_BINARY) $(LUA_LIBDIR)/$(APREQ_BINARY); fi

uninstall:
rm -f $(LUA_SHAREDIR)/apr.lua
@@ -149,6 +161,7 @@ package: docs

clean:
@rm -Rf $(BINARY_MODULE) $(OBJECTS) etc/coverage
@rm -f $(APREQ_BINARY) docs.md docs.html
@which lcov && lcov -z -d .
@rm -f src/*.gcov src/*.gcno

@@ -1,12 +1,13 @@
# This is the Windows makefile for the Lua/APR binding.
#
# Author: Peter Odding <peter@peterodding.com>
# Last Change: February 20, 2011
# Last Change: February 27, 2011
# Homepage: http://peterodding.com/code/lua/apr/
# License: MIT
#
# This makefile has been tested on Windows XP with NMAKE from the free
# Microsoft Visual C++ 2010 Express tool chain.
# Microsoft Visual C++ 2010 Express tool chain. You may want to change the
# following settings:

# The directories where "lua.h" and "lua51.lib" can be found (these defaults
# are based on the directory structure used by Lua for Windows v5.1.4-40).
@@ -27,17 +28,19 @@ APU_LIBDIR = C:\lua-apr\apr-util\release
# The directory where "libapriconv-1.lib" can be found.
API_LIBDIR = C:\lua-apr\apr-iconv\release

# Compiler and linker flags.
# The directories where "apreq.h" and "libapreq-2.lib" can be found.
APREQ_INCDIR = C:\lua-apr\libapreq2\include
APREQ_LIBDIR = C:\lua-apr\libapreq2\win32\libs

# You shouldn't need to change anything below here.

BINARY_MODULE = core.dll
APREQ_BINARY = apreq.dll

# Compiler and linker flags composed from the above settings.
CFLAGS = "/I$(LUA_INCDIR)" "/I$(APR_INCDIR)" "/I$(APU_INCDIR)" /D"_CRT_SECURE_NO_DEPRECATE"
LFLAGS = "/LIBPATH:$(LUA_LINKDIR)" lua51.lib "/LIBPATH:$(APR_LIBDIR)" libapr-1.lib "/LIBPATH:$(APU_LIBDIR)" libaprutil-1.lib

# Create debug builds by default but enable release builds
# using the command line "NMAKE /f Makefile.win RELEASE=1".
!IFNDEF RELEASE
CFLAGS = $(CFLAGS) /Zi /Fd"core.pdb" /DDEBUG
LFLAGS = $(LFLAGS) /debug
!ENDIF

# Names of compiled object files (the individual lines enable automatic
# rebasing between git feature branches and the master branch).
OBJECTS = src\base64.obj \
@@ -73,37 +76,58 @@ OBJECTS = src\base64.obj \
src\xlate.obj \
src\xml.obj

# Create debug builds by default but enable release builds
# using the command line "NMAKE /f Makefile.win RELEASE=1".
!IFNDEF RELEASE
CFLAGS = $(CFLAGS) /Zi /Fd"core.pdb" /DDEBUG
LFLAGS = $(LFLAGS) /debug
!ENDIF

# Experimental support for HTTP request parsing using libapreq2.
!IFNDEF DISABLE_APREQ
OBJECTS = $(OBJECTS) src\http.obj
CFLAGS = $(CFLAGS) "/I$(APREQ_INCDIR)" /DLUA_APR_ENABLE_APREQ
LFLAGS = $(LFLAGS) "/LIBPATH:$(APREQ_LIBDIR)" libapreq2.lib
!ENDIF

# Build rules.

core.dll: $(OBJECTS)
$(BINARY_MODULE): $(OBJECTS)
LINK /nologo /dll /out:$@ $(OBJECTS) $(LFLAGS)
IF EXIST $@.manifest MT -nologo -manifest $@.manifest -outputresource:$@;2

$(APREQ_BINARY): etc\apreq_standalone.c
CD etc && CL /W3 /nologo /MD /D"WIN32" /D"LUA_BUILD_AS_DLL" $(CFLAGS) /TC /c apreq_standalone.c
LINK /nologo /dll /out:$@ etc\apreq_standalone.obj $(LFLAGS)
IF EXIST $@.manifest MT -nologo -manifest $@.manifest -outputresource:$@;2

.c.obj:
CL /W3 /nologo /MD /D"WIN32" /D"LUA_BUILD_AS_DLL" $(CFLAGS) /TC /c $< /Fo$@

src\errno.c: etc\errors.lua
lua etc\errors.lua > src\errno.c.new && move src\errno.c.new src\errno.c

install: core.dll
install: $(BINARY_MODULE)
COPY src\apr.lua "$(LUA_SHAREDIR)"
IF NOT EXIST "$(LUA_SHAREDIR)\apr" MD "$(LUA_SHAREDIR)\apr"
IF NOT EXIST "$(LUA_SHAREDIR)\apr\test" MD "$(LUA_SHAREDIR)\apr\test"
COPY test\*.lua "$(LUA_SHAREDIR)\apr\test"
IF NOT EXIST "$(LUA_LIBDIR)\apr" MD "$(LUA_LIBDIR)\apr"
COPY core.dll "$(LUA_LIBDIR)\apr"
COPY $(BINARY_MODULE) "$(LUA_LIBDIR)\apr"
COPY "$(APR_LIBDIR)\libapr-1.dll" "$(LUA_DIR)"
COPY "$(APU_LIBDIR)\libaprutil-1.dll" "$(LUA_DIR)"
COPY "$(API_LIBDIR)\libapriconv-1.dll" "$(LUA_DIR)"
IF EXIST "$(APREQ_LIBDIR)\libapreq2.dll" COPY "$(APREQ_LIBDIR)\libapreq2.dll" "$(LUA_DIR)"

uninstall:
DEL "$(LUA_SHAREDIR)\apr.lua"
DEL "$(LUA_SHAREDIR)\apr"
DEL "$(LUA_LIBDIR)\apr\core.dll"
DEL "$(LUA_LIBDIR)\apr\$(BINARY_MODULE)"
RD "$(LUA_LIBDIR)\apr"
DEL "$(LUA_DIR)\libapr-1.dll"
DEL "$(LUA_DIR)\libaprutil-1.dll"
DEL "$(LUA_DIR)\libapriconv-1.dll"
IF EXIST "$(LUA_DIR)\libapreq2.dll" DEL "$(LUA_DIR)\libapreq2.dll"

test: install
LUA -l apr.test
@@ -112,7 +136,8 @@ debug:
NTSD -g LUA -l apr.test

clean:
DEL $(OBJECTS) core.dll core.lib core.exp core.pdb core.ilk 2>NUL
DEL $(OBJECTS) $(BINARY_MODULE) core.lib core.exp core.pdb core.ilk core.dll.manifest 2>NUL
DEL $(APREQ_BINARY) apreq.lib apreq.exp apreq.pdb apreq.ilk 2>NUL

.PHONY: install uninstall test debug clean

@@ -37,3 +37,13 @@ The SQLite 3 driver is included in the [Windows binaries](http://github.com/down
4. Build the driver in the Windows SDK command prompt using the command `nmake /f apr_dbd_sqlite3.mak`

5. To install the driver you can copy `sqlite3.dll` and `apr_dbd_sqlite3-1.dll` to Lua's installation directory

### Building `libapreq2` on Windows

I wasted a few hours getting `libapreq2` version 2.13 to build on Windows because of the following issues:

* The included makefile `libapreq2.mak` is full of syntax errors
* The makefile unconditionally includes the Apache module and consequently doesn't link without a full Apache build
* The build environment requires a specific flavor of Perl which I haven't gotten to work

Eventually I decided to just rewrite the damned makefile and be done with it, enabling me to finally test the HTTP request parsing module on Windows (all tests passed the first time). I've included the [customized makefile](https://github.com/xolox/lua-apr/blob/master/etc/libapreq2.mak) in the Lua/APR git repository.
@@ -15,6 +15,7 @@ The [Lua/APR binding](http://peterodding.com/code/lua/apr/) aims to bring most o
* [Network I/O handling](http://peterodding.com/code/lua/apr/docs/#network_i_o_handling)
* [Pipe I/O handling](http://peterodding.com/code/lua/apr/docs/#pipe_i_o_handling)
* [Command argument parsing](http://peterodding.com/code/lua/apr/docs/#command_argument_parsing)
* [HTTP request parsing](http://peterodding.com/code/lua/apr/docs/#http_request_parsing)
* [Process handling](http://peterodding.com/code/lua/apr/docs/#process_handling)
* [Shared memory](http://peterodding.com/code/lua/apr/docs/#shared_memory)
* [String routines](http://peterodding.com/code/lua/apr/docs/#string_routines)
@@ -0,0 +1,77 @@
/* Standalone libapreq2 binding based on the Lua/APR binding.
*
* Author: Peter Odding <peter@peterodding.com>
* Last Change: February 27, 2011
* Homepage: http://peterodding.com/code/lua/apr/
* License: MIT
*
* This file transforms the HTTP request parsing module for the Lua/APR binding
* into a standalone binding to libapreq2, making it a lighter dependency for
* other web projects.
*/

#include "../src/lua_apr.h"

/* Make memory_pool.c use separate memory pool for standalone APREQ module. */
#undef LUA_APR_POOL_MT
#define LUA_APR_POOL_MT "APREQ memory pool type"
#undef LUA_APR_POOL_KEY
#define LUA_APR_POOL_KEY "APREQ memory pool instance"
#define APREQ_STANDALONE

/* Dependencies copied from Lua/APR. */

int status_to_message(lua_State *L, apr_status_t status)
{
char message[LUA_APR_MSGSIZE];
apr_strerror(status, message, count(message));
lua_pushstring(L, message);
return 1;
}

int push_error_status(lua_State *L, apr_status_t status)
{
lua_pushnil(L);
status_to_message(L, status);
status_to_name(L, status);
return 3;
}

#include "../src/errno.c"
#include "../src/memory_pool.c"
#include "../src/http.c"

/* Module loader. */

/* Used to make sure that APR is only initialized once. */
static int apr_was_initialized = 0;

LUA_APR_EXPORT int luaopen_apreq(lua_State *L)
{
apr_status_t status;

/* The Lua/APR binding probably isn't loaded which makes the APREQ binding
* responsible for correctly initializing the Apache Portable Runtime. */
if (!apr_was_initialized) {
if ((status = apr_initialize()) != APR_SUCCESS)
raise_error_status(L, status);
if (atexit(apr_terminate) != 0)
raise_error_message(L, "APREQ: Failed to register apr_terminate()");
apr_was_initialized = 1;
}

/* Create the memory pool for APREQ functions and install a __gc metamethod
* to destroy the memory pool when the Lua state is closed. */
to_pool(L);

/* Create and return the module table. */
lua_newtable(L);
# define push_libfun(f) \
lua_pushcfunction(L, lua_apr_ ## f); \
lua_setfield(L, -2, #f)
push_libfun(parse_headers);
push_libfun(parse_multipart);
push_libfun(parse_cookie_header);
push_libfun(parse_query_string);
return 1;
}
@@ -3,7 +3,7 @@
Documentation generator for the Lua/APR binding.
Author: Peter Odding <peter@peterodding.com>
Last Change: February 23, 2011
Last Change: February 26, 2011
Homepage: http://peterodding.com/code/lua/apr/
License: MIT
@@ -29,6 +29,7 @@ local SOURCES = [[
io_net.c
io_pipe.c
getopt.c
http.c
proc.c
shm.c
str.c
@@ -379,6 +380,10 @@ local bsignore = {
['apr.dbd'] = true,
['apr.os_default_encoding'] = true,
['apr.os_locale_encoding'] = true,
['apr.parse_cookie_header'] = true,
['apr.parse_headers'] = true,
['apr.parse_multipart'] = true,
['apr.parse_query_string'] = true,
['apr.platform_get'] = true,
['apr.proc_fork'] = true,
['apr.strfsize'] = true,

0 comments on commit d962a7d

Please sign in to comment.