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