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