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