mod_curltest.c 24 KB

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