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