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