|
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 |