Home | History | Annotate | Line # | Download | only in test
      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