xref: /freebsd/crypto/openssl/test/http_test.c (revision 78e936b2d0b5e6554425009199be31e76bc67c10)
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