lua.c
changeset 22 822094314703
child 32 6dc2d52e4b13
equal deleted inserted replaced
21:3510b50c6694 22:822094314703
       
     1 /* vim: set noet nosta sw=4 ts=4 ft=c : */
       
     2 /*
       
     3 Copyright (c) 2011-2012, Mahlon E. Smith <mahlon@martini.nu>
       
     4 All rights reserved.
       
     5 Redistribution and use in source and binary forms, with or without
       
     6 modification, are permitted provided that the following conditions are met:
       
     7 
       
     8     * Redistributions of source code must retain the above copyright
       
     9       notice, this list of conditions and the following disclaimer.
       
    10 
       
    11     * Redistributions in binary form must reproduce the above copyright
       
    12       notice, this list of conditions and the following disclaimer in the
       
    13       documentation and/or other materials provided with the distribution.
       
    14 
       
    15     * Neither the name of Mahlon E. Smith nor the names of his
       
    16       contributors may be used to endorse or promote products derived
       
    17       from this software without specific prior written permission.
       
    18 
       
    19 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
       
    20 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    22 DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
       
    23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    29 */
       
    30 
       
    31 #include "volta.h"
       
    32 #include "lua.h"
       
    33 
       
    34 /*
       
    35  * Emit a lua error if a variable is declared without the use of 'local'.
       
    36  * Since we only start up one lua interpreter, we want to ensure the
       
    37  * global namespace isn't polluted by random scripts.
       
    38  *
       
    39  */
       
    40 int
       
    41 luaV_globalindex( lua_State *lua )
       
    42 {
       
    43 	return luaL_error( lua, "attempt to set global var '%s' (use local!)", lua_tostring(lua, -2) );
       
    44 }
       
    45 
       
    46 
       
    47 /*
       
    48  * Override the regular lua print() function with one that formats the string
       
    49  * in the same fashion as the rest of volta output -- and goes to stderr instead
       
    50  * of stdout, which would just confuse squid.
       
    51  *
       
    52  */
       
    53 int
       
    54 luaV_print( lua_State *lua )
       
    55 {
       
    56 	lua_Debug info;
       
    57 	int i = 0;
       
    58 
       
    59 	/* get the file and line number print() was called from. */
       
    60 	lua_getstack( lua, 1, &info );
       
    61 	lua_getinfo( lua, "Sl", &info );
       
    62 
       
    63 	/* output each argument */
       
    64 	for( i = 1; i <= lua_gettop( lua ); i++ )
       
    65 		debug( 2, info.short_src, info.currentline, "%s\n", lua_tostring(lua, i) );
       
    66 
       
    67 	return( 1 );
       
    68 }
       
    69 
       
    70 
       
    71 /*
       
    72  * Create the initial lua interpreter, and configure the default environment.
       
    73  *
       
    74  */
       
    75 lua_State *
       
    76 luaV_setup( void )
       
    77 {
       
    78 	lua_State *lua = luaL_newstate();
       
    79 	luaL_openlibs( lua ); /* include lua standard libraries */
       
    80 
       
    81 	/* Predeclare the request table. */
       
    82 	lua_pushstring( lua, "request" );
       
    83 	lua_createtable( lua, 0, 7 );
       
    84 	lua_settable( lua, LUA_GLOBALSINDEX );
       
    85 
       
    86 	/* Predeclare a table for shared data */
       
    87 	lua_pushstring( lua, "shared" );
       
    88 	lua_newtable( lua );
       
    89 	lua_settable( lua, LUA_GLOBALSINDEX );
       
    90 
       
    91 	/* replace the lua print() function with one that calls debug() instead */
       
    92 	lua_register( lua, "print", luaV_print );
       
    93 
       
    94 	/* Restrict additional globals. */
       
    95     lua_createtable( lua, 0, 1);
       
    96     lua_pushcfunction( lua, luaV_globalindex );
       
    97     lua_setfield( lua, -2, "__newindex");
       
    98     lua_pushboolean( lua, 0 );
       
    99     lua_setfield( lua, -2, "__metatable");
       
   100     lua_setmetatable( lua, LUA_GLOBALSINDEX );
       
   101 
       
   102 	lua_settop( lua, 0 );  /* wipe the stack */
       
   103 	return( lua );
       
   104 }
       
   105 
       
   106 
       
   107 /*
       
   108  * Convert the request struct into a lua table, and inject it into the interpreter.
       
   109  *
       
   110  */
       
   111 void
       
   112 luaV_setup_request( parsed *request )
       
   113 {
       
   114 	lua_getfield( v.lua, LUA_GLOBALSINDEX, "request" );
       
   115 	lua_pushstring( v.lua, request->scheme );
       
   116 	lua_setfield( v.lua, 1, "scheme" );
       
   117 	lua_pushstring( v.lua, request->host );
       
   118 	lua_setfield( v.lua, 1, "host" );
       
   119 	lua_pushstring( v.lua, request->path );
       
   120 	lua_setfield( v.lua, 1, "path" );
       
   121 	lua_pushstring( v.lua, request->port );
       
   122 	lua_setfield( v.lua, 1, "port" );
       
   123 	lua_pushstring( v.lua, request->method );
       
   124 	lua_setfield( v.lua, 1, "method" );
       
   125 	lua_pushstring( v.lua, request->client_ip );
       
   126 	lua_setfield( v.lua, 1, "client_ip" );
       
   127 	lua_pushstring( v.lua, request->tld );
       
   128 	lua_setfield( v.lua, 1, "domain" );
       
   129 
       
   130 	return;
       
   131 }
       
   132 
       
   133 
       
   134 /*
       
   135  * Given a request struct and a path to a lua script (or bytecode),
       
   136  * execute the script within the global lua interpreter, and return
       
   137  * a pointer to the string it generated (or NULL).
       
   138  *
       
   139  */
       
   140 char *
       
   141 luaV_run( parsed *request, char *path )
       
   142 {
       
   143 	int lua_err = 0;
       
   144 
       
   145 	/* provide access to the request struct */
       
   146 	luaV_setup_request( request );
       
   147 
       
   148 	/* suck in the lua chunk(s) */
       
   149 	debug( 4, LOC, "Loading Lua code from '%s'\n", path );
       
   150 	lua_err = luaL_loadfile( v.lua, path );
       
   151 	if ( lua_err ) {
       
   152 		debug( 2, LOC, "Unable to run lua rule: %s\n", lua_tostring(v.lua, -1) );
       
   153 		lua_settop( v.lua, 0 );
       
   154 		return( NULL );
       
   155 	}
       
   156 
       
   157 	/* execute the lua, expecting one value to be returned. */
       
   158 	lua_err = lua_pcall( v.lua, 0, 1, 0 );
       
   159 	if ( lua_err ) {
       
   160 		debug( 2, LOC, "Unable to run lua rule: %s\n", lua_tostring(v.lua, -1) );
       
   161 		lua_settop( v.lua, 0 );
       
   162 		return( NULL );
       
   163 	}
       
   164 
       
   165 	/* get the last element in the stack, which should be the script's return value. */
       
   166 	char *rewrite = (char *)lua_tostring( v.lua, -1 );
       
   167 
       
   168 	debug( 5, LOC, "Lua is currently consuming %dKB of memory\n", lua_gc(v.lua, LUA_GCCOUNT, 0) );
       
   169 	lua_settop( v.lua, 0 ); /* reset the stack. */
       
   170 
       
   171 	return( rewrite );
       
   172 }
       
   173