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