xref: /lighttpd1.4/src/reqpool.c (revision a01e62bb)
1 /*
2  * reqpool - request objects
3  *
4  * Copyright(c) 2020 Glenn Strauss gstrauss()gluelogic.com  All rights reserved
5  * License: BSD 3-clause (same as lighttpd)
6  */
7 #include "first.h"
8 #include "reqpool.h"
9 
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include "base.h"
14 #include "buffer.h"
15 #include "chunk.h"
16 #include "plugins.h"
17 #include "plugin_config.h"
18 #include "request.h"
19 #include "response.h"
20 
21 #ifdef HAVE_PCRE2_H
22 #define PCRE2_CODE_UNIT_WIDTH 8
23 #include <pcre2.h>
24 #endif
25 
26 
27 static const request_config *request_config_defaults;
28 
29 
30 void
31 request_config_set_defaults (const request_config *config_defaults)
32 {
33     request_config_defaults = config_defaults;
34 }
35 
36 
37 __attribute_noinline__
38 void
39 request_config_reset (request_st * const r)
40 {
41     memcpy(&r->conf, request_config_defaults, sizeof(request_config));
42 }
43 
44 
45 void
46 request_init_data (request_st * const r, connection * const con, server * const srv)
47 {
48     chunkqueue_init(&r->write_queue);
49     chunkqueue_init(&r->read_queue);
50     chunkqueue_init(&r->reqbody_queue);
51 
52     r->http_method = HTTP_METHOD_UNSET;
53     r->http_version = HTTP_VERSION_UNSET;
54     r->resp_header_len = 0;
55     r->loops_per_request = 0;
56     r->con = con;
57     r->tmp_buf = srv->tmp_buf;
58     r->resp_body_scratchpad = -1;
59     r->server_name = &r->uri.authority;
60 
61     /* init plugin-specific per-request structures */
62     r->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
63     force_assert(NULL != r->plugin_ctx);
64 
65     r->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
66     force_assert(NULL != r->cond_cache);
67 
68   #ifdef HAVE_PCRE
69     if (srv->config_captures) {
70         r->cond_captures = srv->config_captures;
71         r->cond_match = calloc(srv->config_captures, sizeof(cond_match_t *));
72         force_assert(NULL != r->cond_match);
73         r->cond_match_data = calloc(srv->config_captures, sizeof(cond_match_t));
74         force_assert(NULL != r->cond_match_data);
75     }
76   #endif
77 
78     request_config_reset(r);
79 }
80 
81 
82 void
83 request_reset (request_st * const r)
84 {
85     plugins_call_handle_request_reset(r);
86 
87     http_response_reset(r);
88 
89     r->loops_per_request = 0;
90     r->keep_alive = 0;
91 
92     r->h2state = 0; /* H2_STATE_IDLE */
93     r->h2id = 0;
94     r->http_method = HTTP_METHOD_UNSET;
95     r->http_version = HTTP_VERSION_UNSET;
96 
97     /*con->proto_default_port = 80;*//*set to default in connection_accepted()*/
98 
99     r->http_host = NULL;
100     r->reqbody_length = 0;
101     r->te_chunked = 0;
102     r->resp_body_scratchpad = -1;
103     r->rqst_htags = 0;
104 
105     r->async_callback = 0;
106     r->error_handler_saved_status = 0;
107     /*r->error_handler_saved_method = HTTP_METHOD_UNSET;*/
108     /*(error_handler_saved_method value is not valid
109      * unless error_handler_saved_status is set)*/
110     r->h2_connect_ext = 0;
111 
112     buffer_clear(&r->uri.scheme);
113 
114     if (r->rqst_header_len <= BUFFER_MAX_REUSE_SIZE) {
115         r->rqst_headers.used = 0;
116         /* (Note: total header size not recalculated on HANDLER_COMEBACK
117          *  even if other request headers changed during processing)
118          * (While this might delay release of larger buffers, it is not
119          *  expected to be the general case.  For those systems where it
120          *  is a typical case, the larger buffers are likely to be reused) */
121         buffer_clear(&r->target);
122         buffer_clear(&r->pathinfo);
123         /*buffer_clear(&r->target_orig);*/  /* reset later; used by mod_status*/
124         /*buffer_clear(&r->uri.path);*/     /* reset later; used by mod_status*/
125         /*buffer_clear(&r->uri.query);*/    /* reset later; used by mod_status*/
126         /*buffer_clear(&r->uri.authority);*//* reset later; used by mod_status*/
127         /*buffer_clear(&r->server_name_buf);*//* reset when used */
128     }
129     else {
130         buffer_reset(&r->target);
131         buffer_reset(&r->pathinfo);
132         /*buffer_reset(&r->target_orig);*/  /* reset later; used by mod_status*/
133         /*buffer_reset(&r->uri.path);*/     /* reset later; used by mod_status*/
134         /*buffer_reset(&r->uri.query);*/    /* reset later; used by mod_status*/
135         /*buffer_clear(&r->uri.authority);*//* reset later; used by mod_status*/
136         /*buffer_clear(&r->server_name_buf);*//* reset when used */
137         array_reset_data_strings(&r->rqst_headers);
138     }
139     r->rqst_header_len = 0;
140     if (0 != r->env.used)
141         array_reset_data_strings(&r->env);
142 
143     chunkqueue_reset(&r->reqbody_queue);
144     /* r->read_queue, r->write_queue are shared with con for HTTP/1.1
145      * but are different than con->read_queue, con->write_queue for HTTP/2
146      * For HTTP/1.1, when &r->read_queue == con->read_queue, r->read_queue
147      * is not cleared between requests since it might contain subsequent
148      * requests.  (see also request_release()) */
149 
150     /* The cond_cache gets reset in response.c */
151     /* config_cond_cache_reset(r); */
152 
153     request_config_reset(r);
154 }
155 
156 
157 #if 0 /* DEBUG_DEV */
158 __attribute_cold__
159 static void request_plugin_ctx_check(request_st * const r, server * const srv) {
160     /* plugins should have cleaned themselves up */
161     for (uint32_t i = 0, used = srv->plugins.used; i < used; ++i) {
162         plugin *p = ((plugin **)(srv->plugins.ptr))[i];
163         plugin_data_base *pd = p->data;
164         if (!pd) continue;
165         if (NULL == r->plugin_ctx[pd->id]
166             && NULL == r->con->plugin_ctx[pd->id]) continue;
167         log_error(r->conf.errh, __FILE__, __LINE__,
168           "missing cleanup in %s", p->name);
169         r->plugin_ctx[pd->id] = NULL;
170         r->con->plugin_ctx[pd->id] = NULL;
171     }
172 }
173 #endif
174 
175 
176 void
177 request_reset_ex (request_st * const r)
178 {
179   #if 0 /* DEBUG_DEV */
180     /* plugins should have cleaned themselves up (id range: [1,used]) */
181     connection * const con = r->con;
182     server * const srv = con->srv;
183     for (uint32_t i = 1; i <= srv->plugins.used; ++i) {
184         if (NULL != r->plugin_ctx[i] || NULL != con->plugin_ctx[i]) {
185             request_plugin_ctx_check(r, srv);
186             break;
187         }
188     }
189   #endif
190 
191     r->server_name = &r->uri.authority;
192     buffer_clear(&r->uri.authority);
193     buffer_reset(&r->uri.path);
194     buffer_reset(&r->uri.query);
195     buffer_reset(&r->physical.path);
196     buffer_reset(&r->physical.rel_path);
197     buffer_reset(&r->target_orig);
198     buffer_reset(&r->target);       /*(see comments in request_reset())*/
199     buffer_reset(&r->pathinfo);     /*(see comments in request_reset())*/
200 
201     /* preserve; callers must handle changes */
202     /*r->state = CON_STATE_CONNECT;*/
203 }
204 
205 
206 void
207 request_free_data (request_st * const r)
208 {
209     chunkqueue_reset(&r->reqbody_queue);
210     chunkqueue_reset(&r->write_queue);
211     chunkqueue_reset(&r->read_queue);
212     array_free_data(&r->rqst_headers);
213     array_free_data(&r->resp_headers);
214     array_free_data(&r->env);
215 
216     free(r->target.ptr);
217     free(r->target_orig.ptr);
218 
219     free(r->uri.scheme.ptr);
220     free(r->uri.authority.ptr);
221     free(r->uri.path.ptr);
222     free(r->uri.query.ptr);
223 
224     free(r->physical.doc_root.ptr);
225     free(r->physical.path.ptr);
226     free(r->physical.basedir.ptr);
227     free(r->physical.rel_path.ptr);
228 
229     free(r->pathinfo.ptr);
230     free(r->server_name_buf.ptr);
231 
232     free(r->plugin_ctx);
233     free(r->cond_cache);
234   #ifdef HAVE_PCRE
235     if (r->cond_match_data) {
236         for (int i = 0, used = r->cond_captures; i < used; ++i) {
237           #ifdef HAVE_PCRE2_H
238             if (r->cond_match_data[i].match_data)
239                 pcre2_match_data_free(r->cond_match_data[i].match_data);
240           #else /* HAVE_PCRE_H */
241             if (r->cond_match_data[i].matches)
242                 free(r->cond_match_data[i].matches);
243           #endif
244         }
245         free(r->cond_match_data);
246         free(r->cond_match);
247     }
248   #endif
249 
250     /* note: r is not zeroed here and r is not freed here */
251 }
252 
253 
254 /* linked list of (request_st *) cached for reuse */
255 static request_st *reqpool;
256 
257 
258 void
259 request_pool_free (void)
260 {
261     while (reqpool) {
262         request_st * const r = reqpool;
263         reqpool = (request_st *)r->con; /*(reuse r->con as next ptr)*/
264         request_free_data(r);
265         free(r);
266     }
267 }
268 
269 
270 void
271 request_release (request_st * const r)
272 {
273     /* (For HTTP/1.1, r == &con->request, and so request_release() not called)
274      * r->read_queue, r->write_queue are shared with con for HTTP/1.1
275      * but are different than con->read_queue, con->write_queue for HTTP/2
276      * For HTTP/1.1, when &r->read_queue == con->read_queue, r->read_queue
277      * is not cleared between requests since it might contain subsequent
278      * requests.  (see also request_reset()) */
279     chunkqueue_reset(&r->read_queue);
280 
281     /*(r->cond_cache and r->cond_match are re-init in h2_init_stream())*/
282 
283     request_reset(r);
284     request_reset_ex(r);
285     r->state = CON_STATE_CONNECT;
286 
287     r->con = (connection *)reqpool; /*(reuse r->con as next ptr)*/
288     reqpool = r;
289 }
290 
291 
292 request_st *
293 request_acquire (connection * const con)
294 {
295     request_st *r = reqpool;
296     if (r) {
297         reqpool = (request_st *)r->con; /*(reuse r->con as next ptr)*/
298     }
299     else {
300         r = calloc(1, sizeof(request_st));
301         force_assert(r);
302         request_init_data(r, con, con->srv);
303     }
304 
305     r->con = con;
306     r->tmp_buf = con->srv->tmp_buf;
307     return r;
308 }
309