mod_reqtimeout.c.modreqto2217 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "httpd.h"
  17. #include "http_config.h"
  18. #include "http_request.h"
  19. #include "http_connection.h"
  20. #include "http_protocol.h"
  21. #include "http_log.h"
  22. #include "util_filter.h"
  23. #define APR_WANT_STRFUNC
  24. #include "apr_strings.h"
  25. module AP_MODULE_DECLARE_DATA reqtimeout_module;
  26. typedef struct
  27. {
  28. int header_timeout; /* timeout for reading the req hdrs in secs */
  29. int header_max_timeout; /* max timeout for req hdrs in secs */
  30. int header_min_rate; /* min rate for reading req hdrs in bytes/s */
  31. apr_time_t header_rate_factor;
  32. int body_timeout; /* timeout for reading the req body in secs */
  33. int body_max_timeout; /* max timeout for req body in secs */
  34. int body_min_rate; /* timeout for reading the req body in secs */
  35. apr_time_t body_rate_factor;
  36. } reqtimeout_srv_cfg;
  37. typedef struct
  38. {
  39. apr_time_t timeout_at;
  40. apr_time_t max_timeout_at;
  41. int min_rate;
  42. int new_timeout;
  43. int new_max_timeout;
  44. int in_keep_alive;
  45. char *type;
  46. apr_time_t rate_factor;
  47. } reqtimeout_con_cfg;
  48. typedef struct
  49. {
  50. apr_socket_t *socket;
  51. } reqtimeout_ctx;
  52. static const char *const reqtimeout_filter_name = "reqtimeout";
  53. static void extend_timeout(reqtimeout_con_cfg *ccfg, apr_bucket_brigade *bb)
  54. {
  55. apr_off_t len;
  56. apr_time_t new_timeout_at;
  57. if (apr_brigade_length(bb, 0, &len) != APR_SUCCESS || len <= 0)
  58. return;
  59. new_timeout_at = ccfg->timeout_at + len * ccfg->rate_factor;
  60. if (ccfg->max_timeout_at > 0 && new_timeout_at > ccfg->max_timeout_at) {
  61. ccfg->timeout_at = ccfg->max_timeout_at;
  62. }
  63. else {
  64. ccfg->timeout_at = new_timeout_at;
  65. }
  66. }
  67. static apr_status_t reqtimeout_filter(ap_filter_t *f,
  68. apr_bucket_brigade *bb,
  69. ap_input_mode_t mode,
  70. apr_read_type_e block,
  71. apr_off_t readbytes)
  72. {
  73. reqtimeout_ctx *ctx;
  74. apr_time_t time_left;
  75. apr_time_t now;
  76. apr_status_t rv;
  77. apr_interval_time_t saved_sock_timeout = -1;
  78. reqtimeout_con_cfg *ccfg;
  79. ctx = f->ctx;
  80. AP_DEBUG_ASSERT(ctx != NULL);
  81. ccfg = ap_get_module_config(f->c->conn_config, &reqtimeout_module);
  82. AP_DEBUG_ASSERT(ccfg != NULL);
  83. if (ccfg->in_keep_alive) {
  84. /* For this read, the normal keep-alive timeout must be used */
  85. ccfg->in_keep_alive = 0;
  86. return ap_get_brigade(f->next, bb, mode, block, readbytes);
  87. }
  88. now = apr_time_now();
  89. if (ccfg->new_timeout > 0) {
  90. /* set new timeout */
  91. ccfg->timeout_at = now + apr_time_from_sec(ccfg->new_timeout);
  92. ccfg->new_timeout = 0;
  93. if (ccfg->new_max_timeout > 0) {
  94. ccfg->max_timeout_at = now + apr_time_from_sec(ccfg->new_max_timeout);
  95. ccfg->new_max_timeout = 0;
  96. }
  97. }
  98. else if (ccfg->timeout_at == 0) {
  99. /* no timeout set */
  100. return ap_get_brigade(f->next, bb, mode, block, readbytes);
  101. }
  102. time_left = ccfg->timeout_at - now;
  103. if (time_left <= 0) {
  104. ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
  105. "Request %s read timeout", ccfg->type);
  106. return APR_TIMEUP;
  107. }
  108. if (block == APR_NONBLOCK_READ || mode == AP_MODE_INIT
  109. || mode == AP_MODE_EATCRLF) {
  110. rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
  111. if (ccfg->min_rate > 0 && rv == APR_SUCCESS) {
  112. extend_timeout(ccfg, bb);
  113. }
  114. return rv;
  115. }
  116. if (time_left < apr_time_from_sec(1)) {
  117. time_left = apr_time_from_sec(1);
  118. }
  119. rv = apr_socket_timeout_get(ctx->socket, &saved_sock_timeout);
  120. AP_DEBUG_ASSERT(rv == APR_SUCCESS);
  121. if (saved_sock_timeout >= time_left) {
  122. rv = apr_socket_timeout_set(ctx->socket, time_left);
  123. AP_DEBUG_ASSERT(rv == APR_SUCCESS);
  124. }
  125. else {
  126. saved_sock_timeout = -1;
  127. }
  128. rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
  129. if (saved_sock_timeout != -1) {
  130. apr_socket_timeout_set(ctx->socket, saved_sock_timeout);
  131. }
  132. if (ccfg->min_rate > 0 && rv == APR_SUCCESS) {
  133. extend_timeout(ccfg, bb);
  134. }
  135. if (rv == APR_TIMEUP) {
  136. ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
  137. "Request %s read timeout", ccfg->type);
  138. }
  139. return rv;
  140. }
  141. static int reqtimeout_pre_conn(conn_rec *c, void *csd)
  142. {
  143. reqtimeout_ctx *ctx;
  144. reqtimeout_con_cfg *ccfg;
  145. reqtimeout_srv_cfg *cfg;
  146. cfg = ap_get_module_config(c->base_server->module_config,
  147. &reqtimeout_module);
  148. AP_DEBUG_ASSERT(cfg != NULL);
  149. if (cfg->header_timeout <= 0 && cfg->body_timeout <= 0) {
  150. /* not configured for this vhost */
  151. return OK;
  152. }
  153. ctx = apr_pcalloc(c->pool, sizeof(reqtimeout_ctx));
  154. ctx->socket = csd;
  155. ccfg = apr_pcalloc(c->pool, sizeof(reqtimeout_con_cfg));
  156. ccfg->new_timeout = cfg->header_timeout;
  157. ccfg->new_max_timeout = cfg->header_max_timeout;
  158. ccfg->type = "header";
  159. ccfg->min_rate = cfg->header_min_rate;
  160. ccfg->rate_factor = cfg->header_rate_factor;
  161. ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg);
  162. ap_add_input_filter("reqtimeout", ctx, NULL, c);
  163. return OK;
  164. }
  165. static int reqtimeout_after_headers(request_rec *r)
  166. {
  167. reqtimeout_srv_cfg *cfg;
  168. reqtimeout_con_cfg *ccfg =
  169. ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
  170. if (ccfg == NULL) {
  171. /* not configured for this vhost */
  172. return OK;
  173. }
  174. cfg = ap_get_module_config(r->connection->base_server->module_config,
  175. &reqtimeout_module);
  176. AP_DEBUG_ASSERT(cfg != NULL);
  177. ccfg->timeout_at = 0;
  178. ccfg->max_timeout_at = 0;
  179. ccfg->new_timeout = cfg->body_timeout;
  180. ccfg->new_max_timeout = cfg->body_max_timeout;
  181. ccfg->min_rate = cfg->body_min_rate;
  182. ccfg->rate_factor = cfg->body_rate_factor;
  183. ccfg->type = "body";
  184. return OK;
  185. }
  186. static int reqtimeout_after_body(request_rec *r)
  187. {
  188. reqtimeout_srv_cfg *cfg;
  189. reqtimeout_con_cfg *ccfg =
  190. ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
  191. if (ccfg == NULL) {
  192. /* not configured for this vhost */
  193. return OK;
  194. }
  195. cfg = ap_get_module_config(r->connection->base_server->module_config,
  196. &reqtimeout_module);
  197. AP_DEBUG_ASSERT(cfg != NULL);
  198. ccfg->timeout_at = 0;
  199. ccfg->max_timeout_at = 0;
  200. ccfg->in_keep_alive = 1;
  201. ccfg->new_timeout = cfg->header_timeout;
  202. ccfg->new_max_timeout = cfg->header_max_timeout;
  203. ccfg->min_rate = cfg->header_min_rate;
  204. ccfg->rate_factor = cfg->header_rate_factor;
  205. ccfg->type = "header";
  206. return OK;
  207. }
  208. static void *reqtimeout_create_srv_config(apr_pool_t *p, server_rec *s)
  209. {
  210. reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
  211. cfg->header_timeout = -1;
  212. cfg->header_max_timeout = -1;
  213. cfg->header_min_rate = -1;
  214. cfg->body_timeout = -1;
  215. cfg->body_max_timeout = -1;
  216. cfg->body_min_rate = -1;
  217. return cfg;
  218. }
  219. #define MERGE_INT(cfg, b, a, val) cfg->val = (a->val == -1) ? b->val : a->val;
  220. static void *reqtimeout_merge_srv_config(apr_pool_t *p, void *base_, void *add_)
  221. {
  222. reqtimeout_srv_cfg *base = base_;
  223. reqtimeout_srv_cfg *add = add_;
  224. reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
  225. MERGE_INT(cfg, base, add, header_timeout);
  226. MERGE_INT(cfg, base, add, header_max_timeout);
  227. MERGE_INT(cfg, base, add, header_min_rate);
  228. MERGE_INT(cfg, base, add, body_timeout);
  229. MERGE_INT(cfg, base, add, body_max_timeout);
  230. MERGE_INT(cfg, base, add, body_min_rate);
  231. cfg->header_rate_factor = (cfg->header_min_rate == -1) ? base->header_rate_factor :
  232. add->header_rate_factor;
  233. cfg->body_rate_factor = (cfg->body_min_rate == -1) ? base->body_rate_factor :
  234. add->body_rate_factor;
  235. return cfg;
  236. }
  237. static const char *parse_int(apr_pool_t *p, const char *arg, int *val) {
  238. char *endptr;
  239. *val = strtol(arg, &endptr, 10);
  240. if (arg == endptr) {
  241. return apr_psprintf(p, "Value '%s' not numerical", endptr);
  242. }
  243. if (*endptr != '\0') {
  244. return apr_psprintf(p, "Cannot parse '%s'", endptr);
  245. }
  246. if (*val < 0) {
  247. return "Value must be non-negative";
  248. }
  249. return NULL;
  250. }
  251. static const char *set_reqtimeout_param(reqtimeout_srv_cfg *conf,
  252. apr_pool_t *p,
  253. const char *key,
  254. const char *val)
  255. {
  256. const char *ret = NULL;
  257. char *rate_str = NULL, *initial_str, *max_str = NULL;
  258. int rate = 0, initial = 0, max = 0;
  259. enum { PARAM_HEADER, PARAM_BODY } type;
  260. if (!strcasecmp(key, "header")) {
  261. type = PARAM_HEADER;
  262. }
  263. else if (!strcasecmp(key, "body")) {
  264. type = PARAM_BODY;
  265. }
  266. else {
  267. return "Unknown RequestReadTimeout parameter";
  268. }
  269. if ((rate_str = ap_strcasestr(val, ",minrate="))) {
  270. initial_str = apr_pstrndup(p, val, rate_str - val);
  271. rate_str += strlen(",minrate=");
  272. ret = parse_int(p, rate_str, &rate);
  273. if (ret)
  274. return ret;
  275. if (rate == 0)
  276. return "Minimum data rate must be larger than 0";
  277. if ((max_str = strchr(initial_str, '-'))) {
  278. *max_str++ = '\0';
  279. ret = parse_int(p, max_str, &max);
  280. if (ret)
  281. return ret;
  282. }
  283. ret = parse_int(p, initial_str, &initial);
  284. }
  285. else {
  286. if (ap_strchr_c(val, '-'))
  287. return "Must set MinRate option if using timeout range";
  288. ret = parse_int(p, val, &initial);
  289. }
  290. if (ret)
  291. return ret;
  292. if (max && initial >= max) {
  293. return "Maximum timeout must be larger than initial timeout";
  294. }
  295. if (type == PARAM_HEADER) {
  296. conf->header_timeout = initial;
  297. conf->header_max_timeout = max;
  298. conf->header_min_rate = rate;
  299. if (rate)
  300. conf->header_rate_factor = apr_time_from_sec(1) / rate;
  301. }
  302. else {
  303. conf->body_timeout = initial;
  304. conf->body_max_timeout = max;
  305. conf->body_min_rate = rate;
  306. if (rate)
  307. conf->body_rate_factor = apr_time_from_sec(1) / rate;
  308. }
  309. return ret;
  310. }
  311. static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig,
  312. const char *arg)
  313. {
  314. reqtimeout_srv_cfg *conf =
  315. ap_get_module_config(cmd->server->module_config,
  316. &reqtimeout_module);
  317. while (*arg) {
  318. char *word, *val;
  319. const char *err;
  320. word = ap_getword_conf(cmd->pool, &arg);
  321. val = strchr(word, '=');
  322. if (!val) {
  323. return "Invalid RequestReadTimeout parameter. Parameter must be "
  324. "in the form 'key=value'";
  325. }
  326. else
  327. *val++ = '\0';
  328. err = set_reqtimeout_param(conf, cmd->pool, word, val);
  329. if (err)
  330. return apr_psprintf(cmd->temp_pool, "RequestReadTimeout: %s=%s: %s",
  331. word, val, err);
  332. }
  333. return NULL;
  334. }
  335. static void reqtimeout_hooks(apr_pool_t *pool)
  336. {
  337. /*
  338. * mod_ssl is AP_FTYPE_CONNECTION + 5 and mod_reqtimeout needs to
  339. * be called before mod_ssl. Otherwise repeated reads during the ssl
  340. * handshake can prevent the timeout from triggering.
  341. */
  342. ap_register_input_filter(reqtimeout_filter_name, reqtimeout_filter, NULL,
  343. AP_FTYPE_CONNECTION + 8);
  344. ap_hook_pre_connection(reqtimeout_pre_conn, NULL, NULL, APR_HOOK_MIDDLE);
  345. ap_hook_post_read_request(reqtimeout_after_headers, NULL, NULL,
  346. APR_HOOK_MIDDLE);
  347. ap_hook_log_transaction(reqtimeout_after_body, NULL, NULL,
  348. APR_HOOK_MIDDLE);
  349. }
  350. static const command_rec reqtimeout_cmds[] = {
  351. AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF,
  352. "Set various timeout parameters for reading request "
  353. "headers and body"),
  354. {NULL}
  355. };
  356. module AP_MODULE_DECLARE_DATA reqtimeout_module = {
  357. STANDARD20_MODULE_STUFF,
  358. NULL, /* create per-dir config structures */
  359. NULL, /* merge per-dir config structures */
  360. reqtimeout_create_srv_config, /* create per-server config structures */
  361. reqtimeout_merge_srv_config, /* merge per-server config structures */
  362. reqtimeout_cmds, /* table of config file commands */
  363. reqtimeout_hooks
  364. };