xref: /lighttpd1.4/src/reqpool.c (revision 3a8fc4bc)
14e402670SGlenn Strauss /*
24e402670SGlenn Strauss  * reqpool - request objects
34e402670SGlenn Strauss  *
44e402670SGlenn Strauss  * Copyright(c) 2020 Glenn Strauss gstrauss()gluelogic.com  All rights reserved
54e402670SGlenn Strauss  * License: BSD 3-clause (same as lighttpd)
64e402670SGlenn Strauss  */
74e402670SGlenn Strauss #include "first.h"
84e402670SGlenn Strauss #include "reqpool.h"
94e402670SGlenn Strauss 
104e402670SGlenn Strauss #include <stdlib.h>
11d5366c0aSGlenn Strauss #include <string.h>
124e402670SGlenn Strauss 
134e402670SGlenn Strauss #include "base.h"
144e402670SGlenn Strauss #include "buffer.h"
154e402670SGlenn Strauss #include "chunk.h"
1696557115SGlenn Strauss #include "plugins.h"
174e402670SGlenn Strauss #include "plugin_config.h"
184e402670SGlenn Strauss #include "request.h"
192f2eec18SGlenn Strauss #include "response.h"
204e402670SGlenn Strauss 
217512d82cSGlenn Strauss #ifdef HAVE_PCRE2_H
227512d82cSGlenn Strauss #define PCRE2_CODE_UNIT_WIDTH 8
237512d82cSGlenn Strauss #include <pcre2.h>
247512d82cSGlenn Strauss #endif
257512d82cSGlenn Strauss 
264e402670SGlenn Strauss 
27d5366c0aSGlenn Strauss static const request_config *request_config_defaults;
28d5366c0aSGlenn Strauss 
29d5366c0aSGlenn Strauss 
30d5366c0aSGlenn Strauss void
request_config_set_defaults(const request_config * config_defaults)31d5366c0aSGlenn Strauss request_config_set_defaults (const request_config *config_defaults)
32d5366c0aSGlenn Strauss {
33d5366c0aSGlenn Strauss     request_config_defaults = config_defaults;
34d5366c0aSGlenn Strauss }
35d5366c0aSGlenn Strauss 
36d5366c0aSGlenn Strauss 
37d5366c0aSGlenn Strauss __attribute_noinline__
38d5366c0aSGlenn Strauss void
request_config_reset(request_st * const r)39d5366c0aSGlenn Strauss request_config_reset (request_st * const r)
40d5366c0aSGlenn Strauss {
41d5366c0aSGlenn Strauss     memcpy(&r->conf, request_config_defaults, sizeof(request_config));
42d5366c0aSGlenn Strauss }
43d5366c0aSGlenn Strauss 
44d5366c0aSGlenn Strauss 
454e402670SGlenn Strauss void
request_init_data(request_st * const r,connection * const con,server * const srv)46878073d1SGlenn Strauss request_init_data (request_st * const r, connection * const con, server * const srv)
474e402670SGlenn Strauss {
4881029b8bSGlenn Strauss     chunkqueue_init(&r->write_queue);
4981029b8bSGlenn Strauss     chunkqueue_init(&r->read_queue);
5081029b8bSGlenn Strauss     chunkqueue_init(&r->reqbody_queue);
514e402670SGlenn Strauss 
528d7e9439SGlenn Strauss     r->http_method = HTTP_METHOD_UNSET;
538d7e9439SGlenn Strauss     r->http_version = HTTP_VERSION_UNSET;
544e402670SGlenn Strauss     r->resp_header_len = 0;
554e402670SGlenn Strauss     r->loops_per_request = 0;
564e402670SGlenn Strauss     r->con = con;
574e402670SGlenn Strauss     r->tmp_buf = srv->tmp_buf;
58903024d7SGlenn Strauss     r->resp_body_scratchpad = -1;
59af3df29aSGlenn Strauss     r->server_name = &r->uri.authority;
60*3a8fc4bcSGlenn Strauss     r->dst_addr = &con->dst_addr;
61*3a8fc4bcSGlenn Strauss     r->dst_addr_buf = &con->dst_addr_buf;
624e402670SGlenn Strauss 
634e402670SGlenn Strauss     /* init plugin-specific per-request structures */
645e14db43SGlenn Strauss     r->plugin_ctx = ck_calloc(srv->plugins.used + 1, sizeof(void *));
655e14db43SGlenn Strauss     r->cond_cache = ck_calloc(srv->config_context->used, sizeof(cond_cache_t));
664e402670SGlenn Strauss 
677512d82cSGlenn Strauss   #ifdef HAVE_PCRE
68ef9608f3SGlenn Strauss     if (srv->config_captures) {
69ef9608f3SGlenn Strauss         r->cond_captures = srv->config_captures;
705e14db43SGlenn Strauss         r->cond_match = ck_calloc(srv->config_captures, sizeof(cond_match_t *));
715e14db43SGlenn Strauss         r->cond_match_data = ck_calloc(srv->config_captures,
725e14db43SGlenn Strauss                                        sizeof(cond_match_t));
734e402670SGlenn Strauss     }
744e402670SGlenn Strauss   #endif
75d5366c0aSGlenn Strauss 
76d5366c0aSGlenn Strauss     request_config_reset(r);
774e402670SGlenn Strauss }
784e402670SGlenn Strauss 
794e402670SGlenn Strauss 
804e402670SGlenn Strauss void
request_reset(request_st * const r)814e402670SGlenn Strauss request_reset (request_st * const r)
824e402670SGlenn Strauss {
834e402670SGlenn Strauss     plugins_call_handle_request_reset(r);
844e402670SGlenn Strauss 
852f2eec18SGlenn Strauss     http_response_reset(r);
864e402670SGlenn Strauss 
874e402670SGlenn Strauss     r->loops_per_request = 0;
884a600dabSGlenn Strauss     r->keep_alive = 0;
894e402670SGlenn Strauss 
908d7e9439SGlenn Strauss     r->h2state = 0; /* H2_STATE_IDLE */
918d7e9439SGlenn Strauss     r->h2id = 0;
924e402670SGlenn Strauss     r->http_method = HTTP_METHOD_UNSET;
934e402670SGlenn Strauss     r->http_version = HTTP_VERSION_UNSET;
944e402670SGlenn Strauss 
954e402670SGlenn Strauss     /*con->proto_default_port = 80;*//*set to default in connection_accepted()*/
964e402670SGlenn Strauss 
974e402670SGlenn Strauss     r->http_host = NULL;
984e402670SGlenn Strauss     r->reqbody_length = 0;
994e402670SGlenn Strauss     r->te_chunked = 0;
100903024d7SGlenn Strauss     r->resp_body_scratchpad = -1;
1014e402670SGlenn Strauss     r->rqst_htags = 0;
1024e402670SGlenn Strauss 
1034e402670SGlenn Strauss     r->async_callback = 0;
1044e402670SGlenn Strauss     r->error_handler_saved_status = 0;
1054e402670SGlenn Strauss     /*r->error_handler_saved_method = HTTP_METHOD_UNSET;*/
1064e402670SGlenn Strauss     /*(error_handler_saved_method value is not valid
1074e402670SGlenn Strauss      * unless error_handler_saved_status is set)*/
1085d1aa5d0SGlenn Strauss     r->h2_connect_ext = 0;
1094e402670SGlenn Strauss 
1104e402670SGlenn Strauss     buffer_clear(&r->uri.scheme);
1114e402670SGlenn Strauss 
1124e402670SGlenn Strauss     if (r->rqst_header_len <= BUFFER_MAX_REUSE_SIZE) {
1134e402670SGlenn Strauss         r->rqst_headers.used = 0;
1144e402670SGlenn Strauss         /* (Note: total header size not recalculated on HANDLER_COMEBACK
1154e402670SGlenn Strauss          *  even if other request headers changed during processing)
1164e402670SGlenn Strauss          * (While this might delay release of larger buffers, it is not
1174e402670SGlenn Strauss          *  expected to be the general case.  For those systems where it
1184e402670SGlenn Strauss          *  is a typical case, the larger buffers are likely to be reused) */
1194e402670SGlenn Strauss         buffer_clear(&r->target);
1204e402670SGlenn Strauss         buffer_clear(&r->pathinfo);
1214e402670SGlenn Strauss         /*buffer_clear(&r->target_orig);*/  /* reset later; used by mod_status*/
1224e402670SGlenn Strauss         /*buffer_clear(&r->uri.path);*/     /* reset later; used by mod_status*/
1234e402670SGlenn Strauss         /*buffer_clear(&r->uri.query);*/    /* reset later; used by mod_status*/
1244e402670SGlenn Strauss         /*buffer_clear(&r->uri.authority);*//* reset later; used by mod_status*/
1254e402670SGlenn Strauss         /*buffer_clear(&r->server_name_buf);*//* reset when used */
1264e402670SGlenn Strauss     }
1274e402670SGlenn Strauss     else {
1284e402670SGlenn Strauss         buffer_reset(&r->target);
1294e402670SGlenn Strauss         buffer_reset(&r->pathinfo);
1304e402670SGlenn Strauss         /*buffer_reset(&r->target_orig);*/  /* reset later; used by mod_status*/
1314e402670SGlenn Strauss         /*buffer_reset(&r->uri.path);*/     /* reset later; used by mod_status*/
1324e402670SGlenn Strauss         /*buffer_reset(&r->uri.query);*/    /* reset later; used by mod_status*/
1334e402670SGlenn Strauss         /*buffer_clear(&r->uri.authority);*//* reset later; used by mod_status*/
1344e402670SGlenn Strauss         /*buffer_clear(&r->server_name_buf);*//* reset when used */
1354e402670SGlenn Strauss         array_reset_data_strings(&r->rqst_headers);
1364e402670SGlenn Strauss     }
1374e402670SGlenn Strauss     r->rqst_header_len = 0;
1384e402670SGlenn Strauss     if (0 != r->env.used)
1394e402670SGlenn Strauss         array_reset_data_strings(&r->env);
1404e402670SGlenn Strauss 
14181029b8bSGlenn Strauss     chunkqueue_reset(&r->reqbody_queue);
142550609c8SGlenn Strauss     /* r->read_queue, r->write_queue are shared with con for HTTP/1.1
143550609c8SGlenn Strauss      * but are different than con->read_queue, con->write_queue for HTTP/2
14481029b8bSGlenn Strauss      * For HTTP/1.1, when &r->read_queue == con->read_queue, r->read_queue
145550609c8SGlenn Strauss      * is not cleared between requests since it might contain subsequent
146550609c8SGlenn Strauss      * requests.  (see also request_release()) */
1474e402670SGlenn Strauss 
1484e402670SGlenn Strauss     /* The cond_cache gets reset in response.c */
1494e402670SGlenn Strauss     /* config_cond_cache_reset(r); */
150d5366c0aSGlenn Strauss 
151d5366c0aSGlenn Strauss     request_config_reset(r);
1524e402670SGlenn Strauss }
1534e402670SGlenn Strauss 
1544e402670SGlenn Strauss 
155550609c8SGlenn Strauss #if 0 /* DEBUG_DEV */
156550609c8SGlenn Strauss __attribute_cold__
157550609c8SGlenn Strauss static void request_plugin_ctx_check(request_st * const r, server * const srv) {
158550609c8SGlenn Strauss     /* plugins should have cleaned themselves up */
159550609c8SGlenn Strauss     for (uint32_t i = 0, used = srv->plugins.used; i < used; ++i) {
160550609c8SGlenn Strauss         plugin *p = ((plugin **)(srv->plugins.ptr))[i];
161550609c8SGlenn Strauss         plugin_data_base *pd = p->data;
162550609c8SGlenn Strauss         if (!pd) continue;
163550609c8SGlenn Strauss         if (NULL == r->plugin_ctx[pd->id]
164550609c8SGlenn Strauss             && NULL == r->con->plugin_ctx[pd->id]) continue;
165550609c8SGlenn Strauss         log_error(r->conf.errh, __FILE__, __LINE__,
166550609c8SGlenn Strauss           "missing cleanup in %s", p->name);
167550609c8SGlenn Strauss         r->plugin_ctx[pd->id] = NULL;
168550609c8SGlenn Strauss         r->con->plugin_ctx[pd->id] = NULL;
169550609c8SGlenn Strauss     }
170550609c8SGlenn Strauss }
171550609c8SGlenn Strauss #endif
172550609c8SGlenn Strauss 
173550609c8SGlenn Strauss 
174550609c8SGlenn Strauss void
request_reset_ex(request_st * const r)175550609c8SGlenn Strauss request_reset_ex (request_st * const r)
176550609c8SGlenn Strauss {
177550609c8SGlenn Strauss   #if 0 /* DEBUG_DEV */
178550609c8SGlenn Strauss     /* plugins should have cleaned themselves up (id range: [1,used]) */
179550609c8SGlenn Strauss     connection * const con = r->con;
180550609c8SGlenn Strauss     server * const srv = con->srv;
181550609c8SGlenn Strauss     for (uint32_t i = 1; i <= srv->plugins.used; ++i) {
182550609c8SGlenn Strauss         if (NULL != r->plugin_ctx[i] || NULL != con->plugin_ctx[i]) {
183550609c8SGlenn Strauss             request_plugin_ctx_check(r, srv);
184550609c8SGlenn Strauss             break;
185550609c8SGlenn Strauss         }
186550609c8SGlenn Strauss     }
187550609c8SGlenn Strauss   #endif
188550609c8SGlenn Strauss 
189af3df29aSGlenn Strauss     r->server_name = &r->uri.authority;
190550609c8SGlenn Strauss     buffer_clear(&r->uri.authority);
191550609c8SGlenn Strauss     buffer_reset(&r->uri.path);
192550609c8SGlenn Strauss     buffer_reset(&r->uri.query);
1935bc92071SGlenn Strauss     buffer_reset(&r->physical.path);
1945bc92071SGlenn Strauss     buffer_reset(&r->physical.rel_path);
195550609c8SGlenn Strauss     buffer_reset(&r->target_orig);
196550609c8SGlenn Strauss     buffer_reset(&r->target);       /*(see comments in request_reset())*/
197550609c8SGlenn Strauss     buffer_reset(&r->pathinfo);     /*(see comments in request_reset())*/
198550609c8SGlenn Strauss 
199550609c8SGlenn Strauss     /* preserve; callers must handle changes */
200550609c8SGlenn Strauss     /*r->state = CON_STATE_CONNECT;*/
201550609c8SGlenn Strauss }
202550609c8SGlenn Strauss 
203550609c8SGlenn Strauss 
2044e402670SGlenn Strauss void
request_free_data(request_st * const r)205878073d1SGlenn Strauss request_free_data (request_st * const r)
2064e402670SGlenn Strauss {
20781029b8bSGlenn Strauss     chunkqueue_reset(&r->reqbody_queue);
20881029b8bSGlenn Strauss     chunkqueue_reset(&r->write_queue);
20981029b8bSGlenn Strauss     chunkqueue_reset(&r->read_queue);
2104e402670SGlenn Strauss     array_free_data(&r->rqst_headers);
2114e402670SGlenn Strauss     array_free_data(&r->resp_headers);
2124e402670SGlenn Strauss     array_free_data(&r->env);
2134e402670SGlenn Strauss 
2144e402670SGlenn Strauss     free(r->target.ptr);
2154e402670SGlenn Strauss     free(r->target_orig.ptr);
2164e402670SGlenn Strauss 
2174e402670SGlenn Strauss     free(r->uri.scheme.ptr);
2184e402670SGlenn Strauss     free(r->uri.authority.ptr);
2194e402670SGlenn Strauss     free(r->uri.path.ptr);
2204e402670SGlenn Strauss     free(r->uri.query.ptr);
2214e402670SGlenn Strauss 
2224e402670SGlenn Strauss     free(r->physical.doc_root.ptr);
2234e402670SGlenn Strauss     free(r->physical.path.ptr);
2244e402670SGlenn Strauss     free(r->physical.basedir.ptr);
2254e402670SGlenn Strauss     free(r->physical.rel_path.ptr);
2264e402670SGlenn Strauss 
2274e402670SGlenn Strauss     free(r->pathinfo.ptr);
2284e402670SGlenn Strauss     free(r->server_name_buf.ptr);
2294e402670SGlenn Strauss 
2304e402670SGlenn Strauss     free(r->plugin_ctx);
2314e402670SGlenn Strauss     free(r->cond_cache);
2327512d82cSGlenn Strauss   #ifdef HAVE_PCRE
2337512d82cSGlenn Strauss     if (r->cond_match_data) {
234ef9608f3SGlenn Strauss         for (int i = 0, used = r->cond_captures; i < used; ++i) {
235c378e3adSGlenn Strauss           #ifdef HAVE_PCRE2_H
2367512d82cSGlenn Strauss             if (r->cond_match_data[i].match_data)
2377512d82cSGlenn Strauss                 pcre2_match_data_free(r->cond_match_data[i].match_data);
238c378e3adSGlenn Strauss           #else /* HAVE_PCRE_H */
239c378e3adSGlenn Strauss             if (r->cond_match_data[i].matches)
240c378e3adSGlenn Strauss                 free(r->cond_match_data[i].matches);
2417512d82cSGlenn Strauss           #endif
242c378e3adSGlenn Strauss         }
2437ea2d407SGlenn Strauss         free(r->cond_match_data);
2447512d82cSGlenn Strauss         free(r->cond_match);
2457512d82cSGlenn Strauss     }
2467ea2d407SGlenn Strauss   #endif
2474e402670SGlenn Strauss 
2484e402670SGlenn Strauss     /* note: r is not zeroed here and r is not freed here */
2494e402670SGlenn Strauss }
250550609c8SGlenn Strauss 
251550609c8SGlenn Strauss 
252878073d1SGlenn Strauss /* linked list of (request_st *) cached for reuse */
253878073d1SGlenn Strauss static request_st *reqpool;
254878073d1SGlenn Strauss 
255878073d1SGlenn Strauss 
256878073d1SGlenn Strauss void
request_pool_free(void)257878073d1SGlenn Strauss request_pool_free (void)
258878073d1SGlenn Strauss {
259878073d1SGlenn Strauss     while (reqpool) {
260878073d1SGlenn Strauss         request_st * const r = reqpool;
261878073d1SGlenn Strauss         reqpool = (request_st *)r->con; /*(reuse r->con as next ptr)*/
262878073d1SGlenn Strauss         request_free_data(r);
263878073d1SGlenn Strauss         free(r);
264878073d1SGlenn Strauss     }
265878073d1SGlenn Strauss }
266878073d1SGlenn Strauss 
267878073d1SGlenn Strauss 
268550609c8SGlenn Strauss void
request_release(request_st * const r)269550609c8SGlenn Strauss request_release (request_st * const r)
270550609c8SGlenn Strauss {
271550609c8SGlenn Strauss     /* (For HTTP/1.1, r == &con->request, and so request_release() not called)
272550609c8SGlenn Strauss      * r->read_queue, r->write_queue are shared with con for HTTP/1.1
273550609c8SGlenn Strauss      * but are different than con->read_queue, con->write_queue for HTTP/2
27481029b8bSGlenn Strauss      * For HTTP/1.1, when &r->read_queue == con->read_queue, r->read_queue
275550609c8SGlenn Strauss      * is not cleared between requests since it might contain subsequent
276550609c8SGlenn Strauss      * requests.  (see also request_reset()) */
27781029b8bSGlenn Strauss     chunkqueue_reset(&r->read_queue);
278550609c8SGlenn Strauss 
279550609c8SGlenn Strauss     /*(r->cond_cache and r->cond_match are re-init in h2_init_stream())*/
280550609c8SGlenn Strauss 
281550609c8SGlenn Strauss     request_reset(r);
282550609c8SGlenn Strauss     request_reset_ex(r);
283550609c8SGlenn Strauss     r->state = CON_STATE_CONNECT;
284550609c8SGlenn Strauss 
285878073d1SGlenn Strauss     r->con = (connection *)reqpool; /*(reuse r->con as next ptr)*/
286878073d1SGlenn Strauss     reqpool = r;
287878073d1SGlenn Strauss }
288550609c8SGlenn Strauss 
289550609c8SGlenn Strauss 
290550609c8SGlenn Strauss request_st *
request_acquire(connection * const con)291550609c8SGlenn Strauss request_acquire (connection * const con)
292550609c8SGlenn Strauss {
293878073d1SGlenn Strauss     request_st *r = reqpool;
294878073d1SGlenn Strauss     if (r) {
295878073d1SGlenn Strauss         reqpool = (request_st *)r->con; /*(reuse r->con as next ptr)*/
296878073d1SGlenn Strauss     }
297878073d1SGlenn Strauss     else {
2985e14db43SGlenn Strauss         r = ck_calloc(1, sizeof(request_st));
299878073d1SGlenn Strauss         request_init_data(r, con, con->srv);
300878073d1SGlenn Strauss     }
301550609c8SGlenn Strauss 
302550609c8SGlenn Strauss     r->con = con;
303550609c8SGlenn Strauss     r->tmp_buf = con->srv->tmp_buf;
304550609c8SGlenn Strauss     return r;
305550609c8SGlenn Strauss }
306