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_capturefilter.h"
16 #include "ngx_http_lua_util.h"
17 #include "ngx_http_lua_exception.h"
18 #include "ngx_http_lua_subrequest.h"
19 
20 
21 ngx_http_output_header_filter_pt ngx_http_lua_next_header_filter;
22 ngx_http_output_body_filter_pt ngx_http_lua_next_body_filter;
23 
24 
25 static ngx_int_t ngx_http_lua_capture_header_filter(ngx_http_request_t *r);
26 static ngx_int_t ngx_http_lua_capture_body_filter(ngx_http_request_t *r,
27     ngx_chain_t *in);
28 
29 
30 ngx_int_t
ngx_http_lua_capture_filter_init(ngx_conf_t * cf)31 ngx_http_lua_capture_filter_init(ngx_conf_t *cf)
32 {
33     /* setting up output filters to intercept subrequest responses */
34     ngx_http_lua_next_header_filter = ngx_http_top_header_filter;
35     ngx_http_top_header_filter = ngx_http_lua_capture_header_filter;
36 
37     ngx_http_lua_next_body_filter = ngx_http_top_body_filter;
38     ngx_http_top_body_filter = ngx_http_lua_capture_body_filter;
39 
40     return NGX_OK;
41 }
42 
43 
44 static ngx_int_t
ngx_http_lua_capture_header_filter(ngx_http_request_t * r)45 ngx_http_lua_capture_header_filter(ngx_http_request_t *r)
46 {
47     ngx_http_post_subrequest_t      *psr;
48     ngx_http_lua_ctx_t              *old_ctx;
49     ngx_http_lua_ctx_t              *ctx;
50 
51     ngx_http_lua_post_subrequest_data_t      *psr_data;
52 
53     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
54                    "lua capture header filter, uri \"%V\"", &r->uri);
55 
56     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
57 
58     dd("old ctx: %p", ctx);
59 
60     if (ctx == NULL || ! ctx->capture) {
61 
62         psr = r->post_subrequest;
63 
64         if (psr != NULL
65             && psr->handler == ngx_http_lua_post_subrequest
66             && psr->data != NULL)
67         {
68             /* the lua ctx has been cleared by ngx_http_internal_redirect,
69              * resume it from the post_subrequest data
70              */
71             psr_data = psr->data;
72 
73             old_ctx = psr_data->ctx;
74 
75             if (ctx == NULL) {
76                 ctx = old_ctx;
77                 ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
78 
79             } else {
80                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
81                                "lua restoring ctx with capture %d, index %d",
82                                old_ctx->capture, old_ctx->index);
83 
84                 ctx->capture = old_ctx->capture;
85                 ctx->index = old_ctx->index;
86                 ctx->body = NULL;
87                 ctx->last_body = &ctx->body;
88                 psr_data->ctx = ctx;
89             }
90         }
91     }
92 
93     if (ctx && ctx->capture) {
94         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
95                        "lua capturing response body");
96 
97         /* force subrequest response body buffer in memory */
98         r->filter_need_in_memory = 1;
99         r->header_sent = 1;
100         ctx->header_sent = 1;
101 
102         if (r->method == NGX_HTTP_HEAD) {
103             r->header_only = 1;
104         }
105 
106         return NGX_OK;
107     }
108 
109     return ngx_http_lua_next_header_filter(r);
110 }
111 
112 
113 static ngx_int_t
ngx_http_lua_capture_body_filter(ngx_http_request_t * r,ngx_chain_t * in)114 ngx_http_lua_capture_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
115 {
116     int                              rc;
117     ngx_int_t                        eof;
118     ngx_http_lua_ctx_t              *ctx;
119     ngx_http_lua_ctx_t              *pr_ctx;
120 
121     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
122                    "lua capture body filter, uri \"%V\"", &r->uri);
123 
124     if (in == NULL) {
125         return ngx_http_lua_next_body_filter(r, NULL);
126     }
127 
128     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
129 
130     if (!ctx || !ctx->capture) {
131         dd("no ctx or no capture %.*s", (int) r->uri.len, r->uri.data);
132 
133         return ngx_http_lua_next_body_filter(r, in);
134     }
135 
136     if (ctx->run_post_subrequest) {
137         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
138                        "lua body filter skipped because post subrequest "
139                        "already run");
140         return NGX_OK;
141     }
142 
143     if (r->parent == NULL) {
144         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
145                        "lua body filter skipped because no parent request "
146                        "found");
147 
148         return NGX_ERROR;
149     }
150 
151     pr_ctx = ngx_http_get_module_ctx(r->parent, ngx_http_lua_module);
152     if (pr_ctx == NULL) {
153         return NGX_ERROR;
154     }
155 
156     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
157                    "lua capture body filter capturing response body, uri "
158                    "\"%V\"", &r->uri);
159 
160     rc = ngx_http_lua_add_copy_chain(r, pr_ctx, &ctx->last_body, in, &eof);
161     if (rc != NGX_OK) {
162         return NGX_ERROR;
163     }
164 
165     dd("add copy chain eof: %d, sr: %d", (int) eof, r != r->main);
166 
167     if (eof) {
168         ctx->seen_last_for_subreq = 1;
169     }
170 
171     ngx_http_lua_discard_bufs(r->pool, in);
172 
173     return NGX_OK;
174 }
175 
176 /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
177