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 "ngx_http_lua_contentby.h"
15 : #include "ngx_http_lua_util.h"
16 : #include "ngx_http_lua_exception.h"
17 : #include "ngx_http_lua_cache.h"
18 : #include "ngx_http_lua_probe.h"
19 :
20 :
21 : static void ngx_http_lua_content_phase_post_read(ngx_http_request_t *r);
22 :
23 :
24 : ngx_int_t
25 1 : ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r)
26 : {
27 : int co_ref;
28 : ngx_int_t rc;
29 : lua_State *co;
30 : ngx_event_t *rev;
31 : ngx_http_lua_ctx_t *ctx;
32 : ngx_http_cleanup_t *cln;
33 :
34 : ngx_http_lua_loc_conf_t *llcf;
35 :
36 : dd("content by chunk");
37 :
38 1 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
39 :
40 1 : if (ctx == NULL) {
41 0 : ctx = ngx_http_lua_create_ctx(r);
42 0 : if (ctx == NULL) {
43 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
44 : }
45 :
46 : } else {
47 : dd("reset ctx");
48 1 : ngx_http_lua_reset_ctx(r, L, ctx);
49 : }
50 :
51 1 : ctx->entered_content_phase = 1;
52 :
53 : /* {{{ new coroutine to handle request */
54 1 : co = ngx_http_lua_new_thread(r, L, &co_ref);
55 :
56 1 : if (co == NULL) {
57 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
58 : "lua: failed to create new coroutine to handle request");
59 :
60 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
61 : }
62 :
63 : /* move code closure to new coroutine */
64 1 : lua_xmove(L, co, 1);
65 :
66 : /* set closure's env table to new coroutine's globals table */
67 1 : ngx_http_lua_get_globals_table(co);
68 1 : lua_setfenv(co, -2);
69 :
70 : /* save nginx request in coroutine globals table */
71 1 : ngx_http_lua_set_req(co, r);
72 :
73 1 : ctx->cur_co_ctx = &ctx->entry_co_ctx;
74 1 : ctx->cur_co_ctx->co = co;
75 1 : ctx->cur_co_ctx->co_ref = co_ref;
76 : #ifdef NGX_LUA_USE_ASSERT
77 1 : ctx->cur_co_ctx->co_top = 1;
78 : #endif
79 :
80 : /* {{{ register request cleanup hooks */
81 1 : if (ctx->cleanup == NULL) {
82 1 : cln = ngx_http_cleanup_add(r, 0);
83 1 : if (cln == NULL) {
84 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
85 : }
86 :
87 1 : cln->handler = ngx_http_lua_request_cleanup_handler;
88 1 : cln->data = ctx;
89 1 : ctx->cleanup = &cln->handler;
90 : }
91 : /* }}} */
92 :
93 1 : ctx->context = NGX_HTTP_LUA_CONTEXT_CONTENT;
94 :
95 1 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
96 :
97 1 : if (llcf->check_client_abort) {
98 0 : r->read_event_handler = ngx_http_lua_rd_check_broken_connection;
99 :
100 : #if (NGX_HTTP_V2)
101 0 : if (!r->stream) {
102 : #endif
103 :
104 0 : rev = r->connection->read;
105 :
106 0 : if (!rev->active) {
107 0 : if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) {
108 0 : return NGX_ERROR;
109 : }
110 : }
111 :
112 : #if (NGX_HTTP_V2)
113 : }
114 : #endif
115 :
116 : } else {
117 1 : r->read_event_handler = ngx_http_block_reading;
118 : }
119 :
120 1 : rc = ngx_http_lua_run_thread(L, r, ctx, 0);
121 :
122 1 : if (rc == NGX_ERROR || rc >= NGX_OK) {
123 0 : return rc;
124 : }
125 :
126 1 : if (rc == NGX_AGAIN) {
127 1 : return ngx_http_lua_content_run_posted_threads(L, r, ctx, 0);
128 : }
129 :
130 0 : if (rc == NGX_DONE) {
131 0 : return ngx_http_lua_content_run_posted_threads(L, r, ctx, 1);
132 : }
133 :
134 0 : return NGX_OK;
135 : }
136 :
137 :
138 : void
139 1 : ngx_http_lua_content_wev_handler(ngx_http_request_t *r)
140 : {
141 : ngx_http_lua_ctx_t *ctx;
142 :
143 1 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
144 1 : if (ctx == NULL) {
145 0 : return;
146 : }
147 :
148 1 : (void) ctx->resume_handler(r);
149 : }
150 :
151 :
152 : ngx_int_t
153 1 : ngx_http_lua_content_handler(ngx_http_request_t *r)
154 : {
155 : ngx_http_lua_loc_conf_t *llcf;
156 : ngx_http_lua_ctx_t *ctx;
157 : ngx_int_t rc;
158 :
159 1 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
160 : "lua content handler, uri:\"%V\" c:%ud", &r->uri,
161 : r->main->count);
162 :
163 1 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
164 :
165 1 : if (llcf->content_handler == NULL) {
166 : dd("no content handler found");
167 0 : return NGX_DECLINED;
168 : }
169 :
170 1 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
171 :
172 : dd("ctx = %p", ctx);
173 :
174 1 : if (ctx == NULL) {
175 1 : ctx = ngx_http_lua_create_ctx(r);
176 1 : if (ctx == NULL) {
177 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
178 : }
179 : }
180 :
181 : dd("entered? %d", (int) ctx->entered_content_phase);
182 :
183 1 : if (ctx->waiting_more_body) {
184 0 : return NGX_DONE;
185 : }
186 :
187 1 : if (ctx->entered_content_phase) {
188 : dd("calling wev handler");
189 0 : rc = ctx->resume_handler(r);
190 : dd("wev handler returns %d", (int) rc);
191 0 : return rc;
192 : }
193 :
194 1 : if (llcf->force_read_body && !ctx->read_body_done) {
195 0 : r->request_body_in_single_buf = 1;
196 0 : r->request_body_in_persistent_file = 1;
197 0 : r->request_body_in_clean_file = 1;
198 :
199 0 : rc = ngx_http_read_client_request_body(r,
200 : ngx_http_lua_content_phase_post_read);
201 :
202 0 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
203 : #if (nginx_version < 1002006) || \
204 : (nginx_version >= 1003000 && nginx_version < 1003009)
205 : r->main->count--;
206 : #endif
207 0 : return rc;
208 : }
209 :
210 0 : if (rc == NGX_AGAIN) {
211 0 : ctx->waiting_more_body = 1;
212 :
213 0 : return NGX_DONE;
214 : }
215 : }
216 :
217 : dd("setting entered");
218 :
219 1 : ctx->entered_content_phase = 1;
220 :
221 : dd("calling content handler");
222 1 : return llcf->content_handler(r);
223 : }
224 :
225 :
226 : /* post read callback for the content phase */
227 : static void
228 0 : ngx_http_lua_content_phase_post_read(ngx_http_request_t *r)
229 : {
230 : ngx_http_lua_ctx_t *ctx;
231 :
232 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
233 :
234 0 : ctx->read_body_done = 1;
235 :
236 0 : if (ctx->waiting_more_body) {
237 0 : ctx->waiting_more_body = 0;
238 0 : ngx_http_lua_finalize_request(r, ngx_http_lua_content_handler(r));
239 :
240 : } else {
241 0 : r->main->count--;
242 : }
243 0 : }
244 :
245 :
246 : ngx_int_t
247 0 : ngx_http_lua_content_handler_file(ngx_http_request_t *r)
248 : {
249 : lua_State *L;
250 : ngx_int_t rc;
251 : u_char *script_path;
252 : ngx_http_lua_loc_conf_t *llcf;
253 : ngx_str_t eval_src;
254 :
255 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
256 :
257 0 : if (ngx_http_complex_value(r, &llcf->content_src, &eval_src) != NGX_OK) {
258 0 : return NGX_ERROR;
259 : }
260 :
261 0 : script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
262 : eval_src.len);
263 :
264 0 : if (script_path == NULL) {
265 0 : return NGX_ERROR;
266 : }
267 :
268 0 : L = ngx_http_lua_get_lua_vm(r, NULL);
269 :
270 : /* load Lua script file (w/ cache) sp = 1 */
271 0 : rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path,
272 0 : llcf->content_src_key);
273 0 : if (rc != NGX_OK) {
274 0 : if (rc < NGX_HTTP_SPECIAL_RESPONSE) {
275 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
276 : }
277 :
278 0 : return rc;
279 : }
280 :
281 : /* make sure we have a valid code chunk */
282 0 : ngx_http_lua_assert(lua_isfunction(L, -1));
283 :
284 0 : return ngx_http_lua_content_by_chunk(L, r);
285 : }
286 :
287 :
288 : ngx_int_t
289 1 : ngx_http_lua_content_handler_inline(ngx_http_request_t *r)
290 : {
291 : lua_State *L;
292 : ngx_int_t rc;
293 : ngx_http_lua_loc_conf_t *llcf;
294 :
295 1 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
296 :
297 1 : L = ngx_http_lua_get_lua_vm(r, NULL);
298 :
299 : /* load Lua inline script (w/ cache) sp = 1 */
300 2 : rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
301 1 : llcf->content_src.value.data,
302 : llcf->content_src.value.len,
303 1 : llcf->content_src_key,
304 : (const char *)
305 1 : llcf->content_chunkname);
306 1 : if (rc != NGX_OK) {
307 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
308 : }
309 :
310 1 : return ngx_http_lua_content_by_chunk(L, r);
311 : }
312 :
313 :
314 : ngx_int_t
315 1 : ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r,
316 : ngx_http_lua_ctx_t *ctx, int n)
317 : {
318 : ngx_int_t rc;
319 : ngx_http_lua_posted_thread_t *pt;
320 :
321 : dd("run posted threads: %p", ctx->posted_threads);
322 :
323 : for ( ;; ) {
324 1 : pt = ctx->posted_threads;
325 1 : if (pt == NULL) {
326 1 : goto done;
327 : }
328 :
329 0 : ctx->posted_threads = pt->next;
330 :
331 : ngx_http_lua_probe_run_posted_thread(r, pt->co_ctx->co,
332 : (int) pt->co_ctx->co_status);
333 :
334 : dd("posted thread status: %d", pt->co_ctx->co_status);
335 :
336 0 : if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) {
337 0 : continue;
338 : }
339 :
340 0 : ctx->cur_co_ctx = pt->co_ctx;
341 :
342 0 : rc = ngx_http_lua_run_thread(L, r, ctx, 0);
343 :
344 0 : if (rc == NGX_AGAIN) {
345 0 : continue;
346 : }
347 :
348 0 : if (rc == NGX_DONE) {
349 0 : n++;
350 0 : continue;
351 : }
352 :
353 0 : if (rc == NGX_OK) {
354 0 : while (n > 0) {
355 0 : ngx_http_lua_finalize_request(r, NGX_DONE);
356 0 : n--;
357 : }
358 :
359 0 : return NGX_OK;
360 : }
361 :
362 : /* rc == NGX_ERROR || rc > NGX_OK */
363 :
364 0 : return rc;
365 : }
366 :
367 1 : done:
368 :
369 1 : if (n == 1) {
370 0 : return NGX_DONE;
371 : }
372 :
373 1 : if (n == 0) {
374 1 : r->main->count++;
375 1 : return NGX_DONE;
376 : }
377 :
378 : /* n > 1 */
379 :
380 : do {
381 0 : ngx_http_lua_finalize_request(r, NGX_DONE);
382 0 : } while (--n > 1);
383 :
384 0 : return NGX_DONE;
385 : }
386 :
387 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|