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