mod_curltest.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include <assert.h>
  25. #include <apr_optional.h>
  26. #include <apr_optional_hooks.h>
  27. #include <apr_strings.h>
  28. #include <apr_cstr.h>
  29. #include <apr_time.h>
  30. #include <apr_want.h>
  31. #include <httpd.h>
  32. #include <http_protocol.h>
  33. #include <http_request.h>
  34. #include <http_log.h>
  35. static void curltest_hooks(apr_pool_t *pool);
  36. static int curltest_echo_handler(request_rec *r);
  37. static int curltest_put_handler(request_rec *r);
  38. static int curltest_tweak_handler(request_rec *r);
  39. static int curltest_1_1_required(request_rec *r);
  40. static int curltest_sslinfo_handler(request_rec *r);
  41. AP_DECLARE_MODULE(curltest) =
  42. {
  43. STANDARD20_MODULE_STUFF,
  44. NULL, /* func to create per dir config */
  45. NULL, /* func to merge per dir config */
  46. NULL, /* func to create per server config */
  47. NULL, /* func to merge per server config */
  48. NULL, /* command handlers */
  49. curltest_hooks,
  50. #if defined(AP_MODULE_FLAG_NONE)
  51. AP_MODULE_FLAG_ALWAYS_MERGE
  52. #endif
  53. };
  54. static int curltest_post_config(apr_pool_t *p, apr_pool_t *plog,
  55. apr_pool_t *ptemp, server_rec *s)
  56. {
  57. void *data = NULL;
  58. const char *key = "mod_curltest_init_counter";
  59. (void)plog;(void)ptemp;
  60. apr_pool_userdata_get(&data, key, s->process->pool);
  61. if(!data) {
  62. /* dry run */
  63. apr_pool_userdata_set((const void *)1, key,
  64. apr_pool_cleanup_null, s->process->pool);
  65. return APR_SUCCESS;
  66. }
  67. /* mess with the overall server here */
  68. return APR_SUCCESS;
  69. }
  70. static void curltest_hooks(apr_pool_t *pool)
  71. {
  72. ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks");
  73. /* Run once after configuration is set, but before mpm children initialize.
  74. */
  75. ap_hook_post_config(curltest_post_config, NULL, NULL, APR_HOOK_MIDDLE);
  76. /* curl test handlers */
  77. ap_hook_handler(curltest_echo_handler, NULL, NULL, APR_HOOK_MIDDLE);
  78. ap_hook_handler(curltest_put_handler, NULL, NULL, APR_HOOK_MIDDLE);
  79. ap_hook_handler(curltest_tweak_handler, NULL, NULL, APR_HOOK_MIDDLE);
  80. ap_hook_handler(curltest_1_1_required, NULL, NULL, APR_HOOK_MIDDLE);
  81. ap_hook_handler(curltest_sslinfo_handler, NULL, NULL, APR_HOOK_MIDDLE);
  82. }
  83. #define SECS_PER_HOUR (60*60)
  84. #define SECS_PER_DAY (24*SECS_PER_HOUR)
  85. static apr_status_t duration_parse(apr_interval_time_t *ptimeout,
  86. const char *value, const char *def_unit)
  87. {
  88. char *endp;
  89. apr_int64_t n;
  90. n = apr_strtoi64(value, &endp, 10);
  91. if(errno) {
  92. return errno;
  93. }
  94. if(!endp || !*endp) {
  95. if(!def_unit)
  96. def_unit = "s";
  97. }
  98. else if(endp == value) {
  99. return APR_EINVAL;
  100. }
  101. else {
  102. def_unit = endp;
  103. }
  104. switch(*def_unit) {
  105. case 'D':
  106. case 'd':
  107. *ptimeout = apr_time_from_sec(n * SECS_PER_DAY);
  108. break;
  109. case 's':
  110. case 'S':
  111. *ptimeout = (apr_interval_time_t) apr_time_from_sec(n);
  112. break;
  113. case 'h':
  114. case 'H':
  115. /* Time is in hours */
  116. *ptimeout = (apr_interval_time_t) apr_time_from_sec(n * SECS_PER_HOUR);
  117. break;
  118. case 'm':
  119. case 'M':
  120. switch(*(++def_unit)) {
  121. /* Time is in milliseconds */
  122. case 's':
  123. case 'S':
  124. *ptimeout = (apr_interval_time_t) n * 1000;
  125. break;
  126. /* Time is in minutes */
  127. case 'i':
  128. case 'I':
  129. *ptimeout = (apr_interval_time_t) apr_time_from_sec(n * 60);
  130. break;
  131. default:
  132. return APR_EGENERAL;
  133. }
  134. break;
  135. case 'u':
  136. case 'U':
  137. switch(*(++def_unit)) {
  138. /* Time is in microseconds */
  139. case 's':
  140. case 'S':
  141. *ptimeout = (apr_interval_time_t) n;
  142. break;
  143. default:
  144. return APR_EGENERAL;
  145. }
  146. break;
  147. default:
  148. return APR_EGENERAL;
  149. }
  150. return APR_SUCCESS;
  151. }
  152. static int status_from_str(const char *s, apr_status_t *pstatus)
  153. {
  154. if(!strcmp("timeout", s)) {
  155. *pstatus = APR_TIMEUP;
  156. return 1;
  157. }
  158. else if(!strcmp("reset", s)) {
  159. *pstatus = APR_ECONNRESET;
  160. return 1;
  161. }
  162. return 0;
  163. }
  164. static int curltest_echo_handler(request_rec *r)
  165. {
  166. conn_rec *c = r->connection;
  167. apr_bucket_brigade *bb;
  168. apr_bucket *b;
  169. apr_status_t rv;
  170. char buffer[8192];
  171. const char *ct;
  172. apr_off_t die_after_len = -1, total_read_len = 0;
  173. int just_die = 0, die_after_100 = 0;
  174. long l;
  175. if(strcmp(r->handler, "curltest-echo")) {
  176. return DECLINED;
  177. }
  178. if(r->method_number != M_GET && r->method_number != M_POST) {
  179. return DECLINED;
  180. }
  181. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "echo_handler: processing");
  182. if(r->args) {
  183. apr_array_header_t *args = NULL;
  184. int i;
  185. args = apr_cstr_split(r->args, "&", 1, r->pool);
  186. for(i = 0; i < args->nelts; ++i) {
  187. char *s, *val, *arg = APR_ARRAY_IDX(args, i, char *);
  188. s = strchr(arg, '=');
  189. if(s) {
  190. *s = '\0';
  191. val = s + 1;
  192. if(!strcmp("die_after", arg)) {
  193. die_after_len = (apr_off_t)apr_atoi64(val);
  194. continue;
  195. }
  196. else if(!strcmp("just_die", arg)) {
  197. just_die = 1;
  198. continue;
  199. }
  200. else if(!strcmp("die_after_100", arg)) {
  201. die_after_100 = 1;
  202. continue;
  203. }
  204. }
  205. }
  206. }
  207. if(just_die) {
  208. ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
  209. "echo_handler: dying right away");
  210. /* Generate no HTTP response at all. */
  211. ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
  212. r->connection->keepalive = AP_CONN_CLOSE;
  213. return AP_FILTER_ERROR;
  214. }
  215. r->status = 200;
  216. if(die_after_len >= 0) {
  217. r->clength = die_after_len + 1;
  218. r->chunked = 0;
  219. apr_table_set(r->headers_out, "Content-Length",
  220. apr_ltoa(r->pool, (long)r->clength));
  221. }
  222. else {
  223. r->clength = -1;
  224. r->chunked = 1;
  225. apr_table_unset(r->headers_out, "Content-Length");
  226. }
  227. /* Discourage content-encodings */
  228. apr_table_unset(r->headers_out, "Content-Encoding");
  229. apr_table_setn(r->subprocess_env, "no-brotli", "1");
  230. apr_table_setn(r->subprocess_env, "no-gzip", "1");
  231. ct = apr_table_get(r->headers_in, "content-type");
  232. ap_set_content_type(r, ct ? ct : "application/octet-stream");
  233. bb = apr_brigade_create(r->pool, c->bucket_alloc);
  234. /* copy any request body into the response */
  235. rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
  236. if(rv)
  237. goto cleanup;
  238. if(die_after_100) {
  239. ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
  240. "echo_handler: dying after 100-continue");
  241. /* Generate no HTTP response at all. */
  242. ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
  243. r->connection->keepalive = AP_CONN_CLOSE;
  244. return AP_FILTER_ERROR;
  245. }
  246. if(ap_should_client_block(r)) {
  247. while(0 < (l = ap_get_client_block(r, &buffer[0], sizeof(buffer)))) {
  248. total_read_len += l;
  249. if(die_after_len >= 0 && total_read_len >= die_after_len) {
  250. ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
  251. "echo_handler: dying after %ld bytes as requested",
  252. (long)total_read_len);
  253. ap_pass_brigade(r->output_filters, bb);
  254. ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
  255. r->connection->keepalive = AP_CONN_CLOSE;
  256. return DONE;
  257. }
  258. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
  259. "echo_handler: copying %ld bytes from request body", l);
  260. rv = apr_brigade_write(bb, NULL, NULL, buffer, l);
  261. if(APR_SUCCESS != rv)
  262. goto cleanup;
  263. rv = ap_pass_brigade(r->output_filters, bb);
  264. if(APR_SUCCESS != rv)
  265. goto cleanup;
  266. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
  267. "echo_handler: passed %ld bytes from request body", l);
  268. }
  269. }
  270. /* we are done */
  271. b = apr_bucket_eos_create(c->bucket_alloc);
  272. APR_BRIGADE_INSERT_TAIL(bb, b);
  273. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "echo_handler: request read");
  274. if(r->trailers_in && !apr_is_empty_table(r->trailers_in)) {
  275. ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
  276. "echo_handler: seeing incoming trailers");
  277. apr_table_setn(r->trailers_out, "h2test-trailers-in",
  278. apr_itoa(r->pool, 1));
  279. }
  280. rv = ap_pass_brigade(r->output_filters, bb);
  281. cleanup:
  282. if(rv == APR_SUCCESS ||
  283. r->status != HTTP_OK ||
  284. c->aborted) {
  285. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "echo_handler: done");
  286. return OK;
  287. }
  288. else {
  289. /* no way to know what type of error occurred */
  290. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "echo_handler failed");
  291. return AP_FILTER_ERROR;
  292. }
  293. return DECLINED;
  294. }
  295. static int curltest_tweak_handler(request_rec *r)
  296. {
  297. conn_rec *c = r->connection;
  298. apr_bucket_brigade *bb;
  299. apr_bucket *b;
  300. apr_status_t rv;
  301. char buffer[16*1024];
  302. int i, chunks = 3, error_bucket = 1;
  303. size_t chunk_size = sizeof(buffer);
  304. const char *request_id = "none";
  305. apr_time_t delay = 0, chunk_delay = 0, close_delay = 0;
  306. apr_array_header_t *args = NULL;
  307. int http_status = 200;
  308. apr_status_t error = APR_SUCCESS, body_error = APR_SUCCESS;
  309. int close_conn = 0, with_cl = 0;
  310. if(strcmp(r->handler, "curltest-tweak")) {
  311. return DECLINED;
  312. }
  313. if(r->method_number == M_DELETE) {
  314. http_status = 204;
  315. chunks = 0;
  316. }
  317. else if(r->method_number != M_GET && r->method_number != M_POST) {
  318. return DECLINED;
  319. }
  320. if(r->args) {
  321. args = apr_cstr_split(r->args, "&", 1, r->pool);
  322. for(i = 0; i < args->nelts; ++i) {
  323. char *s, *val, *arg = APR_ARRAY_IDX(args, i, char *);
  324. s = strchr(arg, '=');
  325. if(s) {
  326. *s = '\0';
  327. val = s + 1;
  328. if(!strcmp("status", arg)) {
  329. http_status = (int)apr_atoi64(val);
  330. if(http_status > 0) {
  331. continue;
  332. }
  333. }
  334. else if(!strcmp("chunks", arg)) {
  335. chunks = (int)apr_atoi64(val);
  336. if(chunks >= 0) {
  337. continue;
  338. }
  339. }
  340. else if(!strcmp("chunk_size", arg)) {
  341. chunk_size = (int)apr_atoi64(val);
  342. if(chunk_size >= 0) {
  343. if(chunk_size > sizeof(buffer)) {
  344. ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  345. "chunk_size %zu too large", chunk_size);
  346. ap_die(HTTP_BAD_REQUEST, r);
  347. return OK;
  348. }
  349. continue;
  350. }
  351. }
  352. else if(!strcmp("id", arg)) {
  353. /* just an id for repeated requests with curl's url globbing */
  354. request_id = val;
  355. continue;
  356. }
  357. else if(!strcmp("error", arg)) {
  358. if(status_from_str(val, &error)) {
  359. continue;
  360. }
  361. }
  362. else if(!strcmp("error_bucket", arg)) {
  363. error_bucket = (int)apr_atoi64(val);
  364. if(error_bucket >= 0) {
  365. continue;
  366. }
  367. }
  368. else if(!strcmp("body_error", arg)) {
  369. if(status_from_str(val, &body_error)) {
  370. continue;
  371. }
  372. }
  373. else if(!strcmp("delay", arg)) {
  374. rv = duration_parse(&delay, val, "s");
  375. if(APR_SUCCESS == rv) {
  376. continue;
  377. }
  378. }
  379. else if(!strcmp("chunk_delay", arg)) {
  380. rv = duration_parse(&chunk_delay, val, "s");
  381. if(APR_SUCCESS == rv) {
  382. continue;
  383. }
  384. }
  385. else if(!strcmp("close_delay", arg)) {
  386. rv = duration_parse(&close_delay, val, "s");
  387. if(APR_SUCCESS == rv) {
  388. continue;
  389. }
  390. }
  391. }
  392. else if(!strcmp("close", arg)) {
  393. /* we are asked to close the connection */
  394. close_conn = 1;
  395. continue;
  396. }
  397. else if(!strcmp("with_cl", arg)) {
  398. with_cl = 1;
  399. continue;
  400. }
  401. ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "query parameter not "
  402. "understood: '%s' in %s",
  403. arg, r->args);
  404. ap_die(HTTP_BAD_REQUEST, r);
  405. return OK;
  406. }
  407. }
  408. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "error_handler: processing "
  409. "request, %s", r->args? r->args : "(no args)");
  410. r->status = http_status;
  411. r->clength = with_cl ? (chunks * chunk_size) : -1;
  412. r->chunked = (r->proto_num >= HTTP_VERSION(1, 1)) && !with_cl;
  413. apr_table_setn(r->headers_out, "request-id", request_id);
  414. if(r->clength >= 0) {
  415. apr_table_set(r->headers_out, "Content-Length",
  416. apr_ltoa(r->pool, (long)r->clength));
  417. }
  418. else
  419. apr_table_unset(r->headers_out, "Content-Length");
  420. /* Discourage content-encodings */
  421. apr_table_unset(r->headers_out, "Content-Encoding");
  422. apr_table_setn(r->subprocess_env, "no-brotli", "1");
  423. apr_table_setn(r->subprocess_env, "no-gzip", "1");
  424. ap_set_content_type(r, "application/octet-stream");
  425. bb = apr_brigade_create(r->pool, c->bucket_alloc);
  426. if(delay) {
  427. apr_sleep(delay);
  428. }
  429. if(error != APR_SUCCESS) {
  430. return ap_map_http_request_error(error, HTTP_BAD_REQUEST);
  431. }
  432. /* flush response */
  433. b = apr_bucket_flush_create(c->bucket_alloc);
  434. APR_BRIGADE_INSERT_TAIL(bb, b);
  435. rv = ap_pass_brigade(r->output_filters, bb);
  436. if(APR_SUCCESS != rv)
  437. goto cleanup;
  438. memset(buffer, 'X', sizeof(buffer));
  439. for(i = 0; i < chunks; ++i) {
  440. if(chunk_delay) {
  441. apr_sleep(chunk_delay);
  442. }
  443. rv = apr_brigade_write(bb, NULL, NULL, buffer, chunk_size);
  444. if(APR_SUCCESS != rv)
  445. goto cleanup;
  446. rv = ap_pass_brigade(r->output_filters, bb);
  447. if(APR_SUCCESS != rv)
  448. goto cleanup;
  449. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
  450. "error_handler: passed %lu bytes as response body",
  451. (unsigned long)chunk_size);
  452. if(body_error != APR_SUCCESS) {
  453. rv = body_error;
  454. goto cleanup;
  455. }
  456. }
  457. /* we are done */
  458. b = apr_bucket_eos_create(c->bucket_alloc);
  459. APR_BRIGADE_INSERT_TAIL(bb, b);
  460. rv = ap_pass_brigade(r->output_filters, bb);
  461. apr_brigade_cleanup(bb);
  462. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r,
  463. "error_handler: response passed");
  464. cleanup:
  465. if(close_conn) {
  466. if(close_delay) {
  467. b = apr_bucket_flush_create(c->bucket_alloc);
  468. APR_BRIGADE_INSERT_TAIL(bb, b);
  469. rv = ap_pass_brigade(r->output_filters, bb);
  470. apr_brigade_cleanup(bb);
  471. apr_sleep(close_delay);
  472. }
  473. r->connection->keepalive = AP_CONN_CLOSE;
  474. }
  475. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r,
  476. "error_handler: request cleanup, r->status=%d, aborted=%d, "
  477. "close=%d", r->status, c->aborted, close_conn);
  478. if(rv == APR_SUCCESS) {
  479. return OK;
  480. }
  481. if(error_bucket) {
  482. http_status = ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
  483. b = ap_bucket_error_create(http_status, NULL, r->pool, c->bucket_alloc);
  484. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r,
  485. "error_handler: passing error bucket, status=%d",
  486. http_status);
  487. APR_BRIGADE_INSERT_TAIL(bb, b);
  488. ap_pass_brigade(r->output_filters, bb);
  489. }
  490. return AP_FILTER_ERROR;
  491. }
  492. static int curltest_put_handler(request_rec *r)
  493. {
  494. conn_rec *c = r->connection;
  495. apr_bucket_brigade *bb;
  496. apr_bucket *b;
  497. apr_status_t rv;
  498. char buffer[128*1024];
  499. const char *ct;
  500. apr_off_t rbody_len = 0;
  501. apr_off_t rbody_max_len = -1;
  502. const char *s_rbody_len;
  503. const char *request_id = "none";
  504. apr_time_t read_delay = 0, chunk_delay = 0;
  505. apr_array_header_t *args = NULL;
  506. long l;
  507. int i;
  508. if(strcmp(r->handler, "curltest-put")) {
  509. return DECLINED;
  510. }
  511. if(r->method_number != M_PUT) {
  512. return DECLINED;
  513. }
  514. if(r->args) {
  515. args = apr_cstr_split(r->args, "&", 1, r->pool);
  516. for(i = 0; i < args->nelts; ++i) {
  517. char *s, *val, *arg = APR_ARRAY_IDX(args, i, char *);
  518. s = strchr(arg, '=');
  519. if(s) {
  520. *s = '\0';
  521. val = s + 1;
  522. if(!strcmp("id", arg)) {
  523. /* just an id for repeated requests with curl's url globbing */
  524. request_id = val;
  525. continue;
  526. }
  527. else if(!strcmp("read_delay", arg)) {
  528. rv = duration_parse(&read_delay, val, "s");
  529. if(APR_SUCCESS == rv) {
  530. continue;
  531. }
  532. }
  533. else if(!strcmp("chunk_delay", arg)) {
  534. rv = duration_parse(&chunk_delay, val, "s");
  535. if(APR_SUCCESS == rv) {
  536. continue;
  537. }
  538. }
  539. else if(!strcmp("max_upload", arg)) {
  540. rbody_max_len = (int)apr_atoi64(val);
  541. continue;
  542. }
  543. }
  544. ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "query parameter not "
  545. "understood: '%s' in %s",
  546. arg, r->args);
  547. ap_die(HTTP_BAD_REQUEST, r);
  548. return OK;
  549. }
  550. }
  551. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "put_handler: processing");
  552. r->status = 200;
  553. r->clength = -1;
  554. r->chunked = 1;
  555. apr_table_unset(r->headers_out, "Content-Length");
  556. /* Discourage content-encodings */
  557. apr_table_unset(r->headers_out, "Content-Encoding");
  558. apr_table_setn(r->subprocess_env, "no-brotli", "1");
  559. apr_table_setn(r->subprocess_env, "no-gzip", "1");
  560. ct = apr_table_get(r->headers_in, "content-type");
  561. ap_set_content_type(r, ct ? ct : "text/plain");
  562. if(read_delay) {
  563. apr_sleep(read_delay);
  564. }
  565. bb = apr_brigade_create(r->pool, c->bucket_alloc);
  566. /* copy any request body into the response */
  567. rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
  568. if(rv)
  569. goto cleanup;
  570. if(ap_should_client_block(r)) {
  571. while(0 < (l = ap_get_client_block(r, &buffer[0], sizeof(buffer)))) {
  572. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
  573. "put_handler: read %ld bytes from request body", l);
  574. if(chunk_delay) {
  575. apr_sleep(chunk_delay);
  576. }
  577. rbody_len += l;
  578. if((rbody_max_len > 0) && (rbody_len > rbody_max_len)) {
  579. r->status = 413;
  580. break;
  581. }
  582. }
  583. }
  584. /* we are done */
  585. s_rbody_len = apr_psprintf(r->pool, "%"APR_OFF_T_FMT, rbody_len);
  586. apr_table_setn(r->headers_out, "Received-Length", s_rbody_len);
  587. rv = apr_brigade_puts(bb, NULL, NULL, s_rbody_len);
  588. if(APR_SUCCESS != rv)
  589. goto cleanup;
  590. b = apr_bucket_eos_create(c->bucket_alloc);
  591. APR_BRIGADE_INSERT_TAIL(bb, b);
  592. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "put_handler: request read");
  593. rv = ap_pass_brigade(r->output_filters, bb);
  594. if(r->status == 413) {
  595. apr_sleep(apr_time_from_sec(1));
  596. }
  597. cleanup:
  598. if(rv == APR_SUCCESS
  599. || r->status != HTTP_OK
  600. || c->aborted) {
  601. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "put_handler: done");
  602. return OK;
  603. }
  604. else {
  605. /* no way to know what type of error occurred */
  606. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "put_handler failed");
  607. return AP_FILTER_ERROR;
  608. }
  609. return DECLINED;
  610. }
  611. static int curltest_1_1_required(request_rec *r)
  612. {
  613. conn_rec *c = r->connection;
  614. apr_bucket_brigade *bb;
  615. apr_bucket *b;
  616. apr_status_t rv;
  617. char buffer[16*1024];
  618. const char *ct;
  619. const char *request_id = "none";
  620. apr_time_t chunk_delay = 0;
  621. apr_array_header_t *args = NULL;
  622. long l;
  623. int i;
  624. if(strcmp(r->handler, "curltest-1_1-required")) {
  625. return DECLINED;
  626. }
  627. if(HTTP_VERSION_MAJOR(r->proto_num) > 1) {
  628. apr_table_setn(r->notes, "ssl-renegotiate-forbidden", "1");
  629. ap_die(HTTP_FORBIDDEN, r);
  630. return OK;
  631. }
  632. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "1_1_handler: processing");
  633. r->status = 200;
  634. r->clength = -1;
  635. r->chunked = 1;
  636. apr_table_unset(r->headers_out, "Content-Length");
  637. /* Discourage content-encodings */
  638. apr_table_unset(r->headers_out, "Content-Encoding");
  639. apr_table_setn(r->subprocess_env, "no-brotli", "1");
  640. apr_table_setn(r->subprocess_env, "no-gzip", "1");
  641. ct = apr_table_get(r->headers_in, "content-type");
  642. ap_set_content_type(r, ct ? ct : "text/plain");
  643. bb = apr_brigade_create(r->pool, c->bucket_alloc);
  644. /* flush response */
  645. b = apr_bucket_flush_create(c->bucket_alloc);
  646. APR_BRIGADE_INSERT_TAIL(bb, b);
  647. rv = ap_pass_brigade(r->output_filters, bb);
  648. if(APR_SUCCESS != rv)
  649. goto cleanup;
  650. /* we are done */
  651. rv = apr_brigade_printf(bb, NULL, NULL, "well done!");
  652. if(APR_SUCCESS != rv)
  653. goto cleanup;
  654. b = apr_bucket_eos_create(c->bucket_alloc);
  655. APR_BRIGADE_INSERT_TAIL(bb, b);
  656. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "1_1_handler: request read");
  657. rv = ap_pass_brigade(r->output_filters, bb);
  658. cleanup:
  659. if(rv == APR_SUCCESS
  660. || r->status != HTTP_OK
  661. || c->aborted) {
  662. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "1_1_handler: done");
  663. return OK;
  664. }
  665. else {
  666. /* no way to know what type of error occurred */
  667. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "1_1_handler failed");
  668. return AP_FILTER_ERROR;
  669. }
  670. return DECLINED;
  671. }
  672. static int brigade_env_var(request_rec *r, apr_bucket_brigade *bb,
  673. const char *name)
  674. {
  675. const char *s;
  676. s = apr_table_get(r->subprocess_env, name);
  677. if(s)
  678. return apr_brigade_printf(bb, NULL, NULL, ",\n \"%s\": \"%s\"", name, s);
  679. return 0;
  680. }
  681. static int curltest_sslinfo_handler(request_rec *r)
  682. {
  683. conn_rec *c = r->connection;
  684. apr_bucket_brigade *bb;
  685. apr_bucket *b;
  686. apr_status_t rv;
  687. apr_array_header_t *args = NULL;
  688. const char *request_id = NULL;
  689. int close_conn = 0;
  690. long l;
  691. int i;
  692. if(strcmp(r->handler, "curltest-sslinfo")) {
  693. return DECLINED;
  694. }
  695. if(r->method_number != M_GET) {
  696. return DECLINED;
  697. }
  698. if(r->args) {
  699. apr_array_header_t *args = apr_cstr_split(r->args, "&", 1, r->pool);
  700. for(i = 0; i < args->nelts; ++i) {
  701. char *s, *val, *arg = APR_ARRAY_IDX(args, i, char *);
  702. s = strchr(arg, '=');
  703. if(s) {
  704. *s = '\0';
  705. val = s + 1;
  706. if(!strcmp("id", arg)) {
  707. /* just an id for repeated requests with curl's url globbing */
  708. request_id = val;
  709. continue;
  710. }
  711. }
  712. else if(!strcmp("close", arg)) {
  713. /* we are asked to close the connection */
  714. close_conn = 1;
  715. continue;
  716. }
  717. ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "query parameter not "
  718. "understood: '%s' in %s",
  719. arg, r->args);
  720. ap_die(HTTP_BAD_REQUEST, r);
  721. return OK;
  722. }
  723. }
  724. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "sslinfo: processing");
  725. r->status = 200;
  726. r->clength = -1;
  727. r->chunked = 1;
  728. apr_table_unset(r->headers_out, "Content-Length");
  729. /* Discourage content-encodings */
  730. apr_table_unset(r->headers_out, "Content-Encoding");
  731. apr_table_setn(r->subprocess_env, "no-brotli", "1");
  732. apr_table_setn(r->subprocess_env, "no-gzip", "1");
  733. ap_set_content_type(r, "application/json");
  734. bb = apr_brigade_create(r->pool, c->bucket_alloc);
  735. apr_brigade_puts(bb, NULL, NULL, "{\n \"Name\": \"SSL-Information\"");
  736. brigade_env_var(r, bb, "HTTPS");
  737. brigade_env_var(r, bb, "SSL_PROTOCOL");
  738. brigade_env_var(r, bb, "SSL_CIPHER");
  739. brigade_env_var(r, bb, "SSL_SESSION_ID");
  740. brigade_env_var(r, bb, "SSL_SESSION_RESUMED");
  741. brigade_env_var(r, bb, "SSL_SRP_USER");
  742. brigade_env_var(r, bb, "SSL_SRP_USERINFO");
  743. brigade_env_var(r, bb, "SSL_TLS_SNI");
  744. apr_brigade_puts(bb, NULL, NULL, "}\n");
  745. /* flush response */
  746. b = apr_bucket_flush_create(c->bucket_alloc);
  747. APR_BRIGADE_INSERT_TAIL(bb, b);
  748. rv = ap_pass_brigade(r->output_filters, bb);
  749. if(APR_SUCCESS != rv)
  750. goto cleanup;
  751. /* we are done */
  752. b = apr_bucket_eos_create(c->bucket_alloc);
  753. APR_BRIGADE_INSERT_TAIL(bb, b);
  754. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "1_1_handler: request read");
  755. rv = ap_pass_brigade(r->output_filters, bb);
  756. cleanup:
  757. if(close_conn)
  758. r->connection->keepalive = AP_CONN_CLOSE;
  759. if(rv == APR_SUCCESS
  760. || r->status != HTTP_OK
  761. || c->aborted) {
  762. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "1_1_handler: done");
  763. return OK;
  764. }
  765. else {
  766. /* no way to know what type of error occurred */
  767. ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "1_1_handler failed");
  768. return AP_FILTER_ERROR;
  769. }
  770. return DECLINED;
  771. }