Line data Source code
1 :
2 : /*
3 : * Copyright (C) Xiaozhe Wang (chaoslawful)
4 : * Copyright (C) Yichun Zhang (agentzh)
5 : */
6 :
7 :
8 : #ifndef DDEBUG
9 : #define DDEBUG 0
10 : #endif
11 : #include "ddebug.h"
12 :
13 :
14 : #include <nginx.h>
15 : #include "ngx_http_lua_accessby.h"
16 : #include "ngx_http_lua_util.h"
17 : #include "ngx_http_lua_exception.h"
18 : #include "ngx_http_lua_cache.h"
19 :
20 :
21 : static ngx_int_t ngx_http_lua_access_by_chunk(lua_State *L,
22 : ngx_http_request_t *r);
23 :
24 :
25 : ngx_int_t
26 0 : ngx_http_lua_access_handler(ngx_http_request_t *r)
27 : {
28 : ngx_int_t rc;
29 : ngx_http_lua_ctx_t *ctx;
30 : ngx_http_lua_loc_conf_t *llcf;
31 : ngx_http_lua_main_conf_t *lmcf;
32 : ngx_http_phase_handler_t tmp, *ph, *cur_ph, *last_ph;
33 : ngx_http_core_main_conf_t *cmcf;
34 :
35 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
36 : "lua access handler, uri:\"%V\" c:%ud", &r->uri,
37 : r->main->count);
38 :
39 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
40 :
41 0 : if (!lmcf->postponed_to_access_phase_end) {
42 :
43 0 : lmcf->postponed_to_access_phase_end = 1;
44 :
45 0 : cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
46 :
47 0 : ph = cmcf->phase_engine.handlers;
48 0 : cur_ph = &ph[r->phase_handler];
49 :
50 : /* we should skip the post_access phase handler here too */
51 0 : last_ph = &ph[cur_ph->next - 2];
52 :
53 : dd("ph cur: %d, ph next: %d", (int) r->phase_handler,
54 : (int) (cur_ph->next - 2));
55 :
56 : #if 0
57 : if (cur_ph == last_ph) {
58 : dd("XXX our handler is already the last access phase handler");
59 : }
60 : #endif
61 :
62 0 : if (cur_ph < last_ph) {
63 : dd("swaping the contents of cur_ph and last_ph...");
64 :
65 0 : tmp = *cur_ph;
66 :
67 0 : memmove(cur_ph, cur_ph + 1,
68 0 : (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t));
69 :
70 0 : *last_ph = tmp;
71 :
72 0 : r->phase_handler--; /* redo the current ph */
73 :
74 0 : return NGX_DECLINED;
75 : }
76 : }
77 :
78 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
79 :
80 0 : if (llcf->access_handler == NULL) {
81 : dd("no access handler found");
82 0 : return NGX_DECLINED;
83 : }
84 :
85 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
86 :
87 : dd("ctx = %p", ctx);
88 :
89 0 : if (ctx == NULL) {
90 0 : ctx = ngx_http_lua_create_ctx(r);
91 0 : if (ctx == NULL) {
92 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
93 : }
94 : }
95 :
96 : dd("entered? %d", (int) ctx->entered_access_phase);
97 :
98 0 : if (ctx->entered_access_phase) {
99 : dd("calling wev handler");
100 0 : rc = ctx->resume_handler(r);
101 : dd("wev handler returns %d", (int) rc);
102 :
103 0 : if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) {
104 0 : return rc;
105 : }
106 :
107 0 : if (rc == NGX_OK) {
108 0 : if (r->header_sent) {
109 : dd("header already sent");
110 :
111 : /* response header was already generated in access_by_lua*,
112 : * so it is no longer safe to proceed to later phases
113 : * which may generate responses again */
114 :
115 0 : if (!ctx->eof) {
116 : dd("eof not yet sent");
117 :
118 0 : rc = ngx_http_lua_send_chain_link(r, ctx, NULL
119 : /* indicate last_buf */);
120 0 : if (rc == NGX_ERROR || rc > NGX_OK) {
121 0 : return rc;
122 : }
123 : }
124 :
125 0 : return NGX_HTTP_OK;
126 : }
127 :
128 0 : return NGX_OK;
129 : }
130 :
131 0 : return NGX_DECLINED;
132 : }
133 :
134 0 : if (ctx->waiting_more_body) {
135 : dd("WAITING MORE BODY");
136 0 : return NGX_DONE;
137 : }
138 :
139 0 : if (llcf->force_read_body && !ctx->read_body_done) {
140 0 : r->request_body_in_single_buf = 1;
141 0 : r->request_body_in_persistent_file = 1;
142 0 : r->request_body_in_clean_file = 1;
143 :
144 0 : rc = ngx_http_read_client_request_body(r,
145 : ngx_http_lua_generic_phase_post_read);
146 :
147 0 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
148 : #if (nginx_version < 1002006) || \
149 : (nginx_version >= 1003000 && nginx_version < 1003009)
150 : r->main->count--;
151 : #endif
152 :
153 0 : return rc;
154 : }
155 :
156 0 : if (rc == NGX_AGAIN) {
157 0 : ctx->waiting_more_body = 1;
158 0 : return NGX_DONE;
159 : }
160 : }
161 :
162 : dd("calling access handler");
163 0 : return llcf->access_handler(r);
164 : }
165 :
166 :
167 : ngx_int_t
168 0 : ngx_http_lua_access_handler_inline(ngx_http_request_t *r)
169 : {
170 : ngx_int_t rc;
171 : lua_State *L;
172 : ngx_http_lua_loc_conf_t *llcf;
173 :
174 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
175 :
176 0 : L = ngx_http_lua_get_lua_vm(r, NULL);
177 :
178 : /* load Lua inline script (w/ cache) sp = 1 */
179 0 : rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
180 0 : llcf->access_src.value.data,
181 : llcf->access_src.value.len,
182 0 : llcf->access_src_key,
183 0 : (const char *) llcf->access_chunkname);
184 :
185 0 : if (rc != NGX_OK) {
186 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
187 : }
188 :
189 0 : return ngx_http_lua_access_by_chunk(L, r);
190 : }
191 :
192 :
193 : ngx_int_t
194 0 : ngx_http_lua_access_handler_file(ngx_http_request_t *r)
195 : {
196 : u_char *script_path;
197 : ngx_int_t rc;
198 : ngx_str_t eval_src;
199 : lua_State *L;
200 : ngx_http_lua_loc_conf_t *llcf;
201 :
202 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
203 :
204 : /* Eval nginx variables in code path string first */
205 0 : if (ngx_http_complex_value(r, &llcf->access_src, &eval_src) != NGX_OK) {
206 0 : return NGX_ERROR;
207 : }
208 :
209 0 : script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
210 : eval_src.len);
211 :
212 0 : if (script_path == NULL) {
213 0 : return NGX_ERROR;
214 : }
215 :
216 0 : L = ngx_http_lua_get_lua_vm(r, NULL);
217 :
218 : /* load Lua script file (w/ cache) sp = 1 */
219 0 : rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path,
220 0 : llcf->access_src_key);
221 0 : if (rc != NGX_OK) {
222 0 : if (rc < NGX_HTTP_SPECIAL_RESPONSE) {
223 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
224 : }
225 :
226 0 : return rc;
227 : }
228 :
229 : /* make sure we have a valid code chunk */
230 0 : ngx_http_lua_assert(lua_isfunction(L, -1));
231 :
232 0 : return ngx_http_lua_access_by_chunk(L, r);
233 : }
234 :
235 :
236 : static ngx_int_t
237 0 : ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r)
238 : {
239 : int co_ref;
240 : ngx_int_t rc;
241 : ngx_uint_t nreqs;
242 : lua_State *co;
243 : ngx_event_t *rev;
244 : ngx_connection_t *c;
245 : ngx_http_lua_ctx_t *ctx;
246 : ngx_http_cleanup_t *cln;
247 :
248 : ngx_http_lua_loc_conf_t *llcf;
249 :
250 : /* {{{ new coroutine to handle request */
251 0 : co = ngx_http_lua_new_thread(r, L, &co_ref);
252 :
253 0 : if (co == NULL) {
254 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
255 : "lua: failed to create new coroutine "
256 : "to handle request");
257 :
258 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
259 : }
260 :
261 : /* move code closure to new coroutine */
262 0 : lua_xmove(L, co, 1);
263 :
264 : /* set closure's env table to new coroutine's globals table */
265 0 : ngx_http_lua_get_globals_table(co);
266 0 : lua_setfenv(co, -2);
267 :
268 : /* save nginx request in coroutine globals table */
269 0 : ngx_http_lua_set_req(co, r);
270 :
271 : /* {{{ initialize request context */
272 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
273 :
274 : dd("ctx = %p", ctx);
275 :
276 0 : if (ctx == NULL) {
277 0 : return NGX_ERROR;
278 : }
279 :
280 0 : ngx_http_lua_reset_ctx(r, L, ctx);
281 :
282 0 : ctx->entered_access_phase = 1;
283 :
284 0 : ctx->cur_co_ctx = &ctx->entry_co_ctx;
285 0 : ctx->cur_co_ctx->co = co;
286 0 : ctx->cur_co_ctx->co_ref = co_ref;
287 : #ifdef NGX_LUA_USE_ASSERT
288 0 : ctx->cur_co_ctx->co_top = 1;
289 : #endif
290 :
291 : /* }}} */
292 :
293 : /* {{{ register request cleanup hooks */
294 0 : if (ctx->cleanup == NULL) {
295 0 : cln = ngx_http_cleanup_add(r, 0);
296 0 : if (cln == NULL) {
297 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
298 : }
299 :
300 0 : cln->handler = ngx_http_lua_request_cleanup_handler;
301 0 : cln->data = ctx;
302 0 : ctx->cleanup = &cln->handler;
303 : }
304 : /* }}} */
305 :
306 0 : ctx->context = NGX_HTTP_LUA_CONTEXT_ACCESS;
307 :
308 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
309 :
310 0 : if (llcf->check_client_abort) {
311 0 : r->read_event_handler = ngx_http_lua_rd_check_broken_connection;
312 :
313 : #if (NGX_HTTP_V2)
314 0 : if (!r->stream) {
315 : #endif
316 :
317 0 : rev = r->connection->read;
318 :
319 0 : if (!rev->active) {
320 0 : if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) {
321 0 : return NGX_ERROR;
322 : }
323 : }
324 :
325 : #if (NGX_HTTP_V2)
326 : }
327 : #endif
328 :
329 : } else {
330 0 : r->read_event_handler = ngx_http_block_reading;
331 : }
332 :
333 0 : c = r->connection;
334 0 : nreqs = c->requests;
335 :
336 0 : rc = ngx_http_lua_run_thread(L, r, ctx, 0);
337 :
338 : dd("returned %d", (int) rc);
339 :
340 0 : if (rc == NGX_ERROR || rc > NGX_OK) {
341 0 : return rc;
342 : }
343 :
344 0 : if (rc == NGX_AGAIN) {
345 0 : rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs);
346 :
347 0 : if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) {
348 0 : return rc;
349 : }
350 :
351 0 : if (rc != NGX_OK) {
352 0 : return NGX_DECLINED;
353 : }
354 :
355 0 : } else if (rc == NGX_DONE) {
356 0 : ngx_http_lua_finalize_request(r, NGX_DONE);
357 :
358 0 : rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs);
359 :
360 0 : if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) {
361 0 : return rc;
362 : }
363 :
364 0 : if (rc != NGX_OK) {
365 0 : return NGX_DECLINED;
366 : }
367 : }
368 :
369 : #if 1
370 0 : if (rc == NGX_OK) {
371 0 : if (r->header_sent) {
372 : dd("header already sent");
373 :
374 : /* response header was already generated in access_by_lua*,
375 : * so it is no longer safe to proceed to later phases
376 : * which may generate responses again */
377 :
378 0 : if (!ctx->eof) {
379 : dd("eof not yet sent");
380 :
381 0 : rc = ngx_http_lua_send_chain_link(r, ctx, NULL
382 : /* indicate last_buf */);
383 0 : if (rc == NGX_ERROR || rc > NGX_OK) {
384 0 : return rc;
385 : }
386 : }
387 :
388 0 : return NGX_HTTP_OK;
389 : }
390 :
391 0 : return NGX_OK;
392 : }
393 : #endif
394 :
395 0 : return NGX_DECLINED;
396 : }
397 :
398 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|