1 /*
2 * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved.
3 * Copyright Siemens AG 2020
4 *
5 * Licensed under the Apache License 2.0 (the "License"). You may not use
6 * this file except in compliance with the License. You can obtain a copy
7 * in the file LICENSE in the source distribution or at
8 * https://www.openssl.org/source/license.html
9 */
10
11 #include <openssl/http.h>
12 #include <openssl/pem.h>
13 #include <openssl/x509v3.h>
14 #include <openssl/err.h>
15 #include <string.h>
16
17 #include "testutil.h"
18
19 #define HTTP_STATUS_CODE_OK 200
20 #define HTTP_STATUS_CODES_FATAL_ERROR 399
21 #define HTTP_STATUS_CODES_NONFATAL_ERROR 400
22
23 static const ASN1_ITEM *x509_it = NULL;
24 static X509 *x509 = NULL;
25 #define RPATH "/path"
26
27 typedef struct {
28 BIO *out;
29 const char *content_type;
30 const char *txt;
31 char version;
32 int keep_alive;
33 } server_args;
34
35 /*-
36 * Pretty trivial HTTP mock server:
37 * For POST, copy request headers+body from mem BIO |in| as response to |out|.
38 * For GET, redirect to RPATH unless already there, else use |content_type| and
39 * respond with |txt| if not NULL, else with |rsp| of ASN1 type |it|.
40 * Take the status code suggsted by the client via special prefix of the path.
41 * On fatal status, respond with empty content.
42 * Response hdr has HTTP version 1.|version| and |keep_alive| (unless implicit).
43 */
mock_http_server(BIO * in,BIO * out,char version,int keep_alive,const char * content_type,const char * txt,ASN1_VALUE * rsp,const ASN1_ITEM * it)44 static int mock_http_server(BIO *in, BIO *out, char version, int keep_alive,
45 const char *content_type, const char *txt,
46 ASN1_VALUE *rsp, const ASN1_ITEM *it)
47 {
48 const char *req, *path;
49 long count = BIO_get_mem_data(in, (unsigned char **)&req);
50 const char *hdr = (char *)req, *suggested_status;
51 char status[4] = "200";
52 int len;
53 int is_get = count >= 4 && CHECK_AND_SKIP_PREFIX(hdr, "GET ");
54
55 /* first line should contain "(GET|POST) (/<suggested status>)?/<path> HTTP/1.x" */
56 if (!is_get
57 && !(TEST_true(count >= 5 && CHECK_AND_SKIP_PREFIX(hdr, "POST "))))
58 return 0;
59
60 /* get any status code string to be returned suggested by test client */
61 if (*hdr == '/') {
62 suggested_status = ++hdr;
63 while (*hdr >= '0' && *hdr <= '9')
64 hdr++;
65 if (hdr == suggested_status + sizeof(status) - 1)
66 strncpy(status, suggested_status, sizeof(status) - 1);
67 else
68 hdr = suggested_status - 1;
69 }
70
71 path = hdr;
72 hdr = strchr(hdr, ' ');
73 if (hdr == NULL)
74 return 0;
75 len = strlen("HTTP/1.");
76 if (!TEST_strn_eq(++hdr, "HTTP/1.", len))
77 return 0;
78 hdr += len;
79 /* check for HTTP version 1.0 .. 1.1 */
80 if (!TEST_char_le('0', *hdr) || !TEST_char_le(*hdr++, '1'))
81 return 0;
82 if (!TEST_char_eq(*hdr++, '\r') || !TEST_char_eq(*hdr++, '\n'))
83 return 0;
84
85 count -= (hdr - req);
86 if (count < 0 || out == NULL)
87 return 0;
88
89 if (!HAS_PREFIX(path, RPATH)) {
90 if (!is_get)
91 return 0;
92 return BIO_printf(out, "HTTP/1.%c 301 Moved Permanently\r\n"
93 "Location: %s\r\n\r\n",
94 version, RPATH)
95 > 0; /* same server */
96 }
97 if (BIO_printf(out, "HTTP/1.%c %s %s\r\n", version, status,
98 /* mock some reason string: */
99 strcmp(status, "200") == 0 ? "OK" : strcmp(status, "400") >= 0 ? "error"
100 : "fatal")
101 <= 0)
102 return 0;
103 if ((version == '0') == keep_alive) /* otherwise, default */
104 if (BIO_printf(out, "Connection: %s\r\n",
105 version == '0' ? "keep-alive" : "close")
106 <= 0)
107 return 0;
108
109 if (strcmp(status, "399") == 0) /* HTTP_STATUS_CODES_FATAL_ERROR */
110 return BIO_puts(out, "\r\n") == 2; /* empty content */
111
112 if (is_get) { /* construct new header and body */
113 if (txt != NULL)
114 len = strlen(txt);
115 else if ((len = ASN1_item_i2d(rsp, NULL, it)) <= 0)
116 return 0;
117 if (BIO_printf(out, "Content-Type: %s\r\n"
118 "Content-Length: %d\r\n\r\n",
119 content_type, len)
120 <= 0)
121 return 0;
122 if (txt != NULL)
123 return BIO_puts(out, txt);
124 return ASN1_item_i2d_bio(it, out, rsp);
125 } else { /* respond on POST request */
126 if (CHECK_AND_SKIP_PREFIX(hdr, "Connection: ")) {
127 /* skip req Connection header */
128 hdr = strstr(hdr, "\r\n");
129 if (hdr == NULL)
130 return 0;
131 hdr += 2;
132 }
133 /* echo remaining request header and body */
134 return BIO_write(out, hdr, count) == count;
135 }
136 }
137
http_bio_cb_ex(BIO * bio,int oper,const char * argp,size_t len,int cmd,long argl,int ret,size_t * processed)138 static long http_bio_cb_ex(BIO *bio, int oper, const char *argp, size_t len,
139 int cmd, long argl, int ret, size_t *processed)
140 {
141 server_args *args = (server_args *)BIO_get_callback_arg(bio);
142
143 if (oper == (BIO_CB_CTRL | BIO_CB_RETURN) && cmd == BIO_CTRL_FLUSH)
144 ret = mock_http_server(bio, args->out, args->version, args->keep_alive,
145 args->content_type, args->txt,
146 (ASN1_VALUE *)x509, x509_it);
147 return ret;
148 }
149
150 #define text1 "test\n"
151 #define text2 "more\n"
152 #define REAL_SERVER_URL "http://httpbin.org/"
153 #define DOCTYPE_HTML "<!DOCTYPE html>\n"
154
155 /* do_get > 1 used for testing redirection */
test_http_method(int do_get,int do_txt,int suggested_status)156 static int test_http_method(int do_get, int do_txt, int suggested_status)
157 {
158 BIO *wbio = BIO_new(BIO_s_mem());
159 BIO *rbio = BIO_new(BIO_s_mem());
160 server_args mock_args = { NULL, NULL, NULL, '0', 0 };
161 BIO *req, *rsp;
162 char path[80];
163 STACK_OF(CONF_VALUE) *headers = NULL;
164 const char *content_type;
165 int res = 0;
166 int real_server = do_txt && 0; /* remove "&& 0" for using real server */
167
168 BIO_snprintf(path, sizeof(path), "/%d%s", suggested_status,
169 do_get > 1 ? "/will-be-redirected" : RPATH);
170 if (do_txt) {
171 content_type = "text/plain";
172 req = BIO_new(BIO_s_mem());
173 if (req == NULL
174 || BIO_puts(req, text1) != sizeof(text1) - 1
175 || BIO_puts(req, text2) != sizeof(text2) - 1) {
176 BIO_free(req);
177 req = NULL;
178 }
179 mock_args.txt = text1;
180 } else {
181 content_type = "application/x-x509-ca-cert";
182 req = ASN1_item_i2d_mem_bio(x509_it, (ASN1_VALUE *)x509);
183 mock_args.txt = NULL;
184 }
185 if (wbio == NULL || rbio == NULL || req == NULL)
186 goto err;
187
188 mock_args.out = rbio;
189 mock_args.content_type = content_type;
190 BIO_set_callback_ex(wbio, http_bio_cb_ex);
191 BIO_set_callback_arg(wbio, (char *)&mock_args);
192
193 rsp = do_get ? OSSL_HTTP_get(real_server ? REAL_SERVER_URL : path,
194 NULL /* proxy */, NULL /* no_proxy */,
195 real_server ? NULL : wbio,
196 real_server ? NULL : rbio,
197 NULL /* bio_update_fn */, NULL /* arg */,
198 0 /* buf_size */, headers,
199 real_server ? "text/html; charset=utf-8" : content_type,
200 !do_txt /* expect_asn1 */,
201 OSSL_HTTP_DEFAULT_MAX_RESP_LEN, 0 /* timeout */)
202 : OSSL_HTTP_transfer(NULL, NULL /* host */, NULL /* port */, path,
203 0 /* use_ssl */, NULL /* proxy */, NULL /* no_pr */,
204 wbio, rbio, NULL /* bio_fn */, NULL /* arg */,
205 0 /* buf_size */, headers, content_type,
206 req, content_type, !do_txt /* expect_asn1 */,
207 OSSL_HTTP_DEFAULT_MAX_RESP_LEN, 0 /* timeout */,
208 0 /* keep_alive */);
209 if (!TEST_int_eq(suggested_status == HTTP_STATUS_CODES_FATAL_ERROR, rsp == NULL))
210 goto err;
211 if (suggested_status == HTTP_STATUS_CODES_FATAL_ERROR)
212 res = 1;
213 if (rsp != NULL) {
214 if (do_get && real_server) {
215 char rtext[sizeof(DOCTYPE_HTML)];
216
217 res = TEST_int_eq(BIO_gets(rsp, rtext, sizeof(rtext)),
218 sizeof(DOCTYPE_HTML) - 1)
219 && TEST_str_eq(rtext, DOCTYPE_HTML);
220 } else if (do_txt) {
221 char rtext[sizeof(text1) + 1 /* more space than needed */];
222
223 res = TEST_int_eq(BIO_gets(rsp, rtext, sizeof(rtext)),
224 sizeof(text1) - 1)
225 && TEST_str_eq(rtext, text1);
226 } else {
227 X509 *rcert = d2i_X509_bio(rsp, NULL);
228
229 res = TEST_ptr(rcert) && TEST_int_eq(X509_cmp(x509, rcert), 0);
230 X509_free(rcert);
231 }
232 BIO_free(rsp);
233 }
234
235 err:
236 BIO_free(req);
237 BIO_free(wbio);
238 BIO_free(rbio);
239 sk_CONF_VALUE_pop_free(headers, X509V3_conf_free);
240 return res;
241 }
242
test_http_keep_alive(char version,int keep_alive,int kept_alive)243 static int test_http_keep_alive(char version, int keep_alive, int kept_alive)
244 {
245 BIO *wbio = BIO_new(BIO_s_mem());
246 BIO *rbio = BIO_new(BIO_s_mem());
247 BIO *rsp;
248 const char *const content_type = "application/x-x509-ca-cert";
249 server_args mock_args = { NULL, NULL, NULL, '0', 0 };
250 OSSL_HTTP_REQ_CTX *rctx = NULL;
251 int i, res = 0;
252
253 if (wbio == NULL || rbio == NULL)
254 goto err;
255 mock_args.out = rbio;
256 mock_args.content_type = content_type;
257 mock_args.version = version;
258 mock_args.keep_alive = kept_alive;
259 BIO_set_callback_ex(wbio, http_bio_cb_ex);
260 BIO_set_callback_arg(wbio, (char *)&mock_args);
261
262 for (res = 1, i = 1; res && i <= 2; i++) {
263 rsp = OSSL_HTTP_transfer(&rctx, NULL /* server */, NULL /* port */,
264 RPATH, 0 /* use_ssl */,
265 NULL /* proxy */, NULL /* no_proxy */,
266 wbio, rbio, NULL /* bio_update_fn */, NULL,
267 0 /* buf_size */, NULL /* headers */,
268 NULL /* content_type */, NULL /* req => GET */,
269 content_type, 0 /* ASN.1 not expected */,
270 0 /* max_resp_len */, 0 /* timeout */,
271 keep_alive);
272 if (keep_alive == 2 && kept_alive == 0)
273 res = res && TEST_ptr_null(rsp)
274 && TEST_int_eq(OSSL_HTTP_is_alive(rctx), 0);
275 else
276 res = res && TEST_ptr(rsp)
277 && TEST_int_eq(OSSL_HTTP_is_alive(rctx), keep_alive > 0);
278 BIO_free(rsp);
279 (void)BIO_reset(rbio); /* discard response contents */
280 keep_alive = 0;
281 }
282 OSSL_HTTP_close(rctx, res);
283
284 err:
285 BIO_free(wbio);
286 BIO_free(rbio);
287 return res;
288 }
289
test_http_url_frag_ok(const char * url,int exp_ssl,const char * exp_host,const char * exp_port,const char * exp_path,const char * exp_frag)290 static int test_http_url_frag_ok(const char *url, int exp_ssl, const char *exp_host,
291 const char *exp_port, const char *exp_path, const char *exp_frag)
292 {
293 char *user, *host, *port, *path, *query, *frag;
294 int exp_num, num, ssl;
295 int res;
296
297 if (!TEST_int_eq(sscanf(exp_port, "%d", &exp_num), 1))
298 return 0;
299 res = TEST_true(OSSL_HTTP_parse_url(url, &ssl, &user, &host, &port, &num,
300 &path, &query, &frag))
301 && TEST_str_eq(host, exp_host)
302 && TEST_str_eq(port, exp_port)
303 && TEST_int_eq(num, exp_num)
304 && TEST_str_eq(path, exp_path)
305 && TEST_int_eq(ssl, exp_ssl);
306 if (res && *user != '\0')
307 res = TEST_str_eq(user, "user:pass");
308 if (res)
309 res = TEST_str_eq(frag, exp_frag);
310 if (res && *query != '\0')
311 res = TEST_str_eq(query, "q");
312 OPENSSL_free(user);
313 OPENSSL_free(host);
314 OPENSSL_free(port);
315 OPENSSL_free(path);
316 OPENSSL_free(query);
317 OPENSSL_free(frag);
318 return res;
319 }
320
test_http_url_ok(const char * url,int exp_ssl,const char * exp_host,const char * exp_port,const char * exp_path)321 static int test_http_url_ok(const char *url, int exp_ssl, const char *exp_host,
322 const char *exp_port, const char *exp_path)
323 {
324 return test_http_url_frag_ok(url, exp_ssl, exp_host, exp_port, exp_path, "");
325 }
326
test_http_url_path_query_ok(const char * url,const char * exp_path_qu)327 static int test_http_url_path_query_ok(const char *url, const char *exp_path_qu)
328 {
329 char *host, *path;
330 int res;
331
332 res = TEST_true(OSSL_HTTP_parse_url(url, NULL, NULL, &host, NULL, NULL,
333 &path, NULL, NULL))
334 && TEST_str_eq(host, "host")
335 && TEST_str_eq(path, exp_path_qu);
336 OPENSSL_free(host);
337 OPENSSL_free(path);
338 return res;
339 }
340
test_http_url_host_ok(const char * url,const char * exp_host)341 static int test_http_url_host_ok(const char *url, const char *exp_host)
342 {
343 char *host;
344 int res;
345
346 res = TEST_true(OSSL_HTTP_parse_url(url, NULL, NULL, &host, NULL, NULL,
347 NULL, NULL, NULL))
348 && TEST_str_eq(host, exp_host);
349 OPENSSL_free(host);
350 return res;
351 }
352
test_http_url_dns(void)353 static int test_http_url_dns(void)
354 {
355 return test_http_url_ok("host:65535/path", 0, "host", "65535", "/path");
356 }
357
test_http_url_ip(void)358 static int test_http_url_ip(void)
359 {
360 return test_http_url_ok("1.2.3.4:5678//blahblablah", 0, "1.2.3.4", "5678", "//blahblablah");
361 }
362
test_http_url_timestamp(void)363 static int test_http_url_timestamp(void)
364 {
365 return test_http_url_ok("host/p/2017-01-03T00:00:00", 0, "host", "80",
366 "/p/2017-01-03T00:00:00")
367 && test_http_url_ok("http://host/p/2017-01-03T00:00:00", 0, "host",
368 "80", "/p/2017-01-03T00:00:00")
369 && test_http_url_ok("https://host/p/2017-01-03T00:00:00", 1, "host",
370 "443", "/p/2017-01-03T00:00:00");
371 }
372
test_http_url_path_query(void)373 static int test_http_url_path_query(void)
374 {
375 return test_http_url_path_query_ok("http://usr@host:1/p?q=x#frag", "/p?q=x")
376 && test_http_url_path_query_ok("http://host?query#frag", "/?query")
377 && test_http_url_path_query_ok("http://host:9999#frag", "/");
378 }
379
test_http_url_userinfo_query_fragment(void)380 static int test_http_url_userinfo_query_fragment(void)
381 {
382 return test_http_url_frag_ok("user:pass@host/p?q#fr", 0, "host", "80", "/p", "fr")
383 && test_http_url_frag_ok("host.example.org/some/path#://not-a-scheme/not.a.host:404", 0,
384 "host.example.org", "80", "/some/path", "://not-a-scheme/not.a.host:404");
385 }
386
test_http_url_at_sign_outside_authority(void)387 static int test_http_url_at_sign_outside_authority(void)
388 {
389 return test_http_url_host_ok("http://host/p@attacker.test", "host")
390 && test_http_url_host_ok("http://host/p?q=@attacker.test", "host")
391 && test_http_url_host_ok("http://host/p?q#fr@attacker.test", "host");
392 }
393
test_http_url_ipv4(void)394 static int test_http_url_ipv4(void)
395 {
396 return test_http_url_ok("https://1.2.3.4/p/q", 1, "1.2.3.4", "443", "/p/q");
397 }
398
test_http_url_ipv6(void)399 static int test_http_url_ipv6(void)
400 {
401 return test_http_url_ok("http://[FF01::101]:6", 0, "[FF01::101]", "6", "/");
402 }
403
test_http_url_invalid(const char * url)404 static int test_http_url_invalid(const char *url)
405 {
406 char *host = "1", *port = "1", *path = "1";
407 int num = 1, ssl = 1;
408 int res;
409
410 res = TEST_false(OSSL_HTTP_parse_url(url, &ssl, NULL, &host, &port, &num,
411 &path, NULL, NULL))
412 && TEST_ptr_null(host)
413 && TEST_ptr_null(port)
414 && TEST_ptr_null(path);
415 if (!res) {
416 OPENSSL_free(host);
417 OPENSSL_free(port);
418 OPENSSL_free(path);
419 }
420 return res;
421 }
422
test_http_url_invalid_prefix(void)423 static int test_http_url_invalid_prefix(void)
424 {
425 return test_http_url_invalid("htttps://1.2.3.4:65535/pkix");
426 }
427
test_http_url_invalid_port(void)428 static int test_http_url_invalid_port(void)
429 {
430 return test_http_url_invalid("https://1.2.3.4:65536/pkix")
431 && test_http_url_invalid("https://1.2.3.4:");
432 }
433
test_http_url_invalid_path(void)434 static int test_http_url_invalid_path(void)
435 {
436 return test_http_url_invalid("https://[FF01::101]pkix");
437 }
438
test_http_crlf_rejected(void)439 static int test_http_crlf_rejected(void)
440 {
441 BIO *wbio = BIO_new(BIO_s_mem());
442 BIO *rbio = BIO_new(BIO_s_mem());
443 BIO *req = BIO_new(BIO_s_mem());
444 BIO *proxy_bio = BIO_new(BIO_s_mem());
445 OSSL_HTTP_REQ_CTX *rctx = NULL;
446 int res = 0;
447
448 if (!TEST_ptr(wbio)
449 || !TEST_ptr(rbio)
450 || !TEST_ptr(req)
451 || !TEST_ptr(proxy_bio)
452 || !TEST_int_eq(BIO_puts(req, "x"), 1)
453 || !TEST_ptr(rctx = OSSL_HTTP_REQ_CTX_new(wbio, rbio, 0)))
454 goto err;
455
456 ERR_clear_error();
457 res = TEST_false(OSSL_HTTP_REQ_CTX_set_request_line(rctx, 0 /* GET */,
458 NULL, NULL, "/path\r\nInjected: value"))
459 && TEST_false(OSSL_HTTP_REQ_CTX_set_request_line(rctx, 0 /* GET */,
460 "server\r\nInjected: value", "80", RPATH))
461 && TEST_false(OSSL_HTTP_REQ_CTX_set_request_line(rctx, 0 /* GET */,
462 "server", "80\r\nInjected: value", RPATH))
463 && TEST_true(OSSL_HTTP_REQ_CTX_set_request_line(rctx, 0 /* GET */,
464 NULL, NULL, RPATH))
465 && TEST_false(OSSL_HTTP_REQ_CTX_add1_header(rctx,
466 "X-Test\r\nInjected", "value"))
467 && TEST_false(OSSL_HTTP_REQ_CTX_add1_header(rctx,
468 "X-Test", "value\r\nInjected: value"))
469 && TEST_false(OSSL_HTTP_set1_request(rctx, RPATH, NULL,
470 "text/plain\r\nInjected: value", req,
471 NULL, 0 /* expect_asn1 */, 0 /* max_resp_len */,
472 0 /* timeout */, 0 /* keep_alive */))
473 && TEST_false(OSSL_HTTP_proxy_connect(proxy_bio,
474 "server\r\nInjected: value", "443", NULL, NULL,
475 0 /* timeout */, NULL, NULL))
476 && TEST_false(OSSL_HTTP_proxy_connect(proxy_bio,
477 "server", "443\r\nInjected: value", NULL, NULL,
478 0 /* timeout */, NULL, NULL));
479
480 err:
481 ERR_clear_error();
482 OSSL_HTTP_REQ_CTX_free(rctx);
483 BIO_free(wbio);
484 BIO_free(rbio);
485 BIO_free(req);
486 BIO_free(proxy_bio);
487 return res;
488 }
489
test_http_get_txt(void)490 static int test_http_get_txt(void)
491 {
492 return test_http_method(1 /* GET */, 1, HTTP_STATUS_CODE_OK);
493 }
494
test_http_get_txt_redirected(void)495 static int test_http_get_txt_redirected(void)
496 {
497 return test_http_method(2 /* GET with redirection */, 1, HTTP_STATUS_CODE_OK);
498 }
499
test_http_get_txt_fatal_status(void)500 static int test_http_get_txt_fatal_status(void)
501 {
502 return test_http_method(1 /* GET */, 1, HTTP_STATUS_CODES_FATAL_ERROR);
503 }
504
test_http_get_txt_error_status(void)505 static int test_http_get_txt_error_status(void)
506 {
507 return test_http_method(1 /* GET */, 1, HTTP_STATUS_CODES_NONFATAL_ERROR);
508 }
509
test_http_post_txt(void)510 static int test_http_post_txt(void)
511 {
512 return test_http_method(0 /* POST */, 1, HTTP_STATUS_CODE_OK);
513 }
514
test_http_get_x509(void)515 static int test_http_get_x509(void)
516 {
517 return test_http_method(1 /* GET */, 0, HTTP_STATUS_CODE_OK);
518 }
519
test_http_get_x509_redirected(void)520 static int test_http_get_x509_redirected(void)
521 {
522 return test_http_method(2 /* GET with redirection */, 0, HTTP_STATUS_CODE_OK);
523 }
524
test_http_post_x509(void)525 static int test_http_post_x509(void)
526 {
527 return test_http_method(0 /* POST */, 0, HTTP_STATUS_CODE_OK);
528 }
529
test_http_post_x509_fatal_status(void)530 static int test_http_post_x509_fatal_status(void)
531 {
532 return test_http_method(0 /* POST */, 0, HTTP_STATUS_CODES_FATAL_ERROR);
533 }
534
test_http_post_x509_error_status(void)535 static int test_http_post_x509_error_status(void)
536 {
537 return test_http_method(0 /* POST */, 0, HTTP_STATUS_CODES_NONFATAL_ERROR);
538 }
539
test_http_keep_alive_0_no_no(void)540 static int test_http_keep_alive_0_no_no(void)
541 {
542 return test_http_keep_alive('0', 0, 0);
543 }
544
test_http_keep_alive_1_no_no(void)545 static int test_http_keep_alive_1_no_no(void)
546 {
547 return test_http_keep_alive('1', 0, 0);
548 }
549
test_http_keep_alive_0_prefer_yes(void)550 static int test_http_keep_alive_0_prefer_yes(void)
551 {
552 return test_http_keep_alive('0', 1, 1);
553 }
554
test_http_keep_alive_1_prefer_yes(void)555 static int test_http_keep_alive_1_prefer_yes(void)
556 {
557 return test_http_keep_alive('1', 1, 1);
558 }
559
test_http_keep_alive_0_require_yes(void)560 static int test_http_keep_alive_0_require_yes(void)
561 {
562 return test_http_keep_alive('0', 2, 1);
563 }
564
test_http_keep_alive_1_require_yes(void)565 static int test_http_keep_alive_1_require_yes(void)
566 {
567 return test_http_keep_alive('1', 2, 1);
568 }
569
test_http_keep_alive_0_require_no(void)570 static int test_http_keep_alive_0_require_no(void)
571 {
572 return test_http_keep_alive('0', 2, 0);
573 }
574
test_http_keep_alive_1_require_no(void)575 static int test_http_keep_alive_1_require_no(void)
576 {
577 return test_http_keep_alive('1', 2, 0);
578 }
579
test_http_resp_hdr_limit(size_t limit)580 static int test_http_resp_hdr_limit(size_t limit)
581 {
582 BIO *wbio = BIO_new(BIO_s_mem());
583 BIO *rbio = BIO_new(BIO_s_mem());
584 BIO *mem = NULL;
585 server_args mock_args = { NULL, NULL, NULL, '0', 0 };
586 int res = 0;
587 OSSL_HTTP_REQ_CTX *rctx = NULL;
588
589 if (!TEST_ptr(wbio) || !TEST_ptr(rbio))
590 goto err;
591
592 mock_args.txt = text1;
593 mock_args.content_type = "text/plain";
594 mock_args.version = '1';
595 mock_args.out = rbio;
596
597 BIO_set_callback_ex(wbio, http_bio_cb_ex);
598 BIO_set_callback_arg(wbio, (char *)&mock_args);
599
600 rctx = OSSL_HTTP_REQ_CTX_new(wbio, rbio, 8192);
601 if (!TEST_ptr(rctx))
602 goto err;
603
604 if (!TEST_true(OSSL_HTTP_REQ_CTX_set_request_line(rctx, 0 /* GET */,
605 NULL, NULL, RPATH)))
606 goto err;
607
608 OSSL_HTTP_REQ_CTX_set_max_response_hdr_lines(rctx, limit);
609 mem = OSSL_HTTP_REQ_CTX_exchange(rctx);
610
611 /*
612 * Note the server sends 4 http response headers, thus we expect to
613 * see failure here when we set header limit in http response to 1.
614 */
615 if (limit == 1)
616 res = TEST_ptr_null(mem);
617 else
618 res = TEST_ptr(mem);
619
620 err:
621 BIO_free(wbio);
622 BIO_free(rbio);
623 OSSL_HTTP_REQ_CTX_free(rctx);
624
625 return res;
626 }
627
test_hdr_resp_hdr_limit_none(void)628 static int test_hdr_resp_hdr_limit_none(void)
629 {
630 return test_http_resp_hdr_limit(0);
631 }
632
test_hdr_resp_hdr_limit_short(void)633 static int test_hdr_resp_hdr_limit_short(void)
634 {
635 return (test_http_resp_hdr_limit(1));
636 }
637
test_hdr_resp_hdr_limit_256(void)638 static int test_hdr_resp_hdr_limit_256(void)
639 {
640 return test_http_resp_hdr_limit(256);
641 }
642
test_http_adapt_proxy_empty_server(void)643 static int test_http_adapt_proxy_empty_server(void)
644 {
645 const char *proxy = "http://proxy.local:8080";
646
647 return TEST_str_eq(OSSL_HTTP_adapt_proxy(proxy, "abc", "", 0), proxy)
648 && TEST_str_eq(OSSL_HTTP_adapt_proxy(proxy, "abc", "[]", 0), proxy);
649 }
650
cleanup_tests(void)651 void cleanup_tests(void)
652 {
653 X509_free(x509);
654 }
655
656 OPT_TEST_DECLARE_USAGE("cert.pem\n")
657
setup_tests(void)658 int setup_tests(void)
659 {
660 if (!test_skip_common_options())
661 return 0;
662
663 x509_it = ASN1_ITEM_rptr(X509);
664 if (!TEST_ptr((x509 = load_cert_pem(test_get_argument(0), NULL))))
665 return 0;
666
667 ADD_TEST(test_http_url_dns);
668 ADD_TEST(test_http_url_ip);
669 ADD_TEST(test_http_url_timestamp);
670 ADD_TEST(test_http_url_path_query);
671 ADD_TEST(test_http_url_userinfo_query_fragment);
672 ADD_TEST(test_http_url_at_sign_outside_authority);
673 ADD_TEST(test_http_url_ipv4);
674 ADD_TEST(test_http_url_ipv6);
675 ADD_TEST(test_http_url_invalid_prefix);
676 ADD_TEST(test_http_url_invalid_port);
677 ADD_TEST(test_http_url_invalid_path);
678 ADD_TEST(test_http_crlf_rejected);
679
680 ADD_TEST(test_http_get_txt);
681 ADD_TEST(test_http_get_txt_redirected);
682 ADD_TEST(test_http_get_txt_fatal_status);
683 ADD_TEST(test_http_get_txt_error_status);
684 ADD_TEST(test_http_post_txt);
685 ADD_TEST(test_http_get_x509);
686 ADD_TEST(test_http_get_x509_redirected);
687 ADD_TEST(test_http_post_x509);
688 ADD_TEST(test_http_post_x509_fatal_status);
689 ADD_TEST(test_http_post_x509_error_status);
690
691 ADD_TEST(test_http_keep_alive_0_no_no);
692 ADD_TEST(test_http_keep_alive_1_no_no);
693 ADD_TEST(test_http_keep_alive_0_prefer_yes);
694 ADD_TEST(test_http_keep_alive_1_prefer_yes);
695 ADD_TEST(test_http_keep_alive_0_require_yes);
696 ADD_TEST(test_http_keep_alive_1_require_yes);
697 ADD_TEST(test_http_keep_alive_0_require_no);
698 ADD_TEST(test_http_keep_alive_1_require_no);
699
700 ADD_TEST(test_hdr_resp_hdr_limit_none);
701 ADD_TEST(test_hdr_resp_hdr_limit_short);
702 ADD_TEST(test_hdr_resp_hdr_limit_256);
703 ADD_TEST(test_http_adapt_proxy_empty_server);
704 return 1;
705 }
706