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