1 /*
2   Licensed to the Apache Software Foundation (ASF) under one
3   or more contributor license agreements.  See the NOTICE file
4   distributed with this work for additional information
5   regarding copyright ownership.  The ASF licenses this file
6   to you under the Apache License, Version 2.0 (the
7   "License"); you may not use this file except in compliance
8   with the License.  You may obtain a copy of the License at
9 
10   http://www.apache.org/licenses/LICENSE-2.0
11 
12   Unless required by applicable law or agreed to in writing, software
13   distributed under the License is distributed on an "AS IS" BASIS,
14   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   See the License for the specific language governing permissions and
16   limitations under the License.
17 */
18 
19 #include "ts_lua_hook.h"
20 #include "ts_lua_transform.h"
21 #include "ts_lua_util.h"
22 
23 typedef enum {
24   TS_LUA_HOOK_DUMMY = 0,
25   TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE,
26   TS_LUA_HOOK_SEND_REQUEST_HDR,
27   TS_LUA_HOOK_READ_RESPONSE_HDR,
28   TS_LUA_HOOK_SEND_RESPONSE_HDR,
29   TS_LUA_HOOK_READ_REQUEST_HDR,
30   TS_LUA_HOOK_TXN_START,
31   TS_LUA_HOOK_PRE_REMAP,
32   TS_LUA_HOOK_POST_REMAP,
33   TS_LUA_HOOK_OS_DNS,
34   TS_LUA_HOOK_READ_CACHE_HDR,
35   TS_LUA_HOOK_TXN_CLOSE,
36   TS_LUA_REQUEST_TRANSFORM,
37   TS_LUA_RESPONSE_TRANSFORM,
38   TS_LUA_HOOK_LAST
39 } TSLuaHookID;
40 
41 char *ts_lua_hook_id_string[] = {"TS_LUA_HOOK_DUMMY",
42                                  "TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE",
43                                  "TS_LUA_HOOK_SEND_REQUEST_HDR",
44                                  "TS_LUA_HOOK_READ_RESPONSE_HDR",
45                                  "TS_LUA_HOOK_SEND_RESPONSE_HDR",
46                                  "TS_LUA_HOOK_READ_REQUEST_HDR",
47                                  "TS_LUA_HOOK_TXN_START",
48                                  "TS_LUA_HOOK_PRE_REMAP",
49                                  "TS_LUA_HOOK_POST_REMAP",
50                                  "TS_LUA_HOOK_OS_DNS",
51                                  "TS_LUA_HOOK_READ_CACHE_HDR",
52                                  "TS_LUA_HOOK_TXN_CLOSE",
53                                  "TS_LUA_REQUEST_TRANSFORM",
54                                  "TS_LUA_RESPONSE_TRANSFORM",
55                                  "TS_LUA_HOOK_LAST"};
56 
57 static int ts_lua_add_hook(lua_State *L);
58 static void ts_lua_inject_hook_variables(lua_State *L);
59 
60 void
ts_lua_inject_hook_api(lua_State * L)61 ts_lua_inject_hook_api(lua_State *L)
62 {
63   lua_pushcfunction(L, ts_lua_add_hook);
64   lua_setfield(L, -2, "hook");
65 
66   ts_lua_inject_hook_variables(L);
67 }
68 
69 static void
ts_lua_inject_hook_variables(lua_State * L)70 ts_lua_inject_hook_variables(lua_State *L)
71 {
72   size_t i;
73 
74   for (i = 0; i < sizeof(ts_lua_hook_id_string) / sizeof(char *); i++) {
75     lua_pushinteger(L, (lua_Integer)i);
76     lua_setglobal(L, ts_lua_hook_id_string[i]);
77   }
78 }
79 
80 static int
ts_lua_add_hook(lua_State * L)81 ts_lua_add_hook(lua_State *L)
82 {
83   int type;
84   int entry;
85 
86   TSVConn connp;
87   ts_lua_http_ctx *http_ctx;
88 
89   http_ctx = ts_lua_get_http_ctx(L);
90 
91   entry = lua_tointeger(L, 1); // get hook id
92 
93   type = lua_type(L, 2);
94   if (type != LUA_TFUNCTION)
95     return 0;
96 
97   switch (entry) {
98   case TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE:
99     if (http_ctx) {
100       TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, http_ctx->cinfo.contp);
101       http_ctx->has_hook = 1;
102       lua_pushvalue(L, 2);
103       lua_setglobal(L, TS_LUA_FUNCTION_CACHE_LOOKUP_COMPLETE);
104     } else {
105       lua_pushvalue(L, 2);
106       lua_setglobal(L, TS_LUA_FUNCTION_G_CACHE_LOOKUP_COMPLETE);
107     }
108     break;
109 
110   case TS_LUA_HOOK_SEND_REQUEST_HDR:
111     if (http_ctx) {
112       TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_SEND_REQUEST_HDR_HOOK, http_ctx->cinfo.contp);
113       http_ctx->has_hook = 1;
114       lua_pushvalue(L, 2);
115       lua_setglobal(L, TS_LUA_FUNCTION_SEND_REQUEST);
116     } else {
117       lua_pushvalue(L, 2);
118       lua_setglobal(L, TS_LUA_FUNCTION_G_SEND_REQUEST);
119     }
120     break;
121 
122   case TS_LUA_HOOK_READ_RESPONSE_HDR:
123     if (http_ctx) {
124       TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, http_ctx->cinfo.contp);
125       http_ctx->has_hook = 1;
126       lua_pushvalue(L, 2);
127       lua_setglobal(L, TS_LUA_FUNCTION_READ_RESPONSE);
128     } else {
129       lua_pushvalue(L, 2);
130       lua_setglobal(L, TS_LUA_FUNCTION_G_READ_RESPONSE);
131     }
132     break;
133 
134   case TS_LUA_HOOK_SEND_RESPONSE_HDR:
135     if (http_ctx) {
136       TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, http_ctx->cinfo.contp);
137       http_ctx->has_hook = 1;
138       lua_pushvalue(L, 2);
139       lua_setglobal(L, TS_LUA_FUNCTION_SEND_RESPONSE);
140     } else {
141       lua_pushvalue(L, 2);
142       lua_setglobal(L, TS_LUA_FUNCTION_G_SEND_RESPONSE);
143     }
144     break;
145 
146   case TS_LUA_HOOK_READ_REQUEST_HDR:
147     if (http_ctx) {
148       TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_READ_REQUEST_HDR_HOOK, http_ctx->cinfo.contp);
149       http_ctx->has_hook = 1;
150       lua_pushvalue(L, 2);
151       lua_setglobal(L, TS_LUA_FUNCTION_READ_REQUEST);
152     } else {
153       lua_pushvalue(L, 2);
154       lua_setglobal(L, TS_LUA_FUNCTION_G_READ_REQUEST);
155     }
156     break;
157 
158   case TS_LUA_HOOK_TXN_START:
159     if (http_ctx) {
160       TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_TXN_START_HOOK, http_ctx->cinfo.contp);
161       http_ctx->has_hook = 1;
162       lua_pushvalue(L, 2);
163       lua_setglobal(L, TS_LUA_FUNCTION_TXN_START);
164     } else {
165       lua_pushvalue(L, 2);
166       lua_setglobal(L, TS_LUA_FUNCTION_G_TXN_START);
167     }
168     break;
169 
170   case TS_LUA_HOOK_PRE_REMAP:
171     if (http_ctx) {
172       TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_PRE_REMAP_HOOK, http_ctx->cinfo.contp);
173       http_ctx->has_hook = 1;
174       lua_pushvalue(L, 2);
175       lua_setglobal(L, TS_LUA_FUNCTION_PRE_REMAP);
176     } else {
177       lua_pushvalue(L, 2);
178       lua_setglobal(L, TS_LUA_FUNCTION_G_PRE_REMAP);
179     }
180     break;
181 
182   case TS_LUA_HOOK_POST_REMAP:
183     if (http_ctx) {
184       TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_POST_REMAP_HOOK, http_ctx->cinfo.contp);
185       http_ctx->has_hook = 1;
186       lua_pushvalue(L, 2);
187       lua_setglobal(L, TS_LUA_FUNCTION_POST_REMAP);
188     } else {
189       lua_pushvalue(L, 2);
190       lua_setglobal(L, TS_LUA_FUNCTION_G_POST_REMAP);
191     }
192     break;
193 
194   case TS_LUA_HOOK_OS_DNS:
195     if (http_ctx) {
196       TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_OS_DNS_HOOK, http_ctx->cinfo.contp);
197       http_ctx->has_hook = 1;
198       lua_pushvalue(L, 2);
199       lua_setglobal(L, TS_LUA_FUNCTION_OS_DNS);
200     } else {
201       lua_pushvalue(L, 2);
202       lua_setglobal(L, TS_LUA_FUNCTION_G_OS_DNS);
203     }
204     break;
205 
206   case TS_LUA_HOOK_READ_CACHE_HDR:
207     if (http_ctx) {
208       TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_READ_CACHE_HDR_HOOK, http_ctx->cinfo.contp);
209       http_ctx->has_hook = 1;
210       lua_pushvalue(L, 2);
211       lua_setglobal(L, TS_LUA_FUNCTION_READ_CACHE);
212     } else {
213       lua_pushvalue(L, 2);
214       lua_setglobal(L, TS_LUA_FUNCTION_G_READ_CACHE);
215     }
216     break;
217 
218   case TS_LUA_HOOK_TXN_CLOSE:
219     if (http_ctx) {
220       // we don't need to add a hook because we already have added one by default
221       lua_pushvalue(L, 2);
222       lua_setglobal(L, TS_LUA_FUNCTION_TXN_CLOSE);
223     } else {
224       lua_pushvalue(L, 2);
225       lua_setglobal(L, TS_LUA_FUNCTION_G_TXN_CLOSE);
226     }
227     break;
228 
229   case TS_LUA_REQUEST_TRANSFORM:
230   case TS_LUA_RESPONSE_TRANSFORM:
231     if (http_ctx) {
232       connp = TSTransformCreate(ts_lua_transform_entry, http_ctx->txnp);
233       ts_lua_create_http_transform_ctx(http_ctx, connp);
234 
235       if (entry == TS_LUA_REQUEST_TRANSFORM) {
236         TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_REQUEST_TRANSFORM_HOOK, connp);
237       } else {
238         TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
239       }
240     }
241     break;
242 
243   default:
244     break;
245   }
246 
247   return 0;
248 }
249