Commit 187fa00e authored by Paul Querna's avatar Paul Querna
Browse files

Initial import of mod_wombat to the modules directory.

parent 6ecf215e
Loading
Loading
Loading
Loading

modules/wombat/README

0 → 100644
+77 −0
Original line number Diff line number Diff line
-*- mode:org -*-
* Requirements:
** lua 5.1 ( http://www.lua.org/ )
** libapreq2 ( http://httpd.apache.org/apreq/download.cgi )
** Apache HTTPD 2.2 ( http://httpd.apache.org/ )

* Documentation
  See docs/README

* Building
  For now, see docs/building-from-subversion.txt

* To Consider
  Allow definition of lua_State instances associated with arbitrary
  pool using the pool's user_data constuct. There would, here, be two
  types, pooled and singleton. On the other hand, singleton would work
  fine for almost all cases -- the exception being a process or server
  pool, and then we could stay singleton anyway and lock around it.

  The current "server scope" behavior could, instead, fall into
  connection scope, for long-lived connections, really we want thread
  scope (which Brian Akins knows how to do). Is there a pool
  associated with a thread? Contention on the pool is a pain in a
  highly concurrent environment.

  Could use apr_thread_data_(get|set) if I can find a way to hook into
  thread destruction. Looks like apr threads let you use the standard
  APR_POOL_DECLARE_ACCESSOR(thread); defined method, just need to look
  up what form that takes. -- apr_thread_pool_get -- just attach to
  that pool.

  Given that, we can associate a hash of lua_State instances with
  arbitrary pools, such as the request pool, thread pool, server pool,
  etc. We then use the file as key into the hash. Users, able to
  specify the handler function, can then make use of the same file
  with different handlers to reuse states.

  

* Task List
** TODO Use r->file to determine file, doing rewriting in translate_name   
** TODO Change to controlling lifecycle by passing in a pool?
   Need to determine how to handle server scoped then!
** TODO Provide means to get useful output from lua errors in response body
   Probably have to put it on the vm spec for pre-handler errors, as
   it is pre-handler, will prolly be on the request_config somewhere,
   but sometimes cannot put there, so... fun
** TODO Filters
** TODO Mapping in the server_rec
** TODO Connection scoped vms
** TODO Figure out how reentrancy works regarding filter chain stuff. 
   Do we need new "threads"?
** TODO Flesh out apw_*getvm for each flavor we allow
** TODO Rework apw_sgetvm to use the create_vm stuff like apw_rgetvm
** TODO apw_rgetvm needs to handle connection scoped vms     
** TODO options in server scoped vms (ie, min and max vm counts)
    
* License
  Apache License, Version 2.0,
  
  http://www.apache.org/licenses/LICENSE-2.0 

  See NOTICE file for more information
        
* Problems and Patches:
  Please use dev@httpd.apache.org for discussing mod_wombat development
  To subscribe send email to dev-subscribe@httpd.apache.org  
  Note that this is for development discussion, not user support :-)
   
* Contributors Include
** Brian McCallister
** Paul Querna
** Garrett Rooney
** Martin Traverso
** Brian Akins
** Justin Erenkrantz
** Philip M. Gollucci
+71 −0
Original line number Diff line number Diff line
#include "apr.h"
#include "apr_tables.h"

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

/**
 * make a userdata out of a C pointer, and vice versa
 * instead of using lightuserdata
 */
#ifndef lua_boxpointer
#define lua_boxpointer(L,u) (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u))
#define lua_unboxpointer(L,i)	(*(void **)(lua_touserdata(L, i)))
#endif


apr_table_t* check_apr_table(lua_State* L, int index) {
    luaL_checkudata(L, index, "Apr.Table");
    apr_table_t* t = (apr_table_t*)lua_unboxpointer(L, index);
    return t;
}


void apw_push_apr_table(lua_State* L, const char *name, apr_table_t *t) {
    lua_boxpointer(L, t);    
    luaL_getmetatable(L, "Apr.Table");
    lua_setmetatable(L, -2);
    lua_setfield(L, -2, name);
}

static int lua_table_set(lua_State* L) {
    apr_table_t *t = check_apr_table(L, 1);
    const char* key = luaL_checkstring(L, 2);
    const char* val = luaL_checkstring(L, 3);

    apr_table_set(t, key, val);
    return 0;
}

static int lua_table_get(lua_State* L) {
    apr_table_t *t = check_apr_table(L, 1);
    const char* key = luaL_checkstring(L, 2);
    const char *val = apr_table_get(t, key);
    lua_pushstring(L, val);
    return 1;
}

static const luaL_reg lua_table_methods[] = {
    {"set", lua_table_set},
    {"get", lua_table_get},
    {0, 0}
};


int apr_lua_init(lua_State *L, apr_pool_t *p) {
    luaL_newmetatable(L, "Apr.Table");
    luaL_openlib(L, "apr_table", lua_table_methods, 0);
    lua_pushstring(L, "__index");
    lua_pushstring(L, "get");
    lua_gettable(L, 2);
    lua_settable(L, 1);

    lua_pushstring(L, "__newindex");
    lua_pushstring(L, "set");
    lua_gettable(L, 2);
    lua_settable(L, 1);
    
    return 0;
}
+8 −0
Original line number Diff line number Diff line
#ifndef _APR_LUA_H_
#define _APR_LUA_H_

int apr_lua_init(lua_State *L, apr_pool_t *p);
apr_table_t* check_apr_table(lua_State* L, int index);
void apw_push_apr_table(lua_State* L, const char *name, apr_table_t *t);

#endif
+197 −0
Original line number Diff line number Diff line
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include "config.h"
#include "vmprep.h"

static apw_dir_cfg* check_dir_config(lua_State* L, int index) {
    luaL_checkudata(L, index, "Apache2.DirConfig");
    apw_dir_cfg *cfg = (apw_dir_cfg*)lua_unboxpointer(L, index);
    return cfg;    
}

static cmd_parms* check_cmd_parms(lua_State* L, int index) {
    luaL_checkudata(L, index, "Apache2.CommandParameters");
    cmd_parms *cmd = (cmd_parms*)lua_unboxpointer(L, index);
    return cmd;    
}

static int apw_toscope(const char *name) {
    if (0 == apr_strnatcmp("once", name)) return APW_SCOPE_ONCE;
    if (0 == apr_strnatcmp("request", name)) return APW_SCOPE_REQUEST;
    if (0 == apr_strnatcmp("connection", name)) return APW_SCOPE_CONN;
    if (0 == apr_strnatcmp("conn", name)) return APW_SCOPE_CONN;
    if (0 == apr_strnatcmp("server", name)) return APW_SCOPE_SERVER;
    return APW_SCOPE_ONCE;
}

apr_status_t apw_lua_map_handler(apw_dir_cfg *cfg, 
                                 const char *file, 
                                 const char *function,
                                 const char *pattern,
                                 const char *scope) {
    apr_status_t rv;
    apw_mapped_handler_spec *handler = apr_palloc(cfg->pool, sizeof(apw_mapped_handler_spec));
    handler->uri_pattern = NULL;
    handler->function_name = NULL;
    
    ap_regex_t *uri_pattern = apr_palloc(cfg->pool, sizeof(ap_regex_t));
    if ((rv = ap_regcomp(uri_pattern, pattern, 0)) != APR_SUCCESS) {
        return rv;
    }
    handler->file_name = apr_pstrdup(cfg->pool, file);
    handler->uri_pattern = uri_pattern;
    handler->scope = apw_toscope(scope);
    
    handler->function_name = apr_pstrdup(cfg->pool, function);
    *(const apw_mapped_handler_spec**)apr_array_push(cfg->mapped_handlers) = handler;    
    return APR_SUCCESS;
}

/* Change to use apw_lua_map_handler */
static int cfg_lua_map_handler(lua_State *L) {
    apw_dir_cfg *cfg = check_dir_config(L, 1);
    apw_mapped_handler_spec *handler = apr_palloc(cfg->pool, sizeof(apw_mapped_handler_spec));
    handler->uri_pattern = NULL;
    handler->function_name = NULL;
    
    luaL_checktype(L, 2, LUA_TTABLE);
    lua_getfield(L, 2, "file");
    if (lua_isstring(L, -1)) {
        const char *file = lua_tostring(L, -1);
        handler->file_name = apr_pstrdup(cfg->pool, file);
    }
    lua_pop(L, 1);
    
    lua_getfield(L, 2, "pattern");
    if (lua_isstring(L, -1)) {
        const char *pattern = lua_tostring(L, -1);
        
        ap_regex_t *uri_pattern = apr_palloc(cfg->pool, sizeof(ap_regex_t));
        if (ap_regcomp(uri_pattern, pattern, 0) != OK) {
            return luaL_error(L, "Unable to compile regular expression, '%s'", pattern);
        }
        handler->uri_pattern = uri_pattern;
    }
    lua_pop(L, 1);
    
    lua_getfield(L, 2, "scope");
    if (lua_isstring(L, -1)) {
        const char *scope = lua_tostring(L, -1);
        handler->scope = apw_toscope(scope);
    }
    else {
        handler->scope = APW_SCOPE_ONCE;
    }
    lua_pop(L, 1);
    
    lua_getfield(L, 2, "func");
    if (lua_isstring(L, -1)) {
        const char *value = lua_tostring(L, -1);
        handler->function_name = apr_pstrdup(cfg->pool, value);
    }
    else {
        handler->function_name = "handle";
    }
    lua_pop(L, 1);
    
    
    *(const apw_mapped_handler_spec**)apr_array_push(cfg->mapped_handlers) = handler;    
    return 0;
}

static int cfg_directory(lua_State *L) {
    apw_dir_cfg *cfg = check_dir_config(L, 1);
    lua_pushstring(L, cfg->dir);
    return 1;
}

/*static int cfg_root(lua_State *L) {
    apw_dir_cfg *cfg = check_dir_config(L, 1);
    lua_pushstring(L, cfg->root_path);
    return 1;
}*/

static const struct luaL_Reg cfg_methods[] = {
    {"match_handler", cfg_lua_map_handler},
    {"directory", cfg_directory},
   /* {"root", cfg_root}, */
    {NULL, NULL}
};



static int cmd_foo(lua_State *L) {
    cmd_parms *cmd = check_cmd_parms(L, 1);
    ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server, "FOO!");
    return 0;
}

/* helper function for the logging functions below */
static int cmd_log_at(lua_State* L, int level) {
    cmd_parms *cmd = check_cmd_parms(L, 1);
    lua_Debug dbg;
    
    lua_getstack(L, 1, &dbg);
    lua_getinfo(L, "Sl", &dbg);

    const char* msg = luaL_checkstring(L, 2);
    ap_log_error(dbg.source, dbg.currentline, level, 0, cmd->server, msg);
    return 0;
}

/* r:debug(String) and friends which use apache logging */
static int cmd_emerg(lua_State* L)  { cmd_log_at(L, APLOG_EMERG); return 0; }
static int cmd_alert(lua_State* L)  { cmd_log_at(L, APLOG_ALERT); return 0; }
static int cmd_crit(lua_State* L)   { cmd_log_at(L, APLOG_CRIT); return 0; }
static int cmd_err(lua_State* L)    { cmd_log_at(L, APLOG_ERR); return 0; }
static int cmd_warn(lua_State* L)   { cmd_log_at(L, APLOG_WARNING); return 0; }
static int cmd_notice(lua_State* L) { cmd_log_at(L, APLOG_NOTICE); return 0; }
static int cmd_info(lua_State* L)   { cmd_log_at(L, APLOG_INFO); return 0; }
static int cmd_debug(lua_State* L)  { cmd_log_at(L, APLOG_DEBUG); return 0; }


static const struct luaL_Reg cmd_methods[] = {    
    {"foo", cmd_foo},
    
    {"debug",   cmd_debug},
    {"info",    cmd_info},
    {"notice",  cmd_notice},
    {"warn",    cmd_warn},
    {"err",     cmd_err},
    {"crit",    cmd_crit},
    {"alert",   cmd_alert},
    {"emerg",   cmd_emerg},

    {NULL, NULL}
};

void apw_load_config_lmodule(lua_State *L) {
    luaL_newmetatable(L, "Apache2.DirConfig"); /* [metatable] */
    lua_pushvalue(L, -1); 

    lua_setfield(L, -2, "__index"); 
    luaL_register(L, NULL, cfg_methods); /* [metatable] */
    
    
    luaL_newmetatable(L, "Apache2.CommandParameters");
    lua_pushvalue(L, -1); 

    lua_setfield(L, -2, "__index"); 
    luaL_register(L, NULL, cmd_methods); /* [metatable] */
    
}
+32 −0
Original line number Diff line number Diff line
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include "mod_wombat.h"

#ifndef APW_CONFIG_H
#define APW_CONFIG_H
                 
APR_DECLARE(void) apw_load_config_lmodule(lua_State *L);                                                                 

APR_DECLARE(apr_status_t) apw_lua_map_handler(apw_dir_cfg *cfg, 
                                              const char *file, 
                                              const char *function,
                                              const char *pattern,
                                              const char *scope);

#endif
Loading