summaryrefslogtreecommitdiffstats
path: root/reg-tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:18:05 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:18:05 +0000
commitb46aad6df449445a9fc4aa7b32bd40005438e3f7 (patch)
tree751aa858ca01f35de800164516b298887382919d /reg-tests
parentInitial commit. (diff)
downloadhaproxy-b46aad6df449445a9fc4aa7b32bd40005438e3f7.tar.xz
haproxy-b46aad6df449445a9fc4aa7b32bd40005438e3f7.zip
Adding upstream version 2.9.5.upstream/2.9.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'reg-tests')
-rw-r--r--reg-tests/README71
-rw-r--r--reg-tests/balance/balance-rr.vtc73
-rw-r--r--reg-tests/balance/balance-uri-path-only.vtc97
-rw-r--r--reg-tests/balance/balance-uri.vtc73
-rw-r--r--reg-tests/cache/basic.vtc53
-rw-r--r--reg-tests/cache/caching_rules.vtc320
-rw-r--r--reg-tests/cache/expires.vtc127
-rw-r--r--reg-tests/cache/if-modified-since.vtc144
-rw-r--r--reg-tests/cache/if-none-match.vtc89
-rw-r--r--reg-tests/cache/post_on_entry.vtc65
-rw-r--r--reg-tests/cache/sample_fetches.vtc137
-rw-r--r--reg-tests/cache/vary.vtc461
-rw-r--r--reg-tests/cache/vary_accept_encoding.vtc333
-rw-r--r--reg-tests/checks/1be_40srv_odd_health_checks.vtc117
-rw-r--r--reg-tests/checks/40be_2srv_odd_health_checks.vtc645
-rw-r--r--reg-tests/checks/4be_1srv_health_checks.vtc201
-rw-r--r--reg-tests/checks/4be_1srv_smtpchk_httpchk_layer47errors.vtc100
-rw-r--r--reg-tests/checks/agent-check.vtc42
l---------reg-tests/checks/common.pem1
-rw-r--r--reg-tests/checks/http-check-expect.vtc64
-rw-r--r--reg-tests/checks/http-check-send.vtc165
-rw-r--r--reg-tests/checks/http-check.vtc157
-rw-r--r--reg-tests/checks/http-monitor-uri.vtc56
-rw-r--r--reg-tests/checks/ldap-check.vtc96
-rw-r--r--reg-tests/checks/mysql-check.vtc123
-rw-r--r--reg-tests/checks/pgsql-check.vtc93
-rw-r--r--reg-tests/checks/redis-check.vtc61
-rw-r--r--reg-tests/checks/smtp-check.vtc110
-rw-r--r--reg-tests/checks/spop-check.vtc94
-rw-r--r--reg-tests/checks/ssl-hello-check.vtc76
-rw-r--r--reg-tests/checks/tcp-check-ssl.vtc118
-rw-r--r--reg-tests/checks/tcp-check_min-recv.vtc68
-rw-r--r--reg-tests/checks/tcp-check_multiple_ports.vtc48
-rw-r--r--reg-tests/checks/tcp-checks-socks4.vtc60
-rw-r--r--reg-tests/checks/tls_health_checks.vtc120
-rw-r--r--reg-tests/compression/basic.vtc377
l---------reg-tests/compression/common.pem1
-rw-r--r--reg-tests/compression/etags_conversion.vtc230
-rw-r--r--reg-tests/compression/lua_validation.lua19
-rw-r--r--reg-tests/compression/lua_validation.vtc59
-rw-r--r--reg-tests/compression/vary.vtc308
l---------reg-tests/connection/ca-auth.crt1
-rw-r--r--reg-tests/connection/cli_src_dst.vtc290
l---------reg-tests/connection/client1.pem1
l---------reg-tests/connection/common.pem1
-rw-r--r--reg-tests/connection/dispatch.vtc42
-rw-r--r--reg-tests/connection/http_reuse_aggressive.vtc45
-rw-r--r--reg-tests/connection/http_reuse_always.vtc43
-rw-r--r--reg-tests/connection/http_reuse_be_transparent.vtc82
-rw-r--r--reg-tests/connection/http_reuse_conn_hash.vtc163
-rw-r--r--reg-tests/connection/http_reuse_dispatch.vtc79
-rw-r--r--reg-tests/connection/http_reuse_never.vtc79
-rw-r--r--reg-tests/connection/http_reuse_safe.vtc78
-rw-r--r--reg-tests/connection/proxy_protocol_random_fail.vtc59
-rw-r--r--reg-tests/connection/proxy_protocol_send_generic.vtc74
-rw-r--r--reg-tests/connection/proxy_protocol_send_unique_id.vtc42
-rw-r--r--reg-tests/connection/proxy_protocol_send_unique_id_alpn.vtc33
-rw-r--r--reg-tests/connection/proxy_protocol_tlv_validation.vtc142
-rw-r--r--reg-tests/connection/reverse_connect_full.vtc70
-rw-r--r--reg-tests/connection/reverse_server.vtc69
-rw-r--r--reg-tests/connection/reverse_server_name.vtc87
-rw-r--r--reg-tests/connection/tcp_to_http_upgrade.vtc169
-rw-r--r--reg-tests/contrib/prometheus.vtc113
-rw-r--r--reg-tests/converter/add_item.vtc50
-rw-r--r--reg-tests/converter/be2dec.vtc56
-rw-r--r--reg-tests/converter/be2hex.vtc60
-rw-r--r--reg-tests/converter/bytes.vtc156
-rw-r--r--reg-tests/converter/digest.vtc57
-rw-r--r--reg-tests/converter/field.vtc43
-rw-r--r--reg-tests/converter/fix.vtc235
-rw-r--r--reg-tests/converter/hmac.vtc55
-rw-r--r--reg-tests/converter/iif.vtc46
-rw-r--r--reg-tests/converter/json.vtc40
-rw-r--r--reg-tests/converter/json_query.vtc107
-rw-r--r--reg-tests/converter/mqtt.vtc238
-rw-r--r--reg-tests/converter/param.vtc80
-rw-r--r--reg-tests/converter/secure_memcmp.vtc143
-rw-r--r--reg-tests/converter/sha2.vtc57
-rw-r--r--reg-tests/converter/url_dec.vtc37
-rw-r--r--reg-tests/converter/url_enc.vtc43
-rw-r--r--reg-tests/converter/word.vtc43
-rw-r--r--reg-tests/filters/random-forwarding.vtc138
-rw-r--r--reg-tests/http-capture/multiple_headers.vtc91
-rw-r--r--reg-tests/http-cookies/cookie_insert_indirect.vtc54
-rw-r--r--reg-tests/http-cookies/h2_cookie_concat.vtc42
-rw-r--r--reg-tests/http-errorfiles/errorfiles.vtc51
-rw-r--r--reg-tests/http-errorfiles/errors/400-1.http9
-rw-r--r--reg-tests/http-errorfiles/errors/400-2.http9
-rw-r--r--reg-tests/http-errorfiles/errors/400-3.http9
-rw-r--r--reg-tests/http-errorfiles/errors/400.http9
-rw-r--r--reg-tests/http-errorfiles/errors/403-1.http9
-rw-r--r--reg-tests/http-errorfiles/errors/403-2.http9
-rw-r--r--reg-tests/http-errorfiles/errors/403.http9
-rw-r--r--reg-tests/http-errorfiles/errors/404-1.http9
-rw-r--r--reg-tests/http-errorfiles/errors/404-2.http9
-rw-r--r--reg-tests/http-errorfiles/errors/404-3.http9
-rw-r--r--reg-tests/http-errorfiles/errors/404.http9
-rw-r--r--reg-tests/http-errorfiles/errors/500-1.http9
-rw-r--r--reg-tests/http-errorfiles/errors/500.http9
-rw-r--r--reg-tests/http-errorfiles/errors/lf-403.txt1
-rw-r--r--reg-tests/http-errorfiles/http-error.vtc75
-rw-r--r--reg-tests/http-errorfiles/http_deny_errors.vtc77
-rw-r--r--reg-tests/http-errorfiles/http_errors.vtc134
-rw-r--r--reg-tests/http-errorfiles/http_return.vtc46
l---------reg-tests/http-messaging/common.pem1
-rw-r--r--reg-tests/http-messaging/h1_host_normalization.vtc762
-rw-r--r--reg-tests/http-messaging/h1_to_h1.vtc301
-rw-r--r--reg-tests/http-messaging/h2_desync_attacks.vtc167
-rw-r--r--reg-tests/http-messaging/h2_to_h1.vtc324
-rw-r--r--reg-tests/http-messaging/http_abortonclose.vtc226
-rw-r--r--reg-tests/http-messaging/http_bodyless_response.vtc128
-rw-r--r--reg-tests/http-messaging/http_bodyless_spliced_response.vtc89
-rw-r--r--reg-tests/http-messaging/http_msg_full_on_eom.vtc62
-rw-r--r--reg-tests/http-messaging/http_request_buffer.vtc135
-rw-r--r--reg-tests/http-messaging/http_splicing.vtc77
-rw-r--r--reg-tests/http-messaging/http_splicing_chunk.vtc74
-rw-r--r--reg-tests/http-messaging/http_transfer_encoding.vtc202
-rw-r--r--reg-tests/http-messaging/http_wait_for_body.vtc171
-rw-r--r--reg-tests/http-messaging/protocol_upgrade.vtc228
-rw-r--r--reg-tests/http-messaging/scheme_based_normalize.vtc125
-rw-r--r--reg-tests/http-messaging/srv_ws.vtc180
-rw-r--r--reg-tests/http-messaging/truncated.vtc101
-rw-r--r--reg-tests/http-messaging/websocket.vtc211
-rw-r--r--reg-tests/http-rules/1k.txt16
-rw-r--r--reg-tests/http-rules/acl_cli_spaces.vtc77
-rw-r--r--reg-tests/http-rules/agents.acl1
-rw-r--r--reg-tests/http-rules/converters_ipmask_concat_strcmp_field_word.map1
-rw-r--r--reg-tests/http-rules/converters_ipmask_concat_strcmp_field_word.vtc231
-rw-r--r--reg-tests/http-rules/default_rules.vtc159
-rw-r--r--reg-tests/http-rules/del_header.vtc93
-rw-r--r--reg-tests/http-rules/except-forwardfor-originalto.vtc143
-rw-r--r--reg-tests/http-rules/forwarded-header-7239.vtc171
-rw-r--r--reg-tests/http-rules/h1or2_to_h1c.vtc233
-rw-r--r--reg-tests/http-rules/http_after_response.vtc192
-rw-r--r--reg-tests/http-rules/http_return.vtc99
-rw-r--r--reg-tests/http-rules/ifnone-forwardfor.vtc98
-rw-r--r--reg-tests/http-rules/lf-file.txt1
-rw-r--r--reg-tests/http-rules/map_ordering.map4
-rw-r--r--reg-tests/http-rules/map_ordering.vtc32
-rw-r--r--reg-tests/http-rules/map_redirect-be.map4
-rw-r--r--reg-tests/http-rules/map_redirect.map5
-rw-r--r--reg-tests/http-rules/map_redirect.vtc200
-rw-r--r--reg-tests/http-rules/map_regm_with_backref.map1
-rw-r--r--reg-tests/http-rules/map_regm_with_backref.vtc73
-rw-r--r--reg-tests/http-rules/normalize_uri.vtc549
-rw-r--r--reg-tests/http-rules/path_and_pathq.vtc64
-rw-r--r--reg-tests/http-rules/restrict_req_hdr_names.vtc185
-rw-r--r--reg-tests/http-rules/strict_rw_mode.vtc164
-rw-r--r--reg-tests/http-set-timeout/set_timeout.vtc214
-rwxr-xr-xreg-tests/jwt/build_token.py22
-rw-r--r--reg-tests/jwt/es256-public.pem4
-rw-r--r--reg-tests/jwt/es384-public.pem5
-rw-r--r--reg-tests/jwt/es512-public.pem6
-rw-r--r--reg-tests/jwt/jws_verify.vtc418
-rw-r--r--reg-tests/jwt/rsa-public.pem14
-rw-r--r--reg-tests/log/last_rule.vtc165
-rw-r--r--reg-tests/log/load_balancing.vtc159
-rw-r--r--reg-tests/log/log_backend.vtc185
-rw-r--r--reg-tests/log/log_forward.vtc57
-rw-r--r--reg-tests/log/log_uri.vtc61
-rw-r--r--reg-tests/log/wrong_ip_port_logging.vtc62
-rw-r--r--reg-tests/lua/bad_http_clt_req_duration.lua8
-rw-r--r--reg-tests/lua/bad_http_clt_req_duration.vtc76
-rw-r--r--reg-tests/lua/close_wait_lf.lua1
-rw-r--r--reg-tests/lua/close_wait_lf.vtc53
l---------reg-tests/lua/common.pem1
-rw-r--r--reg-tests/lua/h_txn_get_priv.lua15
-rw-r--r--reg-tests/lua/h_txn_get_priv.vtc33
-rw-r--r--reg-tests/lua/httpclient_action.lua8
-rw-r--r--reg-tests/lua/httpclient_action.vtc39
-rw-r--r--reg-tests/lua/lua_httpclient.lua49
-rw-r--r--reg-tests/lua/lua_httpclient.vtc68
-rw-r--r--reg-tests/lua/lua_socket.lua44
-rw-r--r--reg-tests/lua/lua_socket.vtc33
-rw-r--r--reg-tests/lua/set_var.lua25
-rw-r--r--reg-tests/lua/set_var.vtc83
-rw-r--r--reg-tests/lua/txn_get_priv-print_r.lua96
-rw-r--r--reg-tests/lua/txn_get_priv-thread.vtc69
-rw-r--r--reg-tests/lua/txn_get_priv.lua180
-rw-r--r--reg-tests/lua/txn_get_priv.vtc35
-rw-r--r--reg-tests/lua/wrong_types_usage.lua3
-rw-r--r--reg-tests/lua/wrong_types_usage.vtc77
-rw-r--r--reg-tests/mailers/healthcheckmail.lua70
-rw-r--r--reg-tests/mailers/healthcheckmail.vtc60
l---------reg-tests/mailers/mailers.lua1
-rw-r--r--reg-tests/mcli/mcli_show_info.vtc27
-rw-r--r--reg-tests/mcli/mcli_start_progs.vtc36
-rw-r--r--reg-tests/peers/basic_sync.vtc120
-rw-r--r--reg-tests/peers/basic_sync_wo_stkt_backend.vtc115
l---------reg-tests/peers/common.pem1
-rw-r--r--reg-tests/peers/tls_basic_sync.vtc157
-rw-r--r--reg-tests/peers/tls_basic_sync_wo_stkt_backend.vtc151
-rw-r--r--reg-tests/pki/README23
-rw-r--r--reg-tests/pki/certificates/www.test1.com-csr.json15
-rw-r--r--reg-tests/pki/certificates/www.test1.com-key.pem27
-rw-r--r--reg-tests/pki/certificates/www.test1.com.csr17
-rw-r--r--reg-tests/pki/certificates/www.test1.com.pem23
-rw-r--r--reg-tests/pki/config.json27
-rw-r--r--reg-tests/pki/intermediate/intermediate-ca-key.pem27
-rw-r--r--reg-tests/pki/intermediate/intermediate-ca.csr17
-rw-r--r--reg-tests/pki/intermediate/intermediate-ca.pem22
-rw-r--r--reg-tests/pki/intermediate/intermediate-csr.json14
-rw-r--r--reg-tests/pki/root/root-ca-key.pem27
-rw-r--r--reg-tests/pki/root/root-ca.csr17
-rw-r--r--reg-tests/pki/root/root-ca.pem22
-rw-r--r--reg-tests/pki/root/root-csr.json17
-rw-r--r--reg-tests/sample_fetches/cond_set_var.vtc362
-rw-r--r--reg-tests/sample_fetches/cook.vtc132
-rw-r--r--reg-tests/sample_fetches/hashes.vtc101
-rw-r--r--reg-tests/sample_fetches/so_name.vtc22
-rw-r--r--reg-tests/sample_fetches/srv_name.vtc46
-rw-r--r--reg-tests/sample_fetches/tcpinfo_rtt.vtc39
-rw-r--r--reg-tests/sample_fetches/tlvs.vtc57
-rw-r--r--reg-tests/sample_fetches/ubase64.vtc57
-rw-r--r--reg-tests/sample_fetches/vars.vtc84
-rw-r--r--reg-tests/seamless-reload/abns_socket.vtc55
-rw-r--r--reg-tests/server/cli_add_check_server.vtc161
-rw-r--r--reg-tests/server/cli_add_server.vtc87
-rw-r--r--reg-tests/server/cli_add_ssl_server.vtc110
-rw-r--r--reg-tests/server/cli_add_track_server.vtc242
-rw-r--r--reg-tests/server/cli_delete_dynamic_server.vtc94
-rw-r--r--reg-tests/server/cli_delete_server.vtc60
-rw-r--r--reg-tests/server/cli_set_fqdn.vtc57
-rw-r--r--reg-tests/server/cli_set_ssl.vtc60
l---------reg-tests/server/common.pem1
-rw-r--r--reg-tests/server/get_srv_stats.lua11
-rw-r--r--reg-tests/spoe/wrong_init.vtc22
-rw-r--r--reg-tests/ssl/README2
-rw-r--r--reg-tests/ssl/add_ssl_crt-list.vtc114
l---------reg-tests/ssl/bug-2265.crt1
-rw-r--r--reg-tests/ssl/ca-auth.crt33
-rw-r--r--reg-tests/ssl/cert1-example.com.pem.ecdsa17
-rw-r--r--reg-tests/ssl/cert1-example.com.pem.rsa80
-rw-r--r--reg-tests/ssl/cert2-example.com.pem.ecdsa17
-rw-r--r--reg-tests/ssl/cert2-example.com.pem.rsa80
-rw-r--r--reg-tests/ssl/client.ecdsa.pem28
-rw-r--r--reg-tests/ssl/client1.pem187
-rw-r--r--reg-tests/ssl/client2_expired.pem81
-rw-r--r--reg-tests/ssl/client3_revoked.pem81
-rw-r--r--reg-tests/ssl/common.4096.dh13
-rw-r--r--reg-tests/ssl/common.crt90
-rw-r--r--reg-tests/ssl/common.key28
-rw-r--r--reg-tests/ssl/common.pem72
-rw-r--r--reg-tests/ssl/crl-auth.pem18
-rw-r--r--reg-tests/ssl/del_ssl_crt-list.vtc102
-rw-r--r--reg-tests/ssl/dynamic_server_ssl.vtc113
-rw-r--r--reg-tests/ssl/ecdsa.crt12
-rw-r--r--reg-tests/ssl/ecdsa.key6
-rw-r--r--reg-tests/ssl/ecdsa.pem17
-rw-r--r--reg-tests/ssl/filters.crt-list2
-rw-r--r--reg-tests/ssl/generate_certificates/gen_cert_ca.pem23
-rw-r--r--reg-tests/ssl/generate_certificates/gen_cert_server.pem18
-rw-r--r--reg-tests/ssl/interCA1_crl.pem27
-rw-r--r--reg-tests/ssl/interCA1_crl_empty.pem27
-rw-r--r--reg-tests/ssl/interCA2_crl.pem27
-rw-r--r--reg-tests/ssl/interCA2_crl_empty.pem27
-rw-r--r--reg-tests/ssl/localhost.crt-list5
-rw-r--r--reg-tests/ssl/log_forward_ssl.vtc60
-rw-r--r--reg-tests/ssl/new_del_ssl_cafile.vtc157
-rw-r--r--reg-tests/ssl/new_del_ssl_crlfile.vtc139
-rw-r--r--reg-tests/ssl/ocsp_auto_update.vtc718
-rw-r--r--reg-tests/ssl/ocsp_update/index.txt2
-rw-r--r--reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa33
-rw-r--r--reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa.issuer30
-rw-r--r--reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa.ocspbin0 -> 2281 bytes
-rw-r--r--reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa56
-rw-r--r--reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa.issuer30
-rw-r--r--reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa.ocspbin0 -> 2298 bytes
-rw-r--r--reg-tests/ssl/ocsp_update/multicert/server_ocsp_ecdsa.pem63
-rw-r--r--reg-tests/ssl/ocsp_update/multicert/server_ocsp_ecdsa.pem.ocspbin0 -> 2281 bytes
-rw-r--r--reg-tests/ssl/ocsp_update/multicert_both_certs.crt-list2
-rw-r--r--reg-tests/ssl/ocsp_update/multicert_ecdsa.crt-list1
-rw-r--r--reg-tests/ssl/ocsp_update/multicert_ecdsa_no_update.crt-list1
-rw-r--r--reg-tests/ssl/ocsp_update/multicert_no_ocsp/server_ocsp_ecdsa.pem63
-rw-r--r--reg-tests/ssl/ocsp_update/multicert_no_ocsp/server_ocsp_rsa.pem86
-rw-r--r--reg-tests/ssl/ocsp_update/multicert_rsa.crt-list1
-rw-r--r--reg-tests/ssl/ocsp_update/ocsp.haproxy.com.pem84
-rw-r--r--reg-tests/ssl/ocsp_update/ocsp_update_rootca.crt30
-rw-r--r--reg-tests/ssl/rootCA_crl.pem16
-rw-r--r--reg-tests/ssl/set_cafile_client.pem95
-rw-r--r--reg-tests/ssl/set_cafile_interCA1.crt24
-rw-r--r--reg-tests/ssl/set_cafile_interCA2.crt24
-rw-r--r--reg-tests/ssl/set_cafile_rootCA.crt30
-rw-r--r--reg-tests/ssl/set_cafile_server.pem95
-rw-r--r--reg-tests/ssl/set_default_cert.crt-list2
-rw-r--r--reg-tests/ssl/set_default_cert.pem52
-rw-r--r--reg-tests/ssl/set_ssl_bug_2265.vtc90
-rw-r--r--reg-tests/ssl/set_ssl_cafile.vtc167
-rw-r--r--reg-tests/ssl/set_ssl_cert.vtc206
-rw-r--r--reg-tests/ssl/set_ssl_cert_bundle.vtc111
-rw-r--r--reg-tests/ssl/set_ssl_cert_noext.vtc90
-rw-r--r--reg-tests/ssl/set_ssl_crlfile.vtc146
-rw-r--r--reg-tests/ssl/set_ssl_server_cert.vtc129
-rw-r--r--reg-tests/ssl/show_ocsp_server.pem119
-rw-r--r--reg-tests/ssl/show_ocsp_server.pem.issuer30
-rw-r--r--reg-tests/ssl/show_ocsp_server.pem.ocspbin0 -> 2281 bytes
-rw-r--r--reg-tests/ssl/show_ocsp_server.pem.ocsp.revokedbin0 -> 2298 bytes
-rw-r--r--reg-tests/ssl/show_ssl_ocspresponse.vtc144
-rw-r--r--reg-tests/ssl/simple.crt-list5
-rw-r--r--reg-tests/ssl/ssl_alpn.vtc212
-rw-r--r--reg-tests/ssl/ssl_client_auth.vtc76
-rw-r--r--reg-tests/ssl/ssl_client_samples.vtc74
-rw-r--r--reg-tests/ssl/ssl_crt-list_filters.vtc124
-rw-r--r--reg-tests/ssl/ssl_curve_name.vtc51
-rw-r--r--reg-tests/ssl/ssl_curves.vtc134
-rw-r--r--reg-tests/ssl/ssl_default_server.vtc142
-rw-r--r--reg-tests/ssl/ssl_dh.vtc234
-rw-r--r--reg-tests/ssl/ssl_errors.vtc439
-rw-r--r--reg-tests/ssl/ssl_frontend_samples.vtc69
-rw-r--r--reg-tests/ssl/ssl_generate_certificate.vtc168
-rw-r--r--reg-tests/ssl/ssl_reuse.vtc141
-rw-r--r--reg-tests/ssl/ssl_server_samples.vtc73
-rw-r--r--reg-tests/ssl/ssl_simple_crt-list.vtc50
-rw-r--r--reg-tests/ssl/wrong_ctx_storage.vtc45
-rw-r--r--reg-tests/startup/automatic_maxconn.vtc104
-rw-r--r--reg-tests/startup/check_condition.vtc32
-rw-r--r--reg-tests/startup/common.pem117
-rw-r--r--reg-tests/startup/default_rules.vtc185
-rw-r--r--reg-tests/stick-table/converteers_ref_cnt_never_dec.vtc75
-rw-r--r--reg-tests/stick-table/src_conn_rate.vtc43
-rw-r--r--reg-tests/stick-table/unknown_key.vtc32
-rw-r--r--reg-tests/stickiness/lb-services.vtc292
-rw-r--r--reg-tests/stickiness/srvkey-addr.vtc263
-rw-r--r--reg-tests/stream/unique-id-from-proxy.vtc38
-rw-r--r--reg-tests/stream/unique-id.vtc47
-rw-r--r--reg-tests/tcp-rules/default_rules.vtc61
-rw-r--r--reg-tests/webstats/missing-stats-fields.vtc14
-rw-r--r--reg-tests/webstats/webstats-scope-and-post-change.vtc84
328 files changed, 29305 insertions, 0 deletions
diff --git a/reg-tests/README b/reg-tests/README
new file mode 100644
index 0000000..ef721fd
--- /dev/null
+++ b/reg-tests/README
@@ -0,0 +1,71 @@
+ * Regression testing for HAProxy with VTest *
+
+
+This little README file is about how to compile and run vtest test case files (VTC files)
+to test HAProxy for any regression.
+
+To do so, you will have to compile vtest program sources which depends on
+Varnish cache application sources. vtest, formerly varnishtest, is a very useful
+program which has been developed to test Varnish cache application. vtest has been
+modified in collaboration with Varnish cache conceptor Poul-Henning Kamp to support
+HAProxy in addition to Varnish cache.
+
+See also: doc/regression-testing.txt
+
+* vtest compilation *
+
+ $ git clone https://github.com/vtest/VTest
+
+ $ cd VTest
+
+ $ make vtest
+
+ Then vtest program may be found at the root directory of vtest sources directory.
+ The Varnish cache manuals are located in 'man' directory of Varnish cache sources
+ directory. You will have to have a look at varnishtest(7) and vtc(7) manuals to
+ use vtest.
+
+ Some information may also be found in doc/regression-testing.txt in HAProxy
+ sources.
+
+ Note that VTC files for Varnish cache may be found in bin/varnishtest/tests directory
+ of Varnish cache sources directory which may be found here:
+ https://github.com/varnishcache/varnish-cache
+
+
+* vtest execution *
+
+ You must set HAPROXY_PROGRAM environment variable to give the location
+ of the HAProxy program to test to vtest:
+
+ $ HAPROXY_PROGRAM=<my haproxy program> vtest ...
+
+ The HAProxy VTC files found in HAProxy sources may be run with the reg-tests
+ Makefile target. You must set the VTEST_PROGRAM environment variable to
+ give the location of the vtest program which has been previously compiled.
+
+ $ VTEST_PROGRAM=<my vtest program> make reg-tests
+
+ "reg-tests" Makefile target run scripts/run-regtest.sh script.
+ To get more information about this script run it with --help option.
+
+ Note that vtest is run with -t10 and -l option. -l option is to keep
+ keep vtest temporary directory in case of failed test cases. core files
+ may be found in this directory (if enabled by ulimit).
+
+
+* vtest patches for HAProxy VTC files *
+
+ When producing a patch to add a VTC regression testing file to reg-tests directory,
+ please follow these simple rules:
+
+ - If your VTC file needs others files, if possible, use the same basename as that
+ of the VTC file,
+ - Put these files in a directory with the same name as the code area concerned
+ by the bug ('peers', 'lua', 'acl' etc).
+
+Please note that most tests use a common set of timeouts defined by the
+environment variable HAPROXY_TEST_TIMEOUT. As much as possible, for regular I/O
+(i.e. not errors), please try to reuse that setting so that the value may
+easily be adjusted when running in some particularly slow environments, or be
+shortened to fail faster on developers' machines.
diff --git a/reg-tests/balance/balance-rr.vtc b/reg-tests/balance/balance-rr.vtc
new file mode 100644
index 0000000..908a4f9
--- /dev/null
+++ b/reg-tests/balance/balance-rr.vtc
@@ -0,0 +1,73 @@
+vtest "Test for balance roundrobin"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Server: s1"
+} -repeat 2 -start
+
+server s2 {
+ rxreq
+ txresp -hdr "Server: s2"
+} -repeat 2 -start
+
+server s3 {
+ rxreq
+ txresp -hdr "Server: s3"
+} -repeat 2 -start
+
+server s4 {
+ rxreq
+ txresp -hdr "Server: s4"
+} -repeat 2 -start
+
+haproxy h1 -arg "-L A" -conf {
+ defaults
+ mode http
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen px
+ bind "fd@${px}"
+ balance roundrobin
+ server srv1 ${s1_addr}:${s1_port}
+ server srv2 ${s2_addr}:${s2_port}
+ server srv3 ${s3_addr}:${s3_port}
+ server srv4 ${s4_addr}:${s4_port}
+} -start
+
+client c1 -connect ${h1_px_sock} {
+ txreq -url "/url1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s1
+} -run
+
+client c2 -connect ${h1_px_sock} {
+ txreq -url "/url1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s2
+} -run
+
+client c3 -connect ${h1_px_sock} {
+ txreq -url "/url1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s3
+} -run
+
+client c4 -connect ${h1_px_sock} {
+ txreq -url "/url1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s4
+} -run
+
+client c5 -connect ${h1_px_sock} {
+ txreq -url "/url1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s1
+} -run
diff --git a/reg-tests/balance/balance-uri-path-only.vtc b/reg-tests/balance/balance-uri-path-only.vtc
new file mode 100644
index 0000000..f1291ee
--- /dev/null
+++ b/reg-tests/balance/balance-uri-path-only.vtc
@@ -0,0 +1,97 @@
+vtest "Test for balance URI"
+feature ignore_unknown_macro
+#REQUIRE_VERSION=2.3
+
+server s1 {
+ rxreq
+ txresp -hdr "Server: s1" -body "s1"
+} -repeat 5 -start
+
+server s2 {
+ rxreq
+ txresp -hdr "Server: s2" -body "s2"
+} -repeat 5 -start
+
+server s3 {
+ rxreq
+ txresp -hdr "Server: s3" -body "s3"
+} -repeat 5 -start
+
+server s4 {
+ rxreq
+ txresp -hdr "Server: s4" -body "s4"
+} -repeat 5 -start
+
+haproxy h1 -arg "-L A" -conf {
+ defaults
+ mode http
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen px
+ bind "fd@${px}"
+ bind "fd@${pxh2}" proto h2
+ balance uri path-only
+ server srv1 ${s1_addr}:${s1_port}
+ server srv2 ${s2_addr}:${s2_port}
+ server srv3 ${s3_addr}:${s3_port}
+ server srv4 ${s4_addr}:${s4_port}
+} -start
+
+client c1 -connect ${h1_px_sock} {
+ txreq -url "http://127.0.0.1/url1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s2
+} -run
+
+client c2 -connect ${h1_px_sock} {
+ txreq -url "/url1?ignore=this-arg"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s2
+} -run
+
+client c3 -connect ${h1_px_sock} {
+ txreq -url "http://127.0.0.1/url2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s3
+} -run
+
+client c4 -connect ${h1_px_sock} {
+ txreq -url "/url3"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s4
+} -run
+
+client c5 -connect ${h1_px_sock} {
+ txreq -url "/url4"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s1
+} -run
+
+client c6h2 -connect ${h1_pxh2_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -req "GET" \
+ -scheme "https" \
+ -url "/url1"
+ rxhdrs
+ expect resp.status == 200
+ rxdata -all
+ expect resp.body == "s2"
+ } -run
+} -run
diff --git a/reg-tests/balance/balance-uri.vtc b/reg-tests/balance/balance-uri.vtc
new file mode 100644
index 0000000..e678835
--- /dev/null
+++ b/reg-tests/balance/balance-uri.vtc
@@ -0,0 +1,73 @@
+vtest "Test for balance URI"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Server: s1"
+} -repeat 2 -start
+
+server s2 {
+ rxreq
+ txresp -hdr "Server: s2"
+} -repeat 2 -start
+
+server s3 {
+ rxreq
+ txresp -hdr "Server: s3"
+} -repeat 2 -start
+
+server s4 {
+ rxreq
+ txresp -hdr "Server: s4"
+} -repeat 2 -start
+
+haproxy h1 -arg "-L A" -conf {
+ defaults
+ mode http
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen px
+ bind "fd@${px}"
+ balance uri
+ server srv1 ${s1_addr}:${s1_port}
+ server srv2 ${s2_addr}:${s2_port}
+ server srv3 ${s3_addr}:${s3_port}
+ server srv4 ${s4_addr}:${s4_port}
+} -start
+
+client c1 -connect ${h1_px_sock} {
+ txreq -url "/url1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s2
+} -run
+
+client c2 -connect ${h1_px_sock} {
+ txreq -url "/url1?ignore=this-arg"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s2
+} -run
+
+client c3 -connect ${h1_px_sock} {
+ txreq -url "/url2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s3
+} -run
+
+client c4 -connect ${h1_px_sock} {
+ txreq -url "/url3"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s4
+} -run
+
+client c5 -connect ${h1_px_sock} {
+ txreq -url "/url4"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s1
+} -run
diff --git a/reg-tests/cache/basic.vtc b/reg-tests/cache/basic.vtc
new file mode 100644
index 0000000..377cbb3
--- /dev/null
+++ b/reg-tests/cache/basic.vtc
@@ -0,0 +1,53 @@
+varnishtest "Basic cache test"
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Cache-Control: max-age=5"
+ chunkedlen 1
+ chunkedlen 1
+ chunkedlen 2
+ chunkedlen 3
+ chunkedlen 5
+ chunkedlen 8
+ chunkedlen 13
+ chunkedlen 21
+ chunkedlen 34
+ chunkedlen 55
+ chunkedlen 89
+ chunkedlen 144
+ chunkedlen 233
+ chunkedlen 0
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ default_backend test
+
+ backend test
+ http-request cache-use my_cache
+ server www ${s1_addr}:${s1_port}
+ http-response cache-store my_cache
+
+ cache my_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+} -start
+
+
+client c1 -connect ${h1_fe_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 609
+} -repeat 4 -run
diff --git a/reg-tests/cache/caching_rules.vtc b/reg-tests/cache/caching_rules.vtc
new file mode 100644
index 0000000..a488875
--- /dev/null
+++ b/reg-tests/cache/caching_rules.vtc
@@ -0,0 +1,320 @@
+varnishtest "Caching rules test"
+# A response will not be cached unless it has an explicit age (Cache-Control max-age of s-maxage, Expires) or a validator (Last-Modified, or ETag)
+# A response will not be cached either if it has an Age header that is either invalid (should be an integer) or greater than its max age.
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.url == "/max-age"
+ txresp -hdr "Cache-Control: max-age=5" \
+ -bodylen 150
+
+ rxreq
+ expect req.url == "/s-maxage"
+ txresp -hdr "Cache-Control: s-maxage=5" \
+ -bodylen 160
+
+ rxreq
+ expect req.url == "/last-modified"
+ txresp -hdr "Last-Modified: Thu, 22 Oct 2020 16:51:12 GMT" \
+ -bodylen 180
+
+ rxreq
+ expect req.url == "/etag"
+ txresp -hdr "ETag: \"etag\"" \
+ -bodylen 190
+
+ rxreq
+ expect req.url == "/uncacheable"
+ txresp \
+ -bodylen 200
+
+ rxreq
+ expect req.url == "/uncacheable"
+ txresp \
+ -bodylen 210
+
+ # Age response header checks
+
+ # Invalid age
+ rxreq
+ expect req.url == "/invalid_age"
+ txresp -hdr "Cache-Control: max-age=5" \
+ -hdr "Age: abc" -bodylen 120
+
+ rxreq
+ expect req.url == "/invalid_age"
+ txresp -hdr "Cache-Control: max-age=5" \
+ -hdr "Age: abc" -bodylen 120
+
+ # Old age (greater than max age)
+ rxreq
+ expect req.url == "/old_age"
+ txresp -hdr "Cache-Control: max-age=5" \
+ -hdr "Age: 10" -bodylen 130
+
+ rxreq
+ expect req.url == "/old_age"
+ txresp -hdr "Cache-Control: max-age=5" \
+ -hdr "Age: 10" -bodylen 130
+
+ # Good age
+ rxreq
+ expect req.url == "/good_age"
+ txresp -hdr "Cache-Control: max-age=500" \
+ -hdr "Age: 100" -bodylen 140
+
+
+ # "Control-Cache: no-cache" on client request but still stored in cache
+ rxreq
+ expect req.url == "/nocache"
+ txresp -hdr "Cache-Control: max-age=500" \
+ -hdr "Age: 100" -bodylen 140
+
+ rxreq
+ expect req.url == "/nocache"
+ txresp -hdr "Cache-Control: max-age=500" \
+ -hdr "Age: 100" -bodylen 140
+
+
+ # max-age=0
+ rxreq
+ expect req.url == "/maxage_zero"
+ txresp -hdr "Cache-Control: max-age=0" \
+ -bodylen 150
+
+ rxreq
+ expect req.url == "/maxage_zero"
+ txresp -hdr "Cache-Control: max-age=0" \
+ -bodylen 150
+
+ # Overridden null max-age
+ rxreq
+ expect req.url == "/overridden"
+ txresp -hdr "Cache-Control: max-age=1, s-maxage=5" \
+ -bodylen 160
+
+ rxreq
+ expect req.url == "/overridden_null_maxage"
+ txresp -hdr "Cache-Control: max-age=0, s-maxage=5" \
+ -bodylen 190
+
+
+} -start
+
+server s2 {
+ rxreq
+ expect req.url == "/expires"
+ # Expires header is filled directly by the expires_be backend"
+ txresp \
+ -bodylen 170
+} -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ use_backend expires_be if { path_beg /expires }
+ default_backend test
+
+ backend expires_be
+ http-request cache-use my_cache
+ server www ${s2_addr}:${s2_port}
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+ # Expires value set in the future (current_time+5s)
+ http-response set-header Expires %[date(5),http_date]
+ http-response cache-store my_cache
+
+ backend test
+ http-request cache-use my_cache
+ server www ${s1_addr}:${s1_port}
+ http-response cache-store my_cache
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+
+ cache my_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+} -start
+
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/max-age"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 150
+
+ txreq -url "/max-age"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 150
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/s-maxage"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 160
+
+ txreq -url "/s-maxage"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 160
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/expires"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 170
+
+ txreq -url "/expires"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 170
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/last-modified"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 180
+
+ txreq -url "/last-modified"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 180
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/etag"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 190
+
+ txreq -url "/etag"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 190
+ expect resp.http.X-Cache-Hit == 1
+
+ # The next response should not be cached
+ txreq -url "/uncacheable"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 200
+
+ txreq -url "/uncacheable"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 210
+ expect resp.http.X-Cache-Hit == 0
+
+ # Age header tests
+ txreq -url "/invalid_age"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 120
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/invalid_age"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 120
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/old_age"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 130
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/old_age"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 130
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/good_age"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 140
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/good_age"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 140
+ expect resp.http.X-Cache-Hit == 1
+
+ # Cache-Control: no-cache
+ txreq -url "/nocache" -hdr "Cache-Control: no-cache"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 140
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/nocache" -hdr "Cache-Control: no-cache"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 140
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/nocache"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 140
+ expect resp.http.X-Cache-Hit == 1
+
+ # max-age=0 (control test for the overridden null max-age test below)
+ txreq -url "/maxage_zero"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 150
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/maxage_zero"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 150
+ expect resp.http.X-Cache-Hit == 0
+
+ # Overridden max-age directive
+ txreq -url "/overridden"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 160
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/overridden"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 160
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/overridden_null_maxage"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 190
+ expect resp.http.X-Cache-Hit == 0
+
+ # The previous response should have been cached even if it had
+ # a max-age=0 since it also had a positive s-maxage
+ txreq -url "/overridden_null_maxage"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 190
+ expect resp.http.X-Cache-Hit == 1
+
+
+} -run
diff --git a/reg-tests/cache/expires.vtc b/reg-tests/cache/expires.vtc
new file mode 100644
index 0000000..ee5cd77
--- /dev/null
+++ b/reg-tests/cache/expires.vtc
@@ -0,0 +1,127 @@
+varnishtest "Expires support"
+
+#REQUIRE_VERSION=2.3
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Cache-Control: max-age=5"
+ chunkedlen 15
+ chunkedlen 15
+ chunkedlen 15
+ chunkedlen 0
+} -start
+
+server s2 {
+ rxreq
+ txresp -nolen -hdr "Transfer-Encoding: chunked"
+ chunkedlen 16
+ chunkedlen 16
+ chunkedlen 16
+ chunkedlen 0
+} -start
+
+server s3 {
+ rxreq
+ txresp -nolen -hdr "Transfer-Encoding: chunked"
+ chunkedlen 16
+ chunkedlen 16
+ chunkedlen 16
+ chunkedlen 0
+
+ rxreq
+ txresp -nolen -hdr "Transfer-Encoding: chunked"
+ chunkedlen 17
+ chunkedlen 17
+ chunkedlen 17
+ chunkedlen 0
+} -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ use_backend cache_control_be if { path_beg /cache_control }
+ use_backend future_expires_be if { path_beg /future }
+ default_backend past_expires_be
+
+ backend cache_control_be
+ # Expires header should be ignored since a Cache-Control one is present
+ http-request cache-use my_cache
+ server www ${s1_addr}:${s1_port}
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+ http-response set-header Expires %[date(-1),http_date]
+ http-response cache-store my_cache
+
+ backend future_expires_be
+ # Expires value set in the future (current_time+5s)
+ http-request cache-use my_cache
+ server www ${s2_addr}:${s2_port}
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+ http-response set-header Expires %[date(5),http_date]
+ http-response cache-store my_cache
+
+ backend past_expires_be
+ # Expires value set in the past
+ http-request cache-use my_cache
+ server www ${s3_addr}:${s3_port}
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+ http-response set-header Expires %[date(-1),http_date]
+ http-response cache-store my_cache
+
+ cache my_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+} -start
+
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/cache_control"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 45
+
+ txreq -url "/cache_control"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 45
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/future"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 48
+
+ txreq -url "/future"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 48
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/past"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 48
+
+ txreq -url "/past"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 0
+
+} -run
+
diff --git a/reg-tests/cache/if-modified-since.vtc b/reg-tests/cache/if-modified-since.vtc
new file mode 100644
index 0000000..1fd9a93
--- /dev/null
+++ b/reg-tests/cache/if-modified-since.vtc
@@ -0,0 +1,144 @@
+varnishtest "If-Modified-Since support"
+
+#REQUIRE_VERSION=2.3
+
+feature ignore_unknown_macro
+
+server s1 {
+ # Response containing a "Last-Modified" field
+ rxreq
+ expect req.url == "/last_modified"
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Last-Modified: Thu, 15 Oct 2020 22:23:24 GMT"
+ chunkedlen 15
+ chunkedlen 15
+ chunkedlen 15
+ chunkedlen 0
+
+ # Response containing a "Date" field
+ rxreq
+ expect req.url == "/date"
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Date: Thu, 22 Oct 2020 16:51:12 GMT" \
+ -hdr "Cache-Control: max-age=5"
+ chunkedlen 16
+ chunkedlen 16
+ chunkedlen 16
+ chunkedlen 0
+
+ # Response containing both a "Last-Modified" and a "Date" fields
+ # Should behave the same way as if the "Date" field was not here.
+ rxreq
+ expect req.url == "/last_modified_and_date"
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Last-Modified: Thu, 15 Oct 2020 14:24:38 GMT" \
+ -hdr "Date: Thu, 22 Oct 2020 16:51:12 GMT"
+ chunkedlen 17
+ chunkedlen 17
+ chunkedlen 17
+ chunkedlen 0
+} -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ default_backend test
+
+ backend test
+ http-request cache-use my_cache
+ server www ${s1_addr}:${s1_port}
+ http-response cache-store my_cache
+
+ cache my_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+} -start
+
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/last_modified"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 45
+
+ txreq -url "/date"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 48
+
+ txreq -url "/last_modified_and_date"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+
+
+ # Earlier date
+ # "Last-Modified" version
+ txreq -url "/last_modified" \
+ -hdr "If-Modified-Since: Thu, 15 Oct 2020 00:00:01 GMT"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 45
+ # "Date" version
+ txreq -url "/date" \
+ -hdr "If-Modified-Since: Thu, 01 Oct 2020 00:00:01 GMT"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 48
+ # "Last-Modified" and "Date" version
+ txreq -url "/last_modified_and_date" \
+ -hdr "If-Modified-Since: Thu, 15 Oct 2020 00:00:01 GMT"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+
+
+ # Same date
+ # "Last-Modified" version
+ txreq -url "/last_modified" \
+ -hdr "If-Modified-Since: Thu, 15 Oct 2020 22:23:24 GMT"
+ rxresphdrs
+ expect resp.status == 304
+ # "Date" version
+ txreq -url "/date" \
+ -hdr "If-Modified-Since: Thu, 22 Oct 2020 16:51:12 GMT"
+ rxresphdrs
+ expect resp.status == 304
+ # "Last-Modified" and "Date" version
+ txreq -url "/last_modified_and_date" \
+ -hdr "If-Modified-Since: Thu, 15 Oct 2020 16:51:12 GMT"
+ rxresphdrs
+ expect resp.status == 304
+
+
+ # Later date
+ # "Last-Modified" version
+ txreq -url "/last_modified" \
+ -hdr "If-Modified-Since: Thu, 22 Oct 2020 23:00:00 GMT"
+ rxresphdrs
+ expect resp.status == 304
+ # "Date" version
+ txreq -url "/date" \
+ -hdr "If-Modified-Since: Thu, 22 Oct 2020 23:00:00 GMT"
+ rxresphdrs
+ expect resp.status == 304
+ # "Last-Modified" and "Date" version
+ txreq -url "/last_modified_and_date" \
+ -hdr "If-Modified-Since: Thu, 22 Oct 2020 23:00:00 GMT"
+ rxresphdrs
+ expect resp.status == 304
+
+} -run
diff --git a/reg-tests/cache/if-none-match.vtc b/reg-tests/cache/if-none-match.vtc
new file mode 100644
index 0000000..3dcaec5
--- /dev/null
+++ b/reg-tests/cache/if-none-match.vtc
@@ -0,0 +1,89 @@
+varnishtest "If-None-Match support"
+
+#REQUIRE_VERSION=2.3
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "ETag: \"etag\""
+ chunkedlen 1
+ chunkedlen 1
+ chunkedlen 2
+ chunkedlen 3
+ chunkedlen 5
+ chunkedlen 8
+ chunkedlen 13
+ chunkedlen 21
+ chunkedlen 34
+ chunkedlen 55
+ chunkedlen 89
+ chunkedlen 144
+ chunkedlen 233
+ chunkedlen 0
+} -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ default_backend test
+
+ backend test
+ http-request cache-use my_cache
+ server www ${s1_addr}:${s1_port}
+ http-response cache-store my_cache
+
+ cache my_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+} -start
+
+
+client c1 -connect ${h1_fe_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 609
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 609
+ txreq \
+ -hdr "if-none-match: *"
+ rxresphdrs
+ expect resp.status == 304
+ txreq \
+ -hdr "if-none-match: \"etag\""
+ rxresphdrs
+ expect resp.status == 304
+ txreq \
+ -hdr "if-none-match: W/\"etag\""
+ rxresphdrs
+ expect resp.status == 304
+} -run
+
+client c2 -connect ${h1_fe_sock} {
+ txreq \
+ -hdr "if-none-match: \"wrong_etag\""
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 609
+ txreq \
+ -hdr "if-none-match: W/\"wrong_etag\", W/\"etag\""
+ rxresphdrs
+ expect resp.status == 304
+} -run
diff --git a/reg-tests/cache/post_on_entry.vtc b/reg-tests/cache/post_on_entry.vtc
new file mode 100644
index 0000000..66c89e4
--- /dev/null
+++ b/reg-tests/cache/post_on_entry.vtc
@@ -0,0 +1,65 @@
+varnishtest "A successful unsafe method (POST for instance) on a cached entry must disable it."
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.url == "/cached"
+ txresp -hdr "Cache-Control: max-age=5" \
+ -bodylen 150
+
+ rxreq
+ expect req.url == "/cached"
+ expect req.method == "POST"
+ txresp
+
+ rxreq
+ expect req.url == "/cached"
+ txresp -hdr "Cache-Control: max-age=5" \
+ -bodylen 100
+
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ default_backend test
+
+ backend test
+ http-request cache-use my_cache
+ server www ${s1_addr}:${s1_port}
+ http-response cache-store my_cache
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+
+ cache my_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+} -start
+
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/cached"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 150
+
+ txreq -method "POST" -url "/cached" -bodylen 100
+ rxresp
+ expect resp.status == 200
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/cached"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 100
+ expect resp.http.X-Cache-Hit == 0
+} -run
diff --git a/reg-tests/cache/sample_fetches.vtc b/reg-tests/cache/sample_fetches.vtc
new file mode 100644
index 0000000..c2b99c2
--- /dev/null
+++ b/reg-tests/cache/sample_fetches.vtc
@@ -0,0 +1,137 @@
+
+varnishtest "Basic cache test"
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Cache-Control: max-age=5"
+ chunkedlen 15
+ chunkedlen 15
+ chunkedlen 15
+ chunkedlen 0
+} -start
+
+server s2 {
+ rxreq
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Cache-Control: max-age=5"
+ chunkedlen 16
+ chunkedlen 16
+ chunkedlen 16
+ chunkedlen 0
+} -start
+
+server s3 {
+ rxreq
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Cache-Control: max-age=5"
+ chunkedlen 17
+ chunkedlen 17
+ chunkedlen 17
+ chunkedlen 0
+
+ rxreq
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Cache-Control: max-age=5"
+ chunkedlen 17
+ chunkedlen 17
+ chunkedlen 17
+ chunkedlen 0
+} -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ use_backend first_be if { path_beg /first }
+ use_backend nocache_be if { path_beg /nocache }
+ default_backend second_be
+
+ backend first_be
+ http-request cache-use first_cache
+ server www ${s1_addr}:${s1_port}
+ http-response cache-store first_cache
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+ http-response set-header X-Cache-Name %[res.cache_name]
+
+ backend second_be
+ http-request cache-use second_cache
+ server www ${s2_addr}:${s2_port}
+ http-response cache-store second_cache
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+ http-response set-header X-Cache-Name %[res.cache_name]
+
+ backend nocache_be
+ server www ${s3_addr}:${s3_port}
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+ http-response set-header X-Cache-Name %[res.cache_name]
+
+ cache first_cache
+ total-max-size 3
+ max-age 40
+ max-object-size 3000
+
+ cache second_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+} -start
+
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/first"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 45
+ expect resp.http.X-Cache-Hit == 0
+ expect resp.http.X-Cache-Name == ""
+
+ txreq -url "/second"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 48
+ expect resp.http.X-Cache-Hit == 0
+ expect resp.http.X-Cache-Name == ""
+
+ txreq -url "/nocache"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 0
+ expect resp.http.X-Cache-Name == ""
+
+ # Response should come form the cache now
+ txreq -url "/nocache"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 0
+ expect resp.http.X-Cache-Name == ""
+
+ txreq -url "/first"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 45
+ expect resp.http.X-Cache-Hit == 1
+ expect resp.http.X-Cache-Name == "first_cache"
+
+ txreq -url "/second"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 48
+ expect resp.http.X-Cache-Hit == 1
+ expect resp.http.X-Cache-Name == "second_cache"
+} -run
diff --git a/reg-tests/cache/vary.vtc b/reg-tests/cache/vary.vtc
new file mode 100644
index 0000000..6c8cedf
--- /dev/null
+++ b/reg-tests/cache/vary.vtc
@@ -0,0 +1,461 @@
+varnishtest "Vary support"
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+server s1 {
+ # Response varying on "accept-encoding" with
+ # an unacceptable content-encoding
+ rxreq
+ expect req.url == "/accept-encoding"
+ txresp -hdr "Content-Encoding: gzip" \
+ -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 45
+
+ # Response varying on "accept-encoding"
+ rxreq
+ expect req.url == "/accept-encoding"
+ txresp -hdr "Content-Encoding: gzip" \
+ -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 45
+
+ # Response varying on "accept-encoding" with
+ # no content-encoding
+ rxreq
+ expect req.url == "/accept-encoding"
+ txresp -hdr "Content-Type: text/plain" \
+ -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 48
+
+ # Response varying on "accept-encoding" but having two different encodings
+ rxreq
+ expect req.url == "/accept-encoding-multiple"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 51
+
+
+ # Unmanaged vary
+ rxreq
+ expect req.url == "/unmanaged"
+ txresp -hdr "Vary: accept-encoding,unmanaged" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 51
+
+
+ rxreq
+ expect req.url == "/unmanaged"
+ txresp -hdr "Vary: accept-encoding,unmanaged" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 51
+
+
+
+ # Mixed Vary (Accept-Encoding + Referer)
+ rxreq
+ expect req.url == "/referer-accept-encoding"
+ txresp -hdr "Vary: accept-encoding,referer" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: gzip" \
+ -bodylen 51
+
+ rxreq
+ expect req.url == "/referer-accept-encoding"
+ txresp -hdr "Vary: referer,accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: br" \
+ -bodylen 54
+
+ rxreq
+ expect req.url == "/referer-accept-encoding"
+ txresp -hdr "Vary: referer,accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: gzip" \
+ -bodylen 57
+
+ rxreq
+ expect req.url == "/origin-referer-accept-encoding"
+ txresp -hdr "Vary: origin,referer,accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: gzip" \
+ -bodylen 58
+
+ rxreq
+ expect req.url == "/origin-referer-accept-encoding"
+ txresp -hdr "Vary: origin,referer,accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: gzip" \
+ -bodylen 59
+
+ # Multiple Accept-Encoding headers
+ rxreq
+ expect req.url == "/multiple_headers"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: br" \
+ -bodylen 155
+
+ rxreq
+ expect req.url == "/multiple_headers"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: br" \
+ -bodylen 166
+
+
+ # Too many Accept-Encoding values (we will not cache responses with more than 16 encodings)
+ rxreq
+ expect req.url == "/too_many_encodings"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: gzip" \
+ -bodylen 177
+
+ rxreq
+ expect req.url == "/too_many_encodings"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: gzip" \
+ -bodylen 188
+
+ rxreq
+ expect req.url == "/empty-vs-missing"
+ txresp -hdr "Content-Encoding: gzip" \
+ -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 234
+
+ rxreq
+ expect req.url == "/empty-vs-missing"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 256
+} -start
+
+server s2 {
+ # Responses that should not be cached
+ rxreq
+ expect req.url == "/no_vary_support"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 57
+
+ rxreq
+ expect req.url == "/no_vary_support"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 57
+} -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ use_backend no_vary_be if { path_beg /no_vary_support }
+ default_backend test
+
+ backend test
+ http-request cache-use my_cache
+ server www ${s1_addr}:${s1_port}
+ http-response cache-store my_cache
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+
+ backend no_vary_be
+ http-request cache-use no_vary_cache
+ server www ${s2_addr}:${s2_port}
+ http-response cache-store no_vary_cache
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+
+ cache my_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+ process-vary on
+
+ cache no_vary_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+ process-vary off
+} -start
+
+
+client c1 -connect ${h1_fe_sock} {
+ # Accept-Encoding Vary
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: first_value"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.bodylen == 45
+
+ # The response for the first request had an unacceptable `content-encoding`
+ # which might happen if that's the only thing the server supports, but
+ # we must not cache that and instead defer to the server.
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: first_value"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.bodylen == 45
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: second_value"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 48
+ expect resp.http.content-type == "text/plain"
+ expect resp.http.X-Cache-Hit == 0
+
+ # This request matches the cache entry for the request above, despite
+ # matching the `accept-encoding` of the first request because the
+ # request above only has the `identity` encoding which is implicitly
+ # added, unless explicitly forbidden.
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: first_value"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 48
+ expect resp.http.content-type == "text/plain"
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: second_value"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 48
+ expect resp.http.content-type == "text/plain"
+ expect resp.http.X-Cache-Hit == 1
+
+ # The accept-encoding normalizer function converts the header values
+ # to lower case then calculates the hash of every sub part before
+ # sorting the hashes and xor'ing them (while removing duplicates).
+ txreq -url "/accept-encoding-multiple" -hdr "Accept-Encoding: first,second"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/accept-encoding-multiple" -hdr "Accept-Encoding: first,second"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/accept-encoding-multiple" -hdr "Accept-Encoding: second,first"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/accept-encoding-multiple" -hdr "Accept-Encoding: FirsT,SECOND,first"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 1
+
+ # Unmanaged vary
+ txreq -url "/unmanaged" -hdr "Accept-Encoding: first_value"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/unmanaged" -hdr "Accept-Encoding: first_value"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 0
+
+
+ # Mixed Vary (Accept-Encoding + Referer)
+ txreq -url "/referer-accept-encoding" \
+ -hdr "Accept-Encoding: br, gzip" \
+ -hdr "Referer: referer"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/referer-accept-encoding" \
+ -hdr "Accept-Encoding: br" \
+ -hdr "Referer: other-referer"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 54
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/referer-accept-encoding" \
+ -hdr "Accept-Encoding: gzip" \
+ -hdr "Referer: other-referer"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 57
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/referer-accept-encoding" \
+ -hdr "Referer: referer" \
+ -hdr "Accept-Encoding: gzip, br"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 51
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/referer-accept-encoding" \
+ -hdr "Accept-Encoding: br" \
+ -hdr "Referer: other-referer"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 54
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/referer-accept-encoding" \
+ -hdr "Accept-Encoding: gzip" \
+ -hdr "Referer: other-referer"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 57
+ expect resp.http.X-Cache-Hit == 1
+
+
+ # Mixed Vary (Accept-Encoding + Referer + Origin)
+ txreq -url "/origin-referer-accept-encoding" \
+ -hdr "Accept-Encoding: br, gzip" \
+ -hdr "Referer: referer" \
+ -hdr "Origin: origin"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 58
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/origin-referer-accept-encoding" \
+ -hdr "Accept-Encoding: br, gzip" \
+ -hdr "Referer: referer" \
+ -hdr "Origin: origin"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 58
+ expect resp.http.X-Cache-Hit == 1
+
+ txreq -url "/origin-referer-accept-encoding" \
+ -hdr "Accept-Encoding: br, gzip" \
+ -hdr "Referer: referer" \
+ -hdr "Origin: other-origin"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 59
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/origin-referer-accept-encoding" \
+ -hdr "Accept-Encoding: br, gzip" \
+ -hdr "Referer: referer" \
+ -hdr "Origin: other-origin"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 59
+ expect resp.http.X-Cache-Hit == 1
+
+ # Multiple Accept-encoding headers
+ txreq -url "/multiple_headers" \
+ -hdr "Accept-Encoding: gzip" \
+ -hdr "Accept-Encoding: br, deflate"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 155
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/multiple_headers" \
+ -hdr "Accept-Encoding: deflate" \
+ -hdr "Accept-Encoding: br,gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 155
+ expect resp.http.X-Cache-Hit == 1
+
+ # Should not match a cache entry
+ txreq -url "/multiple_headers" \
+ -hdr "Accept-Encoding: first_encoding"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 166
+ expect resp.http.X-Cache-Hit == 0
+
+ # Too many accept encodings
+ txreq -url "/too_many_encodings" \
+ -hdr "Accept-Encoding: a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 177
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/too_many_encodings" \
+ -hdr "Accept-Encoding: a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 188
+ expect resp.http.X-Cache-Hit == 0
+
+ # A missing 'Accept-Encoding' implies that anything is acceptable,
+ # while an empty 'Accept-Encoding' implies nothing is acceptable.
+
+ # Start by caching a gzip response.
+ txreq -url "/empty-vs-missing" -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 234
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.X-Cache-Hit == 0
+
+ # Check that it is cached.
+ txreq -url "/empty-vs-missing" -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 234
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.X-Cache-Hit == 1
+
+ # Check that the cached response is returned when no accept-encoding is
+ # specified.
+ txreq -url "/empty-vs-missing"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 234
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.X-Cache-Hit == 1
+
+ # Check that the cached response is not returned when an empty
+ # accept-encoding is specified.
+ txreq -url "/empty-vs-missing" -hdr "Accept-Encoding:"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 256
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.X-Cache-Hit == 0
+
+ # The following requests are treated by a backend that does not cache
+ # responses containing a Vary header
+ txreq -url "/no_vary_support"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 57
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/no_vary_support"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 57
+ expect resp.http.X-Cache-Hit == 0
+
+
+} -run
diff --git a/reg-tests/cache/vary_accept_encoding.vtc b/reg-tests/cache/vary_accept_encoding.vtc
new file mode 100644
index 0000000..4b828a8
--- /dev/null
+++ b/reg-tests/cache/vary_accept_encoding.vtc
@@ -0,0 +1,333 @@
+varnishtest "Check the Accept-Encoding processing implemented in the Vary mechanism"
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+server s1 {
+ # Response varying on "accept-encoding" with a gzip content-encoding
+ rxreq
+ expect req.url == "/accept-encoding"
+ txresp -hdr "Content-Encoding: gzip" \
+ -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 45
+
+ # Response varying on "accept-encoding" with a deflate content-encoding
+ rxreq
+ expect req.url == "/accept-encoding"
+ txresp -hdr "Content-Encoding: deflate" \
+ -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 55
+
+
+ # Response varying on "accept-encoding" with no content-encoding (identity)
+ rxreq
+ expect req.url == "/accept-encoding-identity"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 65
+
+ # Response varying on "accept-encoding" with refused identity encoding
+ rxreq
+ expect req.url == "/accept-encoding-identity"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: deflate" \
+ -bodylen 75
+
+
+ rxreq
+ expect req.url == "/accept-encoding-star"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: br" \
+ -bodylen 89
+
+ rxreq
+ expect req.url == "/accept-encoding-star"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: deflate" \
+ -bodylen 99
+
+
+ rxreq
+ expect req.url == "/multiple-content-encoding"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: deflate, gzip" \
+ -bodylen 109
+
+ rxreq
+ expect req.url == "/unknown-content-encoding"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: unknown_encoding" \
+ -bodylen 119
+
+ rxreq
+ expect req.url == "/unknown-content-encoding"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: unknown_encoding" \
+ -bodylen 119
+
+
+ rxreq
+ expect req.url == "/hash-collision"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: br" \
+ -bodylen 129
+
+ rxreq
+ expect req.url == "/hash-collision"
+ txresp -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5" \
+ -hdr "Content-Encoding: gzip" \
+ -bodylen 139
+} -start
+
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ default_backend test
+
+ backend test
+ http-request cache-use my_cache
+ server www ${s1_addr}:${s1_port}
+ http-response cache-store my_cache
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+
+ cache my_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+ process-vary on
+} -start
+
+
+client c1 -connect ${h1_fe_sock} {
+ #
+ # Accept-Encoding Vary
+ #
+
+ # First request
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.bodylen == 45
+
+ # Regular case
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.bodylen == 45
+ expect resp.http.X-Cache-Hit == 1
+
+ # Regular case with upper case encoding
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: GZIP"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.bodylen == 45
+ expect resp.http.X-Cache-Hit == 1
+
+ # Multiple accepted encodings (all standard)
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: deflate,gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.bodylen == 45
+ expect resp.http.X-Cache-Hit == 1
+
+ # Multiple accept-encoding headers + non-standard accepted encodings
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: first_encoding,second_encoding" -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.bodylen == 45
+ expect resp.http.X-Cache-Hit == 1
+
+ # Regular case with positive weight
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: gzip;q=0.8"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.bodylen == 45
+ expect resp.http.X-Cache-Hit == 1
+
+ # Regular case with positive weight and extra whitespaces
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: gzip ; q=0.8"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.bodylen == 45
+ expect resp.http.X-Cache-Hit == 1
+
+ # Regular case with null weight
+ txreq -url "/accept-encoding" -hdr "Accept-Encoding: deflate;q=0.8, gzip;q=0"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "deflate"
+ expect resp.bodylen == 55
+ expect resp.http.X-Cache-Hit == 0
+
+
+ #
+ # Identity tests
+ #
+ txreq -url "/accept-encoding-identity"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.bodylen == 65
+ expect resp.http.X-Cache-Hit == 0
+
+ # Regular case
+ txreq -url "/accept-encoding-identity"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.bodylen == 65
+ expect resp.http.X-Cache-Hit == 1
+
+ # Identity is allowed by default even if another encoding is specified
+ txreq -url "/accept-encoding-identity" -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.bodylen == 65
+ expect resp.http.X-Cache-Hit == 1
+
+ # Refused identity encoding (explicit null weight)
+ txreq -url "/accept-encoding-identity" -hdr "Accept-Encoding: deflate, identity;q=0"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "deflate"
+ expect resp.bodylen == 75
+ expect resp.http.X-Cache-Hit == 0
+
+
+ #
+ # Star tests
+ #
+ txreq -url "/accept-encoding-star" -hdr "Accept-Encoding: *"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "br"
+ expect resp.bodylen == 89
+ expect resp.http.X-Cache-Hit == 0
+
+ # Regular case
+ txreq -url "/accept-encoding-star" -hdr "Accept-Encoding: *"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "br"
+ expect resp.bodylen == 89
+ expect resp.http.X-Cache-Hit == 1
+
+ # Reject some encodings
+ txreq -url "/accept-encoding-star" -hdr "Accept-Encoding: gzip;q=0, deflate,*"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "br"
+ expect resp.bodylen == 89
+ expect resp.http.X-Cache-Hit == 1
+
+ # Weighted star
+ txreq -url "/accept-encoding-star" -hdr "Accept-Encoding: gzip;q=0, deflate,*;q=0.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "br"
+ expect resp.bodylen == 89
+ expect resp.http.X-Cache-Hit == 1
+
+ # Rejected identity
+ txreq -url "/accept-encoding-star" -hdr "Accept-Encoding: gzip;q=0, deflate,*;q=0.1,identity;q=0"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "br"
+ expect resp.bodylen == 89
+ expect resp.http.X-Cache-Hit == 1
+
+ # Rejected star and "br" not accepted
+ txreq -url "/accept-encoding-star" -hdr "Accept-Encoding: gzip;q=0, deflate,*;q=0"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "deflate"
+ expect resp.bodylen == 99
+ expect resp.http.X-Cache-Hit == 0
+
+
+ #
+ # Multiple content-encodings
+ #
+ txreq -url "/multiple-content-encoding" -hdr "Accept-Encoding: gzip;q=0.8, deflate"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "deflate, gzip"
+ expect resp.bodylen == 109
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/multiple-content-encoding" -hdr "Accept-Encoding: deflate,gzip;q=0.7"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "deflate, gzip"
+ expect resp.bodylen == 109
+ expect resp.http.X-Cache-Hit == 1
+
+
+ #
+ # Unknown content-encoding
+ # The response should not be cached since it has an unknown content encoding
+ #
+ txreq -url "/unknown-content-encoding" -hdr "Accept-Encoding: gzip;q=0.8, deflate, first_encoding"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "unknown_encoding"
+ expect resp.bodylen == 119
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/unknown-content-encoding" -hdr "Accept-Encoding: deflate,gzip;q=0.8, first_encoding"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "unknown_encoding"
+ expect resp.bodylen == 119
+ expect resp.http.X-Cache-Hit == 0
+
+ #
+ # Hash collision (https://github.com/haproxy/haproxy/issues/988)
+ #
+ # crc32(gzip) ^ crc32(br) ^ crc32(xxx) ^ crc32(jdcqiab) == crc32(gzip)
+ txreq -url "/hash-collision" -hdr "Accept-Encoding: br,gzip,xxx,jdcqiab"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "br"
+ expect resp.bodylen == 129
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/hash-collision" -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.bodylen == 139
+ expect resp.http.X-Cache-Hit == 0
+} -run
diff --git a/reg-tests/checks/1be_40srv_odd_health_checks.vtc b/reg-tests/checks/1be_40srv_odd_health_checks.vtc
new file mode 100644
index 0000000..d0f3be5
--- /dev/null
+++ b/reg-tests/checks/1be_40srv_odd_health_checks.vtc
@@ -0,0 +1,117 @@
+varnishtest "Health-checks: only for servers with 'check' set"
+feature ignore_unknown_macro
+
+# This test start 40 servers in the same backend, named srv0 up to srv39.
+# Only the odd servers have health-checks enabled.
+# The first health-checks passed tests are checked for all these servers
+# thanks to syslog messages.
+
+#REQUIRE_VERSION=2.4
+#EXCLUDE_TARGETS=freebsd
+#REGTEST_TYPE=slow
+
+syslog S -repeat 20 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv([13579]|[123][13579]) succeeded.+reason: Layer4 check passed.+check duration: [[:digit:]]+ms.+status: 1/1 UP"
+} -start
+
+server s0 {} -start
+server s1 {} -start
+server s2 {} -start
+server s3 {} -start
+server s4 {} -start
+server s5 {} -start
+server s6 {} -start
+server s7 {} -start
+server s8 {} -start
+server s9 {} -start
+server s10 {} -start
+server s11 {} -start
+server s12 {} -start
+server s13 {} -start
+server s14 {} -start
+server s15 {} -start
+server s16 {} -start
+server s17 {} -start
+server s18 {} -start
+server s19 {} -start
+server s20 {} -start
+server s21 {} -start
+server s22 {} -start
+server s23 {} -start
+server s24 {} -start
+server s25 {} -start
+server s26 {} -start
+server s27 {} -start
+server s28 {} -start
+server s29 {} -start
+server s30 {} -start
+server s31 {} -start
+server s32 {} -start
+server s33 {} -start
+server s34 {} -start
+server s35 {} -start
+server s36 {} -start
+server s37 {} -start
+server s38 {} -start
+server s39 {} -start
+
+haproxy h1 -conf {
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ default-server no-check inter 200ms downinter 100ms rise 1 fall 1
+
+ backend be1
+ option log-health-checks
+ log ${S_addr}:${S_port} daemon
+ server srv0 ${s0_addr}:${s0_port}
+ server srv1 ${s1_addr}:${s1_port} check
+ server srv2 ${s2_addr}:${s2_port}
+ server srv3 ${s3_addr}:${s3_port} check
+ server srv4 ${s4_addr}:${s4_port}
+ server srv5 ${s5_addr}:${s5_port} check
+ server srv6 ${s6_addr}:${s6_port}
+ server srv7 ${s7_addr}:${s7_port} check
+ server srv8 ${s8_addr}:${s8_port}
+ server srv9 ${s9_addr}:${s9_port} check
+ server srv10 ${s10_addr}:${s10_port}
+ server srv11 ${s11_addr}:${s11_port} check
+ server srv12 ${s12_addr}:${s12_port}
+ server srv13 ${s13_addr}:${s13_port} check
+ server srv14 ${s14_addr}:${s14_port}
+ server srv15 ${s15_addr}:${s15_port} check
+ server srv16 ${s16_addr}:${s16_port}
+ server srv17 ${s17_addr}:${s17_port} check
+ server srv18 ${s18_addr}:${s18_port}
+ server srv19 ${s19_addr}:${s19_port} check
+ server srv20 ${s20_addr}:${s20_port}
+ server srv21 ${s21_addr}:${s21_port} check
+ server srv22 ${s22_addr}:${s22_port}
+ server srv23 ${s23_addr}:${s23_port} check
+ server srv24 ${s24_addr}:${s24_port}
+ server srv25 ${s25_addr}:${s25_port} check
+ server srv26 ${s26_addr}:${s26_port}
+ server srv27 ${s27_addr}:${s27_port} check
+ server srv28 ${s28_addr}:${s28_port}
+ server srv29 ${s29_addr}:${s29_port} check
+ server srv30 ${s30_addr}:${s30_port}
+ server srv31 ${s31_addr}:${s31_port} check
+ server srv32 ${s32_addr}:${s32_port}
+ server srv33 ${s33_addr}:${s33_port} check
+ server srv34 ${s34_addr}:${s34_port}
+ server srv35 ${s35_addr}:${s35_port} check
+ server srv36 ${s36_addr}:${s36_port}
+ server srv37 ${s37_addr}:${s37_port} check
+ server srv38 ${s38_addr}:${s38_port}
+ server srv39 ${s39_addr}:${s39_port} check
+} -start
+
+syslog S -wait
+
+haproxy h1 -cli {
+ send "show servers state"
+ expect ~ "# be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_result srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id srv_fqdn srv_port srvrecord srv_use_ssl srv_check_port srv_check_addr srv_agent_addr srv_agent_port\n2 be1 1 srv0 ${s0_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s0_port} - 0 0 - - 0\n2 be1 2 srv1 ${s1_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s1_port} - 0 0 - - 0\n2 be1 3 srv2 ${s2_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s2_port} - 0 0 - - 0\n2 be1 4 srv3 ${s3_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s3_port} - 0 0 - - 0\n2 be1 5 srv4 ${s4_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s4_port} - 0 0 - - 0\n2 be1 6 srv5 ${s5_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s5_port} - 0 0 - - 0\n2 be1 7 srv6 ${s6_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s6_port} - 0 0 - - 0\n2 be1 8 srv7 ${s7_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s7_port} - 0 0 - - 0\n2 be1 9 srv8 ${s8_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s8_port} - 0 0 - - 0\n2 be1 10 srv9 ${s9_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s9_port} - 0 0 - - 0\n2 be1 11 srv10 ${s10_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s10_port} - 0 0 - - 0\n2 be1 12 srv11 ${s11_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s11_port} - 0 0 - - 0\n2 be1 13 srv12 ${s12_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s12_port} - 0 0 - - 0\n2 be1 14 srv13 ${s13_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s13_port} - 0 0 - - 0\n2 be1 15 srv14 ${s14_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s14_port} - 0 0 - - 0\n2 be1 16 srv15 ${s15_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s15_port} - 0 0 - - 0\n2 be1 17 srv16 ${s16_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s16_port} - 0 0 - - 0\n2 be1 18 srv17 ${s17_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s17_port} - 0 0 - - 0\n2 be1 19 srv18 ${s18_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s18_port} - 0 0 - - 0\n2 be1 20 srv19 ${s19_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s19_port} - 0 0 - - 0\n2 be1 21 srv20 ${s20_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s20_port} - 0 0 - - 0\n2 be1 22 srv21 ${s21_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s21_port} - 0 0 - - 0\n2 be1 23 srv22 ${s22_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s22_port} - 0 0 - - 0\n2 be1 24 srv23 ${s23_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s23_port} - 0 0 - - 0\n2 be1 25 srv24 ${s24_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s24_port} - 0 0 - - 0\n2 be1 26 srv25 ${s25_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s25_port} - 0 0 - - 0\n2 be1 27 srv26 ${s26_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s26_port} - 0 0 - - 0\n2 be1 28 srv27 ${s27_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s27_port} - 0 0 - - 0\n2 be1 29 srv28 ${s28_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s28_port} - 0 0 - - 0\n2 be1 30 srv29 ${s29_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s29_port} - 0 0 - - 0\n2 be1 31 srv30 ${s30_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s30_port} - 0 0 - - 0\n2 be1 32 srv31 ${s31_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s31_port} - 0 0 - - 0\n2 be1 33 srv32 ${s32_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s32_port} - 0 0 - - 0\n2 be1 34 srv33 ${s33_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s33_port} - 0 0 - - 0\n2 be1 35 srv34 ${s34_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s34_port} - 0 0 - - 0\n2 be1 36 srv35 ${s35_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s35_port} - 0 0 - - 0\n2 be1 37 srv36 ${s36_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s36_port} - 0 0 - - 0\n2 be1 38 srv37 ${s37_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s37_port} - 0 0 - - 0\n2 be1 39 srv38 ${s38_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s38_port} - 0 0 - - 0\n2 be1 40 srv39 ${s39_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s39_port} - 0 0 - - 0\n"
+}
+
diff --git a/reg-tests/checks/40be_2srv_odd_health_checks.vtc b/reg-tests/checks/40be_2srv_odd_health_checks.vtc
new file mode 100644
index 0000000..cbd4fc0
--- /dev/null
+++ b/reg-tests/checks/40be_2srv_odd_health_checks.vtc
@@ -0,0 +1,645 @@
+varnishtest "Health-checks"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+#EXCLUDE_TARGETS=freebsd,osx,generic
+#REGTEST_TYPE=slow
+
+# This script start 40 servers named s0 up to s39.
+# For 0 <= i <= 19:
+# - s(i) and s(i+1) belong to backend be(2*i+1),
+# - fe(2*i+1) backend is configured to used be(2*i+1) backend.
+# - only s(2*i+1) servers have health-checks enabled,
+# - we start 20 clients named s(2*i+1) which connect to fe(2*i+1) frontend,
+# - so that to ensure that health-checks do not consume any connection
+# (any varnishtest server without -repeat <n> with n > 1 accepts
+# only one connection).
+# - we take care of sending the clients to the unchecked servers using the
+# "first" lb algo so that servers always receive a valid request
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv3 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S5 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be5/srv5 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S7 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be7/srv7 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S9 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be9/srv9 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S11 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be11/srv11 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S13 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be13/srv13 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S15 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be15/srv15 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S17 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be17/srv17 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S19 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be19/srv19 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S21 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be21/srv21 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S23 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be23/srv23 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S25 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be25/srv25 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S27 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be27/srv27 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S29 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be29/srv29 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S31 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be31/srv31 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S33 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be33/srv33 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S35 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be35/srv35 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S37 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be37/srv37 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+syslog S39 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be39/srv39 succeeded, reason: Layer4 check passed, check duration: [[:digit:]]+ms, status: 1/1 UP"
+} -start
+
+server s0 {
+ rxreq
+ txresp
+} -start
+
+server s2 {
+ rxreq
+ txresp
+} -start
+
+server s4 {
+ rxreq
+ txresp
+} -start
+
+server s6 {
+ rxreq
+ txresp
+} -start
+
+server s8 {
+ rxreq
+ txresp
+} -start
+
+server s10 {
+ rxreq
+ txresp
+} -start
+
+server s12 {
+ rxreq
+ txresp
+} -start
+
+server s14 {
+ rxreq
+ txresp
+} -start
+
+server s16 {
+ rxreq
+ txresp
+} -start
+
+server s18 {
+ rxreq
+ txresp
+} -start
+
+server s20 {
+ rxreq
+ txresp
+} -start
+
+server s22 {
+ rxreq
+ txresp
+} -start
+
+server s24 {
+ rxreq
+ txresp
+} -start
+
+server s26 {
+ rxreq
+ txresp
+} -start
+
+server s28 {
+ rxreq
+ txresp
+} -start
+
+server s30 {
+ rxreq
+ txresp
+} -start
+
+server s32 {
+ rxreq
+ txresp
+} -start
+
+server s34 {
+ rxreq
+ txresp
+} -start
+
+server s36 {
+ rxreq
+ txresp
+} -start
+
+server s38 {
+ rxreq
+ txresp
+} -start
+
+server s1 {} -start
+server s3 {} -start
+server s5 {} -start
+server s7 {} -start
+server s9 {} -start
+server s11 {} -start
+server s13 {} -start
+server s15 {} -start
+server s17 {} -start
+server s19 {} -start
+server s21 {} -start
+server s23 {} -start
+server s25 {} -start
+server s27 {} -start
+server s29 {} -start
+server s31 {} -start
+server s33 {} -start
+server s35 {} -start
+server s37 {} -start
+server s39 {} -start
+
+haproxy h1 -conf {
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ balance first
+ default-server no-check inter 20ms downinter 1s rise 1 fall 1
+
+ backend be1
+ option log-health-checks
+ log ${S1_addr}:${S1_port} daemon
+ server srv0 ${s0_addr}:${s0_port}
+ server srv1 ${s1_addr}:${s1_port} check
+
+ backend be3
+ option log-health-checks
+ log ${S3_addr}:${S3_port} daemon
+ server srv2 ${s2_addr}:${s2_port}
+ server srv3 ${s3_addr}:${s3_port} check
+
+ backend be5
+ option log-health-checks
+ log ${S5_addr}:${S5_port} daemon
+ server srv4 ${s4_addr}:${s4_port}
+ server srv5 ${s5_addr}:${s5_port} check
+
+ backend be7
+ option log-health-checks
+ log ${S7_addr}:${S7_port} daemon
+ server srv6 ${s6_addr}:${s6_port}
+ server srv7 ${s7_addr}:${s7_port} check
+
+ backend be9
+ option log-health-checks
+ log ${S9_addr}:${S9_port} daemon
+ server srv8 ${s8_addr}:${s8_port}
+ server srv9 ${s9_addr}:${s9_port} check
+
+ backend be11
+ option log-health-checks
+ log ${S11_addr}:${S11_port} daemon
+ server srv10 ${s10_addr}:${s10_port}
+ server srv11 ${s11_addr}:${s11_port} check
+
+ backend be13
+ option log-health-checks
+ log ${S13_addr}:${S13_port} daemon
+ server srv12 ${s12_addr}:${s12_port}
+ server srv13 ${s13_addr}:${s13_port} check
+
+ backend be15
+ option log-health-checks
+ log ${S15_addr}:${S15_port} daemon
+ server srv14 ${s14_addr}:${s14_port}
+ server srv15 ${s15_addr}:${s15_port} check
+
+ backend be17
+ option log-health-checks
+ log ${S17_addr}:${S17_port} daemon
+ server srv16 ${s16_addr}:${s16_port}
+ server srv17 ${s17_addr}:${s17_port} check
+
+ backend be19
+ option log-health-checks
+ log ${S19_addr}:${S19_port} daemon
+ server srv18 ${s18_addr}:${s18_port}
+ server srv19 ${s19_addr}:${s19_port} check
+
+ backend be21
+ option log-health-checks
+ log ${S21_addr}:${S21_port} daemon
+ server srv20 ${s20_addr}:${s20_port}
+ server srv21 ${s21_addr}:${s21_port} check
+
+ backend be23
+ option log-health-checks
+ log ${S23_addr}:${S23_port} daemon
+ server srv22 ${s22_addr}:${s22_port}
+ server srv23 ${s23_addr}:${s23_port} check
+
+ backend be25
+ option log-health-checks
+ log ${S25_addr}:${S25_port} daemon
+ server srv24 ${s24_addr}:${s24_port}
+ server srv25 ${s25_addr}:${s25_port} check
+
+ backend be27
+ option log-health-checks
+ log ${S27_addr}:${S27_port} daemon
+ server srv26 ${s26_addr}:${s26_port}
+ server srv27 ${s27_addr}:${s27_port} check
+
+ backend be29
+ option log-health-checks
+ log ${S29_addr}:${S29_port} daemon
+ server srv28 ${s28_addr}:${s28_port}
+ server srv29 ${s29_addr}:${s29_port} check
+
+ backend be31
+ option log-health-checks
+ log ${S31_addr}:${S31_port} daemon
+ server srv30 ${s30_addr}:${s30_port}
+ server srv31 ${s31_addr}:${s31_port} check
+
+ backend be33
+ option log-health-checks
+ log ${S33_addr}:${S33_port} daemon
+ server srv32 ${s32_addr}:${s32_port}
+ server srv33 ${s33_addr}:${s33_port} check
+
+ backend be35
+ option log-health-checks
+ log ${S35_addr}:${S35_port} daemon
+ server srv34 ${s34_addr}:${s34_port}
+ server srv35 ${s35_addr}:${s35_port} check
+
+ backend be37
+ option log-health-checks
+ log ${S37_addr}:${S37_port} daemon
+ server srv36 ${s36_addr}:${s36_port}
+ server srv37 ${s37_addr}:${s37_port} check
+
+ backend be39
+ option log-health-checks
+ log ${S39_addr}:${S39_port} daemon
+ server srv38 ${s38_addr}:${s38_port}
+ server srv39 ${s39_addr}:${s39_port} check
+
+ frontend fe1
+ bind "fd@${fe1}"
+ use_backend be1
+
+ frontend fe3
+ bind "fd@${fe3}"
+ use_backend be3
+
+ frontend fe5
+ bind "fd@${fe5}"
+ use_backend be5
+
+ frontend fe7
+ bind "fd@${fe7}"
+ use_backend be7
+
+ frontend fe9
+ bind "fd@${fe9}"
+ use_backend be9
+
+ frontend fe11
+ bind "fd@${fe11}"
+ use_backend be11
+
+ frontend fe13
+ bind "fd@${fe13}"
+ use_backend be13
+
+ frontend fe15
+ bind "fd@${fe15}"
+ use_backend be15
+
+ frontend fe17
+ bind "fd@${fe17}"
+ use_backend be17
+
+ frontend fe19
+ bind "fd@${fe19}"
+ use_backend be19
+
+ frontend fe21
+ bind "fd@${fe21}"
+ use_backend be21
+
+ frontend fe23
+ bind "fd@${fe23}"
+ use_backend be23
+
+ frontend fe25
+ bind "fd@${fe25}"
+ use_backend be25
+
+ frontend fe27
+ bind "fd@${fe27}"
+ use_backend be27
+
+ frontend fe29
+ bind "fd@${fe29}"
+ use_backend be29
+
+ frontend fe31
+ bind "fd@${fe31}"
+ use_backend be31
+
+ frontend fe33
+ bind "fd@${fe33}"
+ use_backend be33
+
+ frontend fe35
+ bind "fd@${fe35}"
+ use_backend be35
+
+ frontend fe37
+ bind "fd@${fe37}"
+ use_backend be37
+
+ frontend fe39
+ bind "fd@${fe39}"
+ use_backend be39
+} -start
+
+# This is a sort of synchronization: after having waited for all the syslog
+# servers we are sure that all the health-checks have succeeded.
+syslog S1 -wait
+syslog S3 -wait
+syslog S5 -wait
+syslog S7 -wait
+syslog S9 -wait
+syslog S11 -wait
+syslog S13 -wait
+syslog S15 -wait
+syslog S17 -wait
+syslog S19 -wait
+syslog S21 -wait
+syslog S23 -wait
+syslog S25 -wait
+syslog S27 -wait
+syslog S29 -wait
+syslog S31 -wait
+syslog S33 -wait
+syslog S35 -wait
+syslog S37 -wait
+syslog S39 -wait
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c3 -connect ${h1_fe3_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c5 -connect ${h1_fe5_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c7 -connect ${h1_fe7_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c9 -connect ${h1_fe9_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c11 -connect ${h1_fe11_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c13 -connect ${h1_fe13_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c15 -connect ${h1_fe15_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c17 -connect ${h1_fe17_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c19 -connect ${h1_fe19_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c21 -connect ${h1_fe21_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c23 -connect ${h1_fe23_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c25 -connect ${h1_fe25_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c27 -connect ${h1_fe27_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c29 -connect ${h1_fe29_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c31 -connect ${h1_fe31_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c33 -connect ${h1_fe33_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c35 -connect ${h1_fe35_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c37 -connect ${h1_fe37_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c39 -connect ${h1_fe39_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+client c1 -wait
+client c3 -wait
+client c5 -wait
+client c7 -wait
+client c9 -wait
+client c11 -wait
+client c13 -wait
+client c15 -wait
+client c17 -wait
+client c19 -wait
+client c21 -wait
+client c23 -wait
+client c25 -wait
+client c27 -wait
+client c29 -wait
+client c31 -wait
+client c33 -wait
+client c35 -wait
+client c37 -wait
+client c39 -wait
+
+server s0 -wait
+server s2 -wait
+server s4 -wait
+server s6 -wait
+server s8 -wait
+server s10 -wait
+server s12 -wait
+server s14 -wait
+server s16 -wait
+server s18 -wait
+server s20 -wait
+server s22 -wait
+server s24 -wait
+server s26 -wait
+server s28 -wait
+server s30 -wait
+server s32 -wait
+server s34 -wait
+server s36 -wait
+server s38 -wait
+
+
+haproxy h1 -cli {
+ send "show servers state"
+ # output produced using the command below (warning, a bug inserts a "be0" every other line:
+ # for ((i=0;i<40;i++)); do id=$((i/2+2)); be=$((i|1)); si=$(((i&1)+1));
+ # if ((i&1)); then chk="6 ([[:digit:]]+ ){3}"; else chk="1 0 1 0 ";fi;
+ # printf "%d be%d %d srv%d \${s%d_addr} 2 0 1 1 [[:digit:]]+ %s0 0 0 - \${s%d_port} - 0 0 - - 0\n" "$id" "$be" "$si" "$i" "$i" "$chk" "$i" "$i" ;
+ # done|grep -v be0|sed 's,$,\\n,'| tr -d '\n'
+ expect ~ "# be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_result srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id srv_fqdn srv_port srvrecord srv_use_ssl srv_check_port srv_check_addr srv_agent_addr srv_agent_port\n2 be1 1 srv0 ${s0_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s0_port} - 0 0 - - 0\n2 be1 2 srv1 ${s1_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s1_port} - 0 0 - - 0\n3 be3 1 srv2 ${s2_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s2_port} - 0 0 - - 0\n3 be3 2 srv3 ${s3_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s3_port} - 0 0 - - 0\n4 be5 1 srv4 ${s4_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s4_port} - 0 0 - - 0\n4 be5 2 srv5 ${s5_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s5_port} - 0 0 - - 0\n5 be7 1 srv6 ${s6_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s6_port} - 0 0 - - 0\n5 be7 2 srv7 ${s7_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s7_port} - 0 0 - - 0\n6 be9 1 srv8 ${s8_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s8_port} - 0 0 - - 0\n6 be9 2 srv9 ${s9_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s9_port} - 0 0 - - 0\n7 be11 1 srv10 ${s10_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s10_port} - 0 0 - - 0\n7 be11 2 srv11 ${s11_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s11_port} - 0 0 - - 0\n8 be13 1 srv12 ${s12_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s12_port} - 0 0 - - 0\n8 be13 2 srv13 ${s13_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s13_port} - 0 0 - - 0\n9 be15 1 srv14 ${s14_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s14_port} - 0 0 - - 0\n9 be15 2 srv15 ${s15_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s15_port} - 0 0 - - 0\n10 be17 1 srv16 ${s16_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s16_port} - 0 0 - - 0\n10 be17 2 srv17 ${s17_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s17_port} - 0 0 - - 0\n11 be19 1 srv18 ${s18_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s18_port} - 0 0 - - 0\n11 be19 2 srv19 ${s19_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s19_port} - 0 0 - - 0\n12 be21 1 srv20 ${s20_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s20_port} - 0 0 - - 0\n12 be21 2 srv21 ${s21_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s21_port} - 0 0 - - 0\n13 be23 1 srv22 ${s22_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s22_port} - 0 0 - - 0\n13 be23 2 srv23 ${s23_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s23_port} - 0 0 - - 0\n14 be25 1 srv24 ${s24_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s24_port} - 0 0 - - 0\n14 be25 2 srv25 ${s25_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s25_port} - 0 0 - - 0\n15 be27 1 srv26 ${s26_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s26_port} - 0 0 - - 0\n15 be27 2 srv27 ${s27_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s27_port} - 0 0 - - 0\n16 be29 1 srv28 ${s28_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s28_port} - 0 0 - - 0\n16 be29 2 srv29 ${s29_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s29_port} - 0 0 - - 0\n17 be31 1 srv30 ${s30_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s30_port} - 0 0 - - 0\n17 be31 2 srv31 ${s31_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s31_port} - 0 0 - - 0\n18 be33 1 srv32 ${s32_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s32_port} - 0 0 - - 0\n18 be33 2 srv33 ${s33_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s33_port} - 0 0 - - 0\n19 be35 1 srv34 ${s34_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s34_port} - 0 0 - - 0\n19 be35 2 srv35 ${s35_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s35_port} - 0 0 - - 0\n20 be37 1 srv36 ${s36_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s36_port} - 0 0 - - 0\n20 be37 2 srv37 ${s37_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s37_port} - 0 0 - - 0\n21 be39 1 srv38 ${s38_addr} 2 0 1 1 [[:digit:]]+ 1 0 1 0 0 0 0 - ${s38_port} - 0 0 - - 0\n21 be39 2 srv39 ${s39_addr} 2 0 1 1 [[:digit:]]+ 6 ([[:digit:]]+ ){3}0 0 0 - ${s39_port} - 0 0 - - 0\n"
+}
+
diff --git a/reg-tests/checks/4be_1srv_health_checks.vtc b/reg-tests/checks/4be_1srv_health_checks.vtc
new file mode 100644
index 0000000..02564be
--- /dev/null
+++ b/reg-tests/checks/4be_1srv_health_checks.vtc
@@ -0,0 +1,201 @@
+varnishtest "Health-check test"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+#EXCLUDE_TARGETS=freebsd
+#REGTEST_TYPE=slow
+
+# This script test health-checks for four backends with one server by backend.
+# A syslog server is attached to each backend to check the syslog messages
+# in the right order.
+
+# First, we check a health-check has passed for all the servers thanks to the syslog
+# messages. Then each server is disabled. The health-check status are checked.
+# Then each server is re-enabled. Finally health-check status
+# verifications for each server terminate the execution of this script.
+
+# Note that the CLI is synchronized with the syslog servers so that
+# to be sure to receive the passed health-checks status messages before
+# disabling the servers. Same thing, when we check that the servers are down
+# before enabling the servers.
+
+# Cyclic barrier to synchronize the CLI with the syslog servers
+barrier b1 cond 5 -cyclic
+
+# These servers are there only for the health-check test.
+server s1 {
+} -start
+
+server s2 {
+} -start
+
+server s3 {
+} -start
+
+server s4 {
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 succeeded.+reason: Layer4 check passed.+check duration: [[:digit:]]+ms.+status: 1/1 UP"
+ barrier b1 sync
+ recv alert
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Server be1/srv1 is going DOWN for maintenance. 0 active and 0 backup servers left. [01] sessions active, 0 requeued, 0 remaining in queue."
+ recv emerg
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: backend be1 has no server available!"
+ barrier b1 sync
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: (Server be1/srv1 is UP/READY \\(leaving forced maintenance\\).|Health check for server be1/srv1 succeeded.+reason: Layer4 check passed.+check duration: [[:digit:]]+ms.+status: 1/1 UP)"
+ barrier b1 sync
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv2 succeeded.+reason: Layer4 check passed.+check duration: [[:digit:]]+ms.+status: 1/1 UP"
+ barrier b1 sync
+ recv alert
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Server be2/srv2 is going DOWN for maintenance. 0 active and 0 backup servers left. [01] sessions active, 0 requeued, 0 remaining in queue."
+ recv emerg
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: backend be2 has no server available!"
+ barrier b1 sync
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: (Server be2/srv2 is UP/READY \\(leaving forced maintenance\\).|Health check for server be2/srv2 succeeded.+reason: Layer4 check passed.+check duration: [[:digit:]]+ms.+status: 1/1 UP)"
+ barrier b1 sync
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv3 succeeded.+reason: Layer4 check passed.+check duration: [[:digit:]]+ms.+status: 1/1 UP"
+ barrier b1 sync
+ recv alert
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Server be3/srv3 is going DOWN for maintenance. 0 active and 0 backup servers left. [01] sessions active, 0 requeued, 0 remaining in queue."
+ recv emerg
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: backend be3 has no server available!"
+ barrier b1 sync
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: (Server be3/srv3 is UP/READY \\(leaving forced maintenance\\).|Health check for server be3/srv3 succeeded.+reason: Layer4 check passed.+check duration: [[:digit:]]+ms.+status: 1/1 UP)"
+ barrier b1 sync
+} -start
+
+syslog S4 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv4 succeeded.+reason: Layer4 check passed.+check duration: [[:digit:]]+ms.+status: 1/1 UP"
+ barrier b1 sync
+ recv alert
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Server be4/srv4 is going DOWN for maintenance. 0 active and 0 backup servers left. [01] sessions active, 0 requeued, 0 remaining in queue."
+ recv emerg
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: backend be4 has no server available!"
+ barrier b1 sync
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: (Server be4/srv4 is UP/READY \\(leaving forced maintenance\\).|Health check for server be4/srv4 succeeded.+reason: Layer4 check passed.+check duration: [[:digit:]]+ms.+status: 1/1 UP)"
+ barrier b1 sync
+} -start
+
+
+haproxy h1 -conf {
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ default-server check inter 200ms downinter 100s rise 1 fall 1
+
+ frontend fe1
+ bind "fd@${fe1}"
+ use_backend be1
+
+ frontend fe2
+ bind "fd@${fe2}"
+ use_backend be2
+
+ frontend fe3
+ bind "fd@${fe3}"
+ use_backend be3
+
+ frontend fe4
+ bind "fd@${fe4}"
+ use_backend be4
+
+ backend be1
+ option log-health-checks
+ log ${S1_addr}:${S1_port} daemon
+ server srv1 ${s1_addr}:${s1_port}
+
+ backend be2
+ option log-health-checks
+ log ${S2_addr}:${S2_port} daemon
+ server srv2 ${s2_addr}:${s2_port}
+
+ backend be3
+ option log-health-checks
+ log ${S3_addr}:${S3_port} daemon
+ server srv3 ${s3_addr}:${s3_port}
+
+ backend be4
+ option log-health-checks
+ log ${S4_addr}:${S4_port} daemon
+ server srv4 ${s4_addr}:${s4_port}
+} -start
+
+haproxy h1 -cli {
+ barrier b1 sync
+ send "show servers state"
+ expect ~ "# be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_result srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id srv_fqdn srv_port srvrecord srv_use_ssl srv_check_port srv_check_addr srv_agent_addr srv_agent_port\n6 be1 1 srv1 ${s1_addr} 2 0 1 1 [[:digit:]]+ 6 3 1 [67] 0 0 0 - ${s1_port} - 0 0 - - 0\n7 be2 1 srv2 ${s2_addr} 2 0 1 1 [[:digit:]]+ 6 3 1 [67] 0 0 0 - ${s2_port} - 0 0 - - 0\n8 be3 1 srv3 ${s3_addr} 2 0 1 1 [[:digit:]]+ 6 3 1 [67] 0 0 0 - ${s3_port} - 0 0 - - 0\n9 be4 1 srv4 ${s4_addr} 2 0 1 1 [[:digit:]]+ 6 3 1 [67] 0 0 0 - ${s4_port} - 0 0 - - 0"
+}
+
+haproxy h1 -cli {
+ send "disable server be1/srv1"
+ expect ~ .*
+}
+
+haproxy h1 -cli {
+ send "disable server be2/srv2"
+ expect ~ .*
+}
+
+haproxy h1 -cli {
+ send "disable server be3/srv3"
+ expect ~ .*
+}
+
+haproxy h1 -cli {
+ send "disable server be4/srv4"
+ expect ~ .*
+}
+
+haproxy h1 -cli {
+ barrier b1 sync
+ send "show servers state"
+ expect ~ "# be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_result srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id srv_fqdn srv_port srvrecord srv_use_ssl srv_check_port srv_check_addr srv_agent_addr srv_agent_port\n6 be1 1 srv1 ${s1_addr} 0 1 1 1 [[:digit:]]+ 6 3 [01] 1[45] 0 0 0 - ${s1_port} - 0 0 - - 0\n7 be2 1 srv2 ${s2_addr} 0 1 1 1 [[:digit:]]+ 6 3 [01] 1[45] 0 0 0 - ${s2_port} - 0 0 - - 0\n8 be3 1 srv3 ${s3_addr} 0 1 1 1 [[:digit:]]+ 6 3 [01] 1[45] 0 0 0 - ${s3_port} - 0 0 - - 0\n9 be4 1 srv4 ${s4_addr} 0 1 1 1 [[:digit:]]+ 6 3 [01] 1[45] 0 0 0 - ${s4_port} - 0 0 - - 0"
+}
+
+haproxy h1 -cli {
+ send "enable server be1/srv1"
+ expect ~ .*
+}
+
+haproxy h1 -cli {
+ send "enable server be2/srv2"
+ expect ~ .*
+}
+
+haproxy h1 -cli {
+ send "enable server be3/srv3"
+ expect ~ .*
+}
+
+haproxy h1 -cli {
+ send "enable server be4/srv4"
+ expect ~ .*
+}
+
+haproxy h1 -cli {
+ barrier b1 sync
+ send "show servers state"
+ expect ~ "# be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_result srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id srv_fqdn srv_port srvrecord srv_use_ssl srv_check_port srv_check_addr srv_agent_addr srv_agent_port\n6 be1 1 srv1 ${s1_addr} 2 0 1 1 [[:digit:]]+ 6 [03] 1 [67] 0 0 0 - ${s1_port} - 0 0 - - 0\n7 be2 1 srv2 ${s2_addr} 2 0 1 1 [[:digit:]]+ 6 [03] 1 [67] 0 0 0 - ${s2_port} - 0 0 - - 0\n8 be3 1 srv3 ${s3_addr} 2 0 1 1 [[:digit:]]+ 6 [03] 1 [67] 0 0 0 - ${s3_port} - 0 0 - - 0\n9 be4 1 srv4 ${s4_addr} 2 0 1 1 [[:digit:]]+ 6 [03] 1 [67] 0 0 0 - ${s4_port} - 0 0 - - 0"
+}
+
+syslog S1 -wait
+syslog S2 -wait
+syslog S3 -wait
+syslog S4 -wait
+
diff --git a/reg-tests/checks/4be_1srv_smtpchk_httpchk_layer47errors.vtc b/reg-tests/checks/4be_1srv_smtpchk_httpchk_layer47errors.vtc
new file mode 100644
index 0000000..3d36491
--- /dev/null
+++ b/reg-tests/checks/4be_1srv_smtpchk_httpchk_layer47errors.vtc
@@ -0,0 +1,100 @@
+varnishtest "Check: smptchk option"
+feature ignore_unknown_macro
+
+#EXCLUDE_TARGETS=freebsd,osx,generic
+#REGTEST_TYPE=slow
+
+barrier b cond 3
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 succeeded.+reason: Layer7 check passed.+code: 221.+check duration: [[:digit:]]+ms.+status: 1/1 UP."
+ barrier b sync
+ recv
+ expect ~ "Health check for server be1/srv1 failed.+reason: Layer7 timeout.+check duration: [[:digit:]]+ms.+status: 0/1 DOWN"
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv2 succeeded.+reason: Layer7 check passed.+code: 200.+.+check duration: [[:digit:]]+ms.+status: 1/1 UP."
+ barrier b sync
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv2 failed.+reason: Layer7 timeout.+check duration: [[:digit:]]+ms.+status: 0/1 DOWN"
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv3 failed.+reason: Layer4 connection problem.+info: \"General socket error \\(Network is unreachable\\)\".+check duration: [[:digit:]]+ms.+status: 0/1 DOWN."
+} -start
+
+syslog S4 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv4 failed.+reason: Layer4 connection problem.+info: \"Connection refused\".+check duration: [[:digit:]]+ms.+status: 0/1 DOWN."
+} -start
+
+server s1 {
+ send "2"
+ send "2"
+ send "0"
+ send "\r\n"
+ recv 16
+ send "2"
+ send "4"
+ send "8"
+ send "\r\n"
+ recv 6
+ send "2"
+ send "2"
+ send "1"
+ send " ok\r\n"
+} -start
+
+server s2 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ option log-health-checks
+ default-server inter 200ms downinter 100ms rise 1 fall 1
+
+ backend be1
+ option smtpchk
+ log ${S1_addr}:${S1_port} daemon
+ server srv1 ${s1_addr}:${s1_port} check
+
+ backend be2
+ mode tcp
+ log ${S2_addr}:${S2_port} daemon
+ option httpchk OPTIONS * HTTP/1.1
+ http-check send hdr Host www
+ server srv2 ${s2_addr}:${s2_port} check
+
+ backend be3
+ log ${S3_addr}:${S3_port} daemon
+ server srv3 255.255.255.255:11111 check
+
+ backend be4
+ log ${S4_addr}:${S4_port} daemon
+ server srv4 localhost:11111 check
+} -start
+
+haproxy h1 -cli {
+ barrier b sync
+ send "show servers state"
+ expect ~ .*
+}
+
+server s1 -wait
+server s2 -wait
+
+syslog S1 -wait
+syslog S2 -wait
+syslog S3 -wait
+syslog S4 -wait
+
+
diff --git a/reg-tests/checks/agent-check.vtc b/reg-tests/checks/agent-check.vtc
new file mode 100644
index 0000000..5cf51c6
--- /dev/null
+++ b/reg-tests/checks/agent-check.vtc
@@ -0,0 +1,42 @@
+varnishtest "Health-checks: agent-check"
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+barrier b1 cond 2 -cyclic
+barrier b2 cond 2 -cyclic
+
+server s1 {
+ barrier b1 sync
+ recv 5
+ send "75%,maxconn:30,maint,down\n"
+ expect_close
+ barrier b2 sync
+} -start
+
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ log ${S1_addr}:${S1_port} daemon
+ option log-health-checks
+ server srv ${s1_addr}:${s1_port} weight 100 agent-check agent-addr ${s1_addr} agent-port ${s1_port} agent-send "pouet" agent-inter 100ms
+} -start
+
+haproxy h1 -cli {
+ send "show servers state"
+ expect ~ "be1 1 srv 127.0.0.1 2 0 100 100 [[:digit:]]+ 1 0 [[:digit:]] 0 [[:digit:]]+ 0 0 - ${s1_port} -"
+ send "show stat"
+ expect ~ "be1,srv,0,0,0,0,,"
+
+ barrier b1 sync
+ barrier b2 sync
+ send "show servers state"
+ expect ~ "be1 1 srv 127.0.0.1 0 1 75 100 [[:digit:]]+ 1 0 [[:digit:]] 0 [[:digit:]]+ 0 0 - ${s1_port} -"
+ send "show stat"
+ expect ~ "be1,srv,0,0,0,0,30"
+}
diff --git a/reg-tests/checks/common.pem b/reg-tests/checks/common.pem
new file mode 120000
index 0000000..a4433d5
--- /dev/null
+++ b/reg-tests/checks/common.pem
@@ -0,0 +1 @@
+../ssl/common.pem \ No newline at end of file
diff --git a/reg-tests/checks/http-check-expect.vtc b/reg-tests/checks/http-check-expect.vtc
new file mode 100644
index 0000000..637eec6
--- /dev/null
+++ b/reg-tests/checks/http-check-expect.vtc
@@ -0,0 +1,64 @@
+varnishtest "Health-checks: some http-check expect tests"
+feature ignore_unknown_macro
+#REQUIRE_VERSION=2.2
+#REGTEST_TYPE=slow
+# This script tests http-check expect rules.
+
+server s1 {
+ rxreq
+ expect req.method == OPTIONS
+ expect req.url == /
+ expect req.proto == HTTP/1.0
+ txresp -status 202 \
+ -hdr "x-test1: true, next value" \
+ -hdr "x-test2: true, begin-value, value-end, value-sub-string, value-reg-123ABC" \
+ -hdr "x-begin-test: 1" \
+ -hdr "x-test-end: 1" \
+ -hdr "x-sub-test: 1" \
+ -hdr "x-reg-test1: 1" \
+ -hdr "x-hdr-name: x-test1"
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded.*code: 202"
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ option log-health-checks
+
+ backend be1
+ log ${S1_addr}:${S1_port} len 2048 local0
+ option httpchk
+ http-check expect status 200-399
+
+ http-check expect hdr name "x-test1"
+ http-check expect hdr name -m str "X-Test2"
+ http-check expect hdr name -m beg "X-Begin-"
+ http-check expect hdr name -m end "-End"
+ http-check expect hdr name -m sub "-Sub-"
+ http-check expect hdr name -m reg "^[a-z]+-Reg-[a-z]+[0-9]\$"
+ http-check set-var(check.hdr_name) res.fhdr(x-hdr-name)
+ http-check expect hdr name-lf -m str "%[var(check.hdr_name)]"
+ http-check expect hdr name-lf -m str "%[res.fhdr(x-hdr-name)]"
+
+ http-check expect fhdr name "x-test1" value "true, next value"
+ http-check expect hdr name "x-test2" value -m str "true"
+ http-check expect hdr name -m beg "x-test" value -m beg "begin-"
+ http-check expect hdr name -m beg "x-test" value -m end "-end"
+ http-check expect hdr name -m beg "x-test" value -m sub "-sub-"
+ http-check expect hdr name -m beg "x-test" value -m reg "^value-reg-[A-Z0-9]+\$"
+ http-check expect fhdr name -m beg "x-test" value -m reg "value-reg-[A-Z0-9]+"
+ http-check set-var(check.hdr_value) str(x-test1)
+ http-check expect hdr name -m beg "x-" value-lf -m str "%[var(check.hdr_value)]"
+ http-check expect fhdr name -m beg "x-" value-lf -m str "%[res.fhdr(x-hdr-name)]"
+
+ server srv ${s1_addr}:${s1_port} check inter 100ms rise 1 fall 1
+} -start
+
+syslog S1 -wait
diff --git a/reg-tests/checks/http-check-send.vtc b/reg-tests/checks/http-check-send.vtc
new file mode 100644
index 0000000..530ad75
--- /dev/null
+++ b/reg-tests/checks/http-check-send.vtc
@@ -0,0 +1,165 @@
+varnishtest "Health-checks: http-check send test"
+#REGTEST_TYPE=slow
+#REQUIRE_VERSION=2.4
+feature ignore_unknown_macro
+
+# This script tests HTTP health-checks and more particularly the "http-check
+# send" directive.
+
+server s1 {
+ rxreq
+ expect req.method == OPTIONS
+ expect req.url == /
+ expect req.proto == HTTP/1.0
+ txresp
+} -start
+
+server s2 {
+ rxreq
+ expect req.method == GET
+ expect req.url == /test
+ expect req.proto == HTTP/1.1
+ expect req.http.connection == "close"
+ txresp
+} -start
+
+server s3 {
+ rxreq
+ expect req.method == OPTIONS
+ expect req.url == /
+ expect req.proto == HTTP/1.0
+ expect req.http.host == <undef>
+ expect req.http.x-test == <undef>
+ expect req.bodylen == 0
+ txresp
+} -start
+
+server s4 {
+ rxreq
+ expect req.method == GET
+ expect req.url == /status
+ expect req.proto == HTTP/1.1
+ expect req.http.connection == "close"
+ expect req.http.host == "my-www-host"
+ expect req.http.x-test == true
+ expect req.http.content-length == 4
+ expect req.bodylen == 4
+ expect req.body == "test"
+ txresp
+} -start
+
+server s5 {
+ rxreq
+ expect req.method == OPTIONS
+ expect req.url == /
+ expect req.proto == HTTP/1.0
+ expect req.http.host == "other-www-host"
+ expect req.http.x-test == <undef>
+ expect req.http.x-new-test == true
+ expect req.http.content-length == 10
+ expect req.bodylen == 10
+ expect req.body == "other test"
+ txresp
+} -start
+
+server s6 {
+ rxreq
+ expect req.method == GET
+ expect req.url == /
+ expect req.proto == HTTP/1.1
+ expect req.http.host == "ws-host"
+ expect req.http.connection == "upgrade"
+ expect req.http.upgrade == "raw-proto"
+ txresp \
+ -status 101 \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: raw-proto"
+} -start
+
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded.*code: 200"
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv succeeded.*code: 200"
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv succeeded.*code: 200"
+} -start
+
+syslog S4 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv succeeded.*code: 200"
+} -start
+
+syslog S5 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be5/srv succeeded.*code: 200"
+} -start
+
+syslog S6 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be6_ws/srv succeeded.*code: 101"
+} -start
+
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ option httpchk
+ option log-health-checks
+
+ backend be1
+ log ${S1_addr}:${S1_port} len 2048 local0
+ server srv ${s1_addr}:${s1_port} check inter 200ms rise 1 fall 1
+
+ backend be2
+ log ${S2_addr}:${S2_port} len 2048 local0
+ option httpchk GET /test HTTP/1.1
+ server srv ${s2_addr}:${s2_port} check inter 200ms rise 1 fall 1
+
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ option httpchk GET /status HTTP/1.1
+ option log-health-checks
+ http-check send hdr Host "my-www-host" hdr X-test true body "test"
+
+ backend be3
+ option httpchk
+ log ${S3_addr}:${S3_port} len 2048 local0
+ server srv ${s3_addr}:${s3_port} check inter 200ms rise 1 fall 1
+
+ backend be4
+ log ${S4_addr}:${S4_port} len 2048 local0
+ server srv ${s4_addr}:${s4_port} check inter 200ms rise 1 fall 1
+
+ backend be5
+ log ${S5_addr}:${S5_port} len 2058 local0
+ http-check send hdr Host "other-www-host" hdr X-New-Test true body "other test"
+ server srv ${s5_addr}:${s5_port} check inter 200ms rise 1 fall 1
+
+ backend be6_ws
+ log ${S6_addr}:${S6_port} len 2048 local0
+ http-check send meth GET uri / ver HTTP/1.1 hdr host ws-host hdr connection upgrade hdr upgrade raw-proto
+ http-check expect status 101
+ server srv ${s6_addr}:${s6_port} check inter 200ms rise 1 fall 1
+
+} -start
+
+syslog S1 -wait
+syslog S2 -wait
+syslog S3 -wait
+syslog S4 -wait
+syslog S5 -wait
+syslog S6 -wait
diff --git a/reg-tests/checks/http-check.vtc b/reg-tests/checks/http-check.vtc
new file mode 100644
index 0000000..3353060
--- /dev/null
+++ b/reg-tests/checks/http-check.vtc
@@ -0,0 +1,157 @@
+varnishtest "Health-checks: some http-check tests"
+feature ignore_unknown_macro
+#REQUIRE_VERSION=2.2
+#REGTEST_TYPE=slow
+# This script tests HTTP health-checks.
+
+server s1 {
+ rxreq
+ expect req.method == OPTIONS
+ expect req.url == /
+ expect req.proto == HTTP/1.0
+ txresp
+} -start
+
+server s2 {
+ rxreq
+ expect req.method == GET
+ expect req.url == /status
+ expect req.proto == HTTP/1.1
+ txresp
+} -start
+
+server s3 {
+ rxreq
+ expect req.method == GET
+ expect req.url == /status
+ expect req.proto == HTTP/1.1
+ txresp
+} -start
+
+server s4 {
+ rxreq
+ expect req.method == GET
+ expect req.url == /req1
+ expect req.proto == HTTP/1.1
+ expect req.http.x-test == "server=srv"
+ expect req.http.x-haproxy-server-state ~ "UP.+name=be4/srv"
+ expect req.bodylen == 0
+ txresp
+
+ accept
+ rxreq
+ expect req.method == GET
+ expect req.url == /req2
+ expect req.proto == HTTP/1.1
+ expect req.http.x-test == "server="
+ expect req.http.x-haproxy-server-state ~ "UP.+name=be4/srv"
+ expect req.http.content-length == 17
+ expect req.bodylen == 17
+ expect req.body == "health-check body"
+ txresp
+
+ accept
+ rxreq
+ expect req.method == GET
+ expect req.url == /req3
+ expect req.proto == HTTP/1.0
+ expect req.http.x-test == <undef>
+ expect req.http.x-haproxy-server-state ~ "UP.+name=be4/srv"
+ expect req.bodylen == 0
+ txresp
+
+ accept
+ rxreq
+ expect req.method == GET
+ expect req.url == /
+ expect req.proto == HTTP/1.0
+ expect req.http.x-test == <undef>
+ expect req.http.x-haproxy-server-state ~ "UP.+name=be4/srv"
+ expect req.bodylen == 23
+ expect req.body == "health-check on be4-srv"
+ txresp
+
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]/srv succeeded.*code: 200"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]/srv succeeded.*code: 200"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]/srv succeeded.*code: 200"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]/srv succeeded.*code: 200"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]/srv succeeded.*code: 200"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]/srv succeeded.*code: 200"
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ option log-health-checks
+
+ backend be1
+ log ${S1_addr}:${S1_port} len 2048 local0
+ option httpchk
+ server srv ${s1_addr}:${s1_port} check inter 100ms rise 1 fall 1
+
+ backend be2
+ log ${S1_addr}:${S1_port} len 2048 local0
+ option httpchk GET /status HTTP/1.1
+ server srv ${s2_addr}:${s2_port} check inter 100ms rise 1 fall 1
+
+ backend be3
+ log ${S1_addr}:${S1_port} len 2048 local0
+ option httpchk
+ http-check send meth GET uri /status ver HTTP/1.1
+ server srv ${s3_addr}:${s3_port} check inter 100ms rise 1 fall 1
+
+ backend be4
+ mode tcp
+ log ${S1_addr}:${S1_port} len 2048 local0
+ option httpchk
+ http-check send-state
+ http-check connect addr ${s4_addr}:${s4_port}
+ http-check set-var(check.server) "str(srv)"
+ http-check set-var(check.path) "str(/req1)"
+ http-check send meth GET uri-lf "%[var(check.path)]" ver HTTP/1.1 hdr x-test "server=%[var(check.server)]"
+ http-check expect status 200
+ http-check connect addr ${s4_addr} port ${s4_port}
+ http-check unset-var(check.server)
+ http-check set-var(check.path) "str(/req2)"
+ http-check send meth GET uri-lf "%[var(check.path)]" ver HTTP/1.1 hdr x-test "server=%[var(check.server)]" body "health-check body"
+ http-check expect rstatus "^2[0-9]{2}"
+ http-check connect addr ${s4_addr} port ${s4_port}
+ http-check set-var(check.path) "str(/req3)"
+ http-check send meth GET uri-lf "%[var(check.path)]"
+ http-check expect rstatus "^2[0-9]{2}"
+ http-check connect addr ${s4_addr} port ${s4_port}
+ http-check unset-var(check.path)
+ http-check send meth GET uri-lf "%[var(check.path)]" body-lf "health-check on %[be_name]-%[srv_name]"
+ ## implicit expect rule
+ server srv ${s1_addr}:${s1_port} check inter 100ms rise 1 fall 1
+
+ backend be5
+ log ${S1_addr}:${S1_port} len 2048 local0
+ option httpchk
+ server srv ${h1_li1_addr}:${h1_li1_port} proto h2 check inter 100ms rise 1 fall 1
+
+ backend be6
+ log ${S1_addr}:${S1_port} len 2048 local0
+ option httpchk GET /status HTTP/1.1
+ server srv ${h1_li1_addr}:${h1_li1_port} check check-proto h2 inter 100ms rise 1 fall 1
+
+ listen li1
+ mode http
+ bind "fd@${li1}" proto h2
+ http-request return status 200
+
+} -start
+
+syslog S1 -wait
diff --git a/reg-tests/checks/http-monitor-uri.vtc b/reg-tests/checks/http-monitor-uri.vtc
new file mode 100644
index 0000000..b6c8ccb
--- /dev/null
+++ b/reg-tests/checks/http-monitor-uri.vtc
@@ -0,0 +1,56 @@
+varnishtest "Test the HTTP directive monitor-uri"
+#REQUIRE_VERSION=2.2
+
+# This config tests the HTTP directive monitor-uri. Especially the path matching
+# when an absolute-form uri is received from the client. But also the
+# case-sensitivity of the matching.
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ monitor-uri /health
+
+ frontend fe2
+ bind "fd@${fe2}"
+ monitor-uri http://www.haproxy.org/health
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /health
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c2 -connect ${h1_fe1_sock} {
+ txreq -req GET -url http://www.haproxy.org/health \
+ -hdr "Host: www.haproxy.org"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c3 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /hEAlth
+ rxresp
+ expect resp.status == 503
+} -run
+
+client c4 -connect ${h1_fe2_sock} {
+ txreq -req GET -url http://www.haproxy.org/health \
+ -hdr "Host: www.haproxy.org"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c5 -connect ${h1_fe2_sock} {
+ txreq -req GET -url /health
+ rxresp
+ expect resp.status == 503
+} -run
diff --git a/reg-tests/checks/ldap-check.vtc b/reg-tests/checks/ldap-check.vtc
new file mode 100644
index 0000000..a0e5509
--- /dev/null
+++ b/reg-tests/checks/ldap-check.vtc
@@ -0,0 +1,96 @@
+varnishtest "Health-checks: LDAP health-check"
+#REQUIRE_VERSION=2.2
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+# This scripts tests health-checks for LDAP application, enabled using
+# "option ldap-check" line. A intermediate listener is used to validate
+# the request because it is impossible with VTEST to read and match raw
+# text.
+
+server s1 {
+ recv 14
+ sendhex "300C020101 61 070A01 00 04000400"
+} -start
+
+server s2 {
+ recv 14
+ sendhex "300C020101 60 070A01 00 04000400"
+} -start
+
+server s3 {
+ recv 14
+ sendhex "300C020101 61 070A01 01 04000400"
+} -start
+
+server s4 {
+ recv 14
+ sendhex "308400000010020101 61 84000000070A01"
+ delay 0.1
+ sendhex "00 04000400"
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer7 check passed.+info: \"Success\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv failed, reason: Layer7 invalid response.+info: \"Not LDAPv3 protocol\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv failed, reason: Layer7 wrong status.+code: 1.+info: \"See RFC: http://tools.ietf.org/html/rfc4511#section-4.1.9\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S4 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv succeeded, reason: Layer7 check passed.+info: \"Success\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ log ${S1_addr}:${S1_port} daemon
+ option log-health-checks
+ option ldap-check
+ server srv ${h1_ldap1_addr}:${h1_ldap1_port} check inter 1s rise 1 fall 1
+
+ backend be2
+ log ${S2_addr}:${S2_port} daemon
+ option log-health-checks
+ option ldap-check
+ server srv ${s2_addr}:${s2_port} check inter 1s rise 1 fall 1
+
+ backend be3
+ log ${S3_addr}:${S3_port} daemon
+ option log-health-checks
+ option ldap-check
+ server srv ${s3_addr}:${s3_port} check inter 1s rise 1 fall 1
+
+ backend be4
+ log ${S4_addr}:${S4_port} daemon
+ option log-health-checks
+ option ldap-check
+ server srv ${s4_addr}:${s4_port} check inter 1s rise 1 fall 1
+
+ listen ldap1
+ bind "fd@${ldap1}"
+ tcp-request inspect-delay 100ms
+ tcp-request content accept if { req.len eq 14 } { req.payload(0,14) -m bin "300C020101600702010304008000" }
+ tcp-request content reject
+ server srv ${s1_addr}:${s1_port}
+
+} -start
+
+syslog S1 -wait
+syslog S2 -wait
+syslog S3 -wait
+syslog S4 -wait
diff --git a/reg-tests/checks/mysql-check.vtc b/reg-tests/checks/mysql-check.vtc
new file mode 100644
index 0000000..b2348c3
--- /dev/null
+++ b/reg-tests/checks/mysql-check.vtc
@@ -0,0 +1,123 @@
+varnishtest "Health-checks: MySQL health-check"
+#REQUIRE_VERSION=2.2
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+# This scripts tests health-checks for MySQL application, enabled using
+# "option mysql-check" line. A intermediate listener is used to validate
+# the request because it is impossible with VTEST to read and match raw
+# text.
+
+server s1 {
+ sendhex "4A0000000A382E302E3139000A0000006F3C025E6249410D00FFFFFF0200FFC715000000000000000000007C182159106E2761144322200063616368696E675F736861325F70617373776F726400"
+ expect_close
+} -start
+
+server s2 {
+ sendhex "4A0000000A382E302E3139000A0000006F3C025E6249410D00FFFFFF0200FFC715000000000000000000007C182159106E2761144322200063616368696E675F736861325F70617373776F726400"
+ recv 20
+ sendhex "03000002000000"
+} -start
+
+server s3 {
+ sendhex "4A0000000A382E302E3139000A0000006F3C025E6249410D00FFFFFF0200FFC715000000000000000000007C182159106E2761144322200063616368696E675F736861325F70617373776F726400"
+ recv 47
+ sendhex "0700000200000002000000"
+} -start
+
+server s4 {
+ sendhex "4A0000000A382E302E3139000A0000006F3C025E6249410D00FFFFFF0200FFC715000000000000000000007C182159106E2761144322200063616368696E675F736861325F70617373776F726400"
+ recv 21
+ sendhex "67000002FFE304436C69656E7420646F6573206E6F7420737570706F72742061757468656E7469636174696F6E2070726F746F636F6C20726571756573746564206279207365727665723B20636F6E736964657220757067726164696E67204D7953514C20636C69656E74"
+} -start
+
+server s5 {
+ sendhex "4A0000000A382E302E3139000A0000006F3C025E6249410D00FFFFFF0200FFC715000000000000000000007C182159106E2761144322200063616368696E675F736861325F70617373776F726400"
+ recv 48
+ sendhex "67000002FFE304436C69656E7420646F6573206E6F7420737570706F72742061757468656E7469636174696F6E2070726F746F636F6C20726571756573746564206279207365727665723B20636F6E736964657220757067726164696E67204D7953514C20636C69656E74"
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer7 check passed.+info: \"8.0.19\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv succeeded, reason: Layer7 check passed.+info: \"8.0.19\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv succeeded, reason: Layer7 check passed.+info: \"8.0.19\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S4 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv failed, reason: Layer7 wrong status.+code: 1251.+info: \"Client does not support authentication protocol requested by server; consider upgrading MySQL client\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S5 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be5/srv failed, reason: Layer7 wrong status.+code: 1251.+info: \"Client does not support authentication protocol requested by server; consider upgrading MySQL client\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ log ${S1_addr}:${S1_port} daemon
+ option log-health-checks
+ option mysql-check
+ server srv ${s1_addr}:${s1_port} check inter 1s rise 1 fall 1
+
+ backend be2
+ log ${S2_addr}:${S2_port} daemon
+ option log-health-checks
+ option mysql-check user user pre-41
+ server srv ${h1_mysql1_addr}:${h1_mysql1_port} check inter 1s rise 1 fall 1
+
+ backend be3
+ log ${S3_addr}:${S3_port} daemon
+ option log-health-checks
+ option mysql-check user user
+ server srv ${h1_mysql2_addr}:${h1_mysql2_port} check inter 1s rise 1 fall 1
+
+ backend be4
+ log ${S4_addr}:${S4_port} daemon
+ option log-health-checks
+ option mysql-check user pouet
+ server srv ${s4_addr}:${s4_port} check inter 1s rise 1 fall 1
+
+ backend be5
+ log ${S5_addr}:${S5_port} daemon
+ option log-health-checks
+ option mysql-check user pouet post-41
+ server srv ${s5_addr}:${s5_port} check inter 1s rise 1 fall 1
+
+ listen mysql1
+ bind "fd@${mysql1}"
+ tcp-request inspect-delay 100ms
+ tcp-request content accept if { req.len eq 20 } { req.payload(0,20) -m bin "0B00000100800000017573657200000100000001" }
+ tcp-request content reject
+ server srv ${s2_addr}:${s2_port}
+
+ listen mysql2
+ bind "fd@${mysql2}"
+ tcp-request inspect-delay 100ms
+ tcp-request content accept if { req.len eq 47 } { req.payload(0,47) -m bin "2600000100820000008000012100000000000000000000000000000000000000000000007573657200000100000001" }
+ tcp-request content reject
+ server srv ${s3_addr}:${s3_port}
+
+} -start
+
+syslog S1 -wait
+syslog S2 -wait
+syslog S3 -wait
+syslog S4 -wait
+syslog S5 -wait
diff --git a/reg-tests/checks/pgsql-check.vtc b/reg-tests/checks/pgsql-check.vtc
new file mode 100644
index 0000000..2c9c65b
--- /dev/null
+++ b/reg-tests/checks/pgsql-check.vtc
@@ -0,0 +1,93 @@
+varnishtest "Health-checks: PostgreSQL health-check"
+#REQUIRE_VERSION=2.2
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+# This scripts tests health-checks for PostgreSQL application, enabled using
+# "option pgsql-check" line. A intermediate listener is used to validate
+# the request because it is impossible with VTEST to read and match raw
+# text.
+
+server s1 {
+ recv 23
+ sendhex "520000000800000000"
+} -start
+
+server s2 {
+ recv 23
+ sendhex "450000000B53464154414C00"
+} -start
+
+server s3 {
+ recv 23
+ send "Not a PostgreSQL response"
+} -start
+
+server s4 {
+ recv 23
+ sendhex "52000000170000000A534352414D2D5348412D3235360000"
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer7 check passed.+info: \"PostgreSQL server is ok\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv failed, reason: Layer7 invalid response.+info: \"FATAL\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv failed, reason: Layer7 wrong status.+info: \"PostgreSQL unknown error\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S4 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv succeeded, reason: Layer7 check passed.+info: \"PostgreSQL server is ok\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ log ${S1_addr}:${S1_port} daemon
+ option log-health-checks
+ option pgsql-check user postgres
+ server srv ${h1_pgsql_addr}:${h1_pgsql_port} check inter 1s rise 1 fall 1
+
+ backend be2
+ log ${S2_addr}:${S2_port} daemon
+ option log-health-checks
+ option pgsql-check user postgres
+ server srv ${s2_addr}:${s2_port} check inter 1s rise 1 fall 1
+
+ backend be3
+ log ${S3_addr}:${S3_port} daemon
+ option log-health-checks
+ option pgsql-check user postgres
+ server srv ${s3_addr}:${s3_port} check inter 1s rise 1 fall 1
+
+ backend be4
+ log ${S4_addr}:${S4_port} daemon
+ option log-health-checks
+ option pgsql-check user postgres
+ server srv ${s4_addr}:${s4_port} check inter 1s rise 1 fall 1
+
+ listen pgsql1
+ bind "fd@${pgsql}"
+ tcp-request inspect-delay 100ms
+ tcp-request content accept if { req.len eq 23 } { req.payload(0,23) -m bin "00000017000300007573657200706f7374677265730000" }
+ tcp-request content reject
+ server srv ${s1_addr}:${s1_port}
+} -start
+
+syslog S1 -wait
+syslog S2 -wait
+syslog S3 -wait
+syslog S4 -wait
diff --git a/reg-tests/checks/redis-check.vtc b/reg-tests/checks/redis-check.vtc
new file mode 100644
index 0000000..78b6ed3
--- /dev/null
+++ b/reg-tests/checks/redis-check.vtc
@@ -0,0 +1,61 @@
+varnishtest "Health-checks: Redis health-check"
+#REQUIRE_VERSION=2.2
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+# This scripts tests health-checks for Redis application, enabled using
+# "option redis-check" line. A intermediate listener is used to validate
+# the request because it is impossible with VTEST to read and match raw
+# text.
+
+server s1 {
+ recv 14
+ send "+PONG\r\n"
+} -start
+
+server s2 {
+ recv 14
+ send "-Error message\r\n"
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer7 check passed.+info: \"Redis server is ok\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv failed, reason: Layer7 wrong status.+info: \"-Error message\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ log ${S1_addr}:${S1_port} daemon
+ option log-health-checks
+ option redis-check
+ server srv ${h1_redis_addr}:${h1_redis_port} check inter 1s rise 1 fall 1
+
+ backend be2
+ log ${S2_addr}:${S2_port} daemon
+ option log-health-checks
+ option redis-check
+ server srv ${s2_addr}:${s2_port} check inter 1s rise 1 fall 1
+
+ listen redis1
+ bind "fd@${redis}"
+ tcp-request inspect-delay 100ms
+ tcp-request content accept if { req.len eq 14 } { req.payload(0,14) -m str "*1\r\n\$4\r\nPING\r\n" }
+ tcp-request content reject
+ server srv ${s1_addr}:${s1_port}
+
+} -start
+
+syslog S1 -wait
+syslog S2 -wait
diff --git a/reg-tests/checks/smtp-check.vtc b/reg-tests/checks/smtp-check.vtc
new file mode 100644
index 0000000..723f5f0
--- /dev/null
+++ b/reg-tests/checks/smtp-check.vtc
@@ -0,0 +1,110 @@
+varnishtest "Health-checks: SMTP health-check"
+#REQUIRE_VERSION=2.2
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+# This scripts tests health-checks for SMTP servers, enabled using
+# "option smtpchk" line.
+
+server s1 {
+ send "220 smtp-check.vtc SMTP Server\r\n"
+ recv 16
+ send "250 smtp-check.vtc\r\n"
+ recv 6
+ send "221 smtp-check.vtc closing\r\n"
+} -start
+
+server s2 {
+ send "220 smtp-check.vtc SMTP Server\r\n"
+ recv 17
+ send "250-smtp-check.vtc\r\n"
+ send "250-KEYWORD\r\n"
+ send "250 LAST KEYWORD\r\n"
+ recv 6
+ send "221 smtp-check.vtc closing\r\n"
+} -start
+
+server s3 {
+ send "I'm not a SMTP server\r\n"
+} -start
+
+server s4 {
+ send "421 Try again later\r\n"
+} -start
+
+server s5 {
+ send "220 smtp-check.vtc SMTP Server\r\n"
+ recv 16
+ send "512 DNS error\r\n"
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer7 check passed.+code: 221.+info: \"smtp-check.vtc closing\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv succeeded, reason: Layer7 check passed.+code: 221.+info: \"smtp-check.vtc closing\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv failed, reason: Layer7 invalid response.+info: \"I'm not a SMTP server\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S4 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv failed, reason: Layer7 wrong status.+code: 421.+info: \"Try again later\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S5 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be5/srv failed, reason: Layer7 wrong status.+code: 512.+info: \"DNS error\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ log ${S1_addr}:${S1_port} daemon
+ option log-health-checks
+ option smtpchk
+ server srv ${s1_addr}:${s1_port} check inter 1s rise 1 fall 1
+
+ backend be2
+ log ${S2_addr}:${S2_port} daemon
+ option log-health-checks
+ option smtpchk EHLO domain.tld
+ server srv ${s2_addr}:${s2_port} check inter 1s rise 1 fall 1
+
+ backend be3
+ log ${S3_addr}:${S3_port} daemon
+ option log-health-checks
+ option smtpchk
+ server srv ${s3_addr}:${s3_port} check inter 1s rise 1 fall 1
+
+ backend be4
+ log ${S4_addr}:${S4_port} daemon
+ option log-health-checks
+ option smtpchk
+ server srv ${s4_addr}:${s4_port} check inter 1s rise 1 fall 1
+
+ backend be5
+ log ${S5_addr}:${S5_port} daemon
+ option log-health-checks
+ option smtpchk EHLO domain.tld
+ server srv ${s5_addr}:${s5_port} check inter 1s rise 1 fall 1
+
+} -start
+
+syslog S1 -wait
+syslog S2 -wait
+syslog S3 -wait
+syslog S4 -wait
+syslog S5 -wait
diff --git a/reg-tests/checks/spop-check.vtc b/reg-tests/checks/spop-check.vtc
new file mode 100644
index 0000000..93cef59
--- /dev/null
+++ b/reg-tests/checks/spop-check.vtc
@@ -0,0 +1,94 @@
+varnishtest "Health-checks: SPOP health-check"
+#REQUIRE_VERSION=2.2
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+# This scripts tests health-checks for SPOE agent, enabled using
+# "option spop-check" line. A intermediate listener is used to validate
+# the request because it is impossible with VTEST to read and match raw
+# text.
+
+server s1 {
+ recv 82
+ sendhex "00000036 65 00000001 0000 0776657273696F6E 0803322E30 0E6D61782D6672616D652D73697A65 03FCF0 060C6361706162696C6974696573 0800"
+} -start
+
+server s2 {
+ recv 82
+ sendhex "00000000"
+} -start
+
+server s3 {
+ recv 82
+ sendhex "00000007 65 00000000 0000"
+} -start
+
+server s4 {
+ recv 82
+ sendhex "00000014 65 00000001 0000 0776657273696F6E 0803312E30"
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer7 check passed.+info: \"SPOA server is ok\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv failed, reason: Layer7 invalid response.+info: \"invalid frame received\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv failed, reason: Layer7 invalid response.+info: \"fragmentation not supported\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S4 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv failed, reason: Layer7 invalid response.+info: \"unsupported version\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ log ${S1_addr}:${S1_port} daemon
+ option log-health-checks
+ option spop-check
+ server srv ${h1_spop1_addr}:${h1_spop1_port} check inter 1s rise 1 fall 1
+
+ backend be2
+ log ${S2_addr}:${S2_port} daemon
+ option log-health-checks
+ option spop-check
+ server srv ${s2_addr}:${s2_port} check inter 1s rise 1 fall 1
+
+ backend be3
+ log ${S3_addr}:${S3_port} daemon
+ option log-health-checks
+ option spop-check
+ server srv ${s3_addr}:${s3_port} check inter 1s rise 1 fall 1
+
+ backend be4
+ log ${S4_addr}:${S4_port} daemon
+ option log-health-checks
+ option spop-check
+ server srv ${s4_addr}:${s4_port} check inter 1s rise 1 fall 1
+
+ listen spop1
+ bind "fd@${spop1}"
+ tcp-request inspect-delay 100ms
+ tcp-request content accept if { req.len eq 82 } { req.payload(0,4) -m bin "0000004E" } #{ req.payload(4,4) -m bin "00000001" } { req.payload(8,2) -m bin "0000" } { req.payload(12,17) -m str "supported-version" }
+ tcp-request content reject
+ server srv ${s1_addr}:${s1_port}
+
+} -start
+
+syslog S1 -wait
+syslog S2 -wait
+syslog S3 -wait
+syslog S4 -wait
diff --git a/reg-tests/checks/ssl-hello-check.vtc b/reg-tests/checks/ssl-hello-check.vtc
new file mode 100644
index 0000000..49abc0b
--- /dev/null
+++ b/reg-tests/checks/ssl-hello-check.vtc
@@ -0,0 +1,76 @@
+varnishtest "Health-checks: ssl-hello health-check"
+#REQUIRE_OPTION=OPENSSL
+#REQUIRE_VERSION=2.2
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+# This scripts tests health-checks for SSL application, enabled using
+# "option ssl-hello-chk" line.
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer6 check passed.+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv failed, reason: Layer6 invalid response.+info: \"TCPCHK got an empty response at step 2\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv failed, reason: Layer6 invalid response.+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+haproxy htst -conf {
+ global
+ tune.ssl.default-dh-param 2048
+
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}" ssl crt ${testdir}/common.pem
+
+ frontend fe2
+ bind "fd@${fe2}"
+
+ frontend fe3
+ mode http
+ bind "fd@${fe3}"
+
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ log ${S1_addr}:${S1_port} daemon
+ option log-health-checks
+ option ssl-hello-chk
+ server srv ${htst_fe1_addr}:${htst_fe1_port} check inter 1s rise 1 fall 1
+
+ backend be2
+ log ${S2_addr}:${S2_port} daemon
+ option log-health-checks
+ option ssl-hello-chk
+ server srv ${htst_fe2_addr}:${htst_fe2_port} check inter 1s rise 1 fall 1
+
+ backend be3
+ log ${S3_addr}:${S3_port} daemon
+ option log-health-checks
+ option ssl-hello-chk
+ server srv ${htst_fe3_addr}:${htst_fe3_port} check inter 1s rise 1 fall 1
+} -start
+
+syslog S1 -wait
+syslog S2 -wait
+syslog S3 -wait
diff --git a/reg-tests/checks/tcp-check-ssl.vtc b/reg-tests/checks/tcp-check-ssl.vtc
new file mode 100644
index 0000000..6ac1782
--- /dev/null
+++ b/reg-tests/checks/tcp-check-ssl.vtc
@@ -0,0 +1,118 @@
+varnishtest "Health-checks: tcp-check health-check with ssl options"
+#REQUIRE_OPTION=OPENSSL
+#REQUIRE_VERSION=2.2
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+syslog S_ok -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]+/srv succeeded, reason: Layer6 check passed.+check duration: [[:digit:]]+ms, status: 1/1 UP."
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]+/srv succeeded, reason: Layer6 check passed.+check duration: [[:digit:]]+ms, status: 1/1 UP."
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]+/srv succeeded, reason: Layer6 check passed.+check duration: [[:digit:]]+ms, status: 1/1 UP."
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]+/srv succeeded, reason: Layer6 check passed.+check duration: [[:digit:]]+ms, status: 1/1 UP."
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]+/srv succeeded, reason: Layer6 check passed.+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S3 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv failed, reason: Layer6 invalid response.+info: \"(Connection closed during SSL handshake|SSL handshake failure)\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+syslog S4 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv failed, reason: Layer6 invalid response.+info: \"(Connection closed during SSL handshake|SSL handshake failure) at step 1 of tcp-check \\(connect\\)\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
+} -start
+
+
+haproxy htst -conf {
+ global
+ tune.ssl.default-dh-param 2048
+
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen li1
+ bind "fd@${li1}"
+ tcp-request inspect-delay 100ms
+ tcp-request content reject if { req.ssl_hello_type 0 }
+ tcp-request content accept if { req.ssl_sni check.haproxy.org }
+ tcp-request content accept if { req.ssl_sni connect.haproxy.org }
+ tcp-request content reject
+ server fe1 ${htst_fe1_addr}:${htst_fe1_port}
+
+ listen li2
+ bind "fd@${li2}"
+ tcp-request inspect-delay 100ms
+ tcp-request content reject if { req.ssl_hello_type 0 }
+ tcp-request content accept if { req.ssl_alpn h2 }
+ tcp-request content accept if { req.ssl_alpn http/1.1 }
+ tcp-request content reject
+ server fe1 ${htst_fe1_addr}:${htst_fe1_port}
+
+ frontend fe1
+ bind "fd@${fe1}" ssl crt ${testdir}/common.pem
+
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ log ${S_ok_addr}:${S_ok_port} daemon
+ option log-health-checks
+ server srv ${htst_li1_addr}:${htst_li1_port} check check-ssl check-sni check.haproxy.org inter 1s rise 1 fall 1 verify none
+
+ backend be2
+ log ${S_ok_addr}:${S_ok_port} daemon
+ option log-health-checks
+ option tcp-check
+ tcp-check connect ssl sni connect.haproxy.org
+ server srv ${htst_li1_addr}:${htst_li1_port} check inter 1s rise 1 fall 1 verify none
+
+ backend be3
+ log ${S3_addr}:${S3_port} daemon
+ option log-health-checks
+ server srv ${htst_li1_addr}:${htst_li1_port} check check-ssl check-sni bad.haproxy.org inter 1s rise 1 fall 1 verify none
+
+ backend be4
+ log ${S4_addr}:${S4_port} daemon
+ option log-health-checks
+ option tcp-check
+ tcp-check connect ssl sni bad.haproxy.org
+ server srv ${htst_li1_addr}:${htst_li1_port} check inter 1s rise 1 fall 1 verify none
+
+ backend be5
+ log ${S_ok_addr}:${S_ok_port} daemon
+ option log-health-checks
+ option tcp-check
+ tcp-check connect default
+ server srv ${htst_li1_addr}:${htst_li1_port} check check-ssl check-sni check.haproxy.org inter 1s rise 1 fall 1 verify none
+
+ backend be6
+ log ${S_ok_addr}:${S_ok_port} daemon
+ option log-health-checks
+ server srv ${htst_li2_addr}:${htst_li2_port} check check-ssl check-alpn "h2,http/1.1" inter 1s rise 1 fall 1 verify none
+
+ backend be7
+ log ${S_ok_addr}:${S_ok_port} daemon
+ option log-health-checks
+ option tcp-check
+ tcp-check connect ssl alpn "h2,http/1.1"
+ server srv ${htst_li2_addr}:${htst_li2_port} check inter 1s rise 1 fall 1 verify none
+
+} -start
+
+syslog S_ok -wait
+syslog S3 -wait
+syslog S4 -wait
diff --git a/reg-tests/checks/tcp-check_min-recv.vtc b/reg-tests/checks/tcp-check_min-recv.vtc
new file mode 100644
index 0000000..81f93e0
--- /dev/null
+++ b/reg-tests/checks/tcp-check_min-recv.vtc
@@ -0,0 +1,68 @@
+varnishtest "tcp-check negative bounded regex match"
+#EXCLUDE_TARGETS=freebsd,osx,generic
+#REGTEST_TYPE=slow
+#REQUIRE_VERSION=2.2
+# This test use a negative expect rule and verify that setting a required
+# minimum amount of data to match.
+feature ignore_unknown_macro
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed, reason: Layer7 timeout.*at step 2 of tcp-check"
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv1 succeeded"
+} -start
+
+server s1 {
+ send "valid"
+ delay 0.2
+ expect_close
+} -start
+
+server s2 {
+ send "valid"
+ recv 10
+ send "valid"
+ delay 0.2
+ expect_close
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout check "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ # must fail fast
+ timeout check 1
+ timeout server 1
+ log ${S1_addr}:${S1_port} len 2048 local0
+ option tcp-check
+ option log-health-checks
+ tcp-check connect
+ tcp-check expect !rstring "^error" comment "negative check"
+ tcp-check expect string "valid" comment "positive check"
+ tcp-check send "0123456789"
+ tcp-check expect string "valid" comment "positive check"
+ server srv1 ${s1_addr}:${s1_port} check inter 200ms rise 1 fall 1
+
+ backend be2
+ log ${S2_addr}:${S2_port} len 2048 local0
+ option tcp-check
+ option log-health-checks
+ tcp-check connect
+ tcp-check expect min-recv 5 !rstring "^error" comment "negative check"
+ tcp-check expect string "valid" comment "positive check"
+ tcp-check send "0123456789"
+ tcp-check expect string "valid" comment "positive check"
+ server srv1 ${s2_addr}:${s2_port} check inter 200ms rise 1 fall 1
+} -start
+
+syslog S1 -wait
+syslog S2 -wait
diff --git a/reg-tests/checks/tcp-check_multiple_ports.vtc b/reg-tests/checks/tcp-check_multiple_ports.vtc
new file mode 100644
index 0000000..356ddf6
--- /dev/null
+++ b/reg-tests/checks/tcp-check_multiple_ports.vtc
@@ -0,0 +1,48 @@
+varnishtest "tcp-check multiple ports"
+#EXCLUDE_TARGETS=freebsd,osx,generic
+#REGTEST_TYPE=slow
+# This test uses multiple tcp-check connect rules to perform health checking on
+# a target. It relies on port 1 being unbound on the local system.
+feature ignore_unknown_macro
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed.*Connection refused at step 2 of tcp-check.*connect port 1"
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv1 failed.*Connection refused at step 1 of tcp-check.*connect port 1"
+} -start
+
+server s1 {
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout check "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ #default-server check inter 200ms rise 1 fall 1
+
+ backend be1
+ log ${S1_addr}:${S1_port} len 2048 local0
+ option tcp-check
+ option log-health-checks
+ tcp-check connect port ${s1_port}
+ tcp-check connect port 1
+ server srv1 ${s1_addr}:${s1_port} check inter 200ms rise 1 fall 1
+
+ backend be2
+ log ${S2_addr}:${S2_port} len 2048 local0
+ option tcp-check
+ option log-health-checks
+ tcp-check connect port 1
+ tcp-check connect port ${s1_port}
+ server srv1 ${s1_addr}:${s1_port} check inter 200ms rise 1 fall 1
+} -start
+
+syslog S1 -wait
+syslog S2 -wait
diff --git a/reg-tests/checks/tcp-checks-socks4.vtc b/reg-tests/checks/tcp-checks-socks4.vtc
new file mode 100644
index 0000000..8a730f5
--- /dev/null
+++ b/reg-tests/checks/tcp-checks-socks4.vtc
@@ -0,0 +1,60 @@
+varnishtest "Health-checks: basic HTTP health-check though a socks4 proxy"
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+# This scripts tests a simple HTTP health-checks though a socks4 proxy.
+
+server s1 {
+} -start
+
+server socks {
+ ## get socks4 request
+ recv 16
+
+ ## send socks4 response :
+ ## constant(1): 0x00
+ ## statut(1) : 0x5a (success)
+ ## padding(6) : ignored
+ sendhex "005A000000000000"
+
+ rxreq
+ expect req.method == OPTIONS
+ expect req.url == /
+ expect req.proto == HTTP/1.0
+ txresp
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer7 check passed.+code: 200.+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ log ${S1_addr}:${S1_port} daemon
+ option log-health-checks
+ option httpchk
+ server srv ${s1_addr}:${s1_port} socks4 ${h1_socks_addr}:${h1_socks_port} check-via-socks4 check inter 1s rise 1 fall 1
+
+ listen socks
+ bind "fd@${socks}"
+ tcp-request inspect-delay 500ms
+ ## Accept socks4 request on 16 bytes :
+ ## version(1) : 0x04
+ ## command(1) : 0x01
+ ## port(2) : ${s1_port}
+ ## addr(4) : ${s1_addr}
+ ## user-id : "HAProxy\0"
+ tcp-request content accept if { req.len eq 16 } { req.payload(0,1) -m bin "04" } { req.payload(1,1) -m bin "01" } { req.payload(2,2),hex,hex2i eq ${s1_port} } { req.payload(4,4),hex,hex2i -m ip ${s1_addr} } { req.payload(8,8) -m bin "484150726F787900" }
+ tcp-request content reject
+ server srv ${socks_addr}:${socks_port}
+
+} -start
+
+syslog S1 -wait
diff --git a/reg-tests/checks/tls_health_checks.vtc b/reg-tests/checks/tls_health_checks.vtc
new file mode 100644
index 0000000..9c268f4
--- /dev/null
+++ b/reg-tests/checks/tls_health_checks.vtc
@@ -0,0 +1,120 @@
+varnishtest "Health-check test over TLS/SSL"
+#REQUIRE_OPTIONS=OPENSSL
+#REGTEST_TYPE=slow
+feature ignore_unknown_macro
+
+
+# This script tests health-checks for a TLS/SSL backend with "option httpchk"
+# and "check-ssl" option enabled attached to h2 haproxy process. This haproxy
+# h2 process is chained to h1 other one.
+#
+server s1 {
+ rxreq
+ expect req.method == OPTIONS
+ expect req.url == *
+ expect req.proto == HTTP/1.1
+ txresp
+} -start
+
+server s2 {
+} -start
+
+server s3 {
+ rxreq
+ expect req.method == OPTIONS
+ expect req.url == *
+ expect req.proto == HTTP/1.1
+ txresp
+} -start
+
+syslog S1 -level notice {
+ recv info
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* fe1~ be1/srv1 .* 200 [[:digit:]]+ - - ---- .* \"OPTIONS \\* HTTP/1.1\""
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ server srv1 ${s1_addr}:${s1_port}
+
+ backend be2
+ server srv2 ${s2_addr}:${s2_port}
+
+ backend be3
+ server srv3 ${s3_addr}:${s3_port}
+
+ frontend fe1
+ option httplog
+ log ${S1_addr}:${S1_port} len 2048 local0 debug err
+ bind "fd@${fe1}" ssl crt ${testdir}/common.pem
+ use_backend be1
+
+ frontend fe2
+ option tcplog
+ bind "fd@${fe2}" ssl crt ${testdir}/common.pem
+ use_backend be2
+
+ frontend fe3
+ option httplog
+ bind "fd@${fe3}" ssl crt ${testdir}/common.pem
+ use_backend be3
+} -start
+
+syslog S2 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h2_pid}\\]: Health check for server be2/srv1 succeeded, reason: Layer7 check passed.+code: 200.+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S4 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h2_pid}\\]: Health check for server be4/srv2 succeeded, reason: Layer6 check passed.+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+syslog S6 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h2_pid}\\]: Health check for server be6/srv3 succeeded, reason: Layer7 check passed.+code: 200.+check duration: [[:digit:]]+ms, status: 1/1 UP."
+} -start
+
+haproxy h2 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ default-server downinter 1s inter 500 rise 1 fall 1
+
+ backend be2
+ option log-health-checks
+ option httpchk OPTIONS * HTTP/1.1
+ http-check send hdr Host www
+ log ${S2_addr}:${S2_port} daemon
+ server srv1 ${h1_fe1_addr}:${h1_fe1_port} ssl crt ${testdir}/common.pem verify none check
+
+ backend be4
+ option log-health-checks
+ log ${S4_addr}:${S4_port} daemon
+ server srv2 ${h1_fe2_addr}:${h1_fe2_port} ssl crt ${testdir}/common.pem verify none check-ssl check
+
+ backend be6
+ option log-health-checks
+ option httpchk OPTIONS * HTTP/1.1
+ http-check send hdr Host www
+ log ${S6_addr}:${S6_port} daemon
+ server srv3 127.0.0.1:80 crt ${testdir}/common.pem verify none check check-ssl port ${h1_fe3_port} addr ${h1_fe3_addr}:80
+} -start
+
+syslog S1 -wait
+
+syslog S2 -wait
+syslog S4 -wait
+syslog S6 -wait
diff --git a/reg-tests/compression/basic.vtc b/reg-tests/compression/basic.vtc
new file mode 100644
index 0000000..5d9eada
--- /dev/null
+++ b/reg-tests/compression/basic.vtc
@@ -0,0 +1,377 @@
+varnishtest "Basic compression test"
+
+#REQUIRE_OPTION=ZLIB|SLZ
+
+feature ignore_unknown_macro
+
+server s1 {
+ # client c1 - request 1
+ rxreq
+ expect req.url == "/c1.1"
+ expect req.http.accept-encoding == "<undef>"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+
+ # client c1 - request 2
+ rxreq
+ expect req.url == "/c1.2"
+ expect req.http.user-agent == "Mozilla/4"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+
+ # client c1 - request 3
+ rxreq
+ expect req.url == "/c1.3"
+ expect req.proto == "HTTP/1.0"
+ expect req.http.accept-encoding == "gzip"
+ txresp -bodylen 100
+
+ # client c1 - request 4
+ rxreq
+ expect req.url == "/c1.4"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -proto "HTTP/1.0" \
+ -hdr "Connection: keep-alive" \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+
+ # client c1 - request 5
+ rxreq
+ expect req.url == "/c1.5"
+ expect req.method == "HEAD"
+ expect req.http.accept-encoding == "gzip"
+ txresp -nolen \
+ -hdr "Content-Length: 100" \
+ -hdr "Content-Type: text/plain" \
+
+ # client c1 - request 6
+ rxreq
+ expect req.url == "/c1.6"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -status 400 \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+
+ # client c1 - request 7
+ rxreq
+ expect req.url == "/c1.7"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "Content-Encoding: something" \
+ -body "FOO"
+
+ # client c1 - request 8
+ rxreq
+ expect req.url == "/c1.8"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "Cache-Control: no-transform" \
+ -bodylen 100
+
+ # client c1 - request 9
+ rxreq
+ expect req.url == "/c1.9"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/css" \
+ -bodylen 100
+
+ # client c1 - request 10
+ rxreq
+ expect req.url == "/c1.10"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: multipart/mixed; boundary=\"aaa\"" \
+ -bodylen 100
+
+ # Close the connection with HAProxy and wait for a new one
+ # (C1 has finished and C2 will start)
+ accept
+
+ # client c2 - request 1
+ rxreq
+ expect req.url == "/c2.1"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+
+ # client c2 - request 2
+ rxreq
+ expect req.url == "/c2.2"
+ expect req.http.accept-encoding == "gzip"
+ txresp -nolen \
+ -hdr "Content-Type: text/plain" \
+ -hdr "Transfer-Encoding: chunked"
+ chunkedlen 1
+ chunkedlen 1
+ chunkedlen 2
+ chunkedlen 3
+ chunkedlen 5
+ chunkedlen 8
+ chunkedlen 13
+ chunkedlen 21
+ chunkedlen 34
+ chunkedlen 55
+ chunkedlen 89
+ chunkedlen 144
+ chunkedlen 233
+ chunkedlen 0
+
+ # Close the connection with HAProxy and wait for a new one
+ # (C2 has finished and C3 will start)
+ accept
+
+ # client c3 - request 1
+ rxreq
+ expect req.url == "/c3.1"
+ expect req.http.accept-encoding == "<undef>"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 50000
+
+ # client c3 - request 2
+ rxreq
+ expect req.url == "/c3.2"
+ expect req.http.accept-encoding == "<undef>"
+ txresp -nolen \
+ -hdr "Content-Type: text/plain" \
+ -hdr "Transfer-Encoding: chunked"
+ chunkedlen 1000
+ chunkedlen 1000
+ chunkedlen 1000
+ chunkedlen 1000
+ chunkedlen 1000
+ chunkedlen 5000
+ chunkedlen 10000
+ chunkedlen 30000
+ chunkedlen 0
+
+ # Close the connection with HAProxy and wait for a new one
+ # (C3 has finished and C4 will start)
+ accept
+
+ # client c4 - request 1
+ rxreq
+ expect req.url == "/c4.1"
+ expect req.http.accept-encoding == "<undef>"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+
+ # client c4 - request 2
+ rxreq
+ expect req.url == "/c4.2"
+ expect req.http.accept-encoding == "<undef>"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+} -start
+
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe-gzip
+ bind "fd@${fe_gzip}"
+ default_backend be-gzip
+
+ frontend fe-identity
+ bind "fd@${fe_identity}"
+ default_backend be-identity
+
+ frontend fe-gzip-deflate
+ bind "fd@${fe_gzip_deflate}"
+ default_backend be-gzip-defalte
+
+ backend be-gzip
+ compression algo gzip
+ compression type text/html text/plain
+ server www ${s1_addr}:${s1_port}
+
+ backend be-identity
+ compression algo identity
+ server www ${s1_addr}:${s1_port}
+
+ backend be-gzip-defalte
+ compression algo gzip deflate
+ compression offload
+ server www ${s1_addr}:${s1_port}
+
+} -start
+
+# No compression expected because not supported by the client or because
+# something in the request or response headers forbids it.
+client c1 -connect ${h1_fe_gzip_sock} {
+ # 1. no "Accept-Encoding header"
+ txreq -url "/c1.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.bodylen == 100
+
+ # 2. Buggy User-Agent
+ txreq -url "/c1.2" \
+ -hdr "Accept-Encoding: gzip" \
+ -hdr "User-Agent: Mozilla/4"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.bodylen == 100
+
+ # 3. HTTP/1.0 request
+ txreq -url "/c1.3" \
+ -proto "HTTP/1.0" \
+ -hdr "Accept-Encoding: gzip" \
+ -hdr "Connection: keep-alive"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.bodylen == 100
+
+ # 4. HTTP/1.0 response
+ txreq -url "/c1.4" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.proto == "HTTP/1.0"
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.bodylen == 100
+
+ # 5. HEAD method
+ txreq -req "HEAD" -url "/c1.5" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp -no_obj
+ expect resp.status == 200
+ expect resp.http.content-length == "100"
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+
+ # 6. Response status code != 20[0-3]
+ txreq -url "/c1.6" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 400
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.bodylen == 100
+
+ # 7. Response alerady compressed by the server (with "Accept-Encoding")
+ txreq -url "/c1.7" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "something"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.bodylen == 3
+ expect resp.body == "FOO"
+
+ # 8. Response with "Cache-Control: no-transform"
+ txreq -url "/c1.8" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.http.cache-control == "no-transform"
+ expect resp.bodylen == 100
+
+ # 9. Response with uncompressable content-type
+ txreq -url "/c1.9" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.http.content-type == "text/css"
+ expect resp.bodylen == 100
+
+ # 10. Response with uncompressable content-type
+ txreq -url "/c1.10" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.http.content-type == "multipart/mixed; boundary=\"aaa\""
+ expect resp.bodylen == 100
+} -run
+
+# GZIP Compression expected (small body)
+client c2 -connect ${h1_fe_gzip_sock} {
+ # 1. response from the server with a small body with a C-L
+ txreq -url "/c2.1" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.transfer-encoding == "chunked"
+ gunzip
+ expect resp.bodylen == 100
+
+ # 2. response from the server with a small chunked body
+ txreq -url "/c2.2" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.transfer-encoding == "chunked"
+ gunzip
+ expect resp.bodylen == 609
+} -run
+
+# Identity compression expect (Huge body)
+# Identity is used because of a limitation of vtest (the uncompressed body size
+# must be lower than 10 times of the compressed one)
+client c3 -connect ${h1_fe_identity_sock} {
+ # 1. response from the server with a huge body with a C-L
+ txreq -url "/c3.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "chunked"
+ expect resp.bodylen == 50000
+
+ # 2. response from the server with a huge chunked body
+ txreq -url "/c3.2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "chunked"
+ expect resp.bodylen == 50000
+} -run
+
+
+# Compression expected with priority
+client c4 -connect ${h1_fe_gzip_deflate_sock} {
+ # 1. response from the server with a small body with a C-L
+ txreq -url "/c4.1" \
+ -hdr "Accept-Encoding: *;q=0, gzip;q=0.750, deflate;q=0.500"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.transfer-encoding == "chunked"
+
+ # 2. response from the server with a small body with a C-L
+ txreq -url "/c4.2" \
+ -hdr "Accept-Encoding: *;q=0, gzip;q=0.500, deflate;q=0.750"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "deflate"
+ expect resp.http.transfer-encoding == "chunked"
+} -run
diff --git a/reg-tests/compression/common.pem b/reg-tests/compression/common.pem
new file mode 120000
index 0000000..a4433d5
--- /dev/null
+++ b/reg-tests/compression/common.pem
@@ -0,0 +1 @@
+../ssl/common.pem \ No newline at end of file
diff --git a/reg-tests/compression/etags_conversion.vtc b/reg-tests/compression/etags_conversion.vtc
new file mode 100644
index 0000000..96e34bc
--- /dev/null
+++ b/reg-tests/compression/etags_conversion.vtc
@@ -0,0 +1,230 @@
+varnishtest "Compression converts strong ETags to weak ETags"
+
+#REQUIRE_OPTION=ZLIB|SLZ
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.url == "/strong"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: \"123\"" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/weak"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: W/\"456\"" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/weak-incorrect-quoting"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: \"W/789\"" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/empty-strong"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: \"\"" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/empty-weak"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: W/\"\"" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/invalid1"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: \"invalid" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/invalid2"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: invalid\"" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/invalid3"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: invalid" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/invalid4"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: W/\"invalid" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/invalid5"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: W/invalid\"" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/invalid6"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: W/invalid" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/multiple"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: \"one\"" \
+ -hdr "ETag: \"two\"" \
+ -bodylen 100
+} -start
+
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe-gzip
+ bind "fd@${fe_gzip}"
+ default_backend be-gzip
+
+ backend be-gzip
+ compression algo gzip
+ compression type text/html text/plain
+ server www ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_gzip_sock} {
+ txreq -url "/strong" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.etag == "W/\"123\""
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/weak" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.etag == "W/\"456\""
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/weak-incorrect-quoting" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.etag == "W/\"W/789\""
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/empty-strong" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.etag == "W/\"\""
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/empty-weak" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.etag == "W/\"\""
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/invalid1" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.etag == "\"invalid"
+ expect resp.bodylen == 100
+
+ txreq -url "/invalid2" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.etag == "invalid\""
+ expect resp.bodylen == 100
+
+ txreq -url "/invalid3" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.etag == "invalid"
+ expect resp.bodylen == 100
+
+ txreq -url "/invalid4" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.etag == "W/\"invalid"
+ expect resp.bodylen == 100
+
+ txreq -url "/invalid5" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.etag == "W/invalid\""
+ expect resp.bodylen == 100
+
+ txreq -url "/invalid6" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.etag == "W/invalid"
+ expect resp.bodylen == 100
+
+ txreq -url "/multiple" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.bodylen == 100
+} -run
diff --git a/reg-tests/compression/lua_validation.lua b/reg-tests/compression/lua_validation.lua
new file mode 100644
index 0000000..2cc874b
--- /dev/null
+++ b/reg-tests/compression/lua_validation.lua
@@ -0,0 +1,19 @@
+
+local data = "abcdefghijklmnopqrstuvwxyz"
+local responseblob = ""
+for i = 1,10000 do
+ responseblob = responseblob .. "\r\n" .. i .. data:sub(1, math.floor(i % 27))
+end
+
+http01applet = function(applet)
+ local response = responseblob
+ applet:set_status(200)
+ applet:add_header("Content-Type", "application/javascript")
+ applet:add_header("Content-Length", string.len(response)*10)
+ applet:start_response()
+ for i = 1,10 do
+ applet:send(response)
+ end
+end
+
+core.register_service("fileloader-http01", "http", http01applet)
diff --git a/reg-tests/compression/lua_validation.vtc b/reg-tests/compression/lua_validation.vtc
new file mode 100644
index 0000000..b10cbd9
--- /dev/null
+++ b/reg-tests/compression/lua_validation.vtc
@@ -0,0 +1,59 @@
+# Checks that compression doesn't cause corruption..
+
+varnishtest "Compression validation"
+#REQUIRE_OPTIONS=ZLIB|SLZ,LUA,OPENSSL
+#REGTEST_TYPE=slow
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+global
+# log stdout format short daemon
+ lua-load ${testdir}/lua_validation.lua
+
+defaults
+ mode http
+ log global
+ option httplog
+
+frontend main-https
+ bind "fd@${fe1}" ssl crt ${testdir}/common.pem
+ compression algo gzip
+ compression type text/html text/plain application/json application/javascript
+ compression offload
+ use_backend TestBack if TRUE
+
+backend TestBack
+ server LocalSrv ${h1_fe2_addr}:${h1_fe2_port}
+
+listen fileloader
+ mode http
+ bind "fd@${fe2}"
+ http-request use-service lua.fileloader-http01
+} -start
+
+shell {
+ HOST=${h1_fe1_addr}
+ if [ "${h1_fe1_addr}" = "::1" ] ; then
+ HOST="\[::1\]"
+ fi
+
+ md5=$(command -v md5 || command -v md5sum)
+
+ if [ -z $md5 ] ; then
+ echo "MD5 checksum utility not found"
+ exit 1
+ fi
+
+ expectchecksum="4d9c62aa5370b8d5f84f17ec2e78f483"
+
+ for opt in "" "--limit-rate 300K" "--limit-rate 500K" ; do
+ checksum=$(curl --max-time 15 --compressed -k "https://$HOST:${h1_fe1_port}" $opt | $md5 | cut -d ' ' -f1)
+ if [ "$checksum" != "$expectchecksum" ] ; then
+ echo "Expecting checksum $expectchecksum"
+ echo "Received checksum: $checksum"
+ exit 1;
+ fi
+ done
+
+} -run
diff --git a/reg-tests/compression/vary.vtc b/reg-tests/compression/vary.vtc
new file mode 100644
index 0000000..489de30
--- /dev/null
+++ b/reg-tests/compression/vary.vtc
@@ -0,0 +1,308 @@
+varnishtest "Compression sets Vary header"
+
+#REQUIRE_OPTION=ZLIB|SLZ
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.url == "/plain/accept-encoding-gzip"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/plain/accept-encoding-invalid"
+ expect req.http.accept-encoding == "invalid"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/plain/accept-encoding-null"
+ expect req.http.accept-encoding == "<undef>"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/html/accept-encoding-gzip"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/html" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/html/accept-encoding-invalid"
+ expect req.http.accept-encoding == "invalid"
+ txresp \
+ -hdr "Content-Type: text/html" \
+ -bodylen 100
+
+
+ rxreq
+ expect req.url == "/html/accept-encoding-null"
+ expect req.http.accept-encoding == "<undef>"
+ txresp \
+ -hdr "Content-Type: text/html" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/dup-etag/accept-encoding-gzip"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "ETag: \"123\"" \
+ -hdr "ETag: \"123\"" \
+ -bodylen 100
+} -repeat 2 -start
+
+
+server s2 {
+ rxreq
+ expect req.url == "/vary/no-vary"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/vary/accept-encoding"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "Vary: Accept-Encoding" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/vary/other"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "Vary: Other" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/vary/accept-encoding-and-other"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "Vary: Accept-Encoding,Other" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/vary/other-and-accept-encoding"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "Vary: Other,Accept-Encoding" \
+ -bodylen 100
+
+ rxreq
+ expect req.url == "/vary/empty"
+ expect req.http.accept-encoding == "gzip"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -hdr "Vary: " \
+ -bodylen 100
+} -start
+
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe-gzip
+ bind "fd@${fe_gzip}"
+ default_backend be-gzip
+
+ backend be-gzip
+ compression algo gzip
+ compression type text/plain
+ server www ${s1_addr}:${s1_port}
+
+ frontend fe-nothing
+ bind "fd@${fe_nothing}"
+ default_backend be-nothing
+
+ backend be-nothing
+ server www ${s1_addr}:${s1_port}
+
+ frontend fe-vary
+ bind "fd@${fe_vary}"
+ default_backend be-vary
+
+ backend be-vary
+ compression algo gzip
+ compression type text/plain
+ server www ${s2_addr}:${s2_port}
+
+} -start
+
+client c1 -connect ${h1_fe_gzip_sock} {
+ txreq -url "/plain/accept-encoding-gzip" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.vary == "Accept-Encoding"
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/plain/accept-encoding-invalid" \
+ -hdr "Accept-Encoding: invalid"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/plain/accept-encoding-null"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/html/accept-encoding-gzip" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/html/accept-encoding-invalid" \
+ -hdr "Accept-Encoding: invalid"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/html/accept-encoding-null"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/dup-etag/accept-encoding-gzip" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+} -run
+
+# This Client duplicates c1, against the "nothing" frontend, ensuring no Vary header is ever set.
+client c2 -connect ${h1_fe_nothing_sock} {
+ txreq -url "/plain/accept-encoding-gzip" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/plain/accept-encoding-invalid" \
+ -hdr "Accept-Encoding: invalid"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/plain/accept-encoding-null"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/html/accept-encoding-gzip" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/html/accept-encoding-invalid" \
+ -hdr "Accept-Encoding: invalid"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/html/accept-encoding-null"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+
+ txreq -url "/dup-etag/accept-encoding-gzip" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.vary == "<undef>"
+ expect resp.bodylen == 100
+} -run
+
+
+client c3 -connect ${h1_fe_vary_sock} {
+ txreq -url "/vary/no-vary" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.vary == "Accept-Encoding"
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/vary/accept-encoding" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.vary == "Accept-Encoding"
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/vary/other" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.vary == "Other,Accept-Encoding"
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/vary/accept-encoding-and-other" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.vary == "Accept-Encoding,Other"
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/vary/other-and-accept-encoding" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.vary == "Other,Accept-Encoding"
+ gunzip
+ expect resp.bodylen == 100
+
+ txreq -url "/vary/empty" \
+ -hdr "Accept-Encoding: gzip"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.vary == "Accept-Encoding"
+ gunzip
+ expect resp.bodylen == 100
+} -run
diff --git a/reg-tests/connection/ca-auth.crt b/reg-tests/connection/ca-auth.crt
new file mode 120000
index 0000000..815a970
--- /dev/null
+++ b/reg-tests/connection/ca-auth.crt
@@ -0,0 +1 @@
+../ssl/ca-auth.crt \ No newline at end of file
diff --git a/reg-tests/connection/cli_src_dst.vtc b/reg-tests/connection/cli_src_dst.vtc
new file mode 100644
index 0000000..6809d39
--- /dev/null
+++ b/reg-tests/connection/cli_src_dst.vtc
@@ -0,0 +1,290 @@
+varnishtest "Test multi-level client source and destination addresses"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ tcp-request connection set-src ipv4(10.0.0.1)
+ tcp-request connection set-dst ipv4(10.0.0.2)
+
+ tcp-request session set-var(sess.sess_fc_src) fc_src
+ tcp-request session set-var(sess.sess_fc_dst) fc_dst
+ tcp-request session set-var(sess.sess_src) src
+ tcp-request session set-var(sess.sess_dst) dst
+
+ tcp-request inspect-delay 100ms
+ tcp-request content set-var(txn.strm_fc_src) fc_src
+ tcp-request content set-var(txn.strm_fc_dst) fc_dst
+ tcp-request content set-var(txn.strm_src) src
+ tcp-request content set-var(txn.strm_dst) dst
+
+ http-after-response set-header sess-fc-src %[var(sess.sess_fc_src)]
+ http-after-response set-header sess-src %[var(sess.sess_src)]
+ http-after-response set-header sess-fc-dst %[var(sess.sess_fc_dst)]
+ http-after-response set-header sess-dst %[var(sess.sess_dst)]
+ http-after-response set-header strm-fc-src %[var(txn.strm_fc_src)]
+ http-after-response set-header strm-src %[var(txn.strm_src)]
+ http-after-response set-header strm-fc-dst %[var(txn.strm_fc_dst)]
+ http-after-response set-header strm-dst %[var(txn.strm_dst)]
+
+ default_backend be
+
+ frontend fe2
+ bind "fd@${fe2}"
+ tcp-request connection set-src ipv4(10.0.0.1)
+ tcp-request connection set-dst ipv4(10.0.0.2)
+
+ tcp-request session set-src ipv4(10.1.0.1)
+ tcp-request session set-dst ipv4(10.1.0.2)
+ tcp-request session set-var(sess.sess_fc_src) fc_src
+ tcp-request session set-var(sess.sess_fc_dst) fc_dst
+ tcp-request session set-var(sess.sess_src) src
+ tcp-request session set-var(sess.sess_dst) dst
+
+ tcp-request inspect-delay 100ms
+ tcp-request content set-var(txn.strm_fc_src) fc_src
+ tcp-request content set-var(txn.strm_fc_dst) fc_dst
+ tcp-request content set-var(txn.strm_src) src
+ tcp-request content set-var(txn.strm_dst) dst
+
+ http-after-response set-header sess-fc-src %[var(sess.sess_fc_src)]
+ http-after-response set-header sess-src %[var(sess.sess_src)]
+ http-after-response set-header sess-fc-dst %[var(sess.sess_fc_dst)]
+ http-after-response set-header sess-dst %[var(sess.sess_dst)]
+ http-after-response set-header strm-fc-src %[var(txn.strm_fc_src)]
+ http-after-response set-header strm-src %[var(txn.strm_src)]
+ http-after-response set-header strm-fc-dst %[var(txn.strm_fc_dst)]
+ http-after-response set-header strm-dst %[var(txn.strm_dst)]
+
+ default_backend be
+
+ frontend fe3
+ bind "fd@${fe3}"
+ tcp-request connection set-src ipv4(10.0.0.1)
+ tcp-request connection set-dst ipv4(10.0.0.2)
+
+ tcp-request session set-src ipv4(10.1.0.1)
+ tcp-request session set-dst ipv4(10.1.0.2)
+ tcp-request session set-var(sess.sess_fc_src) fc_src
+ tcp-request session set-var(sess.sess_fc_dst) fc_dst
+ tcp-request session set-var(sess.sess_src) src
+ tcp-request session set-var(sess.sess_dst) dst
+
+ tcp-request inspect-delay 100ms
+ tcp-request content set-src ipv4(10.2.0.1)
+ tcp-request content set-dst ipv4(10.2.0.2)
+ tcp-request content set-var(txn.strm_fc_src) fc_src
+ tcp-request content set-var(txn.strm_fc_dst) fc_dst
+ tcp-request content set-var(txn.strm_src) src
+ tcp-request content set-var(txn.strm_dst) dst
+
+ http-after-response set-header sess-fc-src %[var(sess.sess_fc_src)]
+ http-after-response set-header sess-src %[var(sess.sess_src)]
+ http-after-response set-header sess-fc-dst %[var(sess.sess_fc_dst)]
+ http-after-response set-header sess-dst %[var(sess.sess_dst)]
+ http-after-response set-header strm-fc-src %[var(txn.strm_fc_src)]
+ http-after-response set-header strm-src %[var(txn.strm_src)]
+ http-after-response set-header strm-fc-dst %[var(txn.strm_fc_dst)]
+ http-after-response set-header strm-dst %[var(txn.strm_dst)]
+
+
+ frontend fe4
+ bind "fd@${fe4}"
+
+ tcp-request connection set-src ipv4(10.0.0.1)
+ tcp-request connection set-dst ipv4(10.0.0.2)
+
+ tcp-request session set-var(sess.sess_fc_src) fc_src
+ tcp-request session set-var(sess.sess_fc_dst) fc_dst
+ tcp-request session set-var(sess.sess_src) src
+ tcp-request session set-var(sess.sess_dst) dst
+
+ http-request set-src hdr(x-forwarded-for)
+ http-request set-dst hdr(x-original-to)
+ http-request set-var(txn.strm_fc_src) fc_src
+ http-request set-var(txn.strm_fc_dst) fc_dst
+ http-request set-var(txn.strm_src) src
+ http-request set-var(txn.strm_dst) dst
+
+ http-after-response set-header sess-fc-src %[var(sess.sess_fc_src)]
+ http-after-response set-header sess-src %[var(sess.sess_src)]
+ http-after-response set-header sess-fc-dst %[var(sess.sess_fc_dst)]
+ http-after-response set-header sess-dst %[var(sess.sess_dst)]
+ http-after-response set-header strm-fc-src %[var(txn.strm_fc_src)]
+ http-after-response set-header strm-src %[var(txn.strm_src)]
+ http-after-response set-header strm-fc-dst %[var(txn.strm_fc_dst)]
+ http-after-response set-header strm-dst %[var(txn.strm_dst)]
+
+ default_backend be
+
+ backend be
+ http-request return status 200
+
+ listen li1
+ bind "fd@${li1}"
+
+ tcp-request connection set-src ipv4(10.0.0.1)
+ tcp-request connection set-dst ipv4(10.0.0.2)
+
+ http-request set-src ipv4(192.168.0.1)
+ http-request set-dst ipv4(192.168.0.2)
+
+ http-after-response set-header li1-fc-src %[fc_src]
+ http-after-response set-header li1-src %[src]
+ http-after-response set-header li1-fc-dst %[fc_dst]
+ http-after-response set-header li1-dst %[dst]
+
+
+ server srv ${h1_li3_addr}:${h1_li3_port} send-proxy
+
+ listen li2
+ bind "fd@${li2}"
+
+ tcp-request connection set-src ipv4(10.0.0.1)
+ tcp-request connection set-dst ipv4(10.0.0.2)
+
+ http-request set-src ipv4(192.168.0.1)
+ http-request set-dst ipv4(192.168.0.2)
+
+ http-after-response set-header li2-fc-src %[fc_src]
+ http-after-response set-header li2-src %[src]
+ http-after-response set-header li2-fc-dst %[fc_dst]
+ http-after-response set-header li2-dst %[dst]
+
+ server srv ${h1_li3_addr}:${h1_li3_port} send-proxy-v2
+
+ listen li3
+ bind "fd@${li3}" accept-proxy
+
+ tcp-request connection set-src ipv4(10.1.0.1)
+ tcp-request connection set-dst ipv4(10.1.0.2)
+
+ http-after-response set-header li3-fc-src %[fc_src]
+ http-after-response set-header li3-src %[src]
+ http-after-response set-header li3-fc-dst %[fc_dst]
+ http-after-response set-header li3-dst %[dst]
+
+ http-request return status 200
+
+} -start
+
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq
+ rxresp
+ expect resp.http.sess-fc-src == 10.0.0.1
+ expect resp.http.sess-src == 10.0.0.1
+ expect resp.http.strm-fc-src == 10.0.0.1
+ expect resp.http.strm-src == 10.0.0.1
+
+ expect resp.http.sess-fc-dst == 10.0.0.2
+ expect resp.http.sess-dst == 10.0.0.2
+ expect resp.http.strm-fc-dst == 10.0.0.2
+ expect resp.http.strm-dst == 10.0.0.2
+} -run
+
+client c2 -connect ${h1_fe2_sock} {
+ txreq
+ rxresp
+ expect resp.http.sess-fc-src == 10.0.0.1
+ expect resp.http.sess-src == 10.1.0.1
+ expect resp.http.strm-fc-src == 10.0.0.1
+ expect resp.http.strm-src == 10.1.0.1
+
+ expect resp.http.sess-fc-dst == 10.0.0.2
+ expect resp.http.sess-dst == 10.1.0.2
+ expect resp.http.strm-fc-dst == 10.0.0.2
+ expect resp.http.strm-dst == 10.1.0.2
+} -run
+
+client c3 -connect ${h1_fe3_sock} {
+ txreq
+ rxresp
+ expect resp.http.sess-fc-src == 10.0.0.1
+ expect resp.http.sess-src == 10.1.0.1
+ expect resp.http.strm-fc-src == 10.0.0.1
+ expect resp.http.strm-src == 10.2.0.1
+
+ expect resp.http.sess-fc-dst == 10.0.0.2
+ expect resp.http.sess-dst == 10.1.0.2
+ expect resp.http.strm-fc-dst == 10.0.0.2
+ expect resp.http.strm-dst == 10.2.0.2
+} -run
+
+client c4 -connect ${h1_fe4_sock} {
+ txreq \
+ -hdr "x-forwarded-for: 192.168.0.1" \
+ -hdr "x-original-to: 192.168.0.2"
+ rxresp
+ expect resp.http.sess-fc-src == 10.0.0.1
+ expect resp.http.sess-src == 10.0.0.1
+ expect resp.http.strm-fc-src == 10.0.0.1
+ expect resp.http.strm-src == 192.168.0.1
+
+ expect resp.http.sess-fc-dst == 10.0.0.2
+ expect resp.http.sess-dst == 10.0.0.2
+ expect resp.http.strm-fc-dst == 10.0.0.2
+ expect resp.http.strm-dst == 192.168.0.2
+
+ txreq \
+ -hdr "x-forwarded-for: 192.168.1.1" \
+ -hdr "x-original-to: 192.168.1.2"
+ rxresp
+ expect resp.http.sess-fc-src == 10.0.0.1
+ expect resp.http.sess-src == 10.0.0.1
+ expect resp.http.strm-fc-src == 10.0.0.1
+ expect resp.http.strm-src == 192.168.1.1
+
+ expect resp.http.sess-fc-dst == 10.0.0.2
+ expect resp.http.sess-dst == 10.0.0.2
+ expect resp.http.strm-fc-dst == 10.0.0.2
+ expect resp.http.strm-dst == 192.168.1.2
+
+ txreq
+ rxresp
+ expect resp.http.sess-fc-src == 10.0.0.1
+ expect resp.http.sess-src == 10.0.0.1
+ expect resp.http.strm-fc-src == 10.0.0.1
+ expect resp.http.strm-src == 10.0.0.1
+
+ expect resp.http.sess-fc-dst == 10.0.0.2
+ expect resp.http.sess-dst == 10.0.0.2
+ expect resp.http.strm-fc-dst == 10.0.0.2
+ expect resp.http.strm-dst == 10.0.0.2
+} -run
+
+client c5 -connect ${h1_li1_sock} {
+ txreq
+ rxresp
+ expect resp.http.li1-fc-src == 10.0.0.1
+ expect resp.http.li1-src == 192.168.0.1
+ expect resp.http.li1-fc-dst == 10.0.0.2
+ expect resp.http.li1-dst == 192.168.0.2
+
+ expect resp.http.li3-fc-src == 10.1.0.1
+ expect resp.http.li3-src == 192.168.0.1
+ expect resp.http.li3-fc-dst == 10.1.0.2
+ expect resp.http.li3-dst == 192.168.0.2
+} -run
+
+client c6 -connect ${h1_li2_sock} {
+ txreq
+ rxresp
+ expect resp.http.li2-fc-src == 10.0.0.1
+ expect resp.http.li2-src == 192.168.0.1
+ expect resp.http.li2-fc-dst == 10.0.0.2
+ expect resp.http.li2-dst == 192.168.0.2
+
+ expect resp.http.li3-fc-src == 10.1.0.1
+ expect resp.http.li3-src == 192.168.0.1
+ expect resp.http.li3-fc-dst == 10.1.0.2
+ expect resp.http.li3-dst == 192.168.0.2
+} -run
diff --git a/reg-tests/connection/client1.pem b/reg-tests/connection/client1.pem
new file mode 120000
index 0000000..c4d14f0
--- /dev/null
+++ b/reg-tests/connection/client1.pem
@@ -0,0 +1 @@
+../ssl/client1.pem \ No newline at end of file
diff --git a/reg-tests/connection/common.pem b/reg-tests/connection/common.pem
new file mode 120000
index 0000000..a4433d5
--- /dev/null
+++ b/reg-tests/connection/common.pem
@@ -0,0 +1 @@
+../ssl/common.pem \ No newline at end of file
diff --git a/reg-tests/connection/dispatch.vtc b/reg-tests/connection/dispatch.vtc
new file mode 100644
index 0000000..8696b50
--- /dev/null
+++ b/reg-tests/connection/dispatch.vtc
@@ -0,0 +1,42 @@
+varnishtest "Validate proper operation of the 'dispatch' mode"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+server s2 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+defaults
+ log global
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+listen fe_tcp
+ bind "fd@${fe_tcp}"
+ mode tcp
+ dispatch ${s1_addr}:${s1_port}
+
+listen fe_http
+ bind "fd@${fe_http}"
+ mode http
+ dispatch ${s2_addr}:${s2_port}
+} -start
+
+client c1 -connect ${h1_fe_tcp_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c2 -connect ${h1_fe_http_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/connection/http_reuse_aggressive.vtc b/reg-tests/connection/http_reuse_aggressive.vtc
new file mode 100644
index 0000000..71f4cee
--- /dev/null
+++ b/reg-tests/connection/http_reuse_aggressive.vtc
@@ -0,0 +1,45 @@
+varnishtest "Test the http-reuse aggressive mode"
+
+#REQUIRE_VERSION=2.2
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+
+ listen sender
+ bind "fd@${feS}"
+ http-reuse aggressive
+ server srv ${h1_feR_addr}:${h1_feR_port}
+
+ listen receiver
+ bind "fd@${feR}"
+ http-request return status 200
+ http-after-response set-header http_first_request %[http_first_req]
+} -start
+
+# bootstrap
+client c1 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "1"
+} -run
+
+# first request should not be reused as no safe connection for the moment
+client c2 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+} -run
+
+# first request must be reused with the safe connection
+client c3 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+} -run
diff --git a/reg-tests/connection/http_reuse_always.vtc b/reg-tests/connection/http_reuse_always.vtc
new file mode 100644
index 0000000..3dbd7c0
--- /dev/null
+++ b/reg-tests/connection/http_reuse_always.vtc
@@ -0,0 +1,43 @@
+varnishtest "Test the http-reuse always mode"
+
+#REQUIRE_VERSION=2.2
+
+feature ignore_unknown_macro
+
+haproxy h1 -W -conf {
+ defaults
+ mode http
+
+ listen sender
+ bind "fd@${feS}"
+ http-reuse always
+ server srv ${h1_feR_addr}:${h1_feR_port}
+
+ listen receiver
+ bind "fd@${feR}"
+ http-request return status 200
+ http-after-response set-header http_first_request %[http_first_req]
+} -start
+
+# bootstrap
+client c1 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "1"
+} -run
+
+client c2 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+} -run
+
+client c3 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+} -run
diff --git a/reg-tests/connection/http_reuse_be_transparent.vtc b/reg-tests/connection/http_reuse_be_transparent.vtc
new file mode 100644
index 0000000..3fb9e7a
--- /dev/null
+++ b/reg-tests/connection/http_reuse_be_transparent.vtc
@@ -0,0 +1,82 @@
+varnishtest "Test the proper interaction between http-reuse and backend in transparent mode"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(TPROXY)'"
+
+# If backend is used with the transparent mode, the connection are considered
+# as private and should only be reused for requests of the same session.
+# This is similar to the http-reuse never mode
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+
+ listen sender
+ bind "fd@${feS}"
+ http-request set-header client-id %[req.hdr(client-id)] if { req.hdr(client-id) -m found }
+ option transparent
+ http-request set-dst-port int(${h1_feR_port})
+
+ listen receiver
+ bind "fd@${feR}"
+ http-request set-var(sess.client_id) req.hdr(client-id)
+ http-request return status 200
+ http-after-response set-header http_first_request %[http_first_req]
+ http-after-response set-header client-id %[var(sess.client_id)]
+} -start
+
+client c1 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c1"
+ rxresp
+ expect resp.http.http_first_request == "1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+} -run
+
+client c2 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c2"
+ rxresp
+ expect resp.http.http_first_request == "1"
+ expect resp.http.client-id == "c2"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c2"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c2"
+} -run
+
+client c3 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c3"
+ rxresp
+ expect resp.http.http_first_request == "1"
+ expect resp.http.client-id == "c3"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c3"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c3"
+} -run
+
diff --git a/reg-tests/connection/http_reuse_conn_hash.vtc b/reg-tests/connection/http_reuse_conn_hash.vtc
new file mode 100644
index 0000000..991e86f
--- /dev/null
+++ b/reg-tests/connection/http_reuse_conn_hash.vtc
@@ -0,0 +1,163 @@
+varnishtest "Test the http-reuse with special connection parameters"
+#REQUIRE_VERSION=2.4
+#REQUIRE_OPTIONS=OPENSSL
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+
+ # sni
+ listen sender-sni
+ bind "fd@${feS_sni}"
+ server srv2 ${h1_feR_ssl_addr}:${h1_feR_ssl_port} ssl sni "req.hdr(x-sni)" verify none pool-low-conn 2
+
+ # set-dst
+ # specify dst1_addr for server, which should be identical to dst2_addr
+ # port is specified by the client in header x-dst-port
+ listen sender-set-dst
+ bind "fd@${feS_dst}"
+ http-request set-dst-port hdr(x-dst-port)
+ server srv2 ${h1_feR_dst1_addr}:0 pool-low-conn 2
+
+ # proxy protocol
+ # must use reuse always as consecutive requests are from different client
+ listen sender-proxy
+ bind "fd@${feS_proxy}" accept-proxy
+ http-reuse always
+ server srv2 ${h1_feR_proxy_addr}:${h1_feR_proxy_port} send-proxy pool-low-conn 2
+
+ listen receiver
+ bind "fd@${feR_ssl}" ssl crt ${testdir}/common.pem
+ bind "fd@${feR_proxy}" accept-proxy
+ http-request return status 200
+ http-after-response set-header http_first_request %[http_first_req]
+
+ listen receiver-dst1
+ bind "fd@${feR_dst1}"
+ http-request return status 200 hdr "x-dst" "dst1"
+ http-after-response set-header http_first_request %[http_first_req]
+
+ listen receiver-dst2
+ bind "fd@${feR_dst2}"
+ http-request return status 200 hdr "x-dst" "dst2"
+ http-after-response set-header http_first_request %[http_first_req]
+} -start
+
+# http-reuse with sni parameters
+client c_sni -connect ${h1_feS_sni_sock} {
+ # first request
+ txreq \
+ -hdr "x-sni: www.custom.com"
+ rxresp
+ expect resp.http.http_first_request == "1"
+
+ # second request with same sni, connection must be reused
+ txreq \
+ -hdr "x-sni: www.custom.com"
+ rxresp
+ expect resp.http.http_first_request == "0"
+
+ # third request with a different sni, a new connection must be used
+ txreq \
+ -hdr "x-sni: www.custom2.com"
+ rxresp
+ expect resp.http.http_first_request == "1"
+
+ # fourth request, reuse sni2
+ txreq \
+ -hdr "x-sni: www.custom2.com"
+ rxresp
+ expect resp.http.http_first_request == "0"
+} -run
+
+# http-reuse with destination address
+client c_dst1 -connect ${h1_feS_dst_sock} {
+ txreq \
+ -hdr "x-dst-port: ${h1_feR_dst1_port}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-dst == "dst1"
+ expect resp.http.http_first_request == "1"
+
+ txreq \
+ -hdr "x-dst-port: ${h1_feR_dst1_port}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-dst == "dst1"
+ expect resp.http.http_first_request == "0"
+
+ txreq \
+ -hdr "x-dst-port: ${h1_feR_dst2_port}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-dst == "dst2"
+ expect resp.http.http_first_request == "1"
+
+ txreq \
+ -hdr "x-dst-port: ${h1_feR_dst1_port}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-dst == "dst1"
+ expect resp.http.http_first_request == "0"
+
+ txreq \
+ -hdr "x-dst-port: ${h1_feR_dst2_port}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-dst == "dst2"
+ expect resp.http.http_first_request == "0"
+} -run
+
+## first request with proxy protocol
+client c_proxy -connect ${h1_feS_proxy_sock} -proxy1 "127.0.0.1:40000 ${h1_feS_proxy_addr}:${h1_feS_proxy_port}" {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.http_first_request == "1"
+
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.http_first_request == "0"
+} -run
+
+## second request with different proxy protocol
+# this have the nice effect to fill the server pool to 2 connection
+# (pool-low-conn value) to allow takeover on multi thread run
+client c_proxy -connect ${h1_feS_proxy_sock} -proxy1 "127.0.0.1:50000 ${h1_feS_proxy_addr}:${h1_feS_proxy_port}" {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.http_first_request == "1"
+} -run
+
+## third request, reuse same proxy protocol entry
+client c_proxy -connect ${h1_feS_proxy_sock} -proxy1 "127.0.0.1:40000 ${h1_feS_proxy_addr}:${h1_feS_proxy_port}" {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.http_first_request == "0"
+} -run
+
+## fourth request with different proxy protocol entry, no reuse
+client c_proxy -connect ${h1_feS_proxy_sock} -proxy1 "127.0.0.1:60000 ${h1_feS_proxy_addr}:${h1_feS_proxy_port}" {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.http_first_request == "1"
+} -run
+
+## fifth request, reuse proxy protocol
+client c_proxy -connect ${h1_feS_proxy_sock} -proxy1 "127.0.0.1:50000 ${h1_feS_proxy_addr}:${h1_feS_proxy_port}" {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.http_first_request == "0"
+
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.http_first_request == "0"
+} -run
diff --git a/reg-tests/connection/http_reuse_dispatch.vtc b/reg-tests/connection/http_reuse_dispatch.vtc
new file mode 100644
index 0000000..a419727
--- /dev/null
+++ b/reg-tests/connection/http_reuse_dispatch.vtc
@@ -0,0 +1,79 @@
+varnishtest "Test the proper interaction between http-reuse and dispatch mode"
+
+# With dispatch, the connection are considered as private and should only be
+# reused for requests of the same session
+# This is similar to the http-reuse never mode
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+
+ listen sender
+ bind "fd@${feS}"
+ http-request set-header client-id %[req.hdr(client-id)] if { req.hdr(client-id) -m found }
+ dispatch ${h1_feR_addr}:${h1_feR_port}
+
+ listen receiver
+ bind "fd@${feR}"
+ http-request set-var(sess.client_id) req.hdr(client-id)
+ http-request return status 200
+ http-after-response set-header http_first_request %[http_first_req]
+ http-after-response set-header client-id %[var(sess.client_id)]
+} -start
+
+client c1 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c1"
+ rxresp
+ expect resp.http.http_first_request == "1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+} -run
+
+client c2 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c2"
+ rxresp
+ expect resp.http.http_first_request == "1"
+ expect resp.http.client-id == "c2"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c2"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c2"
+} -run
+
+client c3 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c3"
+ rxresp
+ expect resp.http.http_first_request == "1"
+ expect resp.http.client-id == "c3"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c3"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c3"
+} -run
diff --git a/reg-tests/connection/http_reuse_never.vtc b/reg-tests/connection/http_reuse_never.vtc
new file mode 100644
index 0000000..fc74631
--- /dev/null
+++ b/reg-tests/connection/http_reuse_never.vtc
@@ -0,0 +1,79 @@
+varnishtest "Test the http-reuse never mode"
+
+#REQUIRE_VERSION=2.2
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+
+ # limit idle pool to one connection
+ # this is to mirror http-reuse safe test, but in this case to ensure that
+ # connection are never reused as expected
+ listen sender
+ bind "fd@${feS}"
+ http-reuse never
+ http-request set-header client-id %[req.hdr(client-id)] if { req.hdr(client-id) -m found }
+ server srv ${h1_feR_addr}:${h1_feR_port} pool-max-conn 1
+
+ listen receiver
+ bind "fd@${feR}"
+ http-request set-var(sess.client_id) req.hdr(client-id)
+ http-request return status 200
+ http-after-response set-header http_first_request %[http_first_req]
+ http-after-response set-header client-id %[var(sess.client_id)]
+} -start
+
+client c1 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c1"
+ rxresp
+ expect resp.http.http_first_request == "1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+} -run
+
+client c2 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c2"
+ rxresp
+ expect resp.http.http_first_request == "1"
+ expect resp.http.client-id == "c2"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c2"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c2"
+} -run
+
+client c3 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c3"
+ rxresp
+ expect resp.http.http_first_request == "1"
+ expect resp.http.client-id == "c3"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c3"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c3"
+} -run
diff --git a/reg-tests/connection/http_reuse_safe.vtc b/reg-tests/connection/http_reuse_safe.vtc
new file mode 100644
index 0000000..fa00dd4
--- /dev/null
+++ b/reg-tests/connection/http_reuse_safe.vtc
@@ -0,0 +1,78 @@
+varnishtest "Test the http-reuse safe mode"
+
+#REQUIRE_VERSION=2.2
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+
+ # limit idle pool to one connection
+ # this forces connection reuse for the transaction after the first one
+ listen sender
+ bind "fd@${feS}"
+ http-reuse safe
+ http-request set-header client-id %[req.hdr(client-id)] if { req.hdr(client-id) -m found }
+ server srv ${h1_feR_addr}:${h1_feR_port} pool-max-conn 1
+
+ listen receiver
+ bind "fd@${feR}"
+ http-request set-var(sess.client_id) req.hdr(client-id)
+ http-request return status 200
+ http-after-response set-header http_first_request %[http_first_req]
+ http-after-response set-header client-id %[var(sess.client_id)]
+} -start
+
+client c1 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c1"
+ rxresp
+ expect resp.http.http_first_request == "1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+} -run
+
+client c2 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c2"
+ rxresp
+ expect resp.http.http_first_request == "1"
+ expect resp.http.client-id == "c2"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+} -run
+
+client c3 -connect ${h1_feS_sock} {
+ txreq \
+ -hdr "client-id: c3"
+ rxresp
+ expect resp.http.http_first_request == "1"
+ expect resp.http.client-id == "c3"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+
+ txreq
+ rxresp
+ expect resp.http.http_first_request == "0"
+ expect resp.http.client-id == "c1"
+} -run
diff --git a/reg-tests/connection/proxy_protocol_random_fail.vtc b/reg-tests/connection/proxy_protocol_random_fail.vtc
new file mode 100644
index 0000000..1ae33de
--- /dev/null
+++ b/reg-tests/connection/proxy_protocol_random_fail.vtc
@@ -0,0 +1,59 @@
+#commit b406b87
+# BUG/MEDIUM: connection: don't store recv() result into trash.data
+#
+# Cyril Bonté discovered that the proxy protocol randomly fails since
+# commit 843b7cb ("MEDIUM: chunks: make the chunk struct's fields match
+# the buffer struct"). This is because we used to store recv()'s return
+# code into trash.data which is now unsigned, so it never compares as
+# negative against 0. Let's clean this up and test the result itself
+# without storing it first.
+
+varnishtest "PROXY protocol random failures"
+#REQUIRE_OPTIONS=OPENSSL
+
+feature ignore_unknown_macro
+
+#REGTEST_TYPE=broken
+
+syslog Slog_1 -repeat 8 -level info {
+ recv
+ expect ~ "Connect from .* to ${h1_ssl_addr}:${h1_ssl_port}"
+ recv
+ expect ~ "ssl-offload-http/http .* \"POST (https://.*:${h1_ssl_port})?/[1-8] HTTP/(2\\.0|1\\.1)\""
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ log ${Slog_1_addr}:${Slog_1_port} len 2048 local0 debug err
+
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ log global
+
+ listen http
+ bind unix@"${tmpdir}/http.socket" accept-proxy name ssl-offload-http
+ option forwardfor
+
+ listen ssl-offload-http
+ option httplog
+ bind "fd@${ssl}" ssl crt ${testdir}/common.pem ssl no-sslv3 alpn h2,http/1.1
+ server http unix@"${tmpdir}/http.socket" send-proxy
+} -start
+
+
+shell {
+ HOST=${h1_ssl_addr}
+ if [ "$HOST" = "::1" ] ; then
+ HOST="\[::1\]"
+ fi
+ for i in 1 2 3 4 5 6 7 8 ; do
+ urls="$urls https://$HOST:${h1_ssl_port}/$i"
+ done
+ curl -i -k -d 'x=x' $urls & wait $!
+}
+
+syslog Slog_1 -wait
diff --git a/reg-tests/connection/proxy_protocol_send_generic.vtc b/reg-tests/connection/proxy_protocol_send_generic.vtc
new file mode 100644
index 0000000..605f38c
--- /dev/null
+++ b/reg-tests/connection/proxy_protocol_send_generic.vtc
@@ -0,0 +1,74 @@
+varnishtest "Check that generic TLV IDs are sent properly"
+
+#REQUIRE_VERSION=2.2
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ log global
+
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen sender
+ bind "fd@${feS}"
+ server example ${h1_feR_addr}:${h1_feR_port} send-proxy-v2 set-proxy-v2-tlv-fmt(0xE1) %[str("foo")] set-proxy-v2-tlv-fmt(0xE2)
+
+ listen receiver
+ bind "fd@${feR}" accept-proxy
+
+ # Check that the TLV value is set in the backend.
+ http-request set-var(txn.custom_tlv_a) fc_pp_tlv(0xE1)
+ http-after-response set-header proxy_custom_tlv_a %[var(txn.custom_tlv_a)]
+
+ # Check that TLVs without an value are sent out.
+ http-request set-var(txn.custom_tlv_b) fc_pp_tlv(0xE2)
+ http-after-response set-header proxy_custom_tlv_b %[var(txn.custom_tlv_b)]
+
+ # Note that we do not check for an invalid TLV ID as that would result in an
+ # parser error anyway.
+
+ http-request return status 200
+} -start
+
+
+client c1 -connect ${h1_feS_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.http.proxy_custom_tlv_a == "foo"
+ expect resp.http.proxy_custom_tlv_b == ""
+} -run
+
+# Ensure that we achieve the same via a default-server.
+haproxy h2 -conf {
+ defaults
+ mode http
+ log global
+
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen sender
+ bind "fd@${feS}"
+ default-server send-proxy-v2 set-proxy-v2-tlv-fmt(0xE1) %[str("bar")]
+ server example ${h1_feR_addr}:${h1_feR_port}
+
+ listen receiver
+ bind "fd@${feR}" accept-proxy
+
+ http-request set-var(txn.custom_tlv_a) fc_pp_tlv(0xE1)
+ http-after-response set-header proxy_custom_tlv_a %[var(txn.custom_tlv_a)]
+
+ http-request return status 200
+} -start
+
+
+client c2 -connect ${h2_feS_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.http.proxy_custom_tlv_a == "bar"
+} -run
diff --git a/reg-tests/connection/proxy_protocol_send_unique_id.vtc b/reg-tests/connection/proxy_protocol_send_unique_id.vtc
new file mode 100644
index 0000000..4f6b848
--- /dev/null
+++ b/reg-tests/connection/proxy_protocol_send_unique_id.vtc
@@ -0,0 +1,42 @@
+varnishtest "Check that the unique ID TLV is properly sent"
+
+#REQUIRE_VERSION=2.2
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ log global
+ unique-id-format %{+X}o\ TEST-%[req.hdr(in)]
+
+ listen sender
+ bind "fd@${feS}"
+
+ unique-id-header unique_id
+
+ server example ${h1_feR_addr}:${h1_feR_port} send-proxy-v2 proxy-v2-options unique-id
+
+ listen receiver
+ bind "fd@${feR}" accept-proxy
+
+ http-request set-var(txn.http_unique_id) req.hdr(unique_id)
+ http-request set-var(txn.proxy_unique_id) fc_pp_unique_id
+ http-after-response set-header http_unique_id %[var(txn.http_unique_id)]
+ http-after-response set-header proxy_unique_id %[var(txn.proxy_unique_id)]
+ http-request return status 200
+} -start
+
+# Validate that a correct header passes
+client c1 -connect ${h1_feS_sock} {
+ txreq -url "/" \
+ -hdr "in: foo"
+ rxresp
+ expect resp.http.http_unique_id == "TEST-foo"
+ expect resp.http.proxy_unique_id == "TEST-foo"
+ txreq -url "/" \
+ -hdr "in: bar"
+ rxresp
+ expect resp.http.http_unique_id == "TEST-bar"
+ expect resp.http.proxy_unique_id == "TEST-bar"
+} -run
diff --git a/reg-tests/connection/proxy_protocol_send_unique_id_alpn.vtc b/reg-tests/connection/proxy_protocol_send_unique_id_alpn.vtc
new file mode 100644
index 0000000..87e590a
--- /dev/null
+++ b/reg-tests/connection/proxy_protocol_send_unique_id_alpn.vtc
@@ -0,0 +1,33 @@
+varnishtest "Check that the unique ID TLV is properly sent for servers with ALPN option"
+
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTIONS=OPENSSL
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ log global
+ unique-id-format %{+X}o\ TEST-%[req.hdr(in)]
+
+ listen sender
+ bind "fd@${feS}"
+
+ server example ${h1_feR_addr}:${h1_feR_port} send-proxy-v2 proxy-v2-options unique-id ssl alpn XXX verify none
+
+ listen receiver
+ bind "fd@${feR}" ssl crt ${testdir}/common.pem accept-proxy
+
+ http-request set-var(txn.proxy_unique_id) fc_pp_unique_id
+ http-after-response set-header proxy_unique_id %[var(txn.proxy_unique_id)]
+ http-request return status 200
+} -start
+
+# Validate that a correct header passes
+client c1 -connect ${h1_feS_sock} {
+ txreq -url "/" \
+ -hdr "in: foo"
+ rxresp
+ expect resp.http.proxy_unique_id == "TEST-foo"
+} -run
diff --git a/reg-tests/connection/proxy_protocol_tlv_validation.vtc b/reg-tests/connection/proxy_protocol_tlv_validation.vtc
new file mode 100644
index 0000000..8c7d734
--- /dev/null
+++ b/reg-tests/connection/proxy_protocol_tlv_validation.vtc
@@ -0,0 +1,142 @@
+varnishtest "Check that the TLVs are properly validated"
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+# We need one HAProxy for each test, because apparently the connection by
+# the client is reused, leading to connection resets.
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend a
+ bind "fd@${fe1}" accept-proxy
+ http-after-response set-header echo %[fc_pp_authority,hex]
+ http-request return status 200
+} -start
+
+# Validate that a correct header passes
+client c1 -connect ${h1_fe1_sock} {
+ # PROXY v2 signature
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ # version + PROXY
+ sendhex "21"
+ # TCP4
+ sendhex "11"
+ # length of the address (12) + length of the TLV (8)
+ sendhex "00 14"
+ # 127.0.0.1 42 127.0.0.1 1337
+ sendhex "7F 00 00 01 7F 00 00 01 00 2A 05 39"
+ # PP2_TYPE_AUTHORITY + length of the value + "12345"
+ sendhex "02 00 05 31 32 33 34 35"
+
+ txreq -url "/"
+ rxresp
+ expect resp.http.echo == "3132333435"
+} -run
+
+haproxy h2 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend a
+ bind "fd@${fe1}" accept-proxy
+ http-after-response set-header echo %[fc_pp_authority,hex]
+ http-request return status 200
+} -start
+
+# Validate that a TLV after the end of the PROXYv2 header is not parsed
+# and handle by the HTTP parser, leading to a 400 bad request error
+client c2 -connect ${h2_fe1_sock} {
+ # PROXY v2 signature
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ # version + PROXY
+ sendhex "21"
+ # TCP4
+ sendhex "11"
+ # length of the address (12) + length of the TLV (8)
+ sendhex "00 14"
+ # 127.0.0.1 42 127.0.0.1 1337
+ sendhex "7F 00 00 01 7F 00 00 01 00 2A 05 39"
+ # PP2_TYPE_AUTHORITY + length of the value + "12345"
+ sendhex "02 00 05 31 32 33 34 35"
+ # after the end of the PROXYv2 header: PP2_TYPE_AUTHORITY + length of the value + "54321"
+ sendhex "02 00 05 35 34 33 32 31"
+
+ txreq -url "/"
+ rxresp
+ expect resp.status == 400
+ expect resp.http.echo == <undef>
+} -run
+
+haproxy h3 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend a
+ bind "fd@${fe1}" accept-proxy
+ http-after-response set-header echo %[fc_pp_authority,hex]
+ http-request return status 200
+} -start
+
+# Validate that a TLV length exceeding the PROXYv2 length fails
+client c3 -connect ${h3_fe1_sock} {
+ # PROXY v2 signature
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ # version + PROXY
+ sendhex "21"
+ # TCP4
+ sendhex "11"
+ # length of the address (12) + too small length of the TLV (8)
+ sendhex "00 14"
+ # 127.0.0.1 42 127.0.0.1 1337
+ sendhex "7F 00 00 01 7F 00 00 01 00 2A 05 39"
+ # PP2_TYPE_AUTHORITY + length of the value + "1234512345"
+ sendhex "02 00 0A 31 32 33 34 35 31 32 33 34 35"
+
+ txreq -url "/"
+ expect_close
+} -run
+
+haproxy h4 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend a
+ bind "fd@${fe1}" accept-proxy
+ http-after-response set-header echo %[fc_pp_authority,hex]
+ http-request return status 200
+} -start
+
+# Validate that TLVs not ending with the PROXYv2 header fail
+client c4 -connect ${h4_fe1_sock} {
+ # PROXY v2 signature
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ # version + PROXY
+ sendhex "21"
+ # TCP4
+ sendhex "11"
+ # length of the address (12) + too big length of the TLV (8)
+ sendhex "00 14"
+ # 127.0.0.1 42 127.0.0.1 1337
+ sendhex "7F 00 00 01 7F 00 00 01 00 2A 05 39"
+ # PP2_TYPE_AUTHORITY + length of the value + "1234"
+ sendhex "02 00 04 31 32 33 34"
+
+ txreq -url "/"
+ expect_close
+} -run
diff --git a/reg-tests/connection/reverse_connect_full.vtc b/reg-tests/connection/reverse_connect_full.vtc
new file mode 100644
index 0000000..238831f
--- /dev/null
+++ b/reg-tests/connection/reverse_connect_full.vtc
@@ -0,0 +1,70 @@
+varnishtest "Reverse connect full test"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.9
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+haproxy h_edge -conf {
+global
+ expose-experimental-directives
+
+defaults
+ log global
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ mode http
+
+frontend pub
+ bind "fd@${pub}"
+ use_backend be-reverse
+
+frontend priv
+ bind "fd@${priv}" proto h2
+ tcp-request session attach-srv be-reverse/dev
+
+backend be-reverse
+ server dev rhttp@
+} -start
+
+haproxy h_dev -conf {
+global
+ expose-experimental-directives
+
+defaults
+ log global
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ mode http
+
+frontend fe
+ bind "rhttp@be-pre-connect/srv"
+ use_backend be
+
+backend be-pre-connect
+ server srv ${h_edge_priv_addr}:${h_edge_priv_port} proto h2
+
+backend be
+ server srv ${s1_addr}:${s1_port}
+}
+
+client c1 -connect ${h_edge_pub_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 503
+} -run
+
+haproxy h_dev -start
+# TODO replace delay by a proper wait
+delay 3
+
+client c1 -connect ${h_edge_pub_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/connection/reverse_server.vtc b/reg-tests/connection/reverse_server.vtc
new file mode 100644
index 0000000..50fe8ce
--- /dev/null
+++ b/reg-tests/connection/reverse_server.vtc
@@ -0,0 +1,69 @@
+varnishtest "Reverse server test"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.9
+
+barrier b1 cond 2
+
+haproxy h_edge -conf {
+global
+ expose-experimental-directives
+
+defaults
+ log global
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ mode http
+
+frontend pub
+ bind "fd@${pub}"
+ use_backend be-reverse
+
+backend be-reverse
+ server dev rhttp@
+
+frontend priv
+ bind "fd@${priv}" proto h2
+ tcp-request session attach-srv be-reverse/dev
+} -start
+
+# Run a client through public endpoint
+# Reverse server has no connection available thus a 503 is expected
+client c1 -connect ${h_edge_pub_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 503
+} -run
+
+# Run a client through private endpoint
+# Connection will be attached to the reverse server
+client c_dev -connect ${h_edge_priv_sock} {
+ txpri
+
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ barrier b1 sync
+ stream 1 {
+ rxhdrs
+ } -run
+
+ sendhex "000004 01 05 00000001 88 5c 01 30"
+} -start
+
+# Wait for dev client to be ready to process connection
+barrier b1 sync
+
+# Run a client through public endpoint
+# Reverse server should now be able to proceed with the request
+client c2 -connect ${h_edge_pub_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/connection/reverse_server_name.vtc b/reg-tests/connection/reverse_server_name.vtc
new file mode 100644
index 0000000..0fd850f
--- /dev/null
+++ b/reg-tests/connection/reverse_server_name.vtc
@@ -0,0 +1,87 @@
+varnishtest "Reverse server with a name parameter test"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.9
+
+barrier b1 cond 2
+
+haproxy h_edge -conf {
+global
+ expose-experimental-directives
+
+defaults
+ log global
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ mode http
+
+frontend pub
+ bind "fd@${pub}"
+ use_backend be-reverse
+
+backend be-reverse
+ server dev rhttp@ ssl sni hdr(x-name) verify none
+
+frontend priv
+ bind "fd@${priv}" ssl crt ${testdir}/common.pem verify required ca-verify-file ${testdir}/ca-auth.crt alpn h2
+ tcp-request session attach-srv be-reverse/dev name ssl_c_s_dn(CN)
+} -start
+
+# Simple clear <-> SSL bridge between clients and h_edge haproxy
+# Used certificate has the name "client1"
+haproxy h_ssl_bridge -conf {
+defaults
+ log global
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ mode tcp
+
+listen li
+ bind "fd@${li}"
+ server h_edge "${h_edge_priv_addr}:${h_edge_priv_port}" ssl crt ${testdir}/client1.pem verify none alpn h2
+} -start
+
+# Run a client through private endpoint
+# Connection will be attached to the reverse server
+client c_dev -connect ${h_ssl_bridge_li_sock} {
+ txpri
+
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ barrier b1 sync
+ stream 1 {
+ rxhdrs
+ } -run
+
+ sendhex "000004 01 05 00000001 88 5c 01 30"
+} -start
+
+# Wait for dev client to be ready to process connection
+barrier b1 sync
+
+# Run a client through public endpoint
+# Use a different name than the client certificate thus resulting in a 503
+client c1 -connect ${h_edge_pub_sock} {
+ txreq -url "/" \
+ -hdr "x-name: client99"
+ rxresp
+ expect resp.status == 503
+} -run
+
+# Run a client through public endpoint
+# Use the correct name
+client c2 -connect ${h_edge_pub_sock} {
+ txreq -url "/" \
+ -hdr "x-name: client1"
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/connection/tcp_to_http_upgrade.vtc b/reg-tests/connection/tcp_to_http_upgrade.vtc
new file mode 100644
index 0000000..48ebeba
--- /dev/null
+++ b/reg-tests/connection/tcp_to_http_upgrade.vtc
@@ -0,0 +1,169 @@
+varnishtest "Test connection upgrades from TCP to HTTP"
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+server s1 {
+ # TCP > H1 using "switch-mode http"
+ rxreq
+ expect req.http.x-stream-mode == tcp
+ expect req.http.x-name == fe1
+ txresp
+ rxreq
+ expect req.http.x-stream-mode == http
+ expect req.http.x-name == fe1
+ txresp
+
+ accept
+
+ # TCP > H1 using backend mode
+ rxreq
+ expect req.http.x-name == be
+ txresp
+ rxreq
+ expect req.http.x-name == be
+ txresp
+
+ accept
+
+ # TCP > H2 using "switch-mode http"
+ rxreq
+ expect req.http.x-stream-mode == http
+ expect req.http.x-name == fe1
+ txresp
+ rxreq
+ expect req.http.x-stream-mode == http
+ expect req.http.x-name == fe1
+ txresp
+
+ # To be sure no other request was received
+ accept
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ frontend fe1
+ mode tcp
+ bind "fd@${fe1h1}"
+
+ tcp-request inspect-delay 1s
+ tcp-request content set-var(req.stream_mode) internal.strm.is_htx,iif(http,tcp)
+ tcp-request content switch-mode http if HTTP
+ tcp-request content reject # never reached
+
+ http-request set-header x-stream-mode %[var(req.stream_mode)]
+ http-request set-header x-name %[fe_name]
+
+ default_backend be
+
+ frontend fe2
+ mode tcp
+ bind "fd@${fe2h1}"
+ default_backend be
+
+ backend be
+ mode http
+ http-request set-header x-name %[be_name] unless { req.fhdr(x-name) -m found }
+ server s1 ${s1_addr}:${s1_port}
+
+ listen li1
+ mode http
+ bind "fd@${li1h1}"
+ server s1 ${h1_fe1h1_addr}:${h1_fe1h1_port} proto h2
+
+ listen err1
+ mode http
+ bind "fd@${err1h1}" proto h1
+ server s1 ${s1_addr}:${s1_port}
+
+ listen err2
+ mode tcp
+ bind "fd@${err2h1}"
+
+ tcp-request inspect-delay 1s
+ tcp-request content switch-mode http proto h1 if HTTP
+ tcp-request content reject # never reached
+
+ default_backend be
+
+ listen err3
+ mode tcp
+ bind "fd@${err3h1}" proto none
+
+ tcp-request inspect-delay 1s
+ tcp-request content switch-mode http if HTTP
+ tcp-request content reject # never reached
+
+ default_backend be
+} -start
+
+# TCP > H1 using "switch-mode http"
+client c1 -connect ${h1_fe1h1_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+# TCP > H1 using backend mode
+client c2 -connect ${h1_fe2h1_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+
+# TCP > H2 using "switch-mode http"
+client c3 -connect ${h1_li1h1_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+# implicit H1 > H2 upgrade not performed
+client c_err1 -connect ${h1_err1h1_sock} {
+ send "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+ rxresp
+ expect resp.status == 400
+} -run
+
+
+# TCP > H1 > H2 upgrade not allowed
+client c_err2 -connect ${h1_err2h1_sock} {
+ send "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+ rxresp
+ expect resp.status == 400
+} -run
+
+
+# TCP > HTTP upgrade not allowed
+client c_err3 -connect ${h1_err3h1_sock} {
+ txreq
+ expect_close
+} -run
+
+# TCP > HTTP upgrade with a parsing error
+client c_err4 -connect ${h1_fe2h1_sock} {
+ send "GET / BAD-VERSION\r\n\r\n"
+ rxresp
+ expect resp.status == 400
+} -run
+
+# To be sure no other request was received by the server
+client c_end -connect ${s1_sock} {
+ txreq
+ rxresp
+} -run
diff --git a/reg-tests/contrib/prometheus.vtc b/reg-tests/contrib/prometheus.vtc
new file mode 100644
index 0000000..a481240
--- /dev/null
+++ b/reg-tests/contrib/prometheus.vtc
@@ -0,0 +1,113 @@
+varnishtest "prometheus exporter test"
+
+#REQUIRE_VERSION=2.4
+#REQUIRE_SERVICES=prometheus-exporter
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+server s2 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ option socket-stats
+
+ listen stats
+ bind "fd@${stats}"
+ http-request use-service prometheus-exporter if { path /metrics }
+
+ frontend fe
+ bind "fd@${fe}"
+ default_backend be
+
+ backend be
+ stick-table type ip size 1m expire 10s store http_req_rate(10s)
+ option httpchk
+ server s1 ${s1_addr}:${s1_port}
+ server s2 ${s2_addr}:${s2_port} check inter 5s maxqueue 10 maxconn 12 pool-max-conn 42
+} -start
+
+client c1 -connect ${h1_stats_sock} {
+ txreq -url "/metrics"
+ rxresp
+ # test general metrics
+ expect resp.status == 200
+ expect resp.body ~ ".*haproxy_process.*"
+ expect resp.body ~ ".*haproxy_frontend.*"
+ expect resp.body ~ ".*haproxy_listener.*"
+ expect resp.body ~ ".*haproxy_backend.*"
+ expect resp.body ~ ".*haproxy_server.*"
+ expect resp.body ~ ".*haproxy_sticktable.*"
+
+ # test expected NaN values
+ expect resp.body ~ ".*haproxy_server_check_failures_total{proxy=\"be\",server=\"s1\"} NaN.*"
+ expect resp.body ~ ".*haproxy_server_check_up_down_total{proxy=\"be\",server=\"s1\"} NaN.*"
+ expect resp.body ~ ".*haproxy_server_check_failures_total{proxy=\"be\",server=\"s2\"} 0.*"
+ expect resp.body ~ ".*haproxy_server_check_up_down_total{proxy=\"be\",server=\"s2\"} 0.*"
+
+ expect resp.body ~ ".*haproxy_server_queue_limit{proxy=\"be\",server=\"s1\"} NaN.*"
+ expect resp.body ~ ".*haproxy_server_queue_limit{proxy=\"be\",server=\"s2\"} 10.*"
+
+ expect resp.body ~ ".*haproxy_server_limit_sessions{proxy=\"be\",server=\"s1\"} NaN.*"
+ expect resp.body ~ ".*haproxy_server_limit_sessions{proxy=\"be\",server=\"s2\"} 12.*"
+
+ expect resp.body ~ ".*haproxy_backend_downtime_seconds_total{proxy=\"stats\"} NaN.*"
+ expect resp.body ~ ".*haproxy_backend_downtime_seconds_total{proxy=\"be\"} 0.*"
+ expect resp.body ~ ".*haproxy_server_downtime_seconds_total{proxy=\"be\",server=\"s1\"} NaN.*"
+ expect resp.body ~ ".*haproxy_server_downtime_seconds_total{proxy=\"be\",server=\"s2\"} 0.*"
+
+ expect resp.body ~ ".*haproxy_server_current_throttle{proxy=\"be\",server=\"s1\"} NaN.*"
+
+ expect resp.body ~ ".*haproxy_server_idle_connections_limit{proxy=\"be\",server=\"s1\"} NaN.*"
+ expect resp.body ~ ".*haproxy_server_idle_connections_limit{proxy=\"be\",server=\"s2\"} 42.*"
+
+ # test well known labels presence
+ expect resp.body ~ ".*haproxy_process_build_info{version=\".*\"} 1.*"
+ expect resp.body ~ ".*haproxy_frontend_http_responses_total{proxy=\"stats\",code=\"4xx\"} 0.*"
+ expect resp.body ~ ".*haproxy_frontend_status{proxy=\"fe\",state=\"UP\"} 1.*"
+ expect resp.body ~ ".*haproxy_listener_status{proxy=\"stats\",listener=\"sock-1\",state=\"WAITING\"} 0.*"
+ expect resp.body ~ ".*haproxy_backend_status{proxy=\"be\",state=\"UP\"} 1.*"
+ expect resp.body ~ ".*haproxy_server_status{proxy=\"be\",server=\"s1\",state=\"DOWN\"} 0.*"
+ expect resp.body ~ ".*haproxy_server_check_status{proxy=\"be\",server=\"s2\",state=\"HANA\"} 0.*"
+
+ # test scope
+ txreq -url "/metrics?scope="
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 0
+
+ txreq -url "/metrics?scope=server"
+ rxresp
+ expect resp.status == 200
+ expect resp.body !~ ".*haproxy_process.*"
+ expect resp.body !~ ".*haproxy_frontend.*"
+ expect resp.body !~ ".*haproxy_listener.*"
+ expect resp.body !~ ".*haproxy_backend.*"
+ expect resp.body ~ ".*haproxy_server.*"
+ expect resp.body !~ ".*haproxy_sticktable.*"
+
+ txreq -url "/metrics?scope=frontend&scope=backend"
+ rxresp
+ expect resp.status == 200
+ expect resp.body !~ ".*haproxy_process.*"
+ expect resp.body ~ ".*haproxy_frontend.*"
+ expect resp.body !~ ".*haproxy_listener.*"
+ expect resp.body ~ ".*haproxy_backend.*"
+ expect resp.body !~ ".*haproxy_server.*"
+ expect resp.body !~ ".*haproxy_sticktable.*"
+
+ txreq -url "/metrics?scope"
+ rxresp
+ expect resp.status == 400
+} -run
diff --git a/reg-tests/converter/add_item.vtc b/reg-tests/converter/add_item.vtc
new file mode 100644
index 0000000..474ad7b
--- /dev/null
+++ b/reg-tests/converter/add_item.vtc
@@ -0,0 +1,50 @@
+varnishtest "be2dec converter Test"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.6-dev0)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 3 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.input) req.hdr(input)
+ http-request set-var(txn.var) str("var_content")
+
+ http-response set-header add_item-1 "%[var(txn.input),add_item(',',txn.var,_suff_)]"
+ http-response set-header add_item-2 "%[var(txn.input),add_item(',',txn.var)]"
+ http-response set-header add_item-3 "%[var(txn.input),add_item(',',,_suff_)]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/" \
+ -hdr "input:"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.add_item-1 == "var_content_suff_"
+ expect resp.http.add_item-2 == "var_content"
+ expect resp.http.add_item-3 == "_suff_"
+ txreq -url "/" \
+ -hdr "input: input_string"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.add_item-1 == "input_string,var_content_suff_"
+ expect resp.http.add_item-2 == "input_string,var_content"
+ expect resp.http.add_item-3 == "input_string,_suff_"
+} -run
diff --git a/reg-tests/converter/be2dec.vtc b/reg-tests/converter/be2dec.vtc
new file mode 100644
index 0000000..a0b7104
--- /dev/null
+++ b/reg-tests/converter/be2dec.vtc
@@ -0,0 +1,56 @@
+varnishtest "be2dec converter Test"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 3 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.input) req.hdr(input)
+
+ http-response set-header be2dec-1 "%[var(txn.input),be2dec(:,1)]"
+ http-response set-header be2dec-2 "%[var(txn.input),be2dec(-,3)]"
+ http-response set-header be2dec-3 "%[var(txn.input),be2dec(::,3,1)]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/" \
+ -hdr "input:"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.be2dec-1 == ""
+ expect resp.http.be2dec-2 == ""
+ expect resp.http.be2dec-3 == ""
+ txreq -url "/" \
+ -hdr "input: 0123456789"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.be2dec-1 == "48:49:50:51:52:53:54:55:56:57"
+ expect resp.http.be2dec-2 == "3158322-3355701-3553080-57"
+ expect resp.http.be2dec-3 == "3158322::3355701::3553080"
+ txreq -url "/" \
+ -hdr "input: abcdefghijklmnopqrstuvwxyz"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.be2dec-1 == "97:98:99:100:101:102:103:104:105:106:107:108:109:110:111:112:113:114:115:116:117:118:119:120:121:122"
+ expect resp.http.be2dec-2 == "6382179-6579558-6776937-6974316-7171695-7369074-7566453-7763832-31098"
+ expect resp.http.be2dec-3 == "6382179::6579558::6776937::6974316::7171695::7369074::7566453::7763832"
+} -run
diff --git a/reg-tests/converter/be2hex.vtc b/reg-tests/converter/be2hex.vtc
new file mode 100644
index 0000000..4cf3dc1
--- /dev/null
+++ b/reg-tests/converter/be2hex.vtc
@@ -0,0 +1,60 @@
+varnishtest "be2hex converter Test"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 3 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.input) req.hdr(input)
+
+ http-response set-header be2hex "%[var(txn.input),be2hex,lower]"
+ http-response set-header be2hex-1 "%[var(txn.input),be2hex(:,1),lower]"
+ http-response set-header be2hex-2 "%[var(txn.input),be2hex(--,3),lower]"
+ http-response set-header be2hex-3 "%[var(txn.input),be2hex(.,3,1),lower]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/" \
+ -hdr "input:"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.be2hex == ""
+ expect resp.http.be2hex-1 == ""
+ expect resp.http.be2hex-2 == ""
+ expect resp.http.be2hex-3 == ""
+ txreq -url "/" \
+ -hdr "input: 0123456789"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.be2hex == "30313233343536373839"
+ expect resp.http.be2hex-1 == "30:31:32:33:34:35:36:37:38:39"
+ expect resp.http.be2hex-2 == "303132--333435--363738--39"
+ expect resp.http.be2hex-3 == "303132.333435.363738"
+ txreq -url "/" \
+ -hdr "input: abcdefghijklmnopqrstuvwxyz"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.be2hex == "6162636465666768696a6b6c6d6e6f707172737475767778797a"
+ expect resp.http.be2hex-1 == "61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:78:79:7a"
+ expect resp.http.be2hex-2 == "616263--646566--676869--6a6b6c--6d6e6f--707172--737475--767778--797a"
+ expect resp.http.be2hex-3 == "616263.646566.676869.6a6b6c.6d6e6f.707172.737475.767778"
+} -run
diff --git a/reg-tests/converter/bytes.vtc b/reg-tests/converter/bytes.vtc
new file mode 100644
index 0000000..8abe401
--- /dev/null
+++ b/reg-tests/converter/bytes.vtc
@@ -0,0 +1,156 @@
+varnishtest "bytes converter Test"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.9-dev4)'"
+
+feature ignore_unknown_macro
+
+# TEST - 1
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 1 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.input) req.hdr(input)
+
+ http-response set-header bytes_0 "%[var(txn.input),bytes(0)]"
+ http-response set-header bytes_1 "%[var(txn.input),bytes(1)]"
+ http-response set-header bytes_0_3 "%[var(txn.input),bytes(0,3)]"
+ http-response set-header bytes_1_3 "%[var(txn.input),bytes(1,3)]"
+ http-response set-header bytes_99 "%[var(txn.input),bytes(99)]"
+ http-response set-header bytes_5 "%[var(txn.input),bytes(5)]"
+ http-response set-header bytes_6 "%[var(txn.input),bytes(6)]"
+ http-response set-header bytes_0_6 "%[var(txn.input),bytes(0,6)]"
+ http-response set-header bytes_0_7 "%[var(txn.input),bytes(0,7)]"
+
+ http-response set-var(txn.var_start) int(0)
+ http-response set-header bytes_var0 "%[var(txn.input),bytes(txn.var_start)]"
+
+ http-response set-var(txn.var_start) int(1)
+ http-response set-var(txn.var_length) int(3)
+ http-response set-header bytes_var1_var3 "%[var(txn.input),bytes(txn.var_start,txn.var_length)]"
+
+ http-response set-var(txn.var_start) int(99)
+ http-response set-header bytes_var99 "%[var(txn.input),bytes(txn.var_start)]"
+
+ http-response set-var(txn.var_start) int(0)
+ http-response set-var(txn.var_length) int(7)
+ http-response set-header bytes_var0_var7 "%[var(txn.input),bytes(txn.var_start,txn.var_length)]"
+
+ http-response set-var(txn.var_start) int(1)
+ http-response set-var(txn.var_length) int(3)
+ http-response set-header bytes_var1_3 "%[var(txn.input),bytes(txn.var_start,3)]"
+ http-response set-header bytes_1_var3 "%[var(txn.input),bytes(1,txn.var_length)]"
+
+ http-response set-var(txn.var_start) int(-1)
+ http-response set-var(txn.var_length) int(-1)
+ http-response set-header bytes_varminus1 "%[var(txn.input),bytes(txn.var_start)]"
+ http-response set-header bytes_0_varminus1 "%[var(txn.input),bytes(0,txn.var_length)]"
+
+ http-response set-header bytes_varNA "%[var(txn.input),bytes(txn.NA)]"
+ http-response set-header bytes_1_varNA "%[var(txn.input),bytes(1,txn.NA)]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/" \
+ -hdr "input: 012345"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.bytes_0 == "012345"
+ expect resp.http.bytes_1 == "12345"
+ expect resp.http.bytes_0_3 == "012"
+ expect resp.http.bytes_1_3 == "123"
+ expect resp.http.bytes_99 == ""
+ expect resp.http.bytes_5 == "5"
+ expect resp.http.bytes_6 == ""
+ expect resp.http.bytes_0_6 == "012345"
+
+ # since specified length is > input length, response contains the input till the end
+ expect resp.http.bytes_0_7 == "012345"
+
+ expect resp.http.bytes_var0 == "012345"
+ expect resp.http.bytes_var1_var3 == "123"
+ expect resp.http.bytes_var99 == ""
+ expect resp.http.bytes_var0_var7 == "012345"
+ expect resp.http.bytes_var1_3 == "123"
+ expect resp.http.bytes_1_var3 == "123"
+ expect resp.http.bytes_varminus1 == ""
+ expect resp.http.bytes_0_varminus1 == ""
+ expect resp.http.bytes_varNA == ""
+ expect resp.http.bytes_1_varNA == ""
+} -run
+
+# TEST - 2
+# negative starting index causes startup failure
+haproxy h2 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ http-response set-header bytes_output "%[var(txn.input),bytes(-1)]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start -expectexit 1
+
+# TEST - 3
+# negative length causes startup failure
+haproxy h3 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ http-response set-header bytes_output "%[var(txn.input),bytes(0,-1)]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start -expectexit 1
+
+# TEST - 4
+# 0 length causes startup failure
+haproxy h4 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ http-response set-header bytes_output "%[var(txn.input),bytes(0,0)]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start -expectexit 1
diff --git a/reg-tests/converter/digest.vtc b/reg-tests/converter/digest.vtc
new file mode 100644
index 0000000..e911ff4
--- /dev/null
+++ b/reg-tests/converter/digest.vtc
@@ -0,0 +1,57 @@
+varnishtest "digest converter Test"
+
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTION=OPENSSL
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.hash) req.hdr(hash)
+
+ http-response set-header SHA1 "%[var(txn.hash),digest(sha1),hex,lower]"
+ http-response set-header SHA224 "%[var(txn.hash),digest(sha224),hex,lower]"
+ http-response set-header SHA256 "%[var(txn.hash),digest(sha256),hex,lower]"
+ http-response set-header SHA384 "%[var(txn.hash),digest(sha384),hex,lower]"
+ http-response set-header SHA512 "%[var(txn.hash),digest(sha512),hex,lower]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/" \
+ -hdr "Hash: 1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.sha1 == "356a192b7913b04c54574d18c28d46e6395428ab"
+ expect resp.http.sha224 == "e25388fde8290dc286a6164fa2d97e551b53498dcbf7bc378eb1f178"
+ expect resp.http.sha256 == "6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b"
+ expect resp.http.sha384 == "47f05d367b0c32e438fb63e6cf4a5f35c2aa2f90dc7543f8a41a0f95ce8a40a313ab5cf36134a2068c4c969cb50db776"
+ expect resp.http.sha512 == "4dff4ea340f0a823f15d3f4f01ab62eae0e5da579ccb851f8db9dfe84c58b2b37b89903a740e1ee172da793a6e79d560e5f7f9bd058a12a280433ed6fa46510a"
+ txreq -url "/" \
+ -hdr "Hash: 2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.sha1 == "da4b9237bacccdf19c0760cab7aec4a8359010b0"
+ expect resp.http.sha224 == "58b2aaa0bfae7acc021b3260e941117b529b2e69de878fd7d45c61a9"
+ expect resp.http.sha256 == "d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35"
+ expect resp.http.sha384 == "d063457705d66d6f016e4cdd747db3af8d70ebfd36badd63de6c8ca4a9d8bfb5d874e7fbd750aa804dcaddae7eeef51e"
+ expect resp.http.sha512 == "40b244112641dd78dd4f93b6c9190dd46e0099194d5a44257b7efad6ef9ff4683da1eda0244448cb343aa688f5d3efd7314dafe580ac0bcbf115aeca9e8dc114"
+} -run
diff --git a/reg-tests/converter/field.vtc b/reg-tests/converter/field.vtc
new file mode 100644
index 0000000..3b1d819
--- /dev/null
+++ b/reg-tests/converter/field.vtc
@@ -0,0 +1,43 @@
+varnishtest "field converter Test"
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 3 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.uri) path
+ http-response set-header Found %[var(txn.uri),field(3,/)] if { var(txn.uri),field(3,/) -m found }
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/foo/bar/baz"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "bar"
+ txreq -url "/foo//bar/baz"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == ""
+ txreq -url "/foo"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "<undef>"
+} -run
diff --git a/reg-tests/converter/fix.vtc b/reg-tests/converter/fix.vtc
new file mode 100644
index 0000000..8206da3
--- /dev/null
+++ b/reg-tests/converter/fix.vtc
@@ -0,0 +1,235 @@
+varnishtest "fix converters Test"
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+server s1 {
+ # Valid FIX-4.0 logon
+ recv 92
+ # 8=FIX|4.0|9=66|35=A|34=1|49=EXECUTOR|52=20201029-10:54:19|56=CLIENT1|98=0|108=30|10=147|
+ sendhex "383d4649582e342e3001393d36360133353d410133343d310134393d4558454355544f520135323d32303230313032392d31303a35343a31390135363d434c49454e54310139383d30013130383d33300131303d31343701"
+ close
+
+ # Valid FIX-4.1 logon
+ accept
+ recv 98
+ # 8=FIX.4.1|9=72|35=A|34=1|49=EXECUTOR|52=20201029-12:43:07|56=CLIENT1|98=0|108=30|141=Y|10=187|
+ sendhex "383d4649582e342e3101393d37320133353d410133343d310134393d4558454355544f520135323d32303230313032392d31323a34333a30370135363d434c49454e54310139383d30013130383d3330013134313d590131303d31383701"
+ close
+
+ # Valid FIX-4.2 logon
+ accept
+ recv 98
+ # 8=FIX.4.2|9=79|35=A|34=1|49=EXECUTOR|52=20201029-12:55:12.101414|56=CLIENT1|98=0|108=30|141=Y|10=027|
+ sendhex "383d4649582e342e3201393d37390133353d410133343d310134393d4558454355544f520135323d32303230313032392d31323a35353a31322e3130313431340135363d434c49454e54310139383d30013130383d3330013134313d590131303d30323701"
+ close
+
+ # Valid FIX-4.3 logon
+ accept
+ recv 125
+ # 8=FIX.4.3|9=79|35=A|34=1|49=EXECUTOR|52=20201029-12:58:50.891371|56=CLIENT1|98=0|108=30|141=Y|10=051|
+ sendhex "383d4649582e342e3301393d37390133353d410133343d310134393d4558454355544f520135323d32303230313032392d31323a35383a35302e3839313337310135363d434c49454e54310139383d30013130383d3330013134313d590131303d30353101"
+ close
+
+ # Valid FIX-4.4 logon
+ accept
+ recv 125
+ # 8=FIX.4.4|9=79|35=A|34=1|49=EXECUTOR|52=20201029-13:02:44.535360|56=CLIENT1|98=0|108=30|141=Y|10=038|
+ sendhex "383d4649582e342e3401393d37390133353d410133343d310134393d4558454355544f520135323d32303230313032392d31333a30323a34342e3533353336300135363d434c49454e54310139383d30013130383d3330013134313d590131303d30333801"
+ close
+
+ # Valid FIX-5.0 logon
+ accept
+ recv 140
+ # 8=FIXT.1.1|9=86|35=A|34=1|49=EXECUTOR|52=20201029-13:13:22.626384|56=CLIENT1|98=0|108=30|141=Y|1137=7|10=184|
+ sendhex "383d464958542e312e3101393d38360133353d410133343d310134393d4558454355544f520135323d32303230313032392d31333a31333a32322e3632363338340135363d434c49454e54310139383d30013130383d3330013134313d5901313133373d370131303d31383401"
+} -start
+
+server s2 {
+ # Valid FIX-4.4 logon
+ recv 125
+ # 8=FIX.4.4|9=79|35=A|34=1|49=EXECUTOR|52=20201029-13:02:44.535360|56=CLIENT1|98=0|108=30|141=Y|10=038|
+ sendhex "383d4649582e342e3401393d37390133353d410133343d310134393d4558454355544f520135323d32303230313032392d31333a30323a34342e3533353336300135363d434c49454e54310139383d30013130383d3330013134313d590131303d30333801"
+
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ tcp-request inspect-delay 1s
+ tcp-request content reject unless { req.payload(0,0),fix_is_valid }
+ default_backend be1
+
+ frontend fe2
+ bind "fd@${fe2}"
+ tcp-request inspect-delay 1s
+ tcp-request content reject unless { req.payload(0,0),fix_is_valid }
+ tcp-request content set-var(req.fix_vsn) req.payload(0,0),fix_tag_value(BeginString)
+ tcp-request content set-var(req.fix_len) req.payload(0,0),fix_tag_value(BodyLength)
+ tcp-request content set-var(req.fix_type) req.payload(0,0),fix_tag_value(MsgType)
+ tcp-request content set-var(req.fix_sender) req.payload(0,0),fix_tag_value(SenderCompID)
+ tcp-request content set-var(req.fix_target) req.payload(0,0),fix_tag_value(TargetCompID)
+ tcp-request content set-var(req.fix_chksum) req.payload(0,0),fix_tag_value(CheckSum)
+ tcp-request content reject if ! { var(req.fix_vsn) -m str "FIX.4.4" } || ! { var(req.fix_len) -m str "102" }
+ tcp-request content reject if ! { var(req.fix_type) -m str "A" } || ! { var(req.fix_sender) -m str "CLIENT1" }
+ tcp-request content reject if ! { var(req.fix_target) -m str "EXECUTOR" } || ! { var(req.fix_chksum) -m str "252" }
+ default_backend be2
+
+ backend be1
+ server s1 ${s1_addr}:${s1_port}
+ tcp-response inspect-delay 1s
+ tcp-response content reject unless { res.payload(0,0),fix_is_valid }
+
+ backend be2
+ server s2 ${s2_addr}:${s2_port}
+ tcp-response inspect-delay 1s
+ tcp-response content reject unless { res.payload(0,0),fix_is_valid }
+ tcp-response content set-var(res.fix_vsn) res.payload(0,0),fix_tag_value(8)
+ tcp-response content set-var(res.fix_len) res.payload(0,0),fix_tag_value(9)
+ tcp-response content set-var(res.fix_type) res.payload(0,0),fix_tag_value(35)
+ tcp-response content set-var(res.fix_sender) res.payload(0,0),fix_tag_value(49)
+ tcp-response content set-var(res.fix_target) res.payload(0,0),fix_tag_value(56)
+ tcp-response content set-var(res.fix_chksum) res.payload(0,0),fix_tag_value(10)
+ tcp-response content reject if ! { var(res.fix_vsn) -m str "FIX.4.4" } || ! { var(res.fix_len) -m str "79" }
+ tcp-response content reject if ! { var(res.fix_type) -m str "A" } || ! { var(res.fix_sender) -m str "EXECUTOR" }
+ tcp-response content reject if ! { var(res.fix_target) -m str "CLIENT1" } || ! { var(res.fix_chksum) -m str "038" }
+} -start
+
+client c1_4_0 -connect ${h1_fe1_sock} {
+ # Valid FIX-4.0 logon
+ # 8=FIX|4.0|9=70|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-10:54:19.617|98=0|108=30|10=090|
+ sendhex "383d4649582e342e3001393d37300133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31303a35343a31392e3631370139383d30013130383d33300131303d30393001"
+ recv 88
+ expect_close
+} -run
+
+client c1_4_1 -connect ${h1_fe1_sock} {
+ # Valid FIX-4.1 logon
+ # 8=FIX.4.1|9=76|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-12:43:07.940|98=0|108=30|141=Y|10=138|
+ sendhex "383d4649582e342e3101393d37360133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31323a34333a30372e3934300139383d30013130383d3330013134313d590131303d31333801"
+ recv 94
+ expect_close
+} -run
+
+client c1_4_2 -connect ${h1_fe1_sock} {
+ # Valid FIX-4.2 logon
+ # 8=FIX.4.2|9=76|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-12:55:12.100|98=0|108=30|141=Y|10=126|
+ sendhex "383d4649582e342e3201393d37360133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31323a35353a31322e3130300139383d30013130383d3330013134313d590131303d31323601"
+ recv 101
+ expect_close
+} -run
+
+client c1_4_3 -connect ${h1_fe1_sock} {
+ # Valid FIX-4.3 logon
+ # 8=FIX.4.3|9=102|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-12:58:50.889|98=0|108=30|141=Y|553=Username|554=Password|10=012|
+ sendhex "383d4649582e342e3301393d3130320133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31323a35383a35302e3838390139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d30313201"
+ recv 101
+ expect_close
+} -run
+
+client c1_4_4 -connect ${h1_fe1_sock} {
+ # Valid FIX-4.4 logon
+ # 8=FIX.4.4|9=102|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=0|108=30|141=Y|553=Username|554=Password|10=252|
+ sendhex "383d4649582e342e3401393d3130320133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353201"
+ recv 101
+ expect_close
+} -run
+
+client c1_5_0 -connect ${h1_fe1_sock} {
+ # Valid FIX-5.0 logon
+ # 8=FIXT.1.1|9=116|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:13:22.624|1128=7|98=0|108=30|141=Y|553=Username|554=Password|1137=7|10=204|
+ sendhex "383d464958542e312e3101393d3131360133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a31333a32322e36323401313132383d370139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f726401313133373d370131303d32303401"
+ recv 109
+ expect_close
+} -run
+
+client c2_1 -connect ${h1_fe1_sock} {
+ # InValid FIX-4.4: Empty TagName (missing EncryptMethod <98> tag name)
+ # 8=FIX.4.4|9=100|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|=0|108=30|141=Y|553=Username|554=Password|10=252|
+ sendhex "383d4649582e342e3401393d3130300133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e353238013d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353201"
+ expect_close
+} -run
+
+client c2_2 -connect ${h1_fe1_sock} {
+ # InValid FIX-4.4: Empty TagValue (missing EncryptMethod <98> tag value)
+ # 8=FIX.4.4|9=101|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=|108=30|141=Y|553=Username|554=Password|10=252|
+ sendhex "383d4649582e342e3401393d3130310133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353201"
+ expect_close
+} -run
+
+client c2_3 -connect ${h1_fe1_sock} {
+ # InValid FIX-4.4: Empty Tag no delimiter (missing delimiter for EncryptMethod <98> tag)
+ # 8=FIX.4.4|9=101|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98|108=30|141=Y|553=Username|554=Password|10=252|
+ sendhex "383d4649582e342e3401393d3130300133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e353238013938013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353201"
+ expect_close
+} -run
+
+client c2_4 -connect ${h1_fe1_sock} {
+ # Invalid FIX-4.4: First tag != BeginString
+ # 9=102|8=FIX.4.4|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=0|108=30|141=Y|553=Username|554=Password|10=252|
+ sendhex "393d31303201383d4649582e342e340133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353201"
+ expect_close
+} -run
+
+client c2_5 -connect ${h1_fe1_sock} {
+ # Invalid FIX-4.4: Second tag != BodyLength
+ # 8=FIX.4.4|35=A|9=102|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=0|108=30|141=Y|553=Username|554=Password|10=252|
+ sendhex "383d4649582e342e340133353d4101393d3130320134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353201"
+ expect_close
+} -run
+
+client c2_6 -connect ${h1_fe1_sock} {
+ # Invalid FIX-4.4: Third tag != MsgType
+ # 8=FIX.4.4|9=102|49=CLIENT1|35=A|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=0|108=30|141=Y|553=Username|554=Password|10=252|
+ sendhex "383d4649582e342e3401393d3130320134393d434c49454e54310133353d410135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353201"
+ expect_close
+} -run
+
+client c2_7 -connect ${h1_fe1_sock} {
+ # Invalid FIX-4.4: Bad body length (too short 100 != 102)
+ # 8=FIX.4.4|9=100|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=0|108=30|141=Y|553=Username|554=Password|10=252|
+ sendhex "383d4649582e342e3401393d3130300133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353201"
+ expect_close
+} -run
+
+client c2_8 -connect ${h1_fe1_sock} {
+ # Invalid FIX-4.4: Bad body length (too long 105 != 102)
+ # 8=FIX.4.4|9=105|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=0|108=30|141=Y|553=Username|554=Password|10=252|XXX
+ sendhex "383d4649582e342e3401393d3130350133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353201585858"
+ expect_close
+} -run
+
+client c2_9 -connect ${h1_fe1_sock} {
+ # Invalid FIX-4.4: Too short checksum value (< 3 digit)
+ # 8=FIX.4.4|9=102|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=0|108=30|141=Y|553=Username|554=Password|10=25|
+ sendhex "383d4649582e342e3401393d3130320133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d323501"
+ expect_close
+} -run
+
+client c2_10 -connect ${h1_fe1_sock} {
+ # Invalid FIX-4.4: Too long checksum value (> 3 digit)
+ # 8=FIX.4.4|9=102|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=0|108=30|141=Y|553=Username|554=Password|10=2520|
+ sendhex "383d4649582e342e3401393d3130320133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d3235323001"
+ expect_close
+} -run
+
+client c2_11 -connect ${h1_fe1_sock} {
+ # Invalid FIX-4.4: invalid checksum value (253 != 252)
+ # 8=FIX.4.4|9=102|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=0|108=30|141=Y|553=Username|554=Password|10=253|
+ sendhex "383d4649582e342e3401393d3130320133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353301"
+ expect_close
+} -run
+
+
+client c3_1 -connect ${h1_fe2_sock} {
+ # 8=FIX.4.4|9=102|35=A|49=CLIENT1|56=EXECUTOR|34=1|52=20201029-13:02:44.528|98=0|108=30|141=Y|553=Username|554=Password|10=252|
+ sendhex "383d4649582e342e3401393d3130320133353d410134393d434c49454e54310135363d4558454355544f520133343d310135323d32303230313032392d31333a30323a34342e3532380139383d30013130383d3330013134313d59013535333d557365726e616d65013535343d50617373776f72640131303d32353201"
+ recv 101
+ expect_close
+} -run
diff --git a/reg-tests/converter/hmac.vtc b/reg-tests/converter/hmac.vtc
new file mode 100644
index 0000000..230a44d
--- /dev/null
+++ b/reg-tests/converter/hmac.vtc
@@ -0,0 +1,55 @@
+varnishtest "HMAC converter Test"
+
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTION=OPENSSL
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.hash) req.hdr(hash)
+ http-request set-var(txn.key) str(my_super_secret_long_key),base64
+
+ http-response set-header SHA1-short "%[var(txn.hash),hmac(sha1,a2V5),hex,lower]"
+ http-response set-header SHA1-long "%[var(txn.hash),hmac(sha1,txn.key),hex,lower]"
+ http-response set-header SHA256-short "%[var(txn.hash),hmac(sha256,a2V5),hex,lower]"
+ http-response set-header SHA256-long "%[var(txn.hash),hmac(sha256,txn.key),hex,lower]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/" \
+ -hdr "Hash: 1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.sha1-short == "e23feb105f9622241bf23db1638cd2b4208b1f53"
+ expect resp.http.sha1-long == "87b10ddcf39e26f6bd7c3b0e38e0125997b255be"
+ expect resp.http.sha256-short == "6da91fb91517be1f5cdcf3af91d7d40c717dd638a306157606fb2e584f7ae926"
+ expect resp.http.sha256-long == "2fb3de6a462c54d1803f946b52202f3a8cd46548ffb3f789b4ac11a4361ffef2"
+ txreq -url "/" \
+ -hdr "Hash: 2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.sha1-short == "311219c4a80c5ef81b1cee5505236c1d0ab1922c"
+ expect resp.http.sha1-long == "c5758af565ba4b87b3db49c8b32d4a94d430cb78"
+ expect resp.http.sha256-short == "ae7b3ee87b8c9214f714df1c2042c7a985b9d711e9938a063937ad1636775a88"
+ expect resp.http.sha256-long == "c073191a2ebf29f510444b92c187d62199d84b58f58dceeadb91994c170a9a16"
+} -run
diff --git a/reg-tests/converter/iif.vtc b/reg-tests/converter/iif.vtc
new file mode 100644
index 0000000..f412daf
--- /dev/null
+++ b/reg-tests/converter/iif.vtc
@@ -0,0 +1,46 @@
+varnishtest "iif converter Test"
+#REQUIRE_VERSION=2.3
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 3 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.iif) req.hdr_cnt(count),iif(ok,ko)
+ http-response set-header iif %[var(txn.iif)]
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.iif == "ko"
+ txreq \
+ -hdr "count: 1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.iif == "ok"
+ txreq \
+ -hdr "count: 1,2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.iif == "ok"
+} -run
diff --git a/reg-tests/converter/json.vtc b/reg-tests/converter/json.vtc
new file mode 100644
index 0000000..1f37c9f
--- /dev/null
+++ b/reg-tests/converter/json.vtc
@@ -0,0 +1,40 @@
+varnishtest "json converter test"
+
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ http-response set-header json0 "%[str(foo 1/2),json]"
+ # bad UTF-8 sequence
+ http-response set-header json1 "%[str(\xE0),json(utf8)]"
+ # bad UTF-8 sequence, but removes them
+ http-response set-header json2 "%[str(-\xE0-),json(utf8s)]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.http.json0 == "foo 1\\/2"
+ expect resp.http.json1 == ""
+ expect resp.http.json2 == "--"
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/converter/json_query.vtc b/reg-tests/converter/json_query.vtc
new file mode 100644
index 0000000..f4e3bb2
--- /dev/null
+++ b/reg-tests/converter/json_query.vtc
@@ -0,0 +1,107 @@
+varnishtest "JSON Query converters Test"
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 8 -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ option http-buffer-request
+
+ frontend fe
+ bind "fd@${fe}"
+ tcp-request inspect-delay 1s
+
+ http-request set-var(sess.header_json) req.hdr(Authorization),json_query('$.iss')
+ http-request set-var(sess.pay_json) req.body,json_query('$.iss')
+ http-request set-var(sess.pay_int) req.body,json_query('$.integer',"int"),add(1)
+ http-request set-var(sess.pay_neg_int) req.body,json_query('$.negativ-integer',"int"),add(1)
+ http-request set-var(sess.pay_double) req.body,json_query('$.double')
+ http-request set-var(sess.pay_boolean_true) req.body,json_query('$.boolean-true')
+ http-request set-var(sess.pay_boolean_false) req.body,json_query('$.boolean-false')
+ http-request set-var(sess.pay_mykey) req.body,json_query('$.my\\.key')
+
+ http-response set-header x-var_header %[var(sess.header_json)]
+ http-response set-header x-var_body %[var(sess.pay_json)]
+ http-response set-header x-var_body_int %[var(sess.pay_int)]
+ http-response set-header x-var_body_neg_int %[var(sess.pay_neg_int)]
+ http-response set-header x-var_body_double %[var(sess.pay_double)]
+ http-response set-header x-var_body_boolean_true %[var(sess.pay_boolean_true)]
+ http-response set-header x-var_body_boolean_false %[var(sess.pay_boolean_false)]
+ http-response set-header x-var_body_mykey %[var(sess.pay_mykey)]
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/" \
+ -hdr "Authorization: {\"iss\":\"kubernetes.io/serviceaccount\"}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var_header ~ "kubernetes.io/serviceaccount"
+
+ txreq -url "/" \
+ -body "{\"iss\":\"kubernetes.io/serviceaccount\"}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var_body ~ "kubernetes.io/serviceaccount"
+
+ txreq -url "/" \
+ -body "{\"integer\":4}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var_body_int ~ "5"
+
+ txreq -url "/" \
+ -body "{\"integer\":-4}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var_body_int ~ "-3"
+
+ txreq -url "/" \
+ -body "{\"double\":4.5}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var_body_double ~ "4.5"
+
+ txreq -url "/" \
+ -body "{\"boolean-true\":true}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var_body_boolean_true == 1
+
+ txreq -url "/" \
+ -body "{\"boolean-false\":false}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var_body_boolean_false == 0
+
+ txreq -url "/" \
+ -body "{\"my.key\":\"myvalue\"}"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var_body_mykey ~ "myvalue"
+
+ txreq -url "/" \
+ -body "{\"my.key\":[\"val1\",\"val2\",\"val3\"],\"key2\":\"val4\"}"
+ expect resp.status == 200
+ expect resp.http.x-var_body_mykey ~ "[\"val1\",\"val2\",\"val3\"]"
+
+} -run
diff --git a/reg-tests/converter/mqtt.vtc b/reg-tests/converter/mqtt.vtc
new file mode 100644
index 0000000..fc3daca
--- /dev/null
+++ b/reg-tests/converter/mqtt.vtc
@@ -0,0 +1,238 @@
+varnishtest "mqtt converters Test"
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+server s1 {
+ # MQTT 3.1.1 CONNECT packet (id: test_subaaaaaa... [len = 200])
+ recv 215
+ sendhex "20020000"
+ close
+
+ # MQTT 3.1.1 CONNECT packet (id: <empty> - username: test - passwd: passwd)
+ accept
+ recv 28
+ sendhex "20020000"
+ close
+
+ # MQTT 3.1.1 CONNECT packet (id: test_sub - username: test - passwd: passwd - will_topic: willtopic - will_payload: willpayload)
+ accept
+ recv 60
+ sendhex "20020000"
+ close
+
+ # MQTT 5.0 CONNECT packet (id: test_sub)
+ accept
+ recv 26
+ sendhex "200600000322000a"
+
+ # MQTT 5.0 CONNECT packet (id: test_sub - username: test - passwd: passwd)
+ accept
+ recv 40
+ sendhex "200600000322000a"
+
+ # MQTT 5.0 complex CONNECT/CONNACK packet
+ accept
+ recv 128
+ sendhex "20250000221100000078217fff24012501270000ffff22000a2600016100016226000163000164"
+ close
+
+ # Invalid MQTT 3.1.1 CONNACK packet with invalid flags (!= 0x00)
+ accept
+ recv 22
+ sendhex "21020000"
+ expect_close
+
+ # MQTT 3.1 CONNECT packet (id: test_sub - username: test - passwd: passwd)
+ accept
+ recv 38
+ sendhex "20020000"
+} -start
+
+server s2 {
+ # MQTT 5.0 complex CONNECT packet
+ recv 128
+ sendhex "20250000221100000078217fff24012501270000ffff22000a2600016100016226000163000164"
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode tcp
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ tcp-request inspect-delay 1s
+ tcp-request content reject unless { req.payload(0,0),mqtt_is_valid }
+ default_backend be1
+
+ frontend fe2
+ bind "fd@${fe2}"
+ tcp-request inspect-delay 1s
+ tcp-request content reject unless { req.payload(0,0),mqtt_is_valid }
+ tcp-request content set-var(req.flags) req.payload(0,0),mqtt_field_value(connect,flags)
+ tcp-request content set-var(req.protoname) req.payload(0,0),mqtt_field_value(connect,protocol_name)
+ tcp-request content set-var(req.protovsn) req.payload(0,0),mqtt_field_value(connect,protocol_version)
+ tcp-request content set-var(req.clientid) req.payload(0,0),mqtt_field_value(connect,client_identifier)
+ tcp-request content set-var(req.willtopic) req.payload(0,0),mqtt_field_value(connect,will_topic)
+ tcp-request content set-var(req.willbody) req.payload(0,0),mqtt_field_value(connect,will_payload)
+ tcp-request content set-var(req.user) req.payload(0,0),mqtt_field_value(connect,username)
+ tcp-request content set-var(req.pass) req.payload(0,0),mqtt_field_value(connect,password)
+ tcp-request content set-var(req.maxpktsz) req.payload(0,0),mqtt_field_value(connect,39)
+ tcp-request content set-var(req.reqpbinfo) req.payload(0,0),mqtt_field_value(connect,23)
+ tcp-request content set-var(req.ctype) req.payload(0,0),mqtt_field_value(connect,3)
+ tcp-request content set-var(req.willrsptopic) req.payload(0,0),mqtt_field_value(connect,8)
+ tcp-request content reject if ! { var(req.protoname) -m str "MQTT" } || ! { var(req.protovsn) -m str "5" }
+ tcp-request content reject if ! { var(req.flags) -m str "238" } || ! { var(req.clientid) -m str "test_sub" }
+ tcp-request content reject if ! { var(req.user) -m str "test" } || ! { var(req.pass) -m str "passwd" }
+ tcp-request content reject if ! { var(req.willtopic) -m str "willtopic" } || ! { var(req.willbody) -m str "willpayload" }
+ tcp-request content reject if ! { var(req.maxpktsz) -m str "20" } || ! { var(req.reqpbinfo) -m str "1" }
+ tcp-request content reject if ! { var(req.ctype) -m str "text/plain" } || ! { var(req.willrsptopic) -m str "willrsptopic" }
+ default_backend be2
+
+ backend be1
+ server s1 ${s1_addr}:${s1_port}
+ tcp-response inspect-delay 1s
+ tcp-response content reject unless { res.payload(0,0),mqtt_is_valid }
+
+ backend be2
+ server s2 ${s2_addr}:${s2_port}
+ tcp-response inspect-delay 1s
+ tcp-response content reject unless { res.payload(0,0),mqtt_is_valid }
+ tcp-response content set-var(res.flags) res.payload(0,0),mqtt_field_value(connack,flags)
+ tcp-response content set-var(res.protovsn) res.payload(0,0),mqtt_field_value(connack,protocol_version)
+ tcp-response content set-var(res.rcode) res.payload(0,0),mqtt_field_value(connack,reason_code)
+ tcp-response content set-var(res.sessexpint) res.payload(0,0),mqtt_field_value(connack,17)
+ tcp-response content set-var(res.recvmax) res.payload(0,0),mqtt_field_value(connack,33)
+ tcp-response content set-var(res.maxqos) res.payload(0,0),mqtt_field_value(connack,36)
+ tcp-response content set-var(res.retainavail) res.payload(0,0),mqtt_field_value(connack,37)
+ tcp-response content set-var(res.maxpktsz) res.payload(0,0),mqtt_field_value(connack,39)
+ tcp-response content set-var(res.topicaliasmax) res.payload(0,0),mqtt_field_value(connack,34)
+ tcp-response content reject if ! { var(res.protovsn) -m str "5" } || ! { var(res.flags) -m str "0" }
+ tcp-response content reject if ! { var(res.rcode) -m str "0" } || ! { var(res.sessexpint) -m str "120" }
+ tcp-response content reject if ! { var(res.recvmax) -m str "32767" } || ! { var(res.maxqos) -m str "1" }
+ tcp-response content reject if ! { var(res.retainavail) -m str "1" } || ! { var(res.maxpktsz) -m str "65535" }
+ tcp-response content reject if ! { var(res.topicaliasmax) -m str "10" }
+} -start
+
+client c1_311_1 -connect ${h1_fe1_sock} {
+ # Valid MQTT 3.1.1 CONNECT packet (id: test_sub)
+ sendhex "10d40100044d5154540402003c00c8746573745f737562616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161"
+ recv 4
+ expect_close
+} -run
+
+client c1_311_2 -connect ${h1_fe1_sock} {
+ # Valid MQTT 3.1.1 CONNECT packet (id: <empty> - username: test - passwd: passwd)
+ sendhex "101a00044d51545404c2003c00000004746573740006706173737764"
+ recv 4
+ expect_close
+} -run
+
+client c1_311_3 -connect ${h1_fe1_sock} {
+ # Valid MQTT 3.1.1 CONNECT packet (id: test_sub - username: test - passwd: passwd - will_topic: willtopic - will_payload: willpayload)
+ sendhex "103a00044d51545404ee003c0008746573745f737562000977696c6c746f706963000b77696c6c7061796c6f61640004746573740006706173737764"
+ recv 4
+ expect_close
+} -run
+
+client c1_50_1 -connect ${h1_fe1_sock} {
+ # Valid MQTT 5.0 CONNECT packet (id: test_sub)
+ sendhex "101800044d5154540502003c032100140008746573745f737562"
+ recv 8
+ expect_close
+} -run
+
+client c1_50_2 -connect ${h1_fe1_sock} {
+ # Valid MQTT 5.0 CONNECT packet (id: test_sub - username: test - passwd: passwd)
+ sendhex "102600044d51545405c2003c032100140008746573745f7375620004746573740006706173737764"
+ recv 8
+ expect_close
+} -run
+
+client c1_50_3 -connect ${h1_fe1_sock} {
+ # Valid MQTT 5.0 complex CONNECT/CONNACK packet
+ sendhex "107e00044d51545405ee003c182700000014170126000161000162260001630001642100140008746573745f7375622a03000a746578742f706c61696e08000c77696c6c727370746f7069632600016500016626000167000168000977696c6c746f706963000b77696c6c7061796c6f61640004746573740006706173737764"
+ recv 39
+ expect_close
+} -run
+
+client c2_311_1 -connect ${h1_fe1_sock} {
+ # Invalid MQTT 3.1.1 PINREQ
+ sendhex "d000"
+ expect_close
+} -run
+
+client c2_311_2 -connect ${h1_fe1_sock} {
+ # Invalid MQTT 3.1.1 CONNECT packet with invalid flags (!= 0x00)
+ sendhex "111400044d5154540402003c0008746573745f737562"
+ expect_close
+} -run
+
+client c2_311_3 -connect ${h1_fe1_sock} {
+ # Invalid MQTT 3.1.1 CONNACK packet with invalid flags (!= 0x00)
+ sendhex "101400044d5154540402003c0008746573745f737562"
+ expect_close
+} -run
+
+client c2_311_4 -connect ${h1_fe1_sock} {
+ # Invalid MQTT 3.1.1 CONNECT with too long remaing_length ( > 4 bytes)
+ sendhex "10ffffffff1400044d5154540402003c0008746573745f737562"
+ expect_close
+} -run
+
+client c2_311_4 -connect ${h1_fe1_sock} {
+ # Invalid MQTT 3.1.1 CONNECT with not matching ( 0x13 != 0x14)
+ sendhex "101300044d5154540402003c000874657374a5f737562"
+ expect_close
+} -run
+
+client c2_311_4 -connect ${h1_fe1_sock} {
+ # Invalid MQTT 3.1.1 CONNECT with not matching ( 0x18 != 0x14)
+ sendhex "101800044d5154540402003c000874657374a5f737562ffffffff"
+ expect_close
+} -run
+
+
+client c2_50_1 -connect ${h1_fe2_sock} {
+ # complex MQTT 5.0 CONNECT/CONNACK packet
+ # - CONNECT :
+ # client-id : test_sub
+ # username : test
+ # password : passwd
+ # will-topic : willtopic
+ # will-payload: willpayload
+ # connect props:
+ # maximum-packet-size : 20
+ # request-problem-information: 1
+ # user-property : name=a value=b
+ # user-property : name=c value=d
+ # will props:
+ # content-type : text/plain
+ # response-topic: willrsptopic
+ # user-property : name=e value=f
+ # user-property : name=g value=h
+ # - CONNACK :
+ # flags : 0x00
+ # reason-code: 0x00
+ # connack props:
+ # session-Expiry-interval: 120
+ # receive-maximum : 32767
+ # maximum-qos : 1
+ # retain-available : 1
+ # maximum-packet-size : 65535
+ # topic-alias-maximum : 10
+ # user-property : name=a value=b
+ # user-property : name=c value=d
+ sendhex "107e00044d51545405ee003c182700000014170126000161000162260001630001642100140008746573745f7375622a03000a746578742f706c61696e08000c77696c6c727370746f7069632600016500016626000167000168000977696c6c746f706963000b77696c6c7061796c6f61640004746573740006706173737764"
+ recv 39
+ expect_close
+} -run
+
+client c3_31_1 -connect ${h1_fe1_sock} {
+ # Valid MQTT 3.1 CONNECT packet (id: test_sub - username: test - passwd: passwd)
+ sendhex "102400064d514973647003c200000008746573745f7375620004746573740006706173737764"
+ recv 4
+} -run \ No newline at end of file
diff --git a/reg-tests/converter/param.vtc b/reg-tests/converter/param.vtc
new file mode 100644
index 0000000..1633603
--- /dev/null
+++ b/reg-tests/converter/param.vtc
@@ -0,0 +1,80 @@
+varnishtest "param converter Test"
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 10 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ ### requests
+ http-request set-var(txn.query) query
+ http-response set-header Found %[var(txn.query),param(test)] if { var(txn.query),param(test) -m found }
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/foo/?test=1&b=4&d"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "1"
+
+ txreq -url "/?a=1&b=4&test=34"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "34"
+
+ txreq -url "/?test=bar"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "bar"
+
+ txreq -url "/?a=b&c=d"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "<undef>"
+
+ txreq -url "/?a=b&test=t&c=d"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "t"
+
+ txreq -url "/?a=b&test&c=d"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == ""
+
+ txreq -url "/?test="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == ""
+
+ txreq -url "/?a=b&test"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == ""
+
+ txreq -url "/?testing=123"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "<undef>"
+
+ txreq -url "/?testing=123&test=4"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "4"
+} -run
diff --git a/reg-tests/converter/secure_memcmp.vtc b/reg-tests/converter/secure_memcmp.vtc
new file mode 100644
index 0000000..6ff74e6
--- /dev/null
+++ b/reg-tests/converter/secure_memcmp.vtc
@@ -0,0 +1,143 @@
+varnishtest "secure_memcmp converter Test"
+
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTION=OPENSSL
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 4 -start
+
+server s2 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 7 -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ # This frontend matches two base64 encoded values and does not need to
+ # handle null bytes.
+
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.hash) req.hdr(hash)
+ http-request set-var(txn.raw) req.hdr(raw)
+
+ acl is_match var(txn.raw),sha1,base64,secure_memcmp(txn.hash)
+
+ http-response set-header Match true if is_match
+ http-response set-header Match false if !is_match
+
+ default_backend be
+
+ frontend fe2
+ # This frontend matches two binary values, needing to handle null
+ # bytes.
+ bind "fd@${fe2}"
+
+ #### requests
+ http-request set-var(txn.hash) req.hdr(hash),b64dec
+ http-request set-var(txn.raw) req.hdr(raw)
+
+ acl is_match var(txn.raw),sha1,secure_memcmp(txn.hash)
+
+ http-response set-header Match true if is_match
+ http-response set-header Match false if !is_match
+
+ default_backend be2
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+
+ backend be2
+ server s2 ${s2_addr}:${s2_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/" \
+ -hdr "Raw: 1" \
+ -hdr "Hash: NWoZK3kTsExUV00Ywo1G5jlUKKs="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "true"
+ txreq -url "/" \
+ -hdr "Raw: 2" \
+ -hdr "Hash: 2kuSN7rMzfGcB2DKt67EqDWQELA="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "true"
+ txreq -url "/" \
+ -hdr "Raw: 2" \
+ -hdr "Hash: 2kuSN7rMzfGcB2DKt67EqDWQELX="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "false"
+ txreq -url "/" \
+ -hdr "Raw: 3" \
+ -hdr "Hash: 2kuSN7rMzfGcB2DKt67EqDWQELA="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "false"
+} -run
+
+client c2 -connect ${h1_fe2_sock} {
+ txreq -url "/" \
+ -hdr "Raw: 1" \
+ -hdr "Hash: NWoZK3kTsExUV00Ywo1G5jlUKKs="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "true"
+ txreq -url "/" \
+ -hdr "Raw: 2" \
+ -hdr "Hash: 2kuSN7rMzfGcB2DKt67EqDWQELA="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "true"
+ txreq -url "/" \
+ -hdr "Raw: 2" \
+ -hdr "Hash: 2kuSN7rMzfGcB2DKt67EqDWQELX="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "false"
+ txreq -url "/" \
+ -hdr "Raw: 3" \
+ -hdr "Hash: 2kuSN7rMzfGcB2DKt67EqDWQELA="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "false"
+
+ # Test for values with leading nullbytes.
+ txreq -url "/" \
+ -hdr "Raw: 6132845" \
+ -hdr "Hash: AAAAVaeL9nNcSok1j6sd40EEw8s="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "true"
+ txreq -url "/" \
+ -hdr "Raw: 49177200" \
+ -hdr "Hash: AAAA9GLglTNv2JoMv2n/w9Xadhc="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "true"
+ txreq -url "/" \
+ -hdr "Raw: 6132845" \
+ -hdr "Hash: AAAA9GLglTNv2JoMv2n/w9Xadhc="
+ rxresp
+ expect resp.status == 200
+ expect resp.http.match == "false"
+} -run
diff --git a/reg-tests/converter/sha2.vtc b/reg-tests/converter/sha2.vtc
new file mode 100644
index 0000000..e90e274
--- /dev/null
+++ b/reg-tests/converter/sha2.vtc
@@ -0,0 +1,57 @@
+varnishtest "sha2 converter Test"
+
+#REQUIRE_VERSION=2.1
+#REQUIRE_OPTION=OPENSSL
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.hash) req.hdr(hash)
+
+ http-response set-header SHA2 "%[var(txn.hash),sha2,hex,lower]"
+ http-response set-header SHA2-224 "%[var(txn.hash),sha2(224),hex,lower]"
+ http-response set-header SHA2-256 "%[var(txn.hash),sha2(256),hex,lower]"
+ http-response set-header SHA2-384 "%[var(txn.hash),sha2(384),hex,lower]"
+ http-response set-header SHA2-512 "%[var(txn.hash),sha2(512),hex,lower]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/" \
+ -hdr "Hash: 1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.sha2 == "6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b"
+ expect resp.http.sha2-224 == "e25388fde8290dc286a6164fa2d97e551b53498dcbf7bc378eb1f178"
+ expect resp.http.sha2-256 == "6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b"
+ expect resp.http.sha2-384 == "47f05d367b0c32e438fb63e6cf4a5f35c2aa2f90dc7543f8a41a0f95ce8a40a313ab5cf36134a2068c4c969cb50db776"
+ expect resp.http.sha2-512 == "4dff4ea340f0a823f15d3f4f01ab62eae0e5da579ccb851f8db9dfe84c58b2b37b89903a740e1ee172da793a6e79d560e5f7f9bd058a12a280433ed6fa46510a"
+ txreq -url "/" \
+ -hdr "Hash: 2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.sha2 == "d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35"
+ expect resp.http.sha2-224 == "58b2aaa0bfae7acc021b3260e941117b529b2e69de878fd7d45c61a9"
+ expect resp.http.sha2-256 == "d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35"
+ expect resp.http.sha2-384 == "d063457705d66d6f016e4cdd747db3af8d70ebfd36badd63de6c8ca4a9d8bfb5d874e7fbd750aa804dcaddae7eeef51e"
+ expect resp.http.sha2-512 == "40b244112641dd78dd4f93b6c9190dd46e0099194d5a44257b7efad6ef9ff4683da1eda0244448cb343aa688f5d3efd7314dafe580ac0bcbf115aeca9e8dc114"
+} -run
diff --git a/reg-tests/converter/url_dec.vtc b/reg-tests/converter/url_dec.vtc
new file mode 100644
index 0000000..d5e317b
--- /dev/null
+++ b/reg-tests/converter/url_dec.vtc
@@ -0,0 +1,37 @@
+varnishtest "url_dec converter Test"
+
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ http-request set-var(txn.url) url
+ http-response set-header url_dec0 "%[var(txn.url),url_dec]"
+ http-response set-header url_dec1 "%[var(txn.url),url_dec(1)]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/bla+%20?foo%3Dbar%2B42+42%20"
+ rxresp
+ expect resp.http.url_dec0 == "/bla+ ?foo=bar+42 42 "
+ expect resp.http.url_dec1 == "/bla ?foo=bar+42 42 "
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/converter/url_enc.vtc b/reg-tests/converter/url_enc.vtc
new file mode 100644
index 0000000..74acac8
--- /dev/null
+++ b/reg-tests/converter/url_enc.vtc
@@ -0,0 +1,43 @@
+varnishtest "url_enc converter test"
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ http-request set-var(txn.url0) "str(foo=bar+42 42 )"
+ http-request set-var(txn.url1) "var(txn.url0),url_enc"
+ http-request set-var(txn.url2) "var(txn.url1),url_dec"
+ http-request set-var(txn.url3) "var(txn.url2),url_enc(query)"
+ http-response set-header url_enc0 "%[var(txn.url1)]"
+ http-response set-header url_dec "%[var(txn.url2)]"
+ http-response set-header url_enc1 "%[var(txn.url3)]"
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.http.url_enc0 == "foo%3Dbar%2B42%2042%20"
+ expect resp.http.url_dec == "foo=bar+42 42 "
+ expect resp.http.url_enc1 == "foo%3Dbar%2B42%2042%20"
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/converter/word.vtc b/reg-tests/converter/word.vtc
new file mode 100644
index 0000000..acd4678
--- /dev/null
+++ b/reg-tests/converter/word.vtc
@@ -0,0 +1,43 @@
+varnishtest "word converter Test"
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 3 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ #### requests
+ http-request set-var(txn.uri) path
+ http-response set-header Found %[var(txn.uri),word(2,/)] if { var(txn.uri),word(2,/) -m found }
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/foo/bar/baz"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "bar"
+ txreq -url "/foo//bar/baz"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "bar"
+ txreq -url "/foo"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.found == "<undef>"
+} -run
diff --git a/reg-tests/filters/random-forwarding.vtc b/reg-tests/filters/random-forwarding.vtc
new file mode 100644
index 0000000..abb2bcc
--- /dev/null
+++ b/reg-tests/filters/random-forwarding.vtc
@@ -0,0 +1,138 @@
+varnishtest "Filtering test with several filters and random forwarding (via trace filter)"
+
+#REQUIRE_VERSION=2.4
+#REQUIRE_OPTION=ZLIB|SLZ
+#REGTEST_TYPE=slow
+
+feature ignore_unknown_macro
+
+barrier b1 cond 2 -cyclic
+
+server s1 {
+ rxreq
+ expect req.url == "/"
+ expect req.bodylen == 1048576
+ expect req.http.accept-encoding == "<undef>"
+ txresp \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 1048576
+
+ rxreq
+ expect req.url == "127.0.0.1:80"
+ txresp -nolen
+ recv 36000
+ send_n 1000 "0123456789abcdefghijklmnopqrstuvwxyz"
+ barrier b1 sync
+
+ accept
+ rxreq
+ expect req.url == "/"
+ txresp -nolen \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 20480
+ close
+
+ accept
+ rxreq
+ expect req.url == "/"
+ txresp -nolen
+ close
+
+ accept
+ rxreq
+ expect req.url == "/"
+ expect req.bodylen == 20480
+ txresp -nolen \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 20480
+
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+
+ compression offload
+ compression algo gzip
+
+ filter trace name "BEFORE" random-forwarding quiet
+ filter compression
+ filter trace name "AFTER" random-forwarding quiet
+ default_backend be1
+
+ backend be1
+ server www ${s1_addr}:${s1_port}
+
+ listen li1
+ mode tcp
+ bind "fd@${li1}"
+ # Validate nothing is blocked in TCP mode
+ filter compression
+ server www ${s1_addr}:${s1_port}
+
+
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -url "/" \
+ -hdr "Accept-Encoding: gzip" \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 1048576
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "gzip"
+ expect resp.http.transfer-encoding == "chunked"
+ gunzip
+ expect resp.bodylen == 1048576
+
+ txreq -method "CONNECT" -url "127.0.0.1:80" -nolen
+ rxresp -no_obj
+ expect resp.status == 200
+ send_n 1000 "0123456789abcdefghijklmnopqrstuvwxyz"
+ recv 36000
+ barrier b1 sync
+} -run
+
+client c2 -connect ${h1_fe1_sock} {
+ txreq -url "/" \
+ -hdr "Accept-Encoding: gzip" \
+ -hdr "Content-Type: text/plain"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.http.content-length == "<undef>"
+ expect resp.bodylen == 20480
+} -run
+
+client c3 -connect ${h1_fe1_sock} {
+ txreq -url "/" \
+ -hdr "Accept-Encoding: gzip" \
+ -hdr "Content-Type: text/plain"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.http.content-length == "<undef>"
+ expect resp.bodylen == 0
+} -run
+
+client c4 -connect ${h1_li1_sock} {
+ txreq -url "/" \
+ -hdr "Accept-Encoding: gzip" \
+ -hdr "Content-Type: text/plain" \
+ -bodylen 20480
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-encoding == "<undef>"
+ expect resp.http.transfer-encoding == "<undef>"
+ expect resp.http.content-length == "<undef>"
+ expect resp.bodylen == 20480
+ expect_close
+} -run
diff --git a/reg-tests/http-capture/multiple_headers.vtc b/reg-tests/http-capture/multiple_headers.vtc
new file mode 100644
index 0000000..1ae210b
--- /dev/null
+++ b/reg-tests/http-capture/multiple_headers.vtc
@@ -0,0 +1,91 @@
+varnishtest "Tests for 'capture (request|response) header"
+feature ignore_unknown_macro
+
+# This script checks that the last occurrences of "fooresp" and "fooreq" header
+# are correctly captured and added to the logs.
+# Note that varnishtest does not support more than MAX_HDR header.
+
+syslog S -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h_pid}\\]: .* .* fe be/srv .* 200 1[0-9]{4} - - ---- .* .* {HPhx8n59qjjNBLjP} {htb56qDdCcbRVTfS} \"GET / HTTP/1\\.1\""
+} -start
+
+server s {
+ rxreq
+ txresp -hdr "fooresp: HnFDGJ6KvhSG5QjX" -hdr "fooresp: 8dp7vBMQjTMkVwtG" \
+ -hdr "fooresp: NTpxWmvsNKGxvH6K" -hdr "fooresp: sPKNNJ5VRBDz9qXP" \
+ -hdr "fooresp: HnFDGJ6KvhSG5QjX" -hdr "fooresp: 8dp7vBMQjTMkVwtG" \
+ -hdr "fooresp: VSNnccbGkvfM9JK9" -hdr "fooresp: 9D5cjwtK3LCxmg4F" \
+ -hdr "fooresp: dsbxGqlBPRWGP3vX" -hdr "fooresp: xf6VK6GXlgdj5mwc" \
+ -hdr "fooresp: 8jzM3clRKtdL2WWb" -hdr "fooresp: v7ZHrTPjDR6lm6Bg" \
+ -hdr "fooresp: FQT6th9whMqQ7Z6C" -hdr "fooresp: KM22HH6lRBw6SHQT" \
+ -hdr "fooresp: PmRHphHXmTV9kZNS" -hdr "fooresp: CkGRbTJrD5nSVpFk" \
+ -hdr "fooresp: KQ9mzmMHpmmZ2SXP" -hdr "fooresp: W5FqfFDN6dqBxjK7" \
+ -hdr "fooresp: bvcxNPK4gpnTvn3z" -hdr "fooresp: BSXRLSWMsgQN54cC" \
+ -hdr "fooresp: ZX9ttTnlbXtJK55d" -hdr "fooresp: KH9StjMHF73NqzL8" \
+ -hdr "fooresp: W2q2m6MvMLcnXsX7" -hdr "fooresp: wtrjnJgFzHDvMg5r" \
+ -hdr "fooresp: Vpk2c2DsbWf2Gtwh" -hdr "fooresp: sCcW2qpRhFHHRDpH" \
+ -hdr "fooresp: P4mltXtvxLsnPcNS" -hdr "fooresp: TXgdSKNMmsJ8x9zq" \
+ -hdr "fooresp: n5t8pdZgnGFXZDd3" -hdr "fooresp: pD84GCtkWZqWbCM9" \
+ -hdr "fooresp: wx2FPxsGqSRjNVws" -hdr "fooresp: TXmtBCqPTVGFc3NK" \
+ -hdr "fooresp: 4DrFTLxpcPk2n3Zv" -hdr "fooresp: vrcFr9MWpqJWhK4h" \
+ -hdr "fooresp: HMsCHMZnHT3q8qD2" -hdr "fooresp: HsCXQGTxDpsMf4z6" \
+ -hdr "fooresp: 9rb2vjvvd2SzCQVT" -hdr "fooresp: qn5C2fZTWHVp7NkC" \
+ -hdr "fooresp: ZVd5ltcngZFHXfvr" -hdr "fooresp: j6BZVdV8fkz5tgjR" \
+ -hdr "fooresp: 6qfVwfHqdfntQjmP" -hdr "fooresp: RRr9nTnwjG6d2x7X" \
+ -hdr "fooresp: RJXtWtdJRTss6JgZ" -hdr "fooresp: zzHZWm6bqXDN9k47" \
+ -hdr "fooresp: htb56qDdCcbRVTfS" \
+ -bodylen 16384
+} -start
+
+haproxy h -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be
+ server srv ${s_addr}:${s_port}
+
+ frontend fe
+ option httplog
+ log ${S_addr}:${S_port} local0 debug err
+ capture request header fooreq len 25
+ capture response header fooresp len 25
+
+ bind "fd@${fe}"
+ use_backend be
+} -start
+
+client c1 -connect ${h_fe_sock} {
+ txreq -hdr "fooreq: c8Ck8sx8qfXk5pSS" -hdr "fooreq: TGNXbG2DF3TmLWK3" \
+ -hdr "fooreq: mBxq9Cgr8GN6hkt6" -hdr "fooreq: MHZ6VBCPgs564KfR" \
+ -hdr "fooreq: BCCwX2kL9BSMCqvt" -hdr "fooreq: 8rXw87xVTphpRQb7" \
+ -hdr "fooreq: gJ3Tp9kXQlqLC8Qp" -hdr "fooreq: dFnLs6wpMl2M5N7c" \
+ -hdr "fooreq: r3f9WgQ8Brqw37Kj" -hdr "fooreq: dbJzSSdCqV3ZVtXK" \
+ -hdr "fooreq: 5HxHd6g4n2Rj2CNG" -hdr "fooreq: HNqQSNfkt6q4zK26" \
+ -hdr "fooreq: rzqNcfskPR7vW4jG" -hdr "fooreq: 9c7txWhsdrwmkR6d" \
+ -hdr "fooreq: 3v8Nztg9l9vLSKJm" -hdr "fooreq: lh4WDxMX577h4z3l" \
+ -hdr "fooreq: mFtHj5SKDvfcGzfq" -hdr "fooreq: PZ5B5wRM9D7GLm7W" \
+ -hdr "fooreq: fFpN4zCkLTxzp5Dz" -hdr "fooreq: J5XMdfCCHmmwkr2f" \
+ -hdr "fooreq: KqssZ3SkZnZJF8mz" -hdr "fooreq: HrGgsnBnslKN7Msz" \
+ -hdr "fooreq: d8TQltZ39xFZBNx2" -hdr "fooreq: mwDt2k2tvqM8x5kQ" \
+ -hdr "fooreq: 7Qh6tM7s7z3P8XCl" -hdr "fooreq: S3mTVbbPhJbLR7n2" \
+ -hdr "fooreq: zr7hMDvrrwfvpmTT" -hdr "fooreq: lV9TnZX2CtSnr4k8" \
+ -hdr "fooreq: bMdJx8pVDG2nWFNg" -hdr "fooreq: FkGvB2cBwNrB3cm4" \
+ -hdr "fooreq: 5ckNn3m6m8r2CXLF" -hdr "fooreq: sk4pJGTSZ5HMPJP5" \
+ -hdr "fooreq: HgVgQ73zhLwX6Wzq" -hdr "fooreq: T5k2QbFKvCVJlz4c" \
+ -hdr "fooreq: SKcNPw8CXGKhtxNP" -hdr "fooreq: n9fFrcR2kRQJrCpZ" \
+ -hdr "fooreq: hrJ2MXCdcSCDhQ6n" -hdr "fooreq: 9xsWQ8srzLDvG9F4" \
+ -hdr "fooreq: GNcP9NBTFJkg4hbk" -hdr "fooreq: Vg8B8MNwz4T7q5Tj" \
+ -hdr "fooreq: XXns3qPCzZmt9j4G" -hdr "fooreq: hD7TnP43bcPHm5g2" \
+ -hdr "fooreq: wZbxVq7MwmfBSqb5" -hdr "fooreq: HPhx8n59qjjNBLjP" \
+ -bodylen 16384
+ rxresp
+ expect resp.status == 200
+} -start
+
+server s -wait
+syslog S -wait
+
diff --git a/reg-tests/http-cookies/cookie_insert_indirect.vtc b/reg-tests/http-cookies/cookie_insert_indirect.vtc
new file mode 100644
index 0000000..6b86360
--- /dev/null
+++ b/reg-tests/http-cookies/cookie_insert_indirect.vtc
@@ -0,0 +1,54 @@
+varnishtest "HTTP cookie basic test"
+feature ignore_unknown_macro
+
+# This script tests "cookie <name> insert indirect" directive.
+# The client sends a wrong "SRVID=s2" cookie.
+# haproxy removes it.
+# The server replies with "SRVID=S1" after having checked that
+# no cookies were sent by haproxy.
+# haproxy replies "SRVID=server-one" to the client.
+# We log the HTTP request to a syslog server and check their "--II"
+# (invalid, insert) flags.
+
+syslog S1 -level notice {
+ recv info
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* fe1 be1/srv1 .* --II .* \"GET / HTTP/1\\.1\""
+} -start
+
+server s1 {
+ rxreq
+ expect req.http.cookie == <undef>
+ txresp -hdr "Cookie: SRVID=S1"
+} -start
+
+haproxy h1 -conf {
+ global
+ log ${S1_addr}:${S1_port} len 2048 local0 debug err
+
+ defaults
+ mode http
+ option httplog
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ log global
+
+ backend be1
+ cookie SRVID insert indirect
+ server srv1 ${s1_addr}:${s1_port} cookie server-one
+
+ frontend fe1
+ option httplog
+ bind "fd@${fe1}"
+ use_backend be1
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -hdr "Cookie: SRVID=s2"
+ rxresp
+ expect resp.http.Set-Cookie ~ "^SRVID=server-one;.*"
+} -start
+
+
+client c1 -wait
+syslog S1 -wait
diff --git a/reg-tests/http-cookies/h2_cookie_concat.vtc b/reg-tests/http-cookies/h2_cookie_concat.vtc
new file mode 100644
index 0000000..e2e6d81
--- /dev/null
+++ b/reg-tests/http-cookies/h2_cookie_concat.vtc
@@ -0,0 +1,42 @@
+varnishtest "HTTP/2 cookie concatenation"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.http.cookie == "c1=foo; c2=bar; c3=baz"
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+
+ frontend fe1
+ bind "fd@${fe1}" proto h2
+ use_backend be1
+
+ backend be1
+ server srv1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -req "GET" \
+ -scheme "http" \
+ -url "/" \
+ -hdr "cookie" "c1=foo" \
+ -hdr "cookie" "c2=bar" \
+ -hdr "cookie" "c3=baz"
+ rxhdrs
+ } -run
+} -run
diff --git a/reg-tests/http-errorfiles/errorfiles.vtc b/reg-tests/http-errorfiles/errorfiles.vtc
new file mode 100644
index 0000000..1ace744
--- /dev/null
+++ b/reg-tests/http-errorfiles/errorfiles.vtc
@@ -0,0 +1,51 @@
+varnishtest "Test the errofile directive in proxy sections"
+
+# This config tests the errorfile directive in proxy sections (including the
+# defaults section).
+
+feature ignore_unknown_macro
+
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ errorfile 400 ${testdir}/errors/400.http
+ errorfile 403 ${testdir}/errors/403.http
+ errorfile 408 /dev/null
+
+ frontend fe1
+ bind "fd@${fe1}"
+
+ errorfile 403 ${testdir}/errors/403-1.http
+ errorfile 500 /dev/null
+
+ http-request deny deny_status 400 if { path /400 }
+ http-request deny deny_status 403 if { path /403 }
+ http-request deny deny_status 408 if { path /408 }
+ http-request deny deny_status 500 if { path /500 }
+
+} -start
+
+client c1r1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /400
+ rxresp
+ expect resp.status == 400
+ expect resp.http.x-err-type == "default"
+} -run
+client c1r2 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /403
+ rxresp
+ expect resp.status == 403
+ expect resp.http.x-err-type == "errors-1"
+} -run
+client c1r3 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /408
+ expect_close
+} -run
+client c1r4 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /500
+ expect_close
+} -run
diff --git a/reg-tests/http-errorfiles/errors/400-1.http b/reg-tests/http-errorfiles/errors/400-1.http
new file mode 100644
index 0000000..86a2e69
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/400-1.http
@@ -0,0 +1,9 @@
+HTTP/1.1 400 Bad request
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: errors-1
+
+<html><body><h1>400 Bad request</h1>
+Your browser sent an invalid request.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/400-2.http b/reg-tests/http-errorfiles/errors/400-2.http
new file mode 100644
index 0000000..c108510
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/400-2.http
@@ -0,0 +1,9 @@
+HTTP/1.1 400 Bad request
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: errors-2
+
+<html><body><h1>400 Bad request</h1>
+Your browser sent an invalid request.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/400-3.http b/reg-tests/http-errorfiles/errors/400-3.http
new file mode 100644
index 0000000..1fe1841
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/400-3.http
@@ -0,0 +1,9 @@
+HTTP/1.1 400 Bad request
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: errors-3
+
+<html><body><h1>400 Bad request</h1>
+Your browser sent an invalid request.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/400.http b/reg-tests/http-errorfiles/errors/400.http
new file mode 100644
index 0000000..ce229aa
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/400.http
@@ -0,0 +1,9 @@
+HTTP/1.1 400 Bad request
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: default
+
+<html><body><h1>400 Bad request</h1>
+Your browser sent an invalid request.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/403-1.http b/reg-tests/http-errorfiles/errors/403-1.http
new file mode 100644
index 0000000..08bdf02
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/403-1.http
@@ -0,0 +1,9 @@
+HTTP/1.0 403 Forbidden
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: errors-1
+
+<html><body><h1>403 Forbidden</h1>
+Request forbidden by administrative rules.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/403-2.http b/reg-tests/http-errorfiles/errors/403-2.http
new file mode 100644
index 0000000..9c07e5d
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/403-2.http
@@ -0,0 +1,9 @@
+HTTP/1.0 403 Forbidden
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: errors-2
+
+<html><body><h1>403 Forbidden</h1>
+Request forbidden by administrative rules.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/403.http b/reg-tests/http-errorfiles/errors/403.http
new file mode 100644
index 0000000..fd969b2
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/403.http
@@ -0,0 +1,9 @@
+HTTP/1.0 403 Forbidden
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: default
+
+<html><body><h1>403 Forbidden</h1>
+Request forbidden by administrative rules.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/404-1.http b/reg-tests/http-errorfiles/errors/404-1.http
new file mode 100644
index 0000000..154ed0b
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/404-1.http
@@ -0,0 +1,9 @@
+HTTP/1.1 404 Not Found
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: errors-1
+
+<html><body><h1>404 Not Found</h1>
+The resource could not be found.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/404-2.http b/reg-tests/http-errorfiles/errors/404-2.http
new file mode 100644
index 0000000..e26f91d
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/404-2.http
@@ -0,0 +1,9 @@
+HTTP/1.1 404 Not Found
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: errors-2
+
+<html><body><h1>404 Not Found</h1>
+The resource could not be found.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/404-3.http b/reg-tests/http-errorfiles/errors/404-3.http
new file mode 100644
index 0000000..4bc1661
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/404-3.http
@@ -0,0 +1,9 @@
+HTTP/1.1 404 Not Found
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: errors-3
+
+<html><body><h1>404 Not Found</h1>
+The resource could not be found.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/404.http b/reg-tests/http-errorfiles/errors/404.http
new file mode 100644
index 0000000..8dacd95
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/404.http
@@ -0,0 +1,9 @@
+HTTP/1.1 404 Not Found
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: default
+
+<html><body><h1>404 Not Found</h1>
+The resource could not be found.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/500-1.http b/reg-tests/http-errorfiles/errors/500-1.http
new file mode 100644
index 0000000..4e4f7e4
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/500-1.http
@@ -0,0 +1,9 @@
+HTTP/1.0 500 Internal Server Error
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: errors-1
+
+<html><body><h1>500 Internal Server Error</h1>
+An internal server error occurred.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/500.http b/reg-tests/http-errorfiles/errors/500.http
new file mode 100644
index 0000000..68a31ff
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/500.http
@@ -0,0 +1,9 @@
+HTTP/1.0 500 Internal Server Error
+Cache-Control: no-cache
+Connection: close
+Content-Type: text/html
+x-err-type: default
+
+<html><body><h1>500 Internal Server Error</h1>
+An internal server error occurred.
+</body></html>
diff --git a/reg-tests/http-errorfiles/errors/lf-403.txt b/reg-tests/http-errorfiles/errors/lf-403.txt
new file mode 100644
index 0000000..3a3c3aa
--- /dev/null
+++ b/reg-tests/http-errorfiles/errors/lf-403.txt
@@ -0,0 +1 @@
+The path "%[path]" is forbidden
diff --git a/reg-tests/http-errorfiles/http-error.vtc b/reg-tests/http-errorfiles/http-error.vtc
new file mode 100644
index 0000000..1af909b
--- /dev/null
+++ b/reg-tests/http-errorfiles/http-error.vtc
@@ -0,0 +1,75 @@
+varnishtest "Test the http-error directive"
+#REQUIRE_VERSION=2.2
+
+# This config tests the http-error directive.
+
+feature ignore_unknown_macro
+
+
+haproxy h1 -conf {
+ http-errors errors-1
+ errorfile 400 ${testdir}/errors/400-1.http
+ errorfile 403 ${testdir}/errors/403-1.http
+ errorfile 404 ${testdir}/errors/404-1.http
+ errorfile 500 ${testdir}/errors/500-1.http
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ errorfile 400 ${testdir}/errors/400.http
+ errorfile 404 ${testdir}/errors/404.http
+
+ frontend fe1
+ bind "fd@${fe1}"
+
+ http-error status 400
+ http-error status 403 default-errorfiles
+ http-error status 404 errorfiles errors-1
+ http-error status 500 errorfile ${testdir}/errors/500.http
+ http-error status 200 content-type "text/plain" hdr x-path "path=%[path]" lf-string "The path is \"%[path]\""
+
+ http-request return status 200 default-errorfiles if { path /200 }
+ http-request deny deny_status 400 if { path /400 }
+ http-request deny deny_status 403 if { path /403 }
+ http-request deny deny_status 404 if { path /404 }
+ http-request deny deny_status 500 if { path /500 }
+
+} -start
+
+client c1r1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /200
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-path == "path=/200"
+ expect resp.http.content-type == "text/plain"
+ expect resp.body == "The path is \"/200\""
+} -run
+client c1r2 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /400
+ rxresp
+ expect resp.status == 400
+ expect resp.http.x-err-type == <undef>
+ expect resp.http.content-length == 0
+} -run
+client c1r3 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /403
+ rxresp
+ expect resp.status == 403
+ expect resp.http.x-err-type == <undef>
+ expect resp.http.content-length == 93
+ expect resp.http.content-type == "text/html"
+} -run
+client c1r3 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /404
+ rxresp
+ expect resp.status == 404
+ expect resp.http.x-err-type == "errors-1"
+} -run
+client c1r4 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /500
+ rxresp
+ expect resp.status == 500
+ expect resp.http.x-err-type == "default"
+} -run
diff --git a/reg-tests/http-errorfiles/http_deny_errors.vtc b/reg-tests/http-errorfiles/http_deny_errors.vtc
new file mode 100644
index 0000000..353045d
--- /dev/null
+++ b/reg-tests/http-errorfiles/http_deny_errors.vtc
@@ -0,0 +1,77 @@
+varnishtest "Test the custom errors for HTTP deny rules"
+#REQUIRE_VERSION=2.2
+
+# This config tests the custom errors for HTTP deny rules.
+
+feature ignore_unknown_macro
+
+
+haproxy h1 -conf {
+ http-errors errors-1
+ errorfile 400 ${testdir}/errors/400-1.http
+ errorfile 403 ${testdir}/errors/403-1.http
+ errorfile 404 ${testdir}/errors/404-1.http
+ errorfile 500 /dev/null
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ http-request deny deny_status 400 if { path /400 }
+ http-request deny deny_status 403 errorfile ${testdir}/errors/403.http if { path /403 }
+ http-request deny deny_status 404 errorfiles errors-1 if { path /404 }
+ http-request deny deny_status 500 errorfile /dev/null if { path /500-1 }
+ http-request deny deny_status 500 errorfiles errors-1 if { path /500-2 }
+
+ http-request deny status 500 hdr x-err-info "path=%[path]" content-type "text/plain" string "Internal Error" if { path /int-err }
+ http-request deny status 403 hdr x-err-info "path=%[path]" content-type "text/plain" lf-file ${testdir}/errors/lf-403.txt if { path /forbidden }
+
+} -start
+
+client c1r1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /400
+ rxresp
+ expect resp.status == 400
+ expect resp.http.x-err-type == <undef>
+} -run
+client c1r2 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /403
+ rxresp
+ expect resp.status == 403
+ expect resp.http.x-err-type == "default"
+} -run
+client c1r3 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /404
+ rxresp
+ expect resp.status == 404
+ expect resp.http.x-err-type == "errors-1"
+} -run
+client c1r4 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /500-1
+ expect_close
+} -run
+client c1r5 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /500-2
+ expect_close
+} -run
+client c1r6 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /int-err
+ rxresp
+ expect resp.status == 500
+ expect resp.http.x-err-info == "path=/int-err"
+ expect resp.http.content-type == "text/plain"
+ expect resp.http.content-length == 14
+ expect resp.body == "Internal Error"
+} -run
+client c1r7 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /forbidden
+ rxresp
+ expect resp.status == 403
+ expect resp.http.x-err-info == "path=/forbidden"
+ expect resp.http.content-type == "text/plain"
+ expect resp.body == "The path \"/forbidden\" is forbidden\n"
+} -run
diff --git a/reg-tests/http-errorfiles/http_errors.vtc b/reg-tests/http-errorfiles/http_errors.vtc
new file mode 100644
index 0000000..6b20be7
--- /dev/null
+++ b/reg-tests/http-errorfiles/http_errors.vtc
@@ -0,0 +1,134 @@
+varnishtest "Test the errorfiles directive"
+#REQUIRE_VERSION=2.2
+
+# This config tests the errorfiles directive.
+
+feature ignore_unknown_macro
+
+
+haproxy h1 -conf {
+ http-errors errors-1
+ errorfile 400 ${testdir}/errors/400-1.http
+ errorfile 403 ${testdir}/errors/403-1.http
+ errorfile 404 ${testdir}/errors/404-1.http
+ errorfile 500 ${testdir}/errors/500-1.http
+
+ http-errors errors-2
+ errorfile 400 ${testdir}/errors/400-2.http
+ errorfile 403 ${testdir}/errors/403-2.http
+ errorfile 404 ${testdir}/errors/404-2.http
+
+ http-errors errors-3
+ errorfile 400 ${testdir}/errors/400-3.http
+ errorfile 404 ${testdir}/errors/404-3.http
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ errorfiles errors-2
+ errorfile 400 ${testdir}/errors/400.http
+ errorfile 404 ${testdir}/errors/404.http
+
+ frontend fe1
+ bind "fd@${fe1}"
+ http-request deny deny_status 400 if { path /400 }
+ http-request deny if { path /403 }
+ http-request deny deny_status 404 if { path /404 }
+ http-request deny deny_status 500 if { path /500 }
+
+ frontend fe2
+ bind "fd@${fe2}"
+ errorfiles errors-1
+ errorfile 500 ${testdir}/errors/500.http
+ http-request deny deny_status 400 if { path /400 }
+ http-request deny if { path /403 }
+ http-request deny deny_status 404 if { path /404 }
+ http-request deny deny_status 500 if { path /500 }
+
+ frontend fe3
+ bind "fd@${fe3}"
+ errorfile 500 ${testdir}/errors/500.http
+ errorfiles errors-1 500
+ errorfiles errors-3 400
+ http-request deny deny_status 400 if { path /400 }
+ http-request deny if { path /403 }
+ http-request deny deny_status 404 if { path /404 }
+ http-request deny deny_status 500 if { path /500 }
+} -start
+
+client c1r1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /400
+ rxresp
+ expect resp.status == 400
+ expect resp.http.x-err-type == "default"
+} -run
+client c1r2 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /403
+ rxresp
+ expect resp.status == 403
+ expect resp.http.x-err-type == "errors-2"
+} -run
+client c1r3 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /404
+ rxresp
+ expect resp.status == 404
+ expect resp.http.x-err-type == "default"
+} -run
+client c1r4 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /500
+ rxresp
+ expect resp.status == 500
+ expect resp.http.x-err-type == <undef>
+} -run
+
+client c2r1 -connect ${h1_fe2_sock} {
+ txreq -req GET -url /400
+ rxresp
+ expect resp.status == 400
+ expect resp.http.x-err-type == "errors-1"
+} -run
+client c2r2 -connect ${h1_fe2_sock} {
+ txreq -req GET -url /403
+ rxresp
+ expect resp.status == 403
+ expect resp.http.x-err-type == "errors-1"
+} -run
+client c2r3 -connect ${h1_fe2_sock} {
+ txreq -req GET -url /404
+ rxresp
+ expect resp.status == 404
+ expect resp.http.x-err-type == "errors-1"
+} -run
+client c2r4 -connect ${h1_fe2_sock} {
+ txreq -req GET -url /500
+ rxresp
+ expect resp.status == 500
+ expect resp.http.x-err-type == "default"
+} -run
+
+client c3r1 -connect ${h1_fe3_sock} {
+ txreq -req GET -url /400
+ rxresp
+ expect resp.status == 400
+ expect resp.http.x-err-type == "errors-3"
+} -run
+client c3r2 -connect ${h1_fe3_sock} {
+ txreq -req GET -url /403
+ rxresp
+ expect resp.status == 403
+ expect resp.http.x-err-type == "errors-2"
+} -run
+client c3r3 -connect ${h1_fe3_sock} {
+ txreq -req GET -url /404
+ rxresp
+ expect resp.status == 404
+ expect resp.http.x-err-type == "default"
+} -run
+client c3r4 -connect ${h1_fe3_sock} {
+ txreq -req GET -url /500
+ rxresp
+ expect resp.status == 500
+ expect resp.http.x-err-type == "errors-1"
+} -run
diff --git a/reg-tests/http-errorfiles/http_return.vtc b/reg-tests/http-errorfiles/http_return.vtc
new file mode 100644
index 0000000..8db77a9
--- /dev/null
+++ b/reg-tests/http-errorfiles/http_return.vtc
@@ -0,0 +1,46 @@
+varnishtest "Test the HTTP return action with errorfiles"
+#REQUIRE_VERSION=2.2
+
+# This config tests the HTTP return action when error files are used to reply to
+# the client.
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ http-errors errors-2
+ errorfile 400 ${testdir}/errors/400-2.http
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ errorfile 400 ${testdir}/errors/400.http
+ http-request return status 400 default-errorfiles if { path /def }
+ http-request return status 400 errorfile ${testdir}/errors/400-1.http if { path /400-1 }
+ http-request return status 400 errorfiles errors-2 if { path /400-2 }
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /def
+ rxresp
+ expect resp.status == 400
+ expect resp.http.x-err-type == "default"
+} -run
+
+client c1r2 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /400-1
+ rxresp
+ expect resp.status == 400
+ expect resp.http.x-err-type == "errors-1"
+} -run
+
+client c1r3 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /400-2
+ rxresp
+ expect resp.status == 400
+ expect resp.http.x-err-type == "errors-2"
+} -run
diff --git a/reg-tests/http-messaging/common.pem b/reg-tests/http-messaging/common.pem
new file mode 120000
index 0000000..a4433d5
--- /dev/null
+++ b/reg-tests/http-messaging/common.pem
@@ -0,0 +1 @@
+../ssl/common.pem \ No newline at end of file
diff --git a/reg-tests/http-messaging/h1_host_normalization.vtc b/reg-tests/http-messaging/h1_host_normalization.vtc
new file mode 100644
index 0000000..48174b8
--- /dev/null
+++ b/reg-tests/http-messaging/h1_host_normalization.vtc
@@ -0,0 +1,762 @@
+varnishtest "H1 authority validation and host normalizarion based on the scheme (rfc3982 6.3.2) or the method (connect)"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.6-dev0)'"
+feature ignore_unknown_macro
+
+barrier b1 cond 2 -cyclic
+
+syslog S1 -level info {
+ # C1
+ recv
+ expect ~ "^.* uri: GET http://toto:poue@hostname/c1 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+
+ # C2
+ recv
+ expect ~ "^.* uri: GET http://hostname:8080/c2 HTTP/1.1; host: {hostname:8080}$"
+ barrier b1 sync
+
+ # C3
+ recv
+ expect ~ "^.* uri: GET https://hostname/c3 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+
+ # C4
+ recv
+ expect ~ "^.* uri: GET https://hostname:80/c4 HTTP/1.1; host: {hostname:80}$"
+ barrier b1 sync
+
+ # C5
+ recv
+ expect ~ "^.* uri: CONNECT hostname:80 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+ recv
+ expect ~ "^.* uri: CONNECT hostname:80 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+ recv
+ expect ~ "^.* uri: CONNECT hostname:80 HTTP/1.1; host: {hostname:}$"
+ barrier b1 sync
+
+ # C6
+ recv
+ expect ~ "^.* uri: CONNECT hostname:443 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+ recv
+ expect ~ "^.* uri: CONNECT hostname:443 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+ recv
+ expect ~ "^.* uri: CONNECT hostname:443 HTTP/1.1; host: {hostname:}$"
+ barrier b1 sync
+
+ # C7
+ recv
+ expect ~ "^.* uri: CONNECT hostname:8443 HTTP/1.1; host: {hostname:8443}$"
+ barrier b1 sync
+
+ # C8
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C9
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C10
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C11
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C12
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C13
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C14
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C15
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C16
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C17
+ recv
+ barrier b1 sync
+ expect ~ "^.* uri: <BADREQ>; host: $"
+
+ # C18
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C19
+ recv
+ expect ~ "^.* uri: <BADREQ>; host: $"
+ barrier b1 sync
+
+ # C20
+ recv
+ expect ~ "^.* uri: GET http://hostname/c20 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+
+ # C21
+ recv
+ expect ~ "^.* uri: GET https://hostname/c21 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+
+ # C22
+ recv
+ expect ~ "^.* uri: GET http://hostname/c22 HTTP/1.1; host: {hostname:80}$"
+ barrier b1 sync
+
+ # C23
+ recv
+ expect ~ "^.* uri: GET https://hostname/c23 HTTP/1.1; host: {hostname:443}$"
+ barrier b1 sync
+
+ # C24
+ recv
+ expect ~ "^.* uri: GET http://hostname/c24 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+
+ # C25
+ recv
+ expect ~ "^.* uri: GET https://hostname/c25 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+
+ # C26
+ recv
+ expect ~ "^.* uri: GET http://hostname/c26 HTTP/1.1; host: {hostname:}$"
+ barrier b1 sync
+
+ # C27
+ recv
+ expect ~ "^.* uri: GET https://hostname/c27 HTTP/1.1; host: {hostname:}$"
+ barrier b1 sync
+
+ # C28
+ recv
+ expect ~ "^.* uri: GET http://hostname/c28 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+
+ # C29
+ recv
+ expect ~ "^.* uri: GET http://hostname/c29 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+
+ # C30
+ recv
+ expect ~ "^.* uri: GET https://hostname/c30 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+
+ # C31
+ recv
+ expect ~ "^.* uri: GET https://hostname/c31 HTTP/1.1; host: {hostname}$"
+ barrier b1 sync
+
+ # C32
+ recv
+ expect ~ "^.* uri: GET http:// HTTP/1.1; host: {}$"
+ barrier b1 sync
+
+ # C33
+ recv
+ expect ~ "^.* uri: GET https:// HTTP/1.1; host: {}$"
+ barrier b1 sync
+
+ # C34
+ recv
+ expect ~ "^.* uri: GET http:// HTTP/1.1; host: {}$"
+ barrier b1 sync
+
+ # C35
+ recv
+ expect ~ "^.* uri: GET https:// HTTP/1.1; host: {}$"
+
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ http-request capture req.hdr(host) len 512
+ log-format "uri: %r; host: %hr"
+ log ${S1_addr}:${S1_port} len 2048 local0 debug err
+
+ http-request return status 200
+} -start
+
+# default port 80 with http scheme => should be normalized
+# Be sure userinfo are skipped
+client c1 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://toto:poue@hostname:80/c1" \
+ -hdr "host: hostname:80"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# port 8080 with http scheme => no normalization
+client c2 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname:8080/c2" \
+ -hdr "host: hostname:8080"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# default port 443 with https scheme => should be normalized
+client c3 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "https://hostname:443/c3" \
+ -hdr "host: hostname:443"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# port 80 with https scheme => no normalization
+client c4 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "https://hostname:80/c4" \
+ -hdr "host: hostname:80"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# CONNECT on port 80 => should be normalized
+client c5 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "hostname:80" \
+ -hdr "host: hostname:80"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+client c5 -connect ${h1_fe_sock} {
+
+ txreq \
+ -req "CONNECT" \
+ -url "hostname:80" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+client c5 -connect ${h1_fe_sock} {
+
+ txreq \
+ -req "CONNECT" \
+ -url "hostname:80" \
+ -hdr "host: hostname:"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# CONNECT on port 443 => should be normalized
+client c6 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "hostname:443" \
+ -hdr "host: hostname:443"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+client c6 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "hostname:443" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+client c6 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "hostname:443" \
+ -hdr "host: hostname:"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# CONNECT on port non-default port => no normalization
+client c7 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "hostname:8443" \
+ -hdr "host: hostname:8443"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# host miss-match => error
+client c8 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname1/" \
+ -hdr "host: hostname2"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# port miss-match => error
+client c9 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname:80/" \
+ -hdr "host: hostname:81"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# no host port with a non-default port in abs-uri => error
+client c10 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname:8080/" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# non-default host port with a default in abs-uri => error
+client c11 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname/" \
+ -hdr "host: hostname:81"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# miss-match between host headers => error
+client c12 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname1/" \
+ -hdr "host: hostname1" \
+ -hdr "host: hostname2"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# miss-match between host headers but with a normalization => error
+client c13 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname1/" \
+ -hdr "host: hostname1:80" \
+ -hdr "host: hostname1"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# CONNECT authoriy without port => error
+client c14 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "hostname" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# host miss-match with CONNECT => error
+client c15 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "hostname1:80" \
+ -hdr "host: hostname2:80"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# port miss-match with CONNECT => error
+client c16 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "hostname:80" \
+ -hdr "host: hostname:443"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# no host port with non-default port in CONNECT authority => error
+client c17 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "hostname:8080" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# no authority => error
+client c18 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "/" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# no authority => error
+client c19 -connect ${h1_fe_sock} {
+ txreq \
+ -req "CONNECT" \
+ -url "hostname:" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+
+# default port 80 with http scheme but no port for host value => should be normalized
+client c20 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname:80/c20" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+
+# default port 443 with https scheme but no port for host value => should be normalized
+client c21 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "https://hostname:443/c21" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+
+# http scheme, no port for the authority but default port for host value => no normalization
+client c22 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname/c22" \
+ -hdr "host: hostname:80"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# https scheme, no port for the authority but default port for host value => no normalization
+client c23 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "https://hostname/c23" \
+ -hdr "host: hostname:443"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+
+# http scheme, empty port for the authority and no port for host value => should be normalized
+client c24 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname:/c24" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# https scheme, empty port for the authority and no port for host value => should be normalized
+client c25 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "https://hostname:/c25" \
+ -hdr "host: hostname"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# http scheme, no port for the authority and empty port for host value => no normalization
+client c26 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname/c26" \
+ -hdr "host: hostname:"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# https scheme, no port for the authority and empty port for host value => no normalization
+client c27 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "https://hostname/c27" \
+ -hdr "host: hostname:"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# http scheme, default port for the authority and empty port for host value => should be normalized
+client c28 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname:80/c28" \
+ -hdr "host: hostname:"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# http scheme, empty port for the authority and default port for host value => should be normalized
+client c29 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://hostname:/c29" \
+ -hdr "host: hostname:80"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# https scheme, default port for the authority and empty port for host value => should be normalized
+client c30 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "https://hostname:443/c30" \
+ -hdr "host: hostname:"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# https scheme, empty port for the authority and default port for host value => should be normalized
+client c31 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "https://hostname:/c31" \
+ -hdr "host: hostname:443"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# Strange cases
+client c32 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://:" \
+ -hdr "host: :80"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+
+client c33 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "https://:" \
+ -hdr "host: :443"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# Strange cases
+client c34 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "http://:" \
+ -hdr "host: :"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+
+client c35 -connect ${h1_fe_sock} {
+ txreq \
+ -req "GET" \
+ -url "https://:" \
+ -hdr "host: :"
+
+ rxresp
+ expect resp.status == 200
+} -run
+
+syslog S1 -wait
diff --git a/reg-tests/http-messaging/h1_to_h1.vtc b/reg-tests/http-messaging/h1_to_h1.vtc
new file mode 100644
index 0000000..67aba14
--- /dev/null
+++ b/reg-tests/http-messaging/h1_to_h1.vtc
@@ -0,0 +1,301 @@
+varnishtest "HTTP request tests: H1 to H1 (HTX mode supported only for HAProxy >= 1.9)"
+
+# Run it with HAPROXY_PROGRAM=$PWD/haproxy varnishtest -l -k -t 1 "$1"
+
+feature ignore_unknown_macro
+
+server s1 {
+ ##
+ ## Handle GET requests
+ ##
+ rxreq
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp \
+ -status 200 \
+ -body "response 1"
+
+ rxreq
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp \
+ -status 200 \
+ -body "response 2"
+
+ rxreq
+ expect req.bodylen == 38
+ expect req.body == "this must be delivered, like it or not"
+ txresp \
+ -status 200 \
+ -body "response 3"
+
+ rxreq
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp \
+ -status 200 \
+ -body "response 4"
+
+ accept
+
+ ##
+ ## Handle HEAD requests
+ ##
+ rxreq
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp \
+ -status 200 \
+ -body "response 1"
+
+ accept
+
+ rxreq
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp \
+ -status 200 \
+ -body "response 2"
+
+ accept
+
+ rxreq
+ expect req.bodylen == 38
+ expect req.body == "this must be delivered, like it or not"
+ txresp \
+ -status 200 \
+ -body "response 3"
+
+ accept
+
+ rxreq
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp \
+ -status 200 \
+ -body "response 4"
+
+ accept
+
+ ##
+ ## Handle POST requests
+ ##
+ # POST request without body
+ rxreq
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp \
+ -status 200 \
+ -body "response 1"
+
+ # POST request without body
+ rxreq
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp \
+ -status 200 \
+ -body "response 2"
+
+ # POST request with a body
+ rxreq
+ expect req.bodylen == 12
+ expect req.body == "this is sent"
+ txresp \
+ -status 200 \
+ -body "response 3"
+
+ # POST request without body
+ rxreq
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp \
+ -status 200 \
+ -body "response 4"
+} -repeat 3 -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen feh1
+ bind "fd@${feh1}"
+ #bind "fd@${feh2}" proto h2
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+# GET requests
+client c1h1 -connect ${h1_feh1_sock} {
+ # first request is valid
+ txreq \
+ -req "GET" \
+ -url "/test1.html"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "response 1"
+
+ # second request is valid and advertises C-L:0
+ txreq \
+ -req "GET" \
+ -url "/test2.html" \
+ -hdr "content-length: 0"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "response 2"
+
+ # third request sends a body with a GET
+ txreq \
+ -req "GET" \
+ -url "/test3.html" \
+ -body "this must be delivered, like it or not"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "response 3"
+
+ # fourth request is valid and advertises C-L:0, and close, and is
+ # followed by a string "this is not sent\r\n\r\n" which must be
+ # dropped.
+ txreq \
+ -req "GET" \
+ -url "/test4.html" \
+ -hdr "content-length: 0" \
+ -hdr "connection: close"
+ # "this is not sent"
+ sendhex "74787973207973206E6F742073656E740D0A0D0A"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "response 4"
+
+ # the connection is expected to be closed and no more response must
+ # arrive here.
+ expect_close
+} -run
+
+# HEAD requests
+# Note: for now they fail with varnishtest, which expects the amount of
+# data advertised in the content-length response.
+client c2h1 -connect ${h1_feh1_sock} {
+ # first request is valid
+ txreq \
+ -req "HEAD" \
+ -url "/test11.html"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ # second request is valid and advertises C-L:0
+ txreq \
+ -req "HEAD" \
+ -url "/test12.html" \
+ -hdr "content-length: 0"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ # third request sends a body with a HEAD
+ txreq \
+ -req "HEAD" \
+ -url "/test13.html" \
+ -body "this must be delivered, like it or not"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ # fourth request is valid and advertises C-L:0, and close, and is
+ # followed by a string "this is not sent\r\n\r\n" which must be
+ # dropped.
+ txreq \
+ -req "HEAD" \
+ -url "/test14.html" \
+ -hdr "content-length: 0" \
+ -hdr "connection: close"
+ # "this is not sent"
+ sendhex "74787973207973206E6F742073656E740D0A0D0A"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ # the connection is expected to be closed and no more response must
+ # arrive here.
+ expect_close
+} -run
+
+client c3h1 -connect ${h1_feh1_sock} {
+ # first request is valid
+ txreq \
+ -req "POST" \
+ -url "/test21.html"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "response 1"
+
+ # second request is valid and advertises C-L:0
+ txreq \
+ -req "POST" \
+ -url "/test22.html" \
+ -hdr "content-length: 0"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "response 2"
+
+ # third request is valid and advertises (and sends) some contents
+ txreq \
+ -req "POST" \
+ -url "/test23.html" \
+ -body "this is sent"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "response 3"
+
+ # fourth request is valid and advertises C-L:0, and close, and is
+ # followed by a string "this is not sent\r\n\r\n" which must be
+ # dropped.
+ txreq \
+ -req "POST" \
+ -url "/test24.html" \
+ -hdr "content-length: 0" \
+ -hdr "connection: close"
+ # "this is not sent"
+ sendhex "74787973207973206E6F742073656E740D0A0D0A"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "response 4"
+
+ # the connection is expected to be closed and no more response must
+ # arrive here.
+ expect_close
+} -run
+
+client c4h1 -connect ${h1_feh1_sock} {
+ # this request is invalid and advertises an invalid C-L ending with an
+ # empty value, which results in a stream error.
+ txreq \
+ -req "GET" \
+ -url "/test31.html" \
+ -hdr "content-length: 0," \
+ -hdr "connection: close"
+ rxresp
+ expect resp.status == 400
+ expect_close
+} -run
+
+client c5h1 -connect ${h1_feh1_sock} {
+ # this request is invalid and advertises an empty C-L, which results
+ # in a stream error.
+ txreq \
+ -req "GET" \
+ -url "/test41.html" \
+ -hdr "content-length:" \
+ -hdr "connection: close"
+ rxresp
+ expect resp.status == 400
+ expect_close
+} -run
diff --git a/reg-tests/http-messaging/h2_desync_attacks.vtc b/reg-tests/http-messaging/h2_desync_attacks.vtc
new file mode 100644
index 0000000..112bc60
--- /dev/null
+++ b/reg-tests/http-messaging/h2_desync_attacks.vtc
@@ -0,0 +1,167 @@
+# This test ensures that h2 requests with invalid pseudo-headers are properly
+# rejected. Also, the host header must be ignored if authority is present. This
+# is necessary to avoid http/2 desync attacks through haproxy as described here
+# https://portswigger.net/research/http2
+
+varnishtest "h2 desync attacks"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.http.host == "hostname"
+ txresp
+} -start
+
+# haproxy frontend
+haproxy hap -conf {
+ defaults
+ mode http
+
+ listen feSrvH1
+ bind "fd@${feSrvH1}"
+ http-request return status 200
+
+ listen feSrvH2
+ bind "fd@${feSrvH2}" proto h2
+ http-request return status 200
+
+ listen fe1
+ bind "fd@${fe1}" proto h2
+ server srv-hapSrv "${hap_feSrvH1_addr}:${hap_feSrvH1_port}"
+
+ listen fe2
+ bind "fd@${fe2}" proto h2
+ server srv-hapSrv "${hap_feSrvH2_addr}:${hap_feSrvH2_port}" proto h2
+
+ listen fe3
+ bind "fd@${fe3}" proto h2
+ server s1 "${s1_addr}:${s1_port}"
+} -start
+
+# valid request
+client c1 -connect ${hap_fe1_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -method "GET" \
+ -scheme "http" \
+ -url "/"
+ rxresp
+ expect resp.status == 200
+ } -run
+} -run
+
+# valid request
+client c2 -connect ${hap_fe2_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -method "GET" \
+ -scheme "http" \
+ -url "/"
+ rxresp
+ expect resp.status == 200
+ } -run
+} -run
+
+# invalid path
+client c3-path -connect ${hap_fe1_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -method "GET" \
+ -scheme "http" \
+ -url "hello-world"
+ rxrst
+ } -run
+} -run
+
+# invalid scheme
+client c4-scheme -connect ${hap_fe1_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -method "GET" \
+ -scheme "http://localhost/?" \
+ -url "/"
+ rxresp
+ expect resp.status == 400
+ } -run
+} -run
+
+# invalid method
+client c5-method -connect ${hap_fe2_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -method "GET?" \
+ -scheme "http" \
+ -url "/"
+ rxresp
+ expect resp.status == 400
+ } -run
+} -run
+
+# different authority and host headers
+# in this case, host should be ignored in favor of the authority
+client c6-host-authority -connect ${hap_fe3_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -method "GET" \
+ -scheme "http" \
+ -url "/" \
+ -hdr ":authority" "hostname" \
+ -hdr "host" "other_host"
+ } -run
+} -run
+
+server s1 -wait
diff --git a/reg-tests/http-messaging/h2_to_h1.vtc b/reg-tests/http-messaging/h2_to_h1.vtc
new file mode 100644
index 0000000..637b664
--- /dev/null
+++ b/reg-tests/http-messaging/h2_to_h1.vtc
@@ -0,0 +1,324 @@
+varnishtest "HTTP request tests: H2 to H1 (HTX and legacy mode)"
+
+# Run it with HAPROXY_PROGRAM=$PWD/haproxy varnishtest -l -k -t 1 "$1"
+
+feature ignore_unknown_macro
+
+# synchronize requests between streams
+barrier b1 cond 2 -cyclic
+barrier b2 cond 2 -cyclic
+barrier b3 cond 2 -cyclic
+barrier b4 cond 2 -cyclic
+barrier b5 cond 2 -cyclic
+barrier b6 cond 2 -cyclic
+
+server s1 {
+ rxreq
+ txresp \
+ -status 200 \
+ -body "response 1"
+
+ barrier b2 sync
+ rxreq
+ txresp \
+ -status 200 \
+ -body "response 2"
+
+ barrier b3 sync
+ rxreq
+ txresp \
+ -status 200 \
+ -body "response 3"
+
+ barrier b4 sync
+ # the next request is never received
+
+ barrier b5 sync
+ # the next request is never received
+
+ barrier b6 sync
+ # the next request is never received
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ #log stdout format raw daemon
+ mode http
+ option http-buffer-request
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen feh1
+ bind "fd@${feh1}"
+ bind "fd@${feh2}" proto h2
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1h2 -connect ${h1_feh2_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ # first request is valid
+ stream 1 {
+ txreq \
+ -req "GET" \
+ -scheme "https" \
+ -url "/test1.html"
+ rxhdrs
+ expect resp.status == 200
+ rxdata -all
+ expect resp.body == "response 1"
+ } -run
+
+ # second request is valid and advertises C-L:0
+ stream 3 {
+ barrier b2 sync
+ txreq \
+ -req "GET" \
+ -scheme "https" \
+ -url "/test2.html" \
+ -hdr "content-length" "0"
+ rxhdrs
+ expect resp.status == 200
+ rxdata -all
+ expect resp.body == "response 2"
+ } -run
+
+ # third request sends a body with a GET
+ stream 5 {
+ barrier b3 sync
+ txreq \
+ -req "GET" \
+ -scheme "https" \
+ -url "/test3.html" \
+ -nostrend \
+ -body "this must be delivered, like it or not"
+ rxwinup
+ rxhdrs
+ expect resp.status == 200
+ rxdata -all
+ expect resp.body == "response 3"
+ } -run
+
+ # fourth request is valid and advertises C-L:2, and close, and is
+ # followed by a string "this is not sent\r\n\r\n" which causes a
+ # stream error of type PROTOCOL_ERROR.
+ stream 7 {
+ barrier b4 sync
+ txreq \
+ -req "GET" \
+ -scheme "https" \
+ -url "/test4.html" \
+ -hdr "content-length" "2" \
+ -nostrend
+ txdata -data "this is sent and ignored"
+ rxrst
+ } -run
+
+ # fifth request is invalid and advertises an invalid C-L ending with an
+ # empty value, which results in a stream error.
+ stream 9 {
+ barrier b5 sync
+ txreq \
+ -req "GET" \
+ -scheme "https" \
+ -url "/test5.html" \
+ -hdr "content-length" "0," \
+ -nostrend
+ rxrst
+ } -run
+
+ # sixth request is invalid and advertises an empty C-L, which results
+ # in a stream error.
+ stream 11 {
+ barrier b6 sync
+ txreq \
+ -req "GET" \
+ -scheme "https" \
+ -url "/test6.html" \
+ -hdr "content-length" "" \
+ -nostrend
+ rxrst
+ } -run
+} -run
+
+# HEAD requests : don't work well yet
+#client c2h2 -connect ${h1_feh2_sock} {
+# txpri
+# stream 0 {
+# txsettings
+# rxsettings
+# txsettings -ack
+# rxsettings
+# expect settings.ack == true
+# } -run
+#
+# # first request is valid
+# stream 1 {
+# txreq \
+# -req "HEAD" \
+# -scheme "https" \
+# -url "/test11.html"
+# rxhdrs
+# expect resp.status == 200
+# rxdata -all
+# expect resp.bodylen == 0
+# } -run
+#
+# # second request is valid and advertises C-L:0
+# stream 3 {
+# barrier b2 sync
+# txreq \
+# -req "HEAD" \
+# -scheme "https" \
+# -url "/test12.html" \
+# -hdr "content-length" "0"
+# rxhdrs
+# expect resp.status == 200
+# rxdata -all
+# expect resp.bodylen == 0
+# } -run
+#
+# # third request sends a body with a GET
+# stream 5 {
+# barrier b3 sync
+# txreq \
+# -req "HEAD" \
+# -scheme "https" \
+# -url "/test13.html" \
+# -nostrend \
+# -body "this must be delivered, like it or not"
+# rxwinup
+# rxhdrs
+# expect resp.status == 200
+# rxdata -all
+# expect resp.bodylen == 0
+# } -run
+#
+# # fourth request is valid and advertises C-L:0, and close, and is
+# # followed by a string "this is not sent\r\n\r\n" which must be
+# # dropped.
+# stream 7 {
+# barrier b4 sync
+# txreq \
+# -req "HEAD" \
+# -scheme "https" \
+# -url "/test14.html" \
+# -hdr "content-length" "0" \
+# -nostrend
+# txdata -data "this is sent and ignored"
+# rxwinup
+# rxhdrs
+# expect resp.status == 200
+# rxdata -all
+# expect resp.bodylen == 0
+# } -run
+#} -run
+
+# POST requests
+client c3h2 -connect ${h1_feh2_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ # first request is valid
+ stream 1 {
+ txreq \
+ -req "POST" \
+ -scheme "https" \
+ -url "/test21.html"
+ rxhdrs
+ expect resp.status == 200
+ rxdata -all
+ expect resp.body == "response 1"
+ } -run
+
+ # second request is valid and advertises C-L:0
+ stream 3 {
+ barrier b2 sync
+ txreq \
+ -req "POST" \
+ -scheme "https" \
+ -url "/test22.html" \
+ -hdr "content-length" "0"
+ rxhdrs
+ expect resp.status == 200
+ rxdata -all
+ expect resp.body == "response 2"
+ } -run
+
+ # third request sends a body with a GET
+ stream 5 {
+ barrier b3 sync
+ txreq \
+ -req "POST" \
+ -scheme "https" \
+ -url "/test23.html" \
+ -nostrend \
+ -body "this must be delivered, like it or not"
+ rxwinup
+ rxhdrs
+ expect resp.status == 200
+ rxdata -all
+ expect resp.body == "response 3"
+ } -run
+
+ # fourth request is valid and advertises C-L:2, and close, and is
+ # followed by a string "this is not sent\r\n\r\n" which results
+ # in a stream error.
+ stream 7 {
+ barrier b4 sync
+ txreq \
+ -req "POST" \
+ -scheme "https" \
+ -url "/test24.html" \
+ -hdr "content-length" "2" \
+ -nostrend
+ txdata -data "this is sent and ignored"
+ rxrst
+ } -run
+
+ # fifth request is invalid and advertises invalid C-L ending with an
+ # empty value, which results in a stream error.
+ stream 9 {
+ barrier b5 sync
+ txreq \
+ -req "POST" \
+ -scheme "https" \
+ -url "/test25.html" \
+ -hdr "content-length" "0," \
+ -nostrend
+ rxrst
+ } -run
+
+ # sixth request is invalid and advertises an empty C-L, which results
+ # in a stream error.
+ stream 11 {
+ barrier b6 sync
+ txreq \
+ -req "POST" \
+ -scheme "https" \
+ -url "/test26.html" \
+ -hdr "content-length" "" \
+ -nostrend
+ rxrst
+ } -run
+} -run
diff --git a/reg-tests/http-messaging/http_abortonclose.vtc b/reg-tests/http-messaging/http_abortonclose.vtc
new file mode 100644
index 0000000..ea57f3d
--- /dev/null
+++ b/reg-tests/http-messaging/http_abortonclose.vtc
@@ -0,0 +1,226 @@
+varnishtest "A test for the abortonclose option (H1 only)"
+feature ignore_unknown_macro
+
+# NOTE : This test may fail if too many vtest are running in parallel because
+# the port reserved for closed s1 server may be reused by another vtest
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.2-dev0)'"
+#REGTEST_TYPE=slow
+
+# b0 : Wait s1 was detected as DOWN to be sure it is stopped
+# b1 : Don't send /c4 before /c3 was received by s2 server
+# b2 : Used to receive syslog messages in the right order
+# b3 : finish c3 before s2
+
+barrier b0 cond 3 -cyclic
+barrier b1 cond 2 -cyclic
+barrier b2 cond 2 -cyclic
+barrier b3 cond 2 -cyclic
+
+server s1 {
+} -start
+server s1 -break
+
+server s2 {
+ rxreq
+
+ # unlock c4
+ barrier b1 sync
+
+ # wait end of c3
+ barrier b3 sync
+
+ expect_close
+} -start
+
+syslog S1 -level info {
+ recv alert
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: Server check/srv1 is DOWN.*"
+ barrier b0 sync
+
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1_1/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - SC-- .* .* \"GET /c1 HTTP/1\\.1\""
+ barrier b2 sync
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1_2/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* -1 .* - - CC-- .* .* \"GET /c2 HTTP/1\\.1\""
+ barrier b2 sync
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be2/<NOSRV> [0-9]*/[0-9]*/-1/-1/[0-9]* -1 .* - - CQ-- .* .* \"GET /c4 HTTP/1\\.1\""
+ barrier b2 sync
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be2/srv1 [0-9]*/[0-9]*/[0-9]*/-1/[0-9]* 400 .* - - CH-- .* .* \"GET /c3 HTTP/1\\.1\""
+} -start
+
+syslog S2 -level info {
+ recv alert
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: Server check/srv1 is DOWN.*"
+ barrier b0 sync
+
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* -1 .* - - CC-- .* .* \"GET /c5 HTTP/1\\.1\""
+ barrier b2 sync
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be2/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - SC-- .* .* \"GET /c6 HTTP/1\\.1\""
+} -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ option abortonclose
+ retries 1
+ timeout client 10s
+ timeout server 10s
+ timeout connect 100ms
+ timeout queue 5s
+
+ frontend fe1
+ option httplog
+ log ${S1_addr}:${S1_port} local0 debug err
+ bind "fd@${fe1}"
+ use_backend be1_1 if { path /c1 }
+ use_backend be1_2 if { path /c2 }
+
+ frontend fe2
+ option httplog
+ log ${S1_addr}:${S1_port} local0 debug err
+ bind "fd@${fe2}"
+ use_backend be2
+
+ backend be1_1
+ server srv1 ${s1_addr}:${s1_port}
+
+ backend be1_2
+ timeout connect 1s
+ retries 10
+ server srv1 ${s1_addr}:${s1_port}
+
+ backend be2
+ server srv1 ${s2_addr}:${s2_port} maxconn 1
+
+ backend check
+ server srv1 ${s1_addr}:${s1_port} check
+ log ${S1_addr}:${S1_port} local0 debug alert
+} -start
+
+
+haproxy h2 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ retries 1
+ timeout client 10s
+ timeout server 10s
+ timeout connect 100ms
+ timeout queue 5s
+
+ frontend fe1
+ option httplog
+ log ${S2_addr}:${S2_port} local0 debug err
+ bind "fd@${fe1}"
+ use_backend be1
+
+ backend be1
+ option abortonclose
+ server srv1 ${s1_addr}:${s1_port}
+
+ defaults
+ mode http
+ option abortonclose
+ retries 1
+ timeout client 10s
+ timeout server 10s
+ timeout connect 100ms
+ timeout queue 5s
+
+ frontend fe2
+ option httplog
+ log ${S2_addr}:${S2_port} local0 debug err
+ bind "fd@${fe2}"
+ use_backend be2
+
+ backend be2
+ no option abortonclose
+ server srv1 ${s1_addr}:${s1_port}
+
+ backend check
+ server srv1 ${s1_addr}:${s1_port} check
+ log ${S2_addr}:${S2_port} local0 debug alert
+} -start
+
+
+# Wait s1 was detected as DOWN
+barrier b0 sync
+
+# No server, wait all connection retries : SC--
+client c1 -connect ${h1_fe1_sock} {
+ txreq -url /c1
+ rxresp
+ expect resp.status == 503
+} -run
+
+# Wait c1 log entry
+barrier b2 sync
+
+# No server, abort during connections retries : CC--
+client c2 -connect ${h1_fe1_sock} {
+ txreq -url /c2
+} -run
+
+# Wait c2 log entry
+barrier b2 sync
+
+# server with maxconn=1, abort waiting the server reply : CH--
+client c3 -connect ${h1_fe2_sock} {
+ txreq -url /c3
+
+ # Wait c4 log entry
+ barrier b2 sync
+} -start
+
+# server with maxconn=1, abort waiting in the queue (c3 still attached) : CQ--
+client c4 -connect ${h1_fe2_sock} {
+ # Wait s2 receives c3 request
+ barrier b1 sync
+
+ txreq -url /c4
+ delay .2
+} -run
+
+client c3 -wait
+
+# unlock s2
+barrier b3 sync
+
+syslog S1 -wait
+
+
+# No server, abort during connections retries : CC--
+# abortonclose on backend only
+client c5 -connect ${h2_fe1_sock} {
+ txreq -url /c5
+} -run
+
+# Wait c5 log entry
+barrier b2 sync
+
+# No server, wait all connection retries : SC--
+# abortonclose in defaults section but disabled by backend
+client c6 -connect ${h2_fe2_sock} {
+ txreq -url /c6
+ rxresp
+ expect resp.status == 503
+} -run
+
+
+syslog S2 -wait
diff --git a/reg-tests/http-messaging/http_bodyless_response.vtc b/reg-tests/http-messaging/http_bodyless_response.vtc
new file mode 100644
index 0000000..6b53bc4
--- /dev/null
+++ b/reg-tests/http-messaging/http_bodyless_response.vtc
@@ -0,0 +1,128 @@
+varnishtest "A test to be sure payload is skipped for bodyless responses"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+
+server s1 {
+ rxreq
+ txresp \
+ -status 200 \
+ -body "skipped data"
+
+ rxreq
+ txresp \
+ -status 200 \
+ -bodylen 50000
+
+ rxreq
+ txresp \
+ -status 200 \
+ -nolen -hdr "Transfer-Encoding: chunked"
+ chunkedlen 15
+ chunkedlen 1024
+ chunkedlen 4048
+ chunkedlen 50000
+ chunkedlen 0
+
+ rxreq
+ txresp \
+ -status 200 \
+ -body "last response"
+} -repeat 3 -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen fe1
+ bind "fd@${fe1}"
+ # Rewrite the method to be sure to get the response payload
+ # on the server side
+ http-request set-method GET
+ server s1 ${s1_addr}:${s1_port}
+
+ listen int
+ bind "fd@${int}" proto h2
+ # Rewrite the method to be sure to get the response payload
+ # on the server side
+ http-request set-method GET
+ server s1 ${s1_addr}:${s1_port}
+ #server s1 ${h1_fe1_addr}:${h1_fe1_port}
+
+ listen fe2
+ bind "fd@${fe2}"
+ server s1 ${h1_int_addr}:${h1_int_port} proto h2
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq \
+ -req "HEAD" \
+ -url "/req1"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ txreq \
+ -req "HEAD" \
+ -url "/req2"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ txreq \
+ -req "HEAD" \
+ -url "/req3"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ # The last one have a body and validate the connection was not closed
+ # unexpectedly and no payload was received for previous requests
+ txreq \
+ -req "GET" \
+ -url "/req4"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "last response"
+} -run
+
+client c2 -connect ${h1_fe2_sock} {
+ txreq \
+ -req "HEAD" \
+ -url "/req1"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ txreq \
+ -req "HEAD" \
+ -url "/req2"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ txreq \
+ -req "HEAD" \
+ -url "/req3"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ # The last one have a body and validate the connection was not closed
+ # unexpectedly and no payload was received for previous requests
+ txreq \
+ -req "GET" \
+ -url "/req4"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "last response"
+} -run
diff --git a/reg-tests/http-messaging/http_bodyless_spliced_response.vtc b/reg-tests/http-messaging/http_bodyless_spliced_response.vtc
new file mode 100644
index 0000000..73916f2
--- /dev/null
+++ b/reg-tests/http-messaging/http_bodyless_spliced_response.vtc
@@ -0,0 +1,89 @@
+varnishtest "A test to be sure payload is skipped for bodyless responses when splicing is used"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(LINUX_SPLICE)'"
+feature cmd "$HAPROXY_PROGRAM $HAPROXY_ARGS -cc 'enabled(FAST-FORWARD)'"
+feature cmd "$HAPROXY_PROGRAM $HAPROXY_ARGS -cc 'enabled(SPLICE)'"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+
+server s1 {
+ rxreq
+ txresp \
+ -status 200 \
+ -body "skipped data"
+
+ rxreq
+ txresp \
+ -status 200 \
+ -bodylen 50000
+
+ rxreq
+ txresp \
+ -status 200 \
+ -nolen -hdr "Transfer-Encoding: chunked"
+ chunkedlen 15
+ chunkedlen 1024
+ chunkedlen 4048
+ chunkedlen 50000
+ chunkedlen 0
+
+ rxreq
+ txresp \
+ -status 200 \
+ -body "last response"
+} -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen fe1
+ bind "fd@${fe1}"
+ # Rewrite the method to be sure to get the response payload
+ # on the server side
+ http-request set-method GET
+ option splice-response
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq \
+ -req "HEAD" \
+ -url "/req1"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ txreq \
+ -req "HEAD" \
+ -url "/req2"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ txreq \
+ -req "HEAD" \
+ -url "/req3"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == ""
+
+ # The last one have a body and validate the connection was not closed
+ # unexpectedly and no payload was received for previous requests
+ txreq \
+ -req "GET" \
+ -url "/req4"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "last response"
+} -run
diff --git a/reg-tests/http-messaging/http_msg_full_on_eom.vtc b/reg-tests/http-messaging/http_msg_full_on_eom.vtc
new file mode 100644
index 0000000..2edba7d
--- /dev/null
+++ b/reg-tests/http-messaging/http_msg_full_on_eom.vtc
@@ -0,0 +1,62 @@
+varnishtest "cannot add the HTX EOM block because the buffer is full"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.2
+#REQUIRE_VERSION_BELOW=2.4
+#REGTEST_TYPE=devel
+
+# This test checks that an HTTP message is properly processed when we failed to
+# add the HTX EOM block in an HTX message during the parsing because the buffer
+# is full. Some space must be released in the buffer to make it possible. This
+# requires an extra pass in the H1 multiplexer. Here, we must be sure the mux is
+# called while there is no more incoming data.
+
+server s1 {
+ rxreq
+ expect req.bodylen == 15200
+ txresp -bodylen 15220
+} -start
+
+syslog S -level info {
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"GET / HTTP/1\\.1\""
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.bufsize 16384
+ tune.maxrewrite 1024
+
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ tcp-response inspect-delay 100ms
+ tcp-response content accept if { res.len gt 15272 }
+ tcp-response content reject
+
+ http-response deny if { internal.htx.has_eom -m bool } or { internal.htx.free_data gt 1024 }
+ server srv1 ${s1_addr}:${s1_port}
+
+ frontend fe1
+ option httplog
+ option http-buffer-request
+ log ${S_addr}:${S_port} local0 debug err
+ bind "fd@${fe1}"
+ http-request deny if ! { req.body_len eq 15200 } or { internal.htx.has_eom -m bool } or { internal.htx.free_data gt 1024 }
+ use_backend be1
+} -start
+
+haproxy h1 -cli {
+ send "trace h1 sink stderr; trace h1 level developer; trace h1 verbosity complete; trace h1 start now"
+}
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -bodylen 15200
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 15220
+} -run
diff --git a/reg-tests/http-messaging/http_request_buffer.vtc b/reg-tests/http-messaging/http_request_buffer.vtc
new file mode 100644
index 0000000..302db4a
--- /dev/null
+++ b/reg-tests/http-messaging/http_request_buffer.vtc
@@ -0,0 +1,135 @@
+varnishtest "A test for http-request-buffer option"
+feature ignore_unknown_macro
+
+
+# This test checks HTTP request buffering feature.
+# We run one server s1 which can serve only one client (no -repeat argument here).
+# c1 client uses a malformed request which is not transferred to s1 server
+# thanks to "http-buffer-request". If this was the case, c2 client
+# could not connect to s1 server and this would lead to make this test fail.
+
+barrier b1 cond 2 -cyclic
+
+server s1 {
+ rxreq
+ expect req.bodylen == 257
+ txresp
+
+ accept
+
+ rxreq
+ expect req.bodylen == 2
+ txresp
+} -start
+
+syslog S -level info {
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 fe1/<NOSRV> .* 408 .* - - cR-- .* .* \"GET /this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url HTTP/1\\.1\""
+ barrier b1 sync
+
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"GET / HTTP/1\\.1\""
+ barrier b1 sync
+
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"POST /1 HTTP/1\\.1\""
+ barrier b1 sync
+
+ recv
+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be1/<NOSRV> [0-9]*/-1/-1/-1/[0-9]* 400 .* - - CR-- .* .* \"POST /2 HTTP/1\\.1\""
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout client 100
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend be1
+ server srv1 ${s1_addr}:${s1_port}
+
+ frontend fe1
+ option httplog
+ option http-buffer-request
+ log ${S_addr}:${S_port} local0 debug err
+ bind "fd@${fe1}"
+ use_backend be1
+
+ frontend fe2
+ timeout client 10s
+ option httplog
+ option http-buffer-request
+ log ${S_addr}:${S_port} local0 debug err
+ bind "fd@${fe2}"
+ use_backend be1
+} -start
+
+# 1 byte of the payload is missing.
+# ==> The request must timed out with a 408 response
+client c1 -connect ${h1_fe1_sock} {
+ send "GET"
+ send " "
+ send "/this-is-a-long-url"
+ send "-this-is-a-long-url"
+ send "-this-is-a-long-url"
+ send "-this-is-a-long-url"
+ send "-this-is-a-long-url"
+ send "-this-is-a-long-url"
+ send "-this-is-a-long-url"
+ send " HTT"
+ send "P/1.1"
+ send "\r"
+ send "\n"
+ send "Content-Length: 209\r\n\r\n"
+ send "abcdefghijklmnopqrstuvwxyz"
+ send "abcdefghijklmnopqrstuvwxyz"
+ send "abcdefghijklmnopqrstuvwxyz"
+ send "abcdefghijklmnopqrstuvwxyz"
+ send "abcdefghijklmnopqrstuvwxyz"
+ send "abcdefghijklmnopqrstuvwxyz"
+ send "abcdefghijklmnopqrstuvwxyz"
+ send "abcdefghijklmnopqrstuvwxyz"
+ rxresp
+ expect resp.status == 408
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# Payload is fully sent
+# ==> Request must be sent to the server. A 200 must be received
+client c2 -connect ${h1_fe1_sock} {
+ txreq -bodylen 257
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# Payload is fully sent in 2 steps (with a small delay, smaller than the client
+# timeout) and split on a chunk size.
+# ==> Request must be sent to the server. A 200 must be received
+client c3 -connect ${h1_fe2_sock} {
+ send "POST /1 HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n1\r\n1\r\n1"
+ delay 0.01
+ send "\r\n1\r\n0\r\n\r\n"
+ rxresp
+ expect resp.status == 200
+} -run
+
+# Wait matching on log message
+barrier b1 sync
+
+# Last CRLF of the request payload is missing but payload is sent in 2 steps
+# (with a small delay, smaller than the client timeout) and split on a chunk
+# size. The client aborts before sending the last CRLF.
+# ==> Request must be handled as an error with 'CR--' termination state.
+client c4 -connect ${h1_fe2_sock} {
+ send "POST /2 HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n1\r\n1\r\n1"
+ delay 0.01
+ send "\r\n1\r\n0\r\n"
+} -run
+
+syslog S -wait
diff --git a/reg-tests/http-messaging/http_splicing.vtc b/reg-tests/http-messaging/http_splicing.vtc
new file mode 100644
index 0000000..e86680b
--- /dev/null
+++ b/reg-tests/http-messaging/http_splicing.vtc
@@ -0,0 +1,77 @@
+# This reg-test checks splicing support for the H1 multiplexer
+
+varnishtest "A test to validate h1 splicing support"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.6-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(LINUX_SPLICE)'"
+feature cmd "$HAPROXY_PROGRAM $HAPROXY_ARGS -cc 'enabled(FAST-FORWARD)'"
+feature cmd "$HAPROXY_PROGRAM $HAPROXY_ARGS -cc 'enabled(SPLICE)'"
+feature ignore_unknown_macro
+
+#REGTEST_TYPE=slow
+
+server s1 {
+ rxreq
+ expect req.http.content-length == "1048576"
+ expect req.bodylen == 1048576
+ txresp -status 200 -bodylen 1048576
+} -start
+
+server s2 {
+ rxreq
+ txresp -status 200 -nolen -bodylen 1048576
+} -start
+
+haproxy h1 -conf {
+ global
+ log stderr len 4096 local0 debug
+
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ option splice-request
+ option splice-response
+ log global
+ option httplog
+
+ listen li1
+ bind "fd@${li1}"
+ id 10
+ server srv1 ${s1_addr}:${s1_port}
+
+ listen li2
+ bind "fd@${li2}"
+ id 20
+ server srv2 ${s2_addr}:${s2_port}
+} -start
+
+
+client c1 -connect ${h1_li1_sock} {
+ txreq -method POST -url "/" -bodylen 1048576
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == "1048576"
+ expect resp.bodylen == 1048576
+} -run
+
+client c2 -connect ${h1_li2_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == <undef>
+ expect resp.bodylen == 1048576
+} -run
+
+haproxy h1 -cli {
+ send "show stat typed"
+ expect ~ "F.10.0.[[:digit:]]+.h1_spliced_bytes_in.1:MCP:u64:[1-9][[:digit:]]+\nF.10.0.[[:digit:]]+.h1_spliced_bytes_out.1:MCP:u64:[1-9][[:digit:]]+"
+ send "show stat typed"
+ expect ~ "B.10.0.[[:digit:]]+.h1_spliced_bytes_in.1:MCP:u64:[1-9][[:digit:]]+\nB.10.0.[[:digit:]]+.h1_spliced_bytes_out.1:MCP:u64:[1-9][[:digit:]]+"
+
+ send "show stat typed"
+ expect ~ "F.20.0.[[:digit:]]+.h1_spliced_bytes_in.1:MCP:u64:0\nF.20.0.[[:digit:]]+.h1_spliced_bytes_out.1:MCP:u64:[1-9][[:digit:]]+"
+ send "show stat typed"
+ expect ~ "B.20.0.[[:digit:]]+.h1_spliced_bytes_in.1:MCP:u64:[1-9][[:digit:]]+\nB.20.0.[[:digit:]]+.h1_spliced_bytes_out.1:MCP:u64:0"
+}
diff --git a/reg-tests/http-messaging/http_splicing_chunk.vtc b/reg-tests/http-messaging/http_splicing_chunk.vtc
new file mode 100644
index 0000000..e2e9f32
--- /dev/null
+++ b/reg-tests/http-messaging/http_splicing_chunk.vtc
@@ -0,0 +1,74 @@
+# This reg-test checks splicing support for chunked message in the H1 multiplexer
+
+varnishtest "A test to validate h1 splicing support for chunked messages"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.9-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(LINUX_SPLICE)'"
+feature cmd "$HAPROXY_PROGRAM $HAPROXY_ARGS -cc 'enabled(FAST-FORWARD)'"
+feature cmd "$HAPROXY_PROGRAM $HAPROXY_ARGS -cc 'enabled(SPLICE)'"
+feature ignore_unknown_macro
+
+#REGTEST_TYPE=slow
+
+server s1 {
+ rxreq
+ expect req.http.content-length == <undef>
+ expect req.http.transfer-encoding == "chunked"
+ expect req.bodylen == 500000
+
+ txresp -status 200 -nolen \
+ -hdr "Transfer-Encoding: chunked"
+ chunkedlen 204800
+ chunkedlen 204800
+ chunkedlen 204800
+ chunkedlen 204800
+ chunkedlen 204800
+ chunkedlen 0
+} -start
+
+haproxy h1 -conf {
+ global
+ log stderr len 4096 local0 debug
+
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ option splice-request
+ option splice-response
+ log global
+ option httplog
+
+ listen li1
+ bind "fd@${li1}"
+ id 10
+ server srv1 ${s1_addr}:${s1_port}
+} -start
+
+
+client c1 -connect ${h1_li1_sock} {
+ txreq -method POST -url "/" -nolen \
+ -hdr "Transfer-Encoding: chunked"
+ chunkedlen 10000
+ chunkedlen 10000
+ chunkedlen 10000
+ chunkedlen 10000
+ chunkedlen 10000
+ chunkedlen 50000
+ chunkedlen 100000
+ chunkedlen 300000
+ chunkedlen 0
+
+ rxresp
+ expect resp.http.content-length == <undef>
+ expect resp.http.transfer-encoding == "chunked"
+ expect resp.bodylen == 1024000
+} -run
+
+haproxy h1 -cli {
+ send "show stat typed"
+ expect ~ "F.10.0.[[:digit:]]+.h1_spliced_bytes_in.1:MCP:u64:[1-9][[:digit:]]+\nF.10.0.[[:digit:]]+.h1_spliced_bytes_out.1:MCP:u64:[1-9][[:digit:]]+"
+ send "show stat typed"
+ expect ~ "B.10.0.[[:digit:]]+.h1_spliced_bytes_in.1:MCP:u64:[1-9][[:digit:]]+\nB.10.0.[[:digit:]]+.h1_spliced_bytes_out.1:MCP:u64:[1-9][[:digit:]]+"
+}
diff --git a/reg-tests/http-messaging/http_transfer_encoding.vtc b/reg-tests/http-messaging/http_transfer_encoding.vtc
new file mode 100644
index 0000000..322dfe2
--- /dev/null
+++ b/reg-tests/http-messaging/http_transfer_encoding.vtc
@@ -0,0 +1,202 @@
+varnishtest "A test to validate Transfer-Encoding header conformance to the spec"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.http.content-length == <undef>
+ expect req.http.transfer-encoding == "chunked"
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp -status 200
+
+ accept
+ rxreq
+ expect req.http.content-length == <undef>
+ expect req.http.transfer-encoding == "chunked"
+ expect req.bodylen == 0
+ expect req.body == ""
+ txresp -status 200
+
+ accept
+ rxreq
+ send "HTTP/1.0 200 Ok\r\n"
+ send "Transfer-Encoding: chunked\r\n\r\n"
+ send "0\r\n\r\n"
+
+ accept
+ rxreq
+ send "HTTP/1.1 200 Ok\r\n"
+ send "Transfer-Encoding: chunked\r\n"
+ send "Content-Length: 30\r\n\r\n"
+ send "0\r\n\r\nResponse splitting attach"
+
+ accept
+ rxreq
+ expect req.url == "/1"
+ expect req.http.transfer-encoding == "chunked"
+ expect req.http.te == "trailers"
+ txresp
+
+ rxreq
+ expect req.url == "/2"
+ expect req.http.transfer-encoding == "chunked"
+ expect req.http.te == <undef>
+ txresp
+
+ rxreq
+ expect req.url == "/3"
+ expect req.http.transfer-encoding == "chunked"
+ expect req.http.te == <undef>
+ txresp
+} -start
+
+server s2 {
+ rxreq
+ txresp -nolen \
+ -hdr "Transfer-Encoding: chunked, chunked" \
+ -body "0\r\n\r\n"
+
+ accept
+ rxreq
+ txresp -nolen \
+ -hdr "Transfer-Encoding: chunked, gzip, chunked" \
+ -body "0\r\n\r\n"
+
+ accept
+ rxreq
+ txresp -nolen \
+ -hdr "Transfer-Encoding: chunked, gzip" \
+ -body "0\r\n\r\n"
+
+ accept
+ rxreq
+ txresp \
+ -hdr "Transfer-Encoding: gzip"
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen fe1
+ bind "fd@${fe1}"
+ server s1 ${s1_addr}:${s1_port}
+
+ listen fe2
+ bind "fd@${fe2}"
+ server s2 ${s2_addr}:${s2_port}
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -method POST -nolen \
+ -hdr "Transfer-Encoding: chunked" \
+ -hdr "Content-Length: 31" \
+ -body "0\r\n\r\nGET /smuggled HTTP/1.1\r\n\r\n"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.connection == "close"
+ expect_close
+} -run
+
+client c2 -connect ${h1_fe1_sock} {
+ send "POST / HTTP/1.0\r\n"
+ send "Transfer-Encoding: chunked\r\n\r\n"
+ send "0\r\n\r\n"
+ rxresp
+ expect resp.status == 200
+ expect_close
+} -run
+
+client c3 -connect ${h1_fe1_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == <undef>
+ expect resp.http.transfer-encoding == "chunked"
+ expect resp.bodylen == 0
+ expect resp.body == ""
+ expect_close
+} -run
+
+client c4 -connect ${h1_fe1_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == <undef>
+ expect resp.http.transfer-encoding == "chunked"
+ expect resp.bodylen == 0
+ expect resp.body == ""
+} -run
+
+client c5 -connect ${h1_fe1_sock} {
+ txreq -method POST -url "/1" -nolen \
+ -hdr "Transfer-Encoding: chunked" \
+ -hdr "TE: trailers, gzip" \
+ -body "0\r\n\r\n"
+ rxresp
+ expect resp.status == 200
+
+ txreq -method POST -url "/2" -nolen \
+ -hdr "Transfer-Encoding: chunked" \
+ -hdr "TE: gzip" \
+ -body "0\r\n\r\n"
+ rxresp
+ expect resp.status == 200
+
+ txreq -method POST -url "/3" -nolen \
+ -hdr "Transfer-Encoding: chunked" \
+ -hdr "TE: trailers;q=0.5" \
+ -body "0\r\n\r\n"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c6 -connect ${h1_fe1_sock} {
+ txreq -nolen \
+ -hdr "Transfer-Encoding: chunked, chunked" \
+ -body "0\r\n\r\n"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c7 -connect ${h1_fe1_sock} {
+ txreq -nolen \
+ -hdr "Transfer-Encoding: chunked, gzip, chunked" \
+ -body "0\r\n\r\n"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c8 -connect ${h1_fe1_sock} {
+ txreq -nolen \
+ -hdr "Transfer-Encoding: chunked, gzip" \
+ -body "0\r\n\r\n"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c9 -connect ${h1_fe1_sock} {
+ txreq \
+ -hdr "Transfer-Encoding: gzip"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c10 -connect ${h1_fe1_sock} {
+ txreq -nolen \
+ -hdr "Transfer-Encoding: gzip, chunked" \
+ -body "0\r\n\r\n"
+ rxresp
+ expect resp.status == 422
+} -run
+
+client c11 -connect ${h1_fe2_sock} {
+ txreq
+ rxresp
+ expect resp.status == 502
+} -run -repeat 4
diff --git a/reg-tests/http-messaging/http_wait_for_body.vtc b/reg-tests/http-messaging/http_wait_for_body.vtc
new file mode 100644
index 0000000..a9f8191
--- /dev/null
+++ b/reg-tests/http-messaging/http_wait_for_body.vtc
@@ -0,0 +1,171 @@
+varnishtest "A test for the wait-for-body HTTP action"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+#REGTEST_TYPE=slow
+
+server s1 {
+ rxreq
+ expect req.bodylen == 1001
+ txresp
+
+ rxreq
+ expect req.bodylen == 1001
+ txresp
+} -start
+
+
+server s2 {
+ rxreq
+ send "HTTP/1.1 200 OK\r\n"
+ send "Content-Length: 1001\r\n\r\n"
+ delay 0.01
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+
+ expect_close
+ accept
+
+ rxreq
+ send "HTTP/1.1 200 OK\r\n"
+ send "Content-Length: 1001\r\n\r\n"
+ delay 0.01
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ delay 0.01
+ send "1"
+
+ rxreq
+ send "HTTP/1.1 201 OK\r\n"
+ send "Content-Length: 1001\r\n\r\n"
+ delay 0.01
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ delay 0.1
+ send "1"
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ http-request wait-for-body time 100ms if { path /a }
+ http-request wait-for-body time 100ms at-least 1000 if { path /b }
+ use_backend be1
+
+ backend be1
+ server srv1 ${s1_addr}:${s1_port}
+
+ frontend fe2
+ bind "fd@${fe2}"
+ use_backend be2
+
+ backend be2
+ http-response wait-for-body time 100ms if { status eq 200 }
+ http-response wait-for-body time 100ms at-least 1000 if { status eq 201 }
+ server srv1 ${s2_addr}:${s2_port}
+} -start
+
+
+client c1 -connect ${h1_fe1_sock} {
+ send "GET /a HTTP/1.1\r\n"
+ send "Content-Length: 1001\r\n\r\n"
+ delay 0.01
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ rxresp
+ expect resp.status == 408
+} -run
+
+client c2 -connect ${h1_fe1_sock} {
+ send "GET /a HTTP/1.1\r\n"
+ send "Content-Length: 1001\r\n\r\n"
+ delay 0.01
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ delay 0.01
+ send "1"
+ rxresp
+ expect resp.status == 200
+
+ send "GET /b HTTP/1.1\r\n"
+ send "Content-Length: 1001\r\n\r\n"
+ delay 0.01
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ send "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=====================================\n"
+ delay 0.1
+ send "1"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c3 -connect ${h1_fe2_sock} {
+ txreq
+ rxresp
+ expect resp.status == 504
+} -run
+
+client c4 -connect ${h1_fe2_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 1001
+
+ txreq
+ rxresp
+ expect resp.status == 201
+ expect resp.bodylen == 1001
+} -run
diff --git a/reg-tests/http-messaging/protocol_upgrade.vtc b/reg-tests/http-messaging/protocol_upgrade.vtc
new file mode 100644
index 0000000..ebb6328
--- /dev/null
+++ b/reg-tests/http-messaging/protocol_upgrade.vtc
@@ -0,0 +1,228 @@
+# This reg-test checks the full support of HTTP protocol upgrade, using a GET
+# method and a Connection: Upgrade header. The equivalent mechanism has been
+# defined in rfc8441 for HTTP/2 using CONNECT and a new pseudo-header
+# :protocol. Check that haproxy handles properly h1/h2 translation of protocol
+# upgrade requests and responses.
+
+varnishtest "h1/h2 support for protocol upgrade test"
+
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+
+# http/1.1 server
+server srv_h1 {
+ rxreq
+ expect req.method == "GET"
+ expect req.http.connection == "upgrade"
+ expect req.http.upgrade == "custom_protocol"
+
+ txresp \
+ -status 101 \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: custom_protocol"
+} -repeat 2 -start
+
+# http2 server
+server srv_h2 {
+ rxpri
+
+ stream 0 {
+ # manually send RFC8441 SETTINGS_ENABLE_CONNECT_PROTOCOL
+ sendhex "00 00 06 04 00 00 00 00 00 00 08 00 00 00 01"
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ rxhdrs
+ expect req.method == "CONNECT"
+ expect req.http.:scheme == "https"
+ expect req.http.:path == "/"
+ expect req.http.:authority == "127.0.0.1"
+ expect req.http.:protocol == "custom_protocol"
+
+ txresp \
+ -status 200
+ } -run
+} -repeat 2 -start
+
+# http2 server without support for RFC8441
+server srv_h2_no_ws {
+ rxpri
+
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ rxrst
+ } -run
+} -start
+
+# http2 server without support for RFC8441 : settings announced with value 0
+server srv_h2_no_ws2 {
+ rxpri
+
+ stream 0 {
+ # manually send RFC8441 SETTINGS_ENABLE_CONNECT_PROTOCOL with a value of 0
+ sendhex "00 00 06 04 00 00 00 00 00 00 08 00 00 00 00"
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ rxrst
+ } -run
+} -start
+
+haproxy hap -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ # h1 frontend connected to h2 frontend
+ listen frt_h1_h2
+ bind "fd@${frt_h1_h2}"
+ server feh2_srv ${hap_frt_h2_addr}:${hap_frt_h2_port} proto h2
+
+ # h2 frontend connected to srv_h1
+ listen frt_h2
+ bind "fd@${frt_h2}" proto h2
+ server srv_h1 ${srv_h1_addr}:${srv_h1_port}
+
+ # h1 frontend connected to srv_h2
+ listen frt_h1
+ bind "fd@${frt_h1}"
+ server srv_h2 ${srv_h2_addr}:${srv_h2_port} proto h2
+
+ # h1 frontend connected to srv_h2_no_ws
+ listen frt_h1_no_ws
+ bind "fd@${frt_h1_no_ws}"
+ server srv_h2_no_ws ${srv_h2_no_ws_addr}:${srv_h2_no_ws_port} proto h2
+
+ # h1 frontend connected to srv_h2_no_ws2
+ listen frt_h1_no_ws2
+ bind "fd@${frt_h1_no_ws2}"
+ server srv_h2_no_ws2 ${srv_h2_no_ws2_addr}:${srv_h2_no_ws2_port} proto h2
+
+ # h2 frontend connected to h1 frontend
+ listen frt_h2_h1
+ bind "fd@${frt_h2_h1}" proto h2
+ server frt_h1 ${hap_frt_h1_addr}:${hap_frt_h1_port}
+} -start
+
+## connect to h1 translation frontend
+client c1_h1_h2 -connect ${hap_frt_h1_h2_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: custom_protocol"
+
+ rxresp
+ expect resp.status == 101
+ expect resp.http.connection == "upgrade"
+ expect resp.http.upgrade == "custom_protocol"
+} -run
+
+# connect to h2 server frontend
+client c2_h2 -connect ${hap_frt_h2_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -req "CONNECT" \
+ -scheme "http" \
+ -url "/" \
+ -hdr ":authority" "127.0.0.1" \
+ -hdr ":protocol" "custom_protocol"
+
+ rxhdrs
+ expect resp.status == 200
+ } -run
+} -run
+
+# connect to h2 translation frontend
+client c3_h2_h1 -connect ${hap_frt_h2_h1_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -req "CONNECT" \
+ -scheme "http" \
+ -url "/" \
+ -hdr ":authority" "127.0.0.1" \
+ -hdr ":protocol" "custom_protocol"
+
+ rxhdrs
+ expect resp.status == 200
+ } -run
+} -run
+
+# connect to h1 server frontend
+client c4_h1 -connect ${hap_frt_h1_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: custom_protocol"
+
+ rxresp
+ expect resp.status == 101
+ expect resp.http.connection == "upgrade"
+ expect resp.http.upgrade == "custom_protocol"
+} -run
+
+# connect via h1 server frontend to h2 server without RFC8441 support
+client c5 -connect ${hap_frt_h1_no_ws_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: custom_protocol"
+
+ rxresp
+ expect resp.status == 502
+} -run
+
+# connect via h1 server frontend to h2 server without RFC8441 support
+client c6 -connect ${hap_frt_h1_no_ws2_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: custom_protocol"
+
+ rxresp
+ expect resp.status == 502
+} -run
diff --git a/reg-tests/http-messaging/scheme_based_normalize.vtc b/reg-tests/http-messaging/scheme_based_normalize.vtc
new file mode 100644
index 0000000..3edbafb
--- /dev/null
+++ b/reg-tests/http-messaging/scheme_based_normalize.vtc
@@ -0,0 +1,125 @@
+varnishtest "scheme based normalization (rfc3982 6.3.2)"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature ignore_unknown_macro
+
+syslog S1 -level info {
+ recv
+ expect ~ "^.* uri: GET http://hostname/ HTTP/2.0; host: {hostname}$"
+
+ recv
+ expect ~ "^.* uri: GET http://hostname:8080/ HTTP/2.0; host: {hostname:8080}$"
+
+ recv
+ expect ~ "^.* uri: GET https://hostname/ HTTP/2.0; host: {hostname}$"
+
+ recv
+ expect ~ "^.* uri: GET https://hostname:80/ HTTP/2.0; host: {hostname:80}$"
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}" proto h2
+
+ http-request capture req.hdr(host) len 512
+ log-format "uri: %r; host: %hr"
+ log ${S1_addr}:${S1_port} len 2048 local0 debug err
+
+ http-request return status 200
+} -start
+
+# default port 80 with http scheme => should be normalized
+client c1 -connect ${h1_fe_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -req "GET" \
+ -scheme "http" \
+ -url "/" \
+ -hdr ":authority" "hostname:80"
+ rxhdrs
+ expect resp.status == 200
+ } -run
+} -run
+
+# port 8080 with http scheme => no normalization
+client c2 -connect ${h1_fe_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -req "GET" \
+ -scheme "http" \
+ -url "/" \
+ -hdr ":authority" "hostname:8080"
+ rxhdrs
+ expect resp.status == 200
+ } -run
+} -run
+
+# default port 443 with https scheme => should be normalized
+client c3 -connect ${h1_fe_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -req "GET" \
+ -scheme "https" \
+ -url "/" \
+ -hdr ":authority" "hostname:443"
+ rxhdrs
+ expect resp.status == 200
+ } -run
+} -run
+
+# port 80 with https scheme => no normalization
+client c4 -connect ${h1_fe_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -req "GET" \
+ -scheme "https" \
+ -url "/" \
+ -hdr ":authority" "hostname:80"
+ rxhdrs
+ expect resp.status == 200
+ } -run
+} -run
+
+syslog S1 -wait
diff --git a/reg-tests/http-messaging/srv_ws.vtc b/reg-tests/http-messaging/srv_ws.vtc
new file mode 100644
index 0000000..f0f5f8b
--- /dev/null
+++ b/reg-tests/http-messaging/srv_ws.vtc
@@ -0,0 +1,180 @@
+# This reg-test checks websocket support in regards with the server keyword
+# 'ws'
+
+varnishtest "h2 backend websocket management via server keyword"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)' && !ssllib_name_startswith(wolfSSL)'"
+feature ignore_unknown_macro
+
+# haproxy server
+haproxy hapsrv -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ bind "fd@${fessl}" ssl crt ${testdir}/common.pem alpn h2,http/1.1
+ capture request header sec-websocket-key len 128
+ http-request set-var(txn.ver) req.ver
+ use_backend be
+
+ backend be
+ # define websocket ACL
+ acl ws_handshake hdr(upgrade) -m str websocket
+
+ # handle non-ws streams
+ http-request return status 200 if !ws_handshake
+
+ # handle ws streams
+ #capture request header sec-websocket-key len 128
+ http-request return status 200 hdr connection upgrade hdr upgrade websocket hdr sec-websocket-accept "%[capture.req.hdr(0),concat(258EAFA5-E914-47DA-95CA-C5AB0DC85B11,,),sha1,base64]" if ws_handshake
+ http-after-response set-status 101 if { status eq 200 } { res.hdr(upgrade) -m str websocket }
+ http-after-response set-header x-backend-protocol "%[var(txn.ver)]"
+} -start
+
+# haproxy LB
+haproxy hap -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ # proto X ws h1 -> websocket on h1
+ listen li
+ bind "fd@${li}"
+ server hap_srv ${hapsrv_fe_addr}:${hapsrv_fe_port} proto h2 ws h1
+
+ # proto X ws h2 -> websocket on h2
+ listen lih2
+ bind "fd@${lih2}"
+ server hap_srv ${hapsrv_fe_addr}:${hapsrv_fe_port} proto h2 ws h2
+
+ # alpn h2,http/1.1 ws h2 -> websocket on h2
+ listen lisslh2
+ bind "fd@${lisslh2}"
+ server hap_srv ${hapsrv_fessl_addr}:${hapsrv_fessl_port} ssl verify none alpn h2,http/1.1 ws h2
+ http-response set-header x-alpn "%[ssl_bc_alpn]"
+
+ # ws auto -> websocket on h1
+ listen liauto
+ bind "fd@${liauto}"
+ server hap_srv ${hapsrv_fe_addr}:${hapsrv_fe_port}
+
+ # alpn h2,http/1.1 ws auto -> websocket on h1
+ listen lissl
+ bind "fd@${lissl}"
+ server hap_srv ${hapsrv_fessl_addr}:${hapsrv_fessl_port} ssl verify none alpn h2,http/1.1 ws auto
+ http-response set-header x-alpn "%[ssl_bc_alpn]"
+ # alpn h2,http/1.1 ws auto -> websocket on h1
+ listen lisslauto
+ bind "fd@${lisslauto}"
+ server hap_srv ${hapsrv_fessl_addr}:${hapsrv_fessl_port} ssl verify none alpn h2,http/1.1
+ http-response set-header x-alpn "%[ssl_bc_alpn]"
+
+ # proto h2 ws auto -> websocket on h2
+ listen liauto2
+ bind "fd@${liauto2}"
+ server hap_srv ${hapsrv_fe_addr}:${hapsrv_fe_port} proto h2
+
+ # alpn h2 ws auto -> websocket on h2
+ listen lisslauto2
+ bind "fd@${lisslauto2}"
+ server hap_srv ${hapsrv_fessl_addr}:${hapsrv_fessl_port} ssl verify none alpn h2 ws auto
+ http-response set-header x-alpn "%[ssl_bc_alpn]"
+} -start
+
+client c1 -connect ${hap_li_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket" \
+ -hdr "sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ=="
+ rxresp
+ expect resp.status == 101
+ expect resp.http.x-backend-protocol == "1.1"
+} -run
+
+client c1.2 -connect ${hap_lih2_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket" \
+ -hdr "sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ=="
+ rxresp
+ expect resp.status == 101
+ expect resp.http.x-backend-protocol == "2.0"
+} -run
+
+client c1.3 -connect ${hap_liauto_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket" \
+ -hdr "sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ=="
+ rxresp
+ expect resp.status == 101
+ expect resp.http.x-backend-protocol == "1.1"
+} -run
+
+client c1.4 -connect ${hap_liauto2_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket" \
+ -hdr "sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ=="
+ rxresp
+ expect resp.status == 101
+ expect resp.http.x-backend-protocol == "2.0"
+} -run
+
+client c2 -connect ${hap_lisslauto_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket" \
+ -hdr "sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ=="
+ rxresp
+ expect resp.status == 101
+ expect resp.http.x-alpn == "http/1.1"
+} -run
+
+client c2.2 -connect ${hap_lisslauto2_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket" \
+ -hdr "sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ=="
+ rxresp
+ expect resp.status == 101
+ expect resp.http.x-alpn == "h2"
+} -run
+
+client c2.3 -connect ${hap_lisslh2_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket" \
+ -hdr "sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ=="
+ rxresp
+ expect resp.status == 101
+ expect resp.http.x-alpn == "h2"
+} -run
diff --git a/reg-tests/http-messaging/truncated.vtc b/reg-tests/http-messaging/truncated.vtc
new file mode 100644
index 0000000..7579f6d
--- /dev/null
+++ b/reg-tests/http-messaging/truncated.vtc
@@ -0,0 +1,101 @@
+varnishtest "HTTP response size tests: H2->H1 (HTX and legacy mode)"
+#REQUIRE_VERSION=1.9
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp \
+ -status 200 \
+ -nolen \
+ -hdr "Transfer-encoding: chunked"
+ # -bodylen 16300
+ #chunkedlen 16300
+ #delay 0.05
+ chunkedlen 815
+ #delay 0.05
+ chunkedlen 815
+ delay 0.05
+ chunkedlen 815
+ #delay 0.05
+ chunkedlen 815
+ delay 0.05
+
+ chunkedlen 815
+ #delay 0.05
+ chunkedlen 815
+ delay 0.05
+ chunkedlen 815
+ #delay 0.05
+ chunkedlen 815
+ delay 0.05
+
+ chunkedlen 815
+ #delay 0.05
+ chunkedlen 815
+ delay 0.05
+ chunkedlen 815
+ #delay 0.05
+ chunkedlen 815
+ delay 0.05
+
+ chunkedlen 815
+ #delay 0.05
+ chunkedlen 815
+ delay 0.05
+ chunkedlen 815
+ #delay 0.05
+ chunkedlen 815
+ delay 0.05
+
+ chunkedlen 815
+ #delay 0.05
+ chunkedlen 815
+ delay 0.05
+ chunkedlen 815
+ #delay 0.05
+ chunkedlen 815
+ delay 0.05
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ defaults
+ #log stdout format raw daemon
+ mode http
+ option http-buffer-request
+ timeout connect 1s
+ timeout client 1s
+ timeout server 1s
+
+ listen feh1
+ bind "fd@${feh1}"
+ bind "fd@${feh2}" proto h2
+ http-response add-header a b
+ #http-response del-header content-length
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1h2 -connect ${h1_feh2_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ # first request is valid
+ stream 1 {
+ txreq \
+ -req "GET" \
+ -scheme "https" \
+ -url "/test1.html"
+ rxhdrs
+ #delay 0.1
+ expect resp.status == 200
+ rxdata -all
+ expect resp.bodylen == 16300
+ #expect resp.chunkedlen == 16300
+ } -run
+} -repeat 2 -run
diff --git a/reg-tests/http-messaging/websocket.vtc b/reg-tests/http-messaging/websocket.vtc
new file mode 100644
index 0000000..aed55fe
--- /dev/null
+++ b/reg-tests/http-messaging/websocket.vtc
@@ -0,0 +1,211 @@
+# This reg-test is uses to test respect of the websocket protocol according to
+# rfc6455.
+#
+# In particular, a request/response without a websocket key must be rejected by
+# haproxy. Note that in the tested case (h1 on both sides), haproxy does not
+# validate the key of the server but only checks its presence.
+#
+# For the case h2 client/h1 server, haproxy would add the key and validates it.
+# However, there is no way to check this case quickly at the moment using vtest.
+
+varnishtest "WebSocket test"
+
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+
+# valid websocket server
+server s1 {
+ rxreq
+ expect req.method == "GET"
+ expect req.http.connection == "upgrade"
+ expect req.http.upgrade == "websocket"
+ expect req.http.sec-websocket-key == "dGhlIHNhbXBsZSBub25jZQ=="
+
+ txresp \
+ -status 101 \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket" \
+ -hdr "sec-websocket-accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
+
+ recv 4
+ send "PONG"
+} -start
+
+# non-conformant server: no websocket key
+server s2 {
+ rxreq
+ expect req.method == "GET"
+ expect req.http.connection == "upgrade"
+ expect req.http.upgrade == "websocket"
+
+ txresp \
+ -status 101 \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket"
+} -start
+
+# haproxy instance used as a server
+# generate a http/1.1 websocket response with the valid key
+haproxy hap_srv -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen fe1
+ bind "fd@${fe1}"
+
+ # reject if the request does not contains a websocket key
+ acl ws_handshake hdr(sec-websocket-key) -m found
+ http-request reject unless ws_handshake
+
+ # return a valid websocket handshake response
+ capture request header sec-websocket-key len 128
+ http-request return status 200 hdr connection upgrade hdr upgrade websocket hdr sec-websocket-accept "%[capture.req.hdr(0),concat(258EAFA5-E914-47DA-95CA-C5AB0DC85B11,,),sha1,base64]"
+ http-after-response set-status 101 if { status eq 200 }
+} -start
+
+# haproxy instance used as a server
+# generate a http/1.1 websocket response with an invalid key
+haproxy hap_srv_bad_key -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen fe1
+ bind "fd@${fe1}"
+
+ # reject if the request does not contains a websocket key
+ acl ws_handshake hdr(sec-websocket-key) -m found
+ http-request reject unless ws_handshake
+
+ # return an invalid websocket handshake response
+ capture request header sec-websocket-key len 128
+ http-request return status 200 hdr connection upgrade hdr upgrade websocket hdr sec-websocket-accept "invalid_key"
+ http-after-response set-status 101 if { status eq 200 }
+} -start
+
+haproxy hap -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen fe1
+ bind "fd@${fe1}"
+ server s1 ${s1_addr}:${s1_port}
+
+ listen fe2
+ bind "fd@${fe2}"
+ server s2 ${s2_addr}:${s2_port}
+
+ listen fe3
+ bind "fd@${fe3}" proto h2
+ server hap_srv ${hap_srv_fe1_addr}:${hap_srv_fe1_port}
+
+ listen fe4
+ bind "fd@${fe4}" proto h2
+ server hap_srv_bad_key ${hap_srv_bad_key_fe1_addr}:${hap_srv_bad_key_fe1_port}
+} -start
+
+# standard request
+client c1 -connect ${hap_fe1_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket" \
+ -hdr "sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ=="
+ rxresp
+ expect resp.status == 101
+ expect resp.http.connection == "upgrade"
+ expect resp.http.upgrade == "websocket"
+ expect resp.http.sec-websocket-accept == "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
+
+ send "PING"
+ recv 4
+} -run
+
+# missing websocket key
+client c2 -connect ${hap_fe1_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket"
+
+ rxresp
+ expect resp.status == 400
+} -run
+
+# missing key on server side
+client c3 -connect ${hap_fe2_sock} {
+ txreq \
+ -req "GET" \
+ -url "/" \
+ -hdr "host: 127.0.0.1" \
+ -hdr "connection: upgrade" \
+ -hdr "upgrade: websocket" \
+ -hdr "sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ=="
+
+ rxresp
+ expect resp.status == 502
+} -run
+
+# connect with http/2 on a http/1.1 websocket server
+# the key must be provided by haproxy
+client c4 -connect ${hap_fe3_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -req "CONNECT" \
+ -scheme "http" \
+ -url "/" \
+ -hdr ":authority" "127.0.0.1" \
+ -hdr ":protocol" "websocket"
+
+ rxhdrs
+ expect resp.status == 200
+ } -run
+} -run
+
+# connect with http/2 on a http/1.1 websocket server
+# however, the server will respond with an invalid key
+# haproxy is responsible to reject the request and returning a 502 to the client
+client c5 -connect ${hap_fe4_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+
+ stream 1 {
+ txreq \
+ -req "CONNECT" \
+ -scheme "http" \
+ -url "/" \
+ -hdr ":authority" "127.0.0.1" \
+ -hdr ":protocol" "websocket"
+
+ rxhdrs
+ expect resp.status == 502
+ } -run
+} -run
diff --git a/reg-tests/http-rules/1k.txt b/reg-tests/http-rules/1k.txt
new file mode 100644
index 0000000..bbdd7e7
--- /dev/null
+++ b/reg-tests/http-rules/1k.txt
@@ -0,0 +1,16 @@
+s313l7hzIJ5FIXCmpr+zAyFK80lNfjOIRNZSXJJn/GQVNQsBqDl3AFcb7JQt1ler
+KgBNE1LAiU02vTj4+hlW2qi4Xg1T3lshEOSSxJQN/ITQG/1KVmDiTtsjjSv8iWUj
+T403xvLKQd0FB2h00N9pwd9ApbGPYF8uG1kjnNQmzJOqQ2Pz7jUkNpF+sAAQHaRD
+ocjEucTsb676w8l9EqWNE+DK5IqoO2AK47bHbr4u38ZOwXjQWGw9MiUJZmVQEqdC
+QZlmpFuSKQiig1SZFZlmKVidf1genz6q+4BT80IFU2UE+pWiay/HcZttwM++eG7w
+n/Va7yd3D+ryK2j4rw0sOYM7Cu7AwleZeGEaCZINZmnVAWtg2OVFOTxx6jz8wNuY
+VJPb3VFD72WnnBhtbik5mEqjzVJy530sQBlGlcxi3Tivq69ZnAk55RBN0LO+jWf4
+DI4189LTIfY5WroA8AQeCCQYnzyXo5O/vDmic+uwKALlQ6TXzSuCNpHO8fL1UwHH
+7KBqxHi+/yYJ0431V/LAvRBpVFPYJ8iED7Md67GRVQWy8o+tgC1PmycJtS5ADQGO
+Jys46KjhL9cnaS3aP1YcuuGuSUOVMA7BjqPcz7r+hqYTCZ3akaY4w7AGRCZyRf8e
+finlAkgFpzKSFwaa2M6H3vUE14WzHC0hJ/bO2epjlcOeoMcgBVn5uUMYMVroAK0+
+vI9jg1RDV17oHberVmWj8VAXolDNS0pW2rt+JbqHsAVDDk/Ex3NJWFSYByHFyglQ
+cjYMwrzIsWC09ykW6WhUN6IsopLlDk7O2jcKaHxZ6WaFiVxIGFkepfNhf4wYZ6O9
+tjwMuOqTQtSjdP3MbbVEM6VpAkJW/Si1jmSW02ObMcdEpxJHTB9fC30waMM7e+T4
+FT/AlwB49un/3yYU2iUndW+wenoED9UkdbZ7uvjyu+UgQ3bMaQhX9Z9eHxhfi6Gy
+aRM2IJVeEpk5w0ifAQxrL4Wp+dFbzfGN1yPkI2UAo6WbWi63D \ No newline at end of file
diff --git a/reg-tests/http-rules/acl_cli_spaces.vtc b/reg-tests/http-rules/acl_cli_spaces.vtc
new file mode 100644
index 0000000..a554977
--- /dev/null
+++ b/reg-tests/http-rules/acl_cli_spaces.vtc
@@ -0,0 +1,77 @@
+varnishtest "haproxy ACL, CLI and mCLI spaces"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.method == "GET"
+ txresp
+} -repeat 2 -start
+
+haproxy h1 -W -S -conf {
+ defaults
+ mode http
+ log global
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+
+ http-request deny if { req.hdr(user-agent) -i -m str -f ${testdir}/agents.acl }
+
+ default_backend be1
+
+ backend be1
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -hdr "User-Agent: Mon User Agent"
+ rxresp
+ expect resp.status == 200
+} -run
+
+haproxy h1 -cli {
+ send "add acl ${testdir}/agents.acl Mon\\ User\\ Agent\\;"
+ expect ~ .*
+
+ send "show acl ${testdir}/agents.acl"
+ expect ~ ".*Mon User Agent.*"
+}
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -hdr "User-Agent: Mon User Agent;"
+ rxresp
+ expect resp.status == 403
+} -run
+
+
+haproxy h1 -cli {
+ send "del acl ${testdir}/agents.acl Mon\\ User\\ Agent\\;"
+ expect ~ .*
+
+ send "show acl ${testdir}/agents.acl"
+ expect ~ .*
+}
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -hdr "User-Agent: Mon User Agent;"
+ rxresp
+ expect resp.status == 200
+} -run
+
+
+# Try it with the master CLI
+haproxy h1 -mcli {
+ send "@1 add acl ${testdir}/agents.acl Mon\\ User\\ Agent\\;;@1 show acl ${testdir}/agents.acl"
+ expect ~ ".*Mon User Agent;.*"
+}
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -hdr "User-Agent: Mon User Agent;"
+ rxresp
+ expect resp.status == 403
+} -run
diff --git a/reg-tests/http-rules/agents.acl b/reg-tests/http-rules/agents.acl
new file mode 100644
index 0000000..345e6ae
--- /dev/null
+++ b/reg-tests/http-rules/agents.acl
@@ -0,0 +1 @@
+Test
diff --git a/reg-tests/http-rules/converters_ipmask_concat_strcmp_field_word.map b/reg-tests/http-rules/converters_ipmask_concat_strcmp_field_word.map
new file mode 100644
index 0000000..9a3e8e6
--- /dev/null
+++ b/reg-tests/http-rules/converters_ipmask_concat_strcmp_field_word.map
@@ -0,0 +1 @@
+^(.+)_(.+)$ \2_\1
diff --git a/reg-tests/http-rules/converters_ipmask_concat_strcmp_field_word.vtc b/reg-tests/http-rules/converters_ipmask_concat_strcmp_field_word.vtc
new file mode 100644
index 0000000..55bcb5f
--- /dev/null
+++ b/reg-tests/http-rules/converters_ipmask_concat_strcmp_field_word.vtc
@@ -0,0 +1,231 @@
+varnishtest "Minimal tests for 1.9 converters: ipmask,concat,strcmp,field,word"
+feature ignore_unknown_macro
+
+# ipmask,hdr_ip tests server
+server s1 {
+ rxreq
+ expect req.method == "GET"
+ expect req.http.srciphdr == "192.168.1.101"
+ expect req.http.srcmask1 == "192.168.1.0"
+ expect req.http.srcmask2 == "192.168.0.0"
+ expect req.http.srcmask3 == "192.0.0.0"
+
+ expect req.http.test1mask128 ~ "2001:db8:[0:]*:1"
+ expect req.http.test2mask64 ~ "2001:db8:[0:]+"
+ expect req.http.test2mask128 ~ "2001:db8:[0:]*:bad:c0f:ffff"
+ expect req.http.test2mask120 ~ "2001:db8:[0:]*:bad:c0f:ff00"
+ expect req.http.test2maskff00 ~ "2001:db8:[0:]*:bad:c0f:ff00"
+ expect req.http.test2maskfee0 ~ "2001:db8:[0:]*:bad:c0f:fee0"
+
+ expect req.http.test3mask64 ~ "2001:db8:c001:c01a:[0:]+"
+ expect req.http.test3mask64v2 ~ "2001:db8:c001:c01a:[0:]+"
+ expect req.http.test3mask64v3 ~ "2001:db8:c001:c01a:[0:]+"
+ expect req.http.test3maskff ~ "2001:db8:c001:c01a:[0:]*:ffff:10:[0:]+"
+ expect req.http.test3maskv2 ~ "2001:db8:c001:c01a:c001:c001:[0:]+"
+
+ expect req.http.test4mask32 == "192.168.1.101"
+
+ expect req.http.test5mask24 == "192.168.1.0"
+ expect req.http.test6mask24 == "192.168.1.0"
+ expect req.http.test6mask25 == "192.168.1.128"
+
+ expect req.http.ipv4plain == "192.168.2.1"
+ expect req.http.ipv4port == "192.168.2.1"
+ expect req.http.ipv6plain == "2001:db8:c001:c01a:ffff:ffff:20:ffff"
+ expect req.http.ipv6brackets == "2001:db8:c001:c01a:ffff:ffff:20:ffff"
+
+ txresp
+} -start
+
+# concat,strcmp,field,word tests server
+server s2 {
+ rxreq
+ expect req.method == "GET"
+ expect req.http.fieldconcat == "f1_f2_f3__f5"
+ expect req.http.fieldconcat2 == "f1_f2_f3__f5"
+ expect req.http.fieldconcat3 == "f1_f2_f3__f5"
+ expect req.http.fieldstrcmp == "0"
+
+ # field tests
+ expect req.http.fieldtest1 == "f5"
+ expect req.http.fieldtest2 == "f2_f3__f5"
+ expect req.http.fieldtest3 == "f2_f3"
+ expect req.http.fieldtest4 == "f2_f3_"
+ expect req.http.fieldtest5 == "f1_f2_f3"
+ expect req.http.okfieldtest == "ok"
+ expect req.http.qsfieldtest == "IT_IS"
+ expect req.http.qsfieldconcat == "IT_IS_ok"
+ expect req.http.fieldtest1strcmp == "0"
+
+ # word tests
+ expect req.http.wordtest1 == "f5"
+ expect req.http.wordtest2 == "f2_f3__f5"
+ expect req.http.wordtest3 == "f3__f5"
+ expect req.http.wordtest4 == "f1_f2_f3"
+ expect req.http.wordtest5 == "f1_f2"
+ expect req.http.okwordtest == "OK"
+ expect req.http.qswordtest == "Yes_It"
+ expect req.http.qswordregmtest == "It_Yes"
+ expect req.http.wordtest1strcmp == "0"
+ txresp
+} -start
+
+
+# ipmask,hdr_ip tests with accept-proxy bind
+haproxy h1 -conf {
+ defaults
+ mode http
+ log global
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ # accept-proxy so test client can send src ip
+ bind "fd@${fe1}" accept-proxy
+
+ # ipmask tests w/src
+ http-request set-header Srciphdr %[src]
+ http-request set-header Srcmask1 %[src,ipmask(24)] # 192.168.1.0
+ http-request set-header Srcmask2 %[src,ipmask(16)] # 192.168.0.0
+ http-request set-header Srcmask3 %[src,ipmask(8)] # 192.0.0.0
+
+ # ipmask tests from headers
+ http-request set-header Test1mask128 %[req.hdr_ip(Addr1),ipmask(24,128)]
+
+ http-request set-header Test2mask64 %[req.hdr_ip(Addr2),ipmask(24,64)]
+ http-request set-header Test2mask128 %[req.hdr_ip(Addr2),ipmask(24,128)]
+ http-request set-header Test2mask120 %[req.hdr_ip(Addr2),ipmask(24,120)]
+ http-request set-header Test2maskff00 %[req.hdr_ip(Addr2),ipmask(24,ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00)]
+ http-request set-header Test2maskfee0 %[req.hdr_ip(Addr2),ipmask(24,ffff:ffff:ffff:ffff:ffff:ffff:ffff:fee0)]
+
+ http-request set-header Test3mask64 %[req.hdr_ip(Addr3),ipmask(24,64)]
+ http-request set-header Test3mask64v2 %[req.hdr_ip(Addr3),ipmask(24,ffff:ffff:ffff:ffff:0:0:0:0)]
+ http-request set-header Test3mask64v3 %[req.hdr_ip(Addr3),ipmask(24,ffff:ffff:ffff:ffff::)]
+ http-request set-header Test3maskff %[req.hdr_ip(Addr3),ipmask(24,ffff:ffff:ffff:ffff:0:ffff:ffff:0)]
+ http-request set-header Test3maskv2 %[req.hdr_ip(Addr3),ipmask(24,ffff:ffff:ffff:ffff:c001:c001:0000:0000)]
+
+ # ipv4 mask applied to ipv4 mapped address
+ http-request set-header Test4mask32 %[req.hdr_ip(Addr4),ipmask(32,64)]
+
+ http-request set-header Test5mask24 %[req.hdr_ip(Addr5),ipmask(24)]
+
+ http-request set-header Test6mask24 %[req.hdr_ip(Addr6),ipmask(24)]
+ http-request set-header Test6mask25 %[req.hdr_ip(Addr6),ipmask(25)]
+
+ # track addr/mask in stick table
+ http-request track-sc0 src,ipmask(24) table be1
+ http-request track-sc1 hdr_ip(Addr4),ipmask(32) table be1
+ http-request track-sc2 hdr_ip(Addr3),ipmask(24,64) table be1
+
+ # hdr_ip tests
+ http-request set-header IPv4plain %[req.hdr_ip(AddrIPv4plain)]
+ http-request set-header IPv4port %[req.hdr_ip(AddrIPv4port)]
+ http-request set-header IPv6plain %[req.hdr_ip(AddrIPv6plain)]
+ http-request set-header IPv6brackets %[req.hdr_ip(AddrIPv6brackets)]
+
+ default_backend be1
+
+ backend be1
+ stick-table type ipv6 size 20 expire 360s store gpc0,conn_cnt
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+# concat,strcmp,word,field haproxy
+haproxy h2 -conf {
+ defaults
+ mode http
+ log global
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe2
+ bind "fd@${fe2}"
+
+ # concat f1_f2 + _ + f3__f5 tests
+ http-request set-var(sess.field1) hdr(Field1)
+ http-request set-var(sess.field2) hdr(Field2)
+ http-request set-var(sess.fieldhdr) hdr(Fieldhdr)
+ http-request set-var(sess.fieldconcat) hdr(Field1),concat(_,sess.field2,)
+ http-request set-header Fieldconcat2 %[var(sess.field1),concat(_,sess.field2,)]
+ http-request set-header Fieldconcat3 %[hdr(Field1),concat(_,sess.field2,)]
+ http-request set-header Fieldconcat %[var(sess.fieldconcat)]
+ http-request set-header Fieldstrcmp %[hdr(Fieldhdr),strcmp(sess.fieldconcat)]
+ http-request deny unless { hdr(Fieldhdr),strcmp(sess.fieldconcat) eq 0 }
+
+ # field tests
+ http-request set-header Fieldtest1 %[hdr(Fieldhdr),field(5,_)] #f5
+ http-request set-var(sess.fieldtest1var) hdr(Fieldtest1)
+ http-request set-var(sess.okfield) path,lower,field(4,/,1) #ok
+ http-request set-header Okfieldtest %[var(sess.okfield)] #ok
+ http-request set-var(sess.qsfield) url_param(qs),upper,field(2,_,2) #IT_IS
+ http-request set-header Qsfieldtest %[var(sess.qsfield)] #IT_IS
+ http-request set-header Qsfieldconcat %[var(sess.qsfield),concat(_,sess.okfield,)] #IT_IS_ok
+ http-request set-header Fieldtest2 %[var(sess.fieldhdr),field(2,_,0)] #f2_f3__f5
+ http-request set-header Fieldtest3 %[var(sess.fieldconcat),field(2,_,2)] #f2_f3
+ http-request set-header Fieldtest4 %[hdr(Fieldconcat2),field(-2,_,3)] #f2_f3_
+ http-request set-header Fieldtest5 %[hdr(Fieldconcat3),field(-3,_,0)] #f1_f2_f3
+ http-request set-header Fieldtest1strcmp %[str(f5),strcmp(sess.fieldtest1var)]
+ http-request deny unless { str(f5),strcmp(sess.fieldtest1var) eq 0 }
+ http-request deny unless { str(ok),strcmp(sess.okfield) eq 0 }
+ http-request deny unless { str(IT_IS),strcmp(sess.qsfield) eq 0 }
+
+ # word tests
+ http-request set-header Wordtest1 %[hdr(Fieldhdr),word(4,_)] #f5
+ http-request set-var(sess.wordtest1var) hdr(Wordtest1)
+ http-request set-var(sess.okword) path,upper,word(3,/,1) #OK
+ http-request set-header Okwordtest %[var(sess.okword)] #OK
+ http-request set-var(sess.qsword) url_param(qs),word(1,_,2) #Yes_It
+ http-request set-header Qswordtest %[var(sess.qsword)] #Yes_It
+ http-request set-header Qswordregmtest %[var(sess.qsword),map_regm(${testdir}/converters_ipmask_concat_strcmp_field_word.map)] #It_Yes
+ http-request set-header Wordtest2 %[var(sess.fieldhdr),word(2,_,0)] #f2_f3__f5
+ http-request set-header Wordtest3 %[var(sess.fieldconcat),word(3,_,2)] #f3__f5
+ http-request set-header Wordtest4 %[hdr(Fieldconcat2),word(-2,_,3)] #f1_f2_f3
+ http-request set-header Wordtest5 %[hdr(Fieldconcat3),word(-3,_,0)] #f1_f2
+ http-request set-header Wordtest1strcmp %[str(f5),strcmp(sess.wordtest1var)]
+ http-request deny unless { str(f5),strcmp(sess.wordtest1var) eq 0 }
+ http-request deny unless { str(OK),strcmp(sess.okword) eq 0 }
+ http-request deny unless { str(Yes_It),strcmp(sess.qsword) eq 0 }
+
+ default_backend be2
+
+ backend be2
+ server s2 ${s2_addr}:${s2_port}
+} -start
+
+# ipmask,hdr_ip tests
+client c1 -connect ${h1_fe1_sock} -proxy2 "192.168.1.101:1234 127.0.0.1:2345" {
+ txreq -hdr "Addr1: 2001:db8::1" \
+ -hdr "Addr2: 2001:db8::bad:c0f:ffff" \
+ -hdr "Addr3: 2001:db8:c001:c01a:ffff:ffff:10:ffff" \
+ -hdr "Addr4: ::FFFF:192.168.1.101" \
+ -hdr "Addr5: 192.168.1.2" \
+ -hdr "Addr6: 192.168.1.255" \
+ -hdr "AddrIPv4plain: 192.168.2.1" \
+ -hdr "AddrIPv4port: 192.168.2.1:6789" \
+ -hdr "AddrIPv6plain: 2001:db8:c001:c01a:ffff:ffff:20:ffff" \
+ -hdr "AddrIPv6brackets: [2001:db8:c001:c01a:ffff:ffff:20:ffff]"
+ rxresp
+ expect resp.status == 200
+} -run
+
+# cli show be1 stick table
+haproxy h1 -cli {
+ send "show table be1"
+ expect ~ "^# table: be1, type: ipv6, size:20, used:3\\n0x[a-f0-9]+: key=::ffff:192\\.168\\.1\\.0 use=0 exp=[[:digit:]]+ shard=0 gpc0=0 conn_cnt=1\\n0x[a-f0-9]+: key=::ffff:192\\.168\\.1\\.101 use=0 exp=[[:digit:]]+ shard=0 gpc0=0 conn_cnt=1\\n0x[a-f0-9]+: key=2001:db8:c001:c01a:[0:]+ use=0 exp=[[:digit:]]+ shard=0 gpc0=0 conn_cnt=1\\n"
+}
+
+# concat,strcmp,word,field tests
+client c2 -connect ${h2_fe2_sock} {
+ txreq -req GET \
+ -url /is/this/Ok/or/not?qs=Yes_It_Is \
+ -hdr "Fieldhdr: f1_f2_f3__f5" \
+ -hdr "Field1: f1_f2" \
+ -hdr "Field2: f3__f5"
+ rxresp
+ expect resp.status == 200
+} -run
+
diff --git a/reg-tests/http-rules/default_rules.vtc b/reg-tests/http-rules/default_rules.vtc
new file mode 100644
index 0000000..cc726ab
--- /dev/null
+++ b/reg-tests/http-rules/default_rules.vtc
@@ -0,0 +1,159 @@
+varnishtest "Test declaration of HTTP rules in default sections"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.http.x-frontend == "fe"
+ expect req.http.x-backend == "be"
+ expect req.http.x-test1-frt == "def_front"
+ expect req.http.x-test1-bck == "def_back"
+ txresp
+} -start
+
+server s2 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults common
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ defaults def_front from common
+ http-request set-header x-frontend "%[fe_name]"
+ http-request set-var(txn.test1) "str(def_front)"
+ http-response set-header x-frontend "%[fe_name]"
+ http-response set-var(txn.test2) "str(def_front)"
+ http-after-response set-var(txn.test3) "str(def_front)"
+
+ defaults def_back from common
+ http-request set-header x-backend "%[be_name]"
+ http-request set-var(txn.test1) "str(def_back)"
+ http-response set-header x-backend "%[be_name]"
+ http-response set-var(txn.test2) "str(def_back)"
+ http-after-response set-var(txn.test3) "str(def_back)"
+
+ frontend fe from def_front
+ bind "fd@${feh1}"
+
+ http-request set-header x-test1-frt "%[var(txn.test1)]"
+ http-response set-header x-test2-frt "%[var(txn.test2)]"
+ http-after-response set-header x-test3-frt "%[var(txn.test3)]"
+
+ default_backend be
+
+ backend be from def_back
+ http-request set-header x-test1-bck "%[var(txn.test1)]"
+ http-response set-header x-test2-bck "%[var(txn.test2)]"
+ http-after-response set-header x-test3-bck "%[var(txn.test3)]"
+
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+
+haproxy h2 -conf {
+ defaults common
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ defaults def_front from common
+ http-request allow
+ http-response allow
+ http-after-response allow
+
+ defaults def_back from common
+ http-request allow
+ http-response allow
+ http-after-response allow
+
+ frontend fe from def_front
+ bind "fd@${feh2}"
+
+ http-request deny status 403
+ http-response deny status 502
+ http-after-response set-status 502
+
+ default_backend be
+
+ backend be from def_back
+ http-request deny status 403
+ http-response deny status 502
+ http-after-response set-status 502
+
+ server s2 ${s2_addr}:${s2_port}
+
+} -start
+
+haproxy h3 -conf {
+ defaults base-http
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ http-request capture hdr(Host) len 64 # idx 0
+ http-request capture hdr(X-req-1) len 32 # idx 1
+
+ frontend fe1 from base-http
+ bind "fd@${fe1h3}"
+ declare capture request len 32 # idx 2
+
+ http-request capture hdr(X-req-2) id 2
+ http-request return status 200 hdr "X-Capture-1" "%[capture.req.hdr(0)]" hdr "X-Capture-2" "%[capture.req.hdr(1)]" hdr "X-Capture-3" "%[capture.req.hdr(2)]"
+
+ frontend fe2 from base-http
+ bind "fd@${fe2h3}"
+ http-request capture hdr(X-req-2) id 1
+ http-request return status 200 hdr "X-Capture-1" "%[capture.req.hdr(0)]" hdr "X-Capture-2" "%[capture.req.hdr(1)]"
+
+} -start
+
+client c1 -connect ${h1_feh1_sock} {
+ txreq -req GET -url /
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-frontend == "fe"
+ expect resp.http.x-backend == "be"
+ expect resp.http.x-test2-bck == "def_back"
+ expect resp.http.x-test2-frt == "def_front"
+ expect resp.http.x-test3-bck == "def_back"
+ expect resp.http.x-test3-frt == "def_front"
+} -run
+
+client c2 -connect ${h2_feh2_sock} {
+ txreq -req GET -url /
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c3 -connect ${h3_fe1h3_sock} {
+ txreq -req GET -url / \
+ -hdr "host: v-test" \
+ -hdr "x-req-1: val1" \
+ -hdr "x-req-2: val2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-capture-1 == "v-test"
+ expect resp.http.x-capture-2 == "val1"
+ expect resp.http.x-capture-3 == "val2"
+} -run
+
+client c4 -connect ${h3_fe2h3_sock} {
+ txreq -req GET -url / \
+ -hdr "host: v-test" \
+ -hdr "x-req-1: val1" \
+ -hdr "x-req-2: val2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-capture-1 == "v-test"
+ expect resp.http.x-capture-2 == "val2"
+ expect resp.http.x-capture-3 == "<undef>"
+} -run
diff --git a/reg-tests/http-rules/del_header.vtc b/reg-tests/http-rules/del_header.vtc
new file mode 100644
index 0000000..0f74a60
--- /dev/null
+++ b/reg-tests/http-rules/del_header.vtc
@@ -0,0 +1,93 @@
+varnishtest "del-header tests"
+
+# This config tests various http-request/response del-header operations
+# with or without specified header name matching method.
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.url == /
+ expect req.http.x-always == always
+ expect req.http.x-str1 == <undef>
+ expect req.http.x-str2 == <undef>
+ expect req.http.x-beg1 == <undef>
+ expect req.http.x-beg2 == <undef>
+ expect req.http.x-end1 == <undef>
+ expect req.http.x-end2 == end2
+ expect req.http.x-sub1 == <undef>
+ expect req.http.x-sub2 == <undef>
+ expect req.http.x-reg1 == <undef>
+ expect req.http.x-reg2 == <undef>
+ txresp -hdr "x-always: always" \
+ -hdr "x-str1: str1" \
+ -hdr "x-str2: str2" \
+ -hdr "x-beg1: beg1" \
+ -hdr "x-beg2: beg2" \
+ -hdr "x-end1: end1" \
+ -hdr "x-end2: end2" \
+ -hdr "x-sub1: sub1" \
+ -hdr "x-sub2: sub2" \
+ -hdr "x-reg1: reg1" \
+ -hdr "x-reg2: reg2"
+
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ http-request del-header x-str1
+ http-request del-header x-str2 -m str
+ http-request del-header x-beg -m beg
+ http-request del-header end1 -m end
+ http-request del-header sub -m sub
+ http-request del-header ^x.reg.$ -m reg
+
+ http-response del-header x-str1
+ http-response del-header x-str2 -m str
+ http-response del-header x-beg -m beg
+ http-response del-header end1 -m end
+ http-response del-header sub -m sub
+ http-response del-header ^x.reg.$ -m reg
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -req GET -url / \
+ -hdr "x-always: always" \
+ -hdr "x-str1: str1" \
+ -hdr "x-str2: str2" \
+ -hdr "x-beg1: beg1" \
+ -hdr "x-beg2: beg2" \
+ -hdr "x-end1: end1" \
+ -hdr "x-end2: end2" \
+ -hdr "x-sub1: sub1" \
+ -hdr "x-sub2: sub2" \
+ -hdr "x-reg1: reg1" \
+ -hdr "x-reg2: reg2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-always == always
+ expect resp.http.x-str1 == <undef>
+ expect resp.http.x-str2 == <undef>
+ expect resp.http.x-beg1 == <undef>
+ expect resp.http.x-beg2 == <undef>
+ expect resp.http.x-end1 == <undef>
+ expect resp.http.x-end2 == end2
+ expect resp.http.x-sub1 == <undef>
+ expect resp.http.x-sub2 == <undef>
+ expect resp.http.x-reg1 == <undef>
+ expect resp.http.x-reg2 == <undef>
+} -run
diff --git a/reg-tests/http-rules/except-forwardfor-originalto.vtc b/reg-tests/http-rules/except-forwardfor-originalto.vtc
new file mode 100644
index 0000000..a859160
--- /dev/null
+++ b/reg-tests/http-rules/except-forwardfor-originalto.vtc
@@ -0,0 +1,143 @@
+varnishtest "Test IPv4/IPv6 except param for the forwardfor and originalto options"
+#REQUIRE_VERSION=2.4
+
+# This config tests the except parameter for the HTTP forwardfor and originalto
+# options.
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ http-request set-src hdr(x-src)
+ http-request set-dst hdr(x-dst)
+ use_backend be1 if { path /req1 }
+ use_backend be2 if { path /req2 }
+ use_backend be3 if { path /req3 }
+ use_backend be4 if { path /req4 }
+ use_backend be5 if { path /req5 }
+
+ frontend fe2
+ bind "fd@${fe2}"
+ http-request return status 200 hdr x-ff "%[req.hdr(x-forwarded-for)]" hdr x-ot "%[req.hdr(x-original-to)]"
+
+ backend be1
+ option forwardfor except 127.0.0.1
+ option originalto except 127.0.0.1
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+ backend be2
+ option forwardfor except 10.0.0.1/25
+ option originalto except 10.0.0.1/25
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+ backend be3
+ option forwardfor except ::1
+ option originalto except ::1
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+ backend be4
+ option forwardfor except 2001:db8::1:0:0:1
+ option originalto except 2001:db8::1:0:0:1
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+ backend be5
+ option forwardfor except 2001:db8:1f89::/48
+ option originalto except 2001:db8:1f89::/48
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /req1 \
+ -hdr "x-src: 127.0.0.1" \
+ -hdr "x-dst: 127.0.0.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == <undef>
+ expect resp.http.x-ot == <undef>
+
+ txreq -req GET -url /req1 \
+ -hdr "x-src: 127.0.0.2" \
+ -hdr "x-dst: 127.0.0.2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == "127.0.0.2"
+ expect resp.http.x-ot == "127.0.0.2"
+
+
+ txreq -req GET -url /req2 \
+ -hdr "x-src: 10.0.0.1" \
+ -hdr "x-dst: 10.0.0.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == <undef>
+ expect resp.http.x-ot == <undef>
+
+ txreq -req GET -url /req2 \
+ -hdr "x-src: 10.0.0.128" \
+ -hdr "x-dst: 10.0.0.128"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == "10.0.0.128"
+ expect resp.http.x-ot == "10.0.0.128"
+
+ txreq -req GET -url /req3 \
+ -hdr "x-src: ::1" \
+ -hdr "x-dst: ::1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == <undef>
+ expect resp.http.x-ot == <undef>
+
+ txreq -req GET -url /req3 \
+ -hdr "x-src: ::2" \
+ -hdr "x-dst: ::2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == "::2"
+ expect resp.http.x-ot == "::2"
+
+ txreq -req GET -url /req4 \
+ -hdr "x-src: 2001:db8::1:0:0:1" \
+ -hdr "x-dst: 2001:db8::1:0:0:1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == <undef>
+ expect resp.http.x-ot == <undef>
+
+ txreq -req GET -url /req4 \
+ -hdr "x-src: 2001:db8::1:0:0:2" \
+ -hdr "x-dst: 2001:db8::1:0:0:2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == "2001:db8::1:0:0:2"
+ expect resp.http.x-ot == "2001:db8::1:0:0:2"
+
+ txreq -req GET -url /req5 \
+ -hdr "x-src: 2001:db8:1f89::1" \
+ -hdr "x-dst: 2001:db8:1f89::1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == <undef>
+ expect resp.http.x-ot == <undef>
+
+ txreq -req GET -url /req5 \
+ -hdr "x-src: 2001:db8:1f90::1" \
+ -hdr "x-dst: 2001:db8:1f90::1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == "2001:db8:1f90::1"
+ expect resp.http.x-ot == "2001:db8:1f90::1"
+} -run
diff --git a/reg-tests/http-rules/forwarded-header-7239.vtc b/reg-tests/http-rules/forwarded-header-7239.vtc
new file mode 100644
index 0000000..a894113
--- /dev/null
+++ b/reg-tests/http-rules/forwarded-header-7239.vtc
@@ -0,0 +1,171 @@
+varnishtest "Test RFC 7239 forwarded header support (forwarded option and related converters)"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.8-dev0)'"
+
+# This config tests the HTTP forwarded option and RFC7239 related converters.
+
+feature ignore_unknown_macro
+
+#test: converters, parsing and header injection logic
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ http-request set-src hdr(x-src)
+ http-request set-dst hdr(x-dst)
+ http-request set-header host %[str(vtest)]
+ use_backend be1 if { path /req1 }
+ use_backend be2 if { path /req2 }
+ use_backend be3 if { path /req3 }
+ use_backend be4 if { path /req4 }
+
+ frontend fe2
+ bind "fd@${fe2}"
+ http-request return status 200 hdr forwarded "%[req.hdr(forwarded)]"
+
+ backend be1
+ option forwarded
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+ backend be2
+ option forwarded for-expr src for_port-expr str(id) by by_port-expr int(10)
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+ backend be3
+ acl valid req.hdr(forwarded),rfc7239_is_valid
+ http-request return status 200 if valid
+ http-request return status 400
+
+ backend be4
+ http-request set-var(req.fnode) req.hdr(forwarded),rfc7239_field(for)
+ http-request return status 200 hdr nodename "%[var(req.fnode),rfc7239_n2nn]" hdr nodeport "%[var(req.fnode),rfc7239_n2np]"
+
+} -start
+
+#test: "default" and "no option forwarded"
+haproxy h2 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ option forwarded
+
+ frontend fe1
+ bind "fd@${fe1h2}"
+ use_backend default if { path /default }
+ use_backend override if { path /override }
+ use_backend disabled if { path /disabled }
+
+ backend default
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+ backend override
+ option forwarded host-expr str(override)
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+ backend disabled
+ no option forwarded
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /req1 \
+ -hdr "x-src: 127.0.0.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.forwarded == "proto=http;for=127.0.0.1"
+
+ txreq -req GET -url /req2 \
+ -hdr "x-src: 127.0.0.2" \
+ -hdr "x-dst: 127.0.0.3"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.forwarded == "by=\"127.0.0.3:10\";for=\"127.0.0.2:_id\""
+
+ txreq -req GET -url /req3 \
+ -hdr "forwarded: for=\"unknown:132\";host=\"[::1]:65535\";by=\"_obfs:_port\";proto=https"
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req3 \
+ -hdr "forwarded: for=\"127.0.0.1\";host=v.test"
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req3 \
+ -hdr "forwarded: fore=\"unknown:132\""
+ rxresp
+ expect resp.status == 400
+
+ txreq -req GET -url /req3 \
+ -hdr "forwarded: proto=http;proto=http"
+ rxresp
+ expect resp.status == 400
+
+ txreq -req GET -url /req3 \
+ -hdr "forwarded: \""
+ rxresp
+ expect resp.status == 400
+
+ txreq -req GET -url /req3 \
+ -hdr "forwarded: by=[::1]"
+ rxresp
+ expect resp.status == 400
+
+ txreq -req GET -url /req3 \
+ -hdr "forwarded: by=\"[::1]\""
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req3 \
+ -hdr "forwarded: by=\"[::1]:\""
+ rxresp
+ expect resp.status == 400
+
+ txreq -req GET -url /req3 \
+ -hdr "forwarded: by=\"[::1]:3\""
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req4 \
+ -hdr "forwarded: proto=http;for=\"[::1]:_id\""
+ rxresp
+ expect resp.status == 200
+ expect resp.http.nodename == "::1"
+ expect resp.http.nodeport == "_id"
+} -run
+
+client c2 -connect ${h2_fe1h2_sock} {
+ txreq -req GET -url /default
+ rxresp
+ expect resp.status == 200
+ expect resp.http.forwarded != <undef>
+
+ txreq -req GET -url /override
+ rxresp
+ expect resp.status == 200
+ expect resp.http.forwarded == "host=\"override\""
+
+ txreq -req GET -url /disabled
+ rxresp
+ expect resp.status == 200
+ expect resp.http.forwarded == <undef>
+} -run
diff --git a/reg-tests/http-rules/h1or2_to_h1c.vtc b/reg-tests/http-rules/h1or2_to_h1c.vtc
new file mode 100644
index 0000000..3dd907e
--- /dev/null
+++ b/reg-tests/http-rules/h1or2_to_h1c.vtc
@@ -0,0 +1,233 @@
+varnishtest "Composite HTTP manipulation test (H1 and H2 clear to H1 clear)"
+
+# This config tests several http-request features and their interactions.
+# It extracts some samples, places them into variables, modifies some header
+# fields, appends multiple identical header fields, overwrites the start line
+# using several methods, then dumps the initial list of variables and the final
+# one, then applies CRC32 to these values as signatures that are easy to test.
+# Then it does it again in the backend after saving the current headers into
+# the same names prefixed by "fe-". Then it does the same on the response path.
+# If some modifications are performed, the crc values need to be adjusted based
+# on the failed logs.
+#
+# Run it with HAPROXY_PROGRAM=$PWD/haproxy varnishtest -l -k -t 1 "$1"
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp \
+ -status 234 \
+ -hdr "hdr1: val1" \
+ -hdr "hdr2: val2a" \
+ -hdr "hdr2: val2b" \
+ -hdr "hdr3: val3a, val3b" \
+ -hdr "hdr4:" \
+ -body "This is a body"
+
+ expect req.method == "GET"
+ expect req.http.fe-sl1-crc == 1874847043
+ expect req.http.fe-sl2-crc == 1142278307
+ expect req.http.fe-hdr-crc == 1719311923
+ expect req.http.be-sl1-crc == 3455320059
+ expect req.http.be-sl2-crc == 2509326257
+ expect req.http.be-hdr-crc == 3634102538
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${feh1}"
+ bind "fd@${feh2}" proto h2
+
+ #### requests
+ http-request set-var(req.method) method
+ http-request set-var(req.uri) url
+ http-request set-var(req.path) path
+ http-request set-var(req.query) query
+ http-request set-var(req.param) url_param(qs_arg)
+ http-request set-var(req.cl) req.fhdr(content-length)
+
+ http-request set-header sl1 "sl1: "
+
+ http-request set-method "%[str(GET)]"
+ http-request set-uri %[str(),concat(/bu/,req.uri,/eu)]
+ http-request set-path "/bp/%[var(req.path)]/ep"
+ http-request set-query "bq&%[var(req.query)]&eq"
+
+ http-request set-header sl2 "sl2: "
+
+ http-request set-header sl1 "%[req.fhdr(sl1)] method=<%[var(req.method)]>; uri=<%[var(req.uri)]>; path=<%[var(req.path)]>;"
+ http-request set-header sl1 "%[req.fhdr(sl1)] query=<%[var(req.query)]>; param=<%[var(req.param)]>"
+ http-request set-header sl1 "%[req.fhdr(sl1)] cl=<%[var(req.cl)]>"
+ http-request set-header sl2 "%[req.fhdr(sl2)] method=<%[method]>; uri=<%[url]>; path=<%[path]>; "
+ http-request set-header sl2 "%[req.fhdr(sl2)] query=<%[query]>; param=<%[url_param(qs_arg)]>"
+ http-request set-header sl2 "%[req.fhdr(sl2)] cl=<%[req.fhdr(content-length)]>"
+ http-request set-header hdr "%[req.fhdr(hdr)] hdr1=<%[req.hdr(hdr1)]>; fhdr1=<%[req.fhdr(hdr1)]>;"
+ http-request set-header hdr "%[req.fhdr(hdr)] hdr2=<%[req.hdr(hdr2)]>; fhdr2=<%[req.fhdr(hdr2)]>;"
+ http-request set-header hdr "%[req.fhdr(hdr)] hdr3=<%[req.hdr(hdr3)]>; fhdr3=<%[req.fhdr(hdr3)]>;"
+ http-request set-header hdr "%[req.fhdr(hdr)] hdr4=<%[req.hdr(hdr4)]>; fhdr4=<%[req.fhdr(hdr4)]>;"
+
+ http-request set-header sl1-crc "%[req.fhdr(sl1),crc32]"
+ http-request set-header sl2-crc "%[req.fhdr(sl2),crc32]"
+ http-request set-header hdr-crc "%[req.fhdr(hdr),crc32]"
+
+ #### responses
+ http-response set-header be-sl1 "%[res.fhdr(sl1)]"
+ http-response set-header be-sl2 "%[res.fhdr(sl2)]"
+ http-response set-header be-hdr "%[res.fhdr(hdr)]"
+
+ http-response set-header be-sl1-crc "%[res.fhdr(sl1-crc)]"
+ http-response set-header be-sl2-crc "%[res.fhdr(sl2-crc)]"
+ http-response set-header be-hdr-crc "%[res.fhdr(hdr-crc)]"
+
+ http-response set-var(res.status) status
+ http-response set-header sl1 "sl1: "
+
+ http-response set-status 200
+
+ http-response set-header sl2 "sl2: "
+
+ http-response set-header sl1 "%[res.fhdr(sl1)] status=<%[var(res.status)]>;"
+ http-response set-header sl2 "%[res.fhdr(sl2)] status=<%[status]>;"
+ http-response set-header hdr "%[res.fhdr(hdr)] hdr1=<%[res.hdr(hdr1)]>; fhdr1=<%[res.fhdr(hdr1)]>;"
+ http-response set-header hdr "%[res.fhdr(hdr)] hdr2=<%[res.hdr(hdr2)]>; fhdr2=<%[res.fhdr(hdr2)]>;"
+ http-response set-header hdr "%[res.fhdr(hdr)] hdr3=<%[res.hdr(hdr3)]>; fhdr3=<%[res.fhdr(hdr3)]>;"
+ http-response set-header hdr "%[res.fhdr(hdr)] hdr4=<%[res.hdr(hdr4)]>; fhdr4=<%[res.fhdr(hdr4)]>;"
+
+ http-response set-header fe-sl1-crc "%[res.fhdr(sl1),crc32]"
+ http-response set-header fe-sl2-crc "%[res.fhdr(sl2),crc32]"
+ http-response set-header fe-hdr-crc "%[res.fhdr(hdr),crc32]"
+
+ default_backend be
+
+ backend be
+ #### requests
+ http-request set-header fe-sl1 "%[req.fhdr(sl1)]"
+ http-request set-header fe-sl2 "%[req.fhdr(sl2)]"
+ http-request set-header fe-hdr "%[req.fhdr(hdr)]"
+
+ http-request set-header fe-sl1-crc "%[req.fhdr(sl1-crc)]"
+ http-request set-header fe-sl2-crc "%[req.fhdr(sl2-crc)]"
+ http-request set-header fe-hdr-crc "%[req.fhdr(hdr-crc)]"
+
+ http-request set-var(req.method) method
+ http-request set-var(req.uri) url
+ http-request set-var(req.path) path
+ http-request set-var(req.query) query
+ http-request set-var(req.param) url_param(qs_arg)
+ http-request set-var(req.cl) req.fhdr(content-length)
+
+ http-request set-header sl1 "sl1: "
+
+ http-request set-method "%[str(GET)]"
+ http-request set-uri %[str(),concat(/bu/,req.uri,/eu)]
+ http-request set-path "/bp/%[var(req.path)]/ep"
+ http-request set-query "bq&%[var(req.query)]&eq"
+
+ http-request set-header sl2 "sl2: "
+
+ http-request set-header sl1 "%[req.fhdr(sl1)] method=<%[var(req.method)]>; uri=<%[var(req.uri)]>; path=<%[var(req.path)]>;"
+ http-request set-header sl1 "%[req.fhdr(sl1)] query=<%[var(req.query)]>; param=<%[var(req.param)]>"
+ http-request set-header sl1 "%[req.fhdr(sl1)] cl=<%[var(req.cl)]>"
+ http-request set-header sl2 "%[req.fhdr(sl2)] method=<%[method]>; uri=<%[url]>; path=<%[path]>; "
+ http-request set-header sl2 "%[req.fhdr(sl2)] query=<%[query]>; param=<%[url_param(QS_arg,,i)]>"
+ http-request set-header sl2 "%[req.fhdr(sl2)] cl=<%[req.fhdr(content-length)]>"
+ http-request set-header hdr "%[req.fhdr(hdr)] hdr1=<%[req.hdr(hdr1)]>; fhdr1=<%[req.fhdr(hdr1)]>;"
+ http-request set-header hdr "%[req.fhdr(hdr)] hdr2=<%[req.hdr(hdr2)]>; fhdr2=<%[req.fhdr(hdr2)]>;"
+ http-request set-header hdr "%[req.fhdr(hdr)] hdr3=<%[req.hdr(hdr3)]>; fhdr3=<%[req.fhdr(hdr3)]>;"
+ http-request set-header hdr "%[req.fhdr(hdr)] hdr4=<%[req.hdr(hdr4)]>; fhdr4=<%[req.fhdr(hdr4)]>;"
+
+ http-request set-header be-sl1-crc "%[req.fhdr(sl1),crc32]"
+ http-request set-header be-sl2-crc "%[req.fhdr(sl2),crc32]"
+ http-request set-header be-hdr-crc "%[req.fhdr(hdr),crc32]"
+
+ #### responses
+ http-response set-var(res.status) status
+ http-response set-header sl1 "sl1: "
+
+ http-response set-status 200
+
+ http-response set-header sl2 "sl2: "
+
+ http-response set-header sl1 "%[res.fhdr(sl1)] status=<%[var(res.status)]>;"
+ http-response set-header sl2 "%[res.fhdr(sl2)] status=<%[status]>;"
+ http-response set-header hdr "%[res.fhdr(hdr)] hdr1=<%[res.hdr(hdr1)]>; fhdr1=<%[res.fhdr(hdr1)]>;"
+ http-response set-header hdr "%[res.fhdr(hdr)] hdr2=<%[res.hdr(hdr2)]>; fhdr2=<%[res.fhdr(hdr2)]>;"
+ http-response set-header hdr "%[res.fhdr(hdr)] hdr3=<%[res.hdr(hdr3)]>; fhdr3=<%[res.fhdr(hdr3)]>;"
+ http-response set-header hdr "%[res.fhdr(hdr)] hdr4=<%[res.hdr(hdr4)]>; fhdr4=<%[res.fhdr(hdr4)]>;"
+
+ http-response set-header sl1-crc "%[res.fhdr(sl1),crc32]"
+ http-response set-header sl2-crc "%[res.fhdr(sl2),crc32]"
+ http-response set-header hdr-crc "%[res.fhdr(hdr),crc32]"
+ http-response allow
+ http-response deny # must not be evaluated
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1h1 -connect ${h1_feh1_sock} {
+ txreq \
+ -req GET \
+ -url /path/to/file.extension?qs_arg=qs_value \
+ -hdr "content-length: 000, 00" \
+ -hdr "hdr1: val1" \
+ -hdr "hdr2: val2a" \
+ -hdr "hdr2: val2b" \
+ -hdr "hdr3: val3a, val3b" \
+ -hdr "hdr4:"
+ rxresp
+
+ expect resp.status == 200
+ expect resp.http.be-sl1-crc == 487202719
+ expect resp.http.be-sl2-crc == 561949791
+ expect resp.http.be-hdr-crc == 1719311923
+ expect resp.http.fe-sl1-crc == 146151597
+ expect resp.http.fe-sl2-crc == 561949791
+ expect resp.http.fe-hdr-crc == 3634102538
+ expect resp.bodylen == 14
+ expect resp.body == "This is a body"
+} -run
+
+client c1h2 -connect ${h1_feh2_sock} {
+ txpri
+ stream 0 {
+ txsettings
+ rxsettings
+ txsettings -ack
+ rxsettings
+ expect settings.ack == true
+ } -run
+ stream 1 {
+ # warning: -req, -scheme, -url MUST be placed first otherwise
+ # the H2 protocol is invalid since they are pseudo-headers
+ txreq \
+ -req GET \
+ -scheme "https" \
+ -url /path/to/file.extension?qs_arg=qs_value \
+ -hdr "content-length" "000, 00" \
+ -hdr "hdr1" "val1" \
+ -hdr "hdr2" " val2a" \
+ -hdr "hdr2" " val2b" \
+ -hdr "hdr3" " val3a, val3b" \
+ -hdr "hdr4" ""
+
+ rxhdrs
+ expect resp.status == 200
+ expect resp.http.be-sl1-crc == 487202719
+ expect resp.http.be-sl2-crc == 561949791
+ expect resp.http.be-hdr-crc == 1719311923
+ expect resp.http.fe-sl1-crc == 146151597
+ expect resp.http.fe-sl2-crc == 561949791
+ expect resp.http.fe-hdr-crc == 3634102538
+ expect resp.http.content-length == 14
+
+ rxdata -all
+ expect resp.body == "This is a body"
+ } -run
+} -run
diff --git a/reg-tests/http-rules/http_after_response.vtc b/reg-tests/http-rules/http_after_response.vtc
new file mode 100644
index 0000000..7e8cc1d
--- /dev/null
+++ b/reg-tests/http-rules/http_after_response.vtc
@@ -0,0 +1,192 @@
+varnishtest "Test HTTP response manipulation under the http-after-response rulesets"
+#REQUIRE_VERSION=2.2
+
+# This config tests various http-after-response rules for HTTP responses from a
+# server and the stats applet, but also for internal responses
+# (deny/redirect/auth/return).
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp \
+ -status 234 \
+ -hdr "hdr1: val1" \
+ -hdr "hdr2: val2a" \
+ -hdr "hdr2: val2b" \
+ -hdr "hdr3: val3a, val3b" \
+ -hdr "hdr4:" \
+ -body "This is a body"
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${feh1}"
+
+ http-request deny if { path /deny }
+ http-request redirect location / if { path /redir }
+ http-request auth if { path /auth }
+
+ http-after-response allow if { status eq 403 }
+ http-after-response allow if { status eq 302 }
+ http-after-response allow if { status eq 401 }
+
+ http-after-response set-header be-sl1 "%[res.fhdr(sl1)]"
+ http-after-response set-header be-sl2 "%[res.fhdr(sl2)]"
+ http-after-response set-header be-hdr "%[res.fhdr(hdr)]"
+
+ http-after-response set-header be-sl1-crc "%[res.fhdr(sl1-crc)]"
+ http-after-response set-header be-sl2-crc "%[res.fhdr(sl2-crc)]"
+ http-after-response set-header be-hdr-crc "%[res.fhdr(hdr-crc)]"
+
+ http-after-response set-var(res.status) status
+ http-after-response set-header sl1 "sl1: "
+
+ http-after-response set-status 200
+
+ http-after-response set-header sl2 "sl2: "
+
+ http-after-response set-header sl1 "%[res.fhdr(sl1)] status=<%[var(res.status)]>;"
+ http-after-response set-header sl2 "%[res.fhdr(sl2)] status=<%[status]>;"
+ http-after-response set-header hdr "%[res.fhdr(hdr)] hdr1=<%[res.hdr(hdr1)]>; fhdr1=<%[res.fhdr(hdr1)]>;"
+ http-after-response set-header hdr "%[res.fhdr(hdr)] hdr2=<%[res.hdr(hdr2)]>; fhdr2=<%[res.fhdr(hdr2)]>;"
+ http-after-response set-header hdr "%[res.fhdr(hdr)] hdr3=<%[res.hdr(hdr3)]>; fhdr3=<%[res.fhdr(hdr3)]>;"
+ http-after-response set-header hdr "%[res.fhdr(hdr)] hdr4=<%[res.hdr(hdr4)]>; fhdr4=<%[res.fhdr(hdr4)]>;"
+
+ http-after-response set-header fe-sl1-crc "%[res.fhdr(sl1),crc32]"
+ http-after-response set-header fe-sl2-crc "%[res.fhdr(sl2),crc32]"
+ http-after-response set-header fe-hdr-crc "%[res.fhdr(hdr),crc32]"
+
+ default_backend be
+
+ backend be
+ stats enable
+ stats uri /stats
+
+ http-request return status 234 content-type "text/plain" string "This is a body" if { path /return }
+
+ http-response deny if { capture.req.uri /deny-srv }
+
+ http-after-response allow if { status eq 502 }
+
+ http-after-response set-status 234 if { capture.req.uri /stats }
+ http-after-response add-header hdr1 val1 unless { capture.req.uri / }
+ http-after-response add-header hdr2 val2a unless { capture.req.uri / }
+ http-after-response add-header hdr2 val2b unless { capture.req.uri / }
+ http-after-response add-header hdr3 "val3a, val3b" unless { capture.req.uri / }
+ http-after-response add-header hdr4 "%[str()]" unless { capture.req.uri / }
+ http-after-response del-header content-type
+
+ http-after-response set-var(res.status) status
+ http-after-response set-header sl1 "sl1: "
+
+ http-after-response set-status 200
+
+ http-after-response set-header sl2 "sl2: "
+
+ http-after-response set-header sl1 "%[res.fhdr(sl1)] status=<%[var(res.status)]>;"
+ http-after-response set-header sl2 "%[res.fhdr(sl2)] status=<%[status]>;"
+ http-after-response set-header hdr "%[res.fhdr(hdr)] hdr1=<%[res.hdr(hdr1)]>; fhdr1=<%[res.fhdr(hdr1)]>;"
+ http-after-response set-header hdr "%[res.fhdr(hdr)] hdr2=<%[res.hdr(hdr2)]>; fhdr2=<%[res.fhdr(hdr2)]>;"
+ http-after-response set-header hdr "%[res.fhdr(hdr)] hdr3=<%[res.hdr(hdr3)]>; fhdr3=<%[res.fhdr(hdr3)]>;"
+ http-after-response set-header hdr "%[res.fhdr(hdr)] hdr4=<%[res.hdr(hdr4)]>; fhdr4=<%[res.fhdr(hdr4)]>;"
+
+ http-after-response set-header sl1-crc "%[res.fhdr(sl1),crc32]"
+ http-after-response set-header sl2-crc "%[res.fhdr(sl2),crc32]"
+ http-after-response set-header hdr-crc "%[res.fhdr(hdr),crc32]"
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_feh1_sock} {
+ txreq -req GET -url /
+ rxresp
+ expect resp.status == 200
+ expect resp.http.be-sl1-crc == 487202719
+ expect resp.http.be-sl2-crc == 561949791
+ expect resp.http.be-hdr-crc == 1719311923
+ expect resp.http.fe-sl1-crc == 146151597
+ expect resp.http.fe-sl2-crc == 561949791
+ expect resp.http.fe-hdr-crc == 3634102538
+ expect resp.http.content-type == <undef>
+ expect resp.bodylen == 14
+ expect resp.body == "This is a body"
+
+ txreq -req GET -url /return
+ rxresp
+ expect resp.status == 200
+ expect resp.http.be-sl1-crc == 487202719
+ expect resp.http.be-sl2-crc == 561949791
+ expect resp.http.be-hdr-crc == 1719311923
+ expect resp.http.fe-sl1-crc == 146151597
+ expect resp.http.fe-sl2-crc == 561949791
+ expect resp.http.fe-hdr-crc == 3634102538
+ expect resp.http.content-type == <undef>
+ expect resp.bodylen == 14
+ expect resp.body == "This is a body"
+
+ txreq -req GET -url /stats
+ rxresp
+ expect resp.status == 200
+ expect resp.http.be-sl1-crc == 487202719
+ expect resp.http.be-sl2-crc == 561949791
+ expect resp.http.be-hdr-crc == 1719311923
+ expect resp.http.fe-sl1-crc == 146151597
+ expect resp.http.fe-sl2-crc == 561949791
+ expect resp.http.fe-hdr-crc == 3634102538
+ expect resp.http.content-type == <undef>
+} -run
+
+client c2 -connect ${h1_feh1_sock} {
+ txreq -req GET -url /deny
+ rxresp
+ expect resp.status == 403
+ expect resp.http.be-sl1 == <undef>
+ expect resp.http.be-sl2 == <undef>
+ expect resp.http.be-hdr == <undef>
+ expect resp.http.sl1 == <undef>
+ expect resp.http.sl2 == <undef>
+ expect resp.http.hdr == <undef>
+} -run
+
+client c3 -connect ${h1_feh1_sock} {
+ txreq -req GET -url /redir
+ rxresp
+ expect resp.status == 302
+ expect resp.http.be-sl1 == <undef>
+ expect resp.http.be-sl2 == <undef>
+ expect resp.http.be-hdr == <undef>
+ expect resp.http.sl1 == <undef>
+ expect resp.http.sl2 == <undef>
+ expect resp.http.hdr == <undef>
+} -run
+
+client c4 -connect ${h1_feh1_sock} {
+ txreq -req GET -url /auth
+ rxresp
+ expect resp.status == 401
+ expect resp.http.be-sl1 == <undef>
+ expect resp.http.be-sl2 == <undef>
+ expect resp.http.be-hdr == <undef>
+ expect resp.http.sl1 == <undef>
+ expect resp.http.sl2 == <undef>
+ expect resp.http.hdr == <undef>
+} -run
+
+client c5 -connect ${h1_feh1_sock} {
+ txreq -req GET -url /deny-srv
+ rxresp
+ expect resp.status == 200
+ expect resp.http.be-sl1 == ""
+ expect resp.http.be-sl2 == ""
+ expect resp.http.be-hdr == ""
+ expect resp.http.fe-sl1-crc == 3104968915
+ expect resp.http.fe-sl2-crc == 561949791
+ expect resp.http.fe-hdr-crc == 623352154
+} -run
diff --git a/reg-tests/http-rules/http_return.vtc b/reg-tests/http-rules/http_return.vtc
new file mode 100644
index 0000000..ae96775
--- /dev/null
+++ b/reg-tests/http-rules/http_return.vtc
@@ -0,0 +1,99 @@
+varnishtest "Test the HTTP return action"
+#REQUIRE_VERSION=2.2
+
+# This config tests the HTTP return action.
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ http-request return if { path /def-1 }
+ http-request return hdr "x-custom-hdr" "%[url]" if { path /def-2 }
+ http-request return status 403 if { path /def-3 }
+ http-request return content-type "text/plain" if { path /def-4 }
+
+ http-request return content-type "text/plain" string "hello" hdr "x-custom-hdr" "%[url]" if { path /string }
+ http-request return content-type "text/plain" lf-string "path is %[url]" hdr "x-custom-hdr" "%[url]" if { path /lf-string }
+ http-request return content-type "text/plain" file /dev/null hdr "x-custom-hdr" "%[url]" if { path /empty-file }
+ http-request return content-type "text/plain" file ${testdir}/1k.txt hdr "x-custom-hdr" "%[url]" if { path /file }
+ http-request return content-type "text/plain" lf-file ${testdir}/lf-file.txt hdr "x-custom-hdr" "%[url]" if { path /lf-file }
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /def-1
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == 0
+ expect resp.http.content-type == <undef>
+ expect resp.http.x-custom-hdr == <undef>
+
+ txreq -req GET -url /def-2
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == 0
+ expect resp.http.content-type == <undef>
+ expect resp.http.x-custom-hdr == "/def-2"
+
+ txreq -req GET -url /def-3
+ rxresp
+ expect resp.status == 403
+ expect resp.http.content-length == 0
+ expect resp.http.content-type == <undef>
+
+ txreq -req GET -url /def-4
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == 0
+ expect resp.http.content-type == <undef>
+
+ txreq -req GET -url /string
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == 5
+ expect resp.http.content-type == "text/plain"
+ expect resp.http.x-custom-hdr == "/string"
+ expect resp.body == "hello"
+
+ txreq -req GET -url /lf-string
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == 18
+ expect resp.http.content-type == "text/plain"
+ expect resp.http.x-custom-hdr == "/lf-string"
+ expect resp.body == "path is /lf-string"
+
+ txreq -req GET -url /empty-file
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == 0
+ expect resp.http.content-type == <undef>
+ expect resp.http.x-custom-hdr == "/empty-file"
+
+ txreq -req GET -url /file
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == 1024
+ expect resp.http.content-type == "text/plain"
+ expect resp.http.x-custom-hdr == "/file"
+
+ txreq -req GET -url /lf-file
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == 17
+ expect resp.http.content-type == "text/plain"
+ expect resp.http.x-custom-hdr == "/lf-file"
+ expect resp.body == "path is /lf-file\n"
+} -run
diff --git a/reg-tests/http-rules/ifnone-forwardfor.vtc b/reg-tests/http-rules/ifnone-forwardfor.vtc
new file mode 100644
index 0000000..a743b10
--- /dev/null
+++ b/reg-tests/http-rules/ifnone-forwardfor.vtc
@@ -0,0 +1,98 @@
+varnishtest "Test if-none param for the forwardfor option"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.6-dev0)'"
+
+# This config tests the if-none parameter for the HTTP forwardfor option.
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend none
+ bind "fd@${none}"
+ http-request set-src hdr(x-src)
+ option forwardfor if-none
+ use_backend be1 if { path /req1 }
+ use_backend be2 if { path /req2 }
+ use_backend be3 if { path /req3 }
+
+ frontend normal
+ bind "fd@${normal}"
+ http-request set-src hdr(x-src)
+ option forwardfor
+ use_backend be1 if { path /req1 }
+ use_backend be2 if { path /req2 }
+
+
+ frontend fe2
+ bind "fd@${fe2}"
+ http-request return status 200 hdr x-ff "%[req.fhdr_cnt(x-forwarded-for)]"
+
+ backend be1
+ option forwardfor
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+ backend be2
+ option forwardfor if-none
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+
+ backend be3
+ server s1 ${h1_fe2_addr}:${h1_fe2_port}
+} -start
+
+client c1 -connect ${h1_none_sock} {
+ txreq -req GET -url /req1 \
+ -hdr "x-src: 10.0.0.128" \
+ -hdr "x-forwarded-for: 127.0.0.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == 2
+
+ txreq -req GET -url /req2 \
+ -hdr "x-src: 10.0.0.128" \
+ -hdr "x-forwarded-for: 127.0.0.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == 1
+
+ txreq -req GET -url /req2 \
+ -hdr "x-src: 10.0.0.128"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == 1
+
+ txreq -req GET -url /req3 \
+ -hdr "x-src: 10.0.0.128" \
+ -hdr "x-forwarded-for: 127.0.0.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == 1
+
+} -run
+
+client c1 -connect ${h1_normal_sock} {
+ txreq -req GET -url /req1 \
+ -hdr "x-src: 10.0.0.128" \
+ -hdr "x-forwarded-for: 127.0.0.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == 2
+
+ txreq -req GET -url /req2 \
+ -hdr "x-src: 10.0.0.128" \
+ -hdr "x-forwarded-for: 127.0.0.1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ff == 2
+
+} -run
diff --git a/reg-tests/http-rules/lf-file.txt b/reg-tests/http-rules/lf-file.txt
new file mode 100644
index 0000000..7fda1d4
--- /dev/null
+++ b/reg-tests/http-rules/lf-file.txt
@@ -0,0 +1 @@
+path is %[url]
diff --git a/reg-tests/http-rules/map_ordering.map b/reg-tests/http-rules/map_ordering.map
new file mode 100644
index 0000000..dcd9529
--- /dev/null
+++ b/reg-tests/http-rules/map_ordering.map
@@ -0,0 +1,4 @@
+# These entries are used for list-based match ordering tests
+first.domain.tld first
+domain.tld domain
+second.domain.tld second
diff --git a/reg-tests/http-rules/map_ordering.vtc b/reg-tests/http-rules/map_ordering.vtc
new file mode 100644
index 0000000..40da465
--- /dev/null
+++ b/reg-tests/http-rules/map_ordering.vtc
@@ -0,0 +1,32 @@
+varnishtest "Test list-based matching types ordering"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+
+ # check list ordering using map_dom (list-based match)
+ http-request return hdr dom %[req.hdr(Host),lower,map_dom(${testdir}/map_ordering.map)] if { url_beg /dom }
+} -start
+
+# Check map ordering
+client c1 -connect ${h1_fe1_sock} {
+ # first.domain.tld is above domain.tld so it should match first
+ txreq -url "/dom" -hdr "Host: first.domain.tld"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.dom == "first"
+
+ # second.domain.tld is below domain.tld so domain.tld should match first
+ txreq -url "/dom" -hdr "Host: second.domain.tld"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.dom == "domain"
+} -run
diff --git a/reg-tests/http-rules/map_redirect-be.map b/reg-tests/http-rules/map_redirect-be.map
new file mode 100644
index 0000000..c8822fc
--- /dev/null
+++ b/reg-tests/http-rules/map_redirect-be.map
@@ -0,0 +1,4 @@
+# These entries are used for use_backend rules
+test1.example.com test1_be
+test1.example.invalid test1_be
+test2.example.com test2_be
diff --git a/reg-tests/http-rules/map_redirect.map b/reg-tests/http-rules/map_redirect.map
new file mode 100644
index 0000000..c4743f6
--- /dev/null
+++ b/reg-tests/http-rules/map_redirect.map
@@ -0,0 +1,5 @@
+# These entries are used for http-request redirect rules
+example.org https://www.example.org
+subdomain.example.org https://www.subdomain.example.org
+
+/path/to/old/file /path/to/new/file
diff --git a/reg-tests/http-rules/map_redirect.vtc b/reg-tests/http-rules/map_redirect.vtc
new file mode 100644
index 0000000..f55e0d8
--- /dev/null
+++ b/reg-tests/http-rules/map_redirect.vtc
@@ -0,0 +1,200 @@
+varnishtest "haproxy host header: map / redirect tests"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev5) && (feature(PCRE) || feature(PCRE2))'"
+feature ignore_unknown_macro
+
+
+server s1 {
+ rxreq
+ expect req.method == "GET"
+ expect req.http.host == "test1.example.com"
+ txresp -body "test1 ok"
+} -start
+
+server s2 {
+ rxreq
+ expect req.method == "GET"
+ expect req.http.host == "test2.example.com"
+ txresp -body "test2 ok"
+} -start
+
+server s3 {
+ rxreq
+ expect req.method == "GET"
+ expect req.http.host == "test3.example.com"
+ txresp -body "test3 ok"
+} -start
+
+server s4 {
+ rxreq
+ expect req.method == "GET"
+ expect req.http.host == "test1.example.invalid"
+ txresp -body "test1 after del map ok"
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ log global
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+
+ # automatically redirect matching paths from maps but skip rule on no-match
+ http-request redirect code 301 location %[path,map_str(${testdir}/map_redirect.map)] ignore-empty
+
+ # redirect Host: example.org / subdomain.example.org
+ http-request redirect prefix %[req.hdr(Host),lower,regsub(:\d+$,,),map_str(${testdir}/map_redirect.map)] code 301 if { hdr(Host),lower,regsub(:\d+$,,),map_str(${testdir}/map_redirect.map) -m found }
+
+ # set var and redirect in be1
+ http-request set-var(txn.testvar) req.hdr(Testvar),lower,regsub(:\d+$,,),map_str(${testdir}/map_redirect.map) if { hdr(Testvar),lower,regsub(:\d+$,,),map_str(${testdir}/map_redirect.map) -m found }
+
+ # use map to select backend (no default map value)
+ use_backend %[req.hdr(Host),lower,map_dom(${testdir}/map_redirect-be.map)] if { hdr_dom(Host) -i test1.example.com || hdr_dom(Host) -i test2.example.com }
+
+ # use map to select backend with default value(test3_be)
+ use_backend %[req.hdr(Host),lower,map_dom(${testdir}/map_redirect-be.map,test3_be)] if { hdr_dom(Host) -m end -i example.com }
+
+ # use map(after del map test1.example.com) default value(test4_be)
+ use_backend %[req.hdr(Host),lower,map_dom(${testdir}/map_redirect-be.map,test4_be)] if { hdr_dom(Host) -m end -i example.invalid }
+
+ default_backend be1
+
+ backend be1
+ http-request redirect prefix %[var(txn.testvar)] code 301 if { var(txn.testvar) -m found }
+ http-request deny
+
+ backend test1_be
+ server s1 ${s1_addr}:${s1_port}
+
+ backend test2_be
+ server s2 ${s2_addr}:${s2_port}
+
+ backend test3_be
+ server s3 ${s3_addr}:${s3_port}
+
+ backend test4_be
+ server s4 ${s4_addr}:${s4_port}
+} -start
+
+# Check map redirects
+client c1 -connect ${h1_fe1_sock} {
+ txreq -hdr "Host: example.org:8443"
+ rxresp
+ expect resp.status == 301
+ expect resp.http.location ~ "https://www.example.org"
+
+ txreq -url /path/to/old/file
+ rxresp
+ expect resp.status == 301
+ expect resp.http.location ~ "/path/to/new/file"
+
+ # Closes connection
+} -run
+
+client c2 -connect ${h1_fe1_sock} {
+ txreq -hdr "Host: subdomain.example.org"
+ rxresp
+ expect resp.status == 301
+ expect resp.http.location ~ "https://www.subdomain.example.org"
+ # Closes connection
+} -run
+
+client c3 -connect ${h1_fe1_sock} {
+ # redirect on Testvar header
+ txreq -hdr "Testvar: subdomain.example.org"
+ rxresp
+ expect resp.status == 301
+ expect resp.http.location ~ "https://www.subdomain.example.org"
+ # Closes connection
+} -run
+
+client c4 -connect ${h1_fe1_sock} {
+ txreq -hdr "Host: www.subdomain.example.org"
+ rxresp
+ expect resp.status == 403
+ # Closes connection
+} -run
+
+client c5 -connect ${h1_fe1_sock} {
+ txreq -hdr "Testvar: www.subdomain.example.org"
+ rxresp
+ expect resp.status == 403
+ # Closes connection
+} -run
+
+client c6 -connect ${h1_fe1_sock} {
+ txreq -hdr "Host: :8443example.org"
+ rxresp
+ expect resp.status == 403
+ # Closes connection
+} -run
+
+# Check map backend selection
+client c7 -connect ${h1_fe1_sock} {
+ txreq -hdr "Host: test1.example.com"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "test1 ok"
+
+ txreq -hdr "Host: test2.example.com"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "test2 ok"
+
+ txreq -hdr "Host: test3.example.com"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "test3 ok"
+} -run
+
+# cli show maps
+haproxy h1 -cli {
+ send "show map ${testdir}/map_redirect.map"
+ expect ~ "^0x[a-f0-9]+ example\\.org https://www\\.example\\.org\\n0x[a-f0-9]+ subdomain\\.example\\.org https://www\\.subdomain\\.example\\.org\\n0x[a-f0-9]+ /path/to/old/file /path/to/new/file\n$"
+
+ send "show map ${testdir}/map_redirect-be.map"
+ expect ~ "^0x[a-f0-9]+ test1\\.example\\.com test1_be\\n0x[a-f0-9]+ test1\\.example\\.invalid test1_be\\n0x[a-f0-9]+ test2\\.example\\.com test2_be\\n$"
+}
+
+haproxy h1 -cli {
+ # clear map ${testdir}/map_redirect.map
+ send "clear map ${testdir}/map_redirect.map"
+ expect ~ "^\\n"
+
+ send "show map ${testdir}/map_redirect.map"
+ expect ~ "^\\n"
+
+ # add map ${testdir}/map_redirect.map
+ send "add map ${testdir}/map_redirect.map site1_key site1_value"
+ expect ~ "^\\n"
+
+ # add 2 more entries as payload
+ send "add map ${testdir}/map_redirect.map <<\nsite2_key site2_value\nsite3_key site3_value\n"
+ expect ~ "^\\n"
+
+ send "show map ${testdir}/map_redirect.map"
+ expect ~ "^0x[a-f0-9]+ site1_key site1_value\\n0x[a-f0-9]+ site2_key site2_value\\n0x[a-f0-9]+ site3_key site3_value\\n$"
+
+ # del map ${testdir}/map_redirect-be.map test1.example.{com,invalid}
+ send "del map ${testdir}/map_redirect-be.map test1.example.com"
+ expect ~ "^\\n"
+
+ send "del map ${testdir}/map_redirect-be.map test1.example.invalid"
+ expect ~ "^\\n"
+
+ send "show map ${testdir}/map_redirect-be.map"
+ expect ~ "^0x[a-f0-9]+ test2\\.example\\.com test2_be\\n$"
+}
+
+# Check map backend after del map
+client c6 -connect ${h1_fe1_sock} {
+ # test1.example.invalid should go to test4_be after del map
+ txreq -hdr "Host: test1.example.invalid"
+ rxresp
+ expect resp.status == 200
+ expect resp.body == "test1 after del map ok"
+} -run
diff --git a/reg-tests/http-rules/map_regm_with_backref.map b/reg-tests/http-rules/map_regm_with_backref.map
new file mode 100644
index 0000000..08ffcfb
--- /dev/null
+++ b/reg-tests/http-rules/map_regm_with_backref.map
@@ -0,0 +1 @@
+^(.*)\.(.*)$ \1_AND_\2
diff --git a/reg-tests/http-rules/map_regm_with_backref.vtc b/reg-tests/http-rules/map_regm_with_backref.vtc
new file mode 100644
index 0000000..c3b21fb
--- /dev/null
+++ b/reg-tests/http-rules/map_regm_with_backref.vtc
@@ -0,0 +1,73 @@
+#commit 271022150d7961b9aa39dbfd88e0c6a4bc48c3ee
+# BUG/MINOR: map: fix map_regm with backref
+#
+# Due to a cascade of get_trash_chunk calls the sample is
+# corrupted when we want to read it.
+#
+# The fix consist to use a temporary chunk to copy the sample
+# value and use it.
+
+varnishtest "map_regm get_trash_chunk test"
+feature ignore_unknown_macro
+
+#REGTEST_TYPE=bug
+
+syslog S1 -level notice {
+ recv info
+ # not expecting ${h1_pid} with master-worker
+ expect ~ "[^:\\[ ]\\[[[:digit:]]+\\]: .* fe1 be1/s1 [[:digit:]]+/[[:digit:]]+/[[:digit:]]+/[[:digit:]]+/[[:digit:]]+ 200 [[:digit:]]+ - - ---- .* \"GET / HTTP/(1|2)(\\.1)?\""
+} -start
+
+server s1 {
+ rxreq
+ expect req.method == "GET"
+ expect req.http.x-mapped-from-header == example_AND_org
+ expect req.http.x-mapped-from-var == example_AND_org
+ txresp
+
+ rxreq
+ expect req.method == "GET"
+ expect req.http.x-mapped-from-header == www.example_AND_org
+ expect req.http.x-mapped-from-var == www.example_AND_org
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ log ${S1_addr}:${S1_port} local0 debug err
+
+ defaults
+ mode http
+ log global
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ # Remove port from Host header
+ http-request replace-value Host '(.*):.*' '\1'
+ # Store host header in variable
+ http-request set-var(txn.host) req.hdr(Host)
+ # This works correctly
+ http-request set-header X-Mapped-From-Header %[req.hdr(Host),map_regm(${testdir}/map_regm_with_backref.map,"unknown")]
+ # This breaks before commit 271022150d7961b9aa39dbfd88e0c6a4bc48c3ee
+ http-request set-header X-Mapped-From-Var %[var(txn.host),map_regm(${testdir}/map_regm_with_backref.map,"unknown")]
+
+ default_backend be1
+
+ backend be1
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -hdr "Host: example.org:8443"
+ rxresp
+ expect resp.status == 200
+
+ txreq -hdr "Host: www.example.org"
+ rxresp
+ expect resp.status == 200
+} -run
+
diff --git a/reg-tests/http-rules/normalize_uri.vtc b/reg-tests/http-rules/normalize_uri.vtc
new file mode 100644
index 0000000..ad7b44a
--- /dev/null
+++ b/reg-tests/http-rules/normalize_uri.vtc
@@ -0,0 +1,549 @@
+varnishtest "normalize-uri tests"
+#REQUIRE_VERSION=2.4
+
+# This reg-test tests the http-request normalize-uri action.
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp -hdr "connection: close"
+} -repeat 70 -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+ expose-experimental-directives
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe_path_merge_slashes
+ bind "fd@${fe_path_merge_slashes}"
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri path-merge-slashes
+ http-request set-var(txn.after) url
+
+ http-response add-header before %[var(txn.before)]
+ http-response add-header after %[var(txn.after)]
+
+ default_backend be
+
+ frontend fe_path_strip_dotdot
+ bind "fd@${fe_path_strip_dotdot}"
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri path-strip-dotdot
+ http-request set-var(txn.after) url
+
+ http-request set-uri %[var(txn.before)]
+ http-request normalize-uri path-strip-dotdot full
+ http-request set-var(txn.after_full) url
+
+ http-response add-header before %[var(txn.before)]
+ http-response add-header after %[var(txn.after)]
+ http-response add-header after-full %[var(txn.after_full)]
+
+ default_backend be
+
+ frontend fe_sort_query_by_name
+ bind "fd@${fe_sort_query_by_name}"
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri query-sort-by-name
+ http-request set-var(txn.after) url
+
+ http-response add-header before %[var(txn.before)]
+ http-response add-header after %[var(txn.after)]
+
+ default_backend be
+
+ frontend fe_percent_to_uppercase
+ bind "fd@${fe_percent_to_uppercase}"
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri percent-to-uppercase
+ http-request set-var(txn.after) url
+
+ http-response add-header before %[var(txn.before)]
+ http-response add-header after %[var(txn.after)]
+
+ default_backend be
+
+ frontend fe_percent_to_uppercase_strict
+ bind "fd@${fe_percent_to_uppercase_strict}"
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri percent-to-uppercase strict
+ http-request set-var(txn.after) url
+
+ http-response add-header before %[var(txn.before)]
+ http-response add-header after %[var(txn.after)]
+
+ default_backend be
+
+ frontend fe_dot
+ bind "fd@${fe_dot}"
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri path-strip-dot
+ http-request set-var(txn.after) url
+
+ http-response add-header before %[var(txn.before)]
+ http-response add-header after %[var(txn.after)]
+
+ default_backend be
+
+ frontend fe_percent_decode_unreserved
+ bind "fd@${fe_percent_decode_unreserved}"
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri percent-decode-unreserved
+ http-request set-var(txn.after) url
+
+ http-response add-header before %[var(txn.before)]
+ http-response add-header after %[var(txn.after)]
+
+ default_backend be
+
+ frontend fe_percent_decode_unreserved_strict
+ bind "fd@${fe_percent_decode_unreserved_strict}"
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri percent-decode-unreserved strict
+ http-request set-var(txn.after) url
+
+ http-response add-header before %[var(txn.before)]
+ http-response add-header after %[var(txn.after)]
+
+ default_backend be
+
+ frontend fe_fragment_strip
+ bind "fd@${fe_fragment_strip}"
+ option accept-invalid-http-request
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri fragment-strip
+ http-request set-var(txn.after) url
+
+ http-response add-header before %[var(txn.before)]
+ http-response add-header after %[var(txn.after)]
+
+ default_backend be
+
+ frontend fe_fragment_encode
+ bind "fd@${fe_fragment_encode}"
+ option accept-invalid-http-request
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri fragment-encode
+ http-request set-var(txn.after) url
+
+ http-response add-header before %[var(txn.before)]
+ http-response add-header after %[var(txn.after)]
+
+ default_backend be
+
+ frontend fe_fragment_block
+ bind "fd@${fe_fragment_block}"
+ http-request normalize-uri fragment-strip
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+client c1 -connect ${h1_fe_path_merge_slashes_sock} {
+ txreq -url "/foo/bar"
+ rxresp
+ expect resp.http.before == "/foo/bar"
+ expect resp.http.after == "/foo/bar"
+
+ txreq -url "/foo//bar"
+ rxresp
+ expect resp.http.before == "/foo//bar"
+ expect resp.http.after == "/foo/bar"
+
+ txreq -url "/foo///bar"
+ rxresp
+ expect resp.http.before == "/foo///bar"
+ expect resp.http.after == "/foo/bar"
+
+ txreq -url "///foo///bar"
+ rxresp
+ expect resp.http.before == "///foo///bar"
+ expect resp.http.after == "/foo/bar"
+
+ txreq -url "///foo/bar"
+ rxresp
+ expect resp.http.before == "///foo/bar"
+ expect resp.http.after == "/foo/bar"
+
+ txreq -url "///foo///bar///"
+ rxresp
+ expect resp.http.before == "///foo///bar///"
+ expect resp.http.after == "/foo/bar/"
+
+ txreq -url "///"
+ rxresp
+ expect resp.http.before == "///"
+ expect resp.http.after == "/"
+
+ txreq -url "/foo?bar=///"
+ rxresp
+ expect resp.http.before == "/foo?bar=///"
+ expect resp.http.after == "/foo?bar=///"
+
+ txreq -url "//foo?bar=///"
+ rxresp
+ expect resp.http.before == "//foo?bar=///"
+ expect resp.http.after == "/foo?bar=///"
+
+ txreq -req OPTIONS -url "*"
+ rxresp
+ expect resp.http.before == "*"
+ expect resp.http.after == "*"
+} -run
+
+client c2 -connect ${h1_fe_path_strip_dotdot_sock} {
+ txreq -url "/foo/bar"
+ rxresp
+ expect resp.http.before == "/foo/bar"
+ expect resp.http.after == "/foo/bar"
+ expect resp.http.after-full == "/foo/bar"
+
+ txreq -url "/foo/.."
+ rxresp
+ expect resp.http.before == "/foo/.."
+ expect resp.http.after == "/"
+ expect resp.http.after-full == "/"
+
+ txreq -url "/foo/../"
+ rxresp
+ expect resp.http.before == "/foo/../"
+ expect resp.http.after == "/"
+ expect resp.http.after-full == "/"
+
+ txreq -url "/foo/bar/../"
+ rxresp
+ expect resp.http.before == "/foo/bar/../"
+ expect resp.http.after == "/foo/"
+ expect resp.http.after-full == "/foo/"
+
+ txreq -url "/foo/../bar"
+ rxresp
+ expect resp.http.before == "/foo/../bar"
+ expect resp.http.after == "/bar"
+ expect resp.http.after-full == "/bar"
+
+ txreq -url "/foo/../bar/"
+ rxresp
+ expect resp.http.before == "/foo/../bar/"
+ expect resp.http.after == "/bar/"
+ expect resp.http.after-full == "/bar/"
+
+ txreq -url "/foo/../../bar/"
+ rxresp
+ expect resp.http.before == "/foo/../../bar/"
+ expect resp.http.after == "/../bar/"
+ expect resp.http.after-full == "/bar/"
+
+ txreq -url "/foo//../../bar/"
+ rxresp
+ expect resp.http.before == "/foo//../../bar/"
+ expect resp.http.after == "/bar/"
+ expect resp.http.after-full == "/bar/"
+
+ txreq -url "/foo/?bar=/foo/../"
+ rxresp
+ expect resp.http.before == "/foo/?bar=/foo/../"
+ expect resp.http.after == "/foo/?bar=/foo/../"
+ expect resp.http.after-full == "/foo/?bar=/foo/../"
+
+ txreq -url "/foo/../?bar=/foo/../"
+ rxresp
+ expect resp.http.before == "/foo/../?bar=/foo/../"
+ expect resp.http.after == "/?bar=/foo/../"
+ expect resp.http.after-full == "/?bar=/foo/../"
+
+ txreq -req OPTIONS -url "*"
+ rxresp
+ expect resp.http.before == "*"
+ expect resp.http.after == "*"
+ expect resp.http.after-full == "*"
+} -run
+
+client c3 -connect ${h1_fe_sort_query_by_name_sock} {
+ txreq -url "/?a=a"
+ rxresp
+ expect resp.http.before == "/?a=a"
+ expect resp.http.after == "/?a=a"
+
+ txreq -url "/?a=a&z=z"
+ rxresp
+ expect resp.http.before == "/?a=a&z=z"
+ expect resp.http.after == "/?a=a&z=z"
+
+ txreq -url "/?z=z&a=a"
+ rxresp
+ expect resp.http.before == "/?z=z&a=a"
+ expect resp.http.after == "/?a=a&z=z"
+
+ txreq -url "/?a=z&z=a"
+ rxresp
+ expect resp.http.before == "/?a=z&z=a"
+ expect resp.http.after == "/?a=z&z=a"
+
+ txreq -url "/?z=a&a=z"
+ rxresp
+ expect resp.http.before == "/?z=a&a=z"
+ expect resp.http.after == "/?a=z&z=a"
+
+ txreq -url "/?c&b&a&z&x&y"
+ rxresp
+ expect resp.http.before == "/?c&b&a&z&x&y"
+ expect resp.http.after == "/?a&b&c&x&y&z"
+
+ txreq -url "/?a=&aa=&aaa=&aaaa="
+ rxresp
+ expect resp.http.before == "/?a=&aa=&aaa=&aaaa="
+ expect resp.http.after == "/?a=&aa=&aaa=&aaaa="
+
+ txreq -url "/?aaaa=&a=&aa=&aaa="
+ rxresp
+ expect resp.http.before == "/?aaaa=&a=&aa=&aaa="
+ expect resp.http.after == "/?a=&aa=&aaa=&aaaa="
+
+ txreq -url "/?a=5&a=3&a=1&a=2&a=4"
+ rxresp
+ expect resp.http.before == "/?a=5&a=3&a=1&a=2&a=4"
+ expect resp.http.after == "/?a=5&a=3&a=1&a=2&a=4"
+
+ txreq -url "/?a=5&b=3&a=1&a=2&b=4"
+ rxresp
+ expect resp.http.before == "/?a=5&b=3&a=1&a=2&b=4"
+ expect resp.http.after == "/?a=5&a=1&a=2&b=3&b=4"
+
+ txreq -url "/"
+ rxresp
+ expect resp.http.before == "/"
+ expect resp.http.after == "/"
+
+ txreq -url "/?"
+ rxresp
+ expect resp.http.before == "/?"
+ expect resp.http.after == "/?"
+
+ txreq -req OPTIONS -url "*"
+ rxresp
+ expect resp.http.before == "*"
+ expect resp.http.after == "*"
+} -run
+
+client c4 -connect ${h1_fe_percent_to_uppercase_sock} {
+ txreq -url "/a?a=a"
+ rxresp
+ expect resp.http.before == "/a?a=a"
+ expect resp.http.after == "/a?a=a"
+
+ txreq -url "/%aa?a=%aa"
+ rxresp
+ expect resp.http.before == "/%aa?a=%aa"
+ expect resp.http.after == "/%AA?a=%AA"
+
+ txreq -url "/%zz?a=%zz"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.before == "/%zz?a=%zz"
+ expect resp.http.after == "/%zz?a=%zz"
+
+ txreq -req OPTIONS -url "*"
+ rxresp
+ expect resp.http.before == "*"
+ expect resp.http.after == "*"
+} -run
+
+client c5 -connect ${h1_fe_percent_to_uppercase_strict_sock} {
+ txreq -url "/a?a=a"
+ rxresp
+ expect resp.http.before == "/a?a=a"
+ expect resp.http.after == "/a?a=a"
+
+ txreq -url "/%aa?a=%aa"
+ rxresp
+ expect resp.http.before == "/%aa?a=%aa"
+ expect resp.http.after == "/%AA?a=%AA"
+
+ txreq -url "/%zz?a=%zz"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c6 -connect ${h1_fe_dot_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.http.before == "/"
+ expect resp.http.after == "/"
+
+ txreq -url "/a/b"
+ rxresp
+ expect resp.http.before == "/a/b"
+ expect resp.http.after == "/a/b"
+
+ txreq -url "/."
+ rxresp
+ expect resp.http.before == "/."
+ expect resp.http.after == "/"
+
+ txreq -url "/./"
+ rxresp
+ expect resp.http.before == "/./"
+ expect resp.http.after == "/"
+
+ txreq -url "/a/."
+ rxresp
+ expect resp.http.before == "/a/."
+ expect resp.http.after == "/a/"
+
+ txreq -url "/a."
+ rxresp
+ expect resp.http.before == "/a."
+ expect resp.http.after == "/a."
+
+ txreq -url "/.a"
+ rxresp
+ expect resp.http.before == "/.a"
+ expect resp.http.after == "/.a"
+
+ txreq -url "/a/."
+ rxresp
+ expect resp.http.before == "/a/."
+ expect resp.http.after == "/a/"
+
+ txreq -url "/a/./"
+ rxresp
+ expect resp.http.before == "/a/./"
+ expect resp.http.after == "/a/"
+
+ txreq -url "/a/./a"
+ rxresp
+ expect resp.http.before == "/a/./a"
+ expect resp.http.after == "/a/a"
+
+ txreq -url "/a/../"
+ rxresp
+ expect resp.http.before == "/a/../"
+ expect resp.http.after == "/a/../"
+
+ txreq -url "/a/../a"
+ rxresp
+ expect resp.http.before == "/a/../a"
+ expect resp.http.after == "/a/../a"
+
+ txreq -url "/?a=/./"
+ rxresp
+ expect resp.http.before == "/?a=/./"
+ expect resp.http.after == "/?a=/./"
+} -run
+
+client c7 -connect ${h1_fe_percent_decode_unreserved_sock} {
+ txreq -url "/a?a=a"
+ rxresp
+ expect resp.http.before == "/a?a=a"
+ expect resp.http.after == "/a?a=a"
+
+ txreq -url "/%61?%61=%61"
+ rxresp
+ expect resp.http.before == "/%61?%61=%61"
+ expect resp.http.after == "/a?a=a"
+
+ txreq -url "/%3F?foo=bar"
+ rxresp
+ expect resp.http.before == "/%3F?foo=bar"
+ expect resp.http.after == "/%3F?foo=bar"
+
+ txreq -url "/%%36%36"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.before == "/%%36%36"
+ expect resp.http.after == "/%66"
+
+ txreq -req OPTIONS -url "*"
+ rxresp
+ expect resp.http.before == "*"
+ expect resp.http.after == "*"
+} -run
+
+client c8 -connect ${h1_fe_percent_decode_unreserved_strict_sock} {
+ txreq -url "/a?a=a"
+ rxresp
+ expect resp.http.before == "/a?a=a"
+ expect resp.http.after == "/a?a=a"
+
+ txreq -url "/%61?%61=%61"
+ rxresp
+ expect resp.http.before == "/%61?%61=%61"
+ expect resp.http.after == "/a?a=a"
+
+ txreq -url "/%3F?foo=bar"
+ rxresp
+ expect resp.http.before == "/%3F?foo=bar"
+ expect resp.http.after == "/%3F?foo=bar"
+
+ txreq -url "/%%36%36"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c9 -connect ${h1_fe_fragment_strip_sock} {
+ txreq -url "/#foo"
+ rxresp
+ expect resp.http.before == "/#foo"
+ expect resp.http.after == "/"
+
+ txreq -url "/%23foo"
+ rxresp
+ expect resp.http.before == "/%23foo"
+ expect resp.http.after == "/%23foo"
+
+ txreq -req OPTIONS -url "*"
+ rxresp
+ expect resp.http.before == "*"
+ expect resp.http.after == "*"
+} -run
+
+client c10 -connect ${h1_fe_fragment_encode_sock} {
+ txreq -url "/#foo"
+ rxresp
+ expect resp.http.before == "/#foo"
+ expect resp.http.after == "/%23foo"
+
+ txreq -url "/#foo/#foo"
+ rxresp
+ expect resp.http.before == "/#foo/#foo"
+ expect resp.http.after == "/%23foo/%23foo"
+
+ txreq -url "/%23foo"
+ rxresp
+ expect resp.http.before == "/%23foo"
+ expect resp.http.after == "/%23foo"
+
+ txreq -req OPTIONS -url "*"
+ rxresp
+ expect resp.http.before == "*"
+ expect resp.http.after == "*"
+} -run
+
+client c11 -connect ${h1_fe_fragment_block_sock} {
+ txreq -url "/#foo"
+ rxresp
+ expect resp.status == 400
+} -run
diff --git a/reg-tests/http-rules/path_and_pathq.vtc b/reg-tests/http-rules/path_and_pathq.vtc
new file mode 100644
index 0000000..31e85be
--- /dev/null
+++ b/reg-tests/http-rules/path_and_pathq.vtc
@@ -0,0 +1,64 @@
+varnishtest "path vs pathq tests"
+#REQUIRE_VERSION=2.2
+
+# This config tests various http request rules (set/replace) manipulating the
+# path, with or without the query-string. It also test path and pathq sample
+# fetches.
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.url == /regtest/foo/fe/req1/bar?param1=val1&param2=val2
+ expect req.http.x-path == /req1
+ expect req.http.x-pathq == /req1?param1=val1&param2=val2
+ expect req.http.x-query == param1=val1&param2=val2
+ expect req.http.x-url == /req1?param1=val1&param2=val2
+ txresp
+
+ rxreq
+ expect req.url == http://127.0.0.1/regtest/foo/fe/req2/bar?param1=val1&param2=val2
+ expect req.http.x-path == /req2
+ expect req.http.x-pathq == /req2?param1=val1&param2=val2
+ expect req.http.x-query == param1=val1&param2=val2
+ expect req.http.x-url == http://127.0.0.1/req2?param1=val1&param2=val2
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ http-request add-header x-path %[path]
+ http-request add-header x-pathq %[pathq]
+ http-request add-header x-query %[query]
+ http-request add-header x-url %[url]
+
+ http-request set-path /fe%[path]
+ http-request replace-path (.*) /foo\1
+ http-request replace-path (.*) \1/bar
+ http-request set-pathq %[path]?app=regtest&%[query]
+ http-request replace-pathq /([^?]*)\?app=([^&]*)&?(.*) /\2/\1?\3
+
+ default_backend be
+
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -req GET -url /req1?param1=val1&param2=val2
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url http://127.0.0.1/req2?param1=val1&param2=val2
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/http-rules/restrict_req_hdr_names.vtc b/reg-tests/http-rules/restrict_req_hdr_names.vtc
new file mode 100644
index 0000000..4b26e33
--- /dev/null
+++ b/reg-tests/http-rules/restrict_req_hdr_names.vtc
@@ -0,0 +1,185 @@
+varnishtest "http-restrict-req-hdr-names option tests"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.0-dev0)'"
+
+# This config tests "http-restrict-req-hdr-names" option
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ expect req.http.x-my_hdr == on
+ txresp
+} -start
+
+server s2 {
+ rxreq
+ expect req.http.x-my_hdr == <undef>
+ txresp
+} -start
+
+server s3 {
+ rxreq
+ expect req.http.x-my_hdr == on
+ txresp
+} -start
+
+server s4 {
+ rxreq
+ expect req.http.x-my_hdr == <undef>
+ txresp
+} -start
+
+server s5 {
+ rxreq
+ expect req.http.x-my_hdr == on
+ txresp
+} -start
+
+server s6 {
+ rxreq
+ expect req.http.x_my_hdr_with_lots_of_underscores == <undef>
+ txresp
+} -start
+
+server s7 {
+ rxreq
+ expect req.http.x_my_hdr-1 == <undef>
+ expect req.http.x-my-hdr-2 == on
+ txresp
+} -start
+
+server s8 {
+ rxreq
+ expect req.http.x-my_hdr-1 == <undef>
+ expect req.http.x-my_hdr-2 == <undef>
+ txresp
+} -start
+
+server s9 {
+ rxreq
+ expect req.http.x-my-hdr-with-trailing-underscore_ == <undef>
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ use_backend be-http1 if { path /req1 }
+ use_backend be-http2 if { path /req2 }
+ use_backend be-http3 if { path /req3 }
+ use_backend be-fcgi1 if { path /req4 }
+ use_backend be-fcgi2 if { path /req5 }
+ use_backend be-fcgi3 if { path /req6 }
+ use_backend be-http4 if { path /req7 }
+ use_backend be-http5 if { path /req8 }
+ use_backend be-http6 if { path /req9 }
+ use_backend be-http7 if { path /req10 }
+
+ backend be-http1
+ server s1 ${s1_addr}:${s1_port}
+
+ backend be-http2
+ option http-restrict-req-hdr-names delete
+ server s2 ${s2_addr}:${s2_port}
+
+ backend be-http3
+ option http-restrict-req-hdr-names reject
+
+ backend be-fcgi1
+ option http-restrict-req-hdr-names preserve
+ server s3 ${s3_addr}:${s3_port}
+
+ backend be-fcgi2
+ option http-restrict-req-hdr-names delete
+ server s4 ${s4_addr}:${s4_port}
+
+ backend be-fcgi3
+ option http-restrict-req-hdr-names reject
+
+ backend be-http4
+ option http-restrict-req-hdr-names delete
+ server s6 ${s6_addr}:${s6_port}
+
+ backend be-http5
+ option http-restrict-req-hdr-names delete
+ server s7 ${s7_addr}:${s7_port}
+
+ backend be-http6
+ option http-restrict-req-hdr-names delete
+ server s8 ${s8_addr}:${s8_port}
+
+ backend be-http7
+ option http-restrict-req-hdr-names delete
+ server s9 ${s9_addr}:${s9_port}
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ option http-restrict-req-hdr-names preserve
+
+ frontend fe2
+ bind "fd@${fe2}"
+ default_backend be-fcgi4
+
+ backend be-fcgi4
+ server s5 ${s5_addr}:${s5_port}
+
+ fcgi-app my-fcgi-app
+ docroot ${testdir}
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /req1 -hdr "X-my_hdr: on"
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req2 -hdr "X-my_hdr: on"
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req3 -hdr "X-my_hdr: on"
+ rxresp
+ expect resp.status == 403
+
+ txreq -req GET -url /req4 -hdr "X-my_hdr: on"
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req5 -hdr "X-my_hdr: on"
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req6 -hdr "X-my_hdr: on"
+ rxresp
+ expect resp.status == 403
+
+ txreq -req GET -url /req7 -hdr "X_my_hdr_with_lots_of_underscores: on"
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req8 -hdr "X_my_hdr-1: on" -hdr "X-my-hdr-2: on"
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req9 -hdr "X-my_hdr-1: on" -hdr "X-my_hdr-2: on"
+ rxresp
+ expect resp.status == 200
+
+ txreq -req GET -url /req10 -hdr "X-my-hdr-with-trailing-underscore_: on"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c2 -connect ${h1_fe2_sock} {
+ txreq -req GET -url /req1 -hdr "X-my_hdr: on"
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/http-rules/strict_rw_mode.vtc b/reg-tests/http-rules/strict_rw_mode.vtc
new file mode 100644
index 0000000..14e6901
--- /dev/null
+++ b/reg-tests/http-rules/strict_rw_mode.vtc
@@ -0,0 +1,164 @@
+varnishtest "Test the strict rewriting mode"
+#REQUIRE_VERSION=2.2
+
+# This config tests the strict-mode of HTTP rules.
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp \
+ -status 200
+ expect req.method == "GET"
+ expect req.url == "/req1"
+ expect req.http.x-hdr1 == "123456789012345678901234567890123456789012345678901234567890"
+
+ accept
+ rxreq
+ txresp \
+ -status 200
+ expect req.method == "GET"
+ expect req.url == "/req3"
+ expect req.http.x-hdr1 == "123456789012345678901234567890123456789012345678901234567890"
+ expect req.http.x-hdr3 == <undef>
+} -start
+
+server s2 {
+ rxreq
+ txresp \
+ -status 200 \
+ -hdr "x-req: /req1" \
+ -bodylen 2000
+ expect req.method == "GET"
+ expect req.url == "/req1"
+
+ accept
+ rxreq
+ txresp \
+ -status 200 \
+ -hdr "x-req: /req2" \
+ -bodylen 2000
+ expect req.method == "GET"
+ expect req.url == "/req2"
+
+ accept
+ rxreq
+ txresp \
+ -status 200 \
+ -hdr "x-req: /req3" \
+ -bodylen 2000
+ expect req.method == "GET"
+ expect req.url == "/req3"
+
+ accept
+ rxreq
+ txresp \
+ -status 200 \
+ -hdr "x-req: /req4" \
+ -bodylen 2000
+ expect req.method == "GET"
+ expect req.url == "/req4"
+
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.bufsize 2048
+ tune.maxrewrite 128
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ option http-buffer-request
+
+ frontend fe1
+ bind "fd@${fe1}"
+ http-request set-header x-hdr1 123456789012345678901234567890123456789012345678901234567890
+ http-request set-header x-hdr2 123456789012345678901234567890123456789012345678901234567890 if { path /req2 }
+ http-request strict-mode off if { path /req3 }
+ http-request set-header x-hdr3 123456789012345678901234567890123456789012345678901234567890 if { path /req3 }
+ default_backend be1
+
+ backend be1
+ http-request set-header x-hdr3 123456789012345678901234567890123456789012345678901234567890 if { path /req4 }
+ server s1 ${s1_addr}:${s1_port}
+
+ frontend fe2
+ bind "fd@${fe2}"
+ http-response set-header x-hdr4 123456789012345678901234567890123456789012345678901234567890 if { res.hdr(x-req) /req4 }
+ default_backend be2
+ backend be2
+ http-response set-header x-hdr1 123456789012345678901234567890123456789012345678901234567890
+ http-response set-header x-hdr2 123456789012345678901234567890123456789012345678901234567890 if { res.hdr(x-req) /req2 }
+ http-response strict-mode off if { res.hdr(x-req) /req3 }
+ http-response set-header x-hdr3 123456789012345678901234567890123456789012345678901234567890 if { res.hdr(-req) /req3 }
+ server s2 ${s2_addr}:${s2_port}
+
+} -start
+
+client c1r1 -connect ${h1_fe1_sock} {
+ txreq \
+ -req GET \
+ -url /req1 \
+ -bodylen 2000
+ rxresp
+ expect resp.status == 200
+} -run
+client c1r2 -connect ${h1_fe1_sock} {
+ txreq \
+ -req GET \
+ -url /req2 \
+ -bodylen 2000
+ rxresp
+ expect resp.status == 500
+} -run
+client c1r3 -connect ${h1_fe1_sock} {
+ txreq \
+ -req GET \
+ -url /req3 \
+ -bodylen 2000
+ rxresp
+ expect resp.status == 200
+} -run
+client c1r4 -connect ${h1_fe1_sock} {
+ txreq \
+ -req GET \
+ -url /req4 \
+ -bodylen 2000
+ rxresp
+ expect resp.status == 500
+} -run
+
+client c2r1 -connect ${h1_fe2_sock} {
+ txreq \
+ -req GET \
+ -url /req1
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-hdr1 == "123456789012345678901234567890123456789012345678901234567890"
+} -run
+client c2r2 -connect ${h1_fe2_sock} {
+ txreq \
+ -req GET \
+ -url /req2
+ rxresp
+ expect resp.status == 500
+} -run
+client c2r3 -connect ${h1_fe2_sock} {
+ txreq \
+ -req GET \
+ -url /req3
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-hdr1 == "123456789012345678901234567890123456789012345678901234567890"
+ expect resp.http.x-hdr3 == <undef>
+} -run
+client c2r4 -connect ${h1_fe2_sock} {
+ txreq \
+ -req GET \
+ -url /req4
+ rxresp
+ expect resp.status == 500
+} -run
diff --git a/reg-tests/http-set-timeout/set_timeout.vtc b/reg-tests/http-set-timeout/set_timeout.vtc
new file mode 100644
index 0000000..a112bc5
--- /dev/null
+++ b/reg-tests/http-set-timeout/set_timeout.vtc
@@ -0,0 +1,214 @@
+varnishtest "http-request set-timeout test"
+
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+
+server srv_h1 -repeat 9 {
+ rxreq
+ txresp
+} -start
+
+syslog Slog1 -level info {
+ recv
+ expect ~ "^.*timeout: 5000 5000.*$"
+} -start
+
+syslog Slog2 -level info {
+ recv
+ expect ~ "^.*timeout: 5000 5000.*$"
+} -start
+
+syslog Slog3 -level info {
+ recv
+ expect ~ "^.*timeout: 5000 3000.*$"
+} -start
+
+syslog Slog4 -level info {
+ recv
+ expect ~ "^.*timeout: 5000 5000.*$"
+} -start
+
+syslog Slog5 -level info {
+ recv
+ expect ~ "^.*timeout: 5000 3000.*$"
+} -start
+
+syslog Slog6 -level info {
+ recv
+ expect ~ "^.*timeout: 5000 5000.*$"
+} -start
+
+syslog Slog7 -level info {
+ recv
+ expect ~ "^.*timeout: 5000 5000.*$"
+} -start
+
+syslog Slog8 -level info {
+ recv
+ expect ~ "^.*timeout: 5000 3000.*$"
+} -start
+
+syslog Slog9 -level info {
+ recv
+ expect ~ "^.*timeout: 5000 3000.*$"
+} -start
+
+haproxy hap -conf {
+ defaults
+ timeout connect 5s
+ timeout client 5s
+ timeout server 5s
+ log global
+
+ listen li1
+ mode http
+ bind "fd@${li1}"
+ log-format "timeout: %[be_server_timeout] %[cur_server_timeout]"
+ log ${Slog1_addr}:${Slog1_port} len 2048 local0 debug err
+ server srv_h1 ${srv_h1_addr}:${srv_h1_port}
+
+ listen li2
+ mode http
+ bind "fd@${li2}"
+ log-format "timeout: %[be_server_timeout] %[cur_server_timeout]"
+ log ${Slog2_addr}:${Slog2_port} len 2048 local0 debug err
+ http-request set-timeout server 5s
+ server srv_h1 ${srv_h1_addr}:${srv_h1_port}
+
+ listen li3
+ mode http
+ bind "fd@${li3}"
+ log-format "timeout: %[fe_client_timeout] %[cur_client_timeout]"
+ log ${Slog4_addr}:${Slog4_port} len 2048 local0 debug err
+ http-request set-timeout client 5s
+ server srv_h1 ${srv_h1_addr}:${srv_h1_port}
+
+ frontend fe1
+ mode http
+ bind "fd@${fe1}"
+ log-format "timeout: %[be_server_timeout] %[cur_server_timeout]"
+ log ${Slog3_addr}:${Slog3_port} len 2048 local0 debug err
+ default_backend be1
+
+ backend be1
+ mode http
+ http-request set-timeout server int(3),mul(1000)
+ server srv_h1 ${srv_h1_addr}:${srv_h1_port}
+
+ frontend fe2
+ mode http
+ bind "fd@${fe2}"
+ log-format "timeout: %[fe_client_timeout] %[cur_client_timeout]"
+ log ${Slog5_addr}:${Slog5_port} len 2048 local0 debug err
+ http-request set-timeout client int(3),mul(1000)
+ default_backend be2
+
+ backend be2
+ mode http
+ server srv_h1 ${srv_h1_addr}:${srv_h1_port}
+
+ listen li4
+ mode http
+ bind "fd@${li4}"
+ log-format "timeout: %[be_server_timeout] %[cur_server_timeout]"
+ log ${Slog6_addr}:${Slog6_port} len 2048 local0 debug err
+ http-response set-timeout server 5s
+ server srv_h1 ${srv_h1_addr}:${srv_h1_port}
+
+ listen li5
+ mode http
+ bind "fd@${li5}"
+ log-format "timeout: %[fe_client_timeout] %[cur_client_timeout]"
+ log ${Slog7_addr}:${Slog7_port} len 2048 local0 debug err
+ http-response set-timeout client 5s
+ server srv_h1 ${srv_h1_addr}:${srv_h1_port}
+
+ frontend fe3
+ mode http
+ bind "fd@${fe3}"
+ log-format "timeout: %[be_server_timeout] %[cur_server_timeout]"
+ log ${Slog8_addr}:${Slog8_port} len 2048 local0 debug err
+ default_backend be1
+
+ backend be3
+ mode http
+ http-response set-timeout server int(3),mul(1000)
+ server srv_h1 ${srv_h1_addr}:${srv_h1_port}
+
+ frontend fe4
+ mode http
+ bind "fd@${fe4}"
+ log-format "timeout: %[fe_client_timeout] %[cur_client_timeout]"
+ log ${Slog9_addr}:${Slog9_port} len 2048 local0 debug err
+ http-response set-timeout client int(3),mul(1000)
+ default_backend be2
+
+ backend be4
+ mode http
+ server srv_h1 ${srv_h1_addr}:${srv_h1_port}
+} -start
+
+client c1 -connect ${hap_li1_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c2 -connect ${hap_li2_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c3 -connect ${hap_fe1_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c4 -connect ${hap_li3_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c5 -connect ${hap_fe2_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c6 -connect ${hap_li4_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c7 -connect ${hap_fe3_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c8 -connect ${hap_li5_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c9 -connect ${hap_fe4_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+syslog Slog1 -wait
+syslog Slog2 -wait
+syslog Slog3 -wait
+syslog Slog4 -wait
+syslog Slog5 -wait
+syslog Slog6 -wait
+syslog Slog7 -wait
+syslog Slog8 -wait
+syslog Slog9 -wait
diff --git a/reg-tests/jwt/build_token.py b/reg-tests/jwt/build_token.py
new file mode 100755
index 0000000..2f368ab
--- /dev/null
+++ b/reg-tests/jwt/build_token.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+
+# JWT package can be installed via 'pip install pyjwt' command
+
+import sys
+import jwt
+import json
+
+if len(sys.argv) != 4:
+ print(sys.argv[0],"<alg> <json_to_sign> <priv_key>")
+ quit()
+
+
+alg=sys.argv[1]
+json_to_sign=sys.argv[2]
+priv_key_file=sys.argv[3]
+
+with open(priv_key_file) as file:
+ priv_key = file.read()
+
+print(jwt.encode(json.loads(json_to_sign),priv_key,algorithm=alg))
+
diff --git a/reg-tests/jwt/es256-public.pem b/reg-tests/jwt/es256-public.pem
new file mode 100644
index 0000000..ac69e6d
--- /dev/null
+++ b/reg-tests/jwt/es256-public.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjq7vv/FURryqr7ukvkrn1ek5rjCM
+hOngjD17uQTZN7fo1QRIV18lPx5O2Ed5ok/j8j/hZaFOB6TNshNmthk3dA==
+-----END PUBLIC KEY-----
diff --git a/reg-tests/jwt/es384-public.pem b/reg-tests/jwt/es384-public.pem
new file mode 100644
index 0000000..b726e12
--- /dev/null
+++ b/reg-tests/jwt/es384-public.pem
@@ -0,0 +1,5 @@
+-----BEGIN PUBLIC KEY-----
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm1LU84aybo84c3LWQtaILtzzQsU9sT1b
+uda6u6NBJ9FrVEAQkk5tABimCcn60bxSe7s1+oM8xLsu2RuGibQzbTuL75pEs5kx
+HPQW4nmOz0zXCjvAvtQTA7vMirb/Oste
+-----END PUBLIC KEY-----
diff --git a/reg-tests/jwt/es512-public.pem b/reg-tests/jwt/es512-public.pem
new file mode 100644
index 0000000..46520ac
--- /dev/null
+++ b/reg-tests/jwt/es512-public.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAMJ5MagTv8l+AjWZLLJ+xxV9/iNhb
+xE52xa8uMCiuBM5VHPcBLEPi1haY17abA6j0F173bK/AN7MBOpT4pAFP07IAEpF7
+QWzw+YH7hrWcT66gzfPysgpzktY+xpMFYhmLH1h9DGiJE+5t5FF5+mCg4GXi1Aez
+UzHc9yLw+6meeTWKcv4=
+-----END PUBLIC KEY-----
diff --git a/reg-tests/jwt/jws_verify.vtc b/reg-tests/jwt/jws_verify.vtc
new file mode 100644
index 0000000..43d37c7
--- /dev/null
+++ b/reg-tests/jwt/jws_verify.vtc
@@ -0,0 +1,418 @@
+#REGTEST_TYPE=devel
+
+# This reg-test uses the JSON Web Token (JWT) converters to verify a token's signature.
+# It uses the http_auth_bearer sample fetch to fetch a token contained in an
+# HTTP Authorization header (with the Bearer scheme) which is the common way of
+# transmitting a token (see RFC6750). It then uses the jwt_header_query
+# converter to get the "alg" field declared in the token's JOSE header and
+# gives it to the jwt_verify converter with the appropriate certificate.
+#
+# All the supported algorithms are tested at least once (HMAC, RSA and ECDSA)
+# and the errors codes returned by jwt_verify are tested as well.
+
+varnishtest "Test the 'set ssl ca-file' feature of the CLI"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 24 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen main-fe
+ bind "fd@${mainfe}"
+
+ use_backend hsXXX_be if { path_beg /hs }
+ use_backend rsXXX_be if { path_beg /rs }
+ use_backend esXXX_be if { path_beg /es }
+ use_backend psXXX_be if { path_beg /ps }
+ use_backend auth_bearer_be if { path /auth_bearer }
+ default_backend dflt_be
+
+
+ backend hsXXX_be
+ http-request set-var(txn.bearer) http_auth_bearer
+ http-request set-var(txn.jwt_alg) var(txn.bearer),jwt_header_query('$.alg')
+
+ http-request deny unless { var(txn.jwt_alg) -m beg "HS" }
+
+ http-response set-header x-jwt-token %[var(txn.bearer)]
+ http-response set-header x-jwt-alg %[var(txn.jwt_alg)]
+
+ http-response set-header x-jwt-verify-HS256 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"hmac key hs256")] if { var(txn.jwt_alg) -m str "HS256" }
+ http-response set-header x-jwt-verify-HS384 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"hmac key hs384")] if { var(txn.jwt_alg) -m str "HS384" }
+ http-response set-header x-jwt-verify-HS512 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"hmac key hs512")] if { var(txn.jwt_alg) -m str "HS512" }
+ server s1 ${s1_addr}:${s1_port}
+
+ backend rsXXX_be
+ http-request set-var(txn.bearer) http_auth_bearer
+ http-request set-var(txn.jwt_alg) var(txn.bearer),jwt_header_query('$.alg')
+
+ http-request deny unless { var(txn.jwt_alg) -m beg "RS" }
+
+ http-response set-header x-jwt-token %[var(txn.bearer)]
+ http-response set-header x-jwt-alg %[var(txn.jwt_alg)]
+
+ http-response set-header x-jwt-verify-RS256 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"${testdir}/rsa-public.pem")] if { var(txn.jwt_alg) -m str "RS256" }
+ http-response set-header x-jwt-verify-RS384 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"${testdir}/rsa-public.pem")] if { var(txn.jwt_alg) -m str "RS384" }
+ http-response set-header x-jwt-verify-RS512 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"${testdir}/rsa-public.pem")] if { var(txn.jwt_alg) -m str "RS512" }
+ server s1 ${s1_addr}:${s1_port}
+
+ backend esXXX_be
+ http-request set-var(txn.bearer) http_auth_bearer
+ http-request set-var(txn.jwt_alg) var(txn.bearer),jwt_header_query('$.alg')
+
+ http-request deny unless { var(txn.jwt_alg) -m beg "ES" }
+
+ http-response set-header x-jwt-token %[var(txn.bearer)]
+ http-response set-header x-jwt-alg %[var(txn.jwt_alg)]
+
+ http-response set-header x-jwt-verify-ES256 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"${testdir}/es256-public.pem")] if { var(txn.jwt_alg) -m str "ES256" }
+ http-response set-header x-jwt-verify-ES384 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"${testdir}/es384-public.pem")] if { var(txn.jwt_alg) -m str "ES384" }
+ http-response set-header x-jwt-verify-ES512 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"${testdir}/es512-public.pem")] if { var(txn.jwt_alg) -m str "ES512" }
+ server s1 ${s1_addr}:${s1_port}
+
+ backend psXXX_be
+ http-request set-var(txn.bearer) http_auth_bearer
+ http-request set-var(txn.jwt_alg) var(txn.bearer),jwt_header_query('$.alg')
+
+ http-request deny unless { var(txn.jwt_alg) -m beg "PS" }
+
+ http-response set-header x-jwt-token %[var(txn.bearer)]
+ http-response set-header x-jwt-alg %[var(txn.jwt_alg)]
+
+ http-response set-header x-jwt-verify-PS256 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"${testdir}/rsa-public.pem")] if { var(txn.jwt_alg) -m str "PS256" }
+ http-response set-header x-jwt-verify-PS384 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"${testdir}/rsa-public.pem")] if { var(txn.jwt_alg) -m str "PS384" }
+ http-response set-header x-jwt-verify-PS512 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"${testdir}/rsa-public.pem")] if { var(txn.jwt_alg) -m str "PS512" }
+ server s1 ${s1_addr}:${s1_port}
+
+
+ # This backend will only be used to test the http_auth_bearer sample fetch.
+ # No jwt_verify will then be performed.
+ backend auth_bearer_be
+ http-request set-var(txn.bearer) http_auth_bearer("Custom-Authorization")
+
+ http-response set-header x-jwt-token %[var(txn.bearer)]
+
+ server s1 ${s1_addr}:${s1_port}
+
+ # This backend will mostly be used to test error cases (invalid tokens, algorithm and so on)
+ backend dflt_be
+ http-request set-var(txn.bearer) http_auth_bearer
+ http-request set-var(txn.jwt_alg) var(txn.bearer),jwt_header_query('$.alg')
+
+ http-request set-var(txn.jwt_verify) var(txn.bearer),jwt_verify(txn.jwt_alg,"unknown_cert.pem")
+
+ http-response set-header x-jwt-token %[var(txn.bearer)]
+ http-response set-header x-jwt-alg %[var(txn.jwt_alg)]
+ http-response set-header x-jwt-verify %[var(txn.jwt_verify)]
+
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+
+client c1 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"HS256","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # HMAC key : 'hmac key hs256'
+ # OpenSSL cmd : openssl dgst -sha256 -mac HMAC -macopt key:'hmac key hs256' data.txt | base64 | tr -d '=\n' | tr '/+' '_-'
+
+ txreq -url "/hs256" -hdr "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.hhj1mbYgezxFoYwinThsZQbckYHt4jJlRoQ7W8ksrFM"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "HS256"
+ expect resp.http.x-jwt-verify-HS256 == "1"
+} -run
+
+client c2 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"HS384","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # HMAC key : 'hmac key hs384'
+ # OpenSSL cmd : openssl dgst -sha384 -mac HMAC -macopt key:'hmac key hs384' data.txt | base64 | tr -d '=\n' | tr '/+' '_-'
+
+ txreq -url "/hs384" -hdr "Authorization: Bearer eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.3EsbLfl6DDh5nZMkLWg3ssCurFHyOhXP28a4PDS48aPAIoYLzHchtXmNaYI8He-R"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "HS384"
+ expect resp.http.x-jwt-verify-HS384 == "1"
+} -run
+
+client c3 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"HS512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # HMAC key : 'hmac key hs512'
+ # OpenSSL cmd : openssl dgst -sha512 -mac HMAC -macopt key:'hmac key hs512' data.txt | base64 | tr -d '=\n' | tr '/+' '_-'
+
+ txreq -url "/hs512" -hdr "Authorization: Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.K4Yze5N7jeJrDbJymphaH1YsFlYph5F-U75HzBRKDybrN7WBO494EgNG77mAQj4CVci_xbTD_IsqY2umO0f47A"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "HS512"
+ expect resp.http.x-jwt-verify-HS512 == "1"
+} -run
+
+# The following token is invalid (it has three extra characters at the end of the signature)
+client c4 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"HS512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # HMAC key : 'hmac key hs512'
+ # OpenSSL cmd : openssl dgst -sha512 -mac HMAC -macopt key:'hmac key hs512' data.txt | base64 | tr -d '=\n' | tr '/+' '_-'
+
+ txreq -url "/hs512" -hdr "Authorization: Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.K4Yze5N7jeJrDbJymphaH1YsFlYph5F-U75HzBRKDybrN7WBO494EgNG77mAQj4CVci_xbTD_IsqY2umO0f47AAAA"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "HS512"
+ expect resp.http.x-jwt-verify-HS512 == "-3"
+} -run
+
+
+client c5 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"RS256","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # OpenSSL cmd : openssl dgst -sha256 -sign rsa-private.pem data.txt | base64 | tr -d '=\n' | tr '/+' '_-'
+
+ txreq -url "/rs256" -hdr "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.hRqFM87JzV_YinYhdERp2E9BLhl6s7I5J37GTXAeT5fixJx-OCjTFvwKssyVo7fWAFcQMdQU7vGEXDOiWbNaMUFGIsMxx0Uflk0BeNwk6pWvNGk8KZGMtiqOv-IuPdAiaSW_xhxLHIk7eOwVefvBfk8j2hgU9yoHN87AYnl8oEnzrkzwWvEt-x-P2zB4s_VwhF0gbL1G4FsP5hxWL1HWmSFLBpvWaL5Lx3OJE7mLRLRf8TpMwEe4ROakzMpiv9Xk1H3mZth6d2a91F5Bm65MIJpJ7P2kEL3tdS62VRx8DM_SlsFuWcsqryO3CDQquMbwzAvfRgLPy8PBLRLT64wM3mZtue5GI2KUlqSYsSwKwK580b4drosLvAS75l_4jJwdwuQEvVd8Gry3DWS2mKJSMefmGfD-cdty1vvszs5sUa96Gf7Ro5DvkgXtVCKYk8KJLI62YgZd5S3M0ucP5NLBc_flUi4A2B_aSkd7NDM0ELddk0y48pcF95tejcvliGIy1GRRwevdqensXXQrFweFSZVvuKo8c9pcCBVfKTSllgL0lFGyI_vz6dUYt69I1gqWBDeGcA2XQUBJqfX3o9nkhZspA7b7QxMESatoATsM_XmfhbwsyY-sTq25XIGC4awaZHViZr1YFVD6BwNZWBCEBvW5zObiD5h5A5AgWoBv14E"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "RS256"
+ expect resp.http.x-jwt-verify-RS256 == "1"
+} -run
+
+client c6 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"RS384","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # OpenSSL cmd : openssl dgst -sha384 -sign rsa-private.pem data.txt | base64 | tr -d '=\n' | tr '/+' '_-'
+
+ txreq -url "/rs384" -hdr "Authorization: Bearer eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.GuR-v91EMCVvvTTLiE56O0oDAKeQ5JdLqvHtrgOp2MbUtF7zCDutV0LTmMo4qDNVpvTnD3GZfTTGaVUTvW7kIQ3_1iEVAg61qVWkT9rtHHxifDX70RDBKkvNcMWyQH-dFP_FUvCmhCu7q-AzgBT6PHvs5ZqYyQvlQ1gSWZEPFi184dhvcUQrQC6CySEAdOzIryIHH2oQjN_a9lA9V9M_CH3P-AAwFE7NwUE1H1SGIYM4NHcngEZ3B4lBCHOhhgQMpfagcxQjjXv7VfeSqza6OZDpupwlOl34bb0gnFDGMh4hHSS6iHvvwCeCkclbyvKV0Vq0MaRtJuoKRF-_Oww-nKT_bfNtbF6MeOQLNRlYjGCHerWoBtjv3w2KjoLvQ5iGIFI3cEguyrrKNimpovF4Y5uINH0pWdRF99zOwVUlcJBk3RivIb--Y6s47aNFIVWimUpSn-8MSHTla20TYbcdVaZaMur09Cw500jPrOy6jFqVydSnmU6r13NkmCD5-Bl0mgwGtpZcOQExrnIcPQky12kQJAIrffVblvtkd-8FIBPBy1uBKCgkE-q9_suEvBTdvaoTocBmPcIxfPjZUVXeU3UmnRrXEz17pue0YfrwK9CUR9UoP0F5C7O5eSbAtZNm4Hpkiah0w7qugWG3esMgku3-xx0B2xwg6Ul7bAgEJFg"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "RS384"
+ expect resp.http.x-jwt-verify-RS384 == "1"
+} -run
+
+client c7 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"RS512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # OpenSSL cmd : openssl dgst -sha512 -sign rsa-private.pem data.txt | base64 | tr -d '=\n' | tr '/+' '_-'
+
+ txreq -url "/rs512" -hdr "Authorization: Bearer eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.dgUDvxbWXV-q9lVFDVDt6zffrAjCMkKL7UURz-vvc6utCNMEgt8jSkDWi-mt-jmttkD5mwHqUf3HxWPhfjYNmkTok_XL79F5RXhiF_cu_2oDLDc-RuXdrHaRt9xjUIyZhVJMhaMLdmpcAokQlZxc2W6aj92HKzk3EjyHwfdwfKQNgMooXNzxjE9vCHUbahyLZvtPwiqDtYUSnvN_XOpAMUilxByJStwNqdB7MaOxeAzn76nITh6DqD1bNtxBiLzA7MxYdfsUSmXHMLpkWNAhlrcEIJui9PKm9E0OLFD3M7cCqi6rVvzDxvHqXz3-fcXiSJSRrSmSTu1_ok35TT4WwA9SkHpGe2MJ3uc-8CRlYmjDTcLyXWs_d8i3iNozo6xgiwqIkty4HqScTjhXndRQdmiK-RcUfNLM0Iqm6wYgOifWj728_9GCtdjup-C2uVPdwVwuOjwLbzctZLlFqH3i5IGrCfuOOCAcc_vN3REFqSrDEi4-9qpXuh7yk5pOaiCZYr3-uVhmY5neo55_eV8N3NooDyztwkzRtB_DdbaNrqxk3WEHU79Hseg7c1mkXGm6Djqt3dkkrdpbltzRLrnGKxA4-FzccKOT_P27UYmxQSkyfpAQhfH3jpOE0n9-UYyULbMOY7ZIypXUTquJnrZM3rD_NypU7Jg8uBBGqcziZFc"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "RS512"
+ expect resp.http.x-jwt-verify-RS512 == "1"
+} -run
+
+# The following token is invalid (the signature used SHA384 instead of SHA512)
+client c8 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"RS512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # OpenSSL cmd : openssl dgst -sha512 -sign rsa-private.pem data.txt | base64 | tr -d '=\n' | tr '/+' '_-'
+
+ txreq -url "/rs512" -hdr "Authorization: Bearer eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.GuR-v91EMCVvvTTLiE56O0oDAKeQ5JdLqvHtrgOp2MbUtF7zCDutV0LTmMo4qDNVpvTnD3GZfTTGaVUTvW7kIQ3_1iEVAg61qVWkT9rtHHxifDX70RDBKkvNcMWyQH-dFP_FUvCmhCu7q-AzgBT6PHvs5ZqYyQvlQ1gSWZEPFi184dhvcUQrQC6CySEAdOzIryIHH2oQjN_a9lA9V9M_CH3P-AAwFE7NwUE1H1SGIYM4NHcngEZ3B4lBCHOhhgQMpfagcxQjjXv7VfeSqza6OZDpupwlOl34bb0gnFDGMh4hHSS6iHvvwCeCkclbyvKV0Vq0MaRtJuoKRF-_Oww-nKT_bfNtbF6MeOQLNRlYjGCHerWoBtjv3w2KjoLvQ5iGIFI3cEguyrrKNimpovF4Y5uINH0pWdRF99zOwVUlcJBk3RivIb--Y6s47aNFIVWimUpSn-8MSHTla20TYbcdVaZaMur09Cw500jPrOy6jFqVydSnmU6r13NkmCD5-Bl0mgwGtpZcOQExrnIcPQky12kQJAIrffVblvtkd-8FIBPBy1uBKCgkE-q9_suEvBTdvaoTocBmPcIxfPjZUVXeU3UmnRrXEz17pue0YfrwK9CUR9UoP0F5C7O5eSbAtZNm4Hpkiah0w7qugWG3esMgku3-xx0B2xwg6Ul7bAgEJFg"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "RS512"
+ expect resp.http.x-jwt-verify-RS512 == "0"
+} -run
+
+
+
+client c9 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"ES256","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # Key gen process : openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out es256-private.pem; openssl ec -in es256-private.pem -pubout -out es256-public.pem
+ # Token creation : ./build_token.py ES256 '{"sub":"1234567890","name":"John Doe","iat":1516239022}' es256-private.pem
+
+ txreq -url "/es256" -hdr "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.pNI_c5mHE3mLV0YDpstlP4l3t5XARLl6OmcKLuvF5r60m-C63mbgfKWdPjmJPMTCmX_y50YW_v2SKw0ju0tJHw"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "ES256"
+ expect resp.http.x-jwt-verify-ES256 == "1"
+} -run
+
+client c10 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"ES384","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # Key gen process : openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out es384-private.pem; openssl ec -in es384-private.pem -pubout -out es384-public.pem
+ # Token creation : ./build_token.py ES384 '{"sub":"1234567890","name":"John Doe","iat":1516239022}' es384-private.pem
+
+ txreq -url "/es384" -hdr "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.cs59CQiCI_Pl8J-PKQ2y73L5IJascZXkf7MfRXycO1HkT9pqDW2bFr1bh7pFyPA85GaML4BPYVH_zDhcmjSMn_EIvUV8cPDuuUu69Au7n9LYGVkVJ-k7qN4DAR5eLCiU"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "ES384"
+ expect resp.http.x-jwt-verify-ES384 == "1"
+} -run
+
+client c11 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"ES512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # Key gen process : openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-521 -out es512-private.pem; openssl ec -in es512-private.pem -pubout -out es512-public.pem
+ # Token creation : ./build_token.py ES512 '{"sub":"1234567890","name":"John Doe","iat":1516239022}' es512-private.pem
+
+ txreq -url "/es512" -hdr "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.AJcyt0OYf2wg7SggJJVKYysLUkBQA0f0Zc0EbKgud2fQLeT65n42A9l9hhGje79VLWhEyisQmDpFXTpfFXeD_NiaAXyNnX5b8TbZALqxbjx8iIpbcObgUh_g5Gi81bKmRmfXUHW7L5iAwoNjYbUpXGipCpCD0N6-8zCrjcFD2UX01f0Y"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "ES512"
+ expect resp.http.x-jwt-verify-ES512 == "1"
+} -run
+
+
+
+client c12 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"PS256","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # Token creation : ./build_token.py PS256 '{"sub":"1234567890","name":"John Doe","iat":1516239022}' rsa-private.pem
+ txreq -url "/ps256" -hdr "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.eXzN8m41ejgmbtJPhgifU_jMuYwVXL3HsLMOJ_ERipNcuqVQUmfHib1MWydSOYkgNBIm2lK9LjUmRCs1LvMUsbcqnokebFUNmO6IFdbMj3kD4cvqXHyK0yogQ7fdtJZf3_ukcJQ_-IdCG6mwowq6-OLjv-v2EflwPsT33EGmEDuE-7Z8AVTOVPiKUrqq1KqBi7NnnzdghqKfXn4b0yT7CnxQ_GK4F-ghBxBiMXK2J8M6pvS1vof7PyzVQmpeNzn2Rpbk-Ez88WeoTQXqZL1_BeW0z8FeyWXoIiqAzluRHSfZf2iUwrHuiH-tZ5BkAsJXHMDhMoL8_TKdD2hAnCWdVA9W9bQpzfaCbF5xv8lkGcy01ekrh-rN6ZOjItYeDj3BuaQgrKa5YAs_Grei_iSLqAu_YmDiVJxBfv5ahe1I8rwBQ7lIsZqv6p8BKqBFNylLzIFioAtmHJBF0HtItLoj0Mp_bUuU6RLIwf7C8ZWPQVTVsTgHMAlnZLNnQ3vhcxCjLm-r45M3AUFQfMEy1ajiqpFb3z2ElEwiOS9uLYJs3AOAoJDc-e62VJ7tRlw7KB-Vw0mvztvXgYdit48KOxdbn15HQ0lbBM_jJHvbYjDFC0iGUaizBPqmOJcTvObvKv5itEhPT6ffsv9XBnRSv9f3kW_rI7chrCyRZc0nFUvEJ9o"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "PS256"
+ expect resp.http.x-jwt-verify-PS256 == "1"
+} -run
+
+client c13 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"PS384","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # Token creation : ./build_token.py PS384 '{"sub":"1234567890","name":"John Doe","iat":1516239022}' rsa-private.pem
+ txreq -url "/ps384" -hdr "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzM4NCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.f-il5pRvC_vYuJ5jI-q9zxgqStCzvICKJyJEmVSjK47uLtt24SNLsQ1V24gqGuDOkXAhxlVu9rUwvtbzOQbF6N1YFFKbCuJ7zbGG81j5r3IuFl_5y6v077PW3hSNn62WX1GDv8w_kGedAZqGwKhJR7D1CbPBE5v-b4PskVF1V7IrFx8PufS_LUeJq1Etei0iU7H9OWD0yVApE_nmeELy4Kz1cc1fQZTBzd-b6kB562JbUbENM14HoiuKpnZvDtQks93A7y_B14SZPrxDaiVI-fR1n8Ja10wyBqbw8mWzt4s7vkxQI8U0eTBcj6bpWcm6S947G_jjoum_Lu3ZSKXE4UxcZ2IIuM74PEUgWJUjr4f9klB8kplJS5AIXMUNG6QbgZhOdSfZmlfzZUmSt1CLI22rTadXjvn-5CG_VxWJUjcPF9hViFFKQ7qQw3Tcn73ZKf5toK3imQBay4vR11DYWP5flLscFtqPvFcV4qhNarG-kVTI2xO8wXDXEoKeIXvsr3GTmCmBbs-kxvtyI80GUTzKN2I9vp0W9Qo5GNa3DDU1-io3olVwtMFh_0qfhmdO1Rt-j11gGnYTz3S5zMMMG2Ihy8ho3ayNZlZf7MJvVBSPqbCpHdiRa8VgTyYdYvK81lgkSc3wE8CygFEBMEi9b181OKPODlpux6k-3AL_2Hs"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "PS384"
+ expect resp.http.x-jwt-verify-PS384 == "1"
+} -run
+
+client c14 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"PS512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # Token creation : ./build_token.py PS512 '{"sub":"1234567890","name":"John Doe","iat":1516239022}' rsa-private.pem
+ txreq -url "/ps512" -hdr "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzUxMiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.tJZQn0ksGx7vFpBzhNkP8vupyRiAAy5Rf6UdR2MEnO6-iwisbXOUrwwh8XQWngEe2O5FJabCxJRI_shSVEUuWY2Vz6kvRAQ6sWv_4uoPTUk9zjSXkS6C_nb_UY_6tUz39qA-OI80JKcLadvjB66CGWHI00C5Xz2gyWQuFgSItBIV6l0wI6Spf4NJa2Lefo7XbobQ7-u-yzgbIJ1BgXFOTWHYsgJ67n39gj7MDDsUjSaNbFlKfbvGJrdli5_PNNSdoNiF0pdsd6vldnucs5Rfysp4V-nbBzrORuJhl0_BlPG7_Wbap0sm6NCnzp1ks3D5_OWLZxJZNw_TJ2OuVHOX2PNj2MuHjMPDMKKxgxIXQJ8ry39-sk56ZrCJ8UqZofk8NX7Z4ypeWrK62BNSTLY8Le4WzF6dYcuawxiyt7xsC0MkaplXpRFLdmHrMhvyZz6S8BFhtlGD-PnRnEr8qZkThiZSs5kcEW8ryneKlN5TQ7E0H1HekUUii3_T9MtC5rNsT1vzyGr0XAn5TLxeal4Gvp3WyOHs4l7Q1EyQXPkAX8bWwODtLZ3DrREwdLb7Ex2k9wRDF52aww9EMpeLM3at6MQKggWQhNEClahN9AWBj7Vz-RqliWEIdUdNTL3d1JgLX41GZqXjOGZIwiVJwYpVRh1jKVhUn8pN8jCtoeiUxh8"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "PS512"
+ expect resp.http.x-jwt-verify-PS512 == "1"
+} -run
+
+
+
+# The following token is invalid (too short)
+client c15 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"ES512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # OpenSSL cmd : openssl dgst -sha512 -sign es512-private.pem data.txt | base64 | tr -d '=\n' | tr '/+' '_-'
+
+ txreq -url "/es512" -hdr "Authorization: Bearer eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.MIGHAkEEPEgIrFKIDofBpFKX_mtya55QboGr09P6--v8uO85DwQWR0iKgMNSzYkL3K1lwyExG0Vtwfnife0lNe7Fn5TigAJCAY95NShiTn3tvleXVGCkkD0-HcribnMhd34QPGRc4rlwTkUg9umIUhxnEhPR--OohlmhJyIYGHuH8Ksm5f"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "ES512"
+ # Invalid token
+ expect resp.http.x-jwt-verify-ES512 == "-3"
+} -run
+
+# Unknown algorithm
+client c16 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"UNKNOWN_ALG","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJVTktOT1dOX0FMRyIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.MIGHAkEEPEgIrFKIDofBpFKX_mtya55QboGr09P6--v8uO85DwQWR0iKgMNSzYkL3K1lwyExG0Vtwfnife0lNe7Fn5TigAJCAY95NShiTn3tvleXVGCkkD0-HcribnMhd34QPGRc4rlwTkUg9umIUhxnEhPR--OohlmhJyIYGHuH8Ksm5f"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "UNKNOWN_ALG"
+ # Unmanaged algorithm
+ expect resp.http.x-jwt-verify == "-1"
+} -run
+
+# Invalid token (not enough fields)
+client c17 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"ES512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "ES512"
+ # Invalid token
+ expect resp.http.x-jwt-verify == "-3"
+} -run
+
+# Invalid token (too many fields)
+client c18 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"ES512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.MIGHAkEEPEgIrFKIDofBpFKX_mtya55QboGr09P6--v8uO85DwQWR0iKgMNSzYkL3K1lwyExG0Vtwfnife0lNe7Fn5TigAJCAY95NShiTn3tvleXVGCkkD0-HcribnMhd34QPGRc4rlwTkUg9umIUhxnEhPR--OohlmhJyIYGHuH8Ksm5f.unexpectedextrafield"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "ES512"
+ # Invalid token
+ expect resp.http.x-jwt-verify == "-3"
+} -run
+
+# Invalid token (empty signature)
+client c19 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"ES512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ."
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "ES512"
+ # Invalid token
+ expect resp.http.x-jwt-verify == "-3"
+} -run
+
+# Unknown certificate
+client c20 -connect ${h1_mainfe_sock} {
+ # Token content : {"alg":"ES512","typ":"JWT"}
+ # {"sub":"1234567890","name":"John Doe","iat":1516239022}
+ # Key gen process : openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-521 -out es512-private.pem; openssl ec -in es512-private.pem -pubout -out es512-public.pem
+ # OpenSSL cmd : openssl dgst -sha512 -sign es512-private.pem data.txt | base64 | tr -d '=\n' | tr '/+' '_-'
+
+ txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.MIGHAkEEPEgIrFKIDofBpFKX_mtya55QboGr09P6--v8uO85DwQWR0iKgMNSzYkL3K1lwyExG0Vtwfnife0lNe7Fn5TigAJCAY95NShiTn3tvleXVGCkkD0-HcribnMhd34QPGRc4rlwTkUg9umIUhxnEhPR--OohlmhJyIYGHuH8Ksm5fSIWfRa"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-alg == "ES512"
+ # Unknown certificate
+ expect resp.http.x-jwt-verify == "-5"
+} -run
+
+
+# Test the http_auth_bearer special cases (other header than the default "Authorization" one)
+client c21 -connect ${h1_mainfe_sock} {
+ txreq -url "/auth_bearer" -hdr "Custom-Authorization: Bearer random_value"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-token == "random_value"
+} -run
+
+# Test the http_auth_bearer special cases (multiple spaces after the scheme)
+client c22 -connect ${h1_mainfe_sock} {
+ txreq -url "/auth_bearer" -hdr "Custom-Authorization: Bearer random_value"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-token == "random_value"
+} -run
+
+# Test the http_auth_bearer special cases (no value after the scheme)
+client c23 -connect ${h1_mainfe_sock} {
+ txreq -url "/auth_bearer" -hdr "Custom-Authorization: Bearer "
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-token == ""
+} -run
+
+# Test the http_auth_bearer special cases (no value after the scheme)
+client c24 -connect ${h1_mainfe_sock} {
+ txreq -url "/errors" -hdr "Authorization: Bearer "
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-jwt-token == ""
+} -run
diff --git a/reg-tests/jwt/rsa-public.pem b/reg-tests/jwt/rsa-public.pem
new file mode 100644
index 0000000..a87a89d
--- /dev/null
+++ b/reg-tests/jwt/rsa-public.pem
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxCPdKRUDpwNqrka4OYaI
+9bweoN/YoMYR8sddqK39S0pmzVIWZpZ51wXJU7oT4umSGAP0VpexxKNZdKnq6b9S
+caIfLCazl8EaU3Wg16l5ZD/OmHggaD5iHtI3lV2JhxTFlIdLI6sGoJxaDne0oelv
+tsE2dbBZBPT0OPKWyXgL2qQHCtYnqZI7d9czA61rg1PfiUqV6zh9MC7NW5mKPVS9
+5/MCIILyP4smljh5cUGkzhZaBy/mfKobTRe5xTP+DJ78wZhTAapOY/GmyQ4rFWZF
+ISH2tVQ7Ic32lbxeYXycTcPxEUcijNklnFHfpZ3Hhbz9hBuCWTaujcdYVxkRfMoc
+nz9InY8FCic3vgcOPrpqhZMxjeuVwUV9cjJhsWTjZeIne5P4l6DHmDIdoVJVatKR
++O4AL2q+VZ+d5euSmUe6bwrz1ufczIcRYAo1mnYD+USwjT5rGWSjG8brtfxtrzJz
+QP4oqMgLH2QBEgVDKlvsHiEC2K16tTf1pSEAh9Lyo2t8Tbc1BbuuJPafixNGFEQI
+J7sAwYoWNkncGOfwrPUpU13KtAGoW8hMBlLSuGb70FLbei/Qiz/YsWi86ybetN4W
+MpF096lcgqa/JH8IeYvGa/MQYoavloGv05OhaGrvGRy0GV6I9elnLEaSdBROnA4k
+yPaHW8jKmj04T8EBFmx5Lu0CAwEAAQ==
+-----END PUBLIC KEY-----
diff --git a/reg-tests/log/last_rule.vtc b/reg-tests/log/last_rule.vtc
new file mode 100644
index 0000000..f2b89e4
--- /dev/null
+++ b/reg-tests/log/last_rule.vtc
@@ -0,0 +1,165 @@
+varnishtest "Verify logging of last final rule"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.6-dev0)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -repeat 15 -start
+
+syslog Slg_1 -level info {
+ recv
+ # /trqacc1
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:30"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:31"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:32"
+ recv
+ # /trsacc1
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:36"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:37"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:38"
+ recv
+ # /hrqvar
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*-:-"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:41"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:42"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:43"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:44"
+ recv
+ # /hrsacc1
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:46"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:47"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:48"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* lr=.*/h1/cfg:49"
+} -start
+
+haproxy h1 -conf {
+ global
+ nbthread 1
+
+ defaults
+ mode http
+ option httplog
+ option http-server-close
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe_1}"
+ log ${Slg_1_addr}:${Slg_1_port} local0
+ log-format "ci:%cp [%tr] lr=%[last_rule_file]:%[last_rule_line]"
+ default_backend be
+
+ backend be
+ # handle these URLs:
+ # /trqacc1, /trqrej1, /trqrej2, /trsacc1, /trsrej1, /trsrej2
+ # /hrqvar, /hrqacc1, /hrqred1, /hrqrej1, /hrqrej2,
+ # /hrsacc1, /hrsred1, /hrsrej1, /hrsrej2
+
+ tcp-response inspect-delay 100ms
+ tcp-request content set-var(txn.path) path # must have no effect
+ tcp-request content accept if { var(txn.path) -m beg /trqacc1 /hrqrej1 }
+ tcp-request content reject if { var(txn.path) -m beg /trqrej1 }
+ tcp-request content reject if { var(txn.path) -m beg /trqrej2 }
+
+ tcp-response content reject unless WAIT_END
+ tcp-response content set-var(txn.foo) var(txn.path) # must have no effect
+ tcp-response content accept if { var(txn.path) -m beg /trsacc1 /hrsrej1 }
+ tcp-response content reject if { var(txn.path) -m beg /trsrej1 }
+ tcp-response content reject if { var(txn.path) -m beg /trsrej2 }
+
+ http-request set-var(txn.bar) var(txn.path) if { path_beg /hrqvar } # must have no effect
+ http-request allow if { var(txn.path) -m beg /hrqacc1 /hrsrej2 }
+ http-request redirect location / if { var(txn.path) -m beg /hrqred1 }
+ http-request deny if { var(txn.path) -m beg /hrqrej1 } # accepted by tcp-rq above
+ http-request deny if { var(txn.path) -m beg /hrqrej2 }
+
+ http-response allow if { var(txn.path) -m beg /hrsacc1 }
+ http-response redirect location / if { var(txn.path) -m beg /hrsred1 }
+ http-response deny if { var(txn.path) -m beg /hrsrej1 } # accepted by tcp-rs above
+ http-response deny if { var(txn.path) -m beg /hrsrej2 } # accepted by http-rq above
+ http-response deny if { var(txn.path) -m beg /hrsrej3 }
+
+ server app1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_1_sock} {
+ txreq -url /trqacc1
+ rxresp
+
+ txreq -url /trqrej1
+ expect_close
+} -run
+
+# The following client are started in background and synchronized
+client c2 -connect ${h1_fe_1_sock} {
+ txreq -url /trqrej2
+ expect_close
+} -run
+
+client c3 -connect ${h1_fe_1_sock} {
+ txreq -url /trsacc1
+ rxresp
+ expect resp.status == 200
+
+ txreq -url /trsrej1
+ expect_close
+} -run
+
+client c4 -connect ${h1_fe_1_sock} {
+ txreq -url /trsrej2
+ expect_close
+} -run
+
+client c5 -connect ${h1_fe_1_sock} {
+ txreq -url /hrqvar
+ rxresp
+ expect resp.status == 200
+
+ txreq -url /hrqacc1
+ rxresp
+ expect resp.status == 200
+
+ txreq -url /hrqred1
+ rxresp
+ expect resp.status == 302
+
+ txreq -url /hrqrej1
+ rxresp
+ expect resp.status == 403
+
+ txreq -url /hrqrej2
+ rxresp
+ expect resp.status == 403
+
+ txreq -url /hrsacc1
+ rxresp
+ expect resp.status == 200
+
+ txreq -url /hrsred1
+ rxresp
+ expect resp.status == 302
+
+ txreq -url /hrsrej1
+ rxresp
+ expect resp.status == 502
+
+ txreq -url /hrsrej2
+ rxresp
+ expect resp.status == 502
+} -run
+
+syslog Slg_1 -wait
diff --git a/reg-tests/log/load_balancing.vtc b/reg-tests/log/load_balancing.vtc
new file mode 100644
index 0000000..5c56e65
--- /dev/null
+++ b/reg-tests/log/load_balancing.vtc
@@ -0,0 +1,159 @@
+varnishtest "Basic log load-balancing test"
+feature ignore_unknown_macro
+
+barrier b1 cond 2 -cyclic
+barrier b2 cond 2 -cyclic
+barrier b3 cond 2 -cyclic
+barrier b4 cond 2 -cyclic
+barrier b5 cond 2 -cyclic
+
+server s1 {
+ rxreq
+ txresp
+} -repeat 500 -start
+
+syslog Slg_1 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c1 HTTP/1.1\""
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c2 HTTP/1.1\""
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c3 HTTP/1.1\""
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c4 HTTP/1.1\""
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c5 HTTP/1.1\""
+} -repeat 50 -start
+
+# Here are the syslog messages received by Slg_2:
+syslog Slg_2 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c6 HTTP/1.1\""
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c8 HTTP/1.1\""
+} -repeat 50 -start
+
+haproxy h1 -conf {
+ global
+ nbthread 1
+
+ defaults
+ mode http
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe_1}"
+ log ${Slg_1_addr}:${Slg_1_port} local0
+ default_backend be
+
+ frontend fe2
+ bind "fd@${fe_2}"
+ log ${Slg_2_addr}:${Slg_2_port} sample 1,3:5 local0
+ default_backend be
+
+ backend be
+ server app1 ${s1_addr}:${s1_port}
+} -start
+
+# The following client are started in background and synchronized
+client c1 -connect ${h1_fe_1_sock} {
+ txreq -url "/client_c1"
+ rxresp
+ expect resp.status == 200
+ barrier b1 sync
+ barrier b5 sync
+} -repeat 50 -start
+
+client c2 -connect ${h1_fe_1_sock} {
+ barrier b1 sync
+ txreq -url "/client_c2"
+ rxresp
+ expect resp.status == 200
+ barrier b2 sync
+} -repeat 50 -start
+
+client c3 -connect ${h1_fe_1_sock} {
+ barrier b2 sync
+ txreq -url "/client_c3"
+ rxresp
+ expect resp.status == 200
+ barrier b3 sync
+} -repeat 50 -start
+
+client c4 -connect ${h1_fe_1_sock} {
+ barrier b3 sync
+ txreq -url "/client_c4"
+ rxresp
+ expect resp.status == 200
+ barrier b4 sync
+} -repeat 50 -start
+
+client c5 -connect ${h1_fe_1_sock} {
+ barrier b4 sync
+ txreq -url "/client_c5"
+ rxresp
+ expect resp.status == 200
+ barrier b5 sync
+} -repeat 50 -start
+
+syslog Slg_1 -wait
+
+client c1 -wait
+client c2 -wait
+client c3 -wait
+client c4 -wait
+client c5 -wait
+
+# Same test as before but with fe2 frontend.
+# The following client are started in background and synchronized
+client c6 -connect ${h1_fe_2_sock} {
+ txreq -url "/client_c6"
+ rxresp
+ expect resp.status == 200
+ barrier b1 sync
+ barrier b5 sync
+} -repeat 50 -start
+
+client c7 -connect ${h1_fe_2_sock} {
+ barrier b1 sync
+ txreq -url "/client_c7"
+ rxresp
+ expect resp.status == 200
+ barrier b2 sync
+} -repeat 50 -start
+
+client c8 -connect ${h1_fe_2_sock} {
+ barrier b2 sync
+ txreq -url "/client_c8"
+ rxresp
+ expect resp.status == 200
+ barrier b3 sync
+} -repeat 50 -start
+
+client c9 -connect ${h1_fe_2_sock} {
+ barrier b3 sync
+ txreq -url "/client_c9"
+ rxresp
+ expect resp.status == 200
+ barrier b4 sync
+} -repeat 50 -start
+
+client c10 -connect ${h1_fe_2_sock} {
+ barrier b4 sync
+ txreq -url "/client_c10"
+ rxresp
+ expect resp.status == 200
+ barrier b5 sync
+} -repeat 50 -start
+
+syslog Slg_2 -wait
+
+client c6 -wait
+client c7 -wait
+client c8 -wait
+client c9 -wait
+client c10 -wait
+
diff --git a/reg-tests/log/log_backend.vtc b/reg-tests/log/log_backend.vtc
new file mode 100644
index 0000000..a9223ee
--- /dev/null
+++ b/reg-tests/log/log_backend.vtc
@@ -0,0 +1,185 @@
+varnishtest "Test the log backend target"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.9-dev0)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -repeat 500 -start
+
+syslog Slg1 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /0 HTTP/1.1\""
+} -repeat 100 -start
+
+syslog Slg2 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /1 HTTP/1.1\""
+} -repeat 100 -start
+
+syslog Slg21 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /srv1 HTTP/1.1\""
+} -repeat 1 -start
+
+syslog Slg22 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /srv2 HTTP/1.1\""
+} -repeat 1 -start
+
+syslog Slg23 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /srv3 HTTP/1.1\""
+} -repeat 2 -start
+
+syslog Slg24 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /backup HTTP/1.1\""
+} -repeat 1 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe_1}"
+ log backend@mylog-tcp local0
+ log backend@mylog-udp local0
+ default_backend be
+
+ frontend fe2
+ bind "fd@${fe_2}"
+ log backend@mylog-failover local0
+ default_backend be
+
+ backend be
+ server app1 ${s1_addr}:${s1_port}
+
+ backend mylog-tcp
+ mode log
+ server s1 tcp@127.0.0.1:1514 #TCP: to log-forward
+
+ backend mylog-udp
+ mode log
+
+ # extract id (integer) from URL in the form "GET /id" and use it as hash key
+ balance log-hash 'field(-2,\"),field(2,/),field(1, )'
+ hash-type map-based none
+
+ server s1 udp@${Slg1_addr}:${Slg1_port} # syslog 1 only receives "GET /0" requests
+ server s2 udp@${Slg2_addr}:${Slg2_port} # syslog 2 only receives "GET /1" requests
+
+ log-forward syslog2udp
+ bind 127.0.0.1:1514
+ log backend@mylog-udp local0 # Back to UDP log backend
+
+ backend mylog-failover
+ mode log
+ balance sticky
+
+ server s1 udp@${Slg21_addr}:${Slg21_port} # only receives "GET /srv1" request
+ server s2 udp@${Slg22_addr}:${Slg22_port} # only receives "GET /srv2" request
+ server s3 udp@${Slg23_addr}:${Slg23_port} # only receives "GET /srv3" request
+
+ server s4 udp@${Slg24_addr}:${Slg24_port} backup # only receives "GET /backup" request
+} -start
+
+# Test log distribution reliability
+
+# all logs should go to s1
+client c1 -connect ${h1_fe_1_sock} {
+ txreq -url "/0"
+ rxresp
+ expect resp.status == 200
+} -repeat 50 -start
+
+# all logs should go to s2
+client c2 -connect ${h1_fe_1_sock} {
+ txreq -url "/1"
+ rxresp
+ expect resp.status == 200
+} -repeat 50 -start
+
+syslog Slg1 -wait
+syslog Slg2 -wait
+
+# Test server queue/dequeue/failover mechanism
+
+# s1 should handle this
+client c21 -connect ${h1_fe_2_sock} {
+ txreq -url "/srv1"
+ rxresp
+ expect resp.status == 200
+} -run
+
+haproxy h1 -cli {
+ send "disable server mylog-failover/s1"
+ expect ~ ".*"
+}
+
+# s2 should handle this
+client c22 -connect ${h1_fe_2_sock} {
+ txreq -url "/srv2"
+ rxresp
+ expect resp.status == 200
+} -run
+
+haproxy h1 -cli {
+ send "disable server mylog-failover/s2"
+ expect ~ ".*"
+}
+
+haproxy h1 -cli {
+ send "enable server mylog-failover/s1"
+ expect ~ ".*"
+}
+
+# s3 should handle this
+client c23 -connect ${h1_fe_2_sock} {
+ txreq -url "/srv3"
+ rxresp
+ expect resp.status == 200
+} -run
+
+haproxy h1 -cli {
+ send "disable server mylog-failover/s1"
+ expect ~ ".*"
+}
+
+haproxy h1 -cli {
+ send "disable server mylog-failover/s3"
+ expect ~ ".*"
+}
+
+# backup should handle this
+client c24 -connect ${h1_fe_2_sock} {
+ txreq -url "/backup"
+ rxresp
+ expect resp.status == 200
+} -run
+
+haproxy h1 -cli {
+ send "enable server mylog-failover/s3"
+ expect ~ ".*"
+}
+
+haproxy h1 -cli {
+ send "enable server mylog-failover/s2"
+ expect ~ ".*"
+}
+
+# s3 should handle this
+client c25 -connect ${h1_fe_2_sock} {
+ txreq -url "/srv3"
+ rxresp
+ expect resp.status == 200
+} -run
+
+syslog Slg21 -wait
+syslog Slg22 -wait
+syslog Slg23 -wait
+syslog Slg24 -wait
diff --git a/reg-tests/log/log_forward.vtc b/reg-tests/log/log_forward.vtc
new file mode 100644
index 0000000..3977f4c
--- /dev/null
+++ b/reg-tests/log/log_forward.vtc
@@ -0,0 +1,57 @@
+varnishtest "Test the TCP load-forward"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.3-dev1)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -repeat 500 -start
+
+syslog Slg1 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c1 HTTP/1.1\""
+} -repeat 50 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe_1}"
+ log 127.0.0.1:1514 local0
+# log ${Slg1_addr}:${Slg1_port} local0
+ default_backend be
+
+ backend be
+ server app1 ${s1_addr}:${s1_port}
+
+ ring myring
+ description "My local buffer"
+ format rfc5424
+ maxlen 1200
+ size 32764
+ timeout connect 5s
+ timeout server 10s
+ # syslog tcp server
+ server mysyslogsrv 127.0.0.1:2514
+
+ log-forward syslog2tcp
+ dgram-bind 127.0.0.1:1514
+ log ring@myring local0 # To TCP log
+
+ log-forward syslog2local
+ bind 127.0.0.1:2514
+ log ${Slg1_addr}:${Slg1_port} local0 # To VTest syslog
+} -start
+
+client c1 -connect ${h1_fe_1_sock} {
+ txreq -url "/client_c1"
+ rxresp
+ expect resp.status == 200
+} -repeat 50 -start
+
+syslog Slg1 -wait
diff --git a/reg-tests/log/log_uri.vtc b/reg-tests/log/log_uri.vtc
new file mode 100644
index 0000000..6dd50d2
--- /dev/null
+++ b/reg-tests/log/log_uri.vtc
@@ -0,0 +1,61 @@
+varnishtest "Verify logging of relative/absolute URI path"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close"
+} -repeat 4 -start
+
+syslog Slg_1 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* hpo=/r/1 hp=/r/1 hu=/r/1 hq="
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* hpo=/r/2 hp=/r/2 hu=/r/2\\?q=2 hq=\\?q=2"
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* hpo=/r/3 hp=http://localhost/r/3 hu=http://localhost/r/3 hq="
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* hpo=/r/4 hp=http://localhost/r/4 hu=http://localhost/r/4\\?q=4 hq=\\?q=4"
+} -start
+
+haproxy h1 -conf {
+ global
+ nbthread 1
+
+ defaults
+ mode http
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe_1}"
+ log ${Slg_1_addr}:${Slg_1_port} local0
+ log-format "ci:%cp [%tr] hpo=%HPO hp=%HP hu=%HU hq=%HQ"
+ default_backend be
+
+ backend be
+ server app1 ${s1_addr}:${s1_port}
+} -start
+
+# The following client are started in background and synchronized
+client c1 -connect ${h1_fe_1_sock} {
+ txreq -url "/r/1"
+ rxresp
+ expect resp.status == 200
+ txreq -url "/r/2?q=2"
+ rxresp
+ expect resp.status == 200
+ txreq -url "http://localhost/r/3" -hdr "host: localhost"
+ rxresp
+ expect resp.status == 200
+ txreq -url "http://localhost/r/4?q=4" -hdr "host: localhost"
+ rxresp
+ expect resp.status == 200
+} -start
+
+syslog Slg_1 -wait
+
+client c1 -wait
diff --git a/reg-tests/log/wrong_ip_port_logging.vtc b/reg-tests/log/wrong_ip_port_logging.vtc
new file mode 100644
index 0000000..af8ca84
--- /dev/null
+++ b/reg-tests/log/wrong_ip_port_logging.vtc
@@ -0,0 +1,62 @@
+# commit d02286d
+# BUG/MINOR: log: pin the front connection when front ip/ports are logged
+#
+# Mathias Weiersmueller reported an interesting issue with logs which Lukas
+# diagnosed as dating back from commit 9b061e332 (1.5-dev9). When front
+# connection information (ip, port) are logged in TCP mode and the log is
+# emitted at the end of the connection (eg: because %B or any log tag
+# requiring LW_BYTES is set), the log is emitted after the connection is
+# closed, so the address and ports cannot be retrieved anymore.
+#
+# It could be argued that we'd make a special case of these to immediately
+# retrieve the source and destination addresses from the connection, but it
+# seems cleaner to simply pin the front connection, marking it "tracked" by
+# adding the LW_XPRT flag to mention that we'll need some of these elements
+# at the last moment. Only LW_FRTIP and LW_CLIP are affected. Note that after
+# this change, LW_FRTIP could simply be removed as it's not used anywhere.
+#
+# Note that the problem doesn't happen when using %[src] or %[dst] since
+# all sample expressions set LW_XPRT.
+
+#REGTEST_TYPE=bug
+
+varnishtest "Wrong ip/port logging"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ delay 0.02
+} -start
+
+syslog Slg_1 -level notice {
+ recv info
+ expect ~ \"dip\":\"${h1_fe_1_addr}\",\"dport\":\"${h1_fe_1_port}.*\"ts\":\"[cC]D\",\"
+} -start
+
+haproxy h1 -conf {
+ global
+ log ${Slg_1_addr}:${Slg_1_port} local0
+
+defaults
+ log global
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client 1
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+frontend fe1
+ bind "fd@${fe_1}"
+ mode tcp
+ log-format {\"dip\":\"%fi\",\"dport\":\"%fp\",\"c_ip\":\"%ci\",\"c_port\":\"%cp\",\"fe_name\":\"%ft\",\"be_name\":\"%b\",\"s_name\":\"%s\",\"ts\":\"%ts\",\"bytes_read\":\"%B\"}
+ default_backend be_app
+
+backend be_app
+ server app1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_1_sock} {
+ txreq -url "/"
+ expect_close
+} -run
+
+syslog Slg_1 -wait
+
diff --git a/reg-tests/lua/bad_http_clt_req_duration.lua b/reg-tests/lua/bad_http_clt_req_duration.lua
new file mode 100644
index 0000000..2c2ab1d
--- /dev/null
+++ b/reg-tests/lua/bad_http_clt_req_duration.lua
@@ -0,0 +1,8 @@
+core.register_service("foo.http", "http", function(applet)
+ core.msleep(10)
+ applet:start_response()
+end)
+
+core.register_service("foo.tcp", "tcp", function(applet)
+ applet:send("HTTP/1.1 200 OK\r\nTransfer-encoding: chunked\r\n\r\n0\r\n\r\n")
+end)
diff --git a/reg-tests/lua/bad_http_clt_req_duration.vtc b/reg-tests/lua/bad_http_clt_req_duration.vtc
new file mode 100644
index 0000000..5cfdf1a
--- /dev/null
+++ b/reg-tests/lua/bad_http_clt_req_duration.vtc
@@ -0,0 +1,76 @@
+# commit 7b6cc52784526c32efda44b873a4258d3ae0b8c7
+# BUG/MINOR: lua: Bad HTTP client request duration.
+#
+# HTTP LUA applet callback should not update the date on which the HTTP client requests
+# arrive. This was done just after the LUA applet has completed its job.
+#
+# This patch simply removes the affected statement. The same fix has been applied
+# to TCP LUA applet callback.
+#
+# To reproduce this issue, as reported by Patrick Hemmer, implement an HTTP LUA applet
+# which sleeps a bit before replying:
+#
+# core.register_service("foo", "http", function(applet)
+# core.msleep(100)
+# applet:set_status(200)
+# applet:start_response()
+# end)
+#
+# This had as a consequence to log %TR field with approximately the same value as
+# the LUA sleep time.
+
+varnishtest "LUA bug"
+#REQUIRE_OPTIONS=LUA
+#REGTEST_TYPE=bug
+
+feature ignore_unknown_macro
+
+syslog Slog {
+ recv info
+ expect ~ "[^:\\[ ]\\[[0-9]*\\]: Ta=[0-9]* Tc=[0-9]* Td=[0-9]* Th=[0-9]* Ti=[0-9]* Tq=[0-9]* TR=[0-9]* Tr=[0-9]* Tt=[0-9]* Tw=[0-9]*$"
+
+ recv info
+ expect ~ "[^:\\[ ]\\[[0-9]*\\]: Tc=[0-9]* Td=[0-9]* Th=[0-9]* Tt=[0-9]* Tw=[0-9]*$"
+} -start
+
+haproxy h1 -conf {
+ global
+ lua-load ${testdir}/bad_http_clt_req_duration.lua
+
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend f1
+ mode http
+ bind "fd@${f1}"
+ log ${Slog_addr}:${Slog_port} daemon
+ log-format Ta=%Ta\ Tc=%Tc\ Td=%Td\ Th=%Th\ Ti=%Ti\ Tq=%Tq\ TR=%TR\ Tr=%Tr\ Tt=%Tt\ Tw=%Tw
+ default_backend b1
+
+ backend b1
+ mode http
+ http-request use-service lua.foo.http
+
+ frontend f2
+ mode tcp
+ bind "fd@${f2}"
+ log ${Slog_addr}:${Slog_port} daemon
+ log-format Tc=%Tc\ Td=%Td\ Th=%Th\ Tt=%Tt\ Tw=%Tw
+
+ tcp-request inspect-delay 1s
+ tcp-request content use-service lua.foo.tcp
+} -start
+
+client c1 -connect "${h1_f1_sock}" {
+ txreq
+ rxresp
+} -run
+
+client c2 -connect "${h1_f2_sock}" {
+ txreq
+ rxresp
+} -run
+
+syslog Slog -wait
diff --git a/reg-tests/lua/close_wait_lf.lua b/reg-tests/lua/close_wait_lf.lua
new file mode 100644
index 0000000..cc897e7
--- /dev/null
+++ b/reg-tests/lua/close_wait_lf.lua
@@ -0,0 +1 @@
+core.register_service("donothing", "http", function(applet) end)
diff --git a/reg-tests/lua/close_wait_lf.vtc b/reg-tests/lua/close_wait_lf.vtc
new file mode 100644
index 0000000..7bed3fd
--- /dev/null
+++ b/reg-tests/lua/close_wait_lf.vtc
@@ -0,0 +1,53 @@
+# commit 70d318c
+# BUG/MEDIUM: lua: possible CLOSE-WAIT state with '\n' headers
+#
+# The Lua parser doesn't takes in account end-of-headers containing
+# only '\n'. It expects always '\r\n'. If a '\n' is processes the Lua
+# parser considers it miss 1 byte, and wait indefinitely for new data.
+#
+# When the client reaches their timeout, it closes the connection.
+# This close is not detected and the connection keep in CLOSE-WAIT
+# state.
+#
+# I guess that this patch fix only a visible part of the problem.
+# If the Lua HTTP parser wait for data, the timeout server or the
+# connectio closed by the client may stop the applet.
+
+varnishtest "possible CLOSE-WAIT with '\n' headers"
+#REQUIRE_OPTIONS=LUA
+#REGTEST_TYPE=bug
+
+feature ignore_unknown_macro
+
+syslog Slog -level info -repeat 100 {
+ recv info
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Ta=[0-9]* Tc=[0-9]* Td=[0-9]* Th=[0-9]* Ti=[0-9]* Tq=[0-9]* TR=[0-9]* Tr=[0-9]* Tt=[0-9]* Tw=[0-9]*"
+} -start
+
+haproxy h1 -conf {
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ global
+ lua-load ${testdir}/close_wait_lf.lua
+
+ frontend frt
+ log ${Slog_addr}:${Slog_port} local0 debug err
+ log-format Ta=%Ta\ Tc=%Tc\ Td=%Td\ Th=%Th\ Ti=%Ti\ Tq=%Tq\ TR=%TR\ Tr=%Tr\ Tt=%Tt\ Tw=%Tw
+ mode http
+ bind "fd@${frt}"
+ http-request use-service lua.donothing
+} -start
+
+
+client c1 -connect ${h1_frt_sock} -repeat 100 {
+ send "GET / HTTP/1.1\n\n"
+} -run
+
+syslog Slog -wait
+
+shell {
+ ss -pt | grep CLOSE-WAIT.*haproxy.*pid=${h1_pid}
+ exit $((!$?))
+}
diff --git a/reg-tests/lua/common.pem b/reg-tests/lua/common.pem
new file mode 120000
index 0000000..a4433d5
--- /dev/null
+++ b/reg-tests/lua/common.pem
@@ -0,0 +1 @@
+../ssl/common.pem \ No newline at end of file
diff --git a/reg-tests/lua/h_txn_get_priv.lua b/reg-tests/lua/h_txn_get_priv.lua
new file mode 100644
index 0000000..999ea88
--- /dev/null
+++ b/reg-tests/lua/h_txn_get_priv.lua
@@ -0,0 +1,15 @@
+core.register_action("bug", { "http-res" }, function(txn)
+ data = txn:get_priv()
+ if not data then
+ data = 0
+ end
+ data = data + 1
+ print(string.format("set to %d", data))
+ txn.http:res_set_status(200 + data)
+ txn:set_priv(data)
+end)
+
+core.register_service("fakeserv", "http", function(applet)
+ applet:set_status(200)
+ applet:start_response()
+end)
diff --git a/reg-tests/lua/h_txn_get_priv.vtc b/reg-tests/lua/h_txn_get_priv.vtc
new file mode 100644
index 0000000..bd8c069
--- /dev/null
+++ b/reg-tests/lua/h_txn_get_priv.vtc
@@ -0,0 +1,33 @@
+varnishtest "Lua: txn:get_priv() scope"
+#REQUIRE_OPTIONS=LUA
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ lua-load ${testdir}/h_txn_get_priv.lua
+
+ frontend fe1
+ mode http
+ bind "fd@${fe1}"
+ default_backend b1
+
+ http-response lua.bug
+
+ backend b1
+ mode http
+ http-request use-service lua.fakeserv
+} -start
+
+client c0 -connect ${h1_fe1_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 201
+ txreq -url "/"
+ rxresp
+ expect resp.status == 201
+}
+
+client c0 -start
+
+client c0 -wait
diff --git a/reg-tests/lua/httpclient_action.lua b/reg-tests/lua/httpclient_action.lua
new file mode 100644
index 0000000..9a7209c
--- /dev/null
+++ b/reg-tests/lua/httpclient_action.lua
@@ -0,0 +1,8 @@
+function test()
+ local httpclient = core.httpclient()
+ local response = httpclient:get{url="http://127.0.0.1", headers={ [ "Host" ] = { "localhost" } }}
+
+end
+
+
+core.register_action("test", {"tcp-req"}, test, 0)
diff --git a/reg-tests/lua/httpclient_action.vtc b/reg-tests/lua/httpclient_action.vtc
new file mode 100644
index 0000000..11c7d62
--- /dev/null
+++ b/reg-tests/lua/httpclient_action.vtc
@@ -0,0 +1,39 @@
+varnishtest "Lua: test the httpclient when the lua action timeout"
+#
+# Start an httpclient from "lua.test" whose lua task will expire before the
+# httpclient is ended.
+
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev7)'"
+feature ignore_unknown_macro
+
+#REQUIRE_OPTIONS=LUA
+
+haproxy h1 -conf {
+
+ global
+ lua-load ${testdir}/httpclient_action.lua
+ defaults
+ mode tcp
+ timeout http-request 10s
+ timeout queue 1m
+ timeout connect 10s
+ timeout client 1m
+ timeout server 1m
+ timeout check 10s
+
+ listen li1
+ mode http
+ bind "fd@${fe1}"
+ tcp-request inspect-delay 10ms
+ tcp-request content lua.test
+ http-request return status 503
+
+} -start
+
+client c0 -connect ${h1_fe1_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
diff --git a/reg-tests/lua/lua_httpclient.lua b/reg-tests/lua/lua_httpclient.lua
new file mode 100644
index 0000000..b5a5180
--- /dev/null
+++ b/reg-tests/lua/lua_httpclient.lua
@@ -0,0 +1,49 @@
+
+local vtc_port = 0
+local vtc_port2 = 0
+local vtc_port3 = 0
+
+core.register_service("fakeserv", "http", function(applet)
+ vtc_port = applet.headers["vtcport"][0]
+ vtc_port2 = applet.headers["vtcport2"][0]
+ vtc_port3 = applet.headers["vtcport3"][0]
+ core.Info("APPLET START")
+ local response = "OK"
+ applet:add_header("Server", "haproxy/webstats")
+ applet:add_header("Content-Length", string.len(response))
+ applet:add_header("Content-Type", "text/html")
+ applet:start_response()
+ applet:send(response)
+ core.Info("APPLET DONE")
+end)
+
+local function cron()
+ -- wait for until the correct port is set through the c0 request..
+ while vtc_port == 0 do
+ core.msleep(1)
+ end
+ core.Debug('CRON port:' .. vtc_port)
+
+ local body = ""
+
+ for i = 0, 2000 do
+ body = body .. i .. ' ABCDEFGHIJKLMNOPQRSTUVWXYZ\n'
+ end
+ core.Info("First httpclient request")
+ local httpclient = core.httpclient()
+ local response = httpclient:post{url="http://127.0.0.1:" .. vtc_port, body=body}
+ core.Info("Received: " .. response.body)
+
+ body = response.body
+
+ core.Info("Second httpclient request")
+ local httpclient2 = core.httpclient()
+ local response2 = httpclient2:post{url="http://127.0.0.1:" .. vtc_port2, body=body}
+
+ core.Info("Third httpclient request")
+ local httpclient3 = core.httpclient()
+ local response3 = httpclient3:get{url="http://127.0.0.1", dst = vtc_port3, headers={ [ "Host" ] = { "foobar.haproxy.local" } }}
+
+end
+
+core.register_task(cron)
diff --git a/reg-tests/lua/lua_httpclient.vtc b/reg-tests/lua/lua_httpclient.vtc
new file mode 100644
index 0000000..0a27493
--- /dev/null
+++ b/reg-tests/lua/lua_httpclient.vtc
@@ -0,0 +1,68 @@
+varnishtest "Lua: check httpclient functionality from a lua-task"
+
+# A request if first made with c0 with the port of s1 and s2 so the httpclient
+# can generate its URI with it.
+#
+# This reg-test sends a payload with the httpclient to s1, s1 returns another
+# payload. The 2nd lua httpclient sends back the payload from s1 to s2.
+#
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev7)'"
+feature ignore_unknown_macro
+
+#REQUIRE_OPTIONS=LUA
+
+server s1 {
+ rxreq
+ txresp -bodylen 54000
+ expect req.body ~ ".*0 ABCDEFGHIJKLMNOPQRSTUVWXYZ.*"
+ expect req.body ~ ".*500 ABCDEFGHIJKLMNOPQRSTUVWXYZ.*"
+ expect req.body ~ ".*1000 ABCDEFGHIJKLMNOPQRSTUVWXYZ.*"
+ expect req.body ~ ".*1500 ABCDEFGHIJKLMNOPQRSTUVWXYZ.*"
+ expect req.body ~ ".*2000 ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+} -start
+
+server s2 {
+ rxreq
+ txresp
+ expect req.bodylen == 54000
+} -start
+
+server s3 {
+ rxreq
+ txresp -bodylen 54000
+ expect req.method == "GET"
+ expect req.http.host == "foobar.haproxy.local"
+} -start
+
+
+haproxy h1 -conf {
+ global
+ lua-load ${testdir}/lua_httpclient.lua
+
+ frontend fe1
+ mode http
+ bind "fd@${fe1}"
+ default_backend b1
+
+ backend b1
+ mode http
+ http-request use-service lua.fakeserv
+
+ listen li1
+ mode http
+ bind unix@${tmpdir}/srv3
+ server srv3 ${s3_addr}:${s3_port}
+
+} -start
+
+client c0 -connect ${h1_fe1_sock} {
+ txreq -url "/" -hdr "vtcport: ${s1_port}" -hdr "vtcport2: ${s2_port}" -hdr "vtcport3: unix@${tmpdir}/srv3"
+ rxresp
+ expect resp.status == 200
+} -run
+
+
+server s1 -wait
+server s2 -wait
+server s3 -wait
diff --git a/reg-tests/lua/lua_socket.lua b/reg-tests/lua/lua_socket.lua
new file mode 100644
index 0000000..3ad14fe
--- /dev/null
+++ b/reg-tests/lua/lua_socket.lua
@@ -0,0 +1,44 @@
+
+local vtc_port = 0
+
+core.register_service("fakeserv", "http", function(applet)
+ vtc_port = applet.headers["vtcport"][0]
+ core.Info("APPLET START")
+ local response = "OK"
+ applet:add_header("Server", "haproxy/webstats")
+ applet:add_header("Content-Length", string.len(response))
+ applet:add_header("Content-Type", "text/html")
+ applet:start_response()
+ applet:send(response)
+ core.Info("APPLET DONE")
+end)
+
+local function cron()
+ -- wait for until the correct port is set through the c0 request..
+ while vtc_port == 0 do
+ core.msleep(1)
+ end
+ core.Debug('CRON port:' .. vtc_port)
+
+ local socket = core.tcp()
+ local success = socket:connect("127.0.0.1", vtc_port)
+ core.Info("SOCKET MADE ".. (success or "??"))
+ if success ~= 1 then
+ core.Info("CONNECT SOCKET FAILED?")
+ return
+ end
+ local request = "GET / HTTP/1.1\r\n\r\n"
+ core.Info("SENDING REQUEST")
+ socket:send(request)
+ local result = ""
+ repeat
+ core.Info("4")
+ local d = socket:receive("*a")
+ if d ~= nil then
+ result = result .. d
+ end
+ until d == nil or d == 0
+ core.Info("Received: "..result)
+end
+
+core.register_task(cron) \ No newline at end of file
diff --git a/reg-tests/lua/lua_socket.vtc b/reg-tests/lua/lua_socket.vtc
new file mode 100644
index 0000000..83e06a6
--- /dev/null
+++ b/reg-tests/lua/lua_socket.vtc
@@ -0,0 +1,33 @@
+varnishtest "Lua: check socket functionality from a lua-task"
+feature ignore_unknown_macro
+
+#REQUIRE_OPTIONS=LUA
+
+server s1 {
+ rxreq
+ txresp -bodylen 20
+} -start
+
+haproxy h1 -conf {
+ global
+ lua-load ${testdir}/lua_socket.lua
+
+ frontend fe1
+ mode http
+ bind "fd@${fe1}"
+ default_backend b1
+
+ backend b1
+ mode http
+ http-request use-service lua.fakeserv
+
+} -start
+
+client c0 -connect ${h1_fe1_sock} {
+ txreq -url "/" -hdr "vtcport: ${s1_port}"
+ rxresp
+ expect resp.status == 200
+} -run
+
+
+server s1 -wait
diff --git a/reg-tests/lua/set_var.lua b/reg-tests/lua/set_var.lua
new file mode 100644
index 0000000..f4d5e7a
--- /dev/null
+++ b/reg-tests/lua/set_var.lua
@@ -0,0 +1,25 @@
+core.register_service("set_var", "http", function(applet)
+ local var_name = applet.headers["var"][0]
+ local result = applet:set_var(var_name, "value")
+ if result then
+ applet:set_status(202)
+ else
+ applet:set_status(400)
+ end
+ applet:add_header("echo", applet:get_var(var_name) or "(nil)")
+ applet:start_response()
+ applet:send("")
+end)
+
+core.register_service("set_var_ifexist", "http", function(applet)
+ local var_name = applet.headers["var"][0]
+ local result = applet:set_var(var_name, "value", true)
+ if result then
+ applet:set_status(202)
+ else
+ applet:set_status(400)
+ end
+ applet:add_header("echo", applet:get_var(var_name) or "(nil)")
+ applet:start_response()
+ applet:send("")
+end)
diff --git a/reg-tests/lua/set_var.vtc b/reg-tests/lua/set_var.vtc
new file mode 100644
index 0000000..0c8a4b1
--- /dev/null
+++ b/reg-tests/lua/set_var.vtc
@@ -0,0 +1,83 @@
+varnishtest "Lua: set_var"
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTIONS=LUA
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ global
+ lua-load ${testdir}/set_var.lua
+
+ frontend fe1
+ mode http
+ bind "fd@${fe1}"
+
+ http-request use-service lua.set_var
+
+ frontend fe2
+ mode http
+ bind "fd@${fe2}"
+ # just make sure the variable exists
+ http-request set-header Dummy %[var(proc.fe2_foo)]
+
+ http-request use-service lua.set_var_ifexist
+} -start
+
+client c0 -connect ${h1_fe1_sock} {
+ # create var
+ txreq -url "/" \
+ -hdr "Var: txn.fe1_foo"
+ rxresp
+ expect resp.status == 202
+ expect resp.http.echo == "value"
+
+ # rewrite var
+ txreq -url "/" \
+ -hdr "Var: txn.fe1_foo"
+ rxresp
+ expect resp.status == 202
+ expect resp.http.echo == "value"
+
+ # create var under scope "proc"
+ txreq -url "/" \
+ -hdr "Var: proc.fe1_foo"
+ rxresp
+ expect resp.status == 202
+ expect resp.http.echo == "value"
+
+ # fail to create bad scope
+ txreq -url "/" \
+ -hdr "Var: invalid.var"
+ rxresp
+ expect resp.status == 400
+ expect resp.http.echo == "(nil)"
+} -run
+
+client c1 -connect ${h1_fe2_sock} {
+ # this one exists in the conf, it must succeed
+ txreq -url "/" \
+ -hdr "Var: proc.fe2_foo"
+ rxresp
+ expect resp.status == 202
+ expect resp.http.echo == "value"
+
+ # this one does not exist in the conf, it must fail
+ txreq -url "/" \
+ -hdr "Var: proc.fe2_bar"
+ rxresp
+ expect resp.status == 400
+ expect resp.http.echo == "(nil)"
+
+ # this one is under txn, it must succeed
+ txreq -url "/" \
+ -hdr "Var: txn.fe2_foo"
+ rxresp
+ expect resp.status == 202
+ expect resp.http.echo == "value"
+} -run
diff --git a/reg-tests/lua/txn_get_priv-print_r.lua b/reg-tests/lua/txn_get_priv-print_r.lua
new file mode 100644
index 0000000..185614f
--- /dev/null
+++ b/reg-tests/lua/txn_get_priv-print_r.lua
@@ -0,0 +1,96 @@
+-- Copyright 2016 Thierry Fournier
+
+function color(index, str)
+ return "\x1b[" .. index .. "m" .. str .. "\x1b[00m"
+end
+
+function nocolor(index, str)
+ return str
+end
+
+function sp(count)
+ local spaces = ""
+ while count > 0 do
+ spaces = spaces .. " "
+ count = count - 1
+ end
+ return spaces
+end
+
+function escape(str)
+ local s = ""
+ for i = 1, #str do
+ local c = str:sub(i,i)
+ local ascii = string.byte(c, 1)
+ if ascii > 126 or ascii < 20 then
+ s = s .. string.format("\\x%02x", ascii)
+ else
+ s = s .. c
+ end
+ end
+ return s
+end
+
+function print_rr(p, indent, c, wr, hist)
+ local i = 0
+ local nl = ""
+
+ if type(p) == "table" then
+ wr(c("33", "(table)") .. " " .. c("36", tostring(p)) .. " [")
+
+ for idx, value in ipairs(hist) do
+ if value == p then
+ wr(" " .. c("35", "/* recursion */") .. " ]")
+ return
+ end
+ end
+ hist[indent + 1] = p
+
+ mt = getmetatable(p)
+ if mt ~= nil then
+ wr("\n" .. sp(indent+1) .. c("31", "METATABLE") .. ": ")
+ print_rr(mt, indent+1, c, wr, hist)
+ end
+
+ for k,v in pairs(p) do
+ if i > 0 then
+ nl = "\n"
+ else
+ wr("\n")
+ end
+ wr(nl .. sp(indent+1))
+ if type(k) == "number" then
+ wr(c("32", tostring(k)))
+ else
+ wr("\"" .. c("32", escape(tostring(k))) .. "\"")
+ end
+ wr(": ")
+ print_rr(v, indent+1, c, wr, hist)
+ i = i + 1
+ end
+ if i == 0 then
+ wr(" " .. c("35", "/* empty */") .. " ]")
+ else
+ wr("\n" .. sp(indent) .. "]")
+ end
+
+ hist[indent + 1] = nil
+
+ elseif type(p) == "string" then
+ wr(c("33", "(string)") .. " \"" .. c("36", escape(p)) .. "\"")
+ else
+ wr(c("33", "(" .. type(p) .. ")") .. " " .. c("36", tostring(p)))
+ end
+end
+
+function print_r(p, col, wr)
+ if col == nil then col = true end
+ if wr == nil then wr = function(msg) io.stdout:write(msg) end end
+ local hist = {}
+ if col == true then
+ print_rr(p, 0, color, wr, hist)
+ else
+ print_rr(p, 0, nocolor, wr, hist)
+ end
+ wr("\n")
+end
diff --git a/reg-tests/lua/txn_get_priv-thread.vtc b/reg-tests/lua/txn_get_priv-thread.vtc
new file mode 100644
index 0000000..9538363
--- /dev/null
+++ b/reg-tests/lua/txn_get_priv-thread.vtc
@@ -0,0 +1,69 @@
+varnishtest "Lua: txn:get_priv() scope"
+#REQUIRE_OPTIONS=LUA,OPENSSL
+#REQUIRE_VERSION=2.4
+#REGTEST_TYPE=bug
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ lua-load-per-thread ${testdir}/txn_get_priv.lua
+ lua-load-per-thread ${testdir}/txn_get_priv-print_r.lua
+
+ frontend fe1
+ mode http
+ bind "fd@${fe1}"
+ default_backend b1
+
+ frontend fe2
+ mode http
+ bind ":8443" ssl crt ${testdir}/common.pem
+ stats enable
+ stats uri /
+
+ backend b1
+ mode http
+ http-request use-service lua.fakeserv
+} -start
+
+client c0 -repeat 4 -connect ${h1_fe1_sock} {
+ txreq -url "/0"
+ rxresp
+ expect resp.status == 200
+ txreq -url "/0"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c1 -repeat 4 -connect ${h1_fe1_sock} {
+ txreq -url "/1"
+ rxresp
+ expect resp.status == 200
+ txreq -url "/1"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c2 -repeat 4 -connect ${h1_fe1_sock} {
+ txreq -url "/2"
+ rxresp
+ expect resp.status == 200
+ txreq -url "/2"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c3 -repeat 4 -connect ${h1_fe1_sock} {
+ txreq -url "/3"
+ rxresp
+ expect resp.status == 200
+ txreq -url "/3"
+ rxresp
+ expect resp.status == 200
+} -run
+
diff --git a/reg-tests/lua/txn_get_priv.lua b/reg-tests/lua/txn_get_priv.lua
new file mode 100644
index 0000000..dd5623c
--- /dev/null
+++ b/reg-tests/lua/txn_get_priv.lua
@@ -0,0 +1,180 @@
+Luacurl = {}
+Luacurl.__index = Luacurl
+setmetatable(Luacurl, {
+ __call = function (cls, ...)
+ return cls.new(...)
+ end,
+})
+function Luacurl.new(server, port, ssl)
+ local self = setmetatable({}, Luacurl)
+ self.sockconnected = false
+ self.server = server
+ self.port = port
+ self.ssl = ssl
+ self.cookies = {}
+ return self
+end
+
+function Luacurl:get(method,url,headers,data)
+ core.Info("MAKING SOCKET")
+ if self.sockconnected == false then
+ self.sock = core.tcp()
+ if self.ssl then
+ local r = self.sock:connect_ssl(self.server,self.port)
+ else
+ local r = self.sock:connect(self.server,self.port)
+ end
+ self.sockconnected = true
+ end
+ core.Info("SOCKET MADE")
+ local request = method.." "..url.." HTTP/1.1"
+ if data ~= nil then
+ request = request .. "\r\nContent-Length: "..string.len(data)
+ end
+ if headers ~= null then
+ for h,v in pairs(headers) do
+ request = request .. "\r\n"..h..": "..v
+ end
+ end
+ cookstring = ""
+ for cook,cookval in pairs(self.cookies) do
+ cookstring = cookstring .. cook.."="..cookval.."; "
+ end
+ if string.len(cookstring) > 0 then
+ request = request .. "\r\nCookie: "..cookstring
+ end
+
+ request = request .. "\r\n\r\n"
+ if data and string.len(data) > 0 then
+ request = request .. data
+ end
+--print(request)
+ core.Info("SENDING REQUEST")
+ self.sock:send(request)
+
+-- core.Info("PROCESSING RESPONSE")
+ return processhttpresponse(self.sock)
+end
+
+function processhttpresponse(socket)
+ local res = {}
+core.Info("1")
+ res.status = socket:receive("*l")
+core.Info("2")
+
+ if res.status == nil then
+ core.Info(" processhttpresponse RECEIVING status: NIL")
+ return res
+ end
+ core.Info(" processhttpresponse RECEIVING status:"..res.status)
+ res.headers = {}
+ res.headerslist = {}
+ repeat
+core.Info("3")
+ local header = socket:receive("*l")
+ if header == nil then
+ return "error"
+ end
+ local valuestart = header:find(":")
+ if valuestart ~= nil then
+ local head = header:sub(1,valuestart-1)
+ local value = header:sub(valuestart+2)
+ table.insert(res.headerslist, {head,value})
+ res.headers[head] = value
+ end
+ until header == ""
+ local bodydone = false
+ if res.headers["Connection"] ~= nil and res.headers["Connection"] == "close" then
+-- core.Info("luacurl processresponse with connection:close")
+ res.body = ""
+ repeat
+core.Info("4")
+ local d = socket:receive("*a")
+ if d ~= nil then
+ res.body = res.body .. d
+ end
+ until d == nil or d == 0
+ bodydone = true
+ end
+ if bodydone == false and res.headers["Content-Length"] ~= nil then
+ res.contentlength = tonumber(res.headers["Content-Length"])
+ if res.contentlength == nil then
+ core.Warning("res.contentlength ~NIL = "..res.headers["Content-Length"])
+ end
+-- core.Info("luacur, contentlength="..res.contentlength)
+ res.body = ""
+ repeat
+ local d = socket:receive(res.contentlength)
+ if d == nil then
+-- core.Info("luacurl, ERROR?: received NIL, expecting "..res.contentlength.." bytes only got "..string.len(res.body).." sofar")
+ return
+ else
+ res.body = res.body..d
+-- core.Info("luacurl, COMPLETE?: expecting "..res.contentlength.." bytes, got "..string.len(res.body))
+ if string.len(res.body) >= res.contentlength then
+-- core.Info("luacurl, COMPLETE?: expecting "..res.contentlength.." bytes, got "..string.len(res.body))
+ break
+ end
+ end
+-- core.Info("processhttpresponse, Loopy, get more body data! to receive complete contentlenght")
+ until false
+ end
+ if res.headers["Transfer-Encoding"] ~= nil and res.headers["Transfer-Encoding"] == "chunked" then
+ local chunksize = 0
+ res.contentlength = 0
+ res.body = ""
+ repeat
+core.Info("5")
+ local chunksizestr = socket:receive("*l")
+ if chunksizestr == nil then
+ break
+ end
+ chunksize = tonumber("0x"..chunksizestr)
+ if chunksize ~= nil then
+ res.contentlength = res.contentlength + chunksize
+ if chunksize ~= 0 then
+ local chunk = socket:receive(chunksize)
+ res.body = res.body .. chunk
+ chunksizestr = socket:receive("*l")
+ if chunksizestr ~= "" then
+ return "ERROR Chunk-end expected."
+ end
+ end
+ else
+ break
+ end
+ until false
+ end
+core.Info("6")
+ return res
+end
+
+function Luacurl:close()
+ if self.sockconnected == true then
+ self.sock:close()
+ self.sockconnected = false
+ end
+end
+
+function print_r_string(object)
+ local res = ""
+ print_r(object,false,function(x) res = res .. x end)
+ return res
+end
+
+core.register_service("fakeserv", "http", function(applet)
+ core.Info("APPLET START")
+ local mc = Luacurl("127.0.0.1",8443, true)
+ local headers = {}
+ local body = ""
+ core.Info("APPLET GET")
+ local res = mc:get("GET", "/", headers, body)
+ core.Info("APPLET GET done")
+ local response = print_r_string(res)
+ applet:add_header("Server", "haproxy/webstats")
+ applet:add_header("Content-Length", string.len(response))
+ applet:add_header("Content-Type", "text/html")
+ applet:start_response()
+ applet:send(response)
+ core.Info("APPLET DONE")
+end)
diff --git a/reg-tests/lua/txn_get_priv.vtc b/reg-tests/lua/txn_get_priv.vtc
new file mode 100644
index 0000000..71e7bb5
--- /dev/null
+++ b/reg-tests/lua/txn_get_priv.vtc
@@ -0,0 +1,35 @@
+varnishtest "Lua: txn:get_priv() scope"
+#REQUIRE_OPTIONS=LUA,OPENSSL
+#REGTEST_TYPE=bug
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ lua-load ${testdir}/txn_get_priv.lua
+ lua-load ${testdir}/txn_get_priv-print_r.lua
+
+ frontend fe1
+ mode http
+ bind "fd@${fe1}"
+ default_backend b1
+
+ frontend fe2
+ mode http
+ bind ":8443" ssl crt ${testdir}/common.pem
+ stats enable
+ stats uri /
+
+ backend b1
+ mode http
+ http-request use-service lua.fakeserv
+} -start
+
+client c0 -connect ${h1_fe1_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/lua/wrong_types_usage.lua b/reg-tests/lua/wrong_types_usage.lua
new file mode 100644
index 0000000..d2401fa
--- /dev/null
+++ b/reg-tests/lua/wrong_types_usage.lua
@@ -0,0 +1,3 @@
+core.register_action("foo", { "http-req" }, function(txn)
+ txn.sc:ipmask(txn.f:src(), 24, 112)
+end)
diff --git a/reg-tests/lua/wrong_types_usage.vtc b/reg-tests/lua/wrong_types_usage.vtc
new file mode 100644
index 0000000..ed76579
--- /dev/null
+++ b/reg-tests/lua/wrong_types_usage.vtc
@@ -0,0 +1,77 @@
+# commit f874a83
+# BUG/MINOR: lua: Segfaults with wrong usage of types.
+#
+# Patrick reported that this simple configuration made haproxy segfaults:
+#
+# global
+# lua-load /tmp/haproxy.lua
+#
+# frontend f1
+# mode http
+# bind :8000
+# default_backend b1
+#
+# http-request lua.foo
+#
+# backend b1
+# mode http
+# server s1 127.0.0.1:8080
+#
+# with this '/tmp/haproxy.lua' script:
+#
+# core.register_action("foo", { "http-req" }, function(txn)
+# txn.sc:ipmask(txn.f:src(), 24, 112)
+# end)
+#
+# This is due to missing initialization of the array of arguments
+# passed to hlua_lua2arg_check() which makes it enter code with
+# corrupted arguments.
+#
+# Thanks a lot to Patrick Hemmer for having reported this issue.
+
+
+varnishtest "Basic LUA test h00000"
+#REQUIRE_OPTIONS=LUA
+#REGTEST_TYPE=bug
+
+feature ignore_unknown_macro
+
+server s1 -repeat 2 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ lua-load ${testdir}/wrong_types_usage.lua
+
+ frontend fe1
+ mode http
+ bind "fd@${fe1}"
+ default_backend b1
+
+ http-request lua.foo
+
+ backend b1
+ mode http
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+client c0 -connect ${h1_fe1_sock} {
+ txreq -url "/foo"
+ rxresp
+ expect resp.status == 200
+}
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -url "/foo"
+ rxresp
+ expect resp.status == 200
+}
+
+client c0 -start
+client c1 -start
+
+client c0 -wait
+client c1 -wait
diff --git a/reg-tests/mailers/healthcheckmail.lua b/reg-tests/mailers/healthcheckmail.lua
new file mode 100644
index 0000000..4cb0e9d
--- /dev/null
+++ b/reg-tests/mailers/healthcheckmail.lua
@@ -0,0 +1,70 @@
+
+local vtc_port1 = 0
+local mailsreceived = 0
+local mailconnectionsmade = 0
+local healthcheckcounter = 0
+
+function RecieveAndCheck(applet, expect)
+ data = applet:getline()
+ if data:sub(1,expect:len()) ~= expect then
+ core.Info("Expected: "..expect.." but got:"..data:sub(1,expect:len()))
+ applet:send("Expected: "..expect.." but got:"..data.."\r\n")
+ return false
+ end
+ return true
+end
+
+core.register_service("mailservice", "tcp", function(applet)
+ core.Info("############# Mailservice Called #############")
+ mailconnectionsmade = mailconnectionsmade + 1
+ applet:send("220 Welcome\r\n")
+ local data
+
+ if RecieveAndCheck(applet, "HELO") == false then
+ applet:set_var("txn.result", "ERROR (step: HELO)")
+ return
+ end
+ applet:send("250 OK\r\n")
+ if RecieveAndCheck(applet, "MAIL FROM:") == false then
+ applet:set_var("txn.result", "ERROR (step: MAIL FROM)")
+ return
+ end
+ applet:send("250 OK\r\n")
+ if RecieveAndCheck(applet, "RCPT TO:") == false then
+ applet:set_var("txn.result", "ERROR (step: RCPT TO)")
+ return
+ end
+ applet:send("250 OK\r\n")
+ if RecieveAndCheck(applet, "DATA") == false then
+ applet:set_var("txn.result", "ERROR (step: DATA)")
+ return
+ end
+ applet:send("354 OK\r\n")
+ core.Info("#### Send your mailbody")
+ local endofmail = false
+ local subject = ""
+ while endofmail ~= true do
+ data = applet:getline() -- BODY CONTENT
+ --core.Info(data)
+ if data:sub(1, 9) == "Subject: " then
+ subject = data
+ end
+ if (data == "\r\n") then
+ data = applet:getline() -- BODY CONTENT
+ core.Info(data)
+ if (data == ".\r\n") then
+ endofmail = true
+ end
+ end
+ end
+ core.Info("#### Body received OK")
+ applet:send("250 OK\r\n")
+
+ if RecieveAndCheck(applet, "QUIT") == false then
+ applet:set_var("txn.result", "ERROR (step: QUIT)")
+ return
+ end
+ applet:send("221 Mail queued for delivery to /dev/null \r\n")
+ core.Info("Mail queued for delivery to /dev/null subject: "..subject)
+ applet:set_var("txn.result", "SUCCESS")
+end)
diff --git a/reg-tests/mailers/healthcheckmail.vtc b/reg-tests/mailers/healthcheckmail.vtc
new file mode 100644
index 0000000..208d350
--- /dev/null
+++ b/reg-tests/mailers/healthcheckmail.vtc
@@ -0,0 +1,60 @@
+varnishtest "Check health-check email alerts"
+#REQUIRE_OPTIONS=LUA
+
+feature ignore_unknown_macro
+
+syslog S1 -level notice {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed.+check duration: [[:digit:]]+ms.+status: 0/1 DOWN."
+ recv info
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Result=SUCCESS Bytes=[[:digit:]]+"
+} -start
+
+haproxy h1 -conf {
+ global
+ lua-load ${testdir}/mailers.lua
+ lua-load ${testdir}/healthcheckmail.lua
+
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen lisrv
+ mode tcp
+ bind "fd@${lisrv}"
+ tcp-request connection reject
+
+ listen lismtp
+ mode tcp
+ bind "fd@${lismtp}"
+ log ${S1_addr}:${S1_port} daemon
+ log-format "Result=%[var(txn.result)] Bytes=%B"
+ tcp-request content use-service lua.mailservice
+
+ frontend fe1
+ mode http
+ bind "fd@${fe1}"
+ default_backend be1
+
+ backend be1
+ mode http
+ log ${S1_addr}:${S1_port} daemon
+ option httpchk
+ option log-health-checks
+
+ default-server inter 200ms downinter 100ms rise 1 fall 1
+
+ email-alert mailers mymailers
+ email-alert level info
+ email-alert from from@domain.tld
+ email-alert to to@domain.tld
+
+ server srv1 ${h1_lisrv_addr}:${h1_lisrv_port} check
+
+ mailers mymailers
+ mailer smtp1 ${h1_lismtp_addr}:${h1_lismtp_port}
+
+} -start
+
+syslog S1 -wait
diff --git a/reg-tests/mailers/mailers.lua b/reg-tests/mailers/mailers.lua
new file mode 120000
index 0000000..5ea4673
--- /dev/null
+++ b/reg-tests/mailers/mailers.lua
@@ -0,0 +1 @@
+../../examples/lua/mailers.lua \ No newline at end of file
diff --git a/reg-tests/mcli/mcli_show_info.vtc b/reg-tests/mcli/mcli_show_info.vtc
new file mode 100644
index 0000000..3c44461
--- /dev/null
+++ b/reg-tests/mcli/mcli_show_info.vtc
@@ -0,0 +1,27 @@
+varnishtest "Show info of process 1"
+
+feature ignore_unknown_macro
+
+# Do nothing. Is there only to create s1_* macros
+server s1 {
+} -start
+
+haproxy h1 -W -S -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend myfrontend
+ bind "fd@${my_fe}"
+ default_backend test
+
+ backend test
+ server www1 ${s1_addr}:${s1_port}
+} -start
+
+haproxy h1 -mcli {
+ send "@1 show info"
+ expect ~ ".*\nProcess_num: 1\n.*"
+} -wait
diff --git a/reg-tests/mcli/mcli_start_progs.vtc b/reg-tests/mcli/mcli_start_progs.vtc
new file mode 100644
index 0000000..51b335c
--- /dev/null
+++ b/reg-tests/mcli/mcli_start_progs.vtc
@@ -0,0 +1,36 @@
+varnishtest "Try to start a master CLI with 2 programs"
+#REGTEST_TYPE=bug
+feature cmd "command -v sleep"
+
+feature ignore_unknown_macro
+
+# Do nothing. Is there only to create s1_* macros
+server s1 {
+} -start
+
+haproxy h1 -W -S -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend myfrontend
+ bind "fd@${my_fe}"
+ default_backend test
+
+ backend test
+ server www1 ${s1_addr}:${s1_port}
+
+ program foo
+ command sleep 10
+
+ program bar
+ command sleep 10
+
+} -start
+
+haproxy h1 -mcli {
+ send "show proc"
+ expect ~ ".*foo.*\n.*bar.*\n"
+} -wait
diff --git a/reg-tests/peers/basic_sync.vtc b/reg-tests/peers/basic_sync.vtc
new file mode 100644
index 0000000..5c0cb41
--- /dev/null
+++ b/reg-tests/peers/basic_sync.vtc
@@ -0,0 +1,120 @@
+vtest "Basic test for peers protocol"
+feature ignore_unknown_macro
+
+#REGTEST_TYPE=slow
+
+haproxy h1 -arg "-L A" -conf {
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend stkt
+ stick-table type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000) peers peers
+
+ peers peers
+ bind "fd@${A}"
+ server A
+ server B ${h2_B_addr}:${h2_B_port}
+ server C ${h3_C_addr}:${h3_C_port}
+
+ frontend fe
+ bind "fd@${fe}"
+ tcp-request inspect-delay 100ms
+ tcp-request content track-sc0 url table stkt
+ tcp-request content sc-inc-gpc0(0)
+}
+
+haproxy h2 -arg "-L B" -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend stkt
+ stick-table type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000) peers peers
+
+ peers peers
+ bind "fd@${B}"
+ server A ${h1_A_addr}:${h1_A_port}
+ server B
+ server C ${h3_C_addr}:${h3_C_port}
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request track-sc0 url table stkt
+ http-request sc-inc-gpc0(0)
+}
+
+haproxy h3 -arg "-L C" -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend stkt
+ stick-table type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000) peers peers
+
+ peers peers
+ bind "fd@${C}"
+ server A ${h1_A_addr}:${h1_A_port}
+ server B ${h2_B_addr}:${h2_B_port}
+ server C
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request track-sc0 url table stkt
+ http-request sc-inc-gpc0(0)
+}
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/c1_client"
+ expect_close
+} -start
+
+client c2 -connect ${h1_fe_sock} {
+ txreq -url "/c2_client"
+ expect_close
+} -start
+
+client c3 -connect ${h1_fe_sock} {
+ txreq -url "/c3_client"
+ expect_close
+} -start
+
+client c4 -connect ${h1_fe_sock} {
+ txreq -url "/c4_client"
+ expect_close
+} -start
+
+haproxy h1 -start
+delay 0.2
+haproxy h2 -start
+delay 0.2
+haproxy h3 -start
+delay 0.2
+
+client c1 -wait
+client c2 -wait
+client c3 -wait
+client c4 -wait
+
+delay 2
+
+haproxy h1 -cli {
+ send "show table stkt"
+ expect ~ "# table: stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
+haproxy h2 -cli {
+ send "show table stkt"
+ expect ~ "# table: stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
+haproxy h3 -cli {
+ send "show table stkt"
+ expect ~ "# table: stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
diff --git a/reg-tests/peers/basic_sync_wo_stkt_backend.vtc b/reg-tests/peers/basic_sync_wo_stkt_backend.vtc
new file mode 100644
index 0000000..9f97ff5
--- /dev/null
+++ b/reg-tests/peers/basic_sync_wo_stkt_backend.vtc
@@ -0,0 +1,115 @@
+vtest "Basic test for peers protocol stick-table declared in peers sections"
+feature ignore_unknown_macro
+
+#REGTEST_TYPE=slow
+
+haproxy h1 -arg "-L A" -conf {
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+
+ peers peers
+ bind "fd@${A}"
+ server A
+ server B ${h2_B_addr}:${h2_B_port}
+ server C ${h3_C_addr}:${h3_C_port}
+ table stkt type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000)
+
+ frontend fe
+ bind "fd@${fe}"
+ tcp-request inspect-delay 100ms
+ tcp-request content track-sc0 url table peers/stkt
+ tcp-request content sc-inc-gpc0(0)
+}
+
+haproxy h2 -arg "-L B" -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ peers peers
+ bind "fd@${B}"
+ server A ${h1_A_addr}:${h1_A_port}
+ server B
+ server C ${h3_C_addr}:${h3_C_port}
+ table stkt type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000)
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request track-sc0 url table peers/stkt
+ http-request sc-inc-gpc0(0)
+}
+
+haproxy h3 -arg "-L C" -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ peers peers
+ bind "fd@${C}"
+ server A ${h1_A_addr}:${h1_A_port}
+ server B ${h2_B_addr}:${h2_B_port}
+ server C
+ table stkt type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000)
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request track-sc0 url table peers/stkt
+ http-request sc-inc-gpc0(0)
+}
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/c1_client"
+ expect_close
+} -start
+
+client c2 -connect ${h1_fe_sock} {
+ txreq -url "/c2_client"
+ expect_close
+} -start
+
+client c3 -connect ${h1_fe_sock} {
+ txreq -url "/c3_client"
+ expect_close
+} -start
+
+client c4 -connect ${h1_fe_sock} {
+ txreq -url "/c4_client"
+ expect_close
+} -start
+
+haproxy h1 -start
+delay 0.2
+haproxy h2 -start
+delay 0.2
+haproxy h3 -start
+delay 0.2
+
+client c1 -wait
+client c2 -wait
+client c3 -wait
+client c4 -wait
+
+delay 2
+
+haproxy h1 -cli {
+ send "show table peers/stkt"
+ expect ~ "# table: peers/stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
+haproxy h2 -cli {
+ send "show table peers/stkt"
+ expect ~ "# table: peers/stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
+haproxy h3 -cli {
+ send "show table peers/stkt"
+ expect ~ "# table: peers/stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
diff --git a/reg-tests/peers/common.pem b/reg-tests/peers/common.pem
new file mode 120000
index 0000000..a4433d5
--- /dev/null
+++ b/reg-tests/peers/common.pem
@@ -0,0 +1 @@
+../ssl/common.pem \ No newline at end of file
diff --git a/reg-tests/peers/tls_basic_sync.vtc b/reg-tests/peers/tls_basic_sync.vtc
new file mode 100644
index 0000000..95e3d73
--- /dev/null
+++ b/reg-tests/peers/tls_basic_sync.vtc
@@ -0,0 +1,157 @@
+vtest "Basic test for peers protocol over SSL/TLS"
+#REQUIRE_OPTIONS=OPENSSL
+feature ignore_unknown_macro
+
+#REGTEST_TYPE=slow
+
+haproxy h1 -arg "-L A" -conf {
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend stkt
+ stick-table type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000) peers peers
+
+ peers peers
+ default-server ssl crt ${testdir}/common.pem verify none
+ bind "fd@${A}" ssl crt ${testdir}/common.pem
+ server A
+ server B ${h2_B_addr}:${h2_B_port}
+ server C ${h3_C_addr}:${h3_C_port}
+ server D ${h4_D_addr}:${h4_D_port}
+
+ frontend fe
+ bind "fd@${fe}"
+ tcp-request inspect-delay 100ms
+ tcp-request content track-sc0 url table stkt
+ tcp-request content sc-inc-gpc0(0)
+}
+
+haproxy h2 -arg "-L B" -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend stkt
+ stick-table type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000) peers peers
+
+ peers peers
+ default-server ssl crt ${testdir}/common.pem verify none
+ bind "fd@${B}" ssl crt ${testdir}/common.pem
+ server A ${h1_A_addr}:${h1_A_port}
+ server B
+ server C ${h3_C_addr}:${h3_C_port}
+ server D ${h4_D_addr}:${h4_D_port}
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request track-sc0 url table stkt
+ http-request sc-inc-gpc0(0)
+}
+
+haproxy h3 -arg "-L C" -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend stkt
+ stick-table type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000) peers peers
+
+ peers peers
+ default-server ssl crt ${testdir}/common.pem verify none
+ bind "fd@${C}" ssl crt ${testdir}/common.pem
+ server A ${h1_A_addr}:${h1_A_port}
+ server B ${h2_B_addr}:${h2_B_port}
+ server C
+ server D ${h4_D_addr}:${h4_D_port}
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request track-sc0 url table stkt
+ http-request sc-inc-gpc0(0)
+}
+
+haproxy h4 -arg "-L D" -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend stkt
+ stick-table type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000) peers peers
+
+ peers peers
+ bind "fd@${D}"
+ server A ${h1_A_addr}:${h1_A_port}
+ server B ${h2_B_addr}:${h2_B_port}
+ server C ${h3_C_addr}:${h3_C_port}
+ server D
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request track-sc0 url table stkt
+ http-request sc-inc-gpc0(0)
+}
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/c1_client"
+ expect_close
+} -start
+
+client c2 -connect ${h1_fe_sock} {
+ txreq -url "/c2_client"
+ expect_close
+} -start
+
+client c3 -connect ${h1_fe_sock} {
+ txreq -url "/c3_client"
+ expect_close
+} -start
+
+client c4 -connect ${h1_fe_sock} {
+ txreq -url "/c4_client"
+ expect_close
+} -start
+
+haproxy h1 -start
+delay 0.2
+haproxy h2 -start
+delay 0.2
+haproxy h3 -start
+delay 0.2
+haproxy h4 -start
+delay 0.2
+
+client c1 -wait
+client c2 -wait
+client c3 -wait
+client c4 -wait
+
+delay 2
+
+haproxy h1 -cli {
+ send "show table stkt"
+ expect ~ "# table: stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
+haproxy h2 -cli {
+ send "show table stkt"
+ expect ~ "# table: stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
+haproxy h3 -cli {
+ send "show table stkt"
+ expect ~ "# table: stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
+haproxy h4 -cli {
+ send "show table stkt"
+ expect ~ "# table: stkt, type: string, size:1048[0-9]{4}, used:0\n"
+}
+
diff --git a/reg-tests/peers/tls_basic_sync_wo_stkt_backend.vtc b/reg-tests/peers/tls_basic_sync_wo_stkt_backend.vtc
new file mode 100644
index 0000000..bf46708
--- /dev/null
+++ b/reg-tests/peers/tls_basic_sync_wo_stkt_backend.vtc
@@ -0,0 +1,151 @@
+vtest "Basic test for peers protocol over SSL/TLS with stick-table declared in peers sections"
+feature ignore_unknown_macro
+
+#REQUIRE_OPTIONS=OPENSSL
+#REGTEST_TYPE=slow
+
+haproxy h1 -arg "-L A" -conf {
+ defaults
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ peers peers
+ table stkt type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000)
+ default-server ssl crt ${testdir}/common.pem verify none
+ bind "fd@${A}" ssl crt ${testdir}/common.pem
+ server A
+ server B ${h2_B_addr}:${h2_B_port}
+ server C ${h3_C_addr}:${h3_C_port}
+ server D ${h4_D_addr}:${h4_D_port}
+
+ frontend fe
+ bind "fd@${fe}"
+ tcp-request inspect-delay 100ms
+ tcp-request content track-sc0 url table peers/stkt
+ tcp-request content sc-inc-gpc0(0)
+}
+
+haproxy h2 -arg "-L B" -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ peers peers
+ table stkt type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000)
+ default-server ssl crt ${testdir}/common.pem verify none
+ bind "fd@${B}" ssl crt ${testdir}/common.pem
+ server A ${h1_A_addr}:${h1_A_port}
+ server B
+ server C ${h3_C_addr}:${h3_C_port}
+ server D ${h4_D_addr}:${h4_D_port}
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request track-sc0 url table peers/stkt
+ http-request sc-inc-gpc0(0)
+}
+
+haproxy h3 -arg "-L C" -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ peers peers
+ table stkt type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000)
+ default-server ssl crt ${testdir}/common.pem verify none
+ bind "fd@${C}" ssl crt ${testdir}/common.pem
+ server A ${h1_A_addr}:${h1_A_port}
+ server B ${h2_B_addr}:${h2_B_port}
+ server C
+ server D ${h4_D_addr}:${h4_D_port}
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request track-sc0 url table peers/stkt
+ http-request sc-inc-gpc0(0)
+}
+
+haproxy h4 -arg "-L D" -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ backend stkt
+
+ peers peers
+ table stkt type string size 10m store server_id,gpc0,conn_cur,conn_rate(50000)
+ bind "fd@${D}"
+ server A ${h1_A_addr}:${h1_A_port}
+ server B ${h2_B_addr}:${h2_B_port}
+ server C ${h3_C_addr}:${h3_C_port}
+ server D
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request track-sc0 url table peers/stkt
+ http-request sc-inc-gpc0(0)
+}
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/c1_client"
+ expect_close
+} -start
+
+client c2 -connect ${h1_fe_sock} {
+ txreq -url "/c2_client"
+ expect_close
+} -start
+
+client c3 -connect ${h1_fe_sock} {
+ txreq -url "/c3_client"
+ expect_close
+} -start
+
+client c4 -connect ${h1_fe_sock} {
+ txreq -url "/c4_client"
+ expect_close
+} -start
+
+haproxy h1 -start
+delay 0.02
+haproxy h2 -start
+delay 0.02
+haproxy h3 -start
+delay 0.02
+haproxy h4 -start
+delay 0.02
+
+client c1 -wait
+client c2 -wait
+client c3 -wait
+client c4 -wait
+
+delay 3
+
+haproxy h1 -cli {
+ send "show table peers/stkt"
+ expect ~ "# table: peers/stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
+haproxy h2 -cli {
+ send "show table peers/stkt"
+ expect ~ "# table: peers/stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
+haproxy h3 -cli {
+ send "show table peers/stkt"
+ expect ~ "# table: peers/stkt, type: string, size:1048[0-9]{4}, used:4(\n0x[0-9a-f]*: key=/c[1-4]_client use=0 exp=0 shard=0 server_id=0 gpc0=1 conn_rate\\(50000\\)=1 conn_cur=0){4}"
+}
+
+haproxy h4 -cli {
+ send "show table peers/stkt"
+ expect ~ "# table: peers/stkt, type: string, size:1048[0-9]{4}, used:0\n"
+}
+
diff --git a/reg-tests/pki/README b/reg-tests/pki/README
new file mode 100644
index 0000000..df801bf
--- /dev/null
+++ b/reg-tests/pki/README
@@ -0,0 +1,23 @@
+How it was generated:
+
+cfssl gencert -initca root/root-csr.json \
+| cfssljson -bare root/root-ca
+
+cfssl genkey intermediate/intermediate-csr.json \
+| cfssljson -bare intermediate/intermediate-ca
+
+cfssl sign -ca root/root-ca.pem \
+ -ca-key root/root-ca-key.pem \
+ -config config.json \
+ -profile intermediate \
+ intermediate/intermediate-ca.csr \
+| cfssljson -bare intermediate/intermediate-ca
+
+
+
+ cfssl gencert \
+ -ca intermediate/intermediate-ca.pem \
+ -ca-key intermediate/intermediate-ca-key.pem \
+ -config config.json \
+ -profile host \
+ certificates/www.test1.com-csr.json| cfssljson -bare certificates/www.test1.com
diff --git a/reg-tests/pki/certificates/www.test1.com-csr.json b/reg-tests/pki/certificates/www.test1.com-csr.json
new file mode 100644
index 0000000..734452b
--- /dev/null
+++ b/reg-tests/pki/certificates/www.test1.com-csr.json
@@ -0,0 +1,15 @@
+{
+ "CN": "www.test1.com",
+ "hosts": ["www.test1.com"],
+ "key": {
+ "algo": "rsa",
+ "size": 2048
+ },
+ "names": [
+ {
+ "C": "FR",
+ "L": "Paris",
+ "O": "test1"
+ }
+ ]
+}
diff --git a/reg-tests/pki/certificates/www.test1.com-key.pem b/reg-tests/pki/certificates/www.test1.com-key.pem
new file mode 100644
index 0000000..c46b8fb
--- /dev/null
+++ b/reg-tests/pki/certificates/www.test1.com-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA3fgUyE3616u0t/nSFAZVxHTSl2T6ksIXIK4lTbw4btEJwW4q
+jFfejIhLWvja1r1ct1WONWNKbw0tT61rJwpQTHQRXT5CEaQMdtHM9zOJQQ4v6deJ
+viW2L7FYSxg6MzBG2jsTEnonUxQx0Ku5NG9LDDLydr9PUbz2g8rVmkbQtO51ZWT1
+NHz0AksN6GX9SvbvW3W7jCTnjtg9Pz13s21q3Yt/lbmiuO3vtQYo4ekJvLg/H+0k
+ShhZtukJFfO8ClsPMYT52S9TzVskDXwMxkH+rI6ZmoYc/i72t8sG7+V2lKfKI4MO
+Czq89X7wvHQ4/cFYNdyYVoZsCwv+cxuXmNy7mQIDAQABAoIBAAtHSbcLz00aGmqm
+tPfzgnQjA3hR1zGRzx8H+jlC8RMgaAB+GodbB6HYYwvSTTxQDt/55unri6Ks5rp/
+s0weiAn6c89rFGxVC5UV//YnljfKAsE9BHC29dTii/v01TA4qcD483Ui49Ci3A0g
+TJ7PcN7Dz/IcsmkS0uvLaKMYKg6nXu9UnKkLBqThTiLA5I+eZZ4zX862Yurku8NI
+HwbMtBsICbe1H0Ebdc/PPAShB8pvV3nQMGFjADOEYolaByQAltolADmIc5K9E6wL
+SsHzAjGTjarSYdqjZRuoEtQrWQTG1fnvJZBXB8L1Brv9RbrPWN2TW/A1uhUR4qYd
+wuxB1mkCgYEA9ao05RsJzDVc4qLBvDXuqo1WapwnYUyc8Jeq+r5l67Ota1ykQyiQ
+BJZDM/mdFRzZZjMAAMN9cxsDdY7gp0ebN190F443tSxjvlVOGJ/e8UJ+Au+9WEYM
+xZQo5VquU8XlxfwFYtYANMvr7DB8yEr25S7S2v3jZ70NZQDDR6G+5L8CgYEA506s
+JJM/NfP82e6JtSB9fOEcjEeddPCdf2RkB+E3Ppt7AQX5Aje/8VOSiZkIbOap9oLc
+rBd9GrER2m2pahd9DFkSs1td70IM5CwwgYIKyWkCCkLXyMrLpelFEqZsFvWD14Go
+c29NSDOpVfVJkPr46Gym6dBvy1rCMh+/ZrgsPacCgYAXFU0vEeFTzNfTe9OUacTp
+RaqPDektXVOJz9aDBQzynsl2wxe0L8WIiM37vkKiTzmmPriLWdMZ07n5e9lkHnhZ
+NaDk7boSTf95TO6vpaX/KW5JvFkgSES+8/L7yg+DU58JgWrIJK+URmz+nne7IkAc
+vM+XQC/z+XGewfmXa31SZQKBgGSDpHyUXBCXARa2+LJz9vQQYrZ23G6XrOlR98IQ
+1U/ogrA0JzwWe9tjxLb0gFvKdKtBvKEv59Z0gdyYcNlAcb+u6Vh1aMFyw2VX6pAs
+sYFKl29cEqcXsR1c2/45wZjMgclhd5EKGdw5TumimKBe31Eo/fN29024F9FuSF9b
+wyXbAoGBALGIKzPgV7Tt6SbzcCjJGQHlH/RKBcuFJjJS+Qph3w7K3L5b6Y35zPOY
+3+FxT2Z5wAlOGYeF9Qa8K3/VX1l7Vhktu9EcTqM59fMGuTM0mEgwwdFM4oFgRIau
+wmlIuAFmo7OwlsggHuHJ7lDk+r7AoNVW7l7Gd1JnG4CasvymVc3N
+-----END RSA PRIVATE KEY-----
diff --git a/reg-tests/pki/certificates/www.test1.com.csr b/reg-tests/pki/certificates/www.test1.com.csr
new file mode 100644
index 0000000..6482270
--- /dev/null
+++ b/reg-tests/pki/certificates/www.test1.com.csr
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICtTCCAZ0CAQAwRTELMAkGA1UEBhMCRlIxDjAMBgNVBAcTBVBhcmlzMQ4wDAYD
+VQQKEwV0ZXN0MTEWMBQGA1UEAxMNd3d3LnRlc3QxLmNvbTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAN34FMhN+tertLf50hQGVcR00pdk+pLCFyCuJU28
+OG7RCcFuKoxX3oyIS1r42ta9XLdVjjVjSm8NLU+taycKUEx0EV0+QhGkDHbRzPcz
+iUEOL+nXib4lti+xWEsYOjMwRto7ExJ6J1MUMdCruTRvSwwy8na/T1G89oPK1ZpG
+0LTudWVk9TR89AJLDehl/Ur271t1u4wk547YPT89d7Ntat2Lf5W5orjt77UGKOHp
+Cby4Px/tJEoYWbbpCRXzvApbDzGE+dkvU81bJA18DMZB/qyOmZqGHP4u9rfLBu/l
+dpSnyiODDgs6vPV+8Lx0OP3BWDXcmFaGbAsL/nMbl5jcu5kCAwEAAaArMCkGCSqG
+SIb3DQEJDjEcMBowGAYDVR0RBBEwD4INd3d3LnRlc3QxLmNvbTANBgkqhkiG9w0B
+AQsFAAOCAQEAoQLfxYGBPJljiwlODlnvjjgVcM4OwDYs3Qr/clGxwi3zKfGA9ngh
+t1qfjooypzMNnzeU2OEc7A81h3UY6zd/IrAR6D2+c09+kpiXHB5w5rVpTPGnihDZ
+Y0PtD9+vZV8/zPMQYOJApfaNJ3wyhMnNmg6t6L+G322mJS77A1qw5M19a6/38fPe
+DQSCeR+d5fBZj6/3k/Wizl5Mh2zget53SRCtvHsixO9JdJxzHJwNZ2rN+Q8fXk/F
+7kL1g/0bW64mofyMm3Iq0zDs2quj/MPgKUBx9qHRh69zDoWtNby3Brep0Js57Cds
+QLhwxEcJvd/OeNSOr4iXQXj9D3sj9EpTMQ==
+-----END CERTIFICATE REQUEST-----
diff --git a/reg-tests/pki/certificates/www.test1.com.pem b/reg-tests/pki/certificates/www.test1.com.pem
new file mode 100644
index 0000000..8d0f530
--- /dev/null
+++ b/reg-tests/pki/certificates/www.test1.com.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDxzCCAq+gAwIBAgIURbbHd6AXFZoZEmNAwQU1IbkeEjswDQYJKoZIhvcNAQEL
+BQAwYzELMAkGA1UEBhMCRlIxDjAMBgNVBAcTBVBhcmlzMR0wGwYDVQQKExRIQVBy
+b3h5IFRlY2hub2xvZ2llczElMCMGA1UEAxMcSEFQcm94eSBUZXN0IEludGVybWVk
+aWF0ZSBDQTAeFw0yMzA5MjAxNjI2MDBaFw0zMzA5MTcxNjI2MDBaMEUxCzAJBgNV
+BAYTAkZSMQ4wDAYDVQQHEwVQYXJpczEOMAwGA1UEChMFdGVzdDExFjAUBgNVBAMT
+DXd3dy50ZXN0MS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDd
++BTITfrXq7S3+dIUBlXEdNKXZPqSwhcgriVNvDhu0QnBbiqMV96MiEta+NrWvVy3
+VY41Y0pvDS1PrWsnClBMdBFdPkIRpAx20cz3M4lBDi/p14m+JbYvsVhLGDozMEba
+OxMSeidTFDHQq7k0b0sMMvJ2v09RvPaDytWaRtC07nVlZPU0fPQCSw3oZf1K9u9b
+dbuMJOeO2D0/PXezbWrdi3+VuaK47e+1Bijh6Qm8uD8f7SRKGFm26QkV87wKWw8x
+hPnZL1PNWyQNfAzGQf6sjpmahhz+Lva3ywbv5XaUp8ojgw4LOrz1fvC8dDj9wVg1
+3JhWhmwLC/5zG5eY3LuZAgMBAAGjgZAwgY0wDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
+JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFc8xugp1dGZ
++KqMGcfUmbTYEEurMB8GA1UdIwQYMBaAFHr9tGo8KeCWI09L6wA8+zwp7FEMMBgG
+A1UdEQQRMA+CDXd3dy50ZXN0MS5jb20wDQYJKoZIhvcNAQELBQADggEBAIzfQ//U
+1jqTmdjUNZHOqFvCcc06W9vDUJbeKSyStZnE/J3WHrJeLLNaUV00G93zLLRs6slT
+kZ4eEmUZlPGGz6hFK6d8jSIIxyaw/O5l9Ix/Z5cUMiScHNbiLBiyhy6AvF/NcJYl
+xQ6EUIcOqMxEL0dSRq6ckGZvnyFusPuNgfNeIy0Y1eI30En1mPNGQiu2DP7Ex4Ht
+dAiHT6ITXk43wHyXDqXpt97Rdbq1dNNP6sSkQ8r0IeDi5f/qSsBGbR1a9UoKkJOZ
+OO6IGhEb2XCWc2xquJpUHCOXhzaXj/SmxCDpWVW5tdKNZ96gUlp2Wtf0Rp25yFge
+4mCry3J674p8Oto=
+-----END CERTIFICATE-----
diff --git a/reg-tests/pki/config.json b/reg-tests/pki/config.json
new file mode 100644
index 0000000..4e4af21
--- /dev/null
+++ b/reg-tests/pki/config.json
@@ -0,0 +1,27 @@
+{
+ "signing": {
+ "default": {
+ "expiry": "87600h"
+ },
+ "profiles": {
+ "intermediate": {
+ "usages": ["cert sign", "crl sign"],
+ "expiry": "87600h",
+ "ca_constraint": {
+ "is_ca": true,
+ "max_path_len": 0,
+ "max_path_len_zero": true
+ }
+ },
+ "host": {
+ "usages": [
+ "signing",
+ "digital signing",
+ "key encipherment",
+ "server auth"
+ ],
+ "expiry": "87600h"
+ }
+ }
+ }
+}
diff --git a/reg-tests/pki/intermediate/intermediate-ca-key.pem b/reg-tests/pki/intermediate/intermediate-ca-key.pem
new file mode 100644
index 0000000..0d5203a
--- /dev/null
+++ b/reg-tests/pki/intermediate/intermediate-ca-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAldl9M8BbM0iHUQzcFGU7rcEGlfnEMxvjI4/Y23F72Zkewjl1
+NEaBnKCzBlBXguAp3sHzrw4RtoMY6NPC8Mkjbx+hLWdqWaGeIf+xBqYKl4wRf1ut
+HInV6/aZMszVeQCEqbMZFFsaL4Dwzqkgxo4uafyC+wR6R9q3M4bfBBqYkNctr8vj
+893YYj5xvbA4tG0gfG4Chwv4ODL4shrWreyUbJuhT1dklw6NNrvTkfgVZuFUngpX
+R0jqJJe073Eb/xGS5j1XJmHf2mpT1pDEtYVTLLRyh5xvtHPJStUOVO+ZX1fZ+i1a
+YCdB9ST7jBzn+uE5IU2DWWjAq3swH82Ow86YTwIDAQABAoIBAHGPiwSnJ/ZrZrET
+r819EocRG26ZBAk/fxk6MDvNevBizB6g8KOXMy6B0mpchJVYUCLSlVv6q43HOB9q
+K/fSVpomPD1ue/hFNNPLNFs3hhtnOPNthHl2M7pI/byz4qt6qw73/W+hwuxxKQ1U
+utP+eEo15QVaVVkS9XeFJIm1ph1M7BXdfBRweyQNrZpbpIc7OsHYyZbXsXRbL/ay
+4FnXH4gXHzS/iitbBfGn3hEKD3hOTwNWuZD5DM+QsmaXzJ3MB3vftSYPKfjlcSXT
+o9WRHR5uEy/a9z1GKJuTbF12cV1Sjt5OtSTF+AP7+tY6g//eUft9T8nKERIliQe/
+gVjsY9ECgYEAwC0xp2kebwWtC/oCHnFSJdwp2JTwNwWXtsDPxSf7W+Bq4CgtRJvR
+OoZIagQ7bNJGcsiTmCbI1+ckG/AFMIMEG4sE6BMAQ49mB6fm4CRNIli6Nyc6v21/
+3lY9DE7oi0Axb6nyXlohV0X/XFjqkv4eAY9EjNwSw9oqF6t4U5cfJBMCgYEAx52q
+XB5Q8ab+ZRgXy3eMPheNbo2Zx2yJ+nDccEn1LCPKCmXryvWoA1akF5qUxVnDXls+
+SmQU/oQZyXlCz+u3Am8HJvoKXc+KTWHCt+SKiM5k65tbmcgwFLfQBCnI61yE5SD0
+xgyK+r7g2OMm0Niraigykrmc0Lm8vrLnrFfRqlUCgYEAi/1f+k98t+suj1bjTEHI
+UYP7h6WXBr2wMpRpxXjGhbsIn5kkwKGw3C0NewzyLOdQIjUyLtex3nSlvSQu45PM
+3jN6s4OD4bMH4/PPHt/SwH5Zx+tvxBqD1vaDKgAhLa7pVCo8P7bwKp720dKDregm
++4Pdr65wjPLTTsK9uEaRjLkCgYBkrKsIDK4sQlnZaL5Pevq7Miu9jyL4xlAMhDFZ
+XKOPYHl8pwy17xGOpXrbALZ5lh0HkKMo57MC7mMHDuZYcPx6+L41tTPXPl31SxHm
+pxgLiXSys0cOlz1Qpaf/AYf41E+eM/HflOHfNre2C1I/UJebUay3/W8Ogi6kSxy2
++g+fhQKBgAgXincPNVyvlxbgrYsifwvdX5pZMdpL5OJ59tSf7wTkQTN9K+t1utff
+jU9erDntbetIE2r1SxJvgFLWbmZE4j8ORA3dcJUesToZM+4vKtQlzVS0w/iNZood
+I0NlWjfL0QTkMqBVjU2Inw/nkLlRqgZGP77BVD+KEqbqDBxwC9Ms
+-----END RSA PRIVATE KEY-----
diff --git a/reg-tests/pki/intermediate/intermediate-ca.csr b/reg-tests/pki/intermediate/intermediate-ca.csr
new file mode 100644
index 0000000..02e4cbf
--- /dev/null
+++ b/reg-tests/pki/intermediate/intermediate-ca.csr
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICqDCCAZACAQAwYzELMAkGA1UEBhMCRlIxDjAMBgNVBAcTBVBhcmlzMR0wGwYD
+VQQKExRIQVByb3h5IFRlY2hub2xvZ2llczElMCMGA1UEAxMcSEFQcm94eSBUZXN0
+IEludGVybWVkaWF0ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJXZfTPAWzNIh1EM3BRlO63BBpX5xDMb4yOP2Ntxe9mZHsI5dTRGgZygswZQV4Lg
+Kd7B868OEbaDGOjTwvDJI28foS1nalmhniH/sQamCpeMEX9brRyJ1ev2mTLM1XkA
+hKmzGRRbGi+A8M6pIMaOLmn8gvsEekfatzOG3wQamJDXLa/L4/Pd2GI+cb2wOLRt
+IHxuAocL+Dgy+LIa1q3slGyboU9XZJcOjTa705H4FWbhVJ4KV0dI6iSXtO9xG/8R
+kuY9VyZh39pqU9aQxLWFUyy0coecb7RzyUrVDlTvmV9X2fotWmAnQfUk+4wc5/rh
+OSFNg1lowKt7MB/NjsPOmE8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCQwtG4
+0Lvcpbp3YiYQGRkhP/2SEipTcQ+aVQXiZYpB0gHUZMDJ9xP1wZ+E6lhE9NGQp6Xj
+ewLCup/4UEAEDM6vSbYafpgN3pTJiSjhy548xkKwrm/UvzG68IpfGDgQzwaEtrux
+SmM/v5EH0p3THYIhysqdgJu3M0nhrRiuBx1w/MRPSQW58U2JarOQwFF9OUYPcsAV
+hQJWp8waWEyolMhaCx8z+sUngbV9c0PdsillV++4PMOCl/1RdswufYiYBcvo5js6
+cM0V8y3nFcJnki3NYHe6fZ8J576Lptfwfzn3hlas3vG2kTetEbWaKR5iPzEMibtZ
+AFpgLkgbAY7pDtry
+-----END CERTIFICATE REQUEST-----
diff --git a/reg-tests/pki/intermediate/intermediate-ca.pem b/reg-tests/pki/intermediate/intermediate-ca.pem
new file mode 100644
index 0000000..9856300
--- /dev/null
+++ b/reg-tests/pki/intermediate/intermediate-ca.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDuTCCAqGgAwIBAgIUQQtTP1aDfRAnDdjKkaUT2py2fmswDQYJKoZIhvcNAQEL
+BQAwYjELMAkGA1UEBhMCRlIxDjAMBgNVBAcTBVBhcmlzMR0wGwYDVQQKExRIQVBy
+b3h5IFRlY2hub2xvZ2llczEkMCIGA1UEAxMbSEFQcm94eSBSb290IFRlc3QgQXV0
+aG9yaXR5MB4XDTIzMDkyMDE2MjQwMFoXDTMzMDkxNzE2MjQwMFowYzELMAkGA1UE
+BhMCRlIxDjAMBgNVBAcTBVBhcmlzMR0wGwYDVQQKExRIQVByb3h5IFRlY2hub2xv
+Z2llczElMCMGA1UEAxMcSEFQcm94eSBUZXN0IEludGVybWVkaWF0ZSBDQTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJXZfTPAWzNIh1EM3BRlO63BBpX5
+xDMb4yOP2Ntxe9mZHsI5dTRGgZygswZQV4LgKd7B868OEbaDGOjTwvDJI28foS1n
+almhniH/sQamCpeMEX9brRyJ1ev2mTLM1XkAhKmzGRRbGi+A8M6pIMaOLmn8gvsE
+ekfatzOG3wQamJDXLa/L4/Pd2GI+cb2wOLRtIHxuAocL+Dgy+LIa1q3slGyboU9X
+ZJcOjTa705H4FWbhVJ4KV0dI6iSXtO9xG/8RkuY9VyZh39pqU9aQxLWFUyy0coec
+b7RzyUrVDlTvmV9X2fotWmAnQfUk+4wc5/rhOSFNg1lowKt7MB/NjsPOmE8CAwEA
+AaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0O
+BBYEFHr9tGo8KeCWI09L6wA8+zwp7FEMMB8GA1UdIwQYMBaAFB4wopglmOnetKea
+jkq9OymofpZfMA0GCSqGSIb3DQEBCwUAA4IBAQDQamqX11VfTB5USqAL1E0/qHqG
+WivOWX2K5lCfbalg7Fqlm1d0hKffPODD3RAOU7UhP9B1xc9NRBgbNPEEMu/O92PS
+C5H8WxGoKfa4TuX8JfhhpUGpRelFFHU7mVVyMh7RDQmfFdxC8ej8+iTvBXtacMhh
+VWokTIakyFCj7u/qcQKhpzoTDq9VRE+lmOFYzMtHqk+qGVXDgG8z/e7z5UP98ttI
+XXsQ50Mi6ow8P118eRjJI01DZUu8QnYt/+jhqAFipS2OjyV4Jlq+wGZ4xB9gonlf
+lTdqR19oFnIFi30boIB33MRxz9qWZy7ay5jUV6jGauymQI/1waPtv/KIjXzt
+-----END CERTIFICATE-----
diff --git a/reg-tests/pki/intermediate/intermediate-csr.json b/reg-tests/pki/intermediate/intermediate-csr.json
new file mode 100644
index 0000000..2cbcaef
--- /dev/null
+++ b/reg-tests/pki/intermediate/intermediate-csr.json
@@ -0,0 +1,14 @@
+{
+ "CN": "HAProxy Test Intermediate CA",
+ "key": {
+ "algo": "rsa",
+ "size": 2048
+ },
+ "names": [
+ {
+ "C": "FR",
+ "L": "Paris",
+ "O": "HAProxy Technologies"
+ }
+ ]
+}
diff --git a/reg-tests/pki/root/root-ca-key.pem b/reg-tests/pki/root/root-ca-key.pem
new file mode 100644
index 0000000..a51d46c
--- /dev/null
+++ b/reg-tests/pki/root/root-ca-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA6lV5gcewWGoyPcQWuK75SHyFHBCJVIaTQhDrFTdUTAZeAELk
+cbRhaDoXaPZoisDnWIH2WrfJLmVWO4MfYdx4rzAd5yh5GDeII60bSYyDBPgmC0TA
+3RdvwjT1Dnwgsi/S/+BmpIsjoCwvmKuXXYkFX18wScYbAqEKD/8eWnqUysY2epBY
+0Uv8v2N6I2qtMXl0JUFm65+XZmUmEQe25u9DEMDm+8aPCwCM+wPsFaWXanOHjSe6
+IeG/1E2AoWB5MN3td40zuoGHFF/UWi5nMQL6XbBolv7WOIL92tM8pPfO0QNMSe3i
+CqxnkNyqEX9is8+2O5J/WFdVyr9JzGg6IEQ9wwIDAQABAoIBACHtyE8LK7RRg/6/
+co7A/uUI6nj6x/eOGKo7Kt6CiVkMnvWouczg0i22I4eWDeLxNU3yW0odTCrEj2zE
+enm/41VyQRIkIQxplfOcb9QBXUMN7uw4wzf/2bWj10uGm3FRTVqxEguG/dyGKUoQ
+pjTrzvRVIve7kFOcH4nbZXiyQPLu4yakdS/o5jKjpkhhzbSxAJ62mrC41GEWmQqb
+419iVsyj5iSV4ixQAowpBfkIu33ZTiNFd5Pd/OjPV90ID9ebwcBhiXUAvZvU8K9M
+W0d7fjqeCooNuVBFwi5E/Bxa3zYy8Bo6SCSv9U6RnTmPOdId0LBx8ClI/sZvZo+n
+cEwg5dECgYEA7mSny6+jPp5D6JRfyX5X3VQMagBKCY6UREk0x79C5XDGxHrIG3Dk
+xAxSpyjYMFV4Ju+5pL5o71ej6RzslHSVcVVufudD0CxBOOPWoK/7EuceGkwoXuPu
+cralaA8iyamArT8DRNgDELoxTVp30Ihfv3OCx0MRe2P27SgrkGtFhMkCgYEA+6QR
+uanKdopl4H9Pylp8xLcqpO7oh+IKnNg6liUsDO61c/5BQdI4FteOb68+wKmIGSIR
+R/3NIOpnlYLINH4+QBM/OE3oT4lGYwQ/zYXW1n2bCuyYKaHRbAjDqMoys5iZu9nw
+nspcBMhKuvk5EQOLuu+YWW+loCSgWkr94pAHcCsCgYAfLlM0NRjpC9JeDWop9LiR
+XnjxNHB6p4eFFv4sUjvxvrqA4H5j+HQzoFj/PDxqtgMtNJXXkoAvLgtmZj4bfNQ/
+Kql1N9KK2/777fEYu2vfoRMy5VsybiW2I2WnIrOuJNmLz34h9w8PlQr1zyt0vyGm
+7PjiD0euF/koM+Te0ukY4QKBgQDqZ5L7V+Z5NcJgtTcmT9QZimX27XU93pn0MJei
+dU3rXhE404cGQURuQq0z7BKQdVuJzeo7HXiPSMrkwsar300tcsBZOnlEXaNraPHm
+CN5vPuHF805quYnTEPbxrCg+k8/g5Mr3n5jH+6thL/awmpT2tWk9JnsqCfQ1J9YH
+zhKfsQKBgQDlg8uKdBrQwM7bWeFEwlwRMMIBTcfvBqXtthckU8BmxwrQ8bk8az03
+3pQp3BiEYlHyI0F+ITDMci6fTega5ehJmQWAdFO+hiBPVkU7rdmukB5gCU1aoHcz
+VwGZ5ZXe60aew4jILdkmrPC4AJYQ0dil0yN6Q8pucSfOThhgiq2gFg==
+-----END RSA PRIVATE KEY-----
diff --git a/reg-tests/pki/root/root-ca.csr b/reg-tests/pki/root/root-ca.csr
new file mode 100644
index 0000000..f9817b8
--- /dev/null
+++ b/reg-tests/pki/root/root-ca.csr
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICyTCCAbECAQAwYjELMAkGA1UEBhMCRlIxDjAMBgNVBAcTBVBhcmlzMR0wGwYD
+VQQKExRIQVByb3h5IFRlY2hub2xvZ2llczEkMCIGA1UEAxMbSEFQcm94eSBSb290
+IFRlc3QgQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+6lV5gcewWGoyPcQWuK75SHyFHBCJVIaTQhDrFTdUTAZeAELkcbRhaDoXaPZoisDn
+WIH2WrfJLmVWO4MfYdx4rzAd5yh5GDeII60bSYyDBPgmC0TA3RdvwjT1Dnwgsi/S
+/+BmpIsjoCwvmKuXXYkFX18wScYbAqEKD/8eWnqUysY2epBY0Uv8v2N6I2qtMXl0
+JUFm65+XZmUmEQe25u9DEMDm+8aPCwCM+wPsFaWXanOHjSe6IeG/1E2AoWB5MN3t
+d40zuoGHFF/UWi5nMQL6XbBolv7WOIL92tM8pPfO0QNMSe3iCqxnkNyqEX9is8+2
+O5J/WFdVyr9JzGg6IEQ9wwIDAQABoCIwIAYJKoZIhvcNAQkOMRMwETAPBgNVHRMB
+Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDC6yA0gkpzHntF8lzeHTUMLlEy
+s7tIIStZcmhVjd4u2oNC6fSGoygVgITemb0aQXz49oWFPHRLbZrsDva2jJQfA3nU
+MuHWC9FtFEhkFMbHj9apr+vEDhUXPYc9jr4j2lYwhVcvT5XhL+fN6Hl2WHtJJhyP
+nYbUQHlLdKLE6aNfrb6pyXZ3G0nLrH+Zs0FibnSW0tMk7MTS2eHWn793VxuPpCHg
++oCshOk6CdWUY9p5lC4NynNXUeqP6xRmQxzeVneNouTLHsGdY2lZVBdOgIvjQMAg
+ZPIC6kLgFI50A8SDMIuIGwQ1imS5govlcicemXh2ee/IBR6PmwF5MG9SVZ3h
+-----END CERTIFICATE REQUEST-----
diff --git a/reg-tests/pki/root/root-ca.pem b/reg-tests/pki/root/root-ca.pem
new file mode 100644
index 0000000..4e3c903
--- /dev/null
+++ b/reg-tests/pki/root/root-ca.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDlDCCAnygAwIBAgIUaa8nhmRvY/xmnTuVk0gnbpyms8MwDQYJKoZIhvcNAQEL
+BQAwYjELMAkGA1UEBhMCRlIxDjAMBgNVBAcTBVBhcmlzMR0wGwYDVQQKExRIQVBy
+b3h5IFRlY2hub2xvZ2llczEkMCIGA1UEAxMbSEFQcm94eSBSb290IFRlc3QgQXV0
+aG9yaXR5MB4XDTIzMDkyMDE2MjMwMFoXDTQzMDkxNTE2MjMwMFowYjELMAkGA1UE
+BhMCRlIxDjAMBgNVBAcTBVBhcmlzMR0wGwYDVQQKExRIQVByb3h5IFRlY2hub2xv
+Z2llczEkMCIGA1UEAxMbSEFQcm94eSBSb290IFRlc3QgQXV0aG9yaXR5MIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6lV5gcewWGoyPcQWuK75SHyFHBCJ
+VIaTQhDrFTdUTAZeAELkcbRhaDoXaPZoisDnWIH2WrfJLmVWO4MfYdx4rzAd5yh5
+GDeII60bSYyDBPgmC0TA3RdvwjT1Dnwgsi/S/+BmpIsjoCwvmKuXXYkFX18wScYb
+AqEKD/8eWnqUysY2epBY0Uv8v2N6I2qtMXl0JUFm65+XZmUmEQe25u9DEMDm+8aP
+CwCM+wPsFaWXanOHjSe6IeG/1E2AoWB5MN3td40zuoGHFF/UWi5nMQL6XbBolv7W
+OIL92tM8pPfO0QNMSe3iCqxnkNyqEX9is8+2O5J/WFdVyr9JzGg6IEQ9wwIDAQAB
+o0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
+HjCimCWY6d60p5qOSr07Kah+ll8wDQYJKoZIhvcNAQELBQADggEBAIA+oiN1UsQi
+XQTM4YnBNMU0X0TDBG2tzg48rJBbyJrhYynd4EgHfxGIuNsgGlhzF31QIbEDf4Et
+Rs7SSPhozBaQ81Nnk4HqHH3kSoXt4q3FQQa6kmH6vVcQ121lMa29f/VvcRYwzgzi
+p29aSVpCsz0PTL7IWgXs2AiH0VoK00ULTzaxIJbeByY+hZkaUmTnTDRxSv5z7i4f
+GoJikS8wUogc0QFSg6lwA0B5lGO6JBHpZ8iFErGPKwZXcwKQfTFA6v6vFQspIwF0
+GllXWObls+I4clEqtr0QK4V00GSS/YmiTDNOGMYv61RUQPmrpsomofznbS1jQfLG
+QskPnU6PKhQ=
+-----END CERTIFICATE-----
diff --git a/reg-tests/pki/root/root-csr.json b/reg-tests/pki/root/root-csr.json
new file mode 100644
index 0000000..90f6274
--- /dev/null
+++ b/reg-tests/pki/root/root-csr.json
@@ -0,0 +1,17 @@
+{
+ "CN": "HAProxy Root Test Authority",
+ "key": {
+ "algo": "rsa",
+ "size": 2048
+ },
+ "names": [
+ {
+ "C": "FR",
+ "L": "Paris",
+ "O": "HAProxy Technologies"
+ }
+ ],
+ "ca": {
+ "expiry": "175200h"
+ }
+}
diff --git a/reg-tests/sample_fetches/cond_set_var.vtc b/reg-tests/sample_fetches/cond_set_var.vtc
new file mode 100644
index 0000000..67786ae
--- /dev/null
+++ b/reg-tests/sample_fetches/cond_set_var.vtc
@@ -0,0 +1,362 @@
+#REGTEST_TYPE=devel
+
+# This regtest checks the multiple conditions that can be specified to a
+# set-var call (be it a converter or HTTP or TCP action). It mainly uses the
+# actions but since the "var_set" function is used for the converter and for
+# the actions, it should be enough to focus on one type of set-var.
+# Among the variables that can be defined and the multiple scopes they can
+# have, the proc scope is the only one having a specific behaviour. Proc scoped
+# variables are created during init when a variable of any other scope is
+# created during the first successful set-var.
+# Since this test uses variables of different scopes, the validation cannot be
+# based on the "show var" command of the CLI because it only displays process
+# variables. It then always follows the same logic, for every sub test case :
+# an HTTP header is added to the response in which we add a concatenation of
+# all the tested variables (which exist in the request/response scope). These
+# HTTP headers are then tested upon an expected result (which changes for every
+# test case).
+#
+
+varnishtest "Test the conditional set-var converter and action"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 10 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ set-var proc.int12 int(12)
+ set-var proc.int5 var(proc.str60,60),div(proc.int12)
+
+ defaults
+ mode http
+ timeout connect 100ms
+ timeout client 1s
+ timeout server 1s
+
+ listen main-fe
+ bind "fd@${mainfe}"
+
+ use_backend ifexists_be if { path_beg /ifexists }
+ use_backend ifnotexists_be if { path_beg /ifnotexists }
+ use_backend ifempty_be if { path_beg /ifempty }
+ use_backend ifnotempty_be if { path_beg /ifnotempty }
+ use_backend ifset_be if { path_beg /ifset }
+ use_backend ifnotset_be if { path_beg /ifnotset }
+ use_backend ifgt_be if { path_beg /ifgt }
+ use_backend iflt_be if { path_beg /iflt }
+ use_backend combined_be if { path_beg /combined }
+ use_backend converter_be if { path_beg /converter }
+
+
+ backend ifexists_be
+ server s1 ${s1_addr}:${s1_port}
+
+ # proc scope variables are created during configuration parsing so the
+ # ifexists condition will always be true for those variables
+ http-response set-var(proc.ifexists_proc,ifexists) var(proc.int12)
+ http-response set-var(sess.ifexists_sess,ifexists) var(proc.int5)
+ http-response set-var(res.ifexists_res,ifexists) str(toto)
+
+ http-response set-header x-var "proc.ifexists=%[var(proc.ifexists_proc)] sess.ifexists=%[var(sess.ifexists_sess)] res.ifexists=%[var(res.ifexists_res)]"
+
+
+ backend ifnotexists_be
+ server s1 ${s1_addr}:${s1_port}
+
+ http-response set-header x-var-init "proc.ifnotexists=%[var(proc.ifnotexists_proc)] sess.ifnotexists=%[var(sess.ifnotexists_sess)] res.ifnotexists=%[var(res.ifnotexists_res)]"
+
+ http-response set-var(proc.ifnotexists_proc,ifnotexists) var(proc.int12)
+ http-response set-var(sess.ifnotexists_sess,ifnotexists) var(proc.int5)
+ http-response set-var(res.ifnotexists_res,ifnotexists) str(toto)
+
+ http-response set-header x-var "proc.ifnotexists=%[var(proc.ifnotexists_proc)] sess.ifnotexists=%[var(sess.ifnotexists_sess)] res.ifnotexists=%[var(res.ifnotexists_res)]"
+
+
+ backend ifempty_be
+ server s1 ${s1_addr}:${s1_port}
+ # init
+ http-response set-var(proc.ifempty_proc) str(ifempty_proc)
+ http-response set-var(sess.ifempty_sess) bin(6966656d7074795f73657373) #ifempty_sess
+ http-response set-var(res.ifempty_res) str(ifempty_res)
+ http-response set-var(res.ifempty_res_int) int(5)
+
+ http-response set-header x-var-init "proc.ifempty=%[var(proc.ifempty_proc)] sess.ifempty=%[var(sess.ifempty_sess)] res.ifempty=%[var(res.ifempty_res)] res.ifempty_res_int=%[var(res.ifempty_res_int)]"
+
+ # None of those set-var calls should actually change their respective variables
+ # since none of the samples is empty
+ http-response set-var(proc.ifempty_proc,ifempty) int(12)
+ http-response set-var(sess.ifempty_sess,ifempty) bool(false)
+ http-response set-var(res.ifempty_res,ifempty) bin(746F746F) # "toto"
+ http-response set-var(res.ifempty_res_int,ifempty) str(toto)
+
+ http-response set-header x-var1 "proc.ifempty=%[var(proc.ifempty_proc)] sess.ifempty=%[var(sess.ifempty_sess)] res.ifempty=%[var(res.ifempty_res)] res.ifempty_res_int=%[var(res.ifempty_res_int)]"
+
+ http-response set-var(proc.ifempty_proc,ifempty) str()
+ http-response set-var(sess.ifempty_sess,ifempty) str()
+ http-response set-var(res.ifempty_res,ifempty) str()
+ http-response set-var(res.ifempty_res_int,ifempty) int(7) # should not work, scalar types are never empty
+
+ http-response set-header x-var2 "proc.ifempty=%[var(proc.ifempty_proc)] sess.ifempty=%[var(sess.ifempty_sess)] res.ifempty=%[var(res.ifempty_res)] res.ifempty_res_int=%[var(res.ifempty_res_int)]"
+
+
+ backend ifnotempty_be
+ server s1 ${s1_addr}:${s1_port}
+ # init
+ http-response set-var(proc.ifnotempty_proc) str(ifnotempty_proc)
+ http-response set-var(sess.ifnotempty_sess) bin(69666e6f74656d7074795f73657373) # "ifnotempty_sess"
+ http-response set-var(res.ifnotempty_res) str(ifnotempty_res)
+ http-response set-var(res.ifnotempty_res_int) int(5)
+
+ http-response set-header x-var-init "proc.ifnotempty=%[var(proc.ifnotempty_proc)] sess.ifnotempty=%[var(sess.ifnotempty_sess)] res.ifnotempty=%[var(res.ifnotempty_res)] res.ifnotempty_res_int=%[var(res.ifnotempty_res_int)]"
+
+ # None of those set-var calls should actually change their respective variables
+ # since none of the samples is not empty
+ http-response set-var(proc.ifnotempty_proc,ifnotempty) str(toto)
+ http-response set-var(sess.ifnotempty_sess,ifnotempty) bin(746F746F) # "toto"
+ http-response set-var(res.ifnotempty_res,ifnotempty) str(tata)
+ http-response set-var(res.ifnotempty_res_int,ifnotempty) int(6)
+
+ http-response set-header x-var1 "proc.ifnotempty=%[var(proc.ifnotempty_proc)] sess.ifnotempty=%[var(sess.ifnotempty_sess)] res.ifnotempty=%[var(res.ifnotempty_res)] res.ifnotempty_res_int=%[var(res.ifnotempty_res_int)]"
+
+ # The first three variables should remain unchanged.
+ http-response set-var(proc.ifnotempty_proc,ifnotempty) str()
+ http-response set-var(sess.ifnotempty_sess,ifnotempty) str()
+ http-response set-var(res.ifnotempty_res,ifnotempty) str()
+ http-response set-var(res.ifnotempty_res_int,ifnotempty) int(7) # should not work
+
+ http-response set-header x-var2 "proc.ifnotempty=%[var(proc.ifnotempty_proc)] sess.ifnotempty=%[var(sess.ifnotempty_sess)] res.ifnotempty=%[var(res.ifnotempty_res)] res.ifnotempty_res_int=%[var(res.ifnotempty_res_int)]"
+
+
+ backend ifset_be
+ server s1 ${s1_addr}:${s1_port}
+ # init
+ http-response set-var(proc.ifset_proc) str(ifset_proc)
+ http-response set-var(sess.ifset_sess) bin(69667365745f73657373) # "ifset_sess"
+ http-response set-var(res.ifset_res) str(ifset_res)
+ http-response set-var(res.ifset_res_int) int(5)
+
+ http-response set-header x-var-init "proc.ifset=%[var(proc.ifset_proc)] sess.ifset=%[var(sess.ifset_sess)] res.ifset=%[var(res.ifset_res)] res.ifset_res_int=%[var(res.ifset_res_int)]"
+
+ # All those set-var calls should succeed
+ http-response set-var(proc.ifset_proc,ifset) str(toto)
+ http-response set-var(sess.ifset_sess,ifset) bin(746F746F) # "toto"
+ http-response set-var(res.ifset_res,ifset) int(123)
+ http-response set-var(res.ifset_res_int,ifset) str(azerty)
+
+ http-response set-header x-var1 "proc.ifset=%[var(proc.ifset_proc)] sess.ifset=%[var(sess.ifset_sess)] res.ifset=%[var(res.ifset_res)] res.ifset_res_int=%[var(res.ifset_res_int)]"
+
+ http-response unset-var(proc.ifset_proc)
+ http-response unset-var(sess.ifset_sess)
+ http-response unset-var(res.ifset_res)
+ http-response unset-var(res.ifset_res_int)
+
+ http-response set-header x-var2 "proc.ifset=%[var(proc.ifset_proc)] sess.ifset=%[var(sess.ifset_sess)] res.ifset=%[var(res.ifset_res)] res.ifset_res_int=%[var(res.ifset_res_int)]"
+
+ # None of those set-var calls should succeed
+ http-response set-var(proc.ifset_proc,ifset) str(toto)
+ http-response set-var(sess.ifset_sess,ifset) bin(746F746F) # "toto"
+ http-response set-var(res.ifset_res,ifset) int(123)
+ http-response set-var(res.ifset_res_int,ifset) str(azerty)
+
+ http-response set-header x-var3 "proc.ifset=%[var(proc.ifset_proc)] sess.ifset=%[var(sess.ifset_sess)] res.ifset=%[var(res.ifset_res)] res.ifset_res_int=%[var(res.ifset_res_int)]"
+
+
+ backend ifnotset_be
+ server s1 ${s1_addr}:${s1_port}
+ # init
+ http-response set-var(proc.ifnotset_proc) str(ifnotset_proc)
+ http-response set-var(sess.ifnotset_sess) bin(69666e6f747365745f73657373) # "ifnotset_sess"
+ http-response set-var(res.ifnotset_res) str(ifnotset_res)
+ http-response set-var(res.ifnotset_res_int) int(5)
+
+ http-response set-header x-var-init "proc.ifnotset=%[var(proc.ifnotset_proc)] sess.ifnotset=%[var(sess.ifnotset_sess)] res.ifnotset=%[var(res.ifnotset_res)] res.ifnotset_res_int=%[var(res.ifnotset_res_int)]"
+
+ # None of those set-var calls should succeed
+ http-response set-var(proc.ifnotset_proc,ifnotset) str(toto)
+ http-response set-var(sess.ifnotset_sess,ifnotset) bin(746F746F) # "toto"
+ http-response set-var(res.ifnotset_res,ifnotset) int(123)
+ http-response set-var(res.ifnotset_res_int,ifnotset) str(azerty)
+
+ http-response set-header x-var1 "proc.ifnotset=%[var(proc.ifnotset_proc)] sess.ifnotset=%[var(sess.ifnotset_sess)] res.ifnotset=%[var(res.ifnotset_res)] res.ifnotset_res_int=%[var(res.ifnotset_res_int)]"
+
+ http-response unset-var(proc.ifnotset_proc)
+ http-response unset-var(sess.ifnotset_sess)
+ http-response unset-var(res.ifnotset_res)
+ http-response unset-var(res.ifnotset_res_int)
+
+ http-response set-header x-var2 "proc.ifnotset=%[var(proc.ifnotset_proc)] sess.ifnotset=%[var(sess.ifnotset_sess)] res.ifnotset=%[var(res.ifnotset_res)] res.ifnotset_res_int=%[var(res.ifnotset_res_int)]"
+
+ # All of those set-var calls should succeed
+ http-response set-var(proc.ifnotset_proc,ifnotset) str(toto)
+ http-response set-var(sess.ifnotset_sess,ifnotset) bin(746F746F) # "toto"
+ http-response set-var(res.ifnotset_res,ifnotset) int(123)
+ http-response set-var(res.ifnotset_res_int,ifnotset) str(azerty)
+
+ http-response set-header x-var3 "proc.ifnotset=%[var(proc.ifnotset_proc)] sess.ifnotset=%[var(sess.ifnotset_sess)] res.ifnotset=%[var(res.ifnotset_res)] res.ifnotset_res_int=%[var(res.ifnotset_res_int)]"
+
+ backend ifgt_be
+ server s1 ${s1_addr}:${s1_port}
+ # init
+ http-response set-var(proc.ifgt_proc) str(ifgt_proc)
+ http-response set-var(sess.ifgt_sess) bin(696667745f73657373) # "ifgt_sess"
+ http-response set-var(res.ifgt_res1) str(ifgt_res)
+ http-response set-var(res.ifgt_res2) int(5)
+ http-response set-var(res.ifgt_res_int1) int(5)
+ http-response set-var(res.ifgt_res_int2) int(5)
+
+ http-response set-header x-var-init "proc.ifgt=%[var(proc.ifgt_proc)] sess.ifgt=%[var(sess.ifgt_sess)] res.ifgt1=%[var(res.ifgt_res1)] res.ifgt2=%[var(res.ifgt_res2)] res.ifgt_res_int1=%[var(res.ifgt_res_int1)] res.ifgt_res_int2=%[var(res.ifgt_res_int2)]"
+
+ # ifgt does not apply on non scalar type so the two following set-var will ignore the condition
+ http-response set-var(proc.ifgt_proc,ifgt) str(toto)
+ http-response set-var(sess.ifgt_sess,ifgt) bin(746F746F) # "toto"
+ # ifgt can only apply when the variable and the sample are both scalar. In this case, the variable was a string so the condition is ignored
+ http-response set-var(res.ifgt_res1,ifgt) int(55)
+ # ifgt can only apply when the variable and the sample are both scalar. In this case, the sample is a string so the condition is ignored
+ http-response set-var(res.ifgt_res2,ifgt) str(text)
+ http-response set-var(res.ifgt_res_int1,ifgt) int(55) # should not work
+ http-response set-var(res.ifgt_res_int2,ifgt) int(2) # should work
+
+ http-response set-header x-var1 "proc.ifgt=%[var(proc.ifgt_proc)] sess.ifgt=%[var(sess.ifgt_sess)] res.ifgt1=%[var(res.ifgt_res1)] res.ifgt2=%[var(res.ifgt_res2)] res.ifgt_res_int1=%[var(res.ifgt_res_int1)] res.ifgt_res_int2=%[var(res.ifgt_res_int2)]"
+
+
+ backend iflt_be
+ server s1 ${s1_addr}:${s1_port}
+ # init
+ http-response set-var(proc.iflt_proc) str(iflt_proc)
+ http-response set-var(sess.iflt_sess) bin(69666c745f73657373) # "iflt_sess"
+ http-response set-var(res.iflt_res1) str(iflt_res)
+ http-response set-var(res.iflt_res2) int(5)
+ http-response set-var(res.iflt_res_int1) int(5)
+ http-response set-var(res.iflt_res_int2) int(5)
+
+ http-response set-header x-var-init "proc.iflt=%[var(proc.iflt_proc)] sess.iflt=%[var(sess.iflt_sess)] res.iflt1=%[var(res.iflt_res1)] res.iflt2=%[var(res.iflt_res2)] res.iflt_res_int1=%[var(res.iflt_res_int1)] res.iflt_res_int2=%[var(res.iflt_res_int2)]"
+
+ # iflt does not apply on non scalar type so the two following set-var will ignore the condition
+ http-response set-var(proc.iflt_proc,iflt) str(toto)
+ http-response set-var(sess.iflt_sess,iflt) bin(746F746F) # "toto"
+ # iflt can only apply when the variable and the sample are both scalar. In this case, the variable was a string so the condition is ignored
+ http-response set-var(res.iflt_res1,iflt) int(55)
+ # iflt can only apply when the variable and the sample are both scalar. In this case, the sample is a string so the condition is ignored
+ http-response set-var(res.iflt_res2,iflt) str(text)
+ http-response set-var(res.iflt_res_int1,iflt) int(55) # should work
+ http-response set-var(res.iflt_res_int2,iflt) int(2) # should not work
+
+ http-response set-header x-var1 "proc.iflt=%[var(proc.iflt_proc)] sess.iflt=%[var(sess.iflt_sess)] res.iflt1=%[var(res.iflt_res1)] res.iflt2=%[var(res.iflt_res2)] res.iflt_res_int1=%[var(res.iflt_res_int1)] res.iflt_res_int2=%[var(res.iflt_res_int2)]"
+
+
+ # Test multiple conditions at once
+ backend combined_be
+ server s1 ${s1_addr}:${s1_port}
+ # init
+ http-response set-var(proc.combined_proc) str(combined_proc)
+ http-response set-var(res.combined_res) int(5)
+ http-response unset-var(proc.combined_proc)
+
+ http-response set-header x-var-init "proc.combined=%[var(proc.combined_proc)] res.combined=%[var(res.combined_res)]"
+
+ http-response set-var(proc.combined_proc,ifnotset,ifnotempty) str(toto)
+ http-response set-var(res.combined_res,ifset,iflt) int(55)
+
+ http-response set-header x-var1 "proc.combined=%[var(proc.combined_proc)] res.combined=%[var(res.combined_res)]"
+
+
+ # Test the set-var converter
+ backend converter_be
+ server s1 ${s1_addr}:${s1_port}
+
+ http-request deny if { req.len,set-var(proc.req_len,ifexists) -m int 0 }
+ http-request deny if { req.hdr("X-Cust"),set-var(sess.x_cust,ifnotempty,ifnotset),length -m int 0 }
+
+ http-response set-header x-var "proc.req_len=%[var(proc.req_len)] sess.x_cust=%[var(sess.x_cust)]"
+
+} -start
+
+
+client c1 -connect ${h1_mainfe_sock} {
+ txreq -url "/ifexists"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var == "proc.ifexists=12 sess.ifexists= res.ifexists="
+} -run
+
+client c2 -connect ${h1_mainfe_sock} {
+ txreq -url "/ifnotexists"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var-init == "proc.ifnotexists= sess.ifnotexists= res.ifnotexists="
+ expect resp.http.x-var == "proc.ifnotexists= sess.ifnotexists=5 res.ifnotexists=toto"
+} -run
+
+client c3 -connect ${h1_mainfe_sock} {
+ txreq -url "/ifempty"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var-init == "proc.ifempty=ifempty_proc sess.ifempty=ifempty_sess res.ifempty=ifempty_res res.ifempty_res_int=5"
+ expect resp.http.x-var1 == "proc.ifempty=ifempty_proc sess.ifempty=ifempty_sess res.ifempty=ifempty_res res.ifempty_res_int=5"
+ expect resp.http.x-var2 == "proc.ifempty= sess.ifempty= res.ifempty= res.ifempty_res_int=5"
+} -run
+
+client c4 -connect ${h1_mainfe_sock} {
+ txreq -url "/ifnotempty"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var-init == "proc.ifnotempty=ifnotempty_proc sess.ifnotempty=ifnotempty_sess res.ifnotempty=ifnotempty_res res.ifnotempty_res_int=5"
+ expect resp.http.x-var1 == "proc.ifnotempty=toto sess.ifnotempty=toto res.ifnotempty=tata res.ifnotempty_res_int=6"
+ expect resp.http.x-var2 == "proc.ifnotempty=toto sess.ifnotempty=toto res.ifnotempty=tata res.ifnotempty_res_int=7"
+} -run
+
+client c5 -connect ${h1_mainfe_sock} {
+ txreq -url "/ifset"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var-init == "proc.ifset=ifset_proc sess.ifset=ifset_sess res.ifset=ifset_res res.ifset_res_int=5"
+ expect resp.http.x-var1 == "proc.ifset=toto sess.ifset=toto res.ifset=123 res.ifset_res_int=azerty"
+ expect resp.http.x-var2 == "proc.ifset= sess.ifset= res.ifset= res.ifset_res_int="
+ expect resp.http.x-var3 == "proc.ifset= sess.ifset= res.ifset= res.ifset_res_int="
+} -run
+
+client c6 -connect ${h1_mainfe_sock} {
+ txreq -url "/ifnotset"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var-init == "proc.ifnotset=ifnotset_proc sess.ifnotset=ifnotset_sess res.ifnotset=ifnotset_res res.ifnotset_res_int=5"
+ expect resp.http.x-var1 == "proc.ifnotset=ifnotset_proc sess.ifnotset=ifnotset_sess res.ifnotset=ifnotset_res res.ifnotset_res_int=5"
+ expect resp.http.x-var2 == "proc.ifnotset= sess.ifnotset= res.ifnotset= res.ifnotset_res_int="
+ expect resp.http.x-var3 == "proc.ifnotset=toto sess.ifnotset=toto res.ifnotset=123 res.ifnotset_res_int=azerty"
+} -run
+
+client c7 -connect ${h1_mainfe_sock} {
+ txreq -url "/ifgt"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var-init == "proc.ifgt=ifgt_proc sess.ifgt=ifgt_sess res.ifgt1=ifgt_res res.ifgt2=5 res.ifgt_res_int1=5 res.ifgt_res_int2=5"
+ expect resp.http.x-var1 == "proc.ifgt=toto sess.ifgt=toto res.ifgt1=55 res.ifgt2=text res.ifgt_res_int1=5 res.ifgt_res_int2=2"
+} -run
+
+client c8 -connect ${h1_mainfe_sock} {
+ txreq -url "/iflt"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var-init == "proc.iflt=iflt_proc sess.iflt=iflt_sess res.iflt1=iflt_res res.iflt2=5 res.iflt_res_int1=5 res.iflt_res_int2=5"
+ expect resp.http.x-var1 == "proc.iflt=toto sess.iflt=toto res.iflt1=55 res.iflt2=text res.iflt_res_int1=55 res.iflt_res_int2=5"
+} -run
+
+client c9 -connect ${h1_mainfe_sock} {
+ txreq -url "/combined"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var-init == "proc.combined= res.combined=5"
+ expect resp.http.x-var1 == "proc.combined=toto res.combined=55"
+} -run
+
+client c10 -connect ${h1_mainfe_sock} {
+ txreq -url "/converter" -hdr "X-Cust: foobar"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var == "proc.req_len=67 sess.x_cust=foobar"
+} -run
diff --git a/reg-tests/sample_fetches/cook.vtc b/reg-tests/sample_fetches/cook.vtc
new file mode 100644
index 0000000..b0f5472
--- /dev/null
+++ b/reg-tests/sample_fetches/cook.vtc
@@ -0,0 +1,132 @@
+varnishtest "cook sample fetch Test"
+
+feature ignore_unknown_macro
+
+# TEST - 1
+# Cookie from request
+server s1 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request set-var(txn.count) req.cook_cnt()
+ http-request set-var(txn.val) req.cook_val()
+ http-request set-var(txn.val_cook2) req.cook_val(cook2)
+ http-request set-var(txn.cook_names) req.cook_names
+ http-response set-header count %[var(txn.count)]
+ http-response set-header val %[var(txn.val)]
+ http-response set-header val_cook2 %[var(txn.val_cook2)]
+ http-response set-header cook_names %[var(txn.cook_names)]
+
+ default_backend be
+
+ backend be
+ server srv1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/" \
+ -hdr "cookie: cook1=0; cook2=123; cook3=22"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.count == "3"
+ expect resp.http.val == "0"
+ expect resp.http.val_cook2 == "123"
+ expect resp.http.cook_names == "cook1,cook2,cook3"
+} -run
+
+# TEST - 2
+# Set-Cookie from response
+server s2 {
+ rxreq
+ txresp -hdr "Set-Cookie: cook1=0; cook2=123; cook3=22"
+} -start
+
+haproxy h2 -conf {
+ defaults
+ mode http
+
+ frontend fe
+ bind "fd@${fe}"
+ http-response set-var(txn.cook_names) res.cook_names
+ http-response set-header cook_names %[var(txn.cook_names)]
+
+ default_backend be
+
+ backend be
+ server srv2 ${s2_addr}:${s2_port}
+} -start
+
+client c2 -connect ${h2_fe_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.cook_names == "cook1"
+} -run
+
+# TEST - 3
+# Multiple Cookie headers from request
+server s3 {
+ rxreq
+ txresp
+} -start
+
+haproxy h3 -conf {
+ defaults
+ mode http
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request set-var(txn.cook_names) req.cook_names
+ http-response set-header cook_names %[var(txn.cook_names)]
+
+ default_backend be
+
+ backend be
+ server srv3 ${s3_addr}:${s3_port}
+} -start
+
+client c3 -connect ${h3_fe_sock} {
+ txreq -url "/" \
+ -hdr "cookie: cook1=0; cook2=123; cook3=22" \
+ -hdr "cookie: cook4=1; cook5=2; cook6=3"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.cook_names == "cook1,cook2,cook3,cook4,cook5,cook6"
+} -run
+
+# TEST - 4
+# Multiple Set-Cookie headers from response
+server s4 {
+ rxreq
+ txresp -hdr "Set-Cookie: cook1=0; cook2=123; cook3=22" \
+ -hdr "Set-Cookie: cook4=1; cook5=2; cook6=3"
+} -start
+
+haproxy h4 -conf {
+ defaults
+ mode http
+
+ frontend fe
+ bind "fd@${fe}"
+ http-response set-var(txn.cook_names) res.cook_names
+ http-response set-header cook_names %[var(txn.cook_names)]
+
+ default_backend be
+
+ backend be
+ server srv4 ${s4_addr}:${s4_port}
+} -start
+
+client c4 -connect ${h4_fe_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.cook_names == "cook1,cook4"
+} -run
diff --git a/reg-tests/sample_fetches/hashes.vtc b/reg-tests/sample_fetches/hashes.vtc
new file mode 100644
index 0000000..2c2f60d
--- /dev/null
+++ b/reg-tests/sample_fetches/hashes.vtc
@@ -0,0 +1,101 @@
+varnishtest "Hash validity test"
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+
+ # base64 encoding of \x00\x01\x02...\xFF
+ http-response set-var(res.key) "str(AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==),b64dec"
+
+ # length (start:0, next:255)
+ http-response set-header x-len0 "%[var(res.key),length]"
+ http-response set-header x-len1 "%[var(res.key),bytes(1),length]"
+
+ # text-based encoding
+ http-response set-header x-hex "%[var(res.key),hex]"
+ http-response set-header x-b64 "%[var(res.key),base64]"
+
+ # SHA family
+ http-response set-header x-sha1 "%[var(res.key),sha1,hex]"
+ #http-response set-header x-sha2 "%[var(res.key),sha2,hex]"
+ #http-response set-header x-sha2-224 "%[var(res.key),sha2(224),hex]"
+ #http-response set-header x-sha2-256 "%[var(res.key),sha2(256),hex]"
+ #http-response set-header x-sha2-384 "%[var(res.key),sha2(384),hex]"
+ #http-response set-header x-sha2-512 "%[var(res.key),sha2(512),hex]"
+
+ # 32-bit hashes, and their avalanche variants
+ http-response set-header x-crc32 "%[var(res.key),crc32]"
+ http-response set-header x-crc32-1 "%[var(res.key),crc32(1)]"
+
+ http-response set-header x-crc32c "%[var(res.key),crc32c]"
+ http-response set-header x-crc32c-1 "%[var(res.key),crc32c(1)]"
+
+ http-response set-header x-djb2 "%[var(res.key),djb2]"
+ http-response set-header x-djb2-1 "%[var(res.key),djb2(1)]"
+
+ http-response set-header x-sdbm "%[var(res.key),sdbm]"
+ http-response set-header x-sdbm-1 "%[var(res.key),sdbm(1)]"
+
+ http-response set-header x-wt6 "%[var(res.key),wt6]"
+ http-response set-header x-wt6-1 "%[var(res.key),wt6(1)]"
+
+ # 32/64-bit hashes, with seed variant
+ http-response set-header x-xxh3 "%[var(res.key),xxh3]"
+ http-response set-header x-xxh3-1 "%[var(res.key),xxh3(1)]"
+ http-response set-header x-xxh32 "%[var(res.key),xxh32]"
+ http-response set-header x-xxh32-1 "%[var(res.key),xxh32(1)]"
+ http-response set-header x-xxh64 "%[var(res.key),xxh64]"
+ http-response set-header x-xxh64-1 "%[var(res.key),xxh64(1)]"
+ default_backend be
+
+ backend be
+ server srv1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-len0 == "0"
+ expect resp.http.x-len1 == "255"
+ expect resp.http.x-hex == "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"
+ expect resp.http.x-b64 == "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=="
+
+ expect resp.http.x-sha1 == "4916D6BDB7F78E6803698CAB32D1586EA457DFC8"
+ #expect resp.http.x-sha2 == "40AFF2E9D2D8922E47AFD4648E6967497158785FBD1DA870E7110266BF944880"
+ #expect resp.http.x-sha2-224 == "88702E63237824C4EB0D0FCFE41469A462493E8BEB2A75BBE5981734"
+ #expect resp.http.x-sha2-256 == "40AFF2E9D2D8922E47AFD4648E6967497158785FBD1DA870E7110266BF944880"
+ #expect resp.http.x-sha2-384 == "FFDAEBFF65ED05CF400F0221C4CCFB4B2104FB6A51F87E40BE6C4309386BFDEC2892E9179B34632331A59592737DB5C5"
+ #expect resp.http.x-sha2-512 == "1E7B80BC8EDC552C8FEEB2780E111477E5BC70465FAC1A77B29B35980C3F0CE4A036A6C9462036824BD56801E62AF7E9FEBA5C22ED8A5AF877BF7DE117DCAC6D"
+ expect resp.http.x-crc32 == "688229491"
+ expect resp.http.x-crc32-1 == "4230317029"
+ expect resp.http.x-crc32c == "2621708363"
+ expect resp.http.x-crc32c-1 == "2242979626"
+ expect resp.http.x-djb2 == "2589693061"
+ expect resp.http.x-djb2-1 == "600622701"
+ expect resp.http.x-sdbm == "905707648"
+ expect resp.http.x-sdbm-1 == "3103804144"
+ expect resp.http.x-wt6 == "4090277559"
+ expect resp.http.x-wt6-1 == "1192658767"
+ expect resp.http.x-xxh3 == "-7779787747613135503"
+ expect resp.http.x-xxh3-1 == "5930632130106562027"
+ expect resp.http.x-xxh32 == "1497633363"
+ expect resp.http.x-xxh32-1 == "1070421674"
+ expect resp.http.x-xxh64 == "2282408585429094475"
+ expect resp.http.x-xxh64-1 == "-4689339368900765961"
+} -run
diff --git a/reg-tests/sample_fetches/so_name.vtc b/reg-tests/sample_fetches/so_name.vtc
new file mode 100644
index 0000000..c6211fa
--- /dev/null
+++ b/reg-tests/sample_fetches/so_name.vtc
@@ -0,0 +1,22 @@
+varnishtest "so_name sample fetche Test"
+
+#REQUIRE_VERSION=2.2
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+
+ frontend fe
+ bind "fd@${fe}" name foo
+ http-request return status 200 hdr so-name %[so_name]
+
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.so-name == "foo"
+} -run
diff --git a/reg-tests/sample_fetches/srv_name.vtc b/reg-tests/sample_fetches/srv_name.vtc
new file mode 100644
index 0000000..900957e
--- /dev/null
+++ b/reg-tests/sample_fetches/srv_name.vtc
@@ -0,0 +1,46 @@
+varnishtest "srv_name sample fetche Test"
+
+#REQUIRE_VERSION=2.1
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+server s2 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ http-response set-header srv-id "%[srv_id]"
+ http-response set-header srv-name "%[srv_name]"
+ default_backend be
+
+ backend be
+ server srv1 ${s1_addr}:${s1_port}
+ server srv2 ${s2_addr}:${s2_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.srv-id == "1"
+ expect resp.http.srv-name == "srv1"
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.srv-id == "2"
+ expect resp.http.srv-name == "srv2"
+} -run
diff --git a/reg-tests/sample_fetches/tcpinfo_rtt.vtc b/reg-tests/sample_fetches/tcpinfo_rtt.vtc
new file mode 100644
index 0000000..e21c542
--- /dev/null
+++ b/reg-tests/sample_fetches/tcpinfo_rtt.vtc
@@ -0,0 +1,39 @@
+varnishtest "Test declaration of TCP rtt fetches"
+
+# feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(v2.8-dev8)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults common
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe from common
+ bind "fd@${feh1}"
+
+ default_backend be
+
+ backend be from common
+
+ http-response set-header x-test1 "%[fc_rtt]"
+ http-response set-header x-test2 "%[bc_rtt(us)]"
+ http-response set-header x-test3 "%[fc_rttvar]"
+ http-response set-header x-test4 "%[bc_rttvar]"
+
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+client c1 -connect ${h1_feh1_sock} {
+ txreq -req GET -url /
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-test2 ~ "[0-9]+"
+} -run \ No newline at end of file
diff --git a/reg-tests/sample_fetches/tlvs.vtc b/reg-tests/sample_fetches/tlvs.vtc
new file mode 100644
index 0000000..9312b1d
--- /dev/null
+++ b/reg-tests/sample_fetches/tlvs.vtc
@@ -0,0 +1,57 @@
+varnishtest "Tests for fetching PROXY protocol v2 TLVs"
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend echo
+ bind "fd@${fe1}" accept-proxy
+ tcp-request content set-var(sess.aws) fc_pp_tlv(0xEA),bytes(1) if { fc_pp_tlv(0xEE),bytes(0,1),hex eq 01 }
+ tcp-request content set-var(sess.azure) fc_pp_tlv(0xEE),bytes(1) if { fc_pp_tlv(0xEA),bytes(0,1),hex eq 01 }
+
+ http-after-response set-header echo1 %[var(sess.aws)]
+ http-after-response set-header echo2 %[var(sess.azure)]
+ http-after-response set-header echo3 %[fc_pp_tlv(0xEB)]
+ http-after-response set-header echo4 %[fc_pp_tlv(0xEC),length]
+ http-request return status 200
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ # PROXY v2 signature
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ # version + PROXY
+ sendhex "21"
+ # TCP4
+ sendhex "11"
+ # length of the address (12) + length of the TLVs (14 + 10 + 9 + 131)
+ sendhex "00 B0"
+ # 127.0.0.1 42 127.0.0.1 1337
+ sendhex "7F 00 00 01 7F 00 00 01 00 2A 05 39"
+
+ # PP2_TYPE_AWS (0xEA) + length of the value + PP2_SUBTYPE_AWS_VPCE_ID (0x01) + "aws-vpc-id"
+ # See https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#custom-tlv for the respective definitions.
+ sendhex "EA 00 0B 01 61 77 73 2D 76 70 63 2D 69 64"
+
+ # PP2_TYPE_AZURE (0xEE) + length of the value + PP2_SUBTYPE_AZURE_PRIVATEENDPOINT_LINKID (0x01) + "LINKID"
+ # See https://learn.microsoft.com/en-us/azure/private-link/private-link-service-overview#getting-connection-information-using-tcp-proxy-v2
+ # for the respective definitions.
+ sendhex "EE 00 07 01 4C 49 4E 4B 49 44"
+
+ # custom type (0xEB) + length of the value + "custom"
+ sendhex "EB 00 06 63 75 73 74 6F 6D"
+
+ # custom type (0xEC) + length of the value (128, does not fit in pool) + random data
+ sendhex "EC 00 80 3A D9 32 9B 11 A7 29 81 14 B2 33 F0 C2 0D 7A 53 D1 97 28 74 4B 78 8A D3 10 C4 B1 88 42 9C 63 8E 8B 8A A0 B4 B0 E7 9D 20 27 0F 1E 53 4D 33 F7 5A D0 91 3F B8 C9 E9 16 C4 61 C5 13 02 92 64 9D D4 22 5C 8E 4E 0B 2D 2D 7D 9F 5D 97 9B 25 C4 12 7D 21 75 C8 15 92 6B 64 F2 5F C0 A9 0F 9A 7D 0A 6D 68 79 F4 56 18 6F 23 45 2A 9B 36 34 3A 47 43 32 29 18 6F 23 45 2A 9B 36 34 3A 47 43 32 29 32 29"
+
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.echo1 == "aws-vpc-id"
+ expect resp.http.echo2 == "LINKID"
+ expect resp.http.echo3 == "custom"
+ expect resp.http.echo4 == 128
+} -run
diff --git a/reg-tests/sample_fetches/ubase64.vtc b/reg-tests/sample_fetches/ubase64.vtc
new file mode 100644
index 0000000..8e47d86
--- /dev/null
+++ b/reg-tests/sample_fetches/ubase64.vtc
@@ -0,0 +1,57 @@
+varnishtest "ub64dec sample fetche Test"
+
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${fe}"
+ acl input hdr(encode) -m found
+ http-request return content-type text/plain hdr encode %[hdr(encode),ub64enc] hdr decode %[hdr(decode),ub64dec] if input
+ http-request return content-type text/plain hdr encode %[bin(14fb9c03d97f12d97e),ub64enc] hdr decode %[str(FPucA9l_Etl-),ub64dec,hex,lower] if !input
+
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -hdr "encode: f" -hdr "decode: Zg"
+ rxresp
+ expect resp.http.encode == "Zg"
+ expect resp.http.decode == "f"
+ txreq -hdr "encode: fo" -hdr "decode: Zm8"
+ rxresp
+ expect resp.http.encode == "Zm8"
+ expect resp.http.decode == "fo"
+ txreq -hdr "encode: foo" -hdr "decode: Zm9v"
+ rxresp
+ expect resp.http.encode == "Zm9v"
+ expect resp.http.decode == "foo"
+ txreq -hdr "encode: foob" -hdr "decode: Zm9vYg"
+ rxresp
+ expect resp.http.encode == "Zm9vYg"
+ expect resp.http.decode == "foob"
+ txreq -hdr "encode: fooba" -hdr "decode: Zm9vYmE"
+ rxresp
+ expect resp.http.encode == "Zm9vYmE"
+ expect resp.http.decode == "fooba"
+ txreq -hdr "encode: foobar" -hdr "decode: Zm9vYmFy"
+ rxresp
+ expect resp.http.encode == "Zm9vYmFy"
+ expect resp.http.decode == "foobar"
+ txreq
+ rxresp
+ expect resp.http.encode == "FPucA9l_Etl-"
+ expect resp.http.decode == "14fb9c03d97f12d97e"
+} -run
diff --git a/reg-tests/sample_fetches/vars.vtc b/reg-tests/sample_fetches/vars.vtc
new file mode 100644
index 0000000..29d474c
--- /dev/null
+++ b/reg-tests/sample_fetches/vars.vtc
@@ -0,0 +1,84 @@
+varnishtest "Test a few set-var() in global, tcp and http rule sets, at different scopes"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev5)'"
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ # note below, str60 is purposely not defined so that the default is used
+ set-var proc.int12 int(12)
+ set-var proc.int5 var(proc.str60,60),div(proc.int12)
+ set-var proc.str1 str("this is")
+ set-var proc.str2 str("a string")
+ set-var proc.str var(proc.str1)
+ set-var-fmt proc.str "%[var(proc.str)] a string"
+ set-var proc.uuid uuid()
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe1}"
+ tcp-request session set-var-fmt(sess.str3) "%[var(proc.str1)] %[var(proc.str2)]"
+ tcp-request session set-var(sess.int5) var(proc.int5)
+ tcp-request session set-var(proc.int5) var(proc.int5),add(sess.int5) ## proc. becomes 10
+ tcp-request content set-var-fmt(req.str4) "%[var(sess.str3),regsub(is a,is also a)]"
+ http-request set-var-fmt(txn.str5) "%[var(req.str4)]"
+ http-request set-var(req.int5) var(sess.int5)
+ http-request set-var(sess.int5) var(sess.int5),add(req.int5) ## sess. becomes 10 first time, then 15...
+ http-request return status 200 hdr x-var "proc=%[var(proc.int5)] sess=%[var(sess.int5)] req=%[var(req.int5)] str=%[var(proc.str)] str5=%[var(txn.str5)] uuid=%[var(proc.uuid)]"
+} -start
+
+haproxy h1 -cli {
+ send "get var proc.int5"
+ expect ~ "^proc.int5: type=sint value=<5>"
+}
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /req1_1
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var ~ "proc=10 sess=10 req=5 str=this is a string str5=this is also a string uuid=[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*"
+
+ txreq -req GET -url /req1_2
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var ~ "proc=10 sess=20 req=10 str=this is a string str5=this is also a string uuid=[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*"
+} -run
+
+haproxy h1 -cli {
+ send "get var proc.int5"
+ expect ~ "^proc.int5: type=sint value=<10>"
+}
+
+client c2 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /req2_1
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var ~ "proc=20 sess=20 req=10 str=this is a string str5=this is also a string uuid=[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*"
+
+ txreq -req GET -url /req2_2
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var ~ "proc=20 sess=40 req=20 str=this is a string str5=this is also a string uuid=[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*"
+} -run
+
+haproxy h1 -cli {
+ send "get var proc.int5"
+ expect ~ "^proc.int5: type=sint value=<20>"
+}
+
+haproxy h1 -cli {
+ send "experimental-mode on; set var proc.str str(updating); set var proc.str fmt %[var(proc.str),regsub(ing,ed)]"
+ expect ~ .*
+}
+
+client c3 -connect ${h1_fe1_sock} {
+ txreq -req GET -url /req3_1
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var ~ "proc=40 sess=40 req=20 str=updated str5=this is also a string uuid=[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*"
+} -run
diff --git a/reg-tests/seamless-reload/abns_socket.vtc b/reg-tests/seamless-reload/abns_socket.vtc
new file mode 100644
index 0000000..e8e5f28
--- /dev/null
+++ b/reg-tests/seamless-reload/abns_socket.vtc
@@ -0,0 +1,55 @@
+# commit b4dd15b
+# BUG/MINOR: unix: Make sure we can transfer abns sockets on seamless reload.
+#
+# When checking if a socket we got from the parent is suitable for a listener,
+# we just checked that the path matched sockname.tmp, however this is
+# unsuitable for abns sockets, where we don't have to create a temporary
+# file and rename it later.
+# To detect that, check that the first character of the sun_path is 0 for
+# both, and if so, that &sun_path[1] is the same too.
+#
+# Note: there are some tricks here. One of them is that we must not bind the
+# same abns address to multiple processes that may run in parallel. Since
+# vtest cannot provide abns sockets, we're instead concatenating the number
+# of the listening port that vtest allocated for another frontend to the abns
+# path, which guarantees to make them unique in the system.
+
+varnishtest "Seamless reload issue with abns sockets"
+feature ignore_unknown_macro
+feature cmd "command -v socat"
+feature cmd "command -v grep"
+
+# abns@ sockets are not available on freebsd
+#EXCLUDE_TARGETS=freebsd,osx,generic
+#REGTEST_TYPE=devel
+
+haproxy h1 -W -S -conf {
+ global
+ stats socket "${tmpdir}/h1/stats" level admin expose-fd listeners
+
+ defaults
+ mode http
+ log global
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen testme
+ bind "fd@${testme}"
+ server test_abns_server abns@wpproc1_${h1_testme_port} send-proxy-v2
+
+ frontend test_abns
+ bind abns@wpproc1_${h1_testme_port} accept-proxy
+ http-request deny deny_status 200
+} -start
+
+shell {
+ echo "reload" | socat -t1000 TCP:${h1_mcli_addr}:${h1_mcli_port} - | grep 'Success=1'
+}
+
+client c1 -connect ${h1_testme_sock} {
+ txreq -url "/"
+ rxresp
+} -repeat 50 -run
+
diff --git a/reg-tests/server/cli_add_check_server.vtc b/reg-tests/server/cli_add_check_server.vtc
new file mode 100644
index 0000000..c63710c
--- /dev/null
+++ b/reg-tests/server/cli_add_check_server.vtc
@@ -0,0 +1,161 @@
+varnishtest "Add/Delete server via cli with check support"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev3)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+feature ignore_unknown_macro
+
+barrier b1 cond 2 -cyclic
+barrier b2 cond 2 -cyclic
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+server s2 {
+} -start
+
+# used for agent checks
+server s3 {
+ recv 5
+ send "ready up\n"
+ barrier b2 sync
+} -start
+
+syslog S1 -level notice {
+ recv
+ expect ~ ".*Server be1/s1 is UP/READY \\(leaving forced maintenance\\)."
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/s1 succeeded.+reason: Layer7 check passed, code: 200, check duration: [[:digit:]]+ms.+status: 1/1 UP"
+
+ barrier b1 sync
+
+ recv
+ expect ~ ".*Server be1/s2 is UP/READY \\(leaving forced maintenance\\)."
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/s2 failed.+reason: Layer7 timeout, check duration: [[:digit:]]+ms.+status: 0/1 DOWN"
+
+ barrier b1 sync
+
+ recv
+ expect ~ ".*Server be1/s2 was DOWN and now enters maintenance."
+
+ recv
+ expect ~ ".*Server be1/s3 is UP/READY \\(leaving forced maintenance\\)."
+
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Agent check for server be1/s3 succeeded.+reason: Layer7 check passed, code: 0, info: \"via agent : up\", check duration: [[:digit:]]+ms.+status: 1/1 UP"
+
+ barrier b1 sync
+ barrier b2 sync
+
+ recv
+ expect ~ ".*Server be1/s4 is UP/READY \\(leaving forced maintenance\\)."
+ recv
+ expect ~ "Health check for server be1/s4 failed"
+
+ barrier b1 sync
+
+ recv
+ expect ~ ".*Server be1/s5 is UP/READY \\(leaving forced maintenance\\)."
+ recv
+ expect ~ "Health check for server be1/s5 succeeded."
+} -start
+
+haproxy h1 -conf {
+ global
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ backend be1
+ option log-health-checks
+ option httpchk GET /
+ log ${S1_addr}:${S1_port} daemon
+
+ frontend fe-proxy
+ mode http
+ bind "fd@${hapsrv}" accept-proxy
+ http-request return status 200
+} -start
+
+# check on a functional server
+haproxy h1 -cli {
+ send "add server be1/s1 ${s1_addr}:${s1_port} check inter 200ms rise 1 fall 1"
+ expect ~ "New server registered."
+
+ send "enable server be1/s1"
+ expect ~ ".*"
+ send "enable health be1/s1"
+ expect ~ ".*"
+
+ barrier b1 sync
+
+ send "disable server be1/s1"
+ expect ~ ".*"
+
+ send "del server be1/s1"
+ expect ~ "Server deleted."
+}
+
+server s2 -break
+
+# check on a disabled server
+haproxy h1 -cli {
+ send "add server be1/s2 ${s2_addr}:${s2_port} check inter 200ms rise 1 fall 1"
+ expect ~ "New server registered."
+
+ send "enable server be1/s2"
+ expect ~ ".*"
+ send "enable health be1/s2"
+ expect ~ ".*"
+
+ barrier b1 sync
+
+ send "disable server be1/s2"
+ expect ~ ".*"
+
+ send "del server be1/s2"
+ expect ~ "Server deleted."
+}
+
+# agent check
+haproxy h1 -cli {
+ send "add server be1/s3 ${s1_addr}:${s1_port} agent-check agent-addr ${s3_addr} agent-port ${s3_port} agent-send 'hello' agent-inter 200ms rise 1 fall 1"
+ expect ~ "New server registered."
+
+ send "enable agent be1/s3"
+ expect ~ ".*"
+
+ barrier b1 sync
+
+ send "disable agent be1/s3; disable server be1/s3"
+ expect ~ ".*"
+
+ send "del server be1/s3"
+ expect ~ "Server deleted."
+}
+
+# check PROXY protocol interaction with checks
+haproxy h1 -cli {
+ # no explicit check-send-proxy
+ # The health check should failed.
+ send "add server be1/s4 ${h1_hapsrv_addr}:${h1_hapsrv_port} send-proxy check rise 1 fall 1"
+ expect ~ "New server registered."
+
+ send "enable server be1/s4"
+ expect ~ ".*"
+ send "enable health be1/s4"
+ expect ~ ".*"
+
+ barrier b1 sync
+
+ # explicit check-send-proxy : health check should succeeded
+ send "add server be1/s5 ${h1_hapsrv_addr}:${h1_hapsrv_port} send-proxy check rise 1 fall 1 check-send-proxy"
+ expect ~ "New server registered."
+
+ send "enable server be1/s5"
+ expect ~ ".*"
+ send "enable health be1/s5"
+ expect ~ ".*"
+}
+
+syslog S1 -wait
diff --git a/reg-tests/server/cli_add_server.vtc b/reg-tests/server/cli_add_server.vtc
new file mode 100644
index 0000000..8c29305
--- /dev/null
+++ b/reg-tests/server/cli_add_server.vtc
@@ -0,0 +1,87 @@
+varnishtest "Add server via cli"
+
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${feS}"
+ default_backend test
+
+ backend test
+ balance random
+
+ backend other
+ balance static-rr
+
+ backend other2
+ balance random
+ mode tcp
+} -start
+
+client c1 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+haproxy h1 -cli {
+ # non existent backend
+ send "add server foo/s1 ${s1_addr}:${s1_port}"
+ expect ~ "No such backend."
+
+ # missing address
+ send "add server test/s1"
+ expect ~ "'server' expects <name> and <addr>\\[:<port>\\] as arguments."
+
+ # invalid load-balancing algo
+ send "add server other/s1 ${s1_addr}:${s1_port}"
+ expect ~ "Backend must use a dynamic load balancing to support dynamic servers."
+
+ # invalid mux proto
+ send "add server other2/s1 ${s1_addr}:${s1_port} proto h2"
+ expect ~ "MUX protocol is not usable for server."
+
+ # valid command
+ send "add server test/s1 ${s1_addr}:${s1_port}"
+ expect ~ "New server registered."
+
+ # duplicate server
+ send "add server test/s1 ${s1_addr}:${s1_port}"
+ expect ~ "Already exists a server with the same name in backend."
+
+ # valid command
+ # specify the proto, it should be accepted for this backend
+ send "add server test/s2 ${s1_addr}:${s1_port} proto h2"
+ expect ~ "New server registered."
+}
+
+# dynamic servers are created on MAINT mode and should not be available at first
+client c2 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+haproxy h1 -cli {
+ send "enable server test/s1"
+ expect ~ ".*"
+}
+
+client c3 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/server/cli_add_ssl_server.vtc b/reg-tests/server/cli_add_ssl_server.vtc
new file mode 100644
index 0000000..48faee1
--- /dev/null
+++ b/reg-tests/server/cli_add_ssl_server.vtc
@@ -0,0 +1,110 @@
+varnishtest "Add server via cli with SSL activated"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+barrier b1 cond 2 -cyclic
+
+syslog S1 -level notice {
+ recv
+ expect ~ ".*Server li-ssl/s1 is UP/READY \\(leaving forced maintenance\\)."
+ recv
+ expect ~ ".*Server li-ssl/s2 is UP/READY \\(leaving forced maintenance\\)."
+ recv
+ expect ~ "Health check for server li-ssl/s2 failed"
+
+ barrier b1 sync
+
+ recv
+ expect ~ ".*Server li-ssl/s3 is UP/READY \\(leaving forced maintenance\\)."
+ recv
+ expect ~ "Health check for server li-ssl/s3 succeeded."
+} -start
+
+haproxy h1 -conf {
+ global
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ option log-health-checks
+ option httpchk GET /
+
+ # proxy to attach a ssl server
+ listen li-ssl
+ bind "fd@${feSsl}"
+ balance random
+ log ${S1_addr}:${S1_port} daemon
+
+ # frontend used to respond to ssl connection
+ frontend fe-ssl-term
+ bind "fd@${feSslTerm}" ssl crt ${testdir}/common.pem
+ http-request return status 200
+} -start
+
+### SSL SUPPORT
+# 1. first create a ca-file using CLI
+# 2. create an SSL server and use it
+
+client c1 -connect ${h1_feSsl_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+shell {
+ echo "new ssl ca-file common.pem" | socat "${tmpdir}/h1/stats" -
+ printf "set ssl ca-file common.pem <<\n$(cat ${testdir}/common.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file common.pem" | socat "${tmpdir}/h1/stats" -
+} -run
+
+haproxy h1 -cli {
+ send "show ssl ca-file common.pem"
+ expect ~ ".*SHA1 FingerPrint: DF3B6E847A7BF83DFAAFCFEC65EE9BC36230D3EA"
+}
+
+haproxy h1 -cli {
+ # non existent backend
+ send "add server li-ssl/s1 ${h1_feSslTerm_addr}:${h1_feSslTerm_port} ssl ca-file common.pem verify none"
+ expect ~ "New server registered."
+
+ send "enable server li-ssl/s1"
+ expect ~ ".*"
+}
+
+client c2 -connect ${h1_feSsl_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+# test interaction between SSL and checks for dynamic servers
+haproxy h1 -cli {
+ # no explicit check-ssl
+ # The health check should failed.
+ send "add server li-ssl/s2 ${h1_feSslTerm_addr}:${h1_feSslTerm_port} ssl verify none check"
+ expect ~ "New server registered."
+
+ send "enable server li-ssl/s2"
+ expect ~ ".*"
+ send "enable health li-ssl/s2"
+ expect ~ ".*"
+
+ barrier b1 sync
+
+ # explicit check-ssl : health check should succeeded
+ send "add server li-ssl/s3 ${h1_feSslTerm_addr}:${h1_feSslTerm_port} ssl verify none check check-ssl"
+ expect ~ "New server registered."
+
+ send "enable server li-ssl/s3"
+ expect ~ ".*"
+ send "enable health li-ssl/s3"
+ expect ~ ".*"
+}
+
+syslog S1 -wait
diff --git a/reg-tests/server/cli_add_track_server.vtc b/reg-tests/server/cli_add_track_server.vtc
new file mode 100644
index 0000000..318f236
--- /dev/null
+++ b/reg-tests/server/cli_add_track_server.vtc
@@ -0,0 +1,242 @@
+varnishtest "Add/Delete server via cli with track support"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+feature ignore_unknown_macro
+
+
+# just use to provide s1_{addr,port} macros
+server s1 {
+}
+
+
+# scenario 1
+# -> 3 dynamic servers, delete the first one
+syslog S1 {
+ recv notice
+ expect ~ "Server be1/s1 is UP/READY"
+ recv notice
+ expect ~ "Server be1/s2 is UP/READY"
+ recv notice
+ expect ~ "Server be1/s3 is UP/READY"
+
+ recv alert
+ expect ~ "Server be1/srv is going DOWN for maintenance."
+ recv alert
+ expect ~ "Server be1/s3 is going DOWN for maintenance."
+ recv alert
+ expect ~ "Server be1/s2 is going DOWN for maintenance."
+ recv alert
+ expect ~ "Server be1/s1 is going DOWN for maintenance."
+
+ recv notice
+ expect ~ "Server be1/srv is UP/READY"
+ recv notice
+ expect ~ "Server be1/s3 is UP/READY"
+ recv notice
+ expect ~ "Server be1/s2 is UP/READY"
+} -start
+
+# scenario 2
+# -> 3 dynamic servers, delete the middle one
+syslog S2 {
+ recv notice
+ expect ~ "Server be2/s1 is UP/READY"
+ recv notice
+ expect ~ "Server be2/s2 is UP/READY"
+ recv notice
+ expect ~ "Server be2/s3 is UP/READY"
+
+ recv alert
+ expect ~ "Server be2/srv is going DOWN for maintenance."
+ recv alert
+ expect ~ "Server be2/s3 is going DOWN for maintenance."
+ recv alert
+ expect ~ "Server be2/s2 is going DOWN for maintenance."
+ recv alert
+ expect ~ "Server be2/s1 is going DOWN for maintenance."
+
+ recv notice
+ expect ~ "Server be2/srv is UP/READY"
+ recv notice
+ expect ~ "Server be2/s3 is UP/READY"
+ recv notice
+ expect ~ "Server be2/s1 is UP/READY"
+} -start
+
+# scenario 3
+# -> 3 dynamic servers, delete all of them
+syslog S3 {
+ recv notice
+ expect ~ "Server be3/s1 is UP/READY"
+ recv notice
+ expect ~ "Server be3/s2 is UP/READY"
+ recv notice
+ expect ~ "Server be3/s3 is UP/READY"
+
+ recv alert
+ expect ~ "Server be3/s1 is going DOWN for maintenance."
+ recv alert
+ expect ~ "Server be3/s3 is going DOWN for maintenance."
+ recv alert
+ expect ~ "Server be3/s2 is going DOWN for maintenance."
+
+ recv alert
+ expect ~ "Server be3/srv is going DOWN for maintenance."
+
+ recv notice
+ expect ~ "Server be3/srv is UP/READY"
+} -start
+
+
+haproxy h1 -conf {
+ global
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ backend be_check
+ server srv_check ${s1_addr}:${s1_port} check
+ server srv_no_check ${s1_addr}:${s1_port}
+
+ backend be1
+ log ${S1_addr}:${S1_port} daemon
+ server srv ${s1_addr}:${s1_port} check
+
+ backend be2
+ log ${S2_addr}:${S2_port} daemon
+ server srv ${s1_addr}:${s1_port} check
+
+ backend be3
+ log ${S3_addr}:${S3_port} daemon
+ server srv ${s1_addr}:${s1_port} check
+} -start
+
+
+###
+# check the support of the 'track' keyword on 'add server' CLI command.
+# rejection must happen if track on a non-checked or a dynamic server
+###
+haproxy h1 -cli {
+ # invalid command: track on a non-checked server
+ send "add server be_check/s1 ${s1_addr}:${s1_port} track be_check/srv_no_check"
+ expect ~ "unable to use be_check/srv_no_check for tracking as it does not have any check nor agent enabled."
+
+ # valid track usage
+ send "add server be_check/s1 ${s1_addr}:${s1_port} track be_check/srv_check"
+ expect ~ "New server registered."
+
+ # invalid command: track on a dynamic server
+ send "add server be_check/s3 ${s1_addr}:${s1_port} track be_check/s1"
+ expect ~ "unable to use be_check/s1 for tracking as it is a dynamic server."
+}
+
+###
+# scenario 1
+#
+# Add 3 dynamic servers with tracking on be1/srv
+# Disable be1/srv, S1 should report all servers DOWN
+# Delete the first dynamic server, enable be1/srv, S1 should report s1 and s3 UP
+####
+haproxy h1 -cli {
+ send "add server be1/s1 ${s1_addr}:${s1_port} track be1/srv"
+ expect ~ "New server registered."
+ send "enable server be1/s1"
+ expect ~ ".*"
+
+ send "add server be1/s2 ${s1_addr}:${s1_port} track be1/srv"
+ expect ~ "New server registered."
+ send "enable server be1/s2"
+ expect ~ ".*"
+
+ send "add server be1/s3 ${s1_addr}:${s1_port} track be1/srv"
+ expect ~ "New server registered."
+ send "enable server be1/s3"
+ expect ~ ".*"
+
+ send "disable server be1/srv"
+ expect ~ ".*"
+
+ send "del server be1/s1"
+ expect ~ "Server deleted."
+
+ send "enable server be1/srv"
+ expect ~ ".*"
+}
+
+###
+# scenario 2
+#
+# Add 3 dynamic servers with tracking on be2/srv
+# Disable be2/srv, S3 should report all servers DOWN
+# Delete the second dynamic server, enable be2/srv, S2 should report s2 and s3 UP
+####
+haproxy h1 -cli {
+ send "add server be2/s1 ${s1_addr}:${s1_port} track be2/srv"
+ expect ~ "New server registered."
+ send "enable server be2/s1"
+ expect ~ ".*"
+
+ send "add server be2/s2 ${s1_addr}:${s1_port} track be2/srv"
+ expect ~ "New server registered."
+ send "enable server be2/s2"
+ expect ~ ".*"
+
+ send "add server be2/s3 ${s1_addr}:${s1_port} track be2/srv"
+ expect ~ "New server registered."
+ send "enable server be2/s3"
+ expect ~ ".*"
+
+ send "disable server be2/srv"
+ expect ~ ".*"
+
+ send "del server be2/s2"
+ expect ~ "Server deleted."
+
+ send "enable server be2/srv"
+ expect ~ ".*"
+}
+
+###
+# scenario 3
+#
+# Add 3 dynamic servers with tracking on be3/srv
+# Delete all of them, disable/enable be3/srv, only be3/srv should be reported
+# as DOWN/UP.
+####
+haproxy h1 -cli {
+ # create server 1, track on be3/srv
+ send "add server be3/s1 ${s1_addr}:${s1_port} track be3/srv"
+ expect ~ "New server registered."
+ send "enable server be3/s1"
+ expect ~ ".*"
+
+ # create server 2, track on be3/srv
+ send "add server be3/s2 ${s1_addr}:${s1_port} track be3/srv"
+ expect ~ "New server registered."
+ send "enable server be3/s2"
+ expect ~ ".*"
+
+ # create server 3, track on be3/srv
+ send "add server be3/s3 ${s1_addr}:${s1_port} track be3/srv"
+ expect ~ "New server registered."
+ send "enable server be3/s3"
+ expect ~ ".*"
+
+ # delete all dynamic servers
+ send "disable server be3/s1; del server be3/s1"
+ expect ~ "Server deleted."
+ send "disable server be3/s3; del server be3/s3"
+ expect ~ "Server deleted."
+ send "disable server be3/s2; del server be3/s2"
+ expect ~ "Server deleted."
+
+ # disable / enable the static server
+ send "disable server be3/srv"
+ expect ~ ".*"
+ send "enable server be3/srv"
+ expect ~ ".*"
+}
+
+
+syslog S1 -wait
+syslog S2 -wait
+syslog S3 -wait
diff --git a/reg-tests/server/cli_delete_dynamic_server.vtc b/reg-tests/server/cli_delete_dynamic_server.vtc
new file mode 100644
index 0000000..e667641
--- /dev/null
+++ b/reg-tests/server/cli_delete_dynamic_server.vtc
@@ -0,0 +1,94 @@
+# This script is to test the proper behavior with dynamic servers insertion and
+# deletion, in particular with the load-balancing of requests.
+#
+varnishtest "Delete server via cli"
+
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+
+# static server
+server s1 -repeat 3 {
+ rxreq
+ txresp \
+ -body "resp from s1"
+} -start
+
+# use as a dynamic server, added then deleted via CLI
+server s2 -repeat 3 {
+ rxreq
+ txresp \
+ -body "resp from s2"
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${feS}"
+ default_backend test
+
+ backend test
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+# add a new dynamic server to be able to delete it then
+haproxy h1 -cli {
+ # add a dynamic server and enable it
+ send "add server test/s2 ${s2_addr}:${s2_port}"
+ expect ~ "New server registered."
+
+ send "enable server test/s2"
+ expect ~ ".*"
+}
+
+haproxy h1 -cli {
+ # non existent backend
+ send "del server foo/s1"
+ expect ~ "No such backend."
+
+ # non existent server
+ send "del server test/other"
+ expect ~ "No such server."
+}
+
+# first check that both servers are active
+client c1 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.body == "resp from s1"
+
+ txreq
+ rxresp
+ expect resp.body == "resp from s2"
+} -run
+
+# delete the dynamic server
+haproxy h1 -cli {
+ # server not in maintenance mode
+ send "del server test/s2"
+ expect ~ "Only servers in maintenance mode can be deleted."
+
+ send "disable server test/s2"
+ expect ~ ".*"
+
+ # valid command
+ send "del server test/s2"
+ expect ~ "Server deleted."
+}
+
+# now check that only the first server is used
+client c2 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.body == "resp from s1"
+
+ txreq
+ rxresp
+ expect resp.body == "resp from s1"
+} -run
+
diff --git a/reg-tests/server/cli_delete_server.vtc b/reg-tests/server/cli_delete_server.vtc
new file mode 100644
index 0000000..61d241c
--- /dev/null
+++ b/reg-tests/server/cli_delete_server.vtc
@@ -0,0 +1,60 @@
+# This script is to test the ability to remove servers, unless they are
+# referenced by some elements from the configuration.
+#
+varnishtest "Delete server via cli"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${feS}"
+ acl s1_full srv_sess_rate(test/s1) gt 50
+ default_backend test
+
+ backend test
+ use-server s3 unless { always_false }
+ server s1 ${s1_addr}:${s1_port} # referenced in ACL
+ server s2 ${s1_addr}:${s1_port} check # referenced in track
+ server s3 ${s1_addr}:${s1_port} track s2 # referenced in use-server
+ server s4 ${s1_addr}:${s1_port} # removable server
+} -start
+
+haproxy h1 -cli {
+ # non existent backend
+ send "del server foo/s1"
+ expect ~ "No such backend."
+
+ # non existent server
+ send "del server test/other"
+ expect ~ "No such server."
+
+ # server referenced in ACL
+ send "del server test/s1"
+ expect ~ "This server cannot be removed at runtime due to other configuration elements pointing to it."
+
+ # tracked server
+ send "del server test/s2"
+ expect ~ "This server cannot be removed at runtime due to other configuration elements pointing to it."
+
+ # tracked server
+ send "del server test/s3"
+ expect ~ "This server cannot be removed at runtime due to other configuration elements pointing to it."
+
+ # server in running mode
+ send "del server test/s4"
+ expect ~ "Only servers in maintenance mode can be deleted."
+
+ send "disable server test/s4"
+ expect ~ ".*"
+
+ # valid command
+ send "del server test/s4"
+ expect ~ "Server deleted."
+}
diff --git a/reg-tests/server/cli_set_fqdn.vtc b/reg-tests/server/cli_set_fqdn.vtc
new file mode 100644
index 0000000..f82674f
--- /dev/null
+++ b/reg-tests/server/cli_set_fqdn.vtc
@@ -0,0 +1,57 @@
+varnishtest "Set server FQDN via CLI crash"
+
+feature ignore_unknown_macro
+
+# for "set server <srv> fqdn"
+#REGTEST_TYPE=bug
+
+# Do nothing. Is there only to create s1_* macros
+server s1 {
+} -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend myfrontend
+ bind "fd@${my_fe}"
+ default_backend test
+
+ backend test
+ server www1 ${s1_addr}:${s1_port}
+} -start
+
+haproxy h2 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ resolvers systemdns
+ parse-resolv-conf
+
+ frontend myfrontend
+ bind "fd@${my_fe}"
+ default_backend test
+
+ backend test
+ server www1 ${s1_addr}:${s1_port} resolvers systemdns resolve-prefer ipv4
+} -start
+
+haproxy h1 -cli {
+ send "set server test/www1 fqdn foo.fqdn"
+ expect ~ "set server <b>/<s> fqdn failed because no resolution is configured."
+ send "show servers state test"
+ expect ~ "test 1 www1 ${s1_addr} .* - ${s1_port}"
+} -wait
+
+haproxy h2 -cli {
+ send "set server test/www1 fqdn localhost"
+ expect ~ "test/www1 changed its FQDN from \\(null\\) to localhost"
+ send "show servers state test"
+ expect ~ "test 1 www1 127.0.0.1 .* localhost"
+} -wait
diff --git a/reg-tests/server/cli_set_ssl.vtc b/reg-tests/server/cli_set_ssl.vtc
new file mode 100644
index 0000000..fa6fe68
--- /dev/null
+++ b/reg-tests/server/cli_set_ssl.vtc
@@ -0,0 +1,60 @@
+varnishtest "Set server ssl via CLI"
+
+feature ignore_unknown_macro
+
+# for "set server <srv> ssl"
+#REQUIRE_VERSION=2.4
+#REGTEST_TYPE=devel
+#REQUIRE_OPTIONS=OPENSSL
+
+# Do nothing. Is there only to create s1_* macros
+server s1 {
+} -start
+
+haproxy h1 -conf {
+ global
+ ssl-server-verify none
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend myfrontend
+ bind "fd@${my_fe}"
+ default_backend test0
+
+ backend test0
+ server www0 ${s1_addr}:${s1_port} no-ssl
+ default-server ssl
+ server www1 ${s1_addr}:${s1_port} no-ssl
+
+ backend test1
+ server www0 ${s1_addr}:${s1_port} no-ssl
+} -start
+
+haproxy h1 -cli {
+ # supported case
+ send "show servers state test0"
+ expect ~ "test0 2 www1 ${s1_addr} .* - ${s1_port} - -1"
+ send "set server test0/www1 ssl on"
+ expect ~ "server ssl setting updated"
+ send "show servers state test0"
+ expect ~ "test0 2 www1 ${s1_addr} .* - ${s1_port} - 1"
+ send "set server test0/www1 ssl off"
+ expect ~ "server ssl setting updated"
+ send "show servers state test0"
+ expect ~ "test0 2 www1 ${s1_addr} .* - ${s1_port} - 0"
+
+ # unsupported cases
+ send "show servers state test0"
+ expect ~ "test0 1 www0 ${s1_addr} .* - ${s1_port} - -1"
+ send "set server test0/www0 ssl on"
+ expect ~ "'set server <srv> ssl' cannot be set"
+
+ send "show servers state test1"
+ expect ~ "test1 1 www0 ${s1_addr} .* - ${s1_port} - -1"
+ send "set server test1/www0 ssl on"
+ expect ~ "'set server <srv> ssl' cannot be set"
+} -wait
diff --git a/reg-tests/server/common.pem b/reg-tests/server/common.pem
new file mode 120000
index 0000000..a4433d5
--- /dev/null
+++ b/reg-tests/server/common.pem
@@ -0,0 +1 @@
+../ssl/common.pem \ No newline at end of file
diff --git a/reg-tests/server/get_srv_stats.lua b/reg-tests/server/get_srv_stats.lua
new file mode 100644
index 0000000..105b954
--- /dev/null
+++ b/reg-tests/server/get_srv_stats.lua
@@ -0,0 +1,11 @@
+local function lua_get_srv_stats(txn, name)
+ for _, backend in pairs(core.backends) do
+ for _, server in pairs(backend.servers) do
+ if server.name == name then
+ return server:get_stats()
+ end
+ end
+ end
+end
+
+core.register_fetches('get_srv_stats', lua_get_srv_stats)
diff --git a/reg-tests/spoe/wrong_init.vtc b/reg-tests/spoe/wrong_init.vtc
new file mode 100644
index 0000000..152622c
--- /dev/null
+++ b/reg-tests/spoe/wrong_init.vtc
@@ -0,0 +1,22 @@
+# commit 84c844eb12b250aa86f2aadaff77c42dfc3cb619
+# BUG/MINOR: spoe: Initialize variables used during conf parsing before any check
+#
+# Some initializations must be done at the beginning of parse_spoe_flt to avoid
+# segmentation fault when first errors are caught, when the "filter spoe" line is
+# parsed.
+
+#REGTEST_TYPE=bug
+
+varnishtest "SPOE bug: missing configuration file"
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf-BAD {} {
+ defaults
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend my-front
+ filter spoe
+}
diff --git a/reg-tests/ssl/README b/reg-tests/ssl/README
new file mode 100644
index 0000000..f2fc534
--- /dev/null
+++ b/reg-tests/ssl/README
@@ -0,0 +1,2 @@
+File list:
+ - common.pem: PEM file which may be used by most of the VTC files.
diff --git a/reg-tests/ssl/add_ssl_crt-list.vtc b/reg-tests/ssl/add_ssl_crt-list.vtc
new file mode 100644
index 0000000..8810b72
--- /dev/null
+++ b/reg-tests/ssl/add_ssl_crt-list.vtc
@@ -0,0 +1,114 @@
+#REGTEST_TYPE=devel
+
+# This reg-test uses the "add ssl crt-list" command to add a certificate over the CLI.
+# It requires socat to upload the certificate
+
+# this check does 2 requests, the first one will use "www.test1.com" as SNI, and
+# the second one will use "localhost". Since vtest can't do SSL, we use haproxy
+# as an SSL client with 2 chained listen section.
+
+# If this test does not work anymore:
+# - Check that you have socat
+
+varnishtest "Test the 'add ssl crt-list' feature of the CLI"
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTIONS=OPENSSL
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 2 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ crt-base ${testdir}
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ server s1 "${tmpdir}/ssl.sock" ssl verify none sni str(www.test1.com)
+ server s2 "${tmpdir}/ssl.sock" ssl verify none sni str(localhost)
+
+
+ listen ssl-lst
+ mode http
+ bind "${tmpdir}/ssl.sock" ssl strict-sni crt-list ${testdir}/localhost.crt-list
+
+ server s1 ${s1_addr}:${s1_port}
+ server s2 ${s1_addr}:${s1_port} ssl crt "${testdir}/common.pem" weight 0 verify none
+} -start
+
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/common.pem"
+ expect ~ ".*SHA1 FingerPrint: DF3B6E847A7BF83DFAAFCFEC65EE9BC36230D3EA"
+}
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+shell {
+ echo "new ssl cert ${testdir}/ecdsa.pem" | socat "${tmpdir}/h1/stats" -
+ printf "set ssl cert ${testdir}/ecdsa.pem <<\n$(cat ${testdir}/ecdsa.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/ecdsa.pem" | socat "${tmpdir}/h1/stats" -
+ printf "add ssl crt-list ${testdir}/localhost.crt-list/ <<\n${testdir}/common.pem [ssl-min-ver SSLv3 verify none allow-0rtt] !*\n\n" | socat "${tmpdir}/h1/stats" -
+ printf "add ssl crt-list ${testdir}/localhost.crt-list/ <<\n${testdir}/ecdsa.pem [ssl-min-ver SSLv3 verify none allow-0rtt] localhost !www.test1.com\n\n" | socat "${tmpdir}/h1/stats" -
+ printf "add ssl crt-list ${testdir}/localhost.crt-list <<\n${testdir}/ecdsa.pem [verify none allow-0rtt]\n\n" | socat "${tmpdir}/h1/stats" -
+ printf "add ssl crt-list ${testdir}/localhost.crt-list/// <<\n${testdir}/ecdsa.pem localhost !www.test1.com\n\n" | socat "${tmpdir}/h1/stats" -
+ printf "add ssl crt-list ${testdir}/localhost.crt-list///// <<\n${testdir}/ecdsa.pem\n\n" | socat "${tmpdir}/h1/stats" -
+ printf "add ssl crt-list ${testdir}/localhost.crt-list// ${testdir}/ecdsa.pem\n" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/ecdsa.pem"
+ expect ~ ".*SHA1 FingerPrint: A490D069DBAFBEE66DE434BEC34030ADE8BCCBF1"
+}
+
+haproxy h1 -cli {
+ send "show ssl crt-list ${testdir}/localhost.crt-list//"
+ # check the options and the filters in any order
+ expect ~ ".*${testdir}/ecdsa.pem \\[(?=.*verify none)(?=.*allow-0rtt)(?=.*ssl-min-ver SSLv3).*\\](?=.*!www.test1.com)(?=.*localhost).*"
+}
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+
+# Try to add a new line that mentions an "unknown" CA file (not loaded yet).
+# It should fail since no disk access are allowed during runtime.
+shell {
+ printf "add ssl crt-list ${testdir}/localhost.crt-list/ <<\n${testdir}/ecdsa.pem [ca-file ${testdir}/ca-auth.crt] localhost\n\n" | socat "${tmpdir}/h1/stats" - | grep "unable to load ${testdir}/ca-auth.crt"
+}
+shell {
+ printf "add ssl crt-list ${testdir}/localhost.crt-list/ <<\n${testdir}/ecdsa.pem [ca-verify-file ${testdir}/ca-auth.crt] localhost\n\n" | socat "${tmpdir}/h1/stats" - | grep "unable to load ${testdir}/ca-auth.crt"
+}
+shell {
+ printf "add ssl crt-list ${testdir}/localhost.crt-list/ <<\n${testdir}/ecdsa.pem [crl-file ${testdir}/ca-auth.crt] localhost\n\n" | socat "${tmpdir}/h1/stats" - | grep "unable to load ${testdir}/ca-auth.crt"
+}
+
+# Check that the new line was not added to the crt-list.
+haproxy h1 -cli {
+ send "show ssl crt-list ${testdir}/localhost.crt-list//"
+ expect !~ ".*ca-file ${testdir}/ca-auth.crt"
+}
diff --git a/reg-tests/ssl/bug-2265.crt b/reg-tests/ssl/bug-2265.crt
new file mode 120000
index 0000000..1b7cb2c
--- /dev/null
+++ b/reg-tests/ssl/bug-2265.crt
@@ -0,0 +1 @@
+common.pem \ No newline at end of file
diff --git a/reg-tests/ssl/ca-auth.crt b/reg-tests/ssl/ca-auth.crt
new file mode 100644
index 0000000..1695af5
--- /dev/null
+++ b/reg-tests/ssl/ca-auth.crt
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFyzCCA7OgAwIBAgIURpSju/jEN7LJUV4vEibyeuJwd5kwDQYJKoZIhvcNAQEL
+BQAwdDELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3RhdGUxHTAbBgNVBAoM
+FEhBUHJveHkgVGVjaG5vbG9naWVzMTEwLwYDVQQDDChIQVByb3h5IFRlY2hub2xv
+Z2llcyBDQSBUZXN0IENsaWVudCBBdXRoMCAXDTIwMDQyODE4NTIwMloYDzIwNTAw
+NDIxMTg1MjAyWjB0MQswCQYDVQQGEwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTEd
+MBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxMTAvBgNVBAMMKEhBUHJveHkg
+VGVjaG5vbG9naWVzIENBIFRlc3QgQ2xpZW50IEF1dGgwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDGlgKEhw5RLOBgaTsPJJYglozt3SVv94084RoA19kw
+udemrMaJdXV517MsR9qoHoxFVFdYP//W6vx7c5RadPqMZrWT9QXhJSR0Kr5KdHUs
++t8H8pmlDicxIx0cuRtmKmRuAMoDI1E+5EsRspemyq1ExcBm42zM9Oj9QysKF0wc
+FXq56eHgXSmKQGAiGuGB5v6CeVu3DVhZHuGyv3XVeOsf35s2M757hi+N6mqqvtw8
+JiQyw53YxBaB80CRtiIXzLd07S4GZnRCNOWgXLwo6+8K1gId3KRk4DhUIEIMrchy
+aqeZmJVToF+8fbjZ97pREJyQo4EXsgPrLE3Ck5Y+TfYJli3NJNhEWhucu4RQ6XXg
+lTruatM9uj9ZZEvtJreu5KRvAOfRLBj+C3f+VRoDrE9RSEn/XSGek+/D7+n3U0GO
+h2KcrUn7R+Yy6DdwxhGImqDnYaKaZds+vEjtvP4ViOC982eVl5/lFAw3JBHR57iL
+/K0zTRwjSasUvlJFQNUNAG9HktCYTdEj0U3C/xBDPayY04BFvn8piZeMpoCN9dre
+UxuctmMrz1pIvYAdZSseraf4W0psx6oeU/CcFZnkc5lbUDvn7u6Ozk4gnfyo1fxJ
+8a2X7dl3joqUABwaS/FkP/CPoEKBMFf4pcZUhuWbPkhiVNXZIkQYQISY6JOr5qDn
+TwIDAQABo1MwUTAdBgNVHQ4EFgQUW4t2W4MUuBG0EyFdHObYYZbtjEowHwYDVR0j
+BBgwFoAUW4t2W4MUuBG0EyFdHObYYZbtjEowDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQsFAAOCAgEAIqQJu2nX0Rn9EUPuVDhCrirQFDwMFb7Ifoqr6rMoD9OT
+pgyQb198TkW550Rhg36LnnmBzifOoPBmHVJQWvMAVnH/BQrkRqXFRk2M3PRoEv44
+twMlUPU/NMLVKnXE+neBlXhBWeyY/bCmVftk/TdLwom0Mer4Nw+rt1JQAXKKNRdj
+3b8EnJHGy7Es4fv/traZQ6ZSHoD0GsxydweCjZEO2hLw9/VVrjdM6rNDZlz7cST5
+rhyUeG3mlwWweGY6ahlMx//Z11m/1JLGyDcwMgunRoBiDep7I3ZMcWH1PjM3CyrL
+ZrDoUvwtMSEAuT/be5SfU/CzS/DTyBtfSpEUbm1dg9cqm1vG7/GFdzJqafv8ppwh
+fZhtxKXcyH4C1BeWlDqA06aNM3ClxWNyrAjdcyI45tosxgDuWyRyUC5IhyK6s81O
+6AP7xQH6s+i0k3mzgOxieV/QRo4E67y31XZHJz6uFKSaHOIdpV7li7mAiswFfhMl
++C3ud2rU79X2vTYLzELR05djzAXHJT9sc5NjbODw3RRKRkcB78IoNM7D0Mcctz+3
+1DHcmk6crsxPRDmvKj9zQTjbG1UpjTogdsbh1afuqJ1atxBgav+/YhefAziXazAy
+P1CHU/OYq/vjfGobIz6RVUjkg50RwkD58TR3LzQPOpSNoM55U/jGd3x4X3kh8tU=
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/cert1-example.com.pem.ecdsa b/reg-tests/ssl/cert1-example.com.pem.ecdsa
new file mode 100644
index 0000000..060d92b
--- /dev/null
+++ b/reg-tests/ssl/cert1-example.com.pem.ecdsa
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIIBhzCCAQ2gAwIBAgIUWnUgbYQBOPUC1tc9NFqD2gjVBawwCgYIKoZIzj0EAwIw
+FjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wIBcNMjEwNDAyMTI0NzAyWhgPMjA1MTAz
+MjYxMjQ3MDJaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMHYwEAYHKoZIzj0CAQYF
+K4EEACIDYgAEWuf05jTK9E7VNfDVknHTdp7FHB+LNOMVPB/XBRiLmU/+/EzF0D+5
+t4APkwa4vSw3UckWUMoAxOrJ1dUk8T8Y5AxWGBomcuAQGtfmUlDBXvhUjsJ1s9Zz
+iy6WyRkU/fcsoxowGDAWBgNVHREEDzANggtleGFtcGxlLmNvbTAKBggqhkjOPQQD
+AgNoADBlAjEAwDVLrc9jL2zx9byM1qGyHKnuk8xsEvZEkUPMor1hrTyqkLGIEu3h
+1vyRvboYvGh6AjB45GdtABrNeRHI7QeA1ZX0j34dj7lYP0NvYjSVSyvRhpe/nzl7
+CzU2IkkQ4fmxosI=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCSlVR2c8kUsBYDAqrH
+M60zwqNVVB0FGafWXBJBn4kgTKRQPCqmwkAJp+yd62Z05iKhZANiAARa5/TmNMr0
+TtU18NWScdN2nsUcH4s04xU8H9cFGIuZT/78TMXQP7m3gA+TBri9LDdRyRZQygDE
+6snV1STxPxjkDFYYGiZy4BAa1+ZSUMFe+FSOwnWz1nOLLpbJGRT99yw=
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/cert1-example.com.pem.rsa b/reg-tests/ssl/cert1-example.com.pem.rsa
new file mode 100644
index 0000000..4639b75
--- /dev/null
+++ b/reg-tests/ssl/cert1-example.com.pem.rsa
@@ -0,0 +1,80 @@
+-----BEGIN CERTIFICATE-----
+MIIE1jCCAr6gAwIBAgIUJUqgFv3XQuBU7FxDOYZDO/DZFPowDQYJKoZIhvcNAQEL
+BQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wIBcNMjEwNDAyMTI0NzAzWhgPMjA1
+MTAzMjYxMjQ3MDNaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIICIjANBgkqhkiG
+9w0BAQEFAAOCAg8AMIICCgKCAgEA1Qyp+JCxptby6yTjlF6GKoSiYXMuTC15GqkQ
+9cA5wExRvRj444ZDeltt4qFh50MQGaPL1Uq5pk2LxVhIMApn3aFv0vVXXLOpkcWL
+tknYhcL7y1wZCGrYff0jJsi/en2YKbzdJ+avFlkrae7uhTmEwLcDRVhJpJYj0nj7
+7NIRZEzzvYxdNVVDkdNacZtJrtanTagse15OV7w6dniIjzyr7P5backq8EyQTWvg
+hf56gx8r/JVoMZdxSd3EXcIXBnyDOU6KTiHu970DJmcz4oEaAlKFCehquNfGyVw5
++jzUPyMP/IzvJZY68s3TjKYnJhoyu2GRf+SH2DBjYVL/I9ULK5G68Oqrjl3lZMM9
+NCjvLykBVAeQ2wYscCUChmLU9Vor1N5Z0EqZx9Wx/SBSPmlpTR4p1eoEmcrrZjUW
+TjDBVk4F3cBrFrMEq0rr+aUSluPzpfYEv/tn1h0WTW/8PbSoQluf85i/BXnzmW1L
+JplcembL1cbm0idJjzRvQx8/WGoSSIYHzWFgRhagvQ7xGf88pGGh0+n/K/xPXZ+Z
+I1b89rLqs5pdBJtAgj7wd2oTxiKDILkpvwRBq9q2p7+yEnaIhWVQr3UudiSRcB8O
+lEk8YHpa8wiKMksezCqs4zfdk3Wh1JEwgy1zYk+penzfvQGaySv5Q20P8V2ZK8i1
+HHnTRLUCAwEAAaMaMBgwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20wDQYJKoZIhvcN
+AQELBQADggIBAD6LkOmRDupXUyDmvA1PsZoNAnN6/ikZOzgcLoPbmPto2MAG16VD
+VJF+2i4FddUJmuPSYkGoo+eEcIJ6pyifWm0f673dvHSn/Epgkyp+uOQcLnVGE5QK
+cYk7ETlw9BQ/uRYi70hXLk8yi/XbBXIZdtICuxzEJrB+uE3tBK33Zy+KoDweifAV
+vGNLDdhK2Slq0/ExaifeO2Agkz0Cb5nihsMnNlSiJPh+Qqhcyn0+o5hW80AozD3A
+MZYVhiPtCfOoHYO02GpsPkYq1mfez79O+t5d3akLLPXEMO8iK4HUtlkYj84wP220
+fRct1E1apRCCfHORqnlPEYcinoEvlsl+c0olH6L2L3t4sDzWGHQoAzNQMSMAwdPr
+NShvuWmKdYoPrTfdp73neP4jkzNMi2FR1SL7M/Mr272njrBrYLayVbb5Aogp9Myp
+PrWohhrYaMCeCVLdtX0C8Ijjo+WhQjMJ5I7J2CCsRifhCnloD3nP3Cfd+obmGxTV
+spGxTfQxn8BH/rqEkTKZgqz8McpMXJChzSe7JduGnv5E8nZH1UQBqbtgDP+JndI3
+5Ncs7GsU0JLfju4w3IaAjslOmu4TLS0MDSDJo5heo1U/OB/kqocbKcoP39mCiWPy
+juW/VTheRaszG8tuPhXYovg9LXZX5HW7eWjgwm9kn9c4fu/3NY7PJbmO
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDVDKn4kLGm1vLr
+JOOUXoYqhKJhcy5MLXkaqRD1wDnATFG9GPjjhkN6W23ioWHnQxAZo8vVSrmmTYvF
+WEgwCmfdoW/S9Vdcs6mRxYu2SdiFwvvLXBkIath9/SMmyL96fZgpvN0n5q8WWStp
+7u6FOYTAtwNFWEmkliPSePvs0hFkTPO9jF01VUOR01pxm0mu1qdNqCx7Xk5XvDp2
+eIiPPKvs/ltpySrwTJBNa+CF/nqDHyv8lWgxl3FJ3cRdwhcGfIM5TopOIe73vQMm
+ZzPigRoCUoUJ6Gq418bJXDn6PNQ/Iw/8jO8lljryzdOMpicmGjK7YZF/5IfYMGNh
+Uv8j1Qsrkbrw6quOXeVkwz00KO8vKQFUB5DbBixwJQKGYtT1WivU3lnQSpnH1bH9
+IFI+aWlNHinV6gSZyutmNRZOMMFWTgXdwGsWswSrSuv5pRKW4/Ol9gS/+2fWHRZN
+b/w9tKhCW5/zmL8FefOZbUsmmVx6ZsvVxubSJ0mPNG9DHz9YahJIhgfNYWBGFqC9
+DvEZ/zykYaHT6f8r/E9dn5kjVvz2suqzml0Em0CCPvB3ahPGIoMguSm/BEGr2ran
+v7ISdoiFZVCvdS52JJFwHw6USTxgelrzCIoySx7MKqzjN92TdaHUkTCDLXNiT6l6
+fN+9AZrJK/lDbQ/xXZkryLUcedNEtQIDAQABAoICAAfQoxt/E0UvdVGy1LZIkVtV
+6i7w7q3UrTCRKxIYrwWixwzMsbSG5ErEt88sZE77YsfN/lggmZbEGXBvwJYii5TR
+qyxt23qHDJ1QRcO2Cb8+W8Yl5rUsViyo8HUnv/5aRQ6i4unnyFxlgPYt0YoJhhkb
+nX8ZsfnbmAzMa1FQk1q+h+JYF8MxEX1z50lrjNRhA1oR5S/RUcZeHTbjTP8UFqpm
+2iuTOYP/CvwMDPxdTVkp948YW+4VxA4VmHJoADg4sQeVHfWnwQBNaqQp/Pk+Cxoy
+tLacU+3b3GreezH2sUJvotJ8yPjz/c2SR0RNg/od0+aTuaabV3BSthKH3NwPoI0z
+bfLkwrR5KyJobB399UN3aqg2s4toKNy+6l9x2dh+QimwDOivptvynEd9BIXd0ZCn
+ohdE9b9j9eq0l36WX+u30JMyevjjumnZjKCh80Pf7MnTcqzggcWvoPYtjPqBj0ig
+WvKwPCmV0TG8wN441mjObUXLa1mFlb8b+NM8k8gy5odkyRGm8ZOOxYlOWmtu/sNM
+VBdjG3U6yONDf+TO+v7OVsOVs/IHFOX3RtpCt8wnFZfTxkxjqrk3E8O7RTXcrIny
+Tgzmi0h0bSTahsKm/0roQNPK6XNw6S6CW9B2kPz2gBEIpjrEl+C8hmsiYEzNJ9kM
+oLWlKEuwcMaXS1oazTqBAoIBAQD3S7icGxwTVypEKq7ZT4859UOtsdrqTKEFIVtf
+z4IIwmlo65mfNA7/w2TSV8p/o3NH4yznkEnVzvYYNXKt316oZM2CqCoA3XjeFlO8
+hUoScVn1VV/66E6wTIbRUCMdBfyPVNQ12bTZ/rPpmSlatXfUGarVRlJ15DDS0TpV
+s+ohxpT1IUnCx7N0z8cPbTFy2qguSbID6UydajXtM/h8up4866wg8nzT4PBssiqf
+NzWgAA+XP7oigfncgqSuQ2zk8Bedbm+tE6bKgK3O6VfTDRIV2Kw89Kvt0OWQYpOD
+F/CTarNdlp0kYmos/rC57AVSpdTNQm3944WFi1ts+aL74+b9AoIBAQDcjF0TnKr0
++uSAFNHDIxf7LHnX+uOZ7cTs284hIHZJ4z/GgwHKimWeG4XZsOGPh9Lk5GGMyDBB
+N9daaGYskoQ9qh0e3IyRbbzdcwUMV9xzulYzUg5OKoezpBlp8Ydd8Gp3/9SBQtTi
+9jjLZ45Qea7/F/Kk1TebUvqGQa+c7HdeJ60/6121QPw7eFqJIOVqf47Tkaq3Wmpr
+csfQulNwN4Gi+v2gp3iMR5q/agKCOtI56daheYyNgPxX+chjiqOqC5WElTxPihde
+lKtYtKh3rnboKGUQ4fJOVFoV/wrfo5wfcYkPDB32Ct1B2hsI3oHbnPkBPgvCB0Xa
+/HPrEqWP5W4ZAoIBACQgVbnIZBOXOj93FM/+RWgsIlTvlJGB3EwJkXWvtMlezVNc
+h7awPjiy7LmlxZlb4W1xDJBPjdnEQENNG5G2/fcPss4RjwFNWWjoThdOSYHkOUYT
+0M+wvD4ZD+DoGhkVVM4DkHTFdxwZj2Li0x3DQNwlW8WIXmeGjHNfyWvXuq5wejZN
+RJ9F2TuJVwUz6HNk6gjJD05u+JhOec5LN1PRV2iC7URq6D1zsOvQI1XbFORo3d40
+mxaLclr6YuBqTTAsuuZuybW5FzaiEcIWaJQWZrv2SUMmYy98wuyS2gXeq3B9t/JG
+HHLCRcyI8HxYtHZcb3gE6liasljOAO8skNjHdGkCggEBANF9dm/Jkc2vf1p17CWJ
+8R6BSZ8wzf6JjlNaGjr3JcTbWdnK2Om1ef6rsAFudWKrplQK5uodwVBBpYpXvi26
+YmhcbNrCrbb54LsMpQ/raRh4N6b522K+HTYyun0akfVWBxvC4uyBOcv4C0ySKekh
+HGtsKOwPJ4mfUR4zyIarSlsiHvunKtSfTLeEg6Lbn28AiP9HzzvoY0t6tHf8dIMU
+Bkx0UnPGf8fnwALvxEBFdSjTiC7LUQmcKpW6SnDa4MkFxdkxFB+NUNNjLjrNJ3S/
+QG0W6aEWrd1fXE6meoKhWwu3AXRMky0Bdtc1QBa1m+2p9hALCoob9Guk/sqcZK0B
+RgkCggEAHjEa/4q05VPbMm7TOgF2m5QTdap47LyTBti9TRurGtB/9nWvIHpM9sAy
+0xVvGcoZOqVHYvRZGpZ8IX4B+9FGMNUDBMc8shj3oA514tCZVPCEolnHcuwERiZD
+c5zh2PccktAmT5EXGch0+eRuxJ1ROKgR0coeo8KMOxtrm0hRFTznsJ0nzNjAoCA4
+zW6DVY7qIb9ksI44rWlgGSwXG1OuUpqH8+tBAvR3uNa/j59psBb7Pu5zmg/qhx1m
+Ljd/0JTxE8A00l0bC8S1F15wGn8GQD63pjq8nr/biI0Y39g3TEAffkI33FfCjBxQ
+gO96WUZwPEimQAnu4Jw+RlpLtWjOBg==
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/cert2-example.com.pem.ecdsa b/reg-tests/ssl/cert2-example.com.pem.ecdsa
new file mode 100644
index 0000000..9dbf25f
--- /dev/null
+++ b/reg-tests/ssl/cert2-example.com.pem.ecdsa
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIIBhzCCAQ2gAwIBAgIUJ2zhyUgHjXsPzANqN5ZSHX0RVHYwCgYIKoZIzj0EAwIw
+FjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wIBcNMjEwNDAyMTI0ODMxWhgPMjA1MTAz
+MjYxMjQ4MzFaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMHYwEAYHKoZIzj0CAQYF
+K4EEACIDYgAEx1lz/PGGGGI9EG5L7qx8JGwt15HNuJI9SsdwzkRV/N8sBFzAEVbS
+UWVthQ8tIAdW1y7d9fwkHrzkPulDVwZGGr3qrnZSAgb7NCxBICxgdDI7ku3oPdNd
+bsSASmhJrQO4oxowGDAWBgNVHREEDzANggtleGFtcGxlLmNvbTAKBggqhkjOPQQD
+AgNoADBlAjEAnHx8jSzldb5z4FR3oZ3twWCzRR98n1IBuBi5fe6hhBlQF5u0iAyb
+oDcZ2Tx9UfWhAjB/DKDFrlXAkow4rQxHU602c9SI6hJTCKxIfWWoBYP7zqZXEUjj
+2QK7BQb3sHNpsqY=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDsiqzn+NewEL5bc3CA
+sY4ADwk42yQJCPZalIct5i4e5u660YCUMHqbVAUQe2R6YFyhZANiAATHWXP88YYY
+Yj0QbkvurHwkbC3Xkc24kj1Kx3DORFX83ywEXMARVtJRZW2FDy0gB1bXLt31/CQe
+vOQ+6UNXBkYavequdlICBvs0LEEgLGB0MjuS7eg9011uxIBKaEmtA7g=
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/cert2-example.com.pem.rsa b/reg-tests/ssl/cert2-example.com.pem.rsa
new file mode 100644
index 0000000..7a6678f
--- /dev/null
+++ b/reg-tests/ssl/cert2-example.com.pem.rsa
@@ -0,0 +1,80 @@
+-----BEGIN CERTIFICATE-----
+MIIE1jCCAr6gAwIBAgIUCMeB9uw+PcBIqW8cDI21s7SxWVYwDQYJKoZIhvcNAQEL
+BQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wIBcNMjEwNDAyMTI0ODMyWhgPMjA1
+MTAzMjYxMjQ4MzJaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIICIjANBgkqhkiG
+9w0BAQEFAAOCAg8AMIICCgKCAgEAzt3oEBc1jWk2PaN/tJA/PTTdwfi6ZXqXCrCA
+ZScmo1jvM3CcoOM1BUhiMcoeK4uHRryYUO/eL/ZM5OA11GAIaMevhK65rtBYIh2Q
+klRH+IojmRL91U9tXno+oMBS8WwF7K6eCCj4XUTAKuolQ4yiFHTvdwOsqSrVY3m/
+m2Pp4VTqjDSsljmv8GJ0lQpxan5bZt6WWQiCIbdS7ExgJIALDemg+JOIz/bDmCr/
+3tihmHOK94lCcV/CFOs2XctVnkS6W8x/S4U41Y/eciUbLWr5CxAvfZLOQBuriWiU
+SMHPJI63VPijGKStnBn/zRMvDJhaadkRqAqXlJUZ7nkcZ5WlPuIMgAOc2uCZioW8
+DvyJmplBjBBQdGqRFaeX2lDvJwDECDxSHglfQgVVz3II3ZMSlDsystu4MCgeFa0e
+S0UCvl+5mK1/QVzkzxYj1o9iXhtq5VSLmbaAssDcn20ashJMxmruagsOR4MhaKA0
+RsMosrAiCbcBiY/Q8W6NoOwxNUC8agsqDRNSoJfQgYhTJXqxbnteyy3TXtF4zW+S
+7D0ZsRXM+u2z6V7lP8rvS8ZwzI7nDA/hH34IIw4H875IESLA/8ZiMA3luzMNxwWr
+xCn58JCJM0lJmgkO+NvKctGAGxgtdKzgHemzczx6GuA3V5mOOD01KUbMpZITN4lP
+vAt++qkCAwEAAaMaMBgwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20wDQYJKoZIhvcN
+AQELBQADggIBAMc0Z6hDp5VuihQ1LpmfisQtrs0F5SpfxlbCshg9MOrgRGwViRBM
+bCw1UhDZPT7sQ47JucUkw4RguJTsNQO6Iacq04EKSfHmbxznlZ9eBpAMdK8vWLQH
+jrpmNVE6At3kuyFJrXEc4BOrvzwDqcbG8cFFwT+l9C5BGSZCG/muLPuW3S36IY7i
+uVGc4MqrOQLRghyZbjkXrReGzBZVbuCiz9O+zsjorEzt58gdwIhrl8WyHTJ/Nqy7
+ibfFDh+tJxdNkipa0PZEqovMUcMG1N1E+n4nl6QooUsIx8JmeL5OD4J15ZuvrK3A
+emggxAMs+rkooocc8SL8i0C7l1m74qRKCP/dhIw8R8XiSKaSU5PQxlmY62qHJNkh
+RIkwvv+VcGdUzC74eEPUagKABzYARXBC2410E8vekxVYAZ3U31ypB+/3nWBJOqH0
+P//I1ZKwYLQCuC02O2Uy44kwZsZ1Syh2BYJxjdIeg5oMVnrDhi9kYnMtDmtzLsnC
+kP/cMKX7NZ7d/qbF6Aa9vVE/Ta/OrLxETF8CrjSa/nDLdLpm9sDC26/aqZv5L554
+xeSKVxvZyRFtObSKW1qzK40RMkWUarh72urtd9aM1t5PHOnwY77jO/yemjxfhgvp
+jUKM0pxIe7EmNqoEay+zdN58x8VPDtLFNehorGUnUGkaS57BFBjpEUvY
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDO3egQFzWNaTY9
+o3+0kD89NN3B+LplepcKsIBlJyajWO8zcJyg4zUFSGIxyh4ri4dGvJhQ794v9kzk
+4DXUYAhox6+Errmu0FgiHZCSVEf4iiOZEv3VT21eej6gwFLxbAXsrp4IKPhdRMAq
+6iVDjKIUdO93A6ypKtVjeb+bY+nhVOqMNKyWOa/wYnSVCnFqfltm3pZZCIIht1Ls
+TGAkgAsN6aD4k4jP9sOYKv/e2KGYc4r3iUJxX8IU6zZdy1WeRLpbzH9LhTjVj95y
+JRstavkLEC99ks5AG6uJaJRIwc8kjrdU+KMYpK2cGf/NEy8MmFpp2RGoCpeUlRnu
+eRxnlaU+4gyAA5za4JmKhbwO/ImamUGMEFB0apEVp5faUO8nAMQIPFIeCV9CBVXP
+cgjdkxKUOzKy27gwKB4VrR5LRQK+X7mYrX9BXOTPFiPWj2JeG2rlVIuZtoCywNyf
+bRqyEkzGau5qCw5HgyFooDRGwyiysCIJtwGJj9Dxbo2g7DE1QLxqCyoNE1Kgl9CB
+iFMlerFue17LLdNe0XjNb5LsPRmxFcz67bPpXuU/yu9LxnDMjucMD+EffggjDgfz
+vkgRIsD/xmIwDeW7Mw3HBavEKfnwkIkzSUmaCQ7428py0YAbGC10rOAd6bNzPHoa
+4DdXmY44PTUpRsylkhM3iU+8C376qQIDAQABAoICAEQ6PiKodPop3EDiHul/tcvL
+FuS100xK7WwSIJa8Hes8FtCBcLdDmKYgZHqFbgPwpfI3m4j+Q+rPsja+mCJudfeQ
+/JunQQieIKNH2vnYIFChxvHiqKNk6e6CJQvBwtlrRlz0jpykXp3sYfEFfrrTtFVI
+5/350UWOIgkIC6EFiArQhfcuHEoDxrpizo6lfhigiibYfP/qZXkXTJsw6XjAXmT9
+TCEQD8x/V61laTSngEyWtxvDQo3ABnP9y9WNjbSAeHJ0dPuEeeU96SD+igMlx/PV
+J8Sj2bCdL6tHObjxaw9knqTAyJIFJllY3dxWWmsuCIvmkwM4UxwnPQFBIpQrb+9A
+rguNl+t31zljmToDIEF97G/QcbFqMQEKeNCkwIdtD/8tND7RrchcqQPc96rdHbB7
+Hfb/ZXqCSsYNahurEmeAUZJkLO9U6/0GbWHcxkHBTkrmUs2qV4LrhWP71tKpbNY7
+mGXK6Ok6ZfkAD4uau1oQkndqdlKg/rBOjcT+HGPtxWL9gPtG7om+O9mu++BngrGr
+oyNgujkVRN0fpJhKLhsT6OiZF+7CVQo4ZIw9dBQ2hzLNw5tKgW36GAVTfFxNRTje
+SerlyEog/P3s1tnDn7BngdVOdnDfiOi1O4TEb4btwqP3BSs2p0wJKaJGoClFFuwN
+n5dtHMABtSOKPbmWurbtAoIBAQDqPmZjSLfEwSXph33m7Ms2/AbQJltzU0ftRJU9
+TQGVHBajouupVcyrZ+WiWcltLov+JNlseXG/PsIWEmqSiLodIZJyjWSDUiC5iFEM
+fn2d9X4NLz0A508pFR5FQnULFEDMDryLn+4ta8Bf5NeL2p/ZavKh9rxX/8LAanse
+6Lst59RiiRMkazkjC4DHDmqUAZBt+uQVaHVFpTBJLa1k1nIc82GjsJwWsbADL3+o
+PKiggSir/Uf3nOOPhXsegVTZBiq9DNFciCa+kqT4eluUopjWxIuOKnp5mVh2DnTr
+NXyZ6jDb2JwjcJpy6HLk9EsqY1YuMpT+OCNnLM3l2Gxp/KovAoIBAQDiFJEh/LHl
+++7Z4TE0whMdjkFdSCuPyEnU4WFRKLMTPQRCdS+5GxHDy4lzpArde+51C6UkAjxe
+jaAGzQvabKBl4Al6eFpYvv0d8CQMWIrOffzVMRXuHWgm/SBg7um6ok0rM4/BOdUr
+CN2nWvBF02ZTSsGzzBmzTo4vMkcAQOiGes0Haefxm0DiVvoElL20Fv/iuEzbf60p
+W/0TzeiOBar8WxpTTcnHc6QWQ2t/Zon3/5E1LIOEU2/GQiS6zqNBRGr+kfWtz2wB
+d1IFLXITiqAQb+F3EjKqGS8ln0JYLSLRk3ALbb0EtN59lYwrabUYq9WzA1MlprLp
+GFqzAHNPc+qnAoIBAFg4DAOUXXGCdK7Q0n/n6ljY7g/ygjqawNoBHFur5s6rd3NF
+Zo+tuplLVdahDhVKlHqwkhoiWs516k65vN1XFRDnleoCijpS8fQt/KhB8zlMPZ7l
+jYoLk2qbg3z+HGqBxC2V1ziWkPMWQ6tZ2jvXqKAPgTWyYRibQFOLRrdLW0NcrkY1
+7bmnkCs8p9FQAp+fPy/Mb54IazJBlj/ZLhZuFSgGGV22o/KAFRP+DYvk3HUmb5Tm
+nPYKZkGlOcsxVi0t/2aXrzm0JTNcszjJjDgcTIeGGjD+moW1VPWRWENFL5of8yq5
+F4TZYbGpDaxgvPZH1ysq7aYYqmyvGRRZP+titw0CggEAaPoB1hU/Cbps0xDEx2mi
+dKPcaBMd3xqyZb3tcUEDvdgkRTOi4EHYguDcxyyRuvxT4ldw7AJ5w7Hhb6cAbQDp
+jcR0wkBmOzUb1S3vnyfx9CX+I4QyWamf9hKtWTU2pGm+iWPcyW0wNVZdjdslHFcn
++V8KCJGqEV9VmEaxP0XkcqVM1LdxcveTLkYSu9PRLnFLihvn3Dgx0LWdEvgWlvO8
+zIcE9090dT+WHpxZqwOS5uvtohI0U1pm2VlXMsLGfYTmZaSivn1E+n1MQYkzoi1J
+W7iHqcFycxdUlBSaOtViiIv8h+IB1dCiSxAI0RO5emY3yXKuxhnck22yl9GKuYbq
+mwKCAQA25h2vjVD9x1Yci/qWnKnchjVlTkKWb0D404fhibJpSXHtFOYiE8YXsBBS
+zLYDeDXFagl+AorvG45SoodJGl1/uqGbZMPBs0Yh211nBVtR5W+8vHLPEbw/Qvl/
+AXSmwnVT+K3oeJRxUBIlOLQcDtXcFGBhF3CbbjKU7+9gRdj0oq+O4DZXZVnJPeI4
+Rf42bfQYXub1bB+kH4WwkuLYItrzv4vLgS7kO6Z1GXz7mIBZi7zlUI7Wl5pWg1fq
+H5X6u6V6N2LKS7Sqwa7ihL1ScUMhfmcPE362FyxqwkSMWOx3F/L812MKCgwVoil6
+yupxw0d9CircRDDG93pWn3WxCHpV
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/client.ecdsa.pem b/reg-tests/ssl/client.ecdsa.pem
new file mode 100644
index 0000000..b9940f6
--- /dev/null
+++ b/reg-tests/ssl/client.ecdsa.pem
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIDPzCCAScCAQQwDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCRlIxHTAbBgNV
+BAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRAwDgYDVQQDDAdSb290IENBMB4XDTIx
+MTEzMDExMDIwN1oXDTQ5MDQxNzExMDIwN1owWDELMAkGA1UEBhMCRlIxEzARBgNV
+BAgMClNvbWUtU3RhdGUxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRUw
+EwYDVQQDDAxFQ0RTQSBjbGllbnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQd
+LnaDhFB0RmWq5WQMdPuFXqjBNZutLQRZ5t+AJ1afpujuwr4G79Q0eZKeYyFHldq5
+PMQDBL69D285AsUbMT42MA0GCSqGSIb3DQEBCwUAA4ICAQACnqZefAYCf51Pxhwp
+NElVCzLFcrNfMnCcOxHkuaWjdWbKZi+G4PNIT0ghWgX4k5Gzjx6cVjNmWVkLnJxg
+r6fL31u+Edl9BLr6KKrh830EOK7jN62zySFVjd9sqqBPiEBnT+3OCI9sXWXWg5nB
+B00E6Ll2axwEVrQFIVYnTPC8CJyDvF1t1Jmw/caaiWWVVoUu7Zoq1kVzMCuj7aCO
+BmhvDh237+Cjkly829/Q41aKVBSQ6yDsds4uNceOpAcXOQ8A5ZXa2yearIttvvAz
+LHvXcJZD3h/23mnLQZWo3YisQb3u7O9iIpIXdxpbVHtJ6JvshmiFHTCNB9KG+q2W
+CltrL8lYu2bWzNT8CPJRa5CsFyolIi5fEOfVOWLHKYkOgb9h2hiI9hT9Ujg5H1vM
+d7AeqE+frF5dzxslcQ/wLQoUc+v4bfhh3ffeAdNul8bydoSu3Lq1nXWchNkE6rcg
+pN2uD0eLC1hAXvxi6kQPlutmFJ8yXHySEA5uCek2Kf7dxudqIRKShT7aDVw6pd6R
+ShX4dXTGEO4eBxTcooK4mYQhf+ivyTxfkACnML85C84hXPSoIffMk+Y+PMfNgW/2
+9OH6IwEq7+dSSsAlYweGnqznPCyVfpesMaQCoG3l+5Ciznt5/WA4Mh5HzLE2PE15
+VTEdimSkNohOKYdqQHA3mcH3Dg==
+-----END CERTIFICATE-----
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIAe2GvrgpqaNk1wzyawK9CJYQz4lTVLDyf5MtbDDMYrcoAoGCCqGSM49
+AwEHoUQDQgAEHS52g4RQdEZlquVkDHT7hV6owTWbrS0EWebfgCdWn6bo7sK+Bu/U
+NHmSnmMhR5XauTzEAwS+vQ9vOQLFGzE+Ng==
+-----END EC PRIVATE KEY-----
diff --git a/reg-tests/ssl/client1.pem b/reg-tests/ssl/client1.pem
new file mode 100644
index 0000000..d830a42
--- /dev/null
+++ b/reg-tests/ssl/client1.pem
@@ -0,0 +1,187 @@
+-----BEGIN CERTIFICATE-----
+MIIFLTCCAxUCAQIwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCRlIxEzARBgNV
+BAgMClNvbWUtU3RhdGUxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMTEw
+LwYDVQQDDChIQVByb3h5IFRlY2hub2xvZ2llcyBDQSBUZXN0IENsaWVudCBBdXRo
+MCAXDTIwMDQyODE4NTk0MloYDzIwNTAwNDIxMTg1OTQyWjBDMQswCQYDVQQGEwJG
+UjEiMCAGA1UECgwZSEFQcm94eSBUZWNobm9sb2dpZXMgVGVzdDEQMA4GA1UEAwwH
+Y2xpZW50MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMCUnq4y/rYG
+n2BPYutNd/dQX3KV1qVKKXBsXXqBzE84qjBg6SeQQVwcVN0UYK+l2Rqnkt9m+sV+
+CxAwDAVHts/QmD/4tbjuP8tMQiZcUsl7hxRzLRK2lXGwoX3B7GJgXxjDckCllert
+FgUMylb4ACt8oA1e4c75fY8ppmOcjaNcPBghk09uKVUOKy+UZ/HWkNncF6cO9N82
+Y+bPdL1hg8mr6n7U+jv0bdyBjjN+b/3ggInY8NGyPHpl6ezvmgaI5+stA77YolCY
+NoG7ZexMpBbtv/2M7+PHlx5c5lzd4HbuC5fOtfkMvoosIZJaI8/mM5J6aeu6JpPB
+XvGRRE1Opmmhk1M3aQvU4q9LPYLkXIivuH+sHZnVZHZ32hhpZ4GhTpgayF22n/hI
+fMOzSIMhpao/1YuLVbLgXdWJZx9uOIT//a/3Bd4I/c1/Pt11oNSIhiEAS7beWj0c
+QtsSabeQwEIOOlbxWFA1aRogFNNE3iW4gps4p/4oHmT9Warb5AadE6nzh7N1nCiD
+oO7JoHUzOj8VunLn2RZ8vWuBJI/2fh1TJVjOBmQBl6YGHD8BaRWlzv/VOiq2z8at
+90rXGUb58KYvcfOTOZmYjKK16r/112pEgJuivXXr+N6qJKYxw46m+MAD2eDQ0Bc6
+gFZMlcyBAyJwuxIejUTvWwoddfRnaFajAgMBAAEwDQYJKoZIhvcNAQELBQADggIB
+AFk00NuZDresZ9voh2E9J2GvUbG9x+NSjZR6pQ3MiPPXpLYskV2xAvxFSayGcQhG
+mIfHshsnEhE35WYU80R5Ag1Mxh+XPbZUiNj/oOEFdBj45c0HGorChaVkZtnLilMo
+B0yW+0pnkqKaRkgmVsSrNCgimBtZX1hsZRLDxa2vldJ9lTIg3OuveqBv/uwbMOUC
+eT+il/sdl68K6oNHvAFdY1U34oJnvj4yF6ZZM1jRERK38wY0+2C+mlcXNL648k+2
+lOMeBddaDUKhscWdw1+Ui8Sn6lc6H+iPpGo3xdj9awc0568SCH+D5cpuTMNTREuM
+p3paOMGpLWuQQisltdmz8Ms8lAcJUDeyDmrgE9CPx9DiydB6Z1uP9y9sozqB2SIN
++QqfQLv+lAaUB6cu5xIWfZIFeTxxziABZ2jDF4vVvK+NN2IdBahbI63HQpfeK4tG
+Bkmuny4vlCnHBnzVaAboaQk2xzI9Yp79IN6yhmuO8AjCvd0XlH/nYF6b7WjVy0gU
+LpmkYVHWhADLY4q06PUz8gFGsfDHnx9RQIV01SXbcFxhmAjJBequBbTpucW4UAK4
+sTmg59wlYEeNdomLBPW8f0zkY3Nm/IbyJ8kEofUa4kbwdD/osS5fgWgARiVQXEMW
+W4oMGWpplJan6qe+hInvd+5syZXtO+K/uSOj63H6BwAu
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIJazCCBVOgAwIBAgIUWHoc5e2FUECgyCvyVf8wCtt8gTYwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA4MDQxODU4MTZaFw0yMDA5
+MDMxODU4MTZaMEUxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggQiMA0GCSqGSIb3DQEB
+AQUAA4IEDwAwggQKAoIEAQDARiuHkhrnf38Md1nxGDSneJfwv/QksdNNMNTJBdjg
+OVmaRCIAyz43oefTWDQ/TebbSwB+Lg9pud1zadGWhlZRhCgBPP8JDMhIKH4eXIRk
+5IIa8WD08EwvSlqJL0r4gsMtVsxy7BZHAkka/2Ket9pyGt4kG5n75RFdc6BI80/8
+RwJt/MDxPrcVBAT7LnCluxQpyya9mZCabj7l+9a2yU2hgWS6QqfZJ133krkP/MMh
+AEQkSoA4mmBwWk9yPqXmUqiOi7v6iLkIUEh5SgYVPRk9BtU/kDaUdSwuqRrpCZo4
+SsWZWFLxBmLHkSh+G+BWjCVYMQr2ye7e+VMT/20+5xAfq4fj9n5BsPcx3QcVuTof
+RAc/Oygnt4MYnIcUb7zRFvCAvgpUHL7BnEn6nhyXjHJGqGDchsg8m9t3v/Y3ohq+
+qmrSzdeuylE1n3W5aWJlbFmyXegNP45MJ0xicesVrXEWF7YD/ir9mGJ8bQYr4blf
+77PrbF02komC6AzVPKOJa0jR+eW1wErzYlkYgez6ylBWCiHJd1dhEHlK3h2rXdYa
+Gnb45ILCLpEDjNEUrHifLLNXwqJpgZQsJU6BgMgk7ZgBfAKrCfTeg0rkCqCAPeVb
+8eSLf7FBF7YBRJ5P6u8qXc4RtgEu607GaWV0gIMfyVBY52oV+OaNsEdFetrJnp3c
+friG8vJ+7jdq6zjUCGgnfUIHoViJPh3JuFfhA3jT0gQDKW5PeI7dxhrNvlqdYfHI
+fxX7Y1/J6cTQkqJ1cai2f0bwJIJiTAThNbG+zrtjJ7fZ3wJ4udyU/IKrwShqtmTb
+1Ofj0tJDdwOH8i84vIySLUvR9aAb7ClFlnsx6rzwOxG90W7C0LA2M0EHm4FezJm/
+FfujnZwEWr1T9Wki6qE0MHCbdN/TTDws//EKkkE44FC+amL96w0IQl70vpE37j2A
+zlDWvFFID95SIxfmpkwWDvXDKv6gr1GMLeysCl2fgpY05Xidw5cEo9/tEkuWn/dG
+x/D9hnLBGeroA0251ES12jemqDjI2U0tfaeHakjwSsoWElf94Qmuh2iPZ+1zIxQs
+7o6nAWN8X9hfsmrDTTHlww0TEfrjlbzG5Yh+0ZRxmejgiUyOCXck+eh/ZXMXvfWh
+y3CorIIuWgkRjm80PYkdaRDJdZuyP6R7tXfTXNVzAiSQf0Qx9ru2KB2Fs/XZPamH
+KjItAU5Q6msIVvaRMS0muQgV+b6hqSEBzqXqJfAlpVLHXr5FqK+U7EB9y02B6piB
+tAmxqXP8OOCoQql6/vgIcrDFUOo6KtGBW36ef74XE3KCUVaIzVJZSIt6i/Vi0bZj
+bAjsJUQ3qDlHdorv9TRVOhnC1GUz7SuYnpEOyiXmyx3LAgMBAAGjUzBRMB0GA1Ud
+DgQWBBQ62csZcH/meQcENHhNbqz9LMzwjjAfBgNVHSMEGDAWgBQ62csZcH/meQcE
+NHhNbqz9LMzwjjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IEAQBA
+wLsGf3R1+/I2zQE+lsj7RasZtA/Cos92iEGDAPvFbx9e+roG8Gg8KBsEJu/HN0JH
+lMMiQ8dDRHSBMvRBENL5/57oOOhmqc+1u5sazLuANhzAYPZG17Klib7YpEwWoXar
+FDDiJYtCyLW0oNLpCswYopWK9GC0RJNucB0NFvOxehJ2sP2/fxGBQMB09L6mjKjd
+4KsOzyd3dNf0VYS6jB+/1pcKSHKQUo9HRHB5FK04PsYHoh4AtmEHvmYQKcWWidgU
+v26ftlH00ERzuW2juqBbz9mghlNRqXi0IyZ9b4tSj29dxW+WWFzo7j2zEPaD6z2W
+DEHq7zvON+g+q6qLgWeszqMgJzjvWjMj00E/t06PoHPiz/cAnDKEqp+ZzxCIFrxj
+/qneChpogDWyLbawhyyzbZvbirx5znOSbWjPZgydqaNEFViqbxwinBx4Xxabo6XN
+TU020FuMWmgfbIcvtgjKgyKqc97l7JMNNm7LQV9+9W0U5zdIqQKLZ9MMrd2w3xh4
+MAB8NKnwzHReK0TWwUU9HSgFAGdEX6HnyZ3bQ13ijg+sNBRMEi0gBHaqZKDdyoft
+B2u2uasSwioV48dbSIcHl+rTBKxiMh5XQ7ENnaGOJkjsIqTVzizqnPHU8eMBnSbb
+dsXlamROYII44+j3Ku6OGt51w86eGk4VxI3tmaECcJKqTkwUFD8AcNDrkjtmLuxK
+12yjnoM+u1cclfqQ5NOtRc6MJZ27jCobfBBhVdKVDp4X1WNyqGlbsU5adDAzknuI
+GT7MJO7lGjkZX2n54BNPSfrSknYMOVYcZqL0Dbcrhx5IyEmg+iOlOu1HO1tdnZop
+ej4vT+1V2w9Sa4Wo3UCo84jcm5v/4z7jCYh4BRQ60CFb7GLxZoqXIslcGSPool3n
+jl8JWoaLXrJUPfZGXo1iAlayJ5EiMyZl4eB/TBUf6TMm8vLvsPiUT+CEsjLppOdS
+eYppZAZ6H1JrJGs5kKBdOJHGn6Pkp5QsHIswOBd1HqHrBbYbZmDaDLRHduILWLrM
+e0/IfDdeXB/bKfmZoEpT8xRiauw15p0AHLumiK7KISAehfgBqUnxx+YmgGoZ7EWX
+KnMYAfCuC6oJ1DL0gp4Z9yMK1eu+GV1sLxPq9ZruEHW1R+H+4sGyiA5Gso2tgB6/
+XW//wxKclNp5LZR7hqfs/kGuh5asrJrnEbMwWn2+tr/LqfYtYh1D6nHfIXpT0o1d
+rNy/HrsKnRDMWxjm03r4hCViuNVD3Zb9anAF/NSPDVu8ATM5JbJNrCYX4eipz6ZE
+aQBkwIBkTPgtgP4r8v2G+uMYDw8nq7xh72FK107aeTTwc6MgU5jfeFNMr2XJisJd
+lSem1ngKYQSEzjVsTE4c
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIJazCCBVOgAwIBAgIUJ67hHFw8DWW8omAyqE92SPRxENcwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA4MDQxODU4NTRaFw0yMDA5
+MDMxODU4NTRaMEUxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggQiMA0GCSqGSIb3DQEB
+AQUAA4IEDwAwggQKAoIEAQDARiuHkhrnf38Md1nxGDSneJfwv/QksdNNMNTJBdjg
+OVmaRCIAyz43oefTWDQ/TebbSwB+Lg9pud1zadGWhlZRhCgBPP8JDMhIKH4eXIRk
+5IIa8WD08EwvSlqJL0r4gsMtVsxy7BZHAkka/2Ket9pyGt4kG5n75RFdc6BI80/8
+RwJt/MDxPrcVBAT7LnCluxQpyya9mZCabj7l+9a2yU2hgWS6QqfZJ133krkP/MMh
+AEQkSoA4mmBwWk9yPqXmUqiOi7v6iLkIUEh5SgYVPRk9BtU/kDaUdSwuqRrpCZo4
+SsWZWFLxBmLHkSh+G+BWjCVYMQr2ye7e+VMT/20+5xAfq4fj9n5BsPcx3QcVuTof
+RAc/Oygnt4MYnIcUb7zRFvCAvgpUHL7BnEn6nhyXjHJGqGDchsg8m9t3v/Y3ohq+
+qmrSzdeuylE1n3W5aWJlbFmyXegNP45MJ0xicesVrXEWF7YD/ir9mGJ8bQYr4blf
+77PrbF02komC6AzVPKOJa0jR+eW1wErzYlkYgez6ylBWCiHJd1dhEHlK3h2rXdYa
+Gnb45ILCLpEDjNEUrHifLLNXwqJpgZQsJU6BgMgk7ZgBfAKrCfTeg0rkCqCAPeVb
+8eSLf7FBF7YBRJ5P6u8qXc4RtgEu607GaWV0gIMfyVBY52oV+OaNsEdFetrJnp3c
+friG8vJ+7jdq6zjUCGgnfUIHoViJPh3JuFfhA3jT0gQDKW5PeI7dxhrNvlqdYfHI
+fxX7Y1/J6cTQkqJ1cai2f0bwJIJiTAThNbG+zrtjJ7fZ3wJ4udyU/IKrwShqtmTb
+1Ofj0tJDdwOH8i84vIySLUvR9aAb7ClFlnsx6rzwOxG90W7C0LA2M0EHm4FezJm/
+FfujnZwEWr1T9Wki6qE0MHCbdN/TTDws//EKkkE44FC+amL96w0IQl70vpE37j2A
+zlDWvFFID95SIxfmpkwWDvXDKv6gr1GMLeysCl2fgpY05Xidw5cEo9/tEkuWn/dG
+x/D9hnLBGeroA0251ES12jemqDjI2U0tfaeHakjwSsoWElf94Qmuh2iPZ+1zIxQs
+7o6nAWN8X9hfsmrDTTHlww0TEfrjlbzG5Yh+0ZRxmejgiUyOCXck+eh/ZXMXvfWh
+y3CorIIuWgkRjm80PYkdaRDJdZuyP6R7tXfTXNVzAiSQf0Qx9ru2KB2Fs/XZPamH
+KjItAU5Q6msIVvaRMS0muQgV+b6hqSEBzqXqJfAlpVLHXr5FqK+U7EB9y02B6piB
+tAmxqXP8OOCoQql6/vgIcrDFUOo6KtGBW36ef74XE3KCUVaIzVJZSIt6i/Vi0bZj
+bAjsJUQ3qDlHdorv9TRVOhnC1GUz7SuYnpEOyiXmyx3LAgMBAAGjUzBRMB0GA1Ud
+DgQWBBQ62csZcH/meQcENHhNbqz9LMzwjjAfBgNVHSMEGDAWgBQ62csZcH/meQcE
+NHhNbqz9LMzwjjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IEAQCa
+SXUWwou6JG/0ubilpl4nBPIhK5sp/7jKBSsOEwn4jROz656Qf5M+mSgbQAjp/4I1
+qwCBktTF14bUDrxKpAga4M1KYilal8kiExd3WSGxbeNpdazbjLGdoDKKIBa6++df
+lCrxs/2Mg4RvTN4GOaj9A9LanWLj+rhIi27WD039dzHpZwYwgKpLwpvGHz+7bJzE
+93BqLqoG2q7/Gj+Y/uVfy9Vn1ikxHGJlS5pggH38F0iGy1QhmVHDp7umNUTHBG3p
+Q9a+wcNycrEkHQ/sniXiEaWzn1CFmVt6VcP2AAlioyfv9Q0hF6DRFeQrgNFYixj8
+kpomkqEtFO5Yj+J2FQZFq8UE7Boqv1oSdVnON+7Hy5gb4x5flKvTx5Sok1dg7W9B
+bYfICLwKCEi4mr1toQLT7e7PicGJXKh0nyHWHhpn9SeSElQniIlZbVrkDHx7zwOq
+fcYbjMha3uyqJbd10Rs0ytlL3uiQcHVs+bc9apSW9QPPFW1r5PC05Wn/9+iwU5Vx
+2s9WNgncvvdete/UjGBSbpXROe0fSuJf4+VYNK1SF9DJFaDim1zrOJWiT5bSxJGi
+MGKnQjEZZEs304dfunuH/I16l+UzTecd7QHgHgCfRN+pJnGyYbpT2lt9CCBD4YZX
+qBSQm1iR/7OjgFuLniOF4GLmatuNgVQdKQd6IcllPVK/E0khUwZ3LNV1RRrkvb0c
+9mNsnvhW81rBoD6+KHVgaiA9v9fSqeH8KDNbaqKImt9f9/hZJE1joy2hJIkkc4vz
+KNQy4aWmRUU37xlvF2yTWt8MuSf6UcM1IC5pfl+cEXNM3kyUs6dps2D66AfAsz7w
+C82xUPJ5blKhEWcskmiGXDL64NnD465WoMHPGVorRlRvdHy2mXQWaePF0OpmGtJh
+7LqRuV5ou9M4/fmPHrfLJ81ZDoGoBvKpibr4V/3wxdWYjIaQ97MePssVnBFtBKxI
+lcPsvunxL6dyxL16FfQ2WPqWe6Fq3UT39Lz+3y6SjtrIcASKJAE77HIPypITSoRI
+7Od5OT7ZxB1hxtvqHz45Wyer/aDMq2YDBDDs45s8qEMSPYozvs7LNprU42SJC/LG
+GjVFiIXjeBzwTUIjZOAjQ8lLFN2eBOPljdDLmqNjuVV7CgWrlIQ9PafPRXLsfC11
+71Xx4Kmb+I3v/upagQXKikNQZ3IFuXmCofRoOZEnpIvIj9+Dp3TgvK1Fpe9ldFhN
+h4Q09rb/zCMvB/yRMkp/JP6+9qySBCHl9kl5W9/bsgLgvdZKR0nDKSwxu/doyPQg
+/lgbeYbaZes520gwORtgSYJzuCt0n1nuYxbxINzo9Dw1hH0xgWEhDNL3gjZonmf5
+gCN9CPQlyEFKI9Q2QVUC
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAwJSerjL+tgafYE9i601391BfcpXWpUopcGxdeoHMTziqMGDp
+J5BBXBxU3RRgr6XZGqeS32b6xX4LEDAMBUe2z9CYP/i1uO4/y0xCJlxSyXuHFHMt
+EraVcbChfcHsYmBfGMNyQKWV6u0WBQzKVvgAK3ygDV7hzvl9jymmY5yNo1w8GCGT
+T24pVQ4rL5Rn8daQ2dwXpw703zZj5s90vWGDyavqftT6O/Rt3IGOM35v/eCAidjw
+0bI8emXp7O+aBojn6y0DvtiiUJg2gbtl7EykFu2//Yzv48eXHlzmXN3gdu4Ll861
++Qy+iiwhklojz+Yzknpp67omk8Fe8ZFETU6maaGTUzdpC9Tir0s9guRciK+4f6wd
+mdVkdnfaGGlngaFOmBrIXbaf+Eh8w7NIgyGlqj/Vi4tVsuBd1YlnH244hP/9r/cF
+3gj9zX8+3XWg1IiGIQBLtt5aPRxC2xJpt5DAQg46VvFYUDVpGiAU00TeJbiCmzin
+/igeZP1ZqtvkBp0TqfOHs3WcKIOg7smgdTM6PxW6cufZFny9a4Ekj/Z+HVMlWM4G
+ZAGXpgYcPwFpFaXO/9U6KrbPxq33StcZRvnwpi9x85M5mZiMorXqv/XXakSAm6K9
+dev43qokpjHDjqb4wAPZ4NDQFzqAVkyVzIEDInC7Eh6NRO9bCh119GdoVqMCAwEA
+AQKCAgEAuDVxE2/z9GmhSZ6mIC2Z8xcONazeBH1L5h3BzM0bgSvSnzQT0aRK4LC4
+/D/hvCIH6VchRlBaz04hhvpuhR5z35TIDWj5akt6+huXqtnk1pUyQH1rP9smV/l8
+f65fTjqgvC83ul6paG4gAfSaF1Zh0zcCYcfAdxpu3+IXJnE5imlPkkWLgw78uj8z
+T+/E/a8gH0RH26SS1nBQXxdRs1TzmpS3WVqfgXntHF9QhjELLuzwButcbzjuYKXb
+fKgzzMxoCqykSIkvuaffe3ilpcIps0T3wLBvRpJEGucB8xLJAvnwXOV9axylpcVQ
+140hdFveON6fMrx86hitmKQ7kTcKNZXEnaduehhQgDn6bqeJoAfHs4EX1JJqPZyw
+ibON1LYeUoFw9yWRy35Wr/XMkBoPwAykCWUwmOm2QEbmwhC7ORdjUVVuzrFdn/c8
+beoBfJTJ19GQjqSNcUv0cevfwYMxvimTh6oC0yPn3prRXCzL5Xd6ssSW9ISlIpu1
+etbhkvP1GNDKiAbH5uTZNIYMANbdOybfFHDUDWXHg0ObvXVLOhjH3OzdAORHKugS
+PPygnW4eXKt5R/uDRW/B0aUWLDtuB2Uj/+YQoA6Bm2AD75e4BkW9tRTqNBXOCCtk
+onvyAVJC4NoBZZQBRaOMBa0FIIxrjPLS9zmlyLehLjg5vjwjbAECggEBAPKmWUhO
+0HmwQ4/167CMwn+lIW/v9U1gQ1fvpBClFeJF/Px1AUQP+foajGxuXoMMnwH0fTrE
++ya2PA5ShZCkV+ajlBd1B8ymCRu1lp4ilCzEgjNU5U7nhJESCXBNRFEGFSjmO26a
+66sny4FiV7d6DeiJ36vPSn2BV0GezHedhbZBuaE+vVWahCXESsAqhAgejRB0A1uf
+sSyxXDaJl365J17jdO3YbS7p8LsovsK/Gfn6tTqxMNDnSJWgfFUPLOBznK64L1bJ
+RhW9HVrOeIrgV/l7mWEN/LFmWNMEcvi1E1oF08ZamjcwCmtBdGADaPcx07xQyJnQ
+6czKf52RMMcQK1ECggEBAMstD3JinyrNb71kb3fL0qlx3kO2HRsqbFVvuItd5SF8
+3/y6GuKmAikhmiZTx/DtGDGUIHD/ioiWkgswyoNKbuKcuDHklc9v3zk2A2Kac35c
+KXg//3keNouPLX/NEsu8haVas6GJhlvA+FxgtuNYQeCRMWzrzyCDBNf9KVnV8uV6
+/DBs7W306Q07im1MGMCc3P9Jl1cA0auyxOPD3mSnoDZfdzJmwNjrELSunM2BfzRn
+6h9Yi6adFkIgcEKg1a6/R6CyCTGGYs3QQ7+a+UoiNCXj99td5KWW+WMpSns6I7pw
+0bmiCb87lXrit1nn7Zgkk7W46jO6H/KyGgMQDs7b/bMCggEAC4S4AkWzgcNLQb8z
+w/q6lOKa1rx2UYj7SWZXzG55vncCDl3jhH6ZqDSwa8lFdUUZGzem5i5JmcnWyftC
+2d3jSlCDjCWDDETpc8ZH8xPDIujlIVirVfaJhXVsu0b/sjTutjVPpu11uHc4Itkv
+Psdtd5dr5bT+XTzRjoziOd9hZIh0LmJTDIg8M6rAvaSHBfelTJ2lNyk6eNume/RG
+G77gTpHPkCbQ8AQs6EWD4Ky/p+0twy58Gb6Q5IFsxYDl6XWzf1vA64a8a/XBOflJ
+IZaKto4WdtP6JdWs679vUb0OwRw7tFPCtFH0fKjrxE8FIY7c9TiEfUC8iHsoWat1
+vE1ZMQKCAQBBLl6TQsJvd+LOLsd39kLKK4az0Fv8GBsTOblJtMDKgoZVTNtNNRbi
+XS5X927ggx/M4AmcVs75zNxjjK6beiiiuMZ68yuAlhJWB1cErio5MpX3RwjNsXys
+Py3In2DVTdDOYI/aVgVtsDW9ZSWnP+w6gDoMCIa1lnLaXBSFBpdbOZ5oZrmxGe4e
+WaiqMcyLFofruo870T5yx/JUY8UYI5LJfsz9tWtO6/K7FH2njFDj3iaFEeITfLfk
+VQXOykxjOGhhTFyYr9VI0/S4Jp6tQtXaBg3BKZkt6oZtYpTLfbZynLkbxbk8yX/G
+Ia/Svw5BThK5LO6t05tmP+8KZn9pq7fzAoIBAQC/JwXRuUelycI7+tIXvcDX1ydu
+xASH6fyYcB1378KWNzWddcEb4NscfdRK4ekMO+oPyd40DNFl9ESXSUrxoILUIERV
+DywvQPMh+2sEblzDXvKO70BmSBSwq0tgfLSXpnu6nv+EHMRARA/qTk9R+Gl/REF/
+mH4ojpv2jHE50ysWFWvxK6whSG1/bMXBsT7YocR1TLBxZpaB1mVxUJ11ESKDMy+A
+lf79rIhGfU41mjzr4fkuYbERQy0yM3+lfG5qShAFAl52Fa2eFVBFso090+1TMhlR
+1ZmG9ZnE31uXoKU6OGcAGyFmvwhBIkjczH0z74CIYkD9gZJ1lW4RohgiZUja
+-----END RSA PRIVATE KEY-----
diff --git a/reg-tests/ssl/client2_expired.pem b/reg-tests/ssl/client2_expired.pem
new file mode 100644
index 0000000..9d0d2e5
--- /dev/null
+++ b/reg-tests/ssl/client2_expired.pem
@@ -0,0 +1,81 @@
+-----BEGIN CERTIFICATE-----
+MIIFKzCCAxMCAQMwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCRlIxEzARBgNV
+BAgMClNvbWUtU3RhdGUxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMTEw
+LwYDVQQDDChIQVByb3h5IFRlY2hub2xvZ2llcyBDQSBUZXN0IENsaWVudCBBdXRo
+MB4XDTE4MDQyOTE5MDEwMVoXDTE5MDQyOTE5MDEwMVowQzELMAkGA1UEBhMCRlIx
+IjAgBgNVBAoMGUhBUHJveHkgVGVjaG5vbG9naWVzIFRlc3QxEDAOBgNVBAMMB2Ns
+aWVudDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQD8JQiW54JVNyFa
+lPvw6skL0W5790n5R5kx10H4RUT3sIErV0K6Hvz/KwVG/jYb8yA7YSHZKYaklNis
+Zjpxj7tnKop7QwyWViXlbW1hRC+imsyO8PLrrc6YkLujKBmB1/z4523/opgNE0+m
+ROEjLIEB/nPHSPy57qdS3RdbCkQoBT/1fG8yyKbhcyHbL1Aj3Hk/553ZSgOo/Xl7
+HJ8wM+MzgkoSvPFGHn4WGckBEtiz9Fvt7v8RQJhMePjOXmDLdoiaRmeyhu0a8drq
+fg55s4LFbM58vW/pXAPyb6KzPFC1htFY+yBk2l5s4JpggNuvXEJIiP+9COY4D/oy
+79mMxZXWY/6VY5NQu54LN6vt24q9pBtaF6OjsaXUz4ZW5pj8Qpej1uXS8N69jgy1
+3CR4kFDb7pa1roe9zXq14h64kpoLA86Y17B3rRAIkIDGf/LdwL1il92Jdcl+K4g4
+YycbWCzgNb4whgokfYGfwsVV01SG1+19h+Nsme5hYROQmYbCbC94lAWJD/U/7EUN
+6KN4A7WgCxTt7Vvz2GSEE+HU/WVO+tfgxOPs40M5R3D2LKC0owEyXqkFxAANstd3
+ky6KZfkVQP0U+iz8m54o5HKvoF6EAzEHR/l2kPNCBj/hhyYGi44SwjXEOdzOcJVM
+buA7Hp2U4eOhoAJ/VoWJhY2gntcQJQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCl
+h7ITBQcBe/Rhc7Q7YE/1Sr9duVrUAUgS5bO1xHzqlBeUxPXqQhBMYBYLnvoVdJUz
+Hk/7JgvuTgQWUHHabSmKiQ5ug/8sRJSJpOavWelJW+gKaBbMUDZ2xiVYsVXJSmCk
+RpvZV+Gb4Q3JRPxkz7+KddB8FnvPYg16LyfoRKk5aVPD4vjT3ePgFZRRLY2w6BH3
+tQFB/xjCTLyX6Bhu+fC37S2N/+a+i7/vEpcOcjKpqkE/Kvb9W5Usjz9kIy5ceq6h
+i0t6FfYVcpwO6ZCSB6DT9OnzbdzPbYILdYhpCua5i64YS4cSaW9ltFvsTMDy1Nvm
+VbRh3kEtrkywXa5XmYbQE1Zm56jc7MIiyQRLBS60/SA5IzFQFZQh/NDzysLlvDMf
+vdExBQ5HJGKje+GN9deYoN3WXKpK+Qik6YZ3cVKMhBD6hYTM/da/4A6XGJEKvARy
+21rreRz/D3YMwac1/b5DPViU/6pXMGKud9/ZtlkEi7NHdzVJHMl/htcVQGlTnZdK
+Q6Yeug24JbnBZxIbhcp5aaJ+rzQeswL2SkWpF4td87Ku0gFEBShxG4tQNtfvewML
+XFybPNAkKOhR84K2rdMKwjva7vxm3tI22wll6LTVP8YUd1SS3/t9yL4jWxHX4Ds8
+gxdxuGWjJe6zm9R6OX63sv0meKNUsesmKQTpdu/gLw==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEA/CUIlueCVTchWpT78OrJC9Fue/dJ+UeZMddB+EVE97CBK1dC
+uh78/ysFRv42G/MgO2Eh2SmGpJTYrGY6cY+7ZyqKe0MMllYl5W1tYUQvoprMjvDy
+663OmJC7oygZgdf8+Odt/6KYDRNPpkThIyyBAf5zx0j8ue6nUt0XWwpEKAU/9Xxv
+Msim4XMh2y9QI9x5P+ed2UoDqP15exyfMDPjM4JKErzxRh5+FhnJARLYs/Rb7e7/
+EUCYTHj4zl5gy3aImkZnsobtGvHa6n4OebOCxWzOfL1v6VwD8m+iszxQtYbRWPsg
+ZNpebOCaYIDbr1xCSIj/vQjmOA/6Mu/ZjMWV1mP+lWOTULueCzer7duKvaQbWhej
+o7Gl1M+GVuaY/EKXo9bl0vDevY4MtdwkeJBQ2+6Wta6Hvc16teIeuJKaCwPOmNew
+d60QCJCAxn/y3cC9YpfdiXXJfiuIOGMnG1gs4DW+MIYKJH2Bn8LFVdNUhtftfYfj
+bJnuYWETkJmGwmwveJQFiQ/1P+xFDeijeAO1oAsU7e1b89hkhBPh1P1lTvrX4MTj
+7ONDOUdw9iygtKMBMl6pBcQADbLXd5MuimX5FUD9FPos/JueKORyr6BehAMxB0f5
+dpDzQgY/4YcmBouOEsI1xDncznCVTG7gOx6dlOHjoaACf1aFiYWNoJ7XECUCAwEA
+AQKCAgEApmQJ9wtvhqyK5ivK1oEZiyL5tfTKbCZDghB7CEst6AYiN2euMQSiEAFj
+yiWXr3oRmx3OKHCu2Y0gLySHDMm88aexGwZ0GAFhoLVFqRpGFRfyRaHbrItV+ngI
+WvLrYjQWTGrsu/WgQYCs3xw1NfD4cUhpPul7XXeQE66y6vEraP2N54HmH60p8zz2
+6p2eVQv5N6KxF+Mv5yTeNc/9fOHA3QzttM/aqFsW+Z6qdnrpZlerEqjUyZ3G4zAx
+gH3ngl0GaEhtxfIkJdPUk0n8Y3OCqKXU3Zxlbam7MRFaXM1AtYnyPLX7+pHgHhlZ
+xrVCQ8auNw+xNB3bTsO8aEC/X5ZD+ZdO/NCbhzEXPdx5XF6LDlB9uthC/i5G79DB
+5DK3GsrPjFjmeY3gmvKm5ikiLNiAvMqghIrKKdLhMJe/AfUTkwVh0Hh5St1o9zPT
+ZZP0sNIw+da5/qW2iB1uBdP8h6sdrZVOsfkY/fynny+wEkkP40FAVRHH42p/evRY
+qLu0/4MVUjHEgkC0G2ZLFw3n2Eq5omwH2/4u2xzN8W83+kMdBj8gB3qNFjFXLba0
+Z9izOc8xcFsvnmjWIIZ1RZsby0DqefVSfYuc1ON4qOA4hiZZNywS8Uk52i/+7MDi
+Q8eGOdUzFPmM6nTPwMLFspzzLTiflTvGDeEITJO5/DFa2ZWf3AECggEBAP/QNzTx
+vxOw3nuEvoa/4yp7TBSwvw1V8KC9298IQ3wIqNs699wNqxADGz3P3Vb37psPyBmk
+oOclX7we8hUpP0F7OIQo5oENcRu20fMY9Lvbygr8T9j6rxUj5CCqO/HqiD07J59w
+4/DE3kuzG6wLV+Tbuo+kV1ywNT3NnjzjFgaZYVjp1P71uUQfsg9ccX8N6jaF5LTn
+UTxMAxxvLJ+7qk+4OmFDLZ5y3LiCyezdsCUQeEcHf3VQKNdafkGSmMlpyIpa7D1b
+CLfJcR/UOYMezNzuHlLc18pxATOzbCLLZFmGfhdgI4SnNFpdqGk/tUAyiQrN8tTv
+JeSDi/usSQaZXlECggEBAPxUIfMCaSPpG8KM8gHgp7yz+KqY+cErD4Oh/8j9do/x
+0JkO2sV8EMSuD/alKzbN9O40KCPPw8unnlvkKE0C4of0ugzRg/e1L8SpOYzKWX5J
+zMjO6g7m+QU2kKwrcrjosmaWH32ANPY16fUiUOyl1Md7U0trYFRt9+4eqNdlej9j
+xMql9KCii1SrGrrh1sTzluvkIedqKYB7S9nv/z5diTm4F+IiBXU536YfJXJ16LpM
+aJE8+yECnV8x5Hr9LEGayjRtxIvLObBrCyeVDCQSXT0fB9sAL+gr5baFO6fq3kS0
+pk2hCkx+r0lqwIOOd8guKSIHIpTFOmd0x2RtoxNOu5UCggEBAKL76yCdYYtPJgD2
+i1lZCof3dHq+PYtmlOAk9uA76Jsu/T5obKDUSIf0IrgYJsKRRoGe5XOJE0cR5dP6
+t2xKElZLBrAVSv8wLD9nFI7Y+Jx0JV8ocEsjNMe4TVGOhJDWR6UTemQ4TdIJ7EO4
+wsmzlHVolY2NPGf+kH1m8wmB+XeM45v9p0omDrrbotvsnxc/K1k/p36m3ngXSegk
+4P6IV7NhAjkTzw3jysL3+WUjvWVv/+HpYgjBYLQMoOJwX038StvzoA5bYMuP2bZY
+xafHyOh+Ae3zbL07kHN7PktQ4Qe1C8Mi6p5K1a05fOJJx9Y2HGA45R1LnQ3hzh80
+HnbI4nECggEAPGu0+WixXnz6PbrcVGDEKaZ6u/cHjx7NhzqqcilnU46W4Z+x+Sn9
+Jet8PRZN48CrjsKEfhbJDqIjhGN81vwC3IVYa6tby1vihVf0ROdLSLdJRyhs2Yar
+SHlJaUC6JtbpqTD3d2jUxcQhMqa19AS9j8rTJjMfDPiMLsO+sF1HSZiNTe0xR6nE
+bVDPhMKBWAXwNKobCDveljpv7k7OstNZAa44Ydi9r9Vc3X2FzQO456tWOrj8dWoX
+3uymhmDLUSZMlwNV1heix8DKGf9Rue1/0Bv3GJTR4+lnBy6eG1ZdRNxxGhOe0LRh
+KtZaJOZfflq3VMOanz8e/hjzifPK4duvhQKCAQB8Mo5dWvs5fCpWAQrNqj+ua8gY
+a8ftp7R+idGGgOLSCUArjY7sS1RvZzCB28I3/5QpAuEEhaLFTABNonhbD5MdB5SL
+xVxfXqcW/WfXkGF+QqB1AMXpE4zLeGSRERWpWJSaD7B2I8UdS/Leo3lVchvA66qx
+SG+Pojcp5DsoZP3hrh54fsPdGorzezoTIwfQtsy3P8DnzPohjzbqDKmloglDbo4Q
+rBuJVs/Gc7UwZGvka+roi6VUaVdRa5PAluCE4GS9HSwf31k74jw3TfYVIlQgL5Yi
+kIHsC0yXfJ0FPXiw62CMEr51ssX3QNGTIKfos24smCjK09eInNZpIZm+p+SL
+-----END RSA PRIVATE KEY-----
diff --git a/reg-tests/ssl/client3_revoked.pem b/reg-tests/ssl/client3_revoked.pem
new file mode 100644
index 0000000..0aba2ce
--- /dev/null
+++ b/reg-tests/ssl/client3_revoked.pem
@@ -0,0 +1,81 @@
+-----BEGIN CERTIFICATE-----
+MIIFLTCCAxUCAQMwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCRlIxEzARBgNV
+BAgMClNvbWUtU3RhdGUxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMTEw
+LwYDVQQDDChIQVByb3h5IFRlY2hub2xvZ2llcyBDQSBUZXN0IENsaWVudCBBdXRo
+MCAXDTIwMDQyODE5MjkxN1oYDzIwNTAwNDIxMTkyOTE3WjBDMQswCQYDVQQGEwJG
+UjEiMCAGA1UECgwZSEFQcm94eSBUZWNobm9sb2dpZXMgVGVzdDEQMA4GA1UEAwwH
+Y2xpZW50MzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM+8CxcAKMMh
+BILdtSx27Zjlri9ygpI55eW94t9rYb967glYbF+ZGZ2LiqXHzIpabasquXD/oH9l
+fQpaeb498ZUblbVb0OPyVkSSBpt4y0wPBYYiUGU7T94drdMwEySIyMEIRNlfXePB
+EQJLbdksdFBu4QCQEzzdL3aMBCogFfN85zJ6WJhDHnkbtKdUpKJ5irBB/3Hs+pMq
+I3Y4cdeWmFkJ+xQpu9oh0igAhkbSPYXu+asSCzExO4G4ttBnQQh4RYUUe+IqO8z0
+QQ/La+m+OBXWR1ti+/3ImeZWdRlA7xpTNYTOxAg0eO1FuUhwvw6Fpvo5KV7wre4W
+Qkmsjc5vpxubWWrdfSK/YB8jZJsdx2zgk8thdhj31Zhv0PUP64fhX03DKFSF+qNG
+0POpjPthu+f96umHfIFNNKiLPyWBpl0+ppI1FB8uW9xXRZw00iXl89bXNa1lbQqr
+c3cj893HUnEpx3H0Q3piEsKu0mchGXiVVJsoZgbLn6yOXDnkWBQhAFvvRcfrAzki
+w3f/gU+BiT05csRCXtmbL28RaK70fBxD6fDhGRHyMt/0MFhYnJRxmIB3GniQAgC0
+lyqyMOplkHVeHO0LhjrLTZwbbD083A/KRzpsrVLHd8sjCEjojae0tPDj65u0xg1R
+JrszrjO8ZNLQoXr2rl6hjxeLC2Yn08W1AgMBAAEwDQYJKoZIhvcNAQELBQADggIB
+AIzgQBfDxEdowxYsdZ4cb0wySg+xB11XRLeR9k6c1kExDkpTKRyAy+6CNS0X2mAz
+3v/jVoh3G4crlBkL7UJn6ycunuJ2SdiUexsJAOveVgPPml7YnRRfPW9ddM+gn0y/
+TtTB0D52XaXczeIqQKFD67OtjbVvObbrO1cITkh9q+mMtTO8T/V1gBRd1VH1YFdi
+nPqTYYA9QqJ2zAaufhZVCkpJJn5onpT5t+GBpe9O0lKlkQrduLzjr2rrfJCg2Uuw
+xBXwpvFdOK4BY5tDqVLb7BOLkEUUltWKTYd4IFjonRE6OSxtY+1L/RnEYMfSSVIf
+GsTkKugTuVSmmyFmh5H10YjwMMD3j36hjxJcGJDzZIuOQMY+2UKI61eF7StqZTXE
+wRj+JMHHRHIEw0181lHxGSCArWyLEoSn57NSAqJEzdhq7wb6eZwqZzRo8EJUSYIK
+3fLnfjSLHS/XaH9mCbx7VpYfC310UGzQ1QXSOIp1LtKtxUbT1YL7RTwa7GVfvQ0e
+9nsY9/qd9Oo2VJtxKQRsfro6Z/MdP97lUpTaigQEUpB7KICl1ks56oQrunRLXkO7
+EoDNlnDGkp8DghO+tPqx44OogbXBFCRTO7ncYxSE83WcG0UMUvVfGoMJKqF8V0n3
+LmKLNCvzLQ2Gt21Cp/zNiwHSjMNIIqybjAe+nVT4+sSI
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEAz7wLFwAowyEEgt21LHbtmOWuL3KCkjnl5b3i32thv3ruCVhs
+X5kZnYuKpcfMilptqyq5cP+gf2V9Clp5vj3xlRuVtVvQ4/JWRJIGm3jLTA8FhiJQ
+ZTtP3h2t0zATJIjIwQhE2V9d48ERAktt2Sx0UG7hAJATPN0vdowEKiAV83znMnpY
+mEMeeRu0p1SkonmKsEH/cez6kyojdjhx15aYWQn7FCm72iHSKACGRtI9he75qxIL
+MTE7gbi20GdBCHhFhRR74io7zPRBD8tr6b44FdZHW2L7/ciZ5lZ1GUDvGlM1hM7E
+CDR47UW5SHC/DoWm+jkpXvCt7hZCSayNzm+nG5tZat19Ir9gHyNkmx3HbOCTy2F2
+GPfVmG/Q9Q/rh+FfTcMoVIX6o0bQ86mM+2G75/3q6Yd8gU00qIs/JYGmXT6mkjUU
+Hy5b3FdFnDTSJeXz1tc1rWVtCqtzdyPz3cdScSnHcfRDemISwq7SZyEZeJVUmyhm
+BsufrI5cOeRYFCEAW+9Fx+sDOSLDd/+BT4GJPTlyxEJe2ZsvbxForvR8HEPp8OEZ
+EfIy3/QwWFiclHGYgHcaeJACALSXKrIw6mWQdV4c7QuGOstNnBtsPTzcD8pHOmyt
+Usd3yyMISOiNp7S08OPrm7TGDVEmuzOuM7xk0tChevauXqGPF4sLZifTxbUCAwEA
+AQKCAgEAr48B6ExQJqhOwbJRHOTdY6woCx1BUAbyTbiudZawozxm0ysRW7FtvoFh
+iT1TlVFbAZ833VGL+F5y0D8qSCbddeA8I2sXHK1/TrACOX5agUropjV1sDfyBYsb
+jjFA3E1lLA2q8fHwzTwq/b91dGZnXlp2eR1JxNRA+nTWSCuZoY9bbIONQBDpPfy2
+LfwQrub82HzOPx/BnIGuOoj1XPd+hTE0KhQjF/QhQYE/+bZQHFKcWYEESGyNF9Jd
+Xb8FbP0H87IeCEMdCtcZ7RlDd+U0TPAsmgULZa0Us1850z/XUm4j+rsrXKvLzupv
+7dKrBMDbHvkUB5Jry5ywJMdZiK8/j0QW5bw9Hw8tEyXxT2gzXFze4DrEHC1cPLod
+3bcMOnp8axtdfm23tlFQuq4fGsERABFWByylF2Pu9KQ1AgH8/53IcVnNjd7Z4ZlA
+eBrZynEDg67sggFNRa6EnjAYFS0Zqgmfo/160awcGSLPLSkE5FhtByQOEzyAumXn
+UmDO4zlP3dc54WzCnxdS8GpbbmjniXGSDe9D16D0uWQeo+LCoDDTExT3wDjY3tDt
+R4VjIBVs1vWXH2oG/oC/ulgXwcSKSSvtqftcGnPj9EE6exNzanTQwCFHosYWl5Tn
+MkRsxNRFITKksNH5sXAkzwogWlyG4PK4ink0IixpYh2N0WgncDkCggEBAPqZ7z45
+F/YusR+eJdMrloECYhP1BId7zUzZglAUof/KJH86TVnQ/wGBcl6x9SXGzy5Mix8S
+q0qUILJ3nXkyRqFjlch9c8NlMR5P/IPyQWupSGNFPTIBvNefCfqosEFD9635P4ND
+sN19gwrx9IqMYgyPzw05G2CJPafemjF5NLIHKyhUnjGUij+D/WZYCKvHIrq085ac
+0dLncRvlnzloa8PCGXDXcTuFacVGcj6QZJvn7ZrprMOwpwh7RT02U9cqlLYKfjEg
+9xnTSmxbb8esRtWDlJPoj3+P732Cj7BynSpvLFSsvHAAFS4j/g3XIjdY/yocd0xG
+UfYDEcilgPiaEnMCggEBANQ1st6aaf/7oH4hJ/mgOc2RhGYxpjHgXs+ux77llHks
+o4VlAILV9CLQyQ9/3PU/4vidw/rseZwPmONDlBeU4319MQzjZeihaqfaTQXnQRBj
+xX2sJ/7EeBoq6Xlkvc+lVbiWcA7i97dYEumV/q7ozYRyAhP/D/VAdmT9ZWK3qJ+l
+/L7h43ch9PWGDOjiUIfWx/xAodyDUEM1iforv/S7D4+3j9BriRnhpZRLZT5bG24h
+vVN344ETxaoVWwjw9yzmJHF/4ooqJgdTsjJ8ujPPLvJKXAD7ZVerhcUpZWmyMACL
+Dj8IuNZeB7IN9LOCr1xPenR0jdltz7+LU6WTK0F4NTcCggEBALvxvOL+sMDaTc63
+rgiM1ShWIDZ1ePsfV15+dmQWxVRwRyUAFcj5nHaFnb/1WTUGwJUppOEeAEdDhq4y
+VXDyytP5OvmNVMfDWa4xMOHIS1YyNG73G6kocneH+FT8NIwOLHBW0VJh7wB+RExu
+IAfUtyhSpmd1X9nrs8j1gtD95Q5rn+t0YtwuWey+0cny1jX2eE5srY9Ud2zkVQkm
+El9cuA2twaTGf06zhRsF9WKEql/e9m1LOV3eW7dZtBjvaLujXLqWbgPshEXjGBri
+DJhE1S8GquSu8wgpa+TGiXs8yjBsBmRO1FhvR3M+XSgGI8w8u8naZYJX7tpBfRHt
+RiesbY8CggEBAKMcm14rBmryOIx6Y8Wl+Igf38rFQt93fKjZyULcKGFzhEUWO2xV
+lA/mt4SoXWhNMOK0MV1/woHII1YcLYpqsOlV/wvPBhfnapmWXDm7ZPF6HuTYHO3g
+ighjD451dshSZy84wu1OW+WbVv4gguBipQW2tA42sUdrwxUhCHr2fDAqX7lA25xI
+h4bpAKdIvWmMF6+25jMe4+SlFGcslaFA31cyWuJypbE1FhaEVU+2q8DdQi8UKdSf
+JAH15EFdJkBmrYBoMfLNLunW1VOlN2J3T7iAm3NNyLm4Z1wC06aIhgkE2XBt/dUX
+9YZQ39PTEYM8u/0jUZzcoSCzsRnFoyvxf8UCggEAblaNsi8/Nx8FId/aW3klrIxY
+UfSVXL3InIkrr2hJs7GYMpdWRwQZpo+Nv45cBnGoRwWWIsYkcWEbrs1vxvkNg0Ro
+pTa0Pt5gb1u7BfvpSqC/VyFBd66BcTQeJqTUHzWPKhMyCrP/eRYfFFQtpy5EZ+/O
+cjEVO1Tv5VhqM1PtANHdsS6o0jKMWFQ/Ofu4sOp6hQl4E1oOAzjLdtyBgJzSk1Jg
+M1lKPzSpYgRWcMB9CFTE2JO/4b+iMhxQjvGtD5nkeA6ZD7DSDItH6lhAQsho1pMi
+uoFlxDSFYHt0KcFp9zMrB2810mmNvjiEaqVXkA7QRH3XCA0BTkIXxzQe5QgTNg==
+-----END RSA PRIVATE KEY-----
diff --git a/reg-tests/ssl/common.4096.dh b/reg-tests/ssl/common.4096.dh
new file mode 100644
index 0000000..8db27ac
--- /dev/null
+++ b/reg-tests/ssl/common.4096.dh
@@ -0,0 +1,13 @@
+-----BEGIN DH PARAMETERS-----
+MIICCAKCAgEAvpZPDLMGhdop4RgoSzRJfr681WeWplvSvBsIqyKB8D3uNPZchSg7
+Aci6+yupRDtVeaLMmJgqjiTb9wYXhJNxyuVMPfnFrYwGSm32OUcMhECD6N2elOj5
+WS8fvoYIMvnENyDsutmBObXISKLxeaY+PJEbwyEeJmdzEV6oM0qM/2bEJcgQ00p2
+V1Nge6OZpjahlRCpKHsQAIgtUpchZVTKZCrO9WbYUPVYcUIAmyNLmTlPmM08EcsN
+dJqkhse0xZN2isnGJybe1ABIW8D31aWqfWhjmuNqe9JTqz8BS00WOeKGYiEENIIF
+lHmU1uKYm+9ii1stT7WyrtAMRjbQSVsye9CEkne5jsQuhF2gzLMFhsEwE5svDBn9
+CeJC7V0WHef0kHNUSm9yzRQWFp4Y9sJI7Uq3Po1xOBBCDUQnDJTFsNiJSF84gYGo
+fvjMsvf3mLNkDE12g3trHUMjrns4MLpla21bA3FKEqyfUuR/yYQRtLOkR7sxF4+J
+lporo7jHhgPK57euhG8YLOgSEa0LIYXsNSHI7yDpkXFmwtPBQRE5ZOaN4mw1fsHp
+/+adsUAh30KDeoXXyZg9dpZFnq/GZlAHdiO48oVsYnloNNYwrPH9bU53u5oj73bo
+CTCZOb7V2BvfvnfwNmzwuofXMFXBvNqDSKcM3rkMSi3OomuHBZ/QQwsCAQI=
+-----END DH PARAMETERS-----
diff --git a/reg-tests/ssl/common.crt b/reg-tests/ssl/common.crt
new file mode 100644
index 0000000..1f0c275
--- /dev/null
+++ b/reg-tests/ssl/common.crt
@@ -0,0 +1,90 @@
+-----BEGIN CERTIFICATE-----
+MIIGeTCCBGGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJGUjEW
+MBQGA1UECBMNSWxlLWRlLUZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxEDAOBgNVBAoT
+B296b24uaW8xFTATBgNVBAMTDE96b24gVGVzdCBDQTEeMBwGCSqGSIb3DQEJARYP
+c3VwcG9ydEBvem9uLmlvMB4XDTE2MDExNzIzMDIzOFoXDTE4MDExNjIzMDIzOFow
+gb4xCzAJBgNVBAYTAkZSMRYwFAYDVQQIEw1JbGUtZGUtRnJhbmNlMRowGAYDVQQH
+ExFOZXVpbGx5LXN1ci1TZWluZTEYMBYGA1UEChMPVE9BRCBDb25zdWx0aW5nMRcw
+FQYDVQQLEw5lUGFyYXBoZXIgVGVhbTEWMBQGA1UEAxMNd3d3LnRlc3QxLmNvbTEw
+MC4GCSqGSIb3DQEJARYhYXJuYXVsdC5taWNoZWxAdG9hZC1jb25zdWx0aW5nLmZy
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnb0BDF7FsqzslakNg7u/
+n/JQkq6nheuKwvyTqECfpc9y7uSBe/vrEFqBaDSLQagJxuZdL5geFeVtRbdAoB97
+N1/LZa6vecjjgGSP0Aag/gS/ocnMRIyvlVWWT9MrD46OG3qZY1ORU1ltrVL0NKtt
+JP8xME7j3bTwIDElx/hNI0n7L+ySkAe2xb/7CbZRfoOhjTVAcGv4aSLVc/Hi8k6V
+kIzdOEtH6TcghXmuGcuqvLNH9BuosyngKTcQ8zg6J+e64aVvC+e7vi94uil9Qu+J
+Hm0pkDzAZ2WluNsuXlrJToPirWyj6/YdN6xgSI1hbZkBmUPAebgYuxBt6huvfyQd
+3wIDAQABo4IBvzCCAbswCwYDVR0PBAQDAgOoMBMGA1UdJQQMMAoGCCsGAQUFBwMB
+MB0GA1UdDgQWBBTIihFNVNgOseQnsWEcAQxAbIKE4TCBsgYDVR0jBIGqMIGngBRv
+G9At9gzk2MW5Z7JVey1LtPIZ8KGBg6SBgDB+MQswCQYDVQQGEwJGUjEWMBQGA1UE
+CBMNSWxlLWRlLUZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxEDAOBgNVBAoTB296b24u
+aW8xFTATBgNVBAMTDE96b24gVGVzdCBDQTEeMBwGCSqGSIb3DQEJARYPc3VwcG9y
+dEBvem9uLmlvggkA15FtIaGcrk8wDAYDVR0TAQH/BAIwADAaBgNVHREEEzARgg9j
+b21tb25OYW1lOmNvcHkwCQYDVR0SBAIwADBIBgNVHR8EQTA/MD2gO6A5hjdodHRw
+Oi8vb3BlbnNzbGNhLnRvYWQtY29uc3VsdGluZy5jb20vb3BlbnZwbi9MYXRlc3Qu
+Y3JsMBEGCWCGSAGG+EIBAQQEAwIGQDAxBglghkgBhvhCAQ0EJBYiVE9BRC1Db25z
+dWx0aW5nIHNlcnZlciBjZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAgEAewDa
+9BukGNJMex8gsXmmdaczTr8yh9Uvw4NJcZS38I+26o//2g+d6i7wxcQg8hIm62Hj
+0TblGU3+RsJo4uzcWxxA5YUYlVszbHNBRpQengEE5pjwHvoXVMNES6Bt8xP04+Vj
+0qVnA8gUaDMk9lN5anK7tF/mbHOIJwHJZYCa2t3y95dIOVEXFwOIzzbSbaprjkLN
+w0BgR5paJz7NZWNqo4sZHUUz94uH2bPEd01SqHO0dJwEVxadgxuPnD05I9gqGpGX
+Zf3Rn7EQylvUtX9mpPaulQPXc3emefewLUSSAdnZrVikZK2J/B4lSi9FpUwl4iQH
+pZoE0QLQHtB1SBKacnOAddGSTLSdFvpzjErjjWSpMukF0vutmrP86GG3xtshWVhI
+u+yLfDJVm/pXfaeDtWMXpxIT/U1i0avpk5MZtFMRC0MTaxEWBTnnJm+/yiaAXQYg
+E1ZIP0mkZkiUojIawTR7JTjHGhIraP9UVPNceVy0DLfETHEou3vhwBn7PFOz7piJ
+wjp3A47DStJD4fapaX6B1fqM+n34CMD9ZAiJFgQEIQfObAWC9hyr4m+pqkp1Qfuw
+vsAP/ZoS1CBirJfm3i+Gshh+VeH+TAmO/NBBYCfzBdgkNz4tJCkOc7CUT/NQTR/L
+N2OskR/Fkge149RJi7hHvE3gk/mtGtNmHJPuQ+s=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIJazCCBVOgAwIBAgIUWHoc5e2FUECgyCvyVf8wCtt8gTYwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA4MDQxODU4MTZaFw0yMDA5
+MDMxODU4MTZaMEUxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggQiMA0GCSqGSIb3DQEB
+AQUAA4IEDwAwggQKAoIEAQDARiuHkhrnf38Md1nxGDSneJfwv/QksdNNMNTJBdjg
+OVmaRCIAyz43oefTWDQ/TebbSwB+Lg9pud1zadGWhlZRhCgBPP8JDMhIKH4eXIRk
+5IIa8WD08EwvSlqJL0r4gsMtVsxy7BZHAkka/2Ket9pyGt4kG5n75RFdc6BI80/8
+RwJt/MDxPrcVBAT7LnCluxQpyya9mZCabj7l+9a2yU2hgWS6QqfZJ133krkP/MMh
+AEQkSoA4mmBwWk9yPqXmUqiOi7v6iLkIUEh5SgYVPRk9BtU/kDaUdSwuqRrpCZo4
+SsWZWFLxBmLHkSh+G+BWjCVYMQr2ye7e+VMT/20+5xAfq4fj9n5BsPcx3QcVuTof
+RAc/Oygnt4MYnIcUb7zRFvCAvgpUHL7BnEn6nhyXjHJGqGDchsg8m9t3v/Y3ohq+
+qmrSzdeuylE1n3W5aWJlbFmyXegNP45MJ0xicesVrXEWF7YD/ir9mGJ8bQYr4blf
+77PrbF02komC6AzVPKOJa0jR+eW1wErzYlkYgez6ylBWCiHJd1dhEHlK3h2rXdYa
+Gnb45ILCLpEDjNEUrHifLLNXwqJpgZQsJU6BgMgk7ZgBfAKrCfTeg0rkCqCAPeVb
+8eSLf7FBF7YBRJ5P6u8qXc4RtgEu607GaWV0gIMfyVBY52oV+OaNsEdFetrJnp3c
+friG8vJ+7jdq6zjUCGgnfUIHoViJPh3JuFfhA3jT0gQDKW5PeI7dxhrNvlqdYfHI
+fxX7Y1/J6cTQkqJ1cai2f0bwJIJiTAThNbG+zrtjJ7fZ3wJ4udyU/IKrwShqtmTb
+1Ofj0tJDdwOH8i84vIySLUvR9aAb7ClFlnsx6rzwOxG90W7C0LA2M0EHm4FezJm/
+FfujnZwEWr1T9Wki6qE0MHCbdN/TTDws//EKkkE44FC+amL96w0IQl70vpE37j2A
+zlDWvFFID95SIxfmpkwWDvXDKv6gr1GMLeysCl2fgpY05Xidw5cEo9/tEkuWn/dG
+x/D9hnLBGeroA0251ES12jemqDjI2U0tfaeHakjwSsoWElf94Qmuh2iPZ+1zIxQs
+7o6nAWN8X9hfsmrDTTHlww0TEfrjlbzG5Yh+0ZRxmejgiUyOCXck+eh/ZXMXvfWh
+y3CorIIuWgkRjm80PYkdaRDJdZuyP6R7tXfTXNVzAiSQf0Qx9ru2KB2Fs/XZPamH
+KjItAU5Q6msIVvaRMS0muQgV+b6hqSEBzqXqJfAlpVLHXr5FqK+U7EB9y02B6piB
+tAmxqXP8OOCoQql6/vgIcrDFUOo6KtGBW36ef74XE3KCUVaIzVJZSIt6i/Vi0bZj
+bAjsJUQ3qDlHdorv9TRVOhnC1GUz7SuYnpEOyiXmyx3LAgMBAAGjUzBRMB0GA1Ud
+DgQWBBQ62csZcH/meQcENHhNbqz9LMzwjjAfBgNVHSMEGDAWgBQ62csZcH/meQcE
+NHhNbqz9LMzwjjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IEAQBA
+wLsGf3R1+/I2zQE+lsj7RasZtA/Cos92iEGDAPvFbx9e+roG8Gg8KBsEJu/HN0JH
+lMMiQ8dDRHSBMvRBENL5/57oOOhmqc+1u5sazLuANhzAYPZG17Klib7YpEwWoXar
+FDDiJYtCyLW0oNLpCswYopWK9GC0RJNucB0NFvOxehJ2sP2/fxGBQMB09L6mjKjd
+4KsOzyd3dNf0VYS6jB+/1pcKSHKQUo9HRHB5FK04PsYHoh4AtmEHvmYQKcWWidgU
+v26ftlH00ERzuW2juqBbz9mghlNRqXi0IyZ9b4tSj29dxW+WWFzo7j2zEPaD6z2W
+DEHq7zvON+g+q6qLgWeszqMgJzjvWjMj00E/t06PoHPiz/cAnDKEqp+ZzxCIFrxj
+/qneChpogDWyLbawhyyzbZvbirx5znOSbWjPZgydqaNEFViqbxwinBx4Xxabo6XN
+TU020FuMWmgfbIcvtgjKgyKqc97l7JMNNm7LQV9+9W0U5zdIqQKLZ9MMrd2w3xh4
+MAB8NKnwzHReK0TWwUU9HSgFAGdEX6HnyZ3bQ13ijg+sNBRMEi0gBHaqZKDdyoft
+B2u2uasSwioV48dbSIcHl+rTBKxiMh5XQ7ENnaGOJkjsIqTVzizqnPHU8eMBnSbb
+dsXlamROYII44+j3Ku6OGt51w86eGk4VxI3tmaECcJKqTkwUFD8AcNDrkjtmLuxK
+12yjnoM+u1cclfqQ5NOtRc6MJZ27jCobfBBhVdKVDp4X1WNyqGlbsU5adDAzknuI
+GT7MJO7lGjkZX2n54BNPSfrSknYMOVYcZqL0Dbcrhx5IyEmg+iOlOu1HO1tdnZop
+ej4vT+1V2w9Sa4Wo3UCo84jcm5v/4z7jCYh4BRQ60CFb7GLxZoqXIslcGSPool3n
+jl8JWoaLXrJUPfZGXo1iAlayJ5EiMyZl4eB/TBUf6TMm8vLvsPiUT+CEsjLppOdS
+eYppZAZ6H1JrJGs5kKBdOJHGn6Pkp5QsHIswOBd1HqHrBbYbZmDaDLRHduILWLrM
+e0/IfDdeXB/bKfmZoEpT8xRiauw15p0AHLumiK7KISAehfgBqUnxx+YmgGoZ7EWX
+KnMYAfCuC6oJ1DL0gp4Z9yMK1eu+GV1sLxPq9ZruEHW1R+H+4sGyiA5Gso2tgB6/
+XW//wxKclNp5LZR7hqfs/kGuh5asrJrnEbMwWn2+tr/LqfYtYh1D6nHfIXpT0o1d
+rNy/HrsKnRDMWxjm03r4hCViuNVD3Zb9anAF/NSPDVu8ATM5JbJNrCYX4eipz6ZE
+aQBkwIBkTPgtgP4r8v2G+uMYDw8nq7xh72FK107aeTTwc6MgU5jfeFNMr2XJisJd
+lSem1ngKYQSEzjVsTE4c
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/common.key b/reg-tests/ssl/common.key
new file mode 100644
index 0000000..4b06553
--- /dev/null
+++ b/reg-tests/ssl/common.key
@@ -0,0 +1,28 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAnb0BDF7FsqzslakNg7u/n/JQkq6nheuKwvyTqECfpc9y7uSB
+e/vrEFqBaDSLQagJxuZdL5geFeVtRbdAoB97N1/LZa6vecjjgGSP0Aag/gS/ocnM
+RIyvlVWWT9MrD46OG3qZY1ORU1ltrVL0NKttJP8xME7j3bTwIDElx/hNI0n7L+yS
+kAe2xb/7CbZRfoOhjTVAcGv4aSLVc/Hi8k6VkIzdOEtH6TcghXmuGcuqvLNH9Buo
+syngKTcQ8zg6J+e64aVvC+e7vi94uil9Qu+JHm0pkDzAZ2WluNsuXlrJToPirWyj
+6/YdN6xgSI1hbZkBmUPAebgYuxBt6huvfyQd3wIDAQABAoIBABojc8UE/2W4WgwC
+04Z82ig7Ezb7Ui9S9M+S4zUCYHItijIkE4DkIfO3y7Hk4x6iJdyb191HK9UdC5p9
+32upS9XFPgM/izx3GZvxDhO+xXbSep7ovbyuQ3pPkHTx3TTavpm3GyvmcTKKoy4R
+jP4dWhzDXPdQW1ol3ZS4EDau4rlyClY6oi1mq9aBEX3MqVjB/nO7s2AbdgclAgP2
+OZMhTzWYR1k5tYySHCXh3ggGMCikyvHU0+SsGyrstYzP1VYi/n3f0VgqW/5ZjG8x
+6SHpe04unErPF3HuSun2ZMCFdBxaTFZ8FENb8evrSXe3nQOc9W21RQdRRrNNUbjl
+JYI4veECgYEA0ATYKMS1VCUYRZoQ49b5GTg7avUYqfW4bEo4fSfBue8NrnKR3Wu8
+PPBiCTuIYq1vSF+60B7Vu+hW0A8OuQ2UuMxLpYcQ7lKfNad/+yAfoWWafIqCqNU9
+at0QMdbW6A69d6jZt7OrXtleBsphCnN58jTz4ch4PIa2Oyq46NUXCvUCgYEAwh8t
+G6BOHOs3yRNI2s9Y9EEfwoil2uIKrZhqiL3AwdIpu5uNIMuPnbaEpXvRX6jv/qtL
+321i8vZLc31aM7zfxQ6B4ReQFJfYC80FJsWvcLwT9hB9mTJpLS4sIu5tzQc87O6w
+RtjFMom+5ns5hfPB4Eccy0EtbQWVY4nCzUeO6QMCgYBSvqqRRPXwG7VU8lznlHqP
+upuABzChYrnScY+Y0TixUlL54l79Wb6N6vzEOWceAWkzu8iewrU4QspNhr/PgoR3
+IeSxWlG0yy7Dc/ZnmTabx8O06I/iwrfkizzG5nOj6UEamRLJjPGNEB/jyZriQl7u
+pnugg1K4mMliLbNSAnlhBQKBgQCmYepbv260Qrex1KGhSg9Ia3k5V74weYYFfJnz
+UhChD+1NK+ourcsOtp3C6PlwMHBjq5aAjlU9QfUxq8NgjQaO8/xGXdfUjsFSfAtq
+TA4vZkUFpuTAJgEYBHc4CXx7OzTxLzRPxQRgaMgC7KNFOMR34vu/CsJQq3R7uFwL
+bsYC2QKBgQCtEmg1uDZVdByX9zyUMuRxz5Tq/vDcp+A5lJj2mha1+bUMaKX2+lxQ
+vPxY55Vaw/ukWkJirRrpGv6IytBn0dLAFSlKZworZGBaxsm8OGTFJ5Oe9+kZTjI9
+hvjpClOA1otbmj2F2uZAbuIjxQGDNUkLoifN5yDYCC8JPujHuHmULw==
+-----END RSA PRIVATE KEY-----
+
diff --git a/reg-tests/ssl/common.pem b/reg-tests/ssl/common.pem
new file mode 100644
index 0000000..042fe4e
--- /dev/null
+++ b/reg-tests/ssl/common.pem
@@ -0,0 +1,72 @@
+-----BEGIN CERTIFICATE-----
+MIIDxzCCAq+gAwIBAgIURbbHd6AXFZoZEmNAwQU1IbkeEjswDQYJKoZIhvcNAQEL
+BQAwYzELMAkGA1UEBhMCRlIxDjAMBgNVBAcTBVBhcmlzMR0wGwYDVQQKExRIQVBy
+b3h5IFRlY2hub2xvZ2llczElMCMGA1UEAxMcSEFQcm94eSBUZXN0IEludGVybWVk
+aWF0ZSBDQTAeFw0yMzA5MjAxNjI2MDBaFw0zMzA5MTcxNjI2MDBaMEUxCzAJBgNV
+BAYTAkZSMQ4wDAYDVQQHEwVQYXJpczEOMAwGA1UEChMFdGVzdDExFjAUBgNVBAMT
+DXd3dy50ZXN0MS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDd
++BTITfrXq7S3+dIUBlXEdNKXZPqSwhcgriVNvDhu0QnBbiqMV96MiEta+NrWvVy3
+VY41Y0pvDS1PrWsnClBMdBFdPkIRpAx20cz3M4lBDi/p14m+JbYvsVhLGDozMEba
+OxMSeidTFDHQq7k0b0sMMvJ2v09RvPaDytWaRtC07nVlZPU0fPQCSw3oZf1K9u9b
+dbuMJOeO2D0/PXezbWrdi3+VuaK47e+1Bijh6Qm8uD8f7SRKGFm26QkV87wKWw8x
+hPnZL1PNWyQNfAzGQf6sjpmahhz+Lva3ywbv5XaUp8ojgw4LOrz1fvC8dDj9wVg1
+3JhWhmwLC/5zG5eY3LuZAgMBAAGjgZAwgY0wDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
+JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFc8xugp1dGZ
++KqMGcfUmbTYEEurMB8GA1UdIwQYMBaAFHr9tGo8KeCWI09L6wA8+zwp7FEMMBgG
+A1UdEQQRMA+CDXd3dy50ZXN0MS5jb20wDQYJKoZIhvcNAQELBQADggEBAIzfQ//U
+1jqTmdjUNZHOqFvCcc06W9vDUJbeKSyStZnE/J3WHrJeLLNaUV00G93zLLRs6slT
+kZ4eEmUZlPGGz6hFK6d8jSIIxyaw/O5l9Ix/Z5cUMiScHNbiLBiyhy6AvF/NcJYl
+xQ6EUIcOqMxEL0dSRq6ckGZvnyFusPuNgfNeIy0Y1eI30En1mPNGQiu2DP7Ex4Ht
+dAiHT6ITXk43wHyXDqXpt97Rdbq1dNNP6sSkQ8r0IeDi5f/qSsBGbR1a9UoKkJOZ
+OO6IGhEb2XCWc2xquJpUHCOXhzaXj/SmxCDpWVW5tdKNZ96gUlp2Wtf0Rp25yFge
+4mCry3J674p8Oto=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDuTCCAqGgAwIBAgIUQQtTP1aDfRAnDdjKkaUT2py2fmswDQYJKoZIhvcNAQEL
+BQAwYjELMAkGA1UEBhMCRlIxDjAMBgNVBAcTBVBhcmlzMR0wGwYDVQQKExRIQVBy
+b3h5IFRlY2hub2xvZ2llczEkMCIGA1UEAxMbSEFQcm94eSBSb290IFRlc3QgQXV0
+aG9yaXR5MB4XDTIzMDkyMDE2MjQwMFoXDTMzMDkxNzE2MjQwMFowYzELMAkGA1UE
+BhMCRlIxDjAMBgNVBAcTBVBhcmlzMR0wGwYDVQQKExRIQVByb3h5IFRlY2hub2xv
+Z2llczElMCMGA1UEAxMcSEFQcm94eSBUZXN0IEludGVybWVkaWF0ZSBDQTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJXZfTPAWzNIh1EM3BRlO63BBpX5
+xDMb4yOP2Ntxe9mZHsI5dTRGgZygswZQV4LgKd7B868OEbaDGOjTwvDJI28foS1n
+almhniH/sQamCpeMEX9brRyJ1ev2mTLM1XkAhKmzGRRbGi+A8M6pIMaOLmn8gvsE
+ekfatzOG3wQamJDXLa/L4/Pd2GI+cb2wOLRtIHxuAocL+Dgy+LIa1q3slGyboU9X
+ZJcOjTa705H4FWbhVJ4KV0dI6iSXtO9xG/8RkuY9VyZh39pqU9aQxLWFUyy0coec
+b7RzyUrVDlTvmV9X2fotWmAnQfUk+4wc5/rhOSFNg1lowKt7MB/NjsPOmE8CAwEA
+AaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0O
+BBYEFHr9tGo8KeCWI09L6wA8+zwp7FEMMB8GA1UdIwQYMBaAFB4wopglmOnetKea
+jkq9OymofpZfMA0GCSqGSIb3DQEBCwUAA4IBAQDQamqX11VfTB5USqAL1E0/qHqG
+WivOWX2K5lCfbalg7Fqlm1d0hKffPODD3RAOU7UhP9B1xc9NRBgbNPEEMu/O92PS
+C5H8WxGoKfa4TuX8JfhhpUGpRelFFHU7mVVyMh7RDQmfFdxC8ej8+iTvBXtacMhh
+VWokTIakyFCj7u/qcQKhpzoTDq9VRE+lmOFYzMtHqk+qGVXDgG8z/e7z5UP98ttI
+XXsQ50Mi6ow8P118eRjJI01DZUu8QnYt/+jhqAFipS2OjyV4Jlq+wGZ4xB9gonlf
+lTdqR19oFnIFi30boIB33MRxz9qWZy7ay5jUV6jGauymQI/1waPtv/KIjXzt
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA3fgUyE3616u0t/nSFAZVxHTSl2T6ksIXIK4lTbw4btEJwW4q
+jFfejIhLWvja1r1ct1WONWNKbw0tT61rJwpQTHQRXT5CEaQMdtHM9zOJQQ4v6deJ
+viW2L7FYSxg6MzBG2jsTEnonUxQx0Ku5NG9LDDLydr9PUbz2g8rVmkbQtO51ZWT1
+NHz0AksN6GX9SvbvW3W7jCTnjtg9Pz13s21q3Yt/lbmiuO3vtQYo4ekJvLg/H+0k
+ShhZtukJFfO8ClsPMYT52S9TzVskDXwMxkH+rI6ZmoYc/i72t8sG7+V2lKfKI4MO
+Czq89X7wvHQ4/cFYNdyYVoZsCwv+cxuXmNy7mQIDAQABAoIBAAtHSbcLz00aGmqm
+tPfzgnQjA3hR1zGRzx8H+jlC8RMgaAB+GodbB6HYYwvSTTxQDt/55unri6Ks5rp/
+s0weiAn6c89rFGxVC5UV//YnljfKAsE9BHC29dTii/v01TA4qcD483Ui49Ci3A0g
+TJ7PcN7Dz/IcsmkS0uvLaKMYKg6nXu9UnKkLBqThTiLA5I+eZZ4zX862Yurku8NI
+HwbMtBsICbe1H0Ebdc/PPAShB8pvV3nQMGFjADOEYolaByQAltolADmIc5K9E6wL
+SsHzAjGTjarSYdqjZRuoEtQrWQTG1fnvJZBXB8L1Brv9RbrPWN2TW/A1uhUR4qYd
+wuxB1mkCgYEA9ao05RsJzDVc4qLBvDXuqo1WapwnYUyc8Jeq+r5l67Ota1ykQyiQ
+BJZDM/mdFRzZZjMAAMN9cxsDdY7gp0ebN190F443tSxjvlVOGJ/e8UJ+Au+9WEYM
+xZQo5VquU8XlxfwFYtYANMvr7DB8yEr25S7S2v3jZ70NZQDDR6G+5L8CgYEA506s
+JJM/NfP82e6JtSB9fOEcjEeddPCdf2RkB+E3Ppt7AQX5Aje/8VOSiZkIbOap9oLc
+rBd9GrER2m2pahd9DFkSs1td70IM5CwwgYIKyWkCCkLXyMrLpelFEqZsFvWD14Go
+c29NSDOpVfVJkPr46Gym6dBvy1rCMh+/ZrgsPacCgYAXFU0vEeFTzNfTe9OUacTp
+RaqPDektXVOJz9aDBQzynsl2wxe0L8WIiM37vkKiTzmmPriLWdMZ07n5e9lkHnhZ
+NaDk7boSTf95TO6vpaX/KW5JvFkgSES+8/L7yg+DU58JgWrIJK+URmz+nne7IkAc
+vM+XQC/z+XGewfmXa31SZQKBgGSDpHyUXBCXARa2+LJz9vQQYrZ23G6XrOlR98IQ
+1U/ogrA0JzwWe9tjxLb0gFvKdKtBvKEv59Z0gdyYcNlAcb+u6Vh1aMFyw2VX6pAs
+sYFKl29cEqcXsR1c2/45wZjMgclhd5EKGdw5TumimKBe31Eo/fN29024F9FuSF9b
+wyXbAoGBALGIKzPgV7Tt6SbzcCjJGQHlH/RKBcuFJjJS+Qph3w7K3L5b6Y35zPOY
+3+FxT2Z5wAlOGYeF9Qa8K3/VX1l7Vhktu9EcTqM59fMGuTM0mEgwwdFM4oFgRIau
+wmlIuAFmo7OwlsggHuHJ7lDk+r7AoNVW7l7Gd1JnG4CasvymVc3N
+-----END RSA PRIVATE KEY-----
diff --git a/reg-tests/ssl/crl-auth.pem b/reg-tests/ssl/crl-auth.pem
new file mode 100644
index 0000000..af59d1d
--- /dev/null
+++ b/reg-tests/ssl/crl-auth.pem
@@ -0,0 +1,18 @@
+-----BEGIN X509 CRL-----
+MIIC0jCBuzANBgkqhkiG9w0BAQUFADB0MQswCQYDVQQGEwJGUjETMBEGA1UECAwK
+U29tZS1TdGF0ZTEdMBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxMTAvBgNV
+BAMMKEhBUHJveHkgVGVjaG5vbG9naWVzIENBIFRlc3QgQ2xpZW50IEF1dGgXDTIw
+MDQyODE5MjkyNloYDzIwNTAwNDIxMTkyOTI2WjAUMBICAQMXDTIwMDQyODE5MDE1
+MVowDQYJKoZIhvcNAQEFBQADggIBAMPJgdU6bsFMFKBop0dngtAG1DXSrHo1XlYY
+J1uWEuVcNnimH1EHQXMmL5C26ALrHlQILLzq3RVcNZIT0tVF6jvcf8tzcaGeybS1
+tpDloE2A2jPz3Pf/uS4MB7eTPiMvY7cUl7fk4Oif/PjGPxdu+E5SP6HWVdjCvBHb
+2yye/KjN/vj3g5uI6z2l1Hxh2yzYmMVS8cTRG5SfUXgH+IXJOS8zE7CsMB/IRctQ
+TXD0q0iZLn7Q0liA/wxxJHYg2m3RdFa82THdWaqsIM4ao2KLz324ycQpWT0eRWpv
+6gyVXbEU/sX8HdZdNpfgQADiU8eK4XlnEmXehSE3TwyM1ysnoFRtOqDvaQrHbAMh
+Av0/9JLOPGDqCjof4lLfAW6JDtU55J4SxCYlaRj152939eXwDkb70WefZMssfqcw
+ZPDK6afY358kb7Yb0U2pE73+Z3VDcczBF085nc6q/2m5lvA+XwZYr4xBkVzHbdP3
+USEFd06FHlh2i2rpaiihR7sQx9KJ75ko3TjDbeg/QryMBKsS2CeJoHPDcFjjzFZF
+RW1HYReV1MZT8UEuskMvl+w57OYbfqf/pwhQcJTL8XE9PRtzntmLMofmiN/X5PQV
+YS6JvGVAIC7HFDiZ8Wn8B+WT93ecCNQL1FpIpo1JxuRfx6jTtGqGg65R3CzwbqUH
+dBkieO8E
+-----END X509 CRL-----
diff --git a/reg-tests/ssl/del_ssl_crt-list.vtc b/reg-tests/ssl/del_ssl_crt-list.vtc
new file mode 100644
index 0000000..83eda24
--- /dev/null
+++ b/reg-tests/ssl/del_ssl_crt-list.vtc
@@ -0,0 +1,102 @@
+#REGTEST_TYPE=devel
+
+# This reg-test uses the "del ssl crt-list" command to remove a line from a crt-list.
+
+# It performs three requests towards a frontend that uses simple.crt-list.
+# Between the second and third requests, a line is deleted from the crt-list,
+# which makes the third request fail since it would have used the deleted line
+# and the strict-sni option is enabled on the frontend.
+# Another test is performed as well. A line corresponding to the default instance
+# of a frontend that does not have the strict-sni option enabled cannot be deleted.
+
+varnishtest "Test the 'del ssl crt-list' feature of the CLI"
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTIONS=OPENSSL
+feature ignore_unknown_macro
+
+server s1 -repeat 2 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ crt-base ${testdir}
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ retries 0
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ http-response set-header X-SSL-Server-SHA1 %[ssl_s_sha1,hex]
+ server s1 "${tmpdir}/first-ssl.sock" ssl verify none sni str(record2.bug940.domain.tld)
+ server s2 "${tmpdir}/first-ssl.sock" ssl verify none sni str(record3.bug940.domain.tld)
+ server s3 "${tmpdir}/first-ssl.sock" ssl verify none sni str(record2.bug940.domain.tld)
+
+ listen first-ssl-fe
+ mode http
+ bind "${tmpdir}/first-ssl.sock" ssl strict-sni crt-list ${testdir}/simple.crt-list
+ server s1 ${s1_addr}:${s1_port}
+
+ listen second-ssl-fe
+ mode http
+ bind "${tmpdir}/second-ssl.sock" ssl crt-list ${testdir}/localhost.crt-list
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "DF3B6E847A7BF83DFAAFCFEC65EE9BC36230D3EA"
+ expect resp.status == 200
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "A490D069DBAFBEE66DE434BEC34030ADE8BCCBF1"
+ expect resp.status == 200
+} -run
+
+haproxy h1 -cli {
+ send "del ssl crt-list ${testdir}/simple.crt-list ${testdir}/common.pem:2"
+ expect ~ "Entry '${testdir}/common.pem' deleted in crtlist '${testdir}/simple.crt-list'!"
+}
+
+haproxy h1 -cli {
+ send "show ssl crt-list -n ${testdir}/simple.crt-list"
+ expect !~ "common.pem:2"
+}
+
+# This connection should fail since the corresponding line was deleted from the crt-list
+# and the strict-sni option is enabled.
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+# We should not be able to delete the crt-list's first line since it is the
+# default certificate of this bind line and the strict-sni option is not enabled.
+haproxy h1 -cli {
+ send "del ssl crt-list ${testdir}/localhost.crt-list ${testdir}/common.pem:1"
+ expect ~ "Can't delete the entry: certificate '${testdir}/common.pem' cannot be deleted, it is used as default certificate by the following frontends:"
+}
+
+# We should be able to delete any line of the crt-list since the strict-sni option is enabled.
+haproxy h1 -cli {
+ send "del ssl crt-list ${testdir}/simple.crt-list ${testdir}/common.pem:1"
+ expect ~ "Entry '${testdir}/common.pem' deleted in crtlist '${testdir}/simple.crt-list'!"
+}
diff --git a/reg-tests/ssl/dynamic_server_ssl.vtc b/reg-tests/ssl/dynamic_server_ssl.vtc
new file mode 100644
index 0000000..b7730f5
--- /dev/null
+++ b/reg-tests/ssl/dynamic_server_ssl.vtc
@@ -0,0 +1,113 @@
+#REGTEST_TYPE=bug
+# Test if a certificate can be dynamically updated once a server which used it
+# was removed.
+#
+varnishtest "Delete server via cli and update certificates"
+
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.4
+#REQUIRE_OPTIONS=OPENSSL
+feature cmd "command -v socat"
+
+# static server
+server s1 -repeat 3 {
+ rxreq
+ txresp \
+ -body "resp from s1"
+} -start
+
+haproxy h1 -conf {
+ global
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httpclose
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe
+ bind "fd@${feS}"
+ default_backend test
+
+ backend test
+ server s1 "${tmpdir}/ssl.sock" ssl verify none crt "${testdir}/client1.pem"
+ server s2 "${tmpdir}/ssl.sock" ssl verify none crt "${testdir}/client1.pem"
+ server s3 "${tmpdir}/ssl.sock" ssl verify none crt "${testdir}/client1.pem"
+
+
+ listen ssl-lst
+ bind "${tmpdir}/ssl.sock" ssl crt "${testdir}/common.pem"
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/client1.pem"
+ expect ~ ".*SHA1 FingerPrint: D9C3BAE37EA5A7EDB7B3C9BDD4DCB2FE58A412E4"
+}
+client c1 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.body == "resp from s1"
+} -run
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/client1.pem"
+ expect ~ ".*SHA1 FingerPrint: D9C3BAE37EA5A7EDB7B3C9BDD4DCB2FE58A412E4"
+}
+
+## delete the servers
+haproxy h1 -cli {
+ send "disable server test/s1"
+ expect ~ ".*"
+ send "disable server test/s2"
+ expect ~ ".*"
+ send "disable server test/s3"
+ expect ~ ".*"
+
+ # valid command
+ send "del server test/s1"
+ expect ~ "Server deleted."
+ send "del server test/s2"
+ expect ~ "Server deleted."
+ send "del server test/s3"
+ expect ~ "Server deleted."
+}
+
+# Replace certificate with an expired one
+shell {
+ printf "set ssl cert ${testdir}/client1.pem <<\n$(cat ${testdir}/client2_expired.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/client1.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/client1.pem"
+ expect ~ ".*SHA1 FingerPrint: C625EB01A0A660294B9D7F44C5CEEE5AFC495BE4"
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/client1.pem"
+ expect ~ ".*Status: Unused"
+}
+
+haproxy h1 -cli {
+ send "add server test/s1 ${tmpdir}/ssl.sock ssl verify none crt ${testdir}/client1.pem"
+ expect ~ "New server registered."
+ send "enable server test/s1"
+ expect ~ ".*"
+ send "show ssl cert ${testdir}/client1.pem"
+ expect ~ ".*Status: Used"
+}
+
+
+# check that servers are active
+client c1 -connect ${h1_feS_sock} {
+ txreq
+ rxresp
+ expect resp.body == "resp from s1"
+} -run
+
diff --git a/reg-tests/ssl/ecdsa.crt b/reg-tests/ssl/ecdsa.crt
new file mode 100644
index 0000000..27b5f5d
--- /dev/null
+++ b/reg-tests/ssl/ecdsa.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBfzCCAQWgAwIBAgIUYDgleyiLJSKbSWzlU3PTCB/PPYIwCgYIKoZIzj0EAwIw
+FDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MTIxOTA5MzExMloXDTIwMDExODA5
+MzExMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MHYwEAYHKoZIzj0CAQYFK4EEACID
+YgAEHNNG/ZSuS7CXvL03ye/Y+LpWnX818mnYkxqUQdFO2N1CO0p6kSIMHrzMQIRe
+v3+j2g6drKehMGjBmeZJwsbD6nYyUO1z+0MatW5UiTMWFmPq4v08TDDtd8sNcWgs
+SWrToxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDaAAwZQIw
+N2BdTJOH3BZlJ7HRIJNRC7jjByI9+QYAHiBoXmJVi9aoKd7OIz1Nb2DPe3QS1sDw
+AjEA9KzI8BVIZJEmsVA6rs+vRjX0tUfBhD7BCHKas0roOny9Smj/TkBFxVTNnjzM
+8iLn
+-----END CERTIFICATE-----
+
diff --git a/reg-tests/ssl/ecdsa.key b/reg-tests/ssl/ecdsa.key
new file mode 100644
index 0000000..6eec0ec
--- /dev/null
+++ b/reg-tests/ssl/ecdsa.key
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDZMkuztqaUgCAC9/7P
+CsmlC2ac7rWerq5+NKbP0Cz1+mao6+F5Hc8DKNXHgi5GPr2hZANiAAQc00b9lK5L
+sJe8vTfJ79j4uladfzXyadiTGpRB0U7Y3UI7SnqRIgwevMxAhF6/f6PaDp2sp6Ew
+aMGZ5knCxsPqdjJQ7XP7Qxq1blSJMxYWY+ri/TxMMO13yw1xaCxJatM=
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/ecdsa.pem b/reg-tests/ssl/ecdsa.pem
new file mode 100644
index 0000000..e737689
--- /dev/null
+++ b/reg-tests/ssl/ecdsa.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIIBfzCCAQWgAwIBAgIUYDgleyiLJSKbSWzlU3PTCB/PPYIwCgYIKoZIzj0EAwIw
+FDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MTIxOTA5MzExMloXDTIwMDExODA5
+MzExMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MHYwEAYHKoZIzj0CAQYFK4EEACID
+YgAEHNNG/ZSuS7CXvL03ye/Y+LpWnX818mnYkxqUQdFO2N1CO0p6kSIMHrzMQIRe
+v3+j2g6drKehMGjBmeZJwsbD6nYyUO1z+0MatW5UiTMWFmPq4v08TDDtd8sNcWgs
+SWrToxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDaAAwZQIw
+N2BdTJOH3BZlJ7HRIJNRC7jjByI9+QYAHiBoXmJVi9aoKd7OIz1Nb2DPe3QS1sDw
+AjEA9KzI8BVIZJEmsVA6rs+vRjX0tUfBhD7BCHKas0roOny9Smj/TkBFxVTNnjzM
+8iLn
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDZMkuztqaUgCAC9/7P
+CsmlC2ac7rWerq5+NKbP0Cz1+mao6+F5Hc8DKNXHgi5GPr2hZANiAAQc00b9lK5L
+sJe8vTfJ79j4uladfzXyadiTGpRB0U7Y3UI7SnqRIgwevMxAhF6/f6PaDp2sp6Ew
+aMGZ5knCxsPqdjJQ7XP7Qxq1blSJMxYWY+ri/TxMMO13yw1xaCxJatM=
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/filters.crt-list b/reg-tests/ssl/filters.crt-list
new file mode 100644
index 0000000..e72ee0b
--- /dev/null
+++ b/reg-tests/ssl/filters.crt-list
@@ -0,0 +1,2 @@
+common.pem *.bug810.domain.tld record.bug810.domain.tld *.bug818.domain.tld !another-record.bug818.domain.tld
+ecdsa.pem record.bug810.domain.tld another-record.bug810.domain.tld *.bug818.domain.tld
diff --git a/reg-tests/ssl/generate_certificates/gen_cert_ca.pem b/reg-tests/ssl/generate_certificates/gen_cert_ca.pem
new file mode 100644
index 0000000..1aae9a7
--- /dev/null
+++ b/reg-tests/ssl/generate_certificates/gen_cert_ca.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIICOjCCAcCgAwIBAgIUf+VQOeilN1b1jiOroaMItFRozf8wCgYIKoZIzj0EAwIw
+VDELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3RhdGUxHTAbBgNVBAoMFEhB
+UHJveHkgVGVjaG5vbG9naWVzMREwDwYDVQQDDAhFQ0RTQSBDQTAeFw0yMjAxMTIx
+NDAzNTlaFw00OTA1MzAxNDAzNTlaMFQxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApT
+b21lLVN0YXRlMR0wGwYDVQQKDBRIQVByb3h5IFRlY2hub2xvZ2llczERMA8GA1UE
+AwwIRUNEU0EgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARyx1wAgb1/fuAflF73
+j3Z1intP7+11kGtVZ1EAKd//xqtxFuJ+98/gc5cpiOBMWcn6FyEZ+GShTpQeqsFs
+2C4k0LTtKadXwuQaIs05QMpahTN2vmc6LPgzOrEJxFafjdejUzBRMB0GA1UdDgQW
+BBTX2Q6ojJB88kEKjdnoufDv8TGphzAfBgNVHSMEGDAWgBTX2Q6ojJB88kEKjdno
+ufDv8TGphzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA2gAMGUCMQCLVP3+
+dvfS2k6GYplmmkyC7YVlmNre5gZwIE9zYDDvKDxsS95oqXLT5dTVm9W0MhACMAgB
+D9uOlqoGaHbRGBE8wlV33bVdpzD6JEqVyGCdEtdCW4T5Vsg3pAsUiG2tPWQ2LA==
+-----END CERTIFICATE-----
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDDosJpJuqxVdp/wuJYM1k2OTK8Pri+ChDRVlDySnHYP92aFT0GXX8A5
+X5rLNDtbaCGgBwYFK4EEACKhZANiAARyx1wAgb1/fuAflF73j3Z1intP7+11kGtV
+Z1EAKd//xqtxFuJ+98/gc5cpiOBMWcn6FyEZ+GShTpQeqsFs2C4k0LTtKadXwuQa
+Is05QMpahTN2vmc6LPgzOrEJxFafjdc=
+-----END EC PRIVATE KEY-----
diff --git a/reg-tests/ssl/generate_certificates/gen_cert_server.pem b/reg-tests/ssl/generate_certificates/gen_cert_server.pem
new file mode 100644
index 0000000..ce2f621
--- /dev/null
+++ b/reg-tests/ssl/generate_certificates/gen_cert_server.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIBujCCAV8CAQEwCgYIKoZIzj0EAwIwWDELMAkGA1UEBhMCRlIxEzARBgNVBAgM
+ClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDER
+MA8GA1UEAwwIRUNEU0EgQ0EwHhcNMjIwMjA4MTU0MjMxWhcNNDkwNjI2MTU0MjMx
+WjBcMQswCQYDVQQGEwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTEdMBsGA1UECgwU
+SEFQcm94eSBUZWNobm9sb2dpZXMxGTAXBgNVBAMMEHNlcnZlci5lY2RzYS5jb20w
+djAQBgcqhkjOPQIBBgUrgQQAIgNiAARXlODrnr208aoToRb8MqTp4GYgnk9V4LJ5
+XE8HyM7EWbqx46PdUpLUseFOtF/Yr9nyzMcdd6GNZrHkgM2NaQ/13tTbLJ84wXRQ
+jS9FSqFmDmmgbEARiyEf0K8D9lxI0bgwCgYIKoZIzj0EAwIDSQAwRgIhAJlwV5oJ
+Uz4nYUEWIrgFd7de5GZseFBIbW+UWr17Ip6gAiEAhrVEpmd4Tl5JPTwQznPa6ZlJ
+Zc8S6ipcwXPCJzsSOnQ=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDD6ONh7kiRD6TxwQGIa
+bY5kUclHcPXiWO1QNscmeVtObmTKYiVcRR+Mj4tNRXWH6lyhZANiAARXlODrnr20
+8aoToRb8MqTp4GYgnk9V4LJ5XE8HyM7EWbqx46PdUpLUseFOtF/Yr9nyzMcdd6GN
+ZrHkgM2NaQ/13tTbLJ84wXRQjS9FSqFmDmmgbEARiyEf0K8D9lxI0bg=
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/interCA1_crl.pem b/reg-tests/ssl/interCA1_crl.pem
new file mode 100644
index 0000000..b4b8b03
--- /dev/null
+++ b/reg-tests/ssl/interCA1_crl.pem
@@ -0,0 +1,27 @@
+-----BEGIN X509 CRL-----
+MIIBpDCBjTANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQGEwJGUjEdMBsGA1UECgwU
+SEFQcm94eSBUZWNobm9sb2dpZXMxGTAXBgNVBAMMEEludGVybWVkaWF0ZSBDQTEX
+DTIxMDQyMzE0MzYyNloXDTQ4MDkwODE0MzYyNlowFTATAgIQBxcNMjEwNDIzMTQz
+NjE1WjANBgkqhkiG9w0BAQsFAAOCAQEAi9NKPoPVgYo68ZvTJP2STnFLk71bLoB/
+PbQsM7gpJvgStmLs2lVpSxL2y5CUEG8Ok73yNkQIcOZq9DAXVL/49QHXQOZ0pPMD
+XbUn5py3mEQfuuM46n3wPP8lDgbfbDMPxs2yDf7FZKQQpxBVBq9H3m+nc3RIPP9B
+3kDvYuo3PeRlqkzIdP9ceEfBGY8+cOfvPHFzLl+BEeUI2dhhdRxtWUrfPXfLXSks
+TWp0hgu9vFHguuV3mZGcxzxvdRTsq/vu0rxg2aqGOVJyNhshRn14Tt7z9uQty4Qr
+vrkvpoKVzq93bI6ITRzXlgKKzXK70wGm8tAfbioNostRJ6/gcjaWAg==
+-----END X509 CRL-----
+-----BEGIN X509 CRL-----
+MIICgzBtMA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNVBAYTAkZSMR0wGwYDVQQKDBRI
+QVByb3h5IFRlY2hub2xvZ2llczEQMA4GA1UEAwwHUm9vdCBDQRcNMjEwNDIzMTQz
+MDQ0WhcNNDgwOTA4MTQzMDQ0WjANBgkqhkiG9w0BAQsFAAOCAgEAa39JkwPzmyPc
+1SY8HfJjrkvvaIO4qV/lMUzYjg6yxuTw6g7hoH0fyxK+2+RCoplXwFS7NTDG+jS1
+H3sZWvTg/aY3g4SRudJGSxeqT2a43+U4QjmTm8uClXAA7tuOcz+wSXP7sDGQ0kyg
+PCQGGmiOL5Q2lpziVRuWTHVmUkH48Na7Lyeq5cCry2AwAPjUQtcUiivuASjhUGXh
+Gya8gPV5MXNVq5T2WcZWJnkMGbWLvSFAm5POX1i8c3o2rlIjoYws/VAwOi6wqe9K
+NGNNUUXbOhyqocbzhZvWreyNUx63Pk4TxAAHwSn7H7fJe0yzfqjbZRF3KHCBPRbB
+NBOCYr5YKH6i1xQbrEGzj8+jrXWVvpYF0FXkjzO78I5c366HXPwBCPEsoIYlgjBN
++AqgiyB7xGWiRa2SZVPn+j6wHWdohar6zw4UIBLS7EIjvb/RAM6SduScIbc9l+0I
+VrciCgPScQXbkxLoh0sVBPdfR0cU08JNG+eZ8gUNce8PKdWO2mnFSNiaEz6ESgRn
+0j7q+s4V15LX/vkKyA6u2JTYZCJi23DDBzZp57sgXsQwzp50lkoFmNNASXdURJL3
+60PvFGxzBDgOUhq4yTRbz945SF3jwF9CEl9kFOffOHigwrcbKS0Cib2ac+IpXYrE
+BCm2lSjFCK0p/mAgK8yiNQFKnCAgsXU=
+-----END X509 CRL-----
diff --git a/reg-tests/ssl/interCA1_crl_empty.pem b/reg-tests/ssl/interCA1_crl_empty.pem
new file mode 100644
index 0000000..ce9e0f4
--- /dev/null
+++ b/reg-tests/ssl/interCA1_crl_empty.pem
@@ -0,0 +1,27 @@
+-----BEGIN X509 CRL-----
+MIIBjDB2MA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNVBAYTAkZSMR0wGwYDVQQKDBRI
+QVByb3h5IFRlY2hub2xvZ2llczEZMBcGA1UEAwwQSW50ZXJtZWRpYXRlIENBMRcN
+MjEwNDIzMTQzNDI3WhcNNDgwOTA4MTQzNDI3WjANBgkqhkiG9w0BAQsFAAOCAQEA
+As2A6ys84+wpG7vpjDnxD1Pri45M3sxn9Wb0v7kLBV1AsRADE6bquKYH73pUwsQB
+FmfpgE6KfagM5d/1Pap9rV0PuMc3n8Uc0Q1c30AhHELlzObEzVVeT2WTHBm5XPWn
++jY5eijsWp9NCivDwzCXP/dEXxjXPtO0l4Mctq1vv5c1Ipq9FczpfDiJJMFh7Pxy
+uVDhsnfx6uel851NxA5h2US0tQLbL/50t6vtdAgWaQdUprQwFc9oLStePbLEzT43
+zOQh7DIx0hZltd0p+OqQnfZFR0P/TlLLMGE/HZSzNi0L7WOwuG3MtrFzJwV/wqT+
+AH08jXjU5Pc3XThatlTvGA==
+-----END X509 CRL-----
+-----BEGIN X509 CRL-----
+MIICgzBtMA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNVBAYTAkZSMR0wGwYDVQQKDBRI
+QVByb3h5IFRlY2hub2xvZ2llczEQMA4GA1UEAwwHUm9vdCBDQRcNMjEwNDIzMTQz
+MDQ0WhcNNDgwOTA4MTQzMDQ0WjANBgkqhkiG9w0BAQsFAAOCAgEAa39JkwPzmyPc
+1SY8HfJjrkvvaIO4qV/lMUzYjg6yxuTw6g7hoH0fyxK+2+RCoplXwFS7NTDG+jS1
+H3sZWvTg/aY3g4SRudJGSxeqT2a43+U4QjmTm8uClXAA7tuOcz+wSXP7sDGQ0kyg
+PCQGGmiOL5Q2lpziVRuWTHVmUkH48Na7Lyeq5cCry2AwAPjUQtcUiivuASjhUGXh
+Gya8gPV5MXNVq5T2WcZWJnkMGbWLvSFAm5POX1i8c3o2rlIjoYws/VAwOi6wqe9K
+NGNNUUXbOhyqocbzhZvWreyNUx63Pk4TxAAHwSn7H7fJe0yzfqjbZRF3KHCBPRbB
+NBOCYr5YKH6i1xQbrEGzj8+jrXWVvpYF0FXkjzO78I5c366HXPwBCPEsoIYlgjBN
++AqgiyB7xGWiRa2SZVPn+j6wHWdohar6zw4UIBLS7EIjvb/RAM6SduScIbc9l+0I
+VrciCgPScQXbkxLoh0sVBPdfR0cU08JNG+eZ8gUNce8PKdWO2mnFSNiaEz6ESgRn
+0j7q+s4V15LX/vkKyA6u2JTYZCJi23DDBzZp57sgXsQwzp50lkoFmNNASXdURJL3
+60PvFGxzBDgOUhq4yTRbz945SF3jwF9CEl9kFOffOHigwrcbKS0Cib2ac+IpXYrE
+BCm2lSjFCK0p/mAgK8yiNQFKnCAgsXU=
+-----END X509 CRL-----
diff --git a/reg-tests/ssl/interCA2_crl.pem b/reg-tests/ssl/interCA2_crl.pem
new file mode 100644
index 0000000..798096c
--- /dev/null
+++ b/reg-tests/ssl/interCA2_crl.pem
@@ -0,0 +1,27 @@
+-----BEGIN X509 CRL-----
+MIIBpDCBjTANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQGEwJGUjEdMBsGA1UECgwU
+SEFQcm94eSBUZWNobm9sb2dpZXMxGTAXBgNVBAMMEEludGVybWVkaWF0ZSBDQTIX
+DTIxMDQyMzE0NDUzOVoXDTQ4MDkwODE0NDUzOVowFTATAgIQCBcNMjEwNDIzMTQ0
+NTM2WjANBgkqhkiG9w0BAQsFAAOCAQEAdD35Sf47YUxG6GXiMsT4jFY0hXWgc8QS
+vR6gx6MQkWFV973ALVe1bfIXBGLZ2bTU/IppFUEJxVtyXyMCJIIpdYHirF1Y7kTi
+DLVuWE4I0ZnDSF4LI5g73dYciKeVCq+ZvKx2dZ7Y37pKqNYvhVwp+HwtB4536XvQ
+m7WjFYJFFR71gAscGky621XiRflQoGvpCOVRiJxFQFYRWRA+eR+vjQ4NTYvotDKe
+O9ejZNEpfTeil+wxi5h38GVIBa2aocMVLIu5o0EQGg8d0SEU46rJKowaUz7kESuf
+Al4jnmsb1W8LSD9Agp4GQE8pV2d42kXwpWk/JrUovHRPV2vy5PQuGA==
+-----END X509 CRL-----
+-----BEGIN X509 CRL-----
+MIICgzBtMA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNVBAYTAkZSMR0wGwYDVQQKDBRI
+QVByb3h5IFRlY2hub2xvZ2llczEQMA4GA1UEAwwHUm9vdCBDQRcNMjEwNDIzMTQz
+MDQ0WhcNNDgwOTA4MTQzMDQ0WjANBgkqhkiG9w0BAQsFAAOCAgEAa39JkwPzmyPc
+1SY8HfJjrkvvaIO4qV/lMUzYjg6yxuTw6g7hoH0fyxK+2+RCoplXwFS7NTDG+jS1
+H3sZWvTg/aY3g4SRudJGSxeqT2a43+U4QjmTm8uClXAA7tuOcz+wSXP7sDGQ0kyg
+PCQGGmiOL5Q2lpziVRuWTHVmUkH48Na7Lyeq5cCry2AwAPjUQtcUiivuASjhUGXh
+Gya8gPV5MXNVq5T2WcZWJnkMGbWLvSFAm5POX1i8c3o2rlIjoYws/VAwOi6wqe9K
+NGNNUUXbOhyqocbzhZvWreyNUx63Pk4TxAAHwSn7H7fJe0yzfqjbZRF3KHCBPRbB
+NBOCYr5YKH6i1xQbrEGzj8+jrXWVvpYF0FXkjzO78I5c366HXPwBCPEsoIYlgjBN
++AqgiyB7xGWiRa2SZVPn+j6wHWdohar6zw4UIBLS7EIjvb/RAM6SduScIbc9l+0I
+VrciCgPScQXbkxLoh0sVBPdfR0cU08JNG+eZ8gUNce8PKdWO2mnFSNiaEz6ESgRn
+0j7q+s4V15LX/vkKyA6u2JTYZCJi23DDBzZp57sgXsQwzp50lkoFmNNASXdURJL3
+60PvFGxzBDgOUhq4yTRbz945SF3jwF9CEl9kFOffOHigwrcbKS0Cib2ac+IpXYrE
+BCm2lSjFCK0p/mAgK8yiNQFKnCAgsXU=
+-----END X509 CRL-----
diff --git a/reg-tests/ssl/interCA2_crl_empty.pem b/reg-tests/ssl/interCA2_crl_empty.pem
new file mode 100644
index 0000000..175528b
--- /dev/null
+++ b/reg-tests/ssl/interCA2_crl_empty.pem
@@ -0,0 +1,27 @@
+-----BEGIN X509 CRL-----
+MIIBjDB2MA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNVBAYTAkZSMR0wGwYDVQQKDBRI
+QVByb3h5IFRlY2hub2xvZ2llczEZMBcGA1UEAwwQSW50ZXJtZWRpYXRlIENBMhcN
+MjEwNDIzMTQ0NTE2WhcNNDgwOTA4MTQ0NTE2WjANBgkqhkiG9w0BAQsFAAOCAQEA
+IriCgDMzPowZl99/LoDW42xKFL5Db9mdPPNMY1Xk/6BowIhugz2vP5z38Ryfxy8B
+f1IFaGSf6Twl+F1RHv8twHMi4Vf8hbzPG4PRoEhy0gvzbD8YBtaV/GPyJY8iQt2o
+nuecskDhRp/D2YU5GXy90BMwBfH89yGPW4fUpFn3/83fZ1hhvkewTQedcLihxWGC
+KPuuWyrIN8qw/VKLARlXoFPIqyEdqttJliR1/GHej5iY1msMCftUQpC5sowse3B7
+F2oNySIPxm4jZ+QBrtMNbY7E1EHDBjcLInAfY17fKs6P0HytInBOhpeqz3Jcft2i
+b3qzM/7Ac5k6KPXs/UplMg==
+-----END X509 CRL-----
+-----BEGIN X509 CRL-----
+MIICgzBtMA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNVBAYTAkZSMR0wGwYDVQQKDBRI
+QVByb3h5IFRlY2hub2xvZ2llczEQMA4GA1UEAwwHUm9vdCBDQRcNMjEwNDIzMTQz
+MDQ0WhcNNDgwOTA4MTQzMDQ0WjANBgkqhkiG9w0BAQsFAAOCAgEAa39JkwPzmyPc
+1SY8HfJjrkvvaIO4qV/lMUzYjg6yxuTw6g7hoH0fyxK+2+RCoplXwFS7NTDG+jS1
+H3sZWvTg/aY3g4SRudJGSxeqT2a43+U4QjmTm8uClXAA7tuOcz+wSXP7sDGQ0kyg
+PCQGGmiOL5Q2lpziVRuWTHVmUkH48Na7Lyeq5cCry2AwAPjUQtcUiivuASjhUGXh
+Gya8gPV5MXNVq5T2WcZWJnkMGbWLvSFAm5POX1i8c3o2rlIjoYws/VAwOi6wqe9K
+NGNNUUXbOhyqocbzhZvWreyNUx63Pk4TxAAHwSn7H7fJe0yzfqjbZRF3KHCBPRbB
+NBOCYr5YKH6i1xQbrEGzj8+jrXWVvpYF0FXkjzO78I5c366HXPwBCPEsoIYlgjBN
++AqgiyB7xGWiRa2SZVPn+j6wHWdohar6zw4UIBLS7EIjvb/RAM6SduScIbc9l+0I
+VrciCgPScQXbkxLoh0sVBPdfR0cU08JNG+eZ8gUNce8PKdWO2mnFSNiaEz6ESgRn
+0j7q+s4V15LX/vkKyA6u2JTYZCJi23DDBzZp57sgXsQwzp50lkoFmNNASXdURJL3
+60PvFGxzBDgOUhq4yTRbz945SF3jwF9CEl9kFOffOHigwrcbKS0Cib2ac+IpXYrE
+BCm2lSjFCK0p/mAgK8yiNQFKnCAgsXU=
+-----END X509 CRL-----
diff --git a/reg-tests/ssl/localhost.crt-list b/reg-tests/ssl/localhost.crt-list
new file mode 100644
index 0000000..a0d9756
--- /dev/null
+++ b/reg-tests/ssl/localhost.crt-list
@@ -0,0 +1,5 @@
+common.pem !not.test1.com *.test1.com !localhost # comment
+
+
+ common.pem !not.test1.com *.test1.com !localhost
+# comment
diff --git a/reg-tests/ssl/log_forward_ssl.vtc b/reg-tests/ssl/log_forward_ssl.vtc
new file mode 100644
index 0000000..6b7515b
--- /dev/null
+++ b/reg-tests/ssl/log_forward_ssl.vtc
@@ -0,0 +1,60 @@
+varnishtest "Test the TCP+SSL load-forward"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.3-dev1)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -repeat 500 -start
+
+syslog Slg1 -level info {
+ recv
+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c1 HTTP/1.1\""
+} -repeat 50 -start
+
+haproxy h1 -conf {
+ global
+ insecure-fork-wanted
+ defaults
+ mode http
+ option httplog
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend fe1
+ bind "fd@${fe_1}"
+ log 127.0.0.1:1514 local0
+# log ${Slg1_addr}:${Slg1_port} local0
+ default_backend be
+
+ backend be
+ server app1 ${s1_addr}:${s1_port}
+
+ ring myring
+ description "My local buffer"
+ format rfc5424
+ maxlen 1200
+ size 32764
+ timeout connect 5s
+ timeout server 10s
+ # syslog tcp server
+ server mysyslogsrv 127.0.0.1:2514 ssl verify none
+
+ log-forward syslog2tcp
+ dgram-bind 127.0.0.1:1514
+ log ring@myring local0 # To TCP log
+
+ log-forward syslog2local
+ bind 127.0.0.1:2514 ssl crt ${testdir}/common.pem
+ log ${Slg1_addr}:${Slg1_port} local0 # To VTest syslog
+} -start
+
+client c1 -connect ${h1_fe_1_sock} {
+ txreq -url "/client_c1"
+ rxresp
+ expect resp.status == 200
+} -repeat 50 -start
+
+syslog Slg1 -wait
diff --git a/reg-tests/ssl/new_del_ssl_cafile.vtc b/reg-tests/ssl/new_del_ssl_cafile.vtc
new file mode 100644
index 0000000..2123fb0
--- /dev/null
+++ b/reg-tests/ssl/new_del_ssl_cafile.vtc
@@ -0,0 +1,157 @@
+#REGTEST_TYPE=devel
+
+# This test uses the "new ssl ca-file" and "del ssl ca-file" commands to create
+# a new CA file or delete an unused CA file.
+#
+# It requires socat to upload the CA file.
+#
+# If this test does not work anymore:
+# - Check that you have socat
+
+varnishtest "Test the 'new ssl ca-file' and 'del ssl ca-file' commands of the CLI"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 2 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+ crt-base ${testdir}
+
+ defaults
+ mode http
+ option httplog
+ retries 0
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ use_backend with_ca_be if { path /with-ca }
+ default_backend default_be
+
+ backend default_be
+ server s1 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/set_cafile_client.pem sni str(www.test1.com)
+
+ backend with_ca_be
+ server s1 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/set_cafile_client.pem sni str(with-ca.com)
+
+ listen ssl-lst
+ bind "${tmpdir}/ssl.sock" ssl strict-sni crt-list ${testdir}/localhost.crt-list ca-verify-file ${testdir}/set_cafile_rootCA.crt ca-file ${testdir}/set_cafile_interCA2.crt verify required crt-ignore-err all
+ http-response add-header X-SSL-Client-Verify %[ssl_c_verify]
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+# Request using the default backend and the www.test1.com sni
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ # The CA file known by the frontend does not allow to verify the client's certificate
+ expect resp.http.X-SSL-Client-Verify ~ "20|21"
+} -run
+
+# This connection should fail because the with-ca.com sni is not mentioned in the crt-list yet.
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/with-ca"
+ rxresp
+ expect resp.status == 503
+} -run
+
+# Create a new unlinked CA file
+haproxy h1 -cli {
+ send "new ssl ca-file new_cafile.crt"
+ expect ~ "New CA file created 'new_cafile.crt'!"
+}
+
+shell {
+ printf "set ssl ca-file new_cafile.crt <<\n$(cat ${testdir}/set_cafile_interCA1.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file new_cafile.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+# Remove the unliked CA file and create a new one with the "add ssl ca-file method"
+
+haproxy h1 -cli {
+ send "del ssl ca-file new_cafile.crt"
+ expect ~ "CA file 'new_cafile.crt' deleted!"
+
+ send "new ssl ca-file new_cafile.crt"
+ expect ~ "New CA file created 'new_cafile.crt'!"
+}
+
+shell {
+ printf "add ssl ca-file new_cafile.crt <<\n$(cat ${testdir}/set_cafile_interCA1.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file new_cafile.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+shell {
+ printf "set ssl ca-file new_cafile.crt <<\n$(cat ${testdir}/set_cafile_interCA1.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file new_cafile.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl ca-file"
+ expect ~ ".*new_cafile.crt - 1 certificate.*"
+
+ send "show ssl ca-file new_cafile.crt"
+ expect ~ ".*SHA1 FingerPrint: 4FFF535278883264693CEA72C4FAD13F995D0098"
+}
+
+# The new CA file is still not linked anywhere so the request should fail.
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/with-ca"
+ rxresp
+ expect resp.status == 503
+} -run
+
+# Add a new certificate that will use the new CA file
+shell {
+ echo "new ssl cert ${testdir}/set_cafile_server.pem" | socat "${tmpdir}/h1/stats" -
+ printf "set ssl cert ${testdir}/set_cafile_server.pem <<\n$(cat ${testdir}/set_cafile_server.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/set_cafile_server.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+# Create a new crt-list line that will use the new CA file
+shell {
+ printf "add ssl crt-list ${testdir}/localhost.crt-list <<\n${testdir}/set_cafile_server.pem [ca-file new_cafile.crt] with-ca.com\n\n" | socat "${tmpdir}/h1/stats" -
+}
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/with-ca"
+ rxresp
+ expect resp.status == 200
+ # Thanks to the newly added CA file, the client's certificate can be verified
+ expect resp.http.X-SSL-Client-Verify == 0
+} -run
+
+# Delete the newly added crt-list line and CA file
+haproxy h1 -cli {
+ send "del ssl crt-list ${testdir}/localhost.crt-list ${testdir}/set_cafile_server.pem"
+ expect ~ "Entry '${testdir}/set_cafile_server.pem' deleted in crtlist '${testdir}/localhost.crt-list'!"
+
+ send "del ssl ca-file new_cafile.crt"
+ expect ~ "CA file 'new_cafile.crt' deleted!"
+
+ send "show ssl ca-file"
+ expect !~ "new_cafile.crt"
+}
+
+# The connection should now fail since the crt-list line was deleted
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/with-ca"
+ rxresp
+ expect resp.status == 503
+} -run
+
diff --git a/reg-tests/ssl/new_del_ssl_crlfile.vtc b/reg-tests/ssl/new_del_ssl_crlfile.vtc
new file mode 100644
index 0000000..8658a1a
--- /dev/null
+++ b/reg-tests/ssl/new_del_ssl_crlfile.vtc
@@ -0,0 +1,139 @@
+#REGTEST_TYPE=devel
+
+# This test uses the "new ssl crl-file" and "del ssl crl-file" commands to create
+# a new CRL file or delete an unused CRL file.
+#
+# It requires socat to upload the CRL file.
+#
+# If this test does not work anymore:
+# - Check that you have socat
+
+varnishtest "Test the 'new ssl crl-file' and 'del ssl crl-file' commands of the CLI"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+ crt-base ${testdir}
+
+ defaults
+ mode http
+ option httplog
+ retries 0
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ use_backend with_crl_be if { path /with-crl }
+ default_backend default_be
+
+ backend default_be
+ server s1 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/client3_revoked.pem sni str(www.test1.com)
+
+ backend with_crl_be
+ server s1 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/client3_revoked.pem sni str(with-crl.com)
+
+ listen ssl-lst
+ bind "${tmpdir}/ssl.sock" ssl strict-sni crt-list ${testdir}/localhost.crt-list ca-file ${testdir}/ca-auth.crt verify required crt-ignore-err all
+ http-response add-header X-SSL-Client-Verify %[ssl_c_verify]
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+# Request using the default backend and the www.test1.com sni
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ # The backend has no CRL so the connection should succeed
+ expect resp.http.X-SSL-Client-Verify == 0
+} -run
+
+# This connection should fail because the with-crl.com sni is not mentioned in the crt-list yet.
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/with-crl"
+ rxresp
+ expect resp.status == 503
+} -run
+
+# Create a new unlinked CRL file
+haproxy h1 -cli {
+ send "new ssl crl-file new_crlfile.crt"
+ expect ~ "New CRL file created 'new_crlfile.crt'!"
+}
+
+shell {
+ printf "set ssl crl-file new_crlfile.crt <<\n$(cat ${testdir}/crl-auth.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl crl-file new_crlfile.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl crl-file"
+ expect ~ ".*new_crlfile.crt"
+
+ send "show ssl crl-file new_crlfile.crt"
+ expect ~ ".*Issuer:.*/CN=HAProxy Technologies CA Test Client Auth"
+}
+
+# Add a new certificate that will use the new CA file
+shell {
+ echo "new ssl cert ${testdir}/set_cafile_server.pem" | socat "${tmpdir}/h1/stats" -
+ printf "set ssl cert ${testdir}/set_cafile_server.pem <<\n$(cat ${testdir}/set_cafile_server.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/set_cafile_server.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+# Create a new crt-list line that will use the new CA file
+shell {
+ printf "add ssl crt-list ${testdir}/localhost.crt-list <<\n${testdir}/set_cafile_server.pem [crl-file new_crlfile.crt] with-crl.com\n\n" | socat "${tmpdir}/h1/stats" -
+}
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/with-crl"
+ rxresp
+ expect resp.status == 200
+ # The frontend's certificate is revoked in the newly added CRL, connection should fail
+ expect resp.http.X-SSL-Client-Verify == 23
+} -run
+
+# Request using the default backend and the www.test1.com sni
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ # The backend has no CRL for this SNI so the connection should still succeed
+ expect resp.http.X-SSL-Client-Verify == 0
+} -run
+
+# Delete the newly added crt-list line and CRL file
+haproxy h1 -cli {
+ send "del ssl crt-list ${testdir}/localhost.crt-list ${testdir}/set_cafile_server.pem"
+ expect ~ "Entry '${testdir}/set_cafile_server.pem' deleted in crtlist '${testdir}/localhost.crt-list'!"
+
+ send "del ssl crl-file new_crlfile.crt"
+ expect ~ "CRL file 'new_crlfile.crt' deleted!"
+
+ send "show ssl crl-file"
+ expect !~ "new_crlfile.crt"
+}
+
+# The connection should now fail since the crt-list line was deleted
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/with-crl"
+ rxresp
+ expect resp.status == 503
+} -run
+
diff --git a/reg-tests/ssl/ocsp_auto_update.vtc b/reg-tests/ssl/ocsp_auto_update.vtc
new file mode 100644
index 0000000..2ab4a4a
--- /dev/null
+++ b/reg-tests/ssl/ocsp_auto_update.vtc
@@ -0,0 +1,718 @@
+#REGTEST_TYPE=slow
+
+# broken with BoringSSL.
+
+# This reg-test focuses on the OCSP response auto-update functionality. It does
+# not test the full scope of the feature because most of it is based on
+# expiration times and long delays between updates of valid OCSP responses.
+# Automatic update of valid OCSP responses loaded during init will not be
+# tested because by design, such a response would no be automatically updated
+# until init+1H.
+#
+# This test will then focus on certificates that have a specified OCSP URI but
+# no known OCSP response. For those certificates, OCSP requests are sent as
+# soon as possible by the update task.
+#
+# The ocsp responder used in all the tests will be an openssl using the
+# certificate database in ocsp_update/index.txt. It will listen on port 12346
+# which is not the same as the one specified in the certificates' OCSP URI
+# which point to port 12345. The link from port 12345 to port 12346 will be
+# ensured through HAProxy instances that will enable logs, later used as a
+# synchronization mean.
+#
+# Unfortunately some arbitrary "sleep" calls are still needed to leave some
+# time for the ocsp update task to actually process the ocsp responses and
+# reinsert them into the tree. This explains why the test's mode is set to
+# "slow".
+#
+# The fourth test case focuses on the "update ssl ocsp-response" CLI command
+# and tests two certificates that have a known OCSP response loaded during init
+# but no OCSP auto update. The only difference between the two certificates is
+# that one has a separate .issuer file while the other one has the issuer
+# certificate directly in the main .pem file.
+#
+# If this test does not work anymore:
+# - Check that you have openssl and socat
+
+varnishtest "Test the OCSP auto update feature"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.7-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && !ssllib_name_startswith(BoringSSL) && openssl_version_atleast(1.1.1)'"
+feature cmd "command -v openssl && command -v socat"
+feature ignore_unknown_macro
+
+
+###################
+# #
+# FIRST TEST CASE #
+# #
+###################
+
+# No automatic update should occur in this test case since we load two already
+# valid OCSP responses during init which have a "Next Update" date really far
+# in the future. So they should only be updated after one hour.
+# This test will only be the most basic one where we check that ocsp response
+# loading still works as expected.
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+ crt-base ${testdir}/ocsp_update
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend ssl-fe
+ bind "${tmpdir}/ssl.sock" ssl crt multicert/server_ocsp.pem ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+} -start
+
+
+# We should have two distinct ocsp responses known that were loaded at build time
+haproxy h1 -cli {
+ send "show ssl ocsp-response"
+ expect ~ "Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015"
+ send "show ssl ocsp-response"
+ expect ~ "Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016"
+
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015"
+ expect ~ "Cert Status: revoked"
+
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016"
+ expect ~ "Cert Status: good"
+}
+
+haproxy h1 -wait
+
+
+
+####################
+# #
+# SECOND TEST CASE #
+# #
+####################
+
+# This test will focus on two separate certificates that have the same OCSP uri
+# (http://ocsp.haproxy.com:12345) but no OCSP response loaded at build time.
+# The update mode is set to 'on' in the two crt-lists used. The two ocsp
+# responses should then be fetched automatically after init. We use an http
+# listener as a rebound on which http log is enabled towards Syslog_http. This
+# ensures that two requests are sent by the ocsp auto update task and it
+# enables to use a barrier to synchronize the ocsp task and the subsequent cli
+# calls. Thanks to the barrier we know that when calling "show ssl
+# ocsp-response" on the cli, the two answers should already have been received
+# and processed.
+
+process p1 "openssl ocsp -index ${testdir}/ocsp_update/index.txt -rsigner ${testdir}/ocsp_update/ocsp.haproxy.com.pem -CA ${testdir}/ocsp_update/ocsp_update_rootca.crt -nrequest 2 -ndays 1 -port 12346 -timeout 5" -start
+
+barrier b1 cond 2 -cyclic
+
+syslog Syslog_http -level info {
+ recv
+ expect ~ "GET /MEMwQTA%2FMD0wOzAJBgUrDgMCGgUABBSKg%2BAGD6%2F3Ccp%2Bm5VSKi6BY1%2FaCgQU9lKw5DXV6pI4UVCPCtvpLYXeAHoCAhAV HTTP/1.1"
+
+ recv
+ expect ~ "GET /MEMwQTA%2FMD0wOzAJBgUrDgMCGgUABBSKg%2BAGD6%2F3Ccp%2Bm5VSKi6BY1%2FaCgQU9lKw5DXV6pI4UVCPCtvpLYXeAHoCAhAW HTTP/1.1"
+
+ barrier b1 sync
+} -start
+
+haproxy h2 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h2/stats" level admin
+ crt-base ${testdir}/ocsp_update
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend ssl-rsa-fe
+ bind "${tmpdir}/ssl2.sock" ssl crt-list ${testdir}/ocsp_update/multicert_rsa.crt-list ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ frontend ssl-ecdsa-fe
+ bind "${tmpdir}/ssl3.sock" ssl crt-list ${testdir}/ocsp_update/multicert_ecdsa.crt-list ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ listen http_rebound_lst
+ mode http
+ option httplog
+ log ${Syslog_http_addr}:${Syslog_http_port} local0
+ bind "127.0.0.1:12345"
+ server s1 "127.0.0.1:12346"
+} -start
+
+barrier b1 sync
+
+shell "sleep 1"
+
+# We should have two distinct ocsp IDs known that were loaded at build time and
+# the responses' contents should have been filled automatically by the ocsp
+# update task after init
+haproxy h2 -cli {
+ send "show ssl ocsp-response"
+ expect ~ "Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015"
+ send "show ssl ocsp-response"
+ expect ~ "Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016"
+
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015"
+ expect ~ "Cert Status: revoked"
+
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016"
+ expect ~ "Cert Status: revoked"
+}
+
+haproxy h2 -wait
+process p1 -wait -expect-exit 0
+
+
+###################
+# #
+# THIRD TEST CASE #
+# #
+###################
+
+# This test will be roughly the same as the second one but one of the crt-lists
+# will not enable ocsp-update on its certificate. Only one request should then
+# be sent.
+
+process p2 "openssl ocsp -index ${testdir}/ocsp_update/index.txt -rsigner ${testdir}/ocsp_update/ocsp.haproxy.com.pem -CA ${testdir}/ocsp_update/ocsp_update_rootca.crt -nrequest 1 -ndays 1 -port 12346 -timeout 5" -start
+
+barrier b2 cond 2 -cyclic
+
+syslog Syslog_http2 -level info {
+ recv
+ expect ~ "GET /MEMwQTA%2FMD0wOzAJBgUrDgMCGgUABBSKg%2BAGD6%2F3Ccp%2Bm5VSKi6BY1%2FaCgQU9lKw5DXV6pI4UVCPCtvpLYXeAHoCAhAV HTTP/1.1"
+
+ barrier b2 sync
+} -start
+
+haproxy h3 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h3/stats" level admin
+ crt-base ${testdir}/ocsp_update
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend ssl-rsa-fe
+ bind "${tmpdir}/ssl4.sock" ssl crt-list ${testdir}/ocsp_update/multicert_rsa.crt-list ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ frontend ssl-ecdsa-fe
+ bind "${tmpdir}/ssl5.sock" ssl crt-list ${testdir}/ocsp_update/multicert_ecdsa_no_update.crt-list ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ listen http_rebound_lst
+ mode http
+ option httplog
+ log ${Syslog_http2_addr}:${Syslog_http2_port} local0
+ bind "127.0.0.1:12345"
+ server s1 "127.0.0.1:12346"
+} -start
+
+barrier b2 sync
+
+shell "sleep 1"
+
+# We should have a single ocsp ID known that was loaded at build time and the
+# response should be filled
+haproxy h3 -cli {
+ send "show ssl ocsp-response"
+ expect ~ "Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015"
+ send "show ssl ocsp-response"
+ expect !~ "Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016"
+
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015"
+ expect ~ "Cert Status: revoked"
+}
+
+haproxy h3 -wait
+process p2 -wait
+
+
+
+####################
+# #
+# FOURTH TEST CASE #
+# (CLI COMMAND) #
+# #
+####################
+
+process p3 "openssl ocsp -index ${testdir}/ocsp_update/index.txt -rsigner ${testdir}/ocsp_update/ocsp.haproxy.com.pem -CA ${testdir}/ocsp_update/ocsp_update_rootca.crt -nrequest 2 -ndays 1 -port 12346 -timeout 5" -start
+
+haproxy h4 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h4/stats" level admin
+ crt-base ${testdir}/ocsp_update
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend ssl-rsa-ocsp
+ bind "${tmpdir}/ssl5.sock" ssl crt ${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ frontend ssl-ecdsa-ocsp
+ bind "${tmpdir}/ssl6.sock" ssl crt ${testdir}/ocsp_update/multicert/server_ocsp_ecdsa.pem ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ listen http_rebound_lst
+ mode http
+ option httplog
+ bind "127.0.0.1:12345"
+ http-response set-var(proc.processed) int(1)
+ server s1 "127.0.0.1:12346"
+} -start
+
+# We need to "enable" the cli with a first cli call before using it only through socats
+haproxy h4 -cli {
+ send "show ssl ocsp-response"
+ expect ~ "Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016"
+}
+
+# We should have two OCSP responses loaded during init
+shell {
+ responses=$(echo "show ssl ocsp-response" | socat "${tmpdir}/h4/stats" -)
+
+ [ $(echo "$responses" | grep -c "^Certificate ID key") -eq 2 ] && \
+ echo "$responses" | grep "Serial Number: 1016" && \
+ echo "$responses" | grep "Serial Number: 1015"
+}
+
+shell {
+ echo "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015" | socat "${tmpdir}/h4/stats" - | grep "Cert Status: revoked"
+}
+
+shell {
+ echo "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016" | socat "${tmpdir}/h4/stats" - | grep "Cert Status: good"
+}
+
+# Update the first ocsp response (ckch_data has a non-NULL ocsp_issuer pointer)
+shell {
+ # Store the current "Produced At" in order to ensure that after the update
+ # the OCSP response actually changed
+ produced_at=$(echo "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015" | socat "${tmpdir}/h4/stats" - | grep "Produced At")
+
+ echo "update ssl ocsp-response ${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa" | socat "${tmpdir}/h4/stats" -
+ while ! echo "get var proc.processed" | socat "${tmpdir}/h4/stats" - | grep 'proc.processed: type=sint value=<1>'
+ do
+ echo "get var proc.processed" | socat "${tmpdir}/h4/stats" - >> /tmp/toto
+ sleep 0.5
+ done
+
+ echo "experimental-mode on;set var proc.processed int(0)" | socat "${tmpdir}/h4/stats" -
+
+ ocsp_response=$(echo "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015" | socat "${tmpdir}/h4/stats" -)
+ new_produced_at=$(echo "$ocsp_response" | grep "Produced At")
+
+ echo "$ocsp_response" | grep -q "Serial Number: 1015" && \
+ echo "$ocsp_response" | grep -q "Cert Status: revoked" && \
+ [ "$new_produced_at" != "$produced_at" ]
+}
+
+# Update the second ocsp response (ckch_data has a NULL ocsp_issuer pointer)
+shell {
+ # Store the current "Produced At" in order to ensure that after the update
+ # the OCSP response actually changed
+ produced_at=$(echo "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016" | socat "${tmpdir}/h4/stats" - | grep "Produced At")
+
+ echo "update ssl ocsp-response ${testdir}/ocsp_update/multicert/server_ocsp_ecdsa.pem" | socat "${tmpdir}/h4/stats" -
+ while ! echo "get var proc.processed" | socat "${tmpdir}/h4/stats" - | grep 'proc.processed: type=sint value=<1>'
+ do
+ echo "get var proc.processed" | socat "${tmpdir}/h4/stats" - >> /tmp/toto
+ sleep 0.5
+ done
+
+ echo "experimental-mode on;set var proc.processed int(0)" | socat "${tmpdir}/h4/stats" -
+
+ ocsp_response=$(echo "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016" | socat "${tmpdir}/h4/stats" -)
+ new_produced_at=$(echo "$ocsp_response" | grep "Produced At")
+
+ echo "$ocsp_response" | grep -q "Serial Number: 1016" && \
+ echo "$ocsp_response" | grep -q "Cert Status: revoked" && \
+ [ "$new_produced_at" != "$produced_at" ]
+}
+
+haproxy h4 -wait
+process p3 -wait
+
+
+####################
+# #
+# FIFTH TEST CASE #
+# (CLI COMMAND) #
+# #
+####################
+
+# Test the "show ssl ocsp-updates" command as well as the new 'base64' parameter
+# to the "show ssl ocsp-response" command.
+
+
+process p5 "openssl ocsp -index ${testdir}/ocsp_update/index.txt -rsigner ${testdir}/ocsp_update/ocsp.haproxy.com.pem -CA ${testdir}/ocsp_update/ocsp_update_rootca.crt -nrequest 2 -ndays 1 -port 12346 -timeout 5" -start
+
+barrier b5 cond 2 -cyclic
+
+syslog Syslog_http5 -level info {
+ recv
+ expect ~ "GET /MEMwQTA%2FMD0wOzAJBgUrDgMCGgUABBSKg%2BAGD6%2F3Ccp%2Bm5VSKi6BY1%2FaCgQU9lKw5DXV6pI4UVCPCtvpLYXeAHoCAhAV HTTP/1.1"
+
+ recv
+ expect ~ "GET /MEMwQTA%2FMD0wOzAJBgUrDgMCGgUABBSKg%2BAGD6%2F3Ccp%2Bm5VSKi6BY1%2FaCgQU9lKw5DXV6pI4UVCPCtvpLYXeAHoCAhAW HTTP/1.1"
+
+ barrier b5 sync
+} -start
+
+haproxy h5 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h5/stats" level admin
+ crt-base ${testdir}/ocsp_update
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend ssl-rsa-fe
+ bind "${tmpdir}/ssl7.sock" ssl crt-list ${testdir}/ocsp_update/multicert_rsa.crt-list ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ frontend ssl-ecdsa-fe
+ bind "${tmpdir}/ssl8.sock" ssl crt-list ${testdir}/ocsp_update/multicert_ecdsa.crt-list ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ listen http_rebound_lst
+ mode http
+ option httplog
+ log ${Syslog_http5_addr}:${Syslog_http5_port} local0
+ bind "127.0.0.1:12345"
+ server s1 "127.0.0.1:12346"
+} -start
+
+barrier b5 sync
+
+shell "sleep 1"
+
+# Use "show ssl ocsp-updates" CLI command
+# We should have one line per OCSP response and each one of them should have been successfully updated once
+# The command's output follows this format:
+# OCSP Certid | Next Update | Last Update | Successes | Failures | Last Update Status | Last Update Status (str)
+haproxy h5 -cli {
+ send "show ssl ocsp-updates"
+ expect ~ "303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015 .*| 1 | 0 | 1 | Update successful"
+
+ send "show ssl ocsp-updates"
+ expect ~ "303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016 .*| 1 | 0 | 1 | Update successful"
+}
+
+# Use "show ssl ocsp-response" command to dump an OCSP response in base64
+shell {
+ ocsp_resp_file="${tmpdir}.ocsp_resp.der"
+
+ echo "show ssl ocsp-response base64 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015" | socat "${tmpdir}/h5/stats" - | base64 -d > $ocsp_resp_file
+
+ if [ $? -eq 0 ]
+ then
+ ocsp_resp_txt="$(openssl ocsp -respin $ocsp_resp_file -noverify -text)"
+ echo "$ocsp_resp_txt" | grep "Issuer Name Hash: 8A83E0060FAFF709CA7E9B95522A2E81635FDA0A" && \
+ echo "$ocsp_resp_txt" | grep "Issuer Key Hash: F652B0E435D5EA923851508F0ADBE92D85DE007A" && \
+ echo "$ocsp_resp_txt" | grep "Serial Number: 1015" && \
+ echo "$ocsp_resp_txt" | grep "Cert Status: revoked"
+ else
+ return 1
+ fi
+}
+
+haproxy h5 -wait
+process p5 -wait
+
+
+####################
+# #
+# SIXTH TEST CASE #
+# #
+####################
+
+# Check that a new certificate added via the CLI to a crt-list with
+# the 'ocsp-update on' option will be taken into account by the OCSP
+# auto update task
+#
+process p6 "openssl ocsp -index ${testdir}/ocsp_update/index.txt -rsigner ${testdir}/ocsp_update/ocsp.haproxy.com.pem -CA ${testdir}/ocsp_update/ocsp_update_rootca.crt -nrequest 1 -ndays 1 -port 12346 -timeout 5" -start
+
+barrier b6 cond 2 -cyclic
+
+syslog Syslog_http6 -level info {
+ recv
+ expect ~ "GET /MEMwQTA%2FMD0wOzAJBgUrDgMCGgUABBSKg%2BAGD6%2F3Ccp%2Bm5VSKi6BY1%2FaCgQU9lKw5DXV6pI4UVCPCtvpLYXeAHoCAhAV HTTP/1.1"
+
+ barrier b6 sync
+} -start
+
+haproxy h6 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h6/stats" level admin
+ crt-base ${testdir}
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend ssl-fe
+ bind "${tmpdir}/ssl9.sock" ssl crt-list ${testdir}/simple.crt-list ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ listen http_rebound_lst
+ mode http
+ option httplog
+ log ${Syslog_http6_addr}:${Syslog_http6_port} local0
+ bind "127.0.0.1:12345"
+ server s1 "127.0.0.1:12346"
+} -start
+
+# We need to "enable" the cli with a first cli call before using it only through socats
+haproxy h6 -cli {
+ send "show ssl cert"
+ expect ~ ""
+}
+
+# Create a new certificate that has an OCSP uri and add it to the
+# existing CLI with the 'ocsp-update on' command.
+shell {
+ echo "new ssl cert ${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa" | socat "${tmpdir}/h6/stats" -
+ printf "set ssl cert ${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa <<\n$(cat ${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa)\n\n" | socat "${tmpdir}/h6/stats" -
+ printf "set ssl cert ${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa.issuer <<\n$(cat ${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa.issuer)\n\n" | socat "${tmpdir}/h6/stats" -
+ echo "commit ssl cert ${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa" | socat "${tmpdir}/h6/stats" -
+
+ printf "add ssl crt-list ${testdir}/simple.crt-list <<\n${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa [ocsp-update on] foo.com\n\n" | socat "${tmpdir}/h6/stats" -
+}
+
+barrier b6 sync
+
+shell "sleep 1"
+
+haproxy h6 -cli {
+ send "show ssl ocsp-updates"
+ expect ~ "303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016 .*| 1 | 0 | 1 | Update successful"
+}
+
+haproxy h6 -wait
+process p6 -wait
+
+
+######################
+# #
+# SEVENTH TEST CASE #
+# #
+######################
+
+#
+# Check that removing crt-list instances does not remove the OCSP responses
+# from the tree but that they will not be auto updated anymore if the last
+# instance is removed (via del ssl crt-list).
+#
+
+haproxy h7 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h7/stats" level admin
+ crt-base ${testdir}/ocsp_update
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend ssl-fe
+ bind "${tmpdir}/ssl-h7.sock" ssl crt-list ${testdir}/ocsp_update/multicert_both_certs.crt-list ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ listen http_rebound_lst
+ mode http
+ bind "127.0.0.1:12345"
+ server s1 "127.0.0.1:12346"
+} -start
+
+# Check that the two certificates are taken into account in the auto update process
+haproxy h7 -cli {
+ send "show ssl ocsp-updates"
+ expect ~ "303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015 .*"
+
+ send "show ssl ocsp-updates"
+ expect ~ "303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016 .*"
+}
+
+# Remove the second line from the crt-list and check that the corresponding
+# ocsp response was removed from the auto update list but is still present in the
+# system
+haproxy h7 -cli {
+ send "del ssl crt-list ${testdir}/ocsp_update/multicert_both_certs.crt-list ${testdir}/ocsp_update/multicert/server_ocsp.pem.ecdsa"
+ expect ~ "Entry.*deleted in crtlist"
+
+ send "show ssl ocsp-updates"
+ expect !~ "303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016 .*"
+
+ send "show ssl ocsp-response"
+ expect ~ "Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016"
+
+ send "show ssl ocsp-response ${testdir}/ocsp_update/multicert/server_ocsp.pem.ecdsa"
+ expect ~ ".* Cert Status: good.*"
+}
+
+# Add the previously removed crt-list line with auto-update enabled and check that
+# the ocsp response appears in the auto update list
+shell {
+ printf "add ssl crt-list ${testdir}/ocsp_update/multicert_both_certs.crt-list <<\nmulticert/server_ocsp.pem.ecdsa [ocsp-update on] foo.bar\n\n" | socat "${tmpdir}/h7/stats" - | grep "Inserting certificate.*in crt-list"
+}
+
+haproxy h7 -cli {
+ send "show ssl ocsp-updates"
+ expect ~ "303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021016 .*"
+}
+
+# Check that the auto update option consistency check work even when crt-list
+# lines are added through the cli
+shell {
+ printf "add ssl crt-list ${testdir}/ocsp_update/multicert_both_certs.crt-list <<\nmulticert/server_ocsp.pem.ecdsa foo.foo\n\n" | socat "${tmpdir}/h7/stats" - | grep "Incompatibilities found in OCSP update mode for certificate"
+}
+
+haproxy h7 -wait
+
+####################
+# #
+# EIGTH TEST CASE #
+# #
+####################
+
+#
+# Check that a certificate created through the CLI and which does not have ocsp
+# update enabled can be updated via "update ssl ocsp-response" command.
+#
+
+process p8 "openssl ocsp -index ${testdir}/ocsp_update/index.txt -rsigner ${testdir}/ocsp_update/ocsp.haproxy.com.pem -CA ${testdir}/ocsp_update/ocsp_update_rootca.crt -nrequest 1 -ndays 1 -port 12346 -timeout 5" -start
+
+barrier b8 cond 2 -cyclic
+
+syslog Syslog_h8 -level info {
+ recv
+ expect ~ "GET /MEMwQTA%2FMD0wOzAJBgUrDgMCGgUABBSKg%2BAGD6%2F3Ccp%2Bm5VSKi6BY1%2FaCgQU9lKw5DXV6pI4UVCPCtvpLYXeAHoCAhAV HTTP/1.1"
+
+ barrier b8 sync
+} -start
+
+
+haproxy h8 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h8/stats" level admin
+ crt-base ${testdir}/ocsp_update
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend ssl-fe
+ bind "${tmpdir}/ssl-h8.sock" ssl crt-list ${testdir}/ocsp_update/multicert_ecdsa_no_update.crt-list ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-request return status 200
+
+ listen http_rebound_lst
+ mode http
+ option httplog
+ log ${Syslog_h8_addr}:${Syslog_h8_port} local0
+ bind "127.0.0.1:12345"
+ server s1 "127.0.0.1:12346"
+} -start
+
+# We need to "enable" the cli with a first cli call before using it only through socats
+haproxy h8 -cli {
+ send "show ssl cert"
+ expect ~ ""
+}
+
+# Create a new certificate and add it in the crt-list with ocsp auto-update enabled
+shell {
+ echo "new ssl cert ${testdir}/ocsp_update/rsa.pem" | socat "${tmpdir}/h8/stats" -
+ printf "set ssl cert ${testdir}/ocsp_update/rsa.pem <<\n$(cat ${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa)\n\n" | socat "${tmpdir}/h8/stats" -
+ printf "set ssl cert ${testdir}/ocsp_update/rsa.pem.issuer <<\n$(cat ${testdir}/ocsp_update/ocsp_update_rootca.crt)\n\n" | socat "${tmpdir}/h8/stats" -
+ printf "set ssl cert ${testdir}/ocsp_update/rsa.pem.ocsp <<\n$(base64 -w 1000 ${testdir}/ocsp_update/multicert/server_ocsp.pem.rsa.ocsp)\n\n" | socat "${tmpdir}/h8/stats" -
+ echo "commit ssl cert ${testdir}/ocsp_update/rsa.pem" | socat "${tmpdir}/h8/stats" -
+
+ printf "add ssl crt-list ${testdir}/ocsp_update/multicert_ecdsa_no_update.crt-list <<\nrsa.pem [ocsp-update off] foo.bar\n\n" | socat "${tmpdir}/h8/stats" -
+}
+
+# Check that the line is in the crt-list
+haproxy h8 -cli {
+ send "show ssl crt-list ${testdir}/ocsp_update/multicert_ecdsa_no_update.crt-list"
+ expect ~ "${testdir}/ocsp_update/rsa.pem .* foo.bar"
+}
+
+# Check that the new certificate is NOT in the auto update list
+haproxy h8 -cli {
+ send "show ssl ocsp-updates"
+ expect !~ "303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015.*"
+}
+
+shell {
+ echo "update ssl ocsp-response ${testdir}/ocsp_update/rsa.pem" | socat "${tmpdir}/h8/stats" -
+}
+
+shell "sleep 1"
+
+barrier b8 sync
+
+haproxy h8 -cli {
+ send "show ssl ocsp-response ${testdir}/ocsp_update/rsa.pem"
+ expect ~ ".* Cert Status: revoked.*"
+}
+
+haproxy h8 -wait
+process p8 -wait
diff --git a/reg-tests/ssl/ocsp_update/index.txt b/reg-tests/ssl/ocsp_update/index.txt
new file mode 100644
index 0000000..111ea47
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/index.txt
@@ -0,0 +1,2 @@
+R 20500410103904Z 221123104541Z 1015 unknown /C=FR/O=HAProxy Technologies/CN=rsa.haproxy.com
+R 20500410103956Z 221123104430Z 1016 unknown /C=FR/O=HAProxy Technologies/CN=ecdsa.haproxy.com
diff --git a/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa
new file mode 100644
index 0000000..a04fd2e
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIEODCCAiCgAwIBAgICEBYwDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRAwDgYDVQQDDAdSb290IENB
+MCAXDTIyMTEyMzEwMzk1NloYDzIwNTAwNDEwMTAzOTU2WjBIMQswCQYDVQQGEwJG
+UjEdMBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxGjAYBgNVBAMMEWVjZHNh
+LmhhcHJveHkuY29tMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB5Id0dJy6Vubt
+/ICfwLOOwgvyeOHOvC/yrqU/NCBNDVZLcOXbncm8Lxzl9Rn2t0VV9pla82/Qlexu
+2jhx8LD3du8AmEn/4tkJMz85Jv4TN/eY7Tsfbqy2NtX17eBWkDA/S1v+9uw9m7UJ
+mzwHIkQHi4S+flXt2ZtQKwgmYcuFYsP6jSGjgbswgbgwMgYIKwYBBQUHAQEEJjAk
+MCIGCCsGAQUFBzABhhZodHRwOi8vMTI3LjAuMC4xOjEyMzQ1MB0GA1UdDgQWBBTS
+Tdzvp9SeMDDfWVNdLPzVCaE/oDBjBgNVHSMEXDBaoUKkQDA+MQswCQYDVQQGEwJG
+UjEdMBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxEDAOBgNVBAMMB1Jvb3Qg
+Q0GCFB4L4lCTIAmZTjzoVXNPaWeDYX8XMA0GCSqGSIb3DQEBCwUAA4ICAQBsoRvT
+LPipFUSvGWWFphrqhri40e6GEKio2RNrHSwq6PBPd+FAjIan1yoZX3C/I/octhoq
+/jHAlCB5GQzU3R3M/gaCyDk4x3wbR52zSNzgyh464B7HwlNyC9jCeh3yB8ylUZCu
+Lc8NRTYavceUoDq2ebO8wpWX0LBd0oh7hMcQzWQrmU1B0NYVsTn65Ogcfokz2r0M
+A3YjwT8vH9i9QFx1Fxy4OYJJQmskKrwAQ+MEtyBJvck2nthZA7KNX+OxuJjOh+lW
++WpTudaoMUd188zHFFjeM4C40uPsePlf1gpdjuTdir1sIH8GNa9XP1wEtvD6mNFU
+6KCFSuZSkBqo2iD6yYzsd1H2DSMVQL67ATP8zSMjEccDYwkO72BR3InxWDFnFEQN
+wosdBFKqqKNKkkdSW1QUsVd90Bi5pHFW0l4FaDk2SJRfzwa1Dc+LfQv9Wf+LcENW
+6HOjqcRdU1PU1evVmq5xoHRDovQGNCStfwX3eW+jnHFYqovg51g5pEPEsmQccJXj
+DMCGoQjM+4i+R0GhyJZ/Kr2Lnj5RyT6RVK8hNCx5NjJBK5z/pJK9pbPGoS9fkK8N
+iQvPgw2+Y3rcVKHUw2epz/2mEzDb4rRiSIOIeuHB4PBL41jUNPwSxkjtjkPwVMuU
+TlD6A5wDj3Sq0B4MoxWgIOyWENABvGl+VBtDNQ==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBkWJB8IW867HHc2iB
+7J714zyea0hVD1Z/MEuEyKRZ7aekbjEQKmUfc5MLlQS0nedCqmiLuXObG/PyxxWs
+mWTeH5qhgYkDgYYABAHkh3R0nLpW5u38gJ/As47CC/J44c68L/KupT80IE0NVktw
+5dudybwvHOX1Gfa3RVX2mVrzb9CV7G7aOHHwsPd27wCYSf/i2QkzPzkm/hM395jt
+Ox9urLY21fXt4FaQMD9LW/727D2btQmbPAciRAeLhL5+Ve3Zm1ArCCZhy4Viw/qN
+IQ==
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa.issuer b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa.issuer
new file mode 100644
index 0000000..bed2061
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa.issuer
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFGjCCAwKgAwIBAgIUHgviUJMgCZlOPOhVc09pZ4NhfxcwDQYJKoZIhvcNAQEL
+BQAwPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMB4XDTIxMDQyMjE0MDEyMFoXDTQ4MDkwNzE0MDEy
+MFowPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEAti+5onUeFJNyF5s6xlnBxDnFhw7Q5VbBestHeQttjBWN31zq5yaf/+CYXdu+
+lY6gNZj6JBiFJ5P7VXX3DqUIJBX6byXWfIUWM+auBAMKlTz0+hWrF/UxI/3uG67N
++Z6NVffEPYbA4Emqozr0DIicWorRyHnrhEQQP87xBCUboUr3QEkNngfiJ0fPm3fj
+7HfQemGL2OnTA8qdy0q1l4aUhVr9bgedP2Klvs0XhbszCGLI0Gq5lyNadlH1MEiw
+SXa9rklE6NCNcyamO7Wt8LVrg6pxopa7oGnkLbnjzSuE+xsN0isOLaHH5LfYg6gT
+aAHpnBHiWuDZQIyzKc+Z37gNksd46/y9B+oBZoCTcYMOsn7PK+gPzTbu3ic4L9hO
+WCsTV0tn+qUGj6/J98gRgvuvZGA7NPDKNZU5p34oyApBPBUOgpn6pCuT5NlkPYAe
+Rp/ypiy5NCHp0JW3JWkJ4+wEasZM34TZUYrOsicA0GV4ZVkoQ3WYyAjmLvRXmo/w
+Z3sSlmHvCg9MrQ9pk24+OtvCbii0bb/Zmlx0Y4lU5TogcuJffJDVbj7oxTc2gRmI
+SIZsnYLv2qVoeBoMY5otj+ef0Y8v98mKCbiWe2MzBkC2h5wmwyWedez8RysTaFHS
+Z4yOYoCsEAtCxnib9d5fXf0+6aOuFtKMknkuWbYj6En647ECAwEAAaMQMA4wDAYD
+VR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAjVzxHzq/87uj24It5hYj4mq4
+ero0zix4fA4tJNuTpZ/5r7GUYaf/uT4xfDilBX2fGMsxVTxJC25KzhdFeTzg1Tde
+/N0LAeLWHfe6jR/P5XDATD0ZA73DQALOxRM5uRMeWJDVaUeco/aXsdQaCz2STDI3
+h7VVFoaOlmxQW3BBEvg2VUp9DS2UjqqdwsUDtzwKfrmj/FqyBvGrvNeIMv28HCu7
+r1WE1Z0UEJhpc1BPbu7F/vl60gRF3bQjh2tL8pWThxTJe6Qy+pLoSShyi85AM9XK
+scCmUtQWjy7KQDL8XVFvuCWvMzknZQjJcncbKddPaaSIDkKUpz9FDv+wSJj/LKf7
+bGSFPM6sblioLbLNJByRYI8G7VHvKDbUnYHbHp75NTGA2eDeNqx5bC2G/EJUTwLM
+bfcZr9hv+z1QpvSLEpar30kJjc1QMQcf60ToGYIC93rsVAKou2GPGry4h/nzwro0
+jjFWNgORTXllfcQDbDNOPkV1kFFibPbAU4faZMgC+xwIwDBsndvcvXjLaRUa4fmw
+1xNkOO5Lj9AuvTXdCc9yUXRzmPZhU6Q4YB2daWvs3vbMTtvkAXGyQL4b2HD+NYZs
+cMUtbteGgQzwM1gpMBn4GX53vhlCXq28r3cH1/1tLDweglSrxyvZbB7pZU7BAmLk
+TEj2fXcvdcX+TtYhC10=
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa.ocsp b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa.ocsp
new file mode 100644
index 0000000..793aff1
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.ecdsa.ocsp
Binary files differ
diff --git a/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa
new file mode 100644
index 0000000..058e46d
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa
@@ -0,0 +1,56 @@
+-----BEGIN CERTIFICATE-----
+MIIEvjCCAqagAwIBAgICEBUwDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRAwDgYDVQQDDAdSb290IENB
+MCAXDTIyMTEyMzEwMzkwNFoYDzIwNTAwNDEwMTAzOTA0WjBGMQswCQYDVQQGEwJG
+UjEdMBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxGDAWBgNVBAMMD3JzYS5o
+YXByb3h5LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIRBd2HB
+WFxKohqOWKCZkQcszMx0tpA48sxlDgjsy6iVEycM1eOQopbFOiSAig2gf+8llKUv
+DM66f98FsBKJ/rVksOS07rDBOO9LCGE7JF8o/Cjc3vIX2gvTd0H19ENHFlxCSBn8
+q5NsLmCSCFHFDSPXL3uhrX/9ScBeU1j7M8nF/AEX50q1ubGRHMbYrBkhUDlI+s92
+fvFpuFPf9vcjPLihHEofYKErKVeNfn+3aD/V55Aw1NO15Dt1Vc+TypeuL7jqgJRg
+OVk2MJmedXKUA4A8SaY4gqVKy1aAe6JYWrCGqr8oHNt3nwqMYyhLkeyqmLh+VMXv
+Bdqj3JbwiGGRou8CAwEAAaOBuzCBuDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUH
+MAGGFmh0dHA6Ly8xMjcuMC4wLjE6MTIzNDUwHQYDVR0OBBYEFNGC81nNOAJDX1V+
+vlnE5/iy9ciNMGMGA1UdIwRcMFqhQqRAMD4xCzAJBgNVBAYTAkZSMR0wGwYDVQQK
+DBRIQVByb3h5IFRlY2hub2xvZ2llczEQMA4GA1UEAwwHUm9vdCBDQYIUHgviUJMg
+CZlOPOhVc09pZ4NhfxcwDQYJKoZIhvcNAQELBQADggIBAJmKCsKn0LGUJ5xhSd0c
+d8Aq7TpJImXNUNqoQsyLU5FK8qF3HfJBA2pLkROLZKTXGnwSVndOpxlZy7IpdhZZ
+Ya23mxi6G3iXYAGmiVwGXxZfCwISqARr+CR8psIUQLdi21P5UkLG2LU0+b/ManQD
+4MPvyzi7qf4qaao/miZiT9idrdy0XNQoRy1vJzMMfcRhzWzuGvnr2NVOhZpuDe8p
+K6Hc+8AGZX8qY0DQ30YHU4Ygq0NGRR/oHOoAdJSAuIvfLkKiNZ0s3XTOKu8bogGh
+NbkffborINbB6MG8ZSM+KUrsQbFl6e2lk6VVk1gYIMx/L3MF3WFK9212+8ak0pr1
+JZOd87aWg3WcNqpRgcu3FXZSDfF5JH8jBAoXTZ5YHLMRjrfFLaMmyPC8egcDpogR
+sM4wXyo+5SEX4YWTsd2FRcmPbOFcmwQOy/zmZQyFPnpp+ORRDEkTJmT/VRoexHrt
+8EcKX/CIJ+nzBQtEVThgOCWrE6c9MF+MGkI+TMXy932jEvK14GU2U4aE7uhvyiJt
+RJ+iZGTqwsu7wOqvP8+SsxhpY4ZlNL+LSeHLoq2nBmBwCgHj0ikdEMMLbjciUVGu
+Zb44d9hPea+nfljju5m4VLmonGW2cbzFL4r5mC0/xk6JrB9buw5swkwhslR0guCu
+3knMr1pjkbf8W6DDGKvxHJIX
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCEQXdhwVhcSqIa
+jligmZEHLMzMdLaQOPLMZQ4I7MuolRMnDNXjkKKWxTokgIoNoH/vJZSlLwzOun/f
+BbASif61ZLDktO6wwTjvSwhhOyRfKPwo3N7yF9oL03dB9fRDRxZcQkgZ/KuTbC5g
+kghRxQ0j1y97oa1//UnAXlNY+zPJxfwBF+dKtbmxkRzG2KwZIVA5SPrPdn7xabhT
+3/b3Izy4oRxKH2ChKylXjX5/t2g/1eeQMNTTteQ7dVXPk8qXri+46oCUYDlZNjCZ
+nnVylAOAPEmmOIKlSstWgHuiWFqwhqq/KBzbd58KjGMoS5Hsqpi4flTF7wXao9yW
+8IhhkaLvAgMBAAECggEAIQA46sKU6sqQsnGseb536sNqAuZom4oqQ4g/vUhg9Rrl
+oYvZXyQ6/cYO4QbV69qNsb293o3j8z2kJKFFswqN7PNIFHl1SdOdAlDFsYVRaRFQ
+Al5Cn0QGW4cTrfjST2tQkArV9O4QXgPTerNVshmqUrQiHAZWxaYNHhwrTfu4i3Mo
+v4hfPfXuVLFWzdVFyvBQ+u+yxwqCnKKrKj7uXiPyFwQ0g4wFKs8O48ZZoVryZFJn
+nuUKBr0JBaHpgPTfx1QavvoUeQzDshEAcMXq0Lh4LTzp95jfwsiBj3fEwcrXuJyr
+o3TGHwGHILL8vKpZpw/Ub9Rr4xpyb0Ij+UHzVir5+QKBgQC3a4YNMOy9UD3XSmwU
+qMn1YXpZYv6hz7rFYrQFPjd42b8Orl6v0KrsPVk2hc4KQpiMaEa+IgnD9guMdri4
+oNMri9reoLHDzxN/Wh/jTVVaO2b3mljzF62JF6SJOjeLYvKRqRH4whdCku/1D0xR
+DfhBIVZzCj2tTI1CMZl42vNK6wKBgQC4lv4PakdIY6W3bu2/fuX4PwnrSUmsJV+d
+UAmCls38hnoNHIDrEWbF+StSA/PsHQGOa4w1iYBsD3PptQ43zF7nwvjxKYeXu1/A
+y+0pW/ADlcAm+PcJfgym0663mWZG5bA1s3C1qMM30PM+Z0jTO/GUOeNFofuOWVK+
+mUiGG5U/DQKBgQCmbz74gUiQkFtNHA7uwCpiKs2mhpmfoqtLqMDJcSdM1ej0HW12
+A9bU/uYQ/2FzFfLulUB8Ds7lrkHUd3YusmBrx0AXe6FSmHiMuu7shqPIeNZ6HuhP
+zVB+caGvk9AK/wI1AkF4hEYu9r4elH8fnZmDIAkd4lENC8WyJueoLqVNeQKBgAsj
+uZNOk5yvvslyHVDoJJK1ozCazKJh4wJIWTqTRT0PFICEDtegxjX+UnnxmR/PpE9m
++CAm+yQKTrF05rXBVJzh7EoJepBSk3W8GMTdMn/U4rK3ZZkiDTtoHOwhisWOiPLE
+sHGWDKnqpzNF4mQ1AuAyGiASpW6yv0aXU4QcWAZlAoGBAISfKc6i2akMXufuqj5q
+B6OnFMkFR6JPJhxYo1aYKX0He4WW5RmXhm0lB6UKC7CtE9uofhEn3Tl2AcvwmY7G
+6UE9J/dAUVLGQV07aPyjAMq4ky+ZruI6ptxYgsdPmYZbXhMKIa2vNpB8/bgOKPA5
+3SgdB3ibaIMQtiJqdKjCbWqP
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa.issuer b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa.issuer
new file mode 100644
index 0000000..bed2061
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa.issuer
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFGjCCAwKgAwIBAgIUHgviUJMgCZlOPOhVc09pZ4NhfxcwDQYJKoZIhvcNAQEL
+BQAwPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMB4XDTIxMDQyMjE0MDEyMFoXDTQ4MDkwNzE0MDEy
+MFowPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEAti+5onUeFJNyF5s6xlnBxDnFhw7Q5VbBestHeQttjBWN31zq5yaf/+CYXdu+
+lY6gNZj6JBiFJ5P7VXX3DqUIJBX6byXWfIUWM+auBAMKlTz0+hWrF/UxI/3uG67N
++Z6NVffEPYbA4Emqozr0DIicWorRyHnrhEQQP87xBCUboUr3QEkNngfiJ0fPm3fj
+7HfQemGL2OnTA8qdy0q1l4aUhVr9bgedP2Klvs0XhbszCGLI0Gq5lyNadlH1MEiw
+SXa9rklE6NCNcyamO7Wt8LVrg6pxopa7oGnkLbnjzSuE+xsN0isOLaHH5LfYg6gT
+aAHpnBHiWuDZQIyzKc+Z37gNksd46/y9B+oBZoCTcYMOsn7PK+gPzTbu3ic4L9hO
+WCsTV0tn+qUGj6/J98gRgvuvZGA7NPDKNZU5p34oyApBPBUOgpn6pCuT5NlkPYAe
+Rp/ypiy5NCHp0JW3JWkJ4+wEasZM34TZUYrOsicA0GV4ZVkoQ3WYyAjmLvRXmo/w
+Z3sSlmHvCg9MrQ9pk24+OtvCbii0bb/Zmlx0Y4lU5TogcuJffJDVbj7oxTc2gRmI
+SIZsnYLv2qVoeBoMY5otj+ef0Y8v98mKCbiWe2MzBkC2h5wmwyWedez8RysTaFHS
+Z4yOYoCsEAtCxnib9d5fXf0+6aOuFtKMknkuWbYj6En647ECAwEAAaMQMA4wDAYD
+VR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAjVzxHzq/87uj24It5hYj4mq4
+ero0zix4fA4tJNuTpZ/5r7GUYaf/uT4xfDilBX2fGMsxVTxJC25KzhdFeTzg1Tde
+/N0LAeLWHfe6jR/P5XDATD0ZA73DQALOxRM5uRMeWJDVaUeco/aXsdQaCz2STDI3
+h7VVFoaOlmxQW3BBEvg2VUp9DS2UjqqdwsUDtzwKfrmj/FqyBvGrvNeIMv28HCu7
+r1WE1Z0UEJhpc1BPbu7F/vl60gRF3bQjh2tL8pWThxTJe6Qy+pLoSShyi85AM9XK
+scCmUtQWjy7KQDL8XVFvuCWvMzknZQjJcncbKddPaaSIDkKUpz9FDv+wSJj/LKf7
+bGSFPM6sblioLbLNJByRYI8G7VHvKDbUnYHbHp75NTGA2eDeNqx5bC2G/EJUTwLM
+bfcZr9hv+z1QpvSLEpar30kJjc1QMQcf60ToGYIC93rsVAKou2GPGry4h/nzwro0
+jjFWNgORTXllfcQDbDNOPkV1kFFibPbAU4faZMgC+xwIwDBsndvcvXjLaRUa4fmw
+1xNkOO5Lj9AuvTXdCc9yUXRzmPZhU6Q4YB2daWvs3vbMTtvkAXGyQL4b2HD+NYZs
+cMUtbteGgQzwM1gpMBn4GX53vhlCXq28r3cH1/1tLDweglSrxyvZbB7pZU7BAmLk
+TEj2fXcvdcX+TtYhC10=
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa.ocsp b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa.ocsp
new file mode 100644
index 0000000..5aa51d7
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert/server_ocsp.pem.rsa.ocsp
Binary files differ
diff --git a/reg-tests/ssl/ocsp_update/multicert/server_ocsp_ecdsa.pem b/reg-tests/ssl/ocsp_update/multicert/server_ocsp_ecdsa.pem
new file mode 100644
index 0000000..c33cf58
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert/server_ocsp_ecdsa.pem
@@ -0,0 +1,63 @@
+-----BEGIN CERTIFICATE-----
+MIIEODCCAiCgAwIBAgICEBYwDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRAwDgYDVQQDDAdSb290IENB
+MCAXDTIyMTEyMzEwMzk1NloYDzIwNTAwNDEwMTAzOTU2WjBIMQswCQYDVQQGEwJG
+UjEdMBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxGjAYBgNVBAMMEWVjZHNh
+LmhhcHJveHkuY29tMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB5Id0dJy6Vubt
+/ICfwLOOwgvyeOHOvC/yrqU/NCBNDVZLcOXbncm8Lxzl9Rn2t0VV9pla82/Qlexu
+2jhx8LD3du8AmEn/4tkJMz85Jv4TN/eY7Tsfbqy2NtX17eBWkDA/S1v+9uw9m7UJ
+mzwHIkQHi4S+flXt2ZtQKwgmYcuFYsP6jSGjgbswgbgwMgYIKwYBBQUHAQEEJjAk
+MCIGCCsGAQUFBzABhhZodHRwOi8vMTI3LjAuMC4xOjEyMzQ1MB0GA1UdDgQWBBTS
+Tdzvp9SeMDDfWVNdLPzVCaE/oDBjBgNVHSMEXDBaoUKkQDA+MQswCQYDVQQGEwJG
+UjEdMBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxEDAOBgNVBAMMB1Jvb3Qg
+Q0GCFB4L4lCTIAmZTjzoVXNPaWeDYX8XMA0GCSqGSIb3DQEBCwUAA4ICAQBsoRvT
+LPipFUSvGWWFphrqhri40e6GEKio2RNrHSwq6PBPd+FAjIan1yoZX3C/I/octhoq
+/jHAlCB5GQzU3R3M/gaCyDk4x3wbR52zSNzgyh464B7HwlNyC9jCeh3yB8ylUZCu
+Lc8NRTYavceUoDq2ebO8wpWX0LBd0oh7hMcQzWQrmU1B0NYVsTn65Ogcfokz2r0M
+A3YjwT8vH9i9QFx1Fxy4OYJJQmskKrwAQ+MEtyBJvck2nthZA7KNX+OxuJjOh+lW
++WpTudaoMUd188zHFFjeM4C40uPsePlf1gpdjuTdir1sIH8GNa9XP1wEtvD6mNFU
+6KCFSuZSkBqo2iD6yYzsd1H2DSMVQL67ATP8zSMjEccDYwkO72BR3InxWDFnFEQN
+wosdBFKqqKNKkkdSW1QUsVd90Bi5pHFW0l4FaDk2SJRfzwa1Dc+LfQv9Wf+LcENW
+6HOjqcRdU1PU1evVmq5xoHRDovQGNCStfwX3eW+jnHFYqovg51g5pEPEsmQccJXj
+DMCGoQjM+4i+R0GhyJZ/Kr2Lnj5RyT6RVK8hNCx5NjJBK5z/pJK9pbPGoS9fkK8N
+iQvPgw2+Y3rcVKHUw2epz/2mEzDb4rRiSIOIeuHB4PBL41jUNPwSxkjtjkPwVMuU
+TlD6A5wDj3Sq0B4MoxWgIOyWENABvGl+VBtDNQ==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBkWJB8IW867HHc2iB
+7J714zyea0hVD1Z/MEuEyKRZ7aekbjEQKmUfc5MLlQS0nedCqmiLuXObG/PyxxWs
+mWTeH5qhgYkDgYYABAHkh3R0nLpW5u38gJ/As47CC/J44c68L/KupT80IE0NVktw
+5dudybwvHOX1Gfa3RVX2mVrzb9CV7G7aOHHwsPd27wCYSf/i2QkzPzkm/hM395jt
+Ox9urLY21fXt4FaQMD9LW/727D2btQmbPAciRAeLhL5+Ve3Zm1ArCCZhy4Viw/qN
+IQ==
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIFGjCCAwKgAwIBAgIUHgviUJMgCZlOPOhVc09pZ4NhfxcwDQYJKoZIhvcNAQEL
+BQAwPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMB4XDTIxMDQyMjE0MDEyMFoXDTQ4MDkwNzE0MDEy
+MFowPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEAti+5onUeFJNyF5s6xlnBxDnFhw7Q5VbBestHeQttjBWN31zq5yaf/+CYXdu+
+lY6gNZj6JBiFJ5P7VXX3DqUIJBX6byXWfIUWM+auBAMKlTz0+hWrF/UxI/3uG67N
++Z6NVffEPYbA4Emqozr0DIicWorRyHnrhEQQP87xBCUboUr3QEkNngfiJ0fPm3fj
+7HfQemGL2OnTA8qdy0q1l4aUhVr9bgedP2Klvs0XhbszCGLI0Gq5lyNadlH1MEiw
+SXa9rklE6NCNcyamO7Wt8LVrg6pxopa7oGnkLbnjzSuE+xsN0isOLaHH5LfYg6gT
+aAHpnBHiWuDZQIyzKc+Z37gNksd46/y9B+oBZoCTcYMOsn7PK+gPzTbu3ic4L9hO
+WCsTV0tn+qUGj6/J98gRgvuvZGA7NPDKNZU5p34oyApBPBUOgpn6pCuT5NlkPYAe
+Rp/ypiy5NCHp0JW3JWkJ4+wEasZM34TZUYrOsicA0GV4ZVkoQ3WYyAjmLvRXmo/w
+Z3sSlmHvCg9MrQ9pk24+OtvCbii0bb/Zmlx0Y4lU5TogcuJffJDVbj7oxTc2gRmI
+SIZsnYLv2qVoeBoMY5otj+ef0Y8v98mKCbiWe2MzBkC2h5wmwyWedez8RysTaFHS
+Z4yOYoCsEAtCxnib9d5fXf0+6aOuFtKMknkuWbYj6En647ECAwEAAaMQMA4wDAYD
+VR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAjVzxHzq/87uj24It5hYj4mq4
+ero0zix4fA4tJNuTpZ/5r7GUYaf/uT4xfDilBX2fGMsxVTxJC25KzhdFeTzg1Tde
+/N0LAeLWHfe6jR/P5XDATD0ZA73DQALOxRM5uRMeWJDVaUeco/aXsdQaCz2STDI3
+h7VVFoaOlmxQW3BBEvg2VUp9DS2UjqqdwsUDtzwKfrmj/FqyBvGrvNeIMv28HCu7
+r1WE1Z0UEJhpc1BPbu7F/vl60gRF3bQjh2tL8pWThxTJe6Qy+pLoSShyi85AM9XK
+scCmUtQWjy7KQDL8XVFvuCWvMzknZQjJcncbKddPaaSIDkKUpz9FDv+wSJj/LKf7
+bGSFPM6sblioLbLNJByRYI8G7VHvKDbUnYHbHp75NTGA2eDeNqx5bC2G/EJUTwLM
+bfcZr9hv+z1QpvSLEpar30kJjc1QMQcf60ToGYIC93rsVAKou2GPGry4h/nzwro0
+jjFWNgORTXllfcQDbDNOPkV1kFFibPbAU4faZMgC+xwIwDBsndvcvXjLaRUa4fmw
+1xNkOO5Lj9AuvTXdCc9yUXRzmPZhU6Q4YB2daWvs3vbMTtvkAXGyQL4b2HD+NYZs
+cMUtbteGgQzwM1gpMBn4GX53vhlCXq28r3cH1/1tLDweglSrxyvZbB7pZU7BAmLk
+TEj2fXcvdcX+TtYhC10=
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/ocsp_update/multicert/server_ocsp_ecdsa.pem.ocsp b/reg-tests/ssl/ocsp_update/multicert/server_ocsp_ecdsa.pem.ocsp
new file mode 100644
index 0000000..793aff1
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert/server_ocsp_ecdsa.pem.ocsp
Binary files differ
diff --git a/reg-tests/ssl/ocsp_update/multicert_both_certs.crt-list b/reg-tests/ssl/ocsp_update/multicert_both_certs.crt-list
new file mode 100644
index 0000000..0ec641f
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert_both_certs.crt-list
@@ -0,0 +1,2 @@
+multicert/server_ocsp.pem.rsa [ocsp-update on ssl-min-ver TLSv1.2] *
+multicert/server_ocsp.pem.ecdsa [ocsp-update on ssl-min-ver TLSv1.2] *
diff --git a/reg-tests/ssl/ocsp_update/multicert_ecdsa.crt-list b/reg-tests/ssl/ocsp_update/multicert_ecdsa.crt-list
new file mode 100644
index 0000000..8d28025
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert_ecdsa.crt-list
@@ -0,0 +1 @@
+multicert_no_ocsp/server_ocsp_ecdsa.pem [ocsp-update on] *
diff --git a/reg-tests/ssl/ocsp_update/multicert_ecdsa_no_update.crt-list b/reg-tests/ssl/ocsp_update/multicert_ecdsa_no_update.crt-list
new file mode 100644
index 0000000..22935ba
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert_ecdsa_no_update.crt-list
@@ -0,0 +1 @@
+multicert_no_ocsp/server_ocsp_ecdsa.pem *
diff --git a/reg-tests/ssl/ocsp_update/multicert_no_ocsp/server_ocsp_ecdsa.pem b/reg-tests/ssl/ocsp_update/multicert_no_ocsp/server_ocsp_ecdsa.pem
new file mode 100644
index 0000000..c33cf58
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert_no_ocsp/server_ocsp_ecdsa.pem
@@ -0,0 +1,63 @@
+-----BEGIN CERTIFICATE-----
+MIIEODCCAiCgAwIBAgICEBYwDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRAwDgYDVQQDDAdSb290IENB
+MCAXDTIyMTEyMzEwMzk1NloYDzIwNTAwNDEwMTAzOTU2WjBIMQswCQYDVQQGEwJG
+UjEdMBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxGjAYBgNVBAMMEWVjZHNh
+LmhhcHJveHkuY29tMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB5Id0dJy6Vubt
+/ICfwLOOwgvyeOHOvC/yrqU/NCBNDVZLcOXbncm8Lxzl9Rn2t0VV9pla82/Qlexu
+2jhx8LD3du8AmEn/4tkJMz85Jv4TN/eY7Tsfbqy2NtX17eBWkDA/S1v+9uw9m7UJ
+mzwHIkQHi4S+flXt2ZtQKwgmYcuFYsP6jSGjgbswgbgwMgYIKwYBBQUHAQEEJjAk
+MCIGCCsGAQUFBzABhhZodHRwOi8vMTI3LjAuMC4xOjEyMzQ1MB0GA1UdDgQWBBTS
+Tdzvp9SeMDDfWVNdLPzVCaE/oDBjBgNVHSMEXDBaoUKkQDA+MQswCQYDVQQGEwJG
+UjEdMBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxEDAOBgNVBAMMB1Jvb3Qg
+Q0GCFB4L4lCTIAmZTjzoVXNPaWeDYX8XMA0GCSqGSIb3DQEBCwUAA4ICAQBsoRvT
+LPipFUSvGWWFphrqhri40e6GEKio2RNrHSwq6PBPd+FAjIan1yoZX3C/I/octhoq
+/jHAlCB5GQzU3R3M/gaCyDk4x3wbR52zSNzgyh464B7HwlNyC9jCeh3yB8ylUZCu
+Lc8NRTYavceUoDq2ebO8wpWX0LBd0oh7hMcQzWQrmU1B0NYVsTn65Ogcfokz2r0M
+A3YjwT8vH9i9QFx1Fxy4OYJJQmskKrwAQ+MEtyBJvck2nthZA7KNX+OxuJjOh+lW
++WpTudaoMUd188zHFFjeM4C40uPsePlf1gpdjuTdir1sIH8GNa9XP1wEtvD6mNFU
+6KCFSuZSkBqo2iD6yYzsd1H2DSMVQL67ATP8zSMjEccDYwkO72BR3InxWDFnFEQN
+wosdBFKqqKNKkkdSW1QUsVd90Bi5pHFW0l4FaDk2SJRfzwa1Dc+LfQv9Wf+LcENW
+6HOjqcRdU1PU1evVmq5xoHRDovQGNCStfwX3eW+jnHFYqovg51g5pEPEsmQccJXj
+DMCGoQjM+4i+R0GhyJZ/Kr2Lnj5RyT6RVK8hNCx5NjJBK5z/pJK9pbPGoS9fkK8N
+iQvPgw2+Y3rcVKHUw2epz/2mEzDb4rRiSIOIeuHB4PBL41jUNPwSxkjtjkPwVMuU
+TlD6A5wDj3Sq0B4MoxWgIOyWENABvGl+VBtDNQ==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBkWJB8IW867HHc2iB
+7J714zyea0hVD1Z/MEuEyKRZ7aekbjEQKmUfc5MLlQS0nedCqmiLuXObG/PyxxWs
+mWTeH5qhgYkDgYYABAHkh3R0nLpW5u38gJ/As47CC/J44c68L/KupT80IE0NVktw
+5dudybwvHOX1Gfa3RVX2mVrzb9CV7G7aOHHwsPd27wCYSf/i2QkzPzkm/hM395jt
+Ox9urLY21fXt4FaQMD9LW/727D2btQmbPAciRAeLhL5+Ve3Zm1ArCCZhy4Viw/qN
+IQ==
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIFGjCCAwKgAwIBAgIUHgviUJMgCZlOPOhVc09pZ4NhfxcwDQYJKoZIhvcNAQEL
+BQAwPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMB4XDTIxMDQyMjE0MDEyMFoXDTQ4MDkwNzE0MDEy
+MFowPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEAti+5onUeFJNyF5s6xlnBxDnFhw7Q5VbBestHeQttjBWN31zq5yaf/+CYXdu+
+lY6gNZj6JBiFJ5P7VXX3DqUIJBX6byXWfIUWM+auBAMKlTz0+hWrF/UxI/3uG67N
++Z6NVffEPYbA4Emqozr0DIicWorRyHnrhEQQP87xBCUboUr3QEkNngfiJ0fPm3fj
+7HfQemGL2OnTA8qdy0q1l4aUhVr9bgedP2Klvs0XhbszCGLI0Gq5lyNadlH1MEiw
+SXa9rklE6NCNcyamO7Wt8LVrg6pxopa7oGnkLbnjzSuE+xsN0isOLaHH5LfYg6gT
+aAHpnBHiWuDZQIyzKc+Z37gNksd46/y9B+oBZoCTcYMOsn7PK+gPzTbu3ic4L9hO
+WCsTV0tn+qUGj6/J98gRgvuvZGA7NPDKNZU5p34oyApBPBUOgpn6pCuT5NlkPYAe
+Rp/ypiy5NCHp0JW3JWkJ4+wEasZM34TZUYrOsicA0GV4ZVkoQ3WYyAjmLvRXmo/w
+Z3sSlmHvCg9MrQ9pk24+OtvCbii0bb/Zmlx0Y4lU5TogcuJffJDVbj7oxTc2gRmI
+SIZsnYLv2qVoeBoMY5otj+ef0Y8v98mKCbiWe2MzBkC2h5wmwyWedez8RysTaFHS
+Z4yOYoCsEAtCxnib9d5fXf0+6aOuFtKMknkuWbYj6En647ECAwEAAaMQMA4wDAYD
+VR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAjVzxHzq/87uj24It5hYj4mq4
+ero0zix4fA4tJNuTpZ/5r7GUYaf/uT4xfDilBX2fGMsxVTxJC25KzhdFeTzg1Tde
+/N0LAeLWHfe6jR/P5XDATD0ZA73DQALOxRM5uRMeWJDVaUeco/aXsdQaCz2STDI3
+h7VVFoaOlmxQW3BBEvg2VUp9DS2UjqqdwsUDtzwKfrmj/FqyBvGrvNeIMv28HCu7
+r1WE1Z0UEJhpc1BPbu7F/vl60gRF3bQjh2tL8pWThxTJe6Qy+pLoSShyi85AM9XK
+scCmUtQWjy7KQDL8XVFvuCWvMzknZQjJcncbKddPaaSIDkKUpz9FDv+wSJj/LKf7
+bGSFPM6sblioLbLNJByRYI8G7VHvKDbUnYHbHp75NTGA2eDeNqx5bC2G/EJUTwLM
+bfcZr9hv+z1QpvSLEpar30kJjc1QMQcf60ToGYIC93rsVAKou2GPGry4h/nzwro0
+jjFWNgORTXllfcQDbDNOPkV1kFFibPbAU4faZMgC+xwIwDBsndvcvXjLaRUa4fmw
+1xNkOO5Lj9AuvTXdCc9yUXRzmPZhU6Q4YB2daWvs3vbMTtvkAXGyQL4b2HD+NYZs
+cMUtbteGgQzwM1gpMBn4GX53vhlCXq28r3cH1/1tLDweglSrxyvZbB7pZU7BAmLk
+TEj2fXcvdcX+TtYhC10=
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/ocsp_update/multicert_no_ocsp/server_ocsp_rsa.pem b/reg-tests/ssl/ocsp_update/multicert_no_ocsp/server_ocsp_rsa.pem
new file mode 100644
index 0000000..26c10e3
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert_no_ocsp/server_ocsp_rsa.pem
@@ -0,0 +1,86 @@
+-----BEGIN CERTIFICATE-----
+MIIEvjCCAqagAwIBAgICEBUwDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRAwDgYDVQQDDAdSb290IENB
+MCAXDTIyMTEyMzEwMzkwNFoYDzIwNTAwNDEwMTAzOTA0WjBGMQswCQYDVQQGEwJG
+UjEdMBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxGDAWBgNVBAMMD3JzYS5o
+YXByb3h5LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIRBd2HB
+WFxKohqOWKCZkQcszMx0tpA48sxlDgjsy6iVEycM1eOQopbFOiSAig2gf+8llKUv
+DM66f98FsBKJ/rVksOS07rDBOO9LCGE7JF8o/Cjc3vIX2gvTd0H19ENHFlxCSBn8
+q5NsLmCSCFHFDSPXL3uhrX/9ScBeU1j7M8nF/AEX50q1ubGRHMbYrBkhUDlI+s92
+fvFpuFPf9vcjPLihHEofYKErKVeNfn+3aD/V55Aw1NO15Dt1Vc+TypeuL7jqgJRg
+OVk2MJmedXKUA4A8SaY4gqVKy1aAe6JYWrCGqr8oHNt3nwqMYyhLkeyqmLh+VMXv
+Bdqj3JbwiGGRou8CAwEAAaOBuzCBuDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUH
+MAGGFmh0dHA6Ly8xMjcuMC4wLjE6MTIzNDUwHQYDVR0OBBYEFNGC81nNOAJDX1V+
+vlnE5/iy9ciNMGMGA1UdIwRcMFqhQqRAMD4xCzAJBgNVBAYTAkZSMR0wGwYDVQQK
+DBRIQVByb3h5IFRlY2hub2xvZ2llczEQMA4GA1UEAwwHUm9vdCBDQYIUHgviUJMg
+CZlOPOhVc09pZ4NhfxcwDQYJKoZIhvcNAQELBQADggIBAJmKCsKn0LGUJ5xhSd0c
+d8Aq7TpJImXNUNqoQsyLU5FK8qF3HfJBA2pLkROLZKTXGnwSVndOpxlZy7IpdhZZ
+Ya23mxi6G3iXYAGmiVwGXxZfCwISqARr+CR8psIUQLdi21P5UkLG2LU0+b/ManQD
+4MPvyzi7qf4qaao/miZiT9idrdy0XNQoRy1vJzMMfcRhzWzuGvnr2NVOhZpuDe8p
+K6Hc+8AGZX8qY0DQ30YHU4Ygq0NGRR/oHOoAdJSAuIvfLkKiNZ0s3XTOKu8bogGh
+NbkffborINbB6MG8ZSM+KUrsQbFl6e2lk6VVk1gYIMx/L3MF3WFK9212+8ak0pr1
+JZOd87aWg3WcNqpRgcu3FXZSDfF5JH8jBAoXTZ5YHLMRjrfFLaMmyPC8egcDpogR
+sM4wXyo+5SEX4YWTsd2FRcmPbOFcmwQOy/zmZQyFPnpp+ORRDEkTJmT/VRoexHrt
+8EcKX/CIJ+nzBQtEVThgOCWrE6c9MF+MGkI+TMXy932jEvK14GU2U4aE7uhvyiJt
+RJ+iZGTqwsu7wOqvP8+SsxhpY4ZlNL+LSeHLoq2nBmBwCgHj0ikdEMMLbjciUVGu
+Zb44d9hPea+nfljju5m4VLmonGW2cbzFL4r5mC0/xk6JrB9buw5swkwhslR0guCu
+3knMr1pjkbf8W6DDGKvxHJIX
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCEQXdhwVhcSqIa
+jligmZEHLMzMdLaQOPLMZQ4I7MuolRMnDNXjkKKWxTokgIoNoH/vJZSlLwzOun/f
+BbASif61ZLDktO6wwTjvSwhhOyRfKPwo3N7yF9oL03dB9fRDRxZcQkgZ/KuTbC5g
+kghRxQ0j1y97oa1//UnAXlNY+zPJxfwBF+dKtbmxkRzG2KwZIVA5SPrPdn7xabhT
+3/b3Izy4oRxKH2ChKylXjX5/t2g/1eeQMNTTteQ7dVXPk8qXri+46oCUYDlZNjCZ
+nnVylAOAPEmmOIKlSstWgHuiWFqwhqq/KBzbd58KjGMoS5Hsqpi4flTF7wXao9yW
+8IhhkaLvAgMBAAECggEAIQA46sKU6sqQsnGseb536sNqAuZom4oqQ4g/vUhg9Rrl
+oYvZXyQ6/cYO4QbV69qNsb293o3j8z2kJKFFswqN7PNIFHl1SdOdAlDFsYVRaRFQ
+Al5Cn0QGW4cTrfjST2tQkArV9O4QXgPTerNVshmqUrQiHAZWxaYNHhwrTfu4i3Mo
+v4hfPfXuVLFWzdVFyvBQ+u+yxwqCnKKrKj7uXiPyFwQ0g4wFKs8O48ZZoVryZFJn
+nuUKBr0JBaHpgPTfx1QavvoUeQzDshEAcMXq0Lh4LTzp95jfwsiBj3fEwcrXuJyr
+o3TGHwGHILL8vKpZpw/Ub9Rr4xpyb0Ij+UHzVir5+QKBgQC3a4YNMOy9UD3XSmwU
+qMn1YXpZYv6hz7rFYrQFPjd42b8Orl6v0KrsPVk2hc4KQpiMaEa+IgnD9guMdri4
+oNMri9reoLHDzxN/Wh/jTVVaO2b3mljzF62JF6SJOjeLYvKRqRH4whdCku/1D0xR
+DfhBIVZzCj2tTI1CMZl42vNK6wKBgQC4lv4PakdIY6W3bu2/fuX4PwnrSUmsJV+d
+UAmCls38hnoNHIDrEWbF+StSA/PsHQGOa4w1iYBsD3PptQ43zF7nwvjxKYeXu1/A
+y+0pW/ADlcAm+PcJfgym0663mWZG5bA1s3C1qMM30PM+Z0jTO/GUOeNFofuOWVK+
+mUiGG5U/DQKBgQCmbz74gUiQkFtNHA7uwCpiKs2mhpmfoqtLqMDJcSdM1ej0HW12
+A9bU/uYQ/2FzFfLulUB8Ds7lrkHUd3YusmBrx0AXe6FSmHiMuu7shqPIeNZ6HuhP
+zVB+caGvk9AK/wI1AkF4hEYu9r4elH8fnZmDIAkd4lENC8WyJueoLqVNeQKBgAsj
+uZNOk5yvvslyHVDoJJK1ozCazKJh4wJIWTqTRT0PFICEDtegxjX+UnnxmR/PpE9m
++CAm+yQKTrF05rXBVJzh7EoJepBSk3W8GMTdMn/U4rK3ZZkiDTtoHOwhisWOiPLE
+sHGWDKnqpzNF4mQ1AuAyGiASpW6yv0aXU4QcWAZlAoGBAISfKc6i2akMXufuqj5q
+B6OnFMkFR6JPJhxYo1aYKX0He4WW5RmXhm0lB6UKC7CtE9uofhEn3Tl2AcvwmY7G
+6UE9J/dAUVLGQV07aPyjAMq4ky+ZruI6ptxYgsdPmYZbXhMKIa2vNpB8/bgOKPA5
+3SgdB3ibaIMQtiJqdKjCbWqP
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIFGjCCAwKgAwIBAgIUHgviUJMgCZlOPOhVc09pZ4NhfxcwDQYJKoZIhvcNAQEL
+BQAwPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMB4XDTIxMDQyMjE0MDEyMFoXDTQ4MDkwNzE0MDEy
+MFowPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEAti+5onUeFJNyF5s6xlnBxDnFhw7Q5VbBestHeQttjBWN31zq5yaf/+CYXdu+
+lY6gNZj6JBiFJ5P7VXX3DqUIJBX6byXWfIUWM+auBAMKlTz0+hWrF/UxI/3uG67N
++Z6NVffEPYbA4Emqozr0DIicWorRyHnrhEQQP87xBCUboUr3QEkNngfiJ0fPm3fj
+7HfQemGL2OnTA8qdy0q1l4aUhVr9bgedP2Klvs0XhbszCGLI0Gq5lyNadlH1MEiw
+SXa9rklE6NCNcyamO7Wt8LVrg6pxopa7oGnkLbnjzSuE+xsN0isOLaHH5LfYg6gT
+aAHpnBHiWuDZQIyzKc+Z37gNksd46/y9B+oBZoCTcYMOsn7PK+gPzTbu3ic4L9hO
+WCsTV0tn+qUGj6/J98gRgvuvZGA7NPDKNZU5p34oyApBPBUOgpn6pCuT5NlkPYAe
+Rp/ypiy5NCHp0JW3JWkJ4+wEasZM34TZUYrOsicA0GV4ZVkoQ3WYyAjmLvRXmo/w
+Z3sSlmHvCg9MrQ9pk24+OtvCbii0bb/Zmlx0Y4lU5TogcuJffJDVbj7oxTc2gRmI
+SIZsnYLv2qVoeBoMY5otj+ef0Y8v98mKCbiWe2MzBkC2h5wmwyWedez8RysTaFHS
+Z4yOYoCsEAtCxnib9d5fXf0+6aOuFtKMknkuWbYj6En647ECAwEAAaMQMA4wDAYD
+VR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAjVzxHzq/87uj24It5hYj4mq4
+ero0zix4fA4tJNuTpZ/5r7GUYaf/uT4xfDilBX2fGMsxVTxJC25KzhdFeTzg1Tde
+/N0LAeLWHfe6jR/P5XDATD0ZA73DQALOxRM5uRMeWJDVaUeco/aXsdQaCz2STDI3
+h7VVFoaOlmxQW3BBEvg2VUp9DS2UjqqdwsUDtzwKfrmj/FqyBvGrvNeIMv28HCu7
+r1WE1Z0UEJhpc1BPbu7F/vl60gRF3bQjh2tL8pWThxTJe6Qy+pLoSShyi85AM9XK
+scCmUtQWjy7KQDL8XVFvuCWvMzknZQjJcncbKddPaaSIDkKUpz9FDv+wSJj/LKf7
+bGSFPM6sblioLbLNJByRYI8G7VHvKDbUnYHbHp75NTGA2eDeNqx5bC2G/EJUTwLM
+bfcZr9hv+z1QpvSLEpar30kJjc1QMQcf60ToGYIC93rsVAKou2GPGry4h/nzwro0
+jjFWNgORTXllfcQDbDNOPkV1kFFibPbAU4faZMgC+xwIwDBsndvcvXjLaRUa4fmw
+1xNkOO5Lj9AuvTXdCc9yUXRzmPZhU6Q4YB2daWvs3vbMTtvkAXGyQL4b2HD+NYZs
+cMUtbteGgQzwM1gpMBn4GX53vhlCXq28r3cH1/1tLDweglSrxyvZbB7pZU7BAmLk
+TEj2fXcvdcX+TtYhC10=
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/ocsp_update/multicert_rsa.crt-list b/reg-tests/ssl/ocsp_update/multicert_rsa.crt-list
new file mode 100644
index 0000000..5b9a341
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/multicert_rsa.crt-list
@@ -0,0 +1 @@
+multicert_no_ocsp/server_ocsp_rsa.pem [ocsp-update on] *
diff --git a/reg-tests/ssl/ocsp_update/ocsp.haproxy.com.pem b/reg-tests/ssl/ocsp_update/ocsp.haproxy.com.pem
new file mode 100644
index 0000000..17a4abf
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/ocsp.haproxy.com.pem
@@ -0,0 +1,84 @@
+-----BEGIN CERTIFICATE-----
+MIIFvDCCA6SgAwIBAgICEAkwDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRAwDgYDVQQDDAdSb290IENB
+MB4XDTIxMDUyNzA5MjAyN1oXDTQ4MTAxMjA5MjAyN1owRzELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRkwFwYDVQQDDBBvY3NwLmhh
+cHJveHkuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2CY6WYOd
+Tu9g91tHEsvnPpDicSTzU+jvirLUHlDvak/u8Kd/uTcon43G6H0B8+YMbDl3rIi6
+DniNicsTo9ivZrfeo3QHBf8UW2Mbx1Jda7uEKoBx6CJypsyN4dyNXDueT5UyBWGd
+jt6zvPEZbWLsMBkqyx6HZzKhGP8DGE0opVQJxBqwTOsYTL5bEIKsUp9Wt+X3mrCO
+fyCjrUU0XYoclJnK2RIQH2GSc5X6YBZq2ozh+J5S/tb9YRZ4GglF2PHjpZvOJ0I1
+HuBrVCkheN63hBymE0IfstjWTSoAHrT6NZkAvAV/2PsiXQuwihwTaKhYY8NTP0pH
+qNB++ShUMhuLpp38/IHr8ac1A58B5zSxKNtp5y1miZoM3i9oL7v3RxIg5xqKS21G
+zr4xJfdXzNqL4azxfcLREJ4oLiRDDEfxO7IYw5pOZcQlOnHYOUaJ1aKbqOdVTvlQ
+muwCwATfqGgFgfM4Qc95UxpxvFH3I+PMX8I/djZgtNOYwAGxAhITat2nPHqm3sQX
+W86zTrWhlCT+UG/Tx3YxhPPEWjJlFE+1yh9nEHiuqW9YflcDObfGY+LaPBBBc4yR
+8wtcQxGldaNGhsk87+hvRQM3Rvy69LhtAf2ppBfQFUo41qnI+tWiBpA4U3gvmend
+/y2jyHQImSartuHP701DLtg0Poj3E3mXd9cCAwEAAaOBujCBtzAJBgNVHRMEAjAA
+MB0GA1UdDgQWBBSJgNJnuyjilp8FTQAAE11jjwenkzBjBgNVHSMEXDBaoUKkQDA+
+MQswCQYDVQQGEwJGUjEdMBsGA1UECgwUSEFQcm94eSBUZWNobm9sb2dpZXMxEDAO
+BgNVBAMMB1Jvb3QgQ0GCFB4L4lCTIAmZTjzoVXNPaWeDYX8XMA4GA1UdDwEB/wQE
+AwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCTANBgkqhkiG9w0BAQsFAAOCAgEA
+qz05vqeL54ahtAmPA0gwUuuEGnS/OKgmjs0IPfwgcZ+o355XVs66HJv2KPuQ1ed8
+gbu6Q4B+Hb3QW/42DsFAuFeX0FOmoc9AGBvNnWIu/guys3Wdf/OZ08VhQz96vai8
+bdCcdyBbTVj/P3zx0pZRQ1ZS7V1o9iH73KCckyN6Qi2rYI0R04KfUMqQ/ZBWvUM9
+N231qf6pzcGbIfECb+Gk3DRvzqylagDQztiCMuEnZ2caUhEq2hvKNXcga1KaWYVr
+aryCee3pL2GqyY615Dt8Jtt2adI7hp8FLUJs2BZtaBelxUwqdfzOXjypYFpIaZY5
+uMQqYTinolPdtfKY67oe7XylyL/rMAbdzCWHpG6Z+vFP16lnHE2dpO2OQKNCVoJb
+RoNsirHLwOugGJFpXxhXNfyeLiumMpbWZ1IT5WkL85y/y8JpwYM6H1SMnVYoqNEc
+qrboP1xo4olIPMskbYMXK4MLJzWf1mvRRjhosX/CWC9KhVL8tZiDJnFhXJLG8sX9
+CRjkKcuXXITpHVFpuIL4TkzmvHQ7Q7+gKRdOJLgXzqVccPZRXkyW9miev8cwRq4w
+eQysfIhT4uEugBog7GTDQWEMUE0pphosddKsFth8jFXFWeuf9XLD1Zx8HczZQtC8
+JgAYxF/HFELzZ2aPdBxJ1WzlH2ehTBxC07Ag0+FBxEk=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEA2CY6WYOdTu9g91tHEsvnPpDicSTzU+jvirLUHlDvak/u8Kd/
+uTcon43G6H0B8+YMbDl3rIi6DniNicsTo9ivZrfeo3QHBf8UW2Mbx1Jda7uEKoBx
+6CJypsyN4dyNXDueT5UyBWGdjt6zvPEZbWLsMBkqyx6HZzKhGP8DGE0opVQJxBqw
+TOsYTL5bEIKsUp9Wt+X3mrCOfyCjrUU0XYoclJnK2RIQH2GSc5X6YBZq2ozh+J5S
+/tb9YRZ4GglF2PHjpZvOJ0I1HuBrVCkheN63hBymE0IfstjWTSoAHrT6NZkAvAV/
+2PsiXQuwihwTaKhYY8NTP0pHqNB++ShUMhuLpp38/IHr8ac1A58B5zSxKNtp5y1m
+iZoM3i9oL7v3RxIg5xqKS21Gzr4xJfdXzNqL4azxfcLREJ4oLiRDDEfxO7IYw5pO
+ZcQlOnHYOUaJ1aKbqOdVTvlQmuwCwATfqGgFgfM4Qc95UxpxvFH3I+PMX8I/djZg
+tNOYwAGxAhITat2nPHqm3sQXW86zTrWhlCT+UG/Tx3YxhPPEWjJlFE+1yh9nEHiu
+qW9YflcDObfGY+LaPBBBc4yR8wtcQxGldaNGhsk87+hvRQM3Rvy69LhtAf2ppBfQ
+FUo41qnI+tWiBpA4U3gvmend/y2jyHQImSartuHP701DLtg0Poj3E3mXd9cCAwEA
+AQKCAgB6w0uEp7HisSablqYJUPHnoRZbOKdS0wup9ONwzHsOIJQO7rMmGOPjqvx7
+8vP2+IO5u/Hydj1mFqYcytA+0MTeTDQRFccfar6/IM0YKfmRRJFOKmGHfHktryQu
+Ubuf1OSXQp+EWurHyEjBWRYeAH8w2jpp3s78l87TiZLSbJBXRiG91YKoTSYiAENs
+XytMSd9Q1zYID5r/LSSJNrMFJXoSFD8XhqDNkfdB2r63cEQEGNwG/rUYtDZ4u/A+
+qWGYU9n9pz4xIfNVtBSBWlL+eVA1oqfYbEfgpjMg5GfpCNTLODkokN8J96iOvCLq
+bgO//00kbD2NxrxobvKOxI79XpOzZCRyfwcxIi8sIALT3b6pRwm6+NSY+7cJ5s5x
+FKDngYc5IYy3ByKmFIjRj5rl/fY6RxwX5eMjEXOGe4TyuftBfBxNzpF6oDbc2Ws9
+Ay0PZv6fPLBSKJOEEOXg2v3djdN5DBpqJVFeMkse/uh4XLcUWXuk62fejmKCdOue
+I5xPtAva9ehLykUkgExch46gncNr12npDVixY4nKbLbNaZf8IgpJyA9UdbRH120m
+kUGZp9qRiUbDNA9dfd5+Boq8vfqvsS7Sbl5o0103qW6QWq/aEDNAZGLCssehAlGG
+PmJ0VsSVImFdUdOeL4/cDVsptd15weTnxaU9oLw2yrKy4GdXgQKCAQEA/m3ECOGU
+R4wOGO31NHNRsN0Y9luyZ+jC6wPnpT/9+pwDUB0TqZ0sJh92i0o6jecXKwX/xNbt
+BBsk8v74l3adi0YlZf1qFOPTXURsm07OwM9hjuutG4tjYibwpdokOneJl8LqOQRe
+zPuy0dXgQW35UyCeqBakMtn8g5zorXD4p4+XCvNlECDZCj2hpnjQdrxRWzwwEH9a
+cJJaxrDp8XO+zaQAYndRcxj/SsCuw8se8iWBchvkCx45ino4Jz0iEbGjhGpOccVC
+9UVAap53V6nQNTctLcNl2g398HKAoGGzV4wx7NJ7+ne2gzRFmj3etjmpyzLxCrIM
+xaibh/DCZjBJ4QKCAQEA2Xvx7OrWIsNd/LX70XvQm2RBO6dA47VIW61WOMm3eah/
+bTxJRp2JLgl5ANBAyxS65lhGpBC3/W3OEKDlYfM21wQRogUSuhIXQaOdeLh4pts3
+IfHU3WMxNU4eSws8Gi4W87SvASj8shX5ld3zZDLX8GEOqoYGS8HvcdJwFZftlIaM
+YDQ2oNKov+ob5mh2yS06hm7KOmxr7l5YWGWKD6aK2Dse0Ppj7nzVlaQfeuR07CpJ
+OFd2JiPyahcuG74Yf5t6k/6qAto2T/v9v8cAgzDKpTXzaoCfDwn1hyefeMVxp0lF
+ttdAmqWLXvI3eiEQILKmDTpCiZ6v48rRb4ZJBXeotwKCAQAkbUS+3MUlBTlTemY7
+7zLH9q/HPdOqKtoVWcbFkwbi5YlX5AHXq+gRQTnwsVz2yho4D7DR1s+yYcyFednP
+nazqrs1V79VLTl8JoG1IQx0437ghBT8QjYFaIScdJ8E+GbU6ZC6yoRyNjo/ImS11
+ULB8pVPxzuQNX8ZWdZWel2kSXG2MpNJYX8uTOsW1FuEJzuZ7AIAFLKafLWUPw26L
+Ij40JQHlFx4zM2YBptqer6srkhEZbELXEKm+WMdHXupMzDkUEUBP66Utho+1dCC0
+DV0A8Xhnb+1aLdyom0wtKi/KHglb1broXlFkMYyxi6AiSNk1fYKjPGC1v/EcomzC
+wrEhAoIBAQCyQL9qEpROS9h172alLRkus74vuYca25Oh6HFZ/CMQaMWAb8ATS72K
+6SKvQwFIMgZ6E3JauIVFB0G1KVq4rJKPKvuU0xmlPnynRQYlUvU4tUX74W05wzoq
+2YtEsMGjJ5GST858Ye6zvAUkC5WY039fuv09ULpKT3sEzJknaa3FZX4av9Digabk
+HWqer5Jkk1h7pMTFm+Xeqp84XIkLCNKWJea9G+zaJKEelDVlEWivxHzc2/qvihj/
+UV5uSKFlvbZ7JGiOC/ImHoC9Ncs6u7vsK0sGSMOVnPELxLMVVqcvmIO2N7jwx6xy
+to434G+KjUJCZzTv/Qtm5e5AvUyOWaQDAoIBAA4YxhRf2Zy1wXENoQP6wTZMmwHq
+p1w7Jqk7+u+W1UEhaugN5v7D5Xw6tnVF7tdiaUMREPUZKu9bj7T61DJFS8LlCaTQ
+i6DwV78vXQY9QOaZ85oqC/Cq8ehnTX8Y5nLvTC8daKZsmRv8z/kG84yOGXWX0zVs
+sskcLj0Wk5rz0kUrxiDkDToEmDAHXGmaTW1Z/z4HFGhvRXx3bAViSJgPEVog4+i2
+10E7RevBeWf2dmfizj0qj9RzvJVmB59rleeWCLCAcdsUjwTSMu4NP+KszqiqKyoY
+tuC6t5cgGbPJAY+I0a6+gWoLZpnZu4/dBrj664j3k9a8AhmY9zlrwTybdYM=
+-----END RSA PRIVATE KEY-----
diff --git a/reg-tests/ssl/ocsp_update/ocsp_update_rootca.crt b/reg-tests/ssl/ocsp_update/ocsp_update_rootca.crt
new file mode 100644
index 0000000..bed2061
--- /dev/null
+++ b/reg-tests/ssl/ocsp_update/ocsp_update_rootca.crt
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFGjCCAwKgAwIBAgIUHgviUJMgCZlOPOhVc09pZ4NhfxcwDQYJKoZIhvcNAQEL
+BQAwPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMB4XDTIxMDQyMjE0MDEyMFoXDTQ4MDkwNzE0MDEy
+MFowPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEAti+5onUeFJNyF5s6xlnBxDnFhw7Q5VbBestHeQttjBWN31zq5yaf/+CYXdu+
+lY6gNZj6JBiFJ5P7VXX3DqUIJBX6byXWfIUWM+auBAMKlTz0+hWrF/UxI/3uG67N
++Z6NVffEPYbA4Emqozr0DIicWorRyHnrhEQQP87xBCUboUr3QEkNngfiJ0fPm3fj
+7HfQemGL2OnTA8qdy0q1l4aUhVr9bgedP2Klvs0XhbszCGLI0Gq5lyNadlH1MEiw
+SXa9rklE6NCNcyamO7Wt8LVrg6pxopa7oGnkLbnjzSuE+xsN0isOLaHH5LfYg6gT
+aAHpnBHiWuDZQIyzKc+Z37gNksd46/y9B+oBZoCTcYMOsn7PK+gPzTbu3ic4L9hO
+WCsTV0tn+qUGj6/J98gRgvuvZGA7NPDKNZU5p34oyApBPBUOgpn6pCuT5NlkPYAe
+Rp/ypiy5NCHp0JW3JWkJ4+wEasZM34TZUYrOsicA0GV4ZVkoQ3WYyAjmLvRXmo/w
+Z3sSlmHvCg9MrQ9pk24+OtvCbii0bb/Zmlx0Y4lU5TogcuJffJDVbj7oxTc2gRmI
+SIZsnYLv2qVoeBoMY5otj+ef0Y8v98mKCbiWe2MzBkC2h5wmwyWedez8RysTaFHS
+Z4yOYoCsEAtCxnib9d5fXf0+6aOuFtKMknkuWbYj6En647ECAwEAAaMQMA4wDAYD
+VR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAjVzxHzq/87uj24It5hYj4mq4
+ero0zix4fA4tJNuTpZ/5r7GUYaf/uT4xfDilBX2fGMsxVTxJC25KzhdFeTzg1Tde
+/N0LAeLWHfe6jR/P5XDATD0ZA73DQALOxRM5uRMeWJDVaUeco/aXsdQaCz2STDI3
+h7VVFoaOlmxQW3BBEvg2VUp9DS2UjqqdwsUDtzwKfrmj/FqyBvGrvNeIMv28HCu7
+r1WE1Z0UEJhpc1BPbu7F/vl60gRF3bQjh2tL8pWThxTJe6Qy+pLoSShyi85AM9XK
+scCmUtQWjy7KQDL8XVFvuCWvMzknZQjJcncbKddPaaSIDkKUpz9FDv+wSJj/LKf7
+bGSFPM6sblioLbLNJByRYI8G7VHvKDbUnYHbHp75NTGA2eDeNqx5bC2G/EJUTwLM
+bfcZr9hv+z1QpvSLEpar30kJjc1QMQcf60ToGYIC93rsVAKou2GPGry4h/nzwro0
+jjFWNgORTXllfcQDbDNOPkV1kFFibPbAU4faZMgC+xwIwDBsndvcvXjLaRUa4fmw
+1xNkOO5Lj9AuvTXdCc9yUXRzmPZhU6Q4YB2daWvs3vbMTtvkAXGyQL4b2HD+NYZs
+cMUtbteGgQzwM1gpMBn4GX53vhlCXq28r3cH1/1tLDweglSrxyvZbB7pZU7BAmLk
+TEj2fXcvdcX+TtYhC10=
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/rootCA_crl.pem b/reg-tests/ssl/rootCA_crl.pem
new file mode 100644
index 0000000..cee411e
--- /dev/null
+++ b/reg-tests/ssl/rootCA_crl.pem
@@ -0,0 +1,16 @@
+-----BEGIN X509 CRL-----
+MIICmzCBhDANBgkqhkiG9w0BAQsFADA+MQswCQYDVQQGEwJGUjEdMBsGA1UECgwU
+SEFQcm94eSBUZWNobm9sb2dpZXMxEDAOBgNVBAMMB1Jvb3QgQ0EXDTIxMDQyMzA4
+MjM0NVoXDTQ4MDkwODA4MjM0NVowFTATAgIQBxcNMjEwNDIzMDgyMDM5WjANBgkq
+hkiG9w0BAQsFAAOCAgEAgECfAAcCu1yojdIa3BxpfXgnUoi/Kgp796w67fAOZ9ZS
+0r68n754rWNC6QXsolrMVB4xIHe9PWWY5aCFcdmrZOts3JWaP8/UD/CeUSK30+jR
+jPhDaZJHarHfocPAOvhR2faFmFMrT2NWC9swX1UMPXKAeWg8YubxT7ACx/Yrja3F
+3p/UAAHpGmfPpRPGC6G2zN2zmpycpsH7vDQ7vS/pImyjuOYjMY9qKJeyHhwBIZXK
+C0fuK/40HkFpcWBq6rFoiWRX8gfuKwo0i6BUDyHoFXrptvkXW/ufk+H3uM82/g4I
+ZxLaCSoST+S2aoJOzF8JtjOEjCokP0I4Qs/4uVhbd5PNofgAZhdZY/CREErlVgIa
+OT4hGgyjom7T8+QWApSWRdAkkSDpITSFnXJYXScmxfeT1nRjG9HBX3NHCgQWL8a/
+VwCrzBkCsLfXxFoCuMIKQ2JwhHMTl+gm1YaO6p9BrGMVfxgXvCPWKH0D52pM0z4L
+6F1pKV3OA/LhQMW2tfZpvoWYtlSEy9RnaThS8OdEDI2pxlnI2F4Z6BAMVHUtlBHA
+raklj6ZnD8NkzpVlU7+0OK1rSasP/UEFBXhAOHxDEGXWA8nJCVQiOUjMbitEvQRS
++L+aSMfdpXQcIA3mTJQGXMgsnR75YXllWeHv9EYMHRkoBBUuDi4QX3MvTwa97DM=
+-----END X509 CRL-----
diff --git a/reg-tests/ssl/set_cafile_client.pem b/reg-tests/ssl/set_cafile_client.pem
new file mode 100644
index 0000000..f2fe6f3
--- /dev/null
+++ b/reg-tests/ssl/set_cafile_client.pem
@@ -0,0 +1,95 @@
+Certificate:
+ Data:
+ Version: 1 (0x0)
+ Serial Number: 4103 (0x1007)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=FR, O=HAProxy Technologies, CN=Intermediate CA1
+ Validity
+ Not Before: Apr 22 15:16:27 2021 GMT
+ Not After : Sep 7 15:16:27 2048 GMT
+ Subject: C=FR, O=HAProxy Technologies, CN=Client
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public-Key: (2048 bit)
+ Modulus:
+ 00:bb:d6:23:03:04:ae:d2:41:19:3c:6a:91:f1:41:
+ 07:2f:db:87:fa:ac:d5:c3:ad:db:cd:b3:fd:fa:55:
+ 78:3d:eb:b1:50:98:ce:de:f7:1d:44:42:56:15:e6:
+ cf:f3:75:d5:54:90:39:07:54:70:d1:d2:71:f9:26:
+ 96:79:14:8b:20:e0:7c:dd:8f:d0:13:f1:16:a5:85:
+ 52:5f:ff:16:bf:3d:f3:5b:78:e8:00:6e:0b:79:6a:
+ b7:c3:17:49:df:96:1a:7f:c7:e0:cf:c6:01:03:55:
+ af:36:03:95:aa:95:93:08:75:e4:46:86:9f:af:23:
+ 69:ac:fa:65:f0:5d:5a:97:f6:36:78:b2:a7:11:a7:
+ 93:8b:6b:4b:c4:54:67:b1:82:23:91:72:0f:d9:8b:
+ d8:1a:b4:d4:99:9e:cd:3f:3c:34:73:48:ba:cd:f4:
+ 7d:c8:9f:b2:17:a8:90:9c:e6:c2:f3:46:39:8b:06:
+ af:d0:df:e7:7d:05:92:33:4d:08:80:17:e7:a7:39:
+ 49:eb:f1:35:06:ac:07:d6:0b:1a:4d:55:ae:26:1a:
+ 49:4a:a1:b2:5f:c5:8b:39:98:2c:0c:63:41:2e:be:
+ 0e:3f:5c:c3:3a:39:25:2a:23:a3:a2:d3:51:03:cb:
+ 81:5e:76:04:76:a8:fb:80:a8:5b:19:9f:6c:e3:d7:
+ 31:ff
+ Exponent: 65537 (0x10001)
+ Signature Algorithm: sha256WithRSAEncryption
+ 71:76:f0:82:f0:06:c8:ed:5a:dd:92:37:16:82:c5:9c:dd:7d:
+ 65:b7:47:ee:d5:3c:cc:cd:69:d2:57:83:6a:c1:20:ef:28:a8:
+ b9:c2:db:1b:2b:e1:36:95:e5:e7:03:84:67:64:20:ff:ed:a4:
+ 3c:8b:d5:35:32:fe:7e:c8:c5:fc:04:15:ef:be:de:56:dc:f6:
+ d8:cc:1c:fb:03:02:01:66:fa:e4:2b:3f:2c:3e:9b:46:ec:29:
+ f3:02:1b:d4:c2:be:fe:fa:4d:0c:48:e0:d7:af:30:ca:6c:b3:
+ ea:0b:60:5b:a5:17:17:6f:f6:2f:0b:25:db:7c:ce:65:a5:94:
+ 94:09:84:10:39:1e:69:16:e5:0e:bc:1e:96:68:88:54:39:83:
+ b6:0f:74:61:6a:1c:d3:b6:65:36:bc:4f:75:30:9a:84:8f:98:
+ 68:ab:61:ab:57:88:8b:7c:64:7b:7f:39:a7:56:8a:e0:88:e3:
+ 66:7d:2c:0a:eb:f3:aa:9c:a6:f4:88:e1:0b:58:66:69:06:6b:
+ 93:e8:78:52:56:fc:7f:96:69:1d:76:40:30:fa:d6:4a:c7:2a:
+ 47:24:e0:cd:14:32:74:70:ba:b7:b4:0f:33:ca:3a:3c:75:49:
+ ff:65:2e:4f:65:e3:79:14:1f:76:5e:3f:44:39:60:42:df:97:
+ 0e:f3:a2:2e
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAeECAhAHMA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNVBAYTAkZSMR0wGwYD
+VQQKDBRIQVByb3h5IFRlY2hub2xvZ2llczEZMBcGA1UEAwwQSW50ZXJtZWRpYXRl
+IENBMTAeFw0yMTA0MjIxNTE2MjdaFw00ODA5MDcxNTE2MjdaMD0xCzAJBgNVBAYT
+AkZSMR0wGwYDVQQKDBRIQVByb3h5IFRlY2hub2xvZ2llczEPMA0GA1UEAwwGQ2xp
+ZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu9YjAwSu0kEZPGqR
+8UEHL9uH+qzVw63bzbP9+lV4PeuxUJjO3vcdREJWFebP83XVVJA5B1Rw0dJx+SaW
+eRSLIOB83Y/QE/EWpYVSX/8Wvz3zW3joAG4LeWq3wxdJ35Yaf8fgz8YBA1WvNgOV
+qpWTCHXkRoafryNprPpl8F1al/Y2eLKnEaeTi2tLxFRnsYIjkXIP2YvYGrTUmZ7N
+Pzw0c0i6zfR9yJ+yF6iQnObC80Y5iwav0N/nfQWSM00IgBfnpzlJ6/E1BqwH1gsa
+TVWuJhpJSqGyX8WLOZgsDGNBLr4OP1zDOjklKiOjotNRA8uBXnYEdqj7gKhbGZ9s
+49cx/wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBxdvCC8AbI7VrdkjcWgsWc3X1l
+t0fu1TzMzWnSV4NqwSDvKKi5wtsbK+E2leXnA4RnZCD/7aQ8i9U1Mv5+yMX8BBXv
+vt5W3PbYzBz7AwIBZvrkKz8sPptG7CnzAhvUwr7++k0MSODXrzDKbLPqC2BbpRcX
+b/YvCyXbfM5lpZSUCYQQOR5pFuUOvB6WaIhUOYO2D3RhahzTtmU2vE91MJqEj5ho
+q2GrV4iLfGR7fzmnVorgiONmfSwK6/OqnKb0iOELWGZpBmuT6HhSVvx/lmkddkAw
++tZKxypHJODNFDJ0cLq3tA8zyjo8dUn/ZS5PZeN5FB92Xj9EOWBC35cO86Iu
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC71iMDBK7SQRk8
+apHxQQcv24f6rNXDrdvNs/36VXg967FQmM7e9x1EQlYV5s/zddVUkDkHVHDR0nH5
+JpZ5FIsg4Hzdj9AT8RalhVJf/xa/PfNbeOgAbgt5arfDF0nflhp/x+DPxgEDVa82
+A5WqlZMIdeRGhp+vI2ms+mXwXVqX9jZ4sqcRp5OLa0vEVGexgiORcg/Zi9gatNSZ
+ns0/PDRzSLrN9H3In7IXqJCc5sLzRjmLBq/Q3+d9BZIzTQiAF+enOUnr8TUGrAfW
+CxpNVa4mGklKobJfxYs5mCwMY0Euvg4/XMM6OSUqI6Oi01EDy4FedgR2qPuAqFsZ
+n2zj1zH/AgMBAAECggEAE60Fs948tdeN3i9HpF7scs3rO435Qmsm2DBfjWaAlvPm
+egvXt7FpBmpwfBDWfak9NIN7BdKJkuEZgUDSiFJnlIUPb2IOKNibR7FkhJvC9Tt3
+D4DlxI3Cc/CC2VPKMDqYAgSc/wa9umyyUtUjS2Apq7w1slGNzpnGCxGbtgcBY2OA
+ILjPffpVYJv87LijTIozScjx/Xdub5fWgcLtByWEDk8SxAb47qAAIAjbilpARWmf
+CHOeF+BG7ku2PT9+tLeMDabwRctNs88pef4+Dbe9+2Ess+2bdsG8As1/fw49QCnm
+ODNV1wPXdpS5wHEEdLxnQNXOQEVSRrVOhz5KWG3F0QKBgQDo/LXfjzcrNoVRG29/
+4l9aInk0+5tE4MCsM828LBmGxbYsQqt2g3ZGQCNW2IfnwQOYlujIm+F7ZYivT5Dq
+j3QvuuHjo/EGz4JuJef1oSkWeYVLm+gSzlmt5EzYximtfnEBBeJJh1Zl0R8nQfWh
+RjRMTboVC22dcBSVJdCM+lg8uQKBgQDOY8A2HxDuK3RyVgz9/YtIEqtMg2tzh0jE
+NnqPcy0AGMc1V1lmhn9ZHuUwspc3ZCi7gHRSjFoW+SWIIDFcPqRcZ5ZPxIejhwtF
+vbi20OAx+mbSdXjyYH0Z/CaVOIMHKaOWv6EbYLWIjVRGfLsMHl1xzYjE8SiNdcMf
+naLjF564dwKBgQDStSmuw5D7TdWIIq3WFF5z39WKazpjMnhNxJP96Ew1rL0yjiEP
+j5j5s6vCMRXILLEZ4PEp7IAh3xOcqPLAj3heaj88ZtnmdOjawQFlDZlhMAmy9Y8O
+4vwL3fr52U18EGwWpsGeCf3DGzt3f5mrfxhxIaJ2wd0ik2ip8ocH2KjQUQKBgQCS
+D23730hwBTjHobZYGZL0UqH/6BGnFNqeYZ+i3XO/WcnBKiwOrqh5PbAdIoZ5oNxi
+tamcsc8f6vpwt7e2/G39JyHtGbyUMgH8PSP33SKMvBUAZDpP7ZEbTqNPf0rbStCG
+4t71LR/Ln5lAuQz2qpae70IXfkOguPJ58WlRJWoiSQKBgHwgYsjep0Ms/ZJkkhAp
+59vwahpyWmnq/Wm6I9eyM84H+VQNqJf9/pQ3q3afPl4hRQydpenPBQF3GJ1m/9Nb
+BenesNrmJabCBYsaZEnwOnb7xlai5xjBEQxAJ5ROxdmTYmA0xWzuGwuu9fHwdCvW
+2ZXtTzEEzU7mLUhbiQWAF+H4
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/set_cafile_interCA1.crt b/reg-tests/ssl/set_cafile_interCA1.crt
new file mode 100644
index 0000000..840af61
--- /dev/null
+++ b/reg-tests/ssl/set_cafile_interCA1.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEETCCAfmgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRAwDgYDVQQDDAdSb290IENB
+MB4XDTIxMDQyMjE0MDEyMFoXDTQ4MDkwNzE0MDEyMFowRzELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRkwFwYDVQQDDBBJbnRlcm1l
+ZGlhdGUgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAteNSI+ds
+/DWtxa69I3qQ2dn6nKTCHx3IxS5/UprcO/4t0z/gOgsAn+jDVnMRh57SNQGm5/7o
+DkiYnhV04qfdR8amKVKqAhFHUdpKXRZhP6XpqmpKLwvJH/kQmz1oIg27LPlvrAyV
+UqV1Y0vKkMCVEPuap5sJYQasYfYaavpATOAEAC10dlnpYjQQYt4fHetVi10Jmtzr
+Yea5BDsdeajbq8jWgSWGxA3BrbCubCwhCZfih5ct1KTjotj1hsfVyjPwtp8xVpMs
++amWSL/OI6pxdkVBH/dQa4M67rkQdCezLq3UAryQbdbJJLeJKqgGyIpYpKcS0GQA
+JF3UeWxWgur1IQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
+A4ICAQCiVX9SJFgXpoHHRw42A6AZDyhdv+gagQRhcjtRzdhJM+syot5WL+jxGU7U
+26v3MGDRpn0zDRJ8Hdy+IYefB3NO/D5OPxTiziQcx15qf2fj8VtCygbC77u8QHHR
+08b2uvEDgj9K3b5skfwwez4HabD0Ol1QRZOyykG/wl2g1Bz2lgS6Jfz1wYpmT3Ju
+omufTFfB1a07DkkokGe7qAAsnfUidBScIJbLoD7xMr/zY9iMTVo+MI+Pb/4fivxq
++T75ybJwxlCpv74Zk2ATI/VEfHgPpidYtTkScRe8fsnFrE9z5TNKgNwXRhiDZe8U
+F2oggdnA0fBux5H4AmjbXHgAB8x4NjRZ9yrurjdP7AIOdOn5vvXfDehFKN+OP0Pk
++5ZoUEtd876UrupaeEPd7XZIRrGItmytuntA1pW3RCU2yGsA9ep9Ur84ogzBxXpp
+5/8eGnV/TLfaB56f9cYqL9rcTCI+VLhaTFpBpEjCae5EtS50gsAoaideb45F0wCt
+P266qAc69MU7hPqc6z2rzumcQiAKM6krELhTOVSfRo+Gzuei6bFbTK0RqwGYn+Oc
+shQN++eqrT6YAVudGUJWrKp6JEj3Y24fVhW1x631NRW5JinV2jWVWPgObDrReyya
+4KlIwKMR8vPGOa3qlIRP/QPozktkoonRYg+DsLqAD6sQhJllww==
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/set_cafile_interCA2.crt b/reg-tests/ssl/set_cafile_interCA2.crt
new file mode 100644
index 0000000..dab7bc0
--- /dev/null
+++ b/reg-tests/ssl/set_cafile_interCA2.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEETCCAfmgAwIBAgICEAQwDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRAwDgYDVQQDDAdSb290IENB
+MB4XDTIxMDQyMjE0MDEyMVoXDTQ4MDkwNzE0MDEyMVowRzELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRkwFwYDVQQDDBBJbnRlcm1l
+ZGlhdGUgQ0EyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0jJiCfXy
+yzBDFTW3kaznyYZOZ6+IK1xnN6HhrB0nHwpNtC5nNtFKqbN2uNhOs9qvsX6Lx+oI
+4+811OEdn269EGdlsdni/fLo+nofoD/bkcnvUGTnnmJNp4SGL6npHbHhJaAB0ETe
+3F+blo9N6i+g41c+/8gD2VTgjoSiB6/Cm1sJw5jMxlmZ6dkk+HiHqg2B2o4pkOQm
+0DmRuT3c6mN8I1sMWvZeMq7WaAzwbGmERK88p79QhPKr2kl5gfOOOphhPYqyN8dk
+c1xooWoeUo8ZI+uI8LFVljR7+VMKmkG59wtYW6vVoUrGMH8tKPZVEmKVG57wjoqP
+72n7IodhBFWnBwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
+A4ICAQBHTi+Wzg6g5N5/R88Zt9MFiNfQQJwLm5arVjmw+y8uSIsi5e8l2ZrqSi8i
+AtbduX5PID0kzaDAAzH37YpbJScdXBymh2kX6qJOs+bRFl/GkCD7nD9VjV23h72R
+F67bNpNsT3crcxZTD4QytahdKY43XQwicyrmLl9NahxOOfWR6RD2RriBe1Wj5v/R
+SEu5pVcON5qIgo5mgO0GM7X/IW7hZaUyCdboqd29zgYWsiqIGB23V6RTwAZ2WN/0
+xz3IPgwBwzif9L0RNZaGbg+jlmgMJTv+m+/VYoZsFwxgWIaHkR6dYxEZ2ak/djeb
+DOc764Obg+5XlxIgK+hZQbvK2zRkysUTMdzuPZtIgQU4+V4NzeEdsU2Y3IcsUzvG
+29n9CCZxyeG2hTQ1eJrvLqolPUZAn/u+EbH59h01nrycd3k7AJtr05UCrTKk+6EJ
+YwSNvnNEkmw0MX+aYNE0JYtHp8IrFgnO1vbAT6YCxR69LKWAWMy9eDVxK0bTEnrW
+7lRTTgbUCaM31g2peNoiQdSS5xVwO5bcWmi3CHJtrLavMOV7OVi9f+ggTju4CZqK
+v5U6stVyrLSUkdLZP3uMLvDVSPzPt6kGbeyHxqHfE2ywOwFtF3uxKskTNwdxYwuJ
+T8kCxcSLTyefVwkCn7P6r+LdRpJhcbDRdt9cmyfiePElj2uq2w==
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/set_cafile_rootCA.crt b/reg-tests/ssl/set_cafile_rootCA.crt
new file mode 100644
index 0000000..bed2061
--- /dev/null
+++ b/reg-tests/ssl/set_cafile_rootCA.crt
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFGjCCAwKgAwIBAgIUHgviUJMgCZlOPOhVc09pZ4NhfxcwDQYJKoZIhvcNAQEL
+BQAwPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMB4XDTIxMDQyMjE0MDEyMFoXDTQ4MDkwNzE0MDEy
+MFowPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEAti+5onUeFJNyF5s6xlnBxDnFhw7Q5VbBestHeQttjBWN31zq5yaf/+CYXdu+
+lY6gNZj6JBiFJ5P7VXX3DqUIJBX6byXWfIUWM+auBAMKlTz0+hWrF/UxI/3uG67N
++Z6NVffEPYbA4Emqozr0DIicWorRyHnrhEQQP87xBCUboUr3QEkNngfiJ0fPm3fj
+7HfQemGL2OnTA8qdy0q1l4aUhVr9bgedP2Klvs0XhbszCGLI0Gq5lyNadlH1MEiw
+SXa9rklE6NCNcyamO7Wt8LVrg6pxopa7oGnkLbnjzSuE+xsN0isOLaHH5LfYg6gT
+aAHpnBHiWuDZQIyzKc+Z37gNksd46/y9B+oBZoCTcYMOsn7PK+gPzTbu3ic4L9hO
+WCsTV0tn+qUGj6/J98gRgvuvZGA7NPDKNZU5p34oyApBPBUOgpn6pCuT5NlkPYAe
+Rp/ypiy5NCHp0JW3JWkJ4+wEasZM34TZUYrOsicA0GV4ZVkoQ3WYyAjmLvRXmo/w
+Z3sSlmHvCg9MrQ9pk24+OtvCbii0bb/Zmlx0Y4lU5TogcuJffJDVbj7oxTc2gRmI
+SIZsnYLv2qVoeBoMY5otj+ef0Y8v98mKCbiWe2MzBkC2h5wmwyWedez8RysTaFHS
+Z4yOYoCsEAtCxnib9d5fXf0+6aOuFtKMknkuWbYj6En647ECAwEAAaMQMA4wDAYD
+VR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAjVzxHzq/87uj24It5hYj4mq4
+ero0zix4fA4tJNuTpZ/5r7GUYaf/uT4xfDilBX2fGMsxVTxJC25KzhdFeTzg1Tde
+/N0LAeLWHfe6jR/P5XDATD0ZA73DQALOxRM5uRMeWJDVaUeco/aXsdQaCz2STDI3
+h7VVFoaOlmxQW3BBEvg2VUp9DS2UjqqdwsUDtzwKfrmj/FqyBvGrvNeIMv28HCu7
+r1WE1Z0UEJhpc1BPbu7F/vl60gRF3bQjh2tL8pWThxTJe6Qy+pLoSShyi85AM9XK
+scCmUtQWjy7KQDL8XVFvuCWvMzknZQjJcncbKddPaaSIDkKUpz9FDv+wSJj/LKf7
+bGSFPM6sblioLbLNJByRYI8G7VHvKDbUnYHbHp75NTGA2eDeNqx5bC2G/EJUTwLM
+bfcZr9hv+z1QpvSLEpar30kJjc1QMQcf60ToGYIC93rsVAKou2GPGry4h/nzwro0
+jjFWNgORTXllfcQDbDNOPkV1kFFibPbAU4faZMgC+xwIwDBsndvcvXjLaRUa4fmw
+1xNkOO5Lj9AuvTXdCc9yUXRzmPZhU6Q4YB2daWvs3vbMTtvkAXGyQL4b2HD+NYZs
+cMUtbteGgQzwM1gpMBn4GX53vhlCXq28r3cH1/1tLDweglSrxyvZbB7pZU7BAmLk
+TEj2fXcvdcX+TtYhC10=
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/set_cafile_server.pem b/reg-tests/ssl/set_cafile_server.pem
new file mode 100644
index 0000000..04e2c22
--- /dev/null
+++ b/reg-tests/ssl/set_cafile_server.pem
@@ -0,0 +1,95 @@
+Certificate:
+ Data:
+ Version: 1 (0x0)
+ Serial Number: 4104 (0x1008)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=FR, O=HAProxy Technologies, CN=Intermediate CA2
+ Validity
+ Not Before: Apr 22 15:18:37 2021 GMT
+ Not After : Sep 7 15:18:37 2048 GMT
+ Subject: C=FR, O=HAProxy Technologies, CN=Server
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public-Key: (2048 bit)
+ Modulus:
+ 00:a3:9f:14:1d:de:57:84:a9:8e:17:2a:75:92:be:
+ 70:0e:6d:95:82:36:7a:2d:b2:57:e3:82:fd:20:be:
+ 83:e5:71:0a:ae:3e:58:cc:31:bc:42:12:e7:42:50:
+ 9d:47:c6:f4:02:01:1f:6e:a1:74:38:12:27:df:45:
+ 23:56:9a:b7:74:cb:f1:5a:1a:35:60:0d:6d:59:5e:
+ 71:87:19:9e:84:16:3a:69:ff:8d:ea:b2:77:dd:40:
+ d1:8f:c8:5d:35:c1:53:a4:0b:3f:73:c4:c2:03:52:
+ 2a:f1:bf:dc:2f:32:75:d3:2b:d2:e7:3a:de:ac:ac:
+ 43:59:f1:be:52:a7:30:51:54:ff:3d:a4:5f:97:e7:
+ f8:aa:65:86:b4:7d:a6:9d:c4:2d:94:68:2d:71:dc:
+ 5c:d2:2f:bf:d4:9c:ca:7e:2e:97:a7:10:ad:d9:ad:
+ 8b:74:c9:dd:91:54:71:83:1c:51:17:7e:1b:10:fc:
+ 00:c3:f7:5b:43:76:2d:a3:1e:93:a5:c4:cb:c1:eb:
+ 8e:df:a3:6c:6e:31:1e:27:fc:40:54:ac:8e:a2:ba:
+ 6d:d3:26:0d:ef:8b:e6:20:18:55:fd:11:37:61:90:
+ 40:48:d9:86:fc:34:0b:9c:65:1b:d5:02:02:28:16:
+ 08:1f:df:d8:91:8b:be:89:63:1a:09:27:00:4c:a4:
+ f4:59
+ Exponent: 65537 (0x10001)
+ Signature Algorithm: sha256WithRSAEncryption
+ 01:be:4e:27:fe:cd:03:c9:df:30:5f:a8:e5:b7:33:21:a1:9e:
+ d3:1f:cb:4c:00:64:a0:47:c6:73:c8:f8:f5:a5:f3:ee:8d:b4:
+ 2c:b9:7a:47:71:fb:4a:bd:a4:df:c9:b2:2b:06:f5:77:69:ec:
+ c6:90:8d:16:d0:3d:fa:c0:fb:30:50:39:56:0f:2b:78:15:0a:
+ c2:62:6a:98:59:70:aa:6b:61:55:58:ee:50:b7:cf:d3:7c:0a:
+ 24:04:3d:db:ab:bc:c4:ba:82:52:0c:62:4b:aa:48:47:f4:4f:
+ 05:d8:4f:b2:88:f1:d6:1a:10:e1:bc:98:0b:b9:7f:f9:47:21:
+ 89:7a:37:61:f0:1a:e3:1d:c1:23:ba:71:8d:c8:de:cc:b0:da:
+ 6a:21:5c:41:02:a1:8a:6a:d4:02:32:de:a9:84:97:38:27:de:
+ 2d:8c:bc:c4:fa:a9:fc:3a:7c:58:92:62:20:4b:be:60:25:f6:
+ f4:4e:49:a1:b2:f3:e3:97:7c:84:cd:6c:f5:42:e6:3f:ca:34:
+ a3:26:c7:91:e4:0c:8c:df:36:5e:6b:68:e6:45:2d:c0:af:56:
+ 3c:1e:85:46:79:db:85:6e:98:49:69:ea:4f:fc:00:fc:23:8c:
+ dc:b8:fe:b9:fd:f9:fb:ec:28:f0:1a:f7:3c:b4:74:38:5e:71:
+ bc:1e:39:90
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAeECAhAIMA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNVBAYTAkZSMR0wGwYD
+VQQKDBRIQVByb3h5IFRlY2hub2xvZ2llczEZMBcGA1UEAwwQSW50ZXJtZWRpYXRl
+IENBMjAeFw0yMTA0MjIxNTE4MzdaFw00ODA5MDcxNTE4MzdaMD0xCzAJBgNVBAYT
+AkZSMR0wGwYDVQQKDBRIQVByb3h5IFRlY2hub2xvZ2llczEPMA0GA1UEAwwGU2Vy
+dmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo58UHd5XhKmOFyp1
+kr5wDm2VgjZ6LbJX44L9IL6D5XEKrj5YzDG8QhLnQlCdR8b0AgEfbqF0OBIn30Uj
+Vpq3dMvxWho1YA1tWV5xhxmehBY6af+N6rJ33UDRj8hdNcFTpAs/c8TCA1Iq8b/c
+LzJ10yvS5zrerKxDWfG+UqcwUVT/PaRfl+f4qmWGtH2mncQtlGgtcdxc0i+/1JzK
+fi6XpxCt2a2LdMndkVRxgxxRF34bEPwAw/dbQ3Ytox6TpcTLweuO36NsbjEeJ/xA
+VKyOorpt0yYN74vmIBhV/RE3YZBASNmG/DQLnGUb1QICKBYIH9/YkYu+iWMaCScA
+TKT0WQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQABvk4n/s0Dyd8wX6jltzMhoZ7T
+H8tMAGSgR8ZzyPj1pfPujbQsuXpHcftKvaTfybIrBvV3aezGkI0W0D36wPswUDlW
+Dyt4FQrCYmqYWXCqa2FVWO5Qt8/TfAokBD3bq7zEuoJSDGJLqkhH9E8F2E+yiPHW
+GhDhvJgLuX/5RyGJejdh8BrjHcEjunGNyN7MsNpqIVxBAqGKatQCMt6phJc4J94t
+jLzE+qn8OnxYkmIgS75gJfb0TkmhsvPjl3yEzWz1QuY/yjSjJseR5AyM3zZea2jm
+RS3Ar1Y8HoVGeduFbphJaepP/AD8I4zcuP65/fn77CjwGvc8tHQ4XnG8HjmQ
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjnxQd3leEqY4X
+KnWSvnAObZWCNnotslfjgv0gvoPlcQquPljMMbxCEudCUJ1HxvQCAR9uoXQ4Eiff
+RSNWmrd0y/FaGjVgDW1ZXnGHGZ6EFjpp/43qsnfdQNGPyF01wVOkCz9zxMIDUirx
+v9wvMnXTK9LnOt6srENZ8b5SpzBRVP89pF+X5/iqZYa0faadxC2UaC1x3FzSL7/U
+nMp+LpenEK3ZrYt0yd2RVHGDHFEXfhsQ/ADD91tDdi2jHpOlxMvB647fo2xuMR4n
+/EBUrI6ium3TJg3vi+YgGFX9ETdhkEBI2Yb8NAucZRvVAgIoFggf39iRi76JYxoJ
+JwBMpPRZAgMBAAECggEAAj1OKC5/4ifz8us42r5SiFAFqNeYCoITY+DKGCWjZoOK
+kuH1ky3nFrxtf+HclTvq4RAk3v3EunO9KfgnSKsrcaTM89/B9UOZyIxbX28BVWt8
+dzDxP1IcA+I8PAyRAghYXbltr+b0hNkeD1sB5394T2CdLV8H5zMgZN3DLhxts99B
+V6fp77eSxKvjCByKzTvlECYwxt6GnkAfZulmYGtThBoTyIz9clzl2lcpoPwp9VpF
+IwYn6qig4Gfkrwj/2iMg3b6KOQIGcbH493cGmU+ujK1l4ZbkG6VIYHqLnbD+myui
+LpUjUeZPigvgvhkdakGyrwqBxqNFDMOFTdunKuZ65QKBgQDVKKuAf5NeBWAPUiaN
+AI82+4RTIecw5svrgk/9qSNCVnUwm9qJHyDpJZLvYUXcfB1CW6iYUQ9oo/+RvK5O
+YhouwQotKMI7moIyUiRhvOSFC/7QFYLSf8uMOPlYOxofq1OAqzAsGTHItrydu709
+sdox1alxroScpRfZm8I2fm9l4wKBgQDEgaKDTY3UgpY/KWH4SWMc0+UD9ordf96m
+E9rYTLW7pleZB/L5YvmpAiewUvwk1YipiLh0fQZVEx1BKirzmiWeLm2FO4SX7z9t
+kMeVb3XiGgeoTdPV98YNfB6tx3+2WEYQ5FkvyABsdoUp6e8AkwbFPZnFmM/a0ZSU
+Ob/Sfq8xkwKBgCfzTmlv/7PAeCeG8xi8QRtB+qQGF6mPqCqEqu9U0vns8Fvi6guH
+HQj1dNuOtKRFUsqMGUYq8yNekVjELzsboeKfZYPfPsAjDkHWKWF0ILRa8jAXyAQh
+1Yl7aChEM3o6BxV3gDjTpAQFU8aQWECG4+kxLWfUGKCvRJARZE4IVmKXAoGAU2Hy
+tKaW9ULIQFruAG4biWL8fbcC68RTlMM+DKRYRRzrdLsjxeDSsX2Bm9dKuNKHH/Es
+2/klU7o9oqYi/aU+KyXmQS+lLtdNYc+acPWP3vZOo4MKzXNK7fPqDLFnptdEO+y5
+T4Ydb+jGzqc+TE8XA2EFPAyAvohJ9K+gjtBExNMCgYEAhQSFwr8FRE4TVJT9zTxG
+PUsKzCMin5ewrYSVReBBKSEymrEC2MhsDgikfJHbDF4N3o8gbhXJKf3LcLJH0761
+y6Wt+0tyfUWk4Zv8oliiZi9vcFeNmArLW5+NHQLBh5SX2UXGRmtguZUAs1gkAe5E
+S3GzLHPhcWNEOE/PxejIRKI=
+-----END PRIVATE KEY-----
diff --git a/reg-tests/ssl/set_default_cert.crt-list b/reg-tests/ssl/set_default_cert.crt-list
new file mode 100644
index 0000000..a0d2caa
--- /dev/null
+++ b/reg-tests/ssl/set_default_cert.crt-list
@@ -0,0 +1,2 @@
+set_default_cert.pem !*
+set_default_cert.pem www.test1.com
diff --git a/reg-tests/ssl/set_default_cert.pem b/reg-tests/ssl/set_default_cert.pem
new file mode 100644
index 0000000..550208a
--- /dev/null
+++ b/reg-tests/ssl/set_default_cert.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIENjCCAh4CAQEwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCRlIxDjAMBgNV
+BAgMBVBhcmlzMQ4wDAYDVQQHDAVQYXJpczEVMBMGA1UECgwMSEFQcm94eSBUZWNo
+MRUwEwYDVQQDDAxIQVByb3h5IFRlY2gwHhcNMjEwMzAyMTcxODUwWhcNMjIwMzAy
+MTcxODUwWjBnMQswCQYDVQQGEwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTEOMAwG
+A1UEBwwFUGFyaXMxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRQwEgYD
+VQQDDAsqLnRlc3QxLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+APjmyWLJ1olKg/EOarln7oQB7pdUrF6kS1YG+Nz0sgFzxnU0PHn/IeARCprHyEZ4
+eBOrQ0CHhM5hdEFDX8iq32rektcQqwfH83iwD9zXxFBJ7ItoWG6YAN6WLXjEDYEI
+hxLJMlW3kfYODKhNMvoqXyZi2wTyAJI+aLJI7pbeD+YNb0AwOnSH5ag5ohZIr3QU
+99UD/VUhndv4OP8JZwBiV6Qy79jVDVbPFGaOc70VkMQSCHytyudQicUZrYQdIw1E
+981JF/UpbnECLWyB3V+4t1KtWOW90vkUoBEj8Nxe6kYnMaNSjQhfKSF6zGmUOXYp
+oHPCgms8v4JaovQygo02Qi8CAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAAz8IntYc
+zrbIqweHfD9CZTNIQiobhQmgykT0KQ23Gm2y/e3o63XOqxDv0bEctg4zE83w3g7d
+mJlEyCB0N0qC8UGGsbRm5Cny7H//g3u06NqSMBYbdU+BgZBBj16I5Kcw/kSBb9dA
+wslLlrUjBj6dK83EB1cpyqpyZHIXkR/E424ggfc45rmD60AtU0SvzVNZfIK0PmB0
+3YKiUlO7cl5CzTeTg2BooRvqwblya62SRkhfFL7NCRX1/S9tO/XiaYzgP7J6J09x
+yYs2XhQqJFgtS+1vDp8rHKhcANFVXBJ6rDSbp1qBv7qZkQhlFf8hQtd5iBXvCb0a
+KtN9L4o6t1wvyo0BbERroGU7rkPPUNiMc3gWEf/mgwGLsNNOYqY5eYoeAF7arX5f
+c4LCHiAYMWa/bEY29zmm51GH5ddxFSu1j95Hfd+HlNcX8Oyfed2oCoSamochmbzA
+Kktk0QfCYIv4LlaG5pUliLa6DCLK7yMfT5RC5GGb350p3uDobVj/taY2cVwXOBQb
+MjXK32K9CFrnqKQptPV1ohlWgNiqhvxiGp3Yx17Cn54WL9ksO+8TlwWAttazKVlT
+40tHqGOu6ld90xGZitxL2oA9kBg9Nkxas/f9+9p6sJe5wj09dj/cqRjyiKv7nek1
+TIPtsNbJghDRDQ3uPEYHdX0h490qGMyGARw=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpgIBAAKCAQEA+ObJYsnWiUqD8Q5quWfuhAHul1SsXqRLVgb43PSyAXPGdTQ8
+ef8h4BEKmsfIRnh4E6tDQIeEzmF0QUNfyKrfat6S1xCrB8fzeLAP3NfEUEnsi2hY
+bpgA3pYteMQNgQiHEskyVbeR9g4MqE0y+ipfJmLbBPIAkj5oskjult4P5g1vQDA6
+dIflqDmiFkivdBT31QP9VSGd2/g4/wlnAGJXpDLv2NUNVs8UZo5zvRWQxBIIfK3K
+51CJxRmthB0jDUT3zUkX9SlucQItbIHdX7i3Uq1Y5b3S+RSgESPw3F7qRicxo1KN
+CF8pIXrMaZQ5dimgc8KCazy/glqi9DKCjTZCLwIDAQABAoIBAQC/arWb7L+56/2W
+iFDZb62GBfpYlXzOeCmb6la/jsvKxB/vCRItfGGv8Usnh9dlIsat0bsxyEcBdP80
+Jb1nFMonZS6miSIPJN4Ahd5dJ+7JFGD/QWso+mtIw1QLGTONdWJztxmnxDpTcbCY
+Sm6W57kvSz1HC1oXHjnkSqR6kCLH9y6/i7ox6IPYyDA1t/TKJMnKFOPkxKJ8A96v
+1avPrCWfXWYdn6Og5ERd8FJF2L5BYImmmkPpoUeWPyMBfAYqdK5FRijO6JMn/h5k
+XkJm+2bru+cRwcNYUNPuDIa+ZBWhjFfZfSOhOoECeKLe+lhfcFPC7cCSeDJAjGtR
+dakm15ohAoGBAP4+rVBeSCBhPH27T3HWp74qMWkYJzkdqTV0wUUJ1wtuWZFDg/RP
+OYKC+6cM0nW3K+j/9pTWMS1eM61x/VNyFQGUq/rMJGEWFH08NXnV8AxCtwKUV/rP
+Uq3MB4QWfSYGMo9QL+9lu23fMWYpBLo+KIcqPjLb+8FEJGmaC9JCIYQfAoGBAPqe
+qp7NzMmX2b1VR2XXm1CZzwTEFXb4NeDIxSfNbsqXCmws3jgBX3Lx7dQ9k8ymvaA5
+ucYLU3ppozeB//8Ir9lSA1A4w3VN9a+l1ZdQpKQ4SuHtqDwkmKAT85vmGHCPhwlq
+Er9ests3wQ4T/8HPG92QWs+Gg34F+x9U6h2FMv/xAoGBAOM6h1HWAeaWoSbKWvWm
+YKNQOHryMFQW011IbVfTtJOt23U9/1hB2mdvw5SInCzDOgZzhiF90dP3Zn5063FB
++84+3vo2q6jtwAAx6KVsdK+wjLpMdNlfpEhamrkOFGoAjf2SMFVo+fv3x8HDlUsT
+NMuhEJgKDlasHVMYb8pKeoQHAoGBAMAF7ij6+lvD03tz6d6oUkJxduLp8qBTEcUH
+T7hteOQU0lGMFz/GHYIOx/EEtUfqwgQP9r09VFrIsdwH6UNZPpM+eXdv5qLsdsB8
+SalEisGguA9fbrWWPLL6Vn8uz67+6bJW6cJjJps8ntjQjffLXkhnII09PWbD4mNh
+RngT5L2hAoGBANqa+yYSvEGNAxvdfxE0u3U/4OtjCl168nNwHXmyaCKZ1e4XYflz
+wGI4J1ngcCKN37RkCgfu/XRKrc82XhAhV+YYjAUqQYrTyh26b4v9Dp9tBUWiv7bk
+6L+ZlCms+HpsuYmsCAu/od41OWSSpdg+R3VOE0t3rp0r1QdAGYd1nwQC
+-----END RSA PRIVATE KEY-----
diff --git a/reg-tests/ssl/set_ssl_bug_2265.vtc b/reg-tests/ssl/set_ssl_bug_2265.vtc
new file mode 100644
index 0000000..21e837a
--- /dev/null
+++ b/reg-tests/ssl/set_ssl_bug_2265.vtc
@@ -0,0 +1,90 @@
+#REGTEST_TYPE=devel
+
+# This reg-test uses the "set ssl cert" command to update a certificate over the CLI.
+# It requires socat to upload the certificate
+#
+# this check does 3 requests, the first one will use "www.test1.com" as SNI,
+# the second one with the same but that must fail and the third one will use
+# "localhost". Since vtest can't do SSL, we use haproxy as an SSL client with 2
+# chained listen section.
+#
+# This is the same as "set_ssl_cert_noext.vtc" but the .crt contains both the certificate and the key.
+#
+# If this test does not work anymore:
+# - Check that you have socat
+
+varnishtest "Test the 'set ssl cert' feature of the CLI with separate key and crt"
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTIONS=OPENSSL
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ retries 0
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ retries 0 # 2nd SSL connection must fail so skip the retry
+ server s1 "${tmpdir}/ssl.sock" ssl verify none sni str(www.test1.com)
+ server s2 "${tmpdir}/ssl.sock" ssl verify none sni str(www.test1.com)
+ server s3 "${tmpdir}/ssl.sock" ssl verify none sni str(localhost)
+
+ listen ssl-lst
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/bug-2265.crt strict-sni
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/bug-2265.crt"
+ expect ~ ".*SHA1 FingerPrint: DF3B6E847A7BF83DFAAFCFEC65EE9BC36230D3EA"
+}
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+shell {
+ printf "set ssl cert ${testdir}/bug-2265.crt <<\n$(cat ${testdir}/ecdsa.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/bug-2265.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/bug-2265.crt"
+ expect ~ ".*SHA1 FingerPrint: A490D069DBAFBEE66DE434BEC34030ADE8BCCBF1"
+}
+
+# check that the "www.test1.com" SNI was removed
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/ssl/set_ssl_cafile.vtc b/reg-tests/ssl/set_ssl_cafile.vtc
new file mode 100644
index 0000000..3881a42
--- /dev/null
+++ b/reg-tests/ssl/set_ssl_cafile.vtc
@@ -0,0 +1,167 @@
+#REGTEST_TYPE=devel
+
+# This reg-test uses the "set ssl ca-file" command to update a CA file over the CLI.
+# It also tests the "abort ssl ca-file" and "show ssl ca-file" commands.
+#
+# It is based on two CA certificates, set_cafile_interCA1.crt and set_cafile_interCA2.crt,
+# and a client certificate that was signed with set_cafile_interCA1.crt (set_cafile_client.pem)
+# and a server certificate that was signed with set_cafile_interCA2.crt (set_cafile_server.pem).
+# The CA files used by the client and the server will be updated through the CLI until a
+# proper connection can be established between them.
+#
+# It requires socat to upload the certificate
+#
+# If this test does not work anymore:
+# - Check that you have socat
+
+varnishtest "Test the 'set ssl ca-file' feature of the CLI"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)' && !ssllib_name_startswith(wolfSSL)'"
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 4 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ retries 0
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ # dummy bind used to test a change when the same crt is used as server and bind
+ bind "fd@${foobarlst}" ssl crt ${testdir}/set_cafile_client.pem ca-file ${testdir}/set_cafile_interCA1.crt verify none
+ server s1 "${tmpdir}/ssl.sock" ssl crt ${testdir}/set_cafile_client.pem ca-file ${testdir}/set_cafile_interCA1.crt verify none
+
+ listen clear-verified-lst
+ bind "fd@${clearverifiedlst}"
+ server s1 "${tmpdir}/ssl.sock" ssl crt ${testdir}/set_cafile_client.pem ca-file ${testdir}/set_cafile_interCA1.crt verify required
+
+ listen ssl-lst
+ # crt: certificate of the server
+ # ca-file: CA used for client authentication request
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/set_cafile_server.pem ca-verify-file ${testdir}/set_cafile_rootCA.crt ca-file ${testdir}/set_cafile_interCA2.crt verify required crt-ignore-err all
+ http-response add-header X-SSL-Client-Verify %[ssl_c_verify]
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+# Test the "show ssl ca-file" command
+haproxy h1 -cli {
+ send "show ssl ca-file"
+ expect ~ ".*${testdir}/set_cafile_interCA1.crt - 1 certificate.*"
+ send "show ssl ca-file"
+ expect ~ ".*${testdir}/set_cafile_interCA2.crt - 1 certificate.*"
+
+ send "show ssl ca-file ${testdir}/set_cafile_interCA2.crt"
+ expect ~ ".*SHA1 FingerPrint: 3D3D1D10AD74A8135F05A818E10E5FA91433954D"
+}
+
+
+# This first connection should fail because the client's certificate was signed with the
+# set_cafile_interCA1.crt certificate which is not known by the backend.
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ # unable to verify the client certificate
+ expect resp.http.X-SSL-Client-Verify ~ "20|21"
+} -run
+
+# Set a new ca-file without committing it and check that the new ca-file is not taken into account
+shell {
+ printf "set ssl ca-file ${testdir}/set_cafile_interCA2.crt <<\n$(cat ${testdir}/set_cafile_interCA1.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+}
+
+# Test the "show ssl ca-file" command
+# The transaction should be mentioned in the list
+haproxy h1 -cli {
+ send "show ssl ca-file"
+ expect ~ "\\*${testdir}/set_cafile_interCA2.crt - 1 certificate.*"
+
+# The original CA file did not change
+ send "show ssl ca-file ${testdir}/set_cafile_interCA2.crt"
+ expect ~ ".*SHA1 FingerPrint: 3D3D1D10AD74A8135F05A818E10E5FA91433954D"
+
+# Only the current transaction displays a new certificate
+ send "show ssl ca-file *${testdir}/set_cafile_interCA2.crt"
+ expect ~ ".*SHA1 FingerPrint: 4FFF535278883264693CEA72C4FAD13F995D0098"
+}
+
+# This connection should still fail for the same reasons as previously
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ # unable to verify the client certificate
+ expect resp.http.X-SSL-Client-Verify ~ "20|21"
+} -run
+
+haproxy h1 -cli {
+ send "abort ssl ca-file ${testdir}/set_cafile_interCA2.crt"
+ expect ~ "Transaction aborted for certificate '${testdir}/set_cafile_interCA2.crt'!"
+ send "commit ssl ca-file ${testdir}/set_cafile_interCA2.crt"
+ expect ~ "No ongoing transaction!"
+}
+
+
+# Update the bind line's ca-file in order to accept the client certificate
+shell {
+ printf "set ssl ca-file ${testdir}/set_cafile_interCA2.crt <<\n$(cat ${testdir}/set_cafile_interCA1.crt)\n$(cat ${testdir}/set_cafile_rootCA.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file ${testdir}/set_cafile_interCA2.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+
+# The backend's certificate can't be verified by the frontend because it was signed with
+# the set_cafile_interCA2.crt certificate.
+client c1 -connect ${h1_clearverifiedlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+
+# Update the server line's ca-file. The server certificate should now be accepted by
+# the frontend. We replace the single CA by a list of CAs that includes the correct one.
+shell {
+ printf "set ssl ca-file ${testdir}/set_cafile_interCA1.crt <<\n$(cat ${testdir}/set_cafile_interCA1.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ printf "add ssl ca-file ${testdir}/set_cafile_interCA1.crt <<\n$(cat ${testdir}/set_cafile_interCA2.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ printf "add ssl ca-file ${testdir}/set_cafile_interCA1.crt <<\n$(cat ${testdir}/set_cafile_rootCA.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file ${testdir}/set_cafile_interCA1.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+# Test the "show ssl ca-file" with a certificate index
+haproxy h1 -cli {
+ send "show ssl ca-file"
+ expect ~ ".*${testdir}/set_cafile_interCA1.crt - 3 certificate.*"
+
+ send "show ssl ca-file ${testdir}/set_cafile_interCA1.crt:1"
+ expect ~ ".*SHA1 FingerPrint: 4FFF535278883264693CEA72C4FAD13F995D0098"
+
+ send "show ssl ca-file ${testdir}/set_cafile_interCA1.crt:2"
+ expect !~ ".*SHA1 FingerPrint: 4FFF535278883264693CEA72C4FAD13F995D0098"
+ send "show ssl ca-file ${testdir}/set_cafile_interCA1.crt:2"
+ expect ~ ".*SHA1 FingerPrint: 3D3D1D10AD74A8135F05A818E10E5FA91433954D"
+}
+
+client c1 -connect ${h1_clearverifiedlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ # there should be no error on the backend side but one on the frontend side
+ expect resp.http.X-SSL-Client-Verify == 0
+} -run
diff --git a/reg-tests/ssl/set_ssl_cert.vtc b/reg-tests/ssl/set_ssl_cert.vtc
new file mode 100644
index 0000000..9d4d5a0
--- /dev/null
+++ b/reg-tests/ssl/set_ssl_cert.vtc
@@ -0,0 +1,206 @@
+#REGTEST_TYPE=devel
+
+# This reg-test uses the "set ssl cert" command to update a certificate over the CLI.
+# It requires socat to upload the certificate
+#
+# This check has two separate parts.
+# In the first part, there are 3 requests, the first one will use "www.test1.com" as SNI,
+# the second one with the same but that must fail and the third one will use
+# "localhost". Since vtest can't do SSL, we use haproxy as an SSL client with 2
+# chained listen section.
+#
+# In the second part, we check the update of a default certificate in a crt-list.
+# This corresponds to a bug raised in https://github.com/haproxy/haproxy/issues/1143.
+# A certificate is used as default certificate as well as regular one, and during the update
+# the default certificate would not be properly updated if the default instance did not have
+# any SNI. The test consists in checking that the used certificate is the right one after
+# updating it via a "set ssl cert" call.
+#
+# If this test does not work anymore:
+# - Check that you have socat
+
+varnishtest "Test the 'set ssl cert' feature of the CLI"
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTIONS=OPENSSL
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 9 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+ crt-base ${testdir}
+
+ defaults
+ mode http
+ option httplog
+ retries 0
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+
+ http-response set-header X-SSL-Server-SHA1 %[ssl_s_sha1,hex]
+
+ retries 0 # 2nd SSL connection must fail so skip the retry
+ server s1 "${tmpdir}/ssl.sock" ssl verify none sni str(www.test1.com)
+ server s2 "${tmpdir}/ssl.sock" ssl verify none sni str(www.test1.com)
+ server s3 "${tmpdir}/ssl.sock" ssl verify none sni str(localhost)
+
+ server s4 "${tmpdir}/other-ssl.sock" ssl verify none sni str(www.test1.com)
+ server s5 "${tmpdir}/other-ssl.sock" ssl verify none sni str(other.test1.com) # uses the default certificate
+ server s6 "${tmpdir}/other-ssl.sock" ssl verify none sni str(www.test1.com)
+ server s7 "${tmpdir}/other-ssl.sock" ssl verify none sni str(other.test1.com) # uses the default certificate
+
+ server s8 "${tmpdir}/other-ssl.sock" ssl verify none sni str(www.test1.com)
+ server s9 "${tmpdir}/other-ssl.sock" ssl verify none sni str(other.test1.com) # uses the default certificate
+
+ listen ssl-lst
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/common.pem strict-sni
+ server s1 ${s1_addr}:${s1_port}
+ # dummy server used to test a change when the same crt is used as server and bind
+ server s2 ${s1_addr}:${s1_port} ssl crt ${testdir}/common.pem verify none weight 0
+
+ listen other-ssl-lst
+ bind "${tmpdir}/other-ssl.sock" ssl crt-list ${testdir}/set_default_cert.crt-list
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/common.pem"
+ expect ~ ".*SHA1 FingerPrint: DF3B6E847A7BF83DFAAFCFEC65EE9BC36230D3EA"
+}
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+shell {
+ printf "set ssl cert ${testdir}/common.pem <<\n$(cat ${testdir}/ecdsa.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/common.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/common.pem"
+ expect ~ ".*SHA1 FingerPrint: A490D069DBAFBEE66DE434BEC34030ADE8BCCBF1"
+}
+
+# check that the "www.test1.com" SNI was removed
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+shell {
+ printf "set ssl cert ${testdir}/common.pem <<\n$(cat ${testdir}/common.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "abort ssl cert ${testdir}/common.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/common.pem"
+ expect ~ ".*SHA1 FingerPrint: A490D069DBAFBEE66DE434BEC34030ADE8BCCBF1"
+}
+
+
+
+# The following requests are aimed at a backend that uses the set_default_cert.crt-list file
+
+# Uses the www.test1.com sni
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "9DC18799428875976DDE706E9956035EE88A4CB3"
+ expect resp.status == 200
+} -run
+
+# Uses the other.test1.com sni and the default line of the crt-list
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "9DC18799428875976DDE706E9956035EE88A4CB3"
+ expect resp.status == 200
+} -run
+
+shell {
+ printf "set ssl cert ${testdir}/set_default_cert.pem <<\n$(cat ${testdir}/common.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+}
+
+# Certificate should not have changed yet
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/set_default_cert.pem"
+ expect ~ ".*SHA1 FingerPrint: 9DC18799428875976DDE706E9956035EE88A4CB3"
+}
+
+shell {
+ echo "commit ssl cert ${testdir}/set_default_cert.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/set_default_cert.pem"
+ expect ~ ".*SHA1 FingerPrint: DF3B6E847A7BF83DFAAFCFEC65EE9BC36230D3EA"
+}
+
+# Uses the www.test1.com sni
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "DF3B6E847A7BF83DFAAFCFEC65EE9BC36230D3EA"
+ expect resp.status == 200
+} -run
+
+# Uses the other.test1.com sni and the default line of the crt-list
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "DF3B6E847A7BF83DFAAFCFEC65EE9BC36230D3EA"
+ expect resp.status == 200
+} -run
+
+# Restore original certificate
+shell {
+ printf "set ssl cert ${testdir}/set_default_cert.pem <<\n$(cat ${testdir}/set_default_cert.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/set_default_cert.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/set_default_cert.pem"
+ expect ~ ".*SHA1 FingerPrint: 9DC18799428875976DDE706E9956035EE88A4CB"
+}
+
+# Uses the www.test1.com sni
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "9DC18799428875976DDE706E9956035EE88A4CB3"
+ expect resp.status == 200
+} -run
+
+# Uses the other.test1.com sni and the default line of the crt-list
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "9DC18799428875976DDE706E9956035EE88A4CB3"
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/ssl/set_ssl_cert_bundle.vtc b/reg-tests/ssl/set_ssl_cert_bundle.vtc
new file mode 100644
index 0000000..270cba6
--- /dev/null
+++ b/reg-tests/ssl/set_ssl_cert_bundle.vtc
@@ -0,0 +1,111 @@
+#REGTEST_TYPE=devel
+
+# This reg-test uses the "set ssl cert" command to update a multi-certificate
+# bundle over the CLI.
+# It requires socat to upload the certificate
+#
+# This regtests loads a multi-certificates bundle "cert1-example.com.pem"
+# composed of a .rsa and a .ecdsa
+#
+# After verifying that the RSA and ECDSA algorithms were avalailble with the
+# right certificate, the test changes the certificates and try new requests.
+#
+# If this test does not work anymore:
+# - Check that you have socat
+# - Check that you have at least OpenSSL 1.1.1
+
+varnishtest "Test the 'set ssl cert' feature of the CLI with bundles"
+# could work with haproxy 2.3 but the -cc is not available
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev9)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && ssllib_name_startswith(OpenSSL) && openssl_version_atleast(1.1.1)'"
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 9 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+ crt-base ${testdir}
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+
+ http-response set-header X-SSL-Server-SHA1 %[ssl_s_sha1,hex]
+
+ retries 0 # 2nd SSL connection must fail so skip the retry
+ server s1 "${tmpdir}/ssl.sock" ssl verify none sni str(example.com) force-tlsv12 ciphers ECDHE-RSA-AES128-GCM-SHA256
+ server s2 "${tmpdir}/ssl.sock" ssl verify none sni str(example.com) force-tlsv12 ciphers ECDHE-ECDSA-AES256-GCM-SHA384
+
+ server s3 "${tmpdir}/ssl.sock" ssl verify none sni str(example.com) force-tlsv12 ciphers ECDHE-RSA-AES128-GCM-SHA256
+ server s4 "${tmpdir}/ssl.sock" ssl verify none sni str(example.com) force-tlsv12 ciphers ECDHE-ECDSA-AES256-GCM-SHA384
+
+ listen ssl-lst
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/cert1-example.com.pem
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/cert1-example.com.pem.rsa"
+ expect ~ ".*SHA1 FingerPrint: 94F720DACA71B8B1A0AC9BD48C65BA688FF047DE"
+ send "show ssl cert ${testdir}/cert1-example.com.pem.ecdsa"
+ expect ~ ".*SHA1 FingerPrint: C1BA055D452F92EB02D449F0498C289F50698300"
+}
+
+client c1 -connect ${h1_clearlst_sock} {
+# RSA
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "94F720DACA71B8B1A0AC9BD48C65BA688FF047DE"
+ expect resp.status == 200
+# ECDSA
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "C1BA055D452F92EB02D449F0498C289F50698300"
+ expect resp.status == 200
+} -run
+
+shell {
+ printf "set ssl cert ${testdir}/cert1-example.com.pem.rsa <<\n$(cat ${testdir}/cert2-example.com.pem.rsa)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/cert1-example.com.pem.rsa" | socat "${tmpdir}/h1/stats" -
+ printf "set ssl cert ${testdir}/cert1-example.com.pem.ecdsa <<\n$(cat ${testdir}/cert2-example.com.pem.ecdsa)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/cert1-example.com.pem.ecdsa" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/cert1-example.com.pem.rsa"
+ expect ~ ".*SHA1 FingerPrint: ADC863817FC40C2A9CA913CE45C9A92232558F90"
+ send "show ssl cert ${testdir}/cert1-example.com.pem.ecdsa"
+ expect ~ ".*SHA1 FingerPrint: F49FFA446D072262445C197B85D2F400B3F58808"
+}
+
+client c1 -connect ${h1_clearlst_sock} {
+# RSA
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "ADC863817FC40C2A9CA913CE45C9A92232558F90"
+ expect resp.status == 200
+# ECDSA
+ txreq
+ rxresp
+ expect resp.http.X-SSL-Server-SHA1 == "F49FFA446D072262445C197B85D2F400B3F58808"
+ expect resp.status == 200
+} -run
+
diff --git a/reg-tests/ssl/set_ssl_cert_noext.vtc b/reg-tests/ssl/set_ssl_cert_noext.vtc
new file mode 100644
index 0000000..4326711
--- /dev/null
+++ b/reg-tests/ssl/set_ssl_cert_noext.vtc
@@ -0,0 +1,90 @@
+#REGTEST_TYPE=devel
+
+# This reg-test uses the "set ssl cert" command to update a certificate over the CLI.
+# It requires socat to upload the certificate
+#
+# this check does 3 requests, the first one will use "www.test1.com" as SNI,
+# the second one with the same but that must fail and the third one will use
+# "localhost". Since vtest can't do SSL, we use haproxy as an SSL client with 2
+# chained listen section.
+#
+# If this test does not work anymore:
+# - Check that you have socat
+
+varnishtest "Test the 'set ssl cert' feature of the CLI with separate key and crt"
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTIONS=OPENSSL
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ ssl-load-extra-del-ext
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ retries 0
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ retries 0 # 2nd SSL connection must fail so skip the retry
+ server s1 "${tmpdir}/ssl.sock" ssl verify none sni str(www.test1.com)
+ server s2 "${tmpdir}/ssl.sock" ssl verify none sni str(www.test1.com)
+ server s3 "${tmpdir}/ssl.sock" ssl verify none sni str(localhost)
+
+ listen ssl-lst
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/common.crt strict-sni
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/common.crt"
+ expect ~ ".*SHA1 FingerPrint: 2195C9F0FD58470313013FC27C1B9CF9864BD1C6"
+}
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+shell {
+ printf "set ssl cert ${testdir}/common.crt <<\n$(cat ${testdir}/ecdsa.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ printf "set ssl cert ${testdir}/common.key <<\n$(cat ${testdir}/ecdsa.key)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/common.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/common.crt"
+ expect ~ ".*SHA1 FingerPrint: A490D069DBAFBEE66DE434BEC34030ADE8BCCBF1"
+}
+
+# check that the "www.test1.com" SNI was removed
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/ssl/set_ssl_crlfile.vtc b/reg-tests/ssl/set_ssl_crlfile.vtc
new file mode 100644
index 0000000..f018a33
--- /dev/null
+++ b/reg-tests/ssl/set_ssl_crlfile.vtc
@@ -0,0 +1,146 @@
+#REGTEST_TYPE=devel
+
+# This reg-test uses the "set ssl crl-file" command to update a CRL file over the CLI.
+# It also tests the "abort ssl crl-file" and "show ssl crl-file" commands.
+#
+# The frontend's certificate is signed by set_cafile_interCA1.crt and is revoked in interCA1_crl.pem
+# but not in interCA1_crl_empty.pem.
+# The backend's certificate is signed by set_cafile_interCA2.crt and is revoked in interCA2_crl.pem
+# but not in interCA2_crl_empty.pem.
+#
+# The test consists in replacing the two empty CRLs by their not empty equivalent thanks to CLI
+# calls and to check that the certificates (frontend and backend) are indeed revoked after the
+# update.
+#
+# It requires socat to upload the certificate
+#
+# If this test does not work anymore:
+# - Check that you have socat
+
+varnishtest "Test the 'set ssl crl-file' feature of the CLI"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)' && !ssllib_name_startswith(wolfSSL)'"
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 4 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ retries 0
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ server s1 "${tmpdir}/ssl.sock" ssl crt ${testdir}/set_cafile_client.pem ca-file ${testdir}/set_cafile_interCA2.crt crl-file ${testdir}/interCA2_crl_empty.pem verify required
+
+ listen ssl-lst
+ # crt: certificate of the server
+ # ca-file: CA used for client authentication request
+ # crl-file: revocation list for client auth
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/set_cafile_server.pem ca-file ${testdir}/set_cafile_interCA1.crt ca-verify-file ${testdir}/set_cafile_rootCA.crt crl-file ${testdir}/interCA1_crl_empty.pem verify required crt-ignore-err all
+ http-response add-header X-SSL-Client-Verify %[ssl_c_verify]
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+# Test the "show ssl ca-file" command
+haproxy h1 -cli {
+ send "show ssl ca-file"
+ expect ~ ".*${testdir}/set_cafile_interCA1.crt - 1 certificate.*"
+ send "show ssl ca-file"
+ expect ~ ".*${testdir}/set_cafile_interCA2.crt - 1 certificate.*"
+}
+
+# Add the rootCA certificate to set_cafile_interCA2.crt in order for the frontend to
+# be able to validate the server's certificate
+shell {
+ printf "set ssl ca-file ${testdir}/set_cafile_interCA2.crt <<\n$(cat ${testdir}/set_cafile_interCA2.crt)\n$(cat ${testdir}/set_cafile_rootCA.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file ${testdir}/set_cafile_interCA2.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl ca-file"
+ expect ~ ".*${testdir}/set_cafile_interCA2.crt - 2 certificate.*"
+
+ send "show ssl ca-file ${testdir}/set_cafile_interCA2.crt"
+ expect ~ ".*Subject.*/CN=Root CA"
+}
+
+# This first connection should succeed
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.X-SSL-Client-Verify == 0
+} -run
+
+# Change the frontend's crl-file to one in which the server certificate is revoked
+shell {
+ printf "set ssl crl-file ${testdir}/interCA2_crl_empty.pem <<\n$(cat ${testdir}/interCA2_crl.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+}
+
+# Check that the transaction is displayed in the output of "show ssl crl-list"
+haproxy h1 -cli {
+ send "show ssl crl-file"
+ expect ~ "\\*${testdir}/interCA2_crl_empty.pem"
+
+ send "show ssl crl-file \\*${testdir}/interCA2_crl_empty.pem"
+ expect ~ "Revoked Certificates:"
+ send "show ssl crl-file \\*${testdir}/interCA2_crl_empty.pem:1"
+ expect ~ "Serial Number: 1008"
+}
+
+# This connection should still succeed since the transaction was not committed
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.X-SSL-Client-Verify == 0
+} -run
+
+haproxy h1 -cli {
+ send "commit ssl crl-file ${testdir}/interCA2_crl_empty.pem"
+ expect ~ "Committing ${testdir}/interCA2_crl_empty.pem"
+}
+
+# This connection should fail, the server's certificate is revoked in the newly updated CRL file
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+# Restore the frontend's CRL
+shell {
+ printf "set ssl crl-file ${testdir}/interCA2_crl_empty.pem <<\n$(cat ${testdir}/interCA2_crl_empty.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl crl-file ${testdir}/interCA2_crl_empty.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+# Change the backend's CRL file to one in which the frontend's certificate is revoked
+shell {
+ printf "set ssl crl-file ${testdir}/interCA1_crl_empty.pem <<\n$(cat ${testdir}/interCA1_crl.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl crl-file ${testdir}/interCA1_crl_empty.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+# This connection should fail, the client's certificate is revoked in the newly updated CRL file
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ # Revoked certificate
+ expect resp.http.X-SSL-Client-Verify == 23
+} -run
diff --git a/reg-tests/ssl/set_ssl_server_cert.vtc b/reg-tests/ssl/set_ssl_server_cert.vtc
new file mode 100644
index 0000000..847d45b
--- /dev/null
+++ b/reg-tests/ssl/set_ssl_server_cert.vtc
@@ -0,0 +1,129 @@
+#REGTEST_TYPE=devel
+
+# This reg-test uses the "set ssl cert" command to update a backend certificate over the CLI.
+# It requires socat to upload the certificate
+
+varnishtest "Test the 'set ssl cert' feature of the CLI"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.4)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && !ssllib_name_startswith(wolfSSL)'"
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 4 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+ nbthread 1
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ retries 0 # 2nd SSL connection must fail so skip the retry
+ server s1 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/client1.pem
+
+ listen ssl-lst
+ # crt: certificate of the server
+ # ca-file: CA used for client authentication request
+ # crl-file: revocation list for client auth: the client1 certificate is revoked
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/ca-auth.crt verify optional crt-ignore-err all crl-file ${testdir}/crl-auth.pem
+
+ acl cert_expired ssl_c_verify 10
+ acl cert_revoked ssl_c_verify 23
+ acl cert_ok ssl_c_verify 0
+
+ http-response add-header X-SSL Ok if cert_ok
+ http-response add-header X-SSL Expired if cert_expired
+ http-response add-header X-SSL Revoked if cert_revoked
+ http-response add-header x-ssl-sha1 %[ssl_c_sha1,hex]
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sha1 == "D9C3BAE37EA5A7EDB7B3C9BDD4DCB2FE58A412E4"
+ expect resp.http.x-ssl == "Ok"
+} -run
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/client1.pem"
+ expect ~ ".*SHA1 FingerPrint: D9C3BAE37EA5A7EDB7B3C9BDD4DCB2FE58A412E4"
+}
+
+# Replace certificate with an expired one
+shell {
+ printf "set ssl cert ${testdir}/client1.pem <<\n$(cat ${testdir}/client2_expired.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/client1.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/client1.pem"
+ expect ~ ".*SHA1 FingerPrint: C625EB01A0A660294B9D7F44C5CEEE5AFC495BE4"
+}
+
+
+# The updated client certificate is an expired one so this request should fail
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sha1 == "C625EB01A0A660294B9D7F44C5CEEE5AFC495BE4"
+ expect resp.http.x-ssl == "Expired"
+} -run
+
+# Replace certificate with a revoked one
+shell {
+ printf "set ssl cert ${testdir}/client1.pem <<\n$(cat ${testdir}/client3_revoked.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/client1.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/client1.pem"
+ expect ~ ".*SHA1 FingerPrint: 992386628A40C9D49C89BAC0058B5D45D8575151"
+}
+
+# The updated client certificate is a revoked one so this request should fail
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sha1 == "992386628A40C9D49C89BAC0058B5D45D8575151"
+ expect resp.http.x-ssl == "Revoked"
+} -run
+
+# Abort a transaction
+shell {
+ printf "set ssl cert ${testdir}/client1.pem <<\n$(cat ${testdir}/client3_revoked.pem)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "abort ssl cert ${testdir}/client1.pem" | socat "${tmpdir}/h1/stats" -
+}
+
+haproxy h1 -cli {
+ send "show ssl cert ${testdir}/client1.pem"
+ expect ~ ".*SHA1 FingerPrint: 992386628A40C9D49C89BAC0058B5D45D8575151"
+}
+
+# The certificate was not updated so it should still be revoked
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "Revoked"
+} -run
+
+
diff --git a/reg-tests/ssl/show_ocsp_server.pem b/reg-tests/ssl/show_ocsp_server.pem
new file mode 100644
index 0000000..a652359
--- /dev/null
+++ b/reg-tests/ssl/show_ocsp_server.pem
@@ -0,0 +1,119 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 4111 (0x100f)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=FR, O=HAProxy Technologies, CN=Root CA
+ Validity
+ Not Before: Jun 10 08:54:19 2021 GMT
+ Not After : Oct 26 08:54:19 2048 GMT
+ Subject: C=FR, O=HAProxy Technologies, CN=Server Certificate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public-Key: (2048 bit)
+ Modulus:
+ 00:e9:88:7e:5e:ec:81:d0:f7:2b:9b:c9:5d:81:ea:
+ 9c:ff:61:2f:4b:a2:ad:08:4d:44:7c:65:fa:ab:3a:
+ f2:be:63:ac:34:5c:c4:05:35:be:d4:79:af:a5:fc:
+ 9e:92:10:75:b1:4d:70:d6:82:a3:7e:7e:b0:e6:2c:
+ ba:ec:1b:e9:7f:55:f3:98:6e:d5:b2:00:37:05:76:
+ df:28:be:3e:89:52:ec:47:58:45:7a:dd:7d:89:ae:
+ 7f:43:d6:a5:ce:f6:8d:8d:32:fe:33:dc:16:15:01:
+ 82:23:d1:77:12:75:a2:e2:2a:08:eb:cd:32:1e:5b:
+ 54:12:68:83:21:3a:6e:07:f5:99:f4:e7:79:eb:f7:
+ d0:d9:71:f2:1d:79:08:a2:63:df:ab:59:f3:ac:33:
+ 18:d6:0a:9c:48:0b:9a:b0:ae:79:7b:8e:5a:1d:d2:
+ fc:5c:6c:a5:d5:61:88:e8:50:c2:0f:f2:5b:0d:0c:
+ 82:18:c8:a1:98:19:8a:fc:28:c6:27:e7:94:de:3d:
+ 13:44:16:12:9e:e1:a8:b0:17:a1:4d:14:84:3e:44:
+ bc:76:5d:cd:4e:67:9c:e6:69:0b:5a:fe:cf:08:bb:
+ 6d:0b:be:d6:8e:5d:c6:fc:53:e2:ab:34:28:2f:ef:
+ 03:5a:c4:ad:b7:e8:4e:1c:89:67:78:f5:a4:41:fd:
+ 80:f3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ Authority Information Access:
+ OCSP - URI:http://ocsp.haproxy.com
+
+ Signature Algorithm: sha256WithRSAEncryption
+ 14:c3:1a:2c:37:d4:91:74:10:be:eb:f3:1e:f3:da:cf:ed:0d:
+ b1:37:8e:e8:0c:44:cb:28:ce:4b:5c:ed:02:35:13:55:e1:34:
+ 93:aa:7d:91:fa:4c:a7:31:09:6a:23:b7:0a:d3:37:70:dd:48:
+ 9c:b6:af:31:d7:28:c1:cf:7d:44:f0:d5:ac:58:56:74:40:48:
+ a6:21:85:ea:bf:38:52:fc:8e:16:7c:4d:79:d3:b4:18:11:90:
+ 95:a7:f4:b6:5f:91:dc:3e:bd:e7:58:96:ff:c2:d2:59:20:ed:
+ 4e:de:e5:92:c9:a6:5a:37:a1:fd:00:cb:13:51:ef:ce:98:c8:
+ 01:b5:a1:9a:74:63:a0:da:dc:39:1e:08:8b:60:04:7f:96:c8:
+ 02:cd:cc:dc:04:a4:4c:84:8f:a1:30:49:99:e1:6c:0c:39:65:
+ 2c:03:f8:60:46:cb:28:42:6a:c4:b0:bb:7f:be:67:de:1e:55:
+ 10:2a:55:1f:58:d4:fc:b0:74:9e:11:95:0b:c0:cc:f6:fc:6d:
+ ce:25:17:48:dc:30:5e:b3:29:44:10:11:2d:47:2d:06:81:21:
+ 51:55:4a:4d:72:79:49:ad:29:77:64:92:e7:4e:c9:4f:4c:25:
+ 4d:24:3c:49:07:af:53:74:b5:14:05:e2:f2:fc:ba:d7:a0:db:
+ e4:e4:38:74:fe:f0:34:98:78:f4:2c:68:2d:a6:1e:2d:16:d6:
+ 2b:1d:95:3c:ac:9d:16:6a:7e:d4:cd:0c:94:2b:f4:94:1c:ef:
+ 3b:23:13:78:14:ea:ea:2f:08:f4:ed:21:3d:50:77:4b:50:fe:
+ db:47:19:d1:36:92:7d:7e:e3:18:40:1d:65:0e:fe:95:4f:54:
+ 60:15:16:57:72:06:93:03:ee:8c:89:4e:7b:0b:13:a5:ef:52:
+ c9:53:8d:77:b4:7f:11:f8:03:f1:ce:a0:f8:33:06:89:44:7b:
+ f7:14:4a:51:ba:0e:35:88:ea:69:44:bd:3f:76:78:23:86:79:
+ 13:00:40:1a:d0:69:42:41:72:e6:81:a7:b2:11:25:37:73:15:
+ 89:a7:36:5d:75:3c:e9:1b:dc:ea:8c:98:6e:24:f9:98:e1:62:
+ d6:12:34:a4:c1:bc:08:fd:4d:86:8e:43:a9:9a:36:26:ba:f5:
+ ab:13:9c:08:09:8d:bf:13:84:a0:5f:52:78:fc:1d:11:0c:d6:
+ e1:a3:0c:ce:4d:21:79:90:2a:bb:04:03:d9:76:71:81:36:2a:
+ 1c:56:79:e7:32:03:d8:41:cc:73:e5:6e:45:4e:2d:c9:b0:cc:
+ 70:6b:47:93:6b:00:d0:6d:94:5f:db:e1:d5:dd:73:11:9f:b7:
+ c1:75:50:43:17:b5:e6:51
+-----BEGIN CERTIFICATE-----
+MIIEOjCCAiKgAwIBAgICEA8wDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRAwDgYDVQQDDAdSb290IENB
+MB4XDTIxMDYxMDA4NTQxOVoXDTQ4MTAyNjA4NTQxOVowSTELMAkGA1UEBhMCRlIx
+HTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVzMRswGQYDVQQDDBJTZXJ2ZXIg
+Q2VydGlmaWNhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpiH5e
+7IHQ9yubyV2B6pz/YS9Loq0ITUR8ZfqrOvK+Y6w0XMQFNb7Uea+l/J6SEHWxTXDW
+gqN+frDmLLrsG+l/VfOYbtWyADcFdt8ovj6JUuxHWEV63X2Jrn9D1qXO9o2NMv4z
+3BYVAYIj0XcSdaLiKgjrzTIeW1QSaIMhOm4H9Zn053nr99DZcfIdeQiiY9+rWfOs
+MxjWCpxIC5qwrnl7jlod0vxcbKXVYYjoUMIP8lsNDIIYyKGYGYr8KMYn55TePRNE
+FhKe4aiwF6FNFIQ+RLx2Xc1OZ5zmaQta/s8Iu20LvtaOXcb8U+KrNCgv7wNaxK23
+6E4ciWd49aRB/YDzAgMBAAGjNzA1MDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcw
+AYYXaHR0cDovL29jc3AuaGFwcm94eS5jb20wDQYJKoZIhvcNAQELBQADggIBABTD
+Giw31JF0EL7r8x7z2s/tDbE3jugMRMsozktc7QI1E1XhNJOqfZH6TKcxCWojtwrT
+N3DdSJy2rzHXKMHPfUTw1axYVnRASKYhheq/OFL8jhZ8TXnTtBgRkJWn9LZfkdw+
+vedYlv/C0lkg7U7e5ZLJplo3of0AyxNR786YyAG1oZp0Y6Da3DkeCItgBH+WyALN
+zNwEpEyEj6EwSZnhbAw5ZSwD+GBGyyhCasSwu3++Z94eVRAqVR9Y1PywdJ4RlQvA
+zPb8bc4lF0jcMF6zKUQQES1HLQaBIVFVSk1yeUmtKXdkkudOyU9MJU0kPEkHr1N0
+tRQF4vL8uteg2+TkOHT+8DSYePQsaC2mHi0W1isdlTysnRZqftTNDJQr9JQc7zsj
+E3gU6uovCPTtIT1Qd0tQ/ttHGdE2kn1+4xhAHWUO/pVPVGAVFldyBpMD7oyJTnsL
+E6XvUslTjXe0fxH4A/HOoPgzBolEe/cUSlG6DjWI6mlEvT92eCOGeRMAQBrQaUJB
+cuaBp7IRJTdzFYmnNl11POkb3OqMmG4k+ZjhYtYSNKTBvAj9TYaOQ6maNia69asT
+nAgJjb8ThKBfUnj8HREM1uGjDM5NIXmQKrsEA9l2cYE2KhxWeecyA9hBzHPlbkVO
+LcmwzHBrR5NrANBtlF/b4dXdcxGft8F1UEMXteZR
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA6Yh+XuyB0Pcrm8ldgeqc/2EvS6KtCE1EfGX6qzryvmOsNFzE
+BTW+1HmvpfyekhB1sU1w1oKjfn6w5iy67Bvpf1XzmG7VsgA3BXbfKL4+iVLsR1hF
+et19ia5/Q9alzvaNjTL+M9wWFQGCI9F3EnWi4ioI680yHltUEmiDITpuB/WZ9Od5
+6/fQ2XHyHXkIomPfq1nzrDMY1gqcSAuasK55e45aHdL8XGyl1WGI6FDCD/JbDQyC
+GMihmBmK/CjGJ+eU3j0TRBYSnuGosBehTRSEPkS8dl3NTmec5mkLWv7PCLttC77W
+jl3G/FPiqzQoL+8DWsStt+hOHIlnePWkQf2A8wIDAQABAoIBAQDktypU2zrUpo6O
+F6u9xkIWl17Tq7HddJdDYjkbJDODJWkNK2FLXPTVcYwGe5/tm7M4f4iofe+Tvo6Q
+D3TOMxP/AvX872fY2f8JGf+7Dn9+zLjdsuTxTSVbB4xaq0lepffCNxPhRIZX8k87
+tzTv3kg1SkfMcP3J31Y6ZSMwEuKaZR9bkIT2MlLw89Qrg/o1Z1Yuu4CoJhgJ9x4Q
+smJmu6uu152i0tqQDK76nHfTgK6GTyHQpP/njXZ3gD/4vTOKsZPoXEtM9gq1Ihqm
+c7Pcy71q9nOBWfG3KUVhIlOahyVPewAFG7vNsPWVE0mN3FhCIEUPPLNnvAydSPaV
+vbwohs4BAoGBAPqXF6cTKWIfHTn4TrcOcKslKEzVSgJabZeYw1kTRsSLCsvV3ojx
+txW4A8FM+EVwX+K6FmpAxN9aKERVv1Ez3xvjmZf6czgREd8F2X2j6SwkcSwVZaxz
+FCl81jz6r/9CGP6Wbq0uVKGhEdNYddhc3RvR8oWwnMEgwIkOvfnpCevzAoGBAO6T
+IljTIzsZmLLFdhvS49C4bQ71vQbEnybqHENZcPdjrgbwRDLjQ4ZEGLm/O1zmKVZh
+C5rRqd/fWVtzMPmZJr0aNeVN3dYob/1SS6ixu/D55jRII6RtkTrm8bmOlUXIx3BB
+sgDOhG61U4LJ8n4Utcgv4go1feRNQkIo5qXkLFcBAoGALB0HE+liopxZl8fni4Am
+Q2qiIox1n95tZn+E/BxRm+3iM6ntp+vtUAx51MCJAChdKNubcI8AWVVUu1rg+BmK
+kC1L754uRFN08u7jr6N4O8YaiikmIeqMRRVt3YRAEU6AeejfiOscCOwC6FKtRC5s
+2iXmbLR/k9wBKN+IgAMPNRMCgYEA44MIxDBFbrzQM9u+8HXCr27RAe0y4Fttcszb
+Oxb2ddVnRlKmlujHoikaczh8wfD0Bt3xFSlQmKAENQO69qwolzmBoDULkolpkuiC
+IlOsaPfHoqAQ7WNXlhZa+puQmsYH+3OK7t4CyRi+lQFE8RuK52dSZm3wqmFLCJC8
+tALOjgECgYEAjREmEh/o/moOfIp8x18GYkYkJCv3+/UwMD8kJUu3KtXhER6Kgi2t
+GgqGV7nHm+sZjck+tcWdT7s+SJWQ2t8QkOf9xavy6mhG6ptJT7xoXSCxAUzNjLQZ
+WpoLVecRfaiAwj9DbbVWhjy8RDkyAHcHveVSIH40I7K0oTbNPqyJk6U=
+-----END RSA PRIVATE KEY-----
diff --git a/reg-tests/ssl/show_ocsp_server.pem.issuer b/reg-tests/ssl/show_ocsp_server.pem.issuer
new file mode 100644
index 0000000..bed2061
--- /dev/null
+++ b/reg-tests/ssl/show_ocsp_server.pem.issuer
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFGjCCAwKgAwIBAgIUHgviUJMgCZlOPOhVc09pZ4NhfxcwDQYJKoZIhvcNAQEL
+BQAwPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMB4XDTIxMDQyMjE0MDEyMFoXDTQ4MDkwNzE0MDEy
+MFowPjELMAkGA1UEBhMCRlIxHTAbBgNVBAoMFEhBUHJveHkgVGVjaG5vbG9naWVz
+MRAwDgYDVQQDDAdSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEAti+5onUeFJNyF5s6xlnBxDnFhw7Q5VbBestHeQttjBWN31zq5yaf/+CYXdu+
+lY6gNZj6JBiFJ5P7VXX3DqUIJBX6byXWfIUWM+auBAMKlTz0+hWrF/UxI/3uG67N
++Z6NVffEPYbA4Emqozr0DIicWorRyHnrhEQQP87xBCUboUr3QEkNngfiJ0fPm3fj
+7HfQemGL2OnTA8qdy0q1l4aUhVr9bgedP2Klvs0XhbszCGLI0Gq5lyNadlH1MEiw
+SXa9rklE6NCNcyamO7Wt8LVrg6pxopa7oGnkLbnjzSuE+xsN0isOLaHH5LfYg6gT
+aAHpnBHiWuDZQIyzKc+Z37gNksd46/y9B+oBZoCTcYMOsn7PK+gPzTbu3ic4L9hO
+WCsTV0tn+qUGj6/J98gRgvuvZGA7NPDKNZU5p34oyApBPBUOgpn6pCuT5NlkPYAe
+Rp/ypiy5NCHp0JW3JWkJ4+wEasZM34TZUYrOsicA0GV4ZVkoQ3WYyAjmLvRXmo/w
+Z3sSlmHvCg9MrQ9pk24+OtvCbii0bb/Zmlx0Y4lU5TogcuJffJDVbj7oxTc2gRmI
+SIZsnYLv2qVoeBoMY5otj+ef0Y8v98mKCbiWe2MzBkC2h5wmwyWedez8RysTaFHS
+Z4yOYoCsEAtCxnib9d5fXf0+6aOuFtKMknkuWbYj6En647ECAwEAAaMQMA4wDAYD
+VR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAjVzxHzq/87uj24It5hYj4mq4
+ero0zix4fA4tJNuTpZ/5r7GUYaf/uT4xfDilBX2fGMsxVTxJC25KzhdFeTzg1Tde
+/N0LAeLWHfe6jR/P5XDATD0ZA73DQALOxRM5uRMeWJDVaUeco/aXsdQaCz2STDI3
+h7VVFoaOlmxQW3BBEvg2VUp9DS2UjqqdwsUDtzwKfrmj/FqyBvGrvNeIMv28HCu7
+r1WE1Z0UEJhpc1BPbu7F/vl60gRF3bQjh2tL8pWThxTJe6Qy+pLoSShyi85AM9XK
+scCmUtQWjy7KQDL8XVFvuCWvMzknZQjJcncbKddPaaSIDkKUpz9FDv+wSJj/LKf7
+bGSFPM6sblioLbLNJByRYI8G7VHvKDbUnYHbHp75NTGA2eDeNqx5bC2G/EJUTwLM
+bfcZr9hv+z1QpvSLEpar30kJjc1QMQcf60ToGYIC93rsVAKou2GPGry4h/nzwro0
+jjFWNgORTXllfcQDbDNOPkV1kFFibPbAU4faZMgC+xwIwDBsndvcvXjLaRUa4fmw
+1xNkOO5Lj9AuvTXdCc9yUXRzmPZhU6Q4YB2daWvs3vbMTtvkAXGyQL4b2HD+NYZs
+cMUtbteGgQzwM1gpMBn4GX53vhlCXq28r3cH1/1tLDweglSrxyvZbB7pZU7BAmLk
+TEj2fXcvdcX+TtYhC10=
+-----END CERTIFICATE-----
diff --git a/reg-tests/ssl/show_ocsp_server.pem.ocsp b/reg-tests/ssl/show_ocsp_server.pem.ocsp
new file mode 100644
index 0000000..5ac1457
--- /dev/null
+++ b/reg-tests/ssl/show_ocsp_server.pem.ocsp
Binary files differ
diff --git a/reg-tests/ssl/show_ocsp_server.pem.ocsp.revoked b/reg-tests/ssl/show_ocsp_server.pem.ocsp.revoked
new file mode 100644
index 0000000..bf69b3d
--- /dev/null
+++ b/reg-tests/ssl/show_ocsp_server.pem.ocsp.revoked
Binary files differ
diff --git a/reg-tests/ssl/show_ssl_ocspresponse.vtc b/reg-tests/ssl/show_ssl_ocspresponse.vtc
new file mode 100644
index 0000000..8b1db16
--- /dev/null
+++ b/reg-tests/ssl/show_ssl_ocspresponse.vtc
@@ -0,0 +1,144 @@
+#REGTEST_TYPE=devel
+
+# broken with BoringSSL.
+
+# This reg-test uses the "show ssl ocsp-response" command to display the details
+# of the OCSP responses used by HAProxy.
+# It also uses the new special cases of the "show ssl cert" command, where an OCSP
+# extension is provided to the certificate name (with or without preceding * for an
+# ongoing transaction).
+#
+# It uses the show_ocsp_server.pem server certificate, signed off by set_cafile_rootCA.crt,
+# which has two OCSP responses, show_ocsp_server.pem.ocsp which is loaded by default and in
+# which it is valid, and show_ocsp_server.pem.ocsp.revoked in which it is revoked.
+# The OSCP response is updated through the two means available in the CLI, the
+# "set ssl ocsp-response" command and the update through a "set ssl cert foo.ocsp".
+#
+# It requires socat to upload the new OCSP responses.
+#
+# If this test does not work anymore:
+# - Check that you have socat
+
+varnishtest "Test the 'show ssl ocsp-response' and 'show ssl cert foo.pem.ocsp' features of the CLI"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && !ssllib_name_startswith(BoringSSL) && !ssllib_name_startswith(wolfSSL)'"
+feature cmd "command -v socat && command -v openssl"
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ server s1 "${tmpdir}/ssl.sock" ssl ca-file ${testdir}/set_cafile_rootCA.crt verify none
+
+ listen ssl-lst
+ # crt: certificate of the server
+ # ca-file: CA used for client authentication request
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/show_ocsp_server.pem ca-file ${testdir}/set_cafile_rootCA.crt verify none crt-ignore-err all
+ http-response add-header X-SSL-Client-Verify %[ssl_c_verify]
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+# Test the "show ssl ocsp-response" command
+haproxy h1 -cli {
+ send "show ssl ocsp-response"
+ expect ~ "Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+ expect ~ "Responder Id: C = FR, O = HAProxy Technologies, CN = ocsp.haproxy.com"
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+ expect ~ "Cert Status: good"
+}
+
+# Test the "show ssl ocsp-response" command with a certificate path as parameter
+shell {
+ ocsp_response=$(echo "show ssl ocsp-response ${testdir}/show_ocsp_server.pem" | socat "${tmpdir}/h1/stats" -)
+
+ echo "$ocsp_response" | grep "Responder Id: C = FR, O = HAProxy Technologies, CN = ocsp.haproxy.com" &&
+ echo "$ocsp_response" | grep "Cert Status: good"
+}
+
+# Test the "show ssl cert foo.pem.ocsp" command
+haproxy h1 -cli {
+ send "show ssl cert"
+ expect ~ ".*show_ocsp_server.pem"
+
+ send "show ssl cert ${testdir}/show_ocsp_server.pem"
+ expect ~ "Serial: 100F"
+ send "show ssl cert ${testdir}/show_ocsp_server.pem"
+ expect ~ "OCSP Response Key: 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+
+ send "show ssl cert ${testdir}/show_ocsp_server.pem.ocsp"
+ expect ~ "Responder Id: C = FR, O = HAProxy Technologies, CN = ocsp.haproxy.com"
+ send "show ssl cert ${testdir}/show_ocsp_server.pem.ocsp"
+ expect ~ "Cert Status: good"
+}
+
+
+# Change the server certificate's OCSP response through "set ssl ocsp-response"
+shell {
+ printf "set ssl ocsp-response <<\n$(cat ${testdir}/show_ocsp_server.pem.ocsp.revoked|openssl base64)\n\n" | socat "${tmpdir}/h1/stats" -
+}
+
+# Check that the change was taken into account
+haproxy h1 -cli {
+ send "show ssl ocsp-response"
+ expect ~ "Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+ expect ~ "Responder Id: C = FR, O = HAProxy Technologies, CN = ocsp.haproxy.com"
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+ expect ~ "Cert Status: revoked"
+
+ send "show ssl cert ${testdir}/show_ocsp_server.pem.ocsp"
+ expect ~ "Cert Status: revoked"
+}
+
+
+# Change the server certificate's OCSP response through a transaction
+shell {
+ printf "set ssl cert ${testdir}/show_ocsp_server.pem <<\n$(cat ${testdir}/show_ocsp_server.pem | sed '/^$/d')\n\n" | socat "${tmpdir}/h1/stats" -
+ printf "set ssl cert ${testdir}/show_ocsp_server.pem.issuer <<\n$(cat ${testdir}/show_ocsp_server.pem.issuer | sed '/^$/d')\n\n" | socat "${tmpdir}/h1/stats" -
+ printf "set ssl cert ${testdir}/show_ocsp_server.pem.ocsp <<\n$(cat ${testdir}/show_ocsp_server.pem.ocsp|openssl base64)\n\n" | socat "${tmpdir}/h1/stats" -
+}
+
+
+# Check that the actual tree entry was not changed and that the uncommitted
+# transaction's OCSP response is the new one
+haproxy h1 -cli {
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+ expect ~ "Cert Status: revoked"
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+ expect ~ "This Update: Jun 10 08:57:45 2021 GMT"
+
+ send "show ssl cert *${testdir}/show_ocsp_server.pem.ocsp"
+ expect ~ "Cert Status: good"
+ send "show ssl cert *${testdir}/show_ocsp_server.pem.ocsp"
+ expect ~ "This Update: Jun 10 08:55:04 2021 GMT"
+}
+
+
+# Commit the transaction and check that it was taken into account
+haproxy h1 -cli {
+ send "commit ssl cert ${testdir}/show_ocsp_server.pem"
+ expect ~ "Success!"
+
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+ expect ~ "Cert Status: good"
+ send "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100f"
+ expect ~ "This Update: Jun 10 08:55:04 2021 GMT"
+}
diff --git a/reg-tests/ssl/simple.crt-list b/reg-tests/ssl/simple.crt-list
new file mode 100644
index 0000000..9ffacb4
--- /dev/null
+++ b/reg-tests/ssl/simple.crt-list
@@ -0,0 +1,5 @@
+common.pem record1.bug940.domain.tld
+common.pem record2.bug940.domain.tld
+ecdsa.pem record3.bug940.domain.tld
+ecdsa.pem record4.bug940.domain.tld
+
diff --git a/reg-tests/ssl/ssl_alpn.vtc b/reg-tests/ssl/ssl_alpn.vtc
new file mode 100644
index 0000000..dfc63ac
--- /dev/null
+++ b/reg-tests/ssl/ssl_alpn.vtc
@@ -0,0 +1,212 @@
+#REGTEST_TYPE=devel
+
+# This teg-test verifies that different ALPN values on the "server" line
+# will negotiate the expected protocol depending on the ALPN "bind" line.
+# It requires OpenSSL >= 1.0.2 for ALPN
+
+varnishtest "Test the bind 'alpn' setting"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.8-dev7)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && openssl_version_atleast(1.0.2)'"
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen px-clr
+ bind "fd@${clearfe}"
+ default-server ssl verify none
+
+ # first digit select the alpn sent by the client, second digit, the server one
+ use-server s00 if { path /00 }
+ server s00 "${tmpdir}/ssl0.sock"
+ use-server s01 if { path /01 }
+ server s01 "${tmpdir}/ssl1.sock"
+ use-server s02 if { path /02 }
+ server s02 "${tmpdir}/ssl2.sock"
+ use-server s03 if { path /03 }
+ server s03 "${tmpdir}/ssl3.sock"
+ use-server s04 if { path /04 }
+ server s04 "${tmpdir}/ssl4.sock"
+
+ use-server s10 if { path /10 }
+ server s10 "${tmpdir}/ssl0.sock" alpn http/1.1
+ use-server s11 if { path /11 }
+ server s11 "${tmpdir}/ssl1.sock" alpn http/1.1
+ use-server s12 if { path /12 }
+ server s12 "${tmpdir}/ssl2.sock" alpn http/1.1
+ use-server s13 if { path /13 }
+ server s13 "${tmpdir}/ssl3.sock" alpn http/1.1
+ use-server s14 if { path /14 }
+ server s14 "${tmpdir}/ssl4.sock" alpn http/1.1
+
+ use-server s20 if { path /20 }
+ server s20 "${tmpdir}/ssl0.sock" alpn h2
+ use-server s21 if { path /21 }
+ server s21 "${tmpdir}/ssl1.sock" alpn h2
+ use-server s22 if { path /22 }
+ server s22 "${tmpdir}/ssl2.sock" alpn h2
+ use-server s23 if { path /23 }
+ server s23 "${tmpdir}/ssl3.sock" alpn h2
+ use-server s24 if { path /24 }
+ server s24 "${tmpdir}/ssl4.sock" alpn h2
+
+ use-server s30 if { path /30 }
+ server s30 "${tmpdir}/ssl0.sock" alpn h2,http/1.1
+ use-server s31 if { path /31 }
+ server s31 "${tmpdir}/ssl1.sock" alpn h2,http/1.1
+ use-server s32 if { path /32 }
+ server s32 "${tmpdir}/ssl2.sock" alpn h2,http/1.1
+ use-server s33 if { path /33 }
+ server s33 "${tmpdir}/ssl3.sock" alpn h2,http/1.1
+ use-server s34 if { path /34 }
+ server s34 "${tmpdir}/ssl4.sock" alpn h2,http/1.1
+
+ frontend fe-ssl
+ bind "${tmpdir}/ssl0.sock" ssl crt ${testdir}/common.pem
+ bind "${tmpdir}/ssl1.sock" ssl crt ${testdir}/common.pem alpn http/1.1
+ bind "${tmpdir}/ssl2.sock" ssl crt ${testdir}/common.pem alpn h2
+ bind "${tmpdir}/ssl3.sock" ssl crt ${testdir}/common.pem alpn h2,http/1.1
+ bind "${tmpdir}/ssl4.sock" ssl crt ${testdir}/common.pem no-alpn
+ http-request return status 200 hdr x-alpn _%[ssl_fc_alpn] hdr x-path %[path] hdr x-ver _%[req.ver]
+} -start
+
+# client sends no alpn
+client c1 -connect ${h1_clearfe_sock} {
+ txreq -url "/00"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_"
+ expect resp.http.x-ver == "_1.1"
+
+ txreq -url "/01"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_"
+ expect resp.http.x-ver == "_1.1"
+
+ txreq -url "/02"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_"
+ expect resp.http.x-ver == "_1.1"
+
+ txreq -url "/03"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_"
+ expect resp.http.x-ver == "_1.1"
+
+ txreq -url "/04"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_"
+ expect resp.http.x-ver == "_1.1"
+} -run
+
+# client sends alpn=http/1.1
+client c1 -connect ${h1_clearfe_sock} {
+ txreq -url "/10"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_http/1.1"
+ expect resp.http.x-ver == "_1.1"
+
+ txreq -url "/11"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_http/1.1"
+ expect resp.http.x-ver == "_1.1"
+
+ txreq -url "/12"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_"
+ expect resp.http.x-ver == "_1.1"
+
+ txreq -url "/13"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_http/1.1"
+ expect resp.http.x-ver == "_1.1"
+
+ txreq -url "/14"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_"
+ expect resp.http.x-ver == "_1.1"
+} -run
+
+# client sends alpn=h2
+client c1 -connect ${h1_clearfe_sock} {
+ txreq -url "/20"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_h2"
+ expect resp.http.x-ver == "_2.0"
+
+ txreq -url "/21"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_"
+ expect resp.http.x-ver == "_1.1"
+
+ txreq -url "/22"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_h2"
+ expect resp.http.x-ver == "_2.0"
+
+ txreq -url "/23"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_h2"
+ expect resp.http.x-ver == "_2.0"
+
+ txreq -url "/24"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_"
+ expect resp.http.x-ver == "_1.1"
+} -run
+
+# client sends alpn=h2,http/1.1
+client c1 -connect ${h1_clearfe_sock} {
+ txreq -url "/30"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_h2"
+ expect resp.http.x-ver == "_2.0"
+
+ txreq -url "/31"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_http/1.1"
+ expect resp.http.x-ver == "_1.1"
+
+ txreq -url "/32"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_h2"
+ expect resp.http.x-ver == "_2.0"
+
+ txreq -url "/33"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_h2"
+ expect resp.http.x-ver == "_2.0"
+
+ txreq -url "/34"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-alpn == "_"
+ expect resp.http.x-ver == "_1.1"
+} -run
diff --git a/reg-tests/ssl/ssl_client_auth.vtc b/reg-tests/ssl/ssl_client_auth.vtc
new file mode 100644
index 0000000..ab8ba18
--- /dev/null
+++ b/reg-tests/ssl/ssl_client_auth.vtc
@@ -0,0 +1,76 @@
+#REGTEST_TYPE=devel
+
+# This reg-test tests the client auth feature of HAProxy for both the backend
+# and frontend section with a CRL list
+#
+# This reg-test uses 2 chained listeners because vtest does not handle the SSL.
+# Test the frontend client auth and the backend side at the same time.
+#
+# The sends 3 requests one with a correct certificate, one with an expired one and one which was revoked.
+# The client then check if we received the right one with the right error.
+#
+# Certificates, CA and CRL are expiring in 2050 so it should be fine for the CI.
+#
+# Detail about configuration is explained there:
+# https://www.haproxy.com/blog/ssl-client-certificate-management-at-application-level/
+
+varnishtest "Test the client auth"
+#REQUIRE_OPTIONS=OPENSSL
+feature ignore_unknown_macro
+
+server s1 -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ # crt: certificate sent for a client certificate request
+ server s1 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/client1.pem
+ server s2 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/client2_expired.pem # expired
+ server s3 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/client3_revoked.pem # revoked
+
+ listen ssl-lst
+ # crt: certificate of the server
+ # ca-file: CA used for client authentication request
+ # crl-file: revocation list for client auth: the client1 certificate is revoked
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/ca-auth.crt verify optional crt-ignore-err X509_V_ERR_CERT_REVOKED,X509_V_ERR_CERT_HAS_EXPIRED crl-file ${testdir}/crl-auth.pem
+
+ http-response add-header X-SSL %[ssl_c_verify,x509_v_err_str]
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "X509_V_OK"
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "X509_V_ERR_CERT_HAS_EXPIRED"
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "X509_V_ERR_CERT_REVOKED"
+} -run
diff --git a/reg-tests/ssl/ssl_client_samples.vtc b/reg-tests/ssl/ssl_client_samples.vtc
new file mode 100644
index 0000000..5a84e4b
--- /dev/null
+++ b/reg-tests/ssl/ssl_client_samples.vtc
@@ -0,0 +1,74 @@
+#REGTEST_TYPE=devel
+
+varnishtest "Test the ssl_c_* sample fetches"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.8-dev11)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && openssl_version_atleast(1.1.1)'"
+feature ignore_unknown_macro
+
+server s1 -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ crt-base ${testdir}
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ server s1 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/client1.pem
+
+ listen ssl-lst
+ mode http
+
+ http-response add-header x-ssl-der %[ssl_c_der,hex]
+ http-response add-header x-ssl-chain-der %[ssl_c_chain_der,hex]
+ http-response add-header x-ssl-sha1 %[ssl_c_sha1,hex]
+ http-response add-header x-ssl-notafter %[ssl_c_notafter]
+ http-response add-header x-ssl-notbefore %[ssl_c_notbefore]
+ http-response add-header x-ssl-sig_alg %[ssl_c_sig_alg]
+ http-response add-header x-ssl-i_dn %[ssl_c_i_dn]
+ http-response add-header x-ssl-s_dn %[ssl_c_s_dn]
+ http-response add-header x-ssl-r_dn %[ssl_c_r_dn]
+ http-response add-header x-ssl-s_serial %[ssl_c_serial,hex]
+ http-response add-header x-ssl-key_alg %[ssl_c_key_alg]
+ http-response add-header x-ssl-version %[ssl_c_version]
+
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/ca-auth.crt verify optional crt-ignore-err all crl-file ${testdir}/crl-auth.pem
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-der ~ 3082052D30820315020102300D0.*995ED3BE2BFB923A3EB71FA07002E
+ expect resp.http.x-ssl-chain-der ~ 3082096B30820553A0030201020.*0237D08F425C8414A23D436415502
+ expect resp.http.x-ssl-sha1 == "D9C3BAE37EA5A7EDB7B3C9BDD4DCB2FE58A412E4"
+ expect resp.http.x-ssl-notafter == "500421185942Z"
+ expect resp.http.x-ssl-notbefore == "200428185942Z"
+ expect resp.http.x-ssl-sig_alg == "RSA-SHA256"
+ expect resp.http.x-ssl-i_dn == "/C=FR/ST=Some-State/O=HAProxy Technologies/CN=HAProxy Technologies CA Test Client Auth"
+ expect resp.http.x-ssl-s_dn == "/C=FR/O=HAProxy Technologies Test/CN=client1"
+ expect resp.http.x-ssl-r_dn == "/C=FR/ST=Some-State/O=HAProxy Technologies/CN=HAProxy Technologies CA Test Client Auth"
+ expect resp.http.x-ssl-s_serial == "02"
+ expect resp.http.x-ssl-key_alg == "rsaEncryption"
+ expect resp.http.x-ssl-version == "1"
+} -run
+
+
diff --git a/reg-tests/ssl/ssl_crt-list_filters.vtc b/reg-tests/ssl/ssl_crt-list_filters.vtc
new file mode 100644
index 0000000..e98efb7
--- /dev/null
+++ b/reg-tests/ssl/ssl_crt-list_filters.vtc
@@ -0,0 +1,124 @@
+#REGTEST_TYPE=bug
+varnishtest "Test for ECDSA/RSA selection and crt-list filters"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.8)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && ssllib_name_startswith(OpenSSL) && openssl_version_atleast(1.1.1)'"
+# This test checks if the multiple certificate types works correctly with the
+# SNI, and that the negative filters are correctly excluded
+#
+# The selection is done with ciphers in TLSv1.2 and with the sigalgs in TLSv1.3
+#
+feature ignore_unknown_macro
+
+server s1 -repeat 6 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ crt-base ${testdir}
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ retries 0
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+
+ http-response add-header x-ssl-sha1 '%[ssl_s_sha1,hex]'
+ http-response add-header x-ssl-keyalg '%[ssl_s_key_alg]'
+
+## TLSv1.2
+
+ server s1 "${tmpdir}/ssl.sock" ssl verify none sni str(another-record.bug810.domain.tld) ssl-min-ver TLSv1.2 ssl-max-ver TLSv1.2 ciphers "kRSA"
+ server s2 "${tmpdir}/ssl.sock" ssl verify none sni str(another-record.bug810.domain.tld) ssl-min-ver TLSv1.2 ssl-max-ver TLSv1.2 ciphers "aECDSA"
+
+ server s3 "${tmpdir}/ssl.sock" ssl verify none sni str(another-record.bug818.domain.tld) ssl-min-ver TLSv1.2 ssl-max-ver TLSv1.2 ciphers "kRSA"
+
+## TLSv1.3
+
+ server s4 "${tmpdir}/ssl2.sock" ssl verify none sni str(another-record.bug810.domain.tld) ssl-min-ver TLSv1.3 sigalgs rsa_pss_rsae_sha384:rsa_pkcs1_sha256:ecdsa_secp384r1_sha384
+ server s5 "${tmpdir}/ssl2.sock" ssl verify none sni str(another-record.bug810.domain.tld) ssl-min-ver TLSv1.3 sigalgs rsa_pss_rsae_sha384:rsa_pkcs1_sha256
+ server s6 "${tmpdir}/ssl2.sock" ssl verify none sni str(another-record.bug810.domain.tld) ssl-min-ver TLSv1.3 sigalgs ecdsa_secp384r1_sha384
+
+ server s7 "${tmpdir}/ssl2.sock" ssl verify none sni str(another-record.bug818.domain.tld) ssl-min-ver TLSv1.3 sigalgs rsa_pss_rsae_sha384:rsa_pkcs1_sha256
+
+
+ listen ssl-lst
+ mode http
+ bind "${tmpdir}/ssl.sock" ssl strict-sni ssl-min-ver TLSv1.2 ssl-max-ver TLSv1.2 crt-list ${testdir}/filters.crt-list
+ bind "${tmpdir}/ssl2.sock" ssl strict-sni ssl-min-ver TLSv1.3 ssl-max-ver TLSv1.3 crt-list ${testdir}/filters.crt-list
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+## TLSv1.2
+
+# RSA + TLSv1.2 + another-record.bug810.domain.tld OK
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-keyalg == "rsaEncryption"
+} -run
+
+# ECDSA + TLSv1.2 + another-record.bug810.domain.tld OK
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-keyalg == "id-ecPublicKey"
+} -run
+
+# RSA + TLSv1.2 + another-record.bug818.domain.tld OK, domain not available in
+# RSA because of the '!another-record.bug818.domain.tld' in the configuration.
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+## TLSv1.3
+
+# ECDSA/RSA sigalgs + TLSv1.3 + another-record.bug810.domain.tld should return the ECDSA cert
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-keyalg == "id-ecPublicKey"
+} -run
+
+# RSA sigalgs + TLSv1.3 + another-record.bug810.domain.tld should return the RSA cert
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-keyalg == "rsaEncryption"
+} -run
+
+
+# ECDSA sigalgs + TLSv1.3 + another-record.bug810.domain.tld should return the ECDSA cert
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-keyalg == "id-ecPublicKey"
+} -run
+
+# RSA sigalgs + TLSv1.3 + another-record.bug818.domain.tld must fail because
+# this domain is not available with RSA
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
diff --git a/reg-tests/ssl/ssl_curve_name.vtc b/reg-tests/ssl/ssl_curve_name.vtc
new file mode 100644
index 0000000..a285a8f
--- /dev/null
+++ b/reg-tests/ssl/ssl_curve_name.vtc
@@ -0,0 +1,51 @@
+#REGTEST_TYPE=devel
+
+varnishtest "Test the ssl_fc_curve/ssl_bc_curve sample fetches"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && ssllib_name_startswith(OpenSSL) && openssl_version_atleast(3.0.0)'"
+feature ignore_unknown_macro
+
+server s1 -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ crt-base ${testdir}
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ http-response add-header x-ssl-bc-curve-name %[ssl_bc_curve]
+ server s1 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/client.ecdsa.pem
+
+ listen ssl-lst
+ mode http
+ http-response add-header x-ssl-fc-curve-name %[ssl_fc_curve]
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/set_cafile_rootCA.crt verify optional curves X25519:P-256:P-384
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-fc-curve-name == "X25519"
+ expect resp.http.x-ssl-bc-curve-name == "X25519"
+
+} -run
+
diff --git a/reg-tests/ssl/ssl_curves.vtc b/reg-tests/ssl/ssl_curves.vtc
new file mode 100644
index 0000000..6a8b1b6
--- /dev/null
+++ b/reg-tests/ssl/ssl_curves.vtc
@@ -0,0 +1,134 @@
+#REGTEST_TYPE=devel
+
+# This reg-test checks the behaviour of the 'curves' and 'ecdhe' options on a
+# bind line. Its main point is to ensure that the default curve used in
+# HAProxy is indeed prime256v1 (or P-256 depending on the curve's
+# representation). In order to check this, is uses two ssl frontends that have
+# different lists of accepted curves, one of them accepting this default curve
+# while the other one does not. A backend tries to connect to those two
+# frontends by using the default curve, and it should succeed in one case and
+# fail in the other.
+# For some strange reason, OpenSSL 1.0.2 does not behave the same way as later
+# versions when it comes to ECDH and curves related matters. Instead of trying
+# to make it work the same way as the other (more used) versions, we will
+# ignore it and disable this test on OpenSSL 1.0.2.
+# For the same reason, this test is disabled for other SSL libraries as well.
+#
+
+varnishtest "Test the 'curves' and 'ecdhe' options and default curve value"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && ssllib_name_startswith(OpenSSL) && openssl_version_atleast(1.1.1)'"
+feature ignore_unknown_macro
+
+server s1 -repeat 2 {
+ rxreq
+ txresp
+} -start
+
+barrier b1 cond 2 -cyclic
+
+syslog Slg_cust_fmt -level info {
+ recv
+ expect ~ "ERROR.*conn_status:\"34:SSL handshake failure\" hsk_err:\".*wrong curve\".*"
+
+ barrier b1 sync
+
+ recv
+ expect ~ "ERROR ECDHE.*conn_status:\"34:SSL handshake failure\" hsk_err:\".*wrong curve\".*"
+} -start
+
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+
+ defaults
+ mode http
+ option httpslog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ retries 0
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+
+ use_backend ssl-curves-be if { path /curves }
+ use_backend ssl-ecdhe-521-be if { path /ecdhe-521 }
+ use_backend ssl-ecdhe-256-be if { path /ecdhe-256 }
+ default_backend ssl-be
+
+ backend ssl-be
+ server s1 "${tmpdir}/ssl1.sock" ssl verify none crt ${testdir}/client.ecdsa.pem force-tlsv12 curves P-256:P-384
+
+ backend ssl-curves-be
+ server s1 "${tmpdir}/ssl2.sock" ssl verify none crt ${testdir}/client.ecdsa.pem force-tlsv12 curves P-384
+
+ backend ssl-ecdhe-256-be
+ server s1 "${tmpdir}/ssl-ecdhe-256.sock" ssl verify none crt ${testdir}/client.ecdsa.pem force-tlsv12
+
+ backend ssl-ecdhe-521-be
+ server s1 "${tmpdir}/ssl-ecdhe-521.sock" ssl verify none crt ${testdir}/client.ecdsa.pem force-tlsv12
+
+
+ listen ssl1-lst
+ bind "${tmpdir}/ssl1.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/set_cafile_rootCA.crt verify optional curves P-256:P-384
+ server s1 ${s1_addr}:${s1_port}
+
+ # The prime256v1 curve, which is used by default by a backend when no
+ # 'curves' or 'ecdhe' option is specified, is not allowed on this listener
+ listen ssl2-lst
+ log ${Slg_cust_fmt_addr}:${Slg_cust_fmt_port} local0
+ error-log-format "ERROR conn_status:\"%[fc_err]:%[fc_err_str]\" hsk_err:%{+Q}[ssl_fc_err_str]"
+
+ bind "${tmpdir}/ssl2.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/set_cafile_rootCA.crt verify optional curves P-384
+ server s1 ${s1_addr}:${s1_port}
+
+ listen ssl-ecdhe-521-lst
+ log ${Slg_cust_fmt_addr}:${Slg_cust_fmt_port} local0
+ error-log-format "ERROR ECDHE-521 conn_status:\"%[fc_err]:%[fc_err_str]\" hsk_err:%{+Q}[ssl_fc_err_str]"
+
+ bind "${tmpdir}/ssl-ecdhe-521.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/set_cafile_rootCA.crt verify optional ecdhe secp521r1
+ server s1 ${s1_addr}:${s1_port}
+
+ listen ssl-ecdhe-256-lst
+ log ${Slg_cust_fmt_addr}:${Slg_cust_fmt_port} local0
+ error-log-format "ERROR ECDHE-256 conn_status:\"%[fc_err]:%[fc_err_str]\" hsk_err:%{+Q}[ssl_fc_err_str]"
+
+ bind "${tmpdir}/ssl-ecdhe-256.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/set_cafile_rootCA.crt verify optional ecdhe prime256v1
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+# The backend tries to use the prime256v1 curve that is not accepted by the
+# frontend so the handshake should fail.
+client c2 -connect ${h1_clearlst_sock} {
+ txreq -url "/curves"
+ rxresp
+ expect resp.status == 503
+} -run
+
+barrier b1 sync
+
+# The backend tries to use the prime256v1 curve that is not accepted by the
+# frontend so the handshake should fail.
+client c3 -connect ${h1_clearlst_sock} {
+ txreq -url "/ecdhe-521"
+ rxresp
+ expect resp.status == 503
+} -run
+
+client c4 -connect ${h1_clearlst_sock} {
+ txreq -url "/ecdhe-256"
+ rxresp
+ expect resp.status == 200
+} -run
+
+syslog Slg_cust_fmt -wait
diff --git a/reg-tests/ssl/ssl_default_server.vtc b/reg-tests/ssl/ssl_default_server.vtc
new file mode 100644
index 0000000..485a9ba
--- /dev/null
+++ b/reg-tests/ssl/ssl_default_server.vtc
@@ -0,0 +1,142 @@
+#REGTEST_TYPE=devel
+
+# This reg-test ensures that SSL related configuration specified in a
+# default-server option are properly taken into account by the servers
+# (frontend). It mainly focuses on the client certificate used by the frontend,
+# that can either be defined in the server line itself, in the default-server
+# line or in both.
+#
+# It was created following a bug raised in redmine (issue #3906) in which a
+# server used an "empty" SSL context instead of the proper one.
+#
+
+varnishtest "Test the 'set ssl cert' feature of the CLI"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+feature ignore_unknown_macro
+
+server s1 -repeat 7 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+ crt-base ${testdir}
+ ca-base ${testdir}
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ use_backend first_be if { path /first }
+ use_backend second_be if { path /second }
+ use_backend third_be if { path /third }
+ use_backend fourth_be if { path /fourth }
+ use_backend fifth_be if { path /fifth }
+
+
+ backend first_be
+ default-server ssl crt client1.pem ca-file ca-auth.crt verify none
+ server s1 "${tmpdir}/ssl.sock"
+
+ backend second_be
+ default-server ssl ca-file ca-auth.crt verify none
+ server s1 "${tmpdir}/ssl.sock" crt client1.pem
+
+ backend third_be
+ default-server ssl crt client1.pem ca-file ca-auth.crt verify none
+ server s1 "${tmpdir}/ssl.sock" crt client2_expired.pem
+
+ backend fourth_be
+ default-server ssl crt client1.pem verify none
+ server s1 "${tmpdir}/ssl.sock" ca-file ca-auth.crt
+
+ backend fifth_be
+ balance roundrobin
+ default-server ssl crt client1.pem verify none
+ server s1 "${tmpdir}/ssl.sock"
+ server s2 "${tmpdir}/ssl.sock" crt client2_expired.pem
+ server s3 "${tmpdir}/ssl.sock"
+
+
+ listen ssl-lst
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/common.pem ca-file ca-auth.crt verify required crt-ignore-err all
+
+ acl cert_expired ssl_c_verify 10
+ acl cert_revoked ssl_c_verify 23
+ acl cert_ok ssl_c_verify 0
+
+ http-response add-header X-SSL Ok if cert_ok
+ http-response add-header X-SSL Expired if cert_expired
+ http-response add-header X-SSL Revoked if cert_revoked
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/first"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "Ok"
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/second"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "Ok"
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/third"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "Expired"
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/fourth"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "Ok"
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/fifth"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "Ok"
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/fifth"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "Expired"
+} -run
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq -url "/fifth"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl == "Ok"
+} -run
diff --git a/reg-tests/ssl/ssl_dh.vtc b/reg-tests/ssl/ssl_dh.vtc
new file mode 100644
index 0000000..5fe7c88
--- /dev/null
+++ b/reg-tests/ssl/ssl_dh.vtc
@@ -0,0 +1,234 @@
+#REGTEST_TYPE=devel
+
+# This reg-tests checks that the DH-related mechanisms works properly.
+# When no DH is specified, either directly in the server's PEM or through a
+# ssl-dh-param-file global option, and no tune.ssl.default-dh-param is defined,
+# DHE ciphers are disabled.
+# If a default-dh-param is defined, we will use DH parameters of the same size
+# as the server's RSA or DSA key, or default-dh-param if it is smaller.
+# This test has three distinct HAProxy instances, one with no DH-related option
+# used, one with the tune.ssl.default-dh-param global parameter set, and one
+# with an ssl-dh-param-file global option.
+# We use "openssl s_client" calls in order to check the size of the "Server
+# Temp Key" (which will be the same as the DH parameters in case a DHE cipher
+# is used).
+#
+# The main goal of this test was to check that the newly added OpenSSLv3
+# specific DH code worked as before, since it needed to be created in order to
+# stop using deprecated APIs.
+
+varnishtest "Test the DH related SSL options"
+# AWS-LC does not support any FFDH ciphersuites
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && !ssllib_name_startswith(AWS-LC)' && !ssllib_name_startswith(wolfSSL)'"
+feature cmd "command -v openssl && command -v grep && command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 8 {
+ rxreq
+ txresp
+} -start
+
+
+haproxy h1 -conf {
+ global
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httpslog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ retries 0
+
+ frontend clear-fe
+ bind "fd@${clearlst}"
+ use_backend gen_cert_be if { path /gencert }
+ default_backend dflt_be
+
+ backend dflt_be
+ server s1 "${tmpdir}/ssl_dflt.sock" ssl verify none ssl-max-ver TLSv1.2
+
+ backend gen_cert_be
+ server s1 "${tmpdir}/ssl_dflt_gencert.sock" ssl verify none ssl-max-ver TLSv1.2
+
+ listen ssl-dflt-lst
+ bind "${tmpdir}/ssl_dflt.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/set_cafile_rootCA.crt verify optional ciphers "DHE-RSA-AES256-GCM-SHA384" ssl-max-ver TLSv1.2
+ http-response set-header x-ssl-cipher %[ssl_fc_cipher]
+ server s1 ${s1_addr}:${s1_port}
+
+ listen ssl-dflt-gencert-lst
+ bind "${tmpdir}/ssl_dflt_gencert.sock" ssl generate-certificates crt ${testdir}/common.pem ca-file ${testdir}/set_cafile_rootCA.crt ca-sign-file ${testdir}/generate_certificates/gen_cert_ca.pem verify optional ciphers "DHE-RSA-AES256-GCM-SHA384" ssl-max-ver TLSv1.2
+ http-response set-header x-ssl-cipher %[ssl_fc_cipher]
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+haproxy h2 -conf {
+ global
+ stats socket "${tmpdir}/h2/stats" level admin
+
+ global
+ tune.ssl.default-dh-param 4096
+
+ defaults
+ mode http
+ option httpslog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ retries 0
+
+ listen clear-lst
+ bind "fd@${clearlst_dfltdh}"
+ server s1 "${tmpdir}/ssl_dfltdh.sock" ssl verify none ssl-max-ver TLSv1.2
+
+ listen ssl-4096dh-dflt-lst
+ bind "${tmpdir}/ssl_dfltdh.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/set_cafile_rootCA.crt verify optional ciphers "DHE-RSA-AES256-GCM-SHA384" ssl-max-ver TLSv1.2
+ http-response set-header x-ssl-cipher %[ssl_fc_cipher]
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+haproxy h3 -conf {
+ global
+ stats socket "${tmpdir}/h3/stats" level admin
+
+ global
+ ssl-dh-param-file ${testdir}/common.4096.dh
+
+ defaults
+ mode http
+ option httpslog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ retries 0
+
+ listen clear-lst
+ bind "fd@${clearlst_dhfile}"
+ server s1 "${tmpdir}/ssl_dhfile.sock" ssl verify none ssl-max-ver TLSv1.2
+
+ listen ssl-dhfile-lst
+ bind "${tmpdir}/ssl_dhfile.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/set_cafile_rootCA.crt verify optional ciphers "DHE-RSA-AES256-GCM-SHA384" ssl-max-ver TLSv1.2
+ http-response set-header x-ssl-cipher %[ssl_fc_cipher]
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+#
+# Check that all the SSL backend <-> SSL frontend connections work
+#
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ # No DH parameters are defined, DHE ciphers are unavailable
+ expect resp.status == 503
+} -run
+
+client c2 -connect ${h2_clearlst_dfltdh_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-cipher == "DHE-RSA-AES256-GCM-SHA384"
+} -run
+
+client c3 -connect ${h3_clearlst_dhfile_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-cipher == "DHE-RSA-AES256-GCM-SHA384"
+} -run
+
+client c4 -connect ${h1_clearlst_sock} {
+ txreq -url "/gencert"
+ rxresp
+ # No DH parameters are defined, DHE ciphers are unavailable
+ expect resp.status == 503
+} -run
+
+
+# On the second HAProxy instance, even if default-dh-param is set to 4096, this
+# value is only considered as a maximum DH key length and we will always try to
+# match the server's certificate key length in our DHE key exchange (2048 bits
+# in the case of common.pem).
+shell {
+ echo "Q" | openssl s_client -unix "${tmpdir}/ssl_dfltdh.sock" -tls1_2 2>/dev/null | grep -E "Server Temp Key: DH, 2048 bits"
+}
+
+shell {
+ echo "Q" | openssl s_client -unix "${tmpdir}/ssl_dhfile.sock" -tls1_2 2>/dev/null | grep -E "Server Temp Key: DH, 4096 bits"
+}
+
+
+#
+# Add a custom DH to the server's PEM certificate
+#
+shell {
+ printf "set ssl cert ${testdir}/common.pem <<\n$(cat ${testdir}/common.pem)\n$(cat ${testdir}/common.4096.dh)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl cert ${testdir}/common.pem" | socat "${tmpdir}/h1/stats" -
+
+ printf "set ssl cert ${testdir}/common.pem <<\n$(cat ${testdir}/common.pem)\n$(cat ${testdir}/common.4096.dh)\n\n" | socat "${tmpdir}/h2/stats" -
+ echo "commit ssl cert ${testdir}/common.pem" | socat "${tmpdir}/h2/stats" -
+
+ printf "set ssl cert ${testdir}/common.pem <<\n$(cat ${testdir}/common.pem)\n$(cat ${testdir}/common.4096.dh)\n\n" | socat "${tmpdir}/h3/stats" -
+ echo "commit ssl cert ${testdir}/common.pem" | socat "${tmpdir}/h3/stats" -
+}
+
+
+#
+# Check that all the SSL backend <-> SSL frontend connections still work
+# Common.pem now contains DH parameters so the first instance's frontends
+# can now use DHE ciphers.
+#
+client c5 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-cipher == "DHE-RSA-AES256-GCM-SHA384"
+} -run
+
+client c6 -connect ${h2_clearlst_dfltdh_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-cipher == "DHE-RSA-AES256-GCM-SHA384"
+} -run
+
+client c7 -connect ${h3_clearlst_dhfile_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-cipher == "DHE-RSA-AES256-GCM-SHA384"
+} -run
+
+client c8 -connect ${h1_clearlst_sock} {
+ txreq -url "/gencert"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-cipher == "DHE-RSA-AES256-GCM-SHA384"
+} -run
+
+
+
+#
+# Check the new size of the DH key
+#
+shell {
+ echo "Q" | openssl s_client -unix "${tmpdir}/ssl_dflt.sock" -tls1_2 2>/dev/null | grep -E "Server Temp Key: DH, 4096 bits"
+}
+
+shell {
+ echo "Q" | openssl s_client -unix "${tmpdir}/ssl_dfltdh.sock" -tls1_2 2>/dev/null | grep -E "Server Temp Key: DH, 4096 bits"
+}
+
+shell {
+ echo "Q" | openssl s_client -unix "${tmpdir}/ssl_dhfile.sock" -tls1_2 2>/dev/null | grep -E "Server Temp Key: DH, 4096 bits"
+}
+
+shell {
+ echo "Q" | openssl s_client -unix "${tmpdir}/ssl_dflt_gencert.sock" -tls1_2 2>/dev/null | grep -E "Server Temp Key: DH, 4096 bits"
+}
diff --git a/reg-tests/ssl/ssl_errors.vtc b/reg-tests/ssl/ssl_errors.vtc
new file mode 100644
index 0000000..8fb9c5a
--- /dev/null
+++ b/reg-tests/ssl/ssl_errors.vtc
@@ -0,0 +1,439 @@
+#REGTEST_TYPE=devel
+
+# This reg-test checks that the connection and SSL sample fetches related to
+# errors are functioning properly. It also tests the proper behaviour of the
+# default HTTPS log format and of the error-log-format option which allows to
+# define a specific log format used only in case of connection error (otherwise
+# a line following the configured log-format is output).
+#
+# It works by sending request through three different paths, one using a custom
+# log-format line that contains the connection error and SSL handshake error
+# sample fetches, one using the default HTTPS log-format and one using the
+# legacy error log format.
+#
+# The output log lines are caught by syslog blocks (one for each path) and
+# compared to an expected format.
+# Since the syslog is not by design synchronized with the Varnish clients and
+# servers, synchronization is achieved through barriers, which ensure that
+# syslog messages arrive in the right order.
+#
+# In order to ensure that the log line raised in case of connection error if an
+# error-log-format is defined still follows the log-separate-error option, the
+# log lines raised by the https_fmt_lst listener will be sent to two separate
+# syslog servers.
+#
+
+varnishtest "Test the connection and SSL error fetches."
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev2)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && ssllib_name_startswith(OpenSSL)'"
+feature cmd "command -v socat"
+feature ignore_unknown_macro
+
+server s1 -repeat 4 {
+ rxreq
+ txresp
+} -start
+
+barrier b1 cond 4 -cyclic
+barrier b2 cond 2 -cyclic
+
+
+syslog Slg_cust_fmt -level info {
+ recv
+ expect ~ ".*conn_status:\"0:Success\" hsk_err:\"0:-\" CN=\"/C=FR/O=HAProxy Technologies/CN=Client\",serial=1007,hash=063DCC2E6A9159E66994B325D6D2EF3D17A75B6F"
+
+ barrier b1 sync
+
+ recv
+ expect ~ "ERROR.*conn_status:\"30:SSL client CA chain cannot be verified\" hsk_err:\"134:.*:certificate verify failed\" CN=\"/C=FR/O=HAProxy Technologies/CN=Client\",serial=1007,hash=063DCC2E6A9159E66994B325D6D2EF3D17A75B6F"
+
+ barrier b1 sync
+
+ recv
+ expect ~ "ERROR.*conn_status:\"31:SSL client certificate not trusted\" hsk_err:\"134:.*:certificate verify failed\" CN=\"/C=FR/O=HAProxy Technologies/CN=Client\",serial=1007,hash=063DCC2E6A9159E66994B325D6D2EF3D17A75B6F"
+
+ barrier b1 sync
+
+ # In case of an error occurring before the certificate verification process,
+ # the client certificate chain is never parsed and verified so we can't
+ # have information about the client's certificate.
+ recv
+ expect ~ "ERROR.*conn_status:\"34:SSL handshake failure\" hsk_err:\"193:.*:no shared cipher\" CN=\"\",serial=-,hash=-"
+} -start
+
+syslog Slg_https_fmt -level info {
+ recv
+ expect ~ ".*https_logfmt_ssl_lst~ https_logfmt_ssl_lst/s1.*0/0000000000000000/0/0/.? foo.com/TLSv1.2/AES256-GCM-SHA384"
+
+ barrier b1 sync
+} -start
+
+syslog Slg_https_fmt_err -level info {
+ recv
+ expect ~ "ERROR.*https_logfmt_ssl_lst~ https_logfmt_ssl_lst/<NOSRV>.*30/0000000000000086/0/2/.? foo.com/TLSv1.2/\\(NONE\\)"
+
+ barrier b1 sync
+
+ recv
+ expect ~ "ERROR.*https_logfmt_ssl_lst~ https_logfmt_ssl_lst/<NOSRV>.*31/0000000000000086/20/0/.? foo.com/TLSv1.2/\\(NONE\\)"
+
+ barrier b1 sync
+
+ recv
+ expect ~ "ERROR.*https_logfmt_ssl_lst~ https_logfmt_ssl_lst/<NOSRV>.*34/00000000000000C1/0/0/.? foo.com/TLSv1.2/\\(NONE\\)"
+} -start
+
+syslog Slg_logconnerror -level info {
+ recv
+ expect ~ ".*logconnerror_ssl_lst~ logconnerror_ssl_lst/s1"
+
+ barrier b1 sync
+
+ recv
+ expect ~ ".*logconnerror_ssl_lst/1: SSL client CA chain cannot be verified"
+
+ barrier b1 sync
+
+ recv
+ expect ~ ".*logconnerror_ssl_lst/1: SSL client certificate not trusted"
+
+ barrier b1 sync
+
+ recv
+ expect ~ ".*logconnerror_ssl_lst/1: SSL handshake failure"
+} -start
+
+syslog Slg_bcknd -level info {
+ recv
+ expect ~ ".*bc_err:0:\"Success\" ssl_bc_err:0:"
+
+ barrier b2 sync
+
+ recv
+ expect ~ ".*bc_err:34:\"SSL handshake failure\" ssl_bc_err:134:.*:certificate verify failed"
+
+ barrier b2 sync
+
+ recv
+ expect ~ ".*bc_err:33:\"Server presented an SSL certificate different from the expected one\" ssl_bc_err:134:.*:certificate verify failed"
+
+ barrier b2 sync
+
+ # Verify errors on the server side cannot be caught when using TLSv1.3 but it works for TLSv1.2
+ recv
+ expect ~ ".*bc_err:34:\"SSL handshake failure\" ssl_bc_err:1048:.*:tlsv1 alert unknown ca"
+
+ barrier b2 sync
+
+ recv
+ expect ~ ".*bc_err:34:\"SSL handshake failure\" ssl_bc_err:1040:.* alert handshake failure"
+
+ barrier b2 sync
+
+ recv
+ expect ~ ".*bc_err:34:\"SSL handshake failure\" ssl_bc_err:1040:.* alert handshake failure"
+} -start
+
+syslog Slg_bcknd_fe -level info {
+ # Client c13 - No error
+ # Depending on the version of OpenSSL, the TLS version and ciphersuite will change
+ recv
+ expect ~ ".* Server/(TLSv1.3/TLS_AES_256_GCM_SHA384|TLSv1.2/ECDHE-RSA-AES256-GCM-SHA384)"
+
+ # Client c14 - Server certificate rejected
+ # Depending on the version of OpenSSL, the TLS version and ciphersuite will change
+ recv
+ expect ~ ".* foo.com/(TLSv1.3/TLS_AES_256_GCM_SHA384|TLSv1.2/\\(NONE\\))"
+
+ # Client c15 - Server certificate mismatch (verifyhost option on backend)
+ # Depending on the version of OpenSSL, the TLS version and ciphersuite will change
+ recv
+ expect ~ ".* foo.com/(TLSv1.3/TLS_AES_256_GCM_SHA384|TLSv1.2/\\(NONE\\))"
+
+ # Client c16 - Client certificate rejected
+ recv
+ expect ~ ".* foo.com/TLSv1.2/\\(NONE\\)"
+
+ # Client c17 - Wrong ciphers TLSv1.2
+ recv
+ expect ~ ".* foo.com/TLSv1.2/\\(NONE\\)"
+
+ # Client c18
+ # With OpenSSL1.0.2 -Wrong ciphers TLSv1.2 (same as c17)
+ # With newer versions - Wrong ciphers TLSv1.3 - the client does not get to send its certificate because the error happens before
+ recv
+ expect ~ ".* (foo.com/TLSv1.2|-/TLSv1.3)/\\(NONE\\)"
+} -start
+
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ stats socket "${tmpdir}/h1/stats" level admin
+ .if openssl_version_atleast(3.0.0)
+ set-var proc.ssl_error_mask str(7FFFFF),hex2i
+ .else
+ set-var proc.ssl_error_mask str(FFF),hex2i
+ .endif
+
+ defaults
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ retries 0
+
+ listen clear_lst
+ bind "fd@${clearlst}"
+ default-server ssl crt ${testdir}/set_cafile_client.pem ca-file ${testdir}/set_cafile_interCA2.crt verify none no-ssl-reuse force-tlsv12 sni str(foo.com)
+
+ balance roundrobin
+ server cust_fmt "${tmpdir}/cust_logfmt_ssl.sock"
+ server https_fmt "${tmpdir}/https_logfmt_ssl.sock"
+ server logconnerror "${tmpdir}/logconnerror_ssl.sock"
+
+
+ listen clear_wrong_ciphers_lst
+ bind "fd@${wrongcipherslst}"
+ default-server ssl crt ${testdir}/set_cafile_client.pem ca-file ${testdir}/set_cafile_interCA2.crt verify none no-ssl-reuse force-tlsv12 ciphers "aECDSA" sni str(foo.com)
+
+ balance roundrobin
+ server cust_fmt "${tmpdir}/cust_logfmt_ssl.sock"
+ server https_fmt "${tmpdir}/https_logfmt_ssl.sock"
+ server logconnerror "${tmpdir}/logconnerror_ssl.sock"
+
+
+ # This listener will be used to test backend fetches (bc_err and ssl_bc_err)
+ listen clear_backend_errors_lst
+ bind "fd@${backenderrorslst}"
+ log ${Slg_bcknd_addr}:${Slg_bcknd_port} local0
+ log-format "bc_err:%[bc_err]:%{+Q}[bc_err_str]\ ssl_bc_err:%[ssl_bc_err,and(proc.ssl_error_mask)]:%{+Q}[ssl_bc_err_str]"
+ error-log-format "ERROR bc_err:%[bc_err]:%{+Q}[bc_err_str]\ ssl_bc_err:%[ssl_bc_err,and(proc.ssl_error_mask)]:%[ssl_bc_err_str]"
+
+ balance roundrobin
+ server no_err "${tmpdir}/no_err_ssl.sock" ssl crt ${testdir}/set_cafile_client.pem ca-file ${testdir}/set_cafile_interCA2.crt verify required sni str(Server)
+ server srv_cert_rejected "${tmpdir}/srv_rejected_ssl.sock" ssl crt ${testdir}/set_cafile_client.pem ca-file ${testdir}/set_cafile_interCA1.crt verify required sni str(foo.com)
+ server mismatch_frontend "${tmpdir}/mismatch_fe_ssl.sock" ssl crt ${testdir}/set_cafile_client.pem ca-file ${testdir}/set_cafile_interCA2.crt verify required sni str(foo.com) verifyhost str(toto) # We force TLSv1.2 for this specific case because server-side
+ # verification errors cannot be caught by the backend fetches when
+ # using TLSv1.3
+ server clt_cert_rejected "${tmpdir}/rejected_ssl.sock" ssl crt ${testdir}/set_cafile_client.pem ca-file ${testdir}/set_cafile_interCA2.crt verify none force-tlsv12 sni str(foo.com)
+ server wrong_ciphers "${tmpdir}/wrong_ciphers_ssl.sock" ssl verify none crt ${testdir}/client1.pem ca-file ${testdir}/ca-auth.crt force-tlsv12 ciphers "aECDSA" sni str(foo.com)
+
+ # No TLSv1.3 support with OpenSSL 1.0.2 so we duplicate the previous
+ # wrong cipher test in this case so that the error log remains the same
+.if openssl_version_before(1.1.1)
+ server wrong_ciphers2 "${tmpdir}/wrong_ciphers_ssl.sock" ssl verify none crt ${testdir}/client1.pem ca-file ${testdir}/ca-auth.crt force-tlsv12 ciphers "aECDSA" sni str(foo.com)
+.else
+ server wrong_ciphers_tls13 "${tmpdir}/wrong_ciphers_tls13_ssl.sock" ssl verify none crt ${testdir}/client1.pem ca-file ${testdir}/ca-auth.crt ciphersuites "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" force-tlsv13 sni str(foo.com)
+.endif
+
+
+
+
+ listen cust_logfmt_ssl_lst
+ log ${Slg_cust_fmt_addr}:${Slg_cust_fmt_port} local0
+ mode http
+ log-format "conn_status:\"%[fc_err]:%[fc_err_str]\" hsk_err:\"%[ssl_fc_err]:%[ssl_fc_err_str]\" CN=%{+Q}[ssl_c_s_dn],serial=%[ssl_c_serial,hex],hash=%[ssl_c_sha1,hex]"
+ error-log-format "ERROR conn_status:\"%[fc_err]:%[fc_err_str]\" hsk_err:\"%[ssl_fc_err,and(proc.ssl_error_mask)]:%[ssl_fc_err_str]\" CN=%{+Q}[ssl_c_s_dn],serial=%[ssl_c_serial,hex],hash=%[ssl_c_sha1,hex]"
+ bind "${tmpdir}/cust_logfmt_ssl.sock" ssl crt ${testdir}/set_cafile_server.pem ca-verify-file ${testdir}/set_cafile_rootCA.crt ca-file ${testdir}/set_cafile_interCA1.crt verify required ciphers "kRSA"
+ server s1 ${s1_addr}:${s1_port}
+
+ listen https_logfmt_ssl_lst
+ log ${Slg_https_fmt_addr}:${Slg_https_fmt_port} local0 info
+ log ${Slg_https_fmt_err_addr}:${Slg_https_fmt_err_port} local0 err info
+ option log-separate-errors
+ mode http
+ option httpslog
+ error-log-format "ERROR %ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r %[fc_err]/%[ssl_fc_err,and(proc.ssl_error_mask),hex]/%[ssl_c_err]/%[ssl_c_ca_err]/%[ssl_fc_is_resumed] %[ssl_fc_sni]/%sslv/%sslc"
+ bind "${tmpdir}/https_logfmt_ssl.sock" ssl crt ${testdir}/set_cafile_server.pem ca-verify-file ${testdir}/set_cafile_rootCA.crt ca-file ${testdir}/set_cafile_interCA1.crt verify required ciphers "kRSA"
+ server s1 ${s1_addr}:${s1_port}
+
+ listen logconnerror_ssl_lst
+ log ${Slg_logconnerror_addr}:${Slg_logconnerror_port} local0 info
+ mode http
+ option httplog
+ bind "${tmpdir}/logconnerror_ssl.sock" ssl crt ${testdir}/set_cafile_server.pem ca-verify-file ${testdir}/set_cafile_rootCA.crt ca-file ${testdir}/set_cafile_interCA1.crt verify required ciphers "kRSA"
+ server s1 ${s1_addr}:${s1_port}
+
+
+
+ defaults bknd_err_dflt
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ retries 0
+ log ${Slg_bcknd_fe_addr}:${Slg_bcknd_fe_port} local0
+ log-format "%ci:%cp %[ssl_fc_sni]/%sslv/%sslc"
+ error-log-format "ERROR %ci:%cp %[ssl_fc_sni]/%sslv/%sslc"
+
+ # The following listeners allow to test backend error fetches
+ listen no_backend_err_ssl_lst from bknd_err_dflt
+ bind "${tmpdir}/no_err_ssl.sock" ssl crt ${testdir}/set_cafile_server.pem ca-file ${testdir}/set_cafile_interCA2.crt verify none
+ server s1 ${s1_addr}:${s1_port}
+
+ listen srv_rejected_ssl_lst from bknd_err_dflt
+ bind "${tmpdir}/srv_rejected_ssl.sock" ssl crt ${testdir}/set_cafile_server.pem ca-file ${testdir}/set_cafile_interCA2.crt verify none
+ server s1 ${s1_addr}:${s1_port}
+
+ listen mismatch_fe_ssl_lst from bknd_err_dflt
+ bind "${tmpdir}/mismatch_fe_ssl.sock" ssl crt ${testdir}/set_cafile_server.pem ca-file ${testdir}/set_cafile_interCA2.crt verify none
+ server s1 ${s1_addr}:${s1_port}
+
+ listen rejected_clt_ssl_lst from bknd_err_dflt
+ bind "${tmpdir}/rejected_ssl.sock" ssl crt ${testdir}/set_cafile_server.pem ca-file ${testdir}/set_cafile_interCA2.crt verify required
+ server s1 ${s1_addr}:${s1_port}
+
+ listen wrong_ciphers_ssl_lst from bknd_err_dflt
+ bind "${tmpdir}/wrong_ciphers_ssl.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/ca-auth.crt verify none force-tlsv12 ciphers "kRSA"
+ server s1 ${s1_addr}:${s1_port}
+
+.if openssl_version_atleast(1.1.1)
+ listen wrong_ciphers_tls13_ssl_lst from bknd_err_dflt
+ bind "${tmpdir}/wrong_ciphers_tls13_ssl.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/ca-auth.crt verify none force-tlsv13 ciphersuites "TLS_AES_128_GCM_SHA256"
+ server s1 ${s1_addr}:${s1_port}
+.endif
+
+} -start
+
+
+# The three following requests should all succeed
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c2 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c3 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+
+barrier b1 sync
+
+
+# Change the root CA in the frontends
+shell {
+ printf "set ssl ca-file ${testdir}/set_cafile_rootCA.crt <<\n$(cat ${testdir}/set_cafile_interCA1.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file ${testdir}/set_cafile_rootCA.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+client c4 -connect ${h1_clearlst_sock} {
+ txreq
+ expect_close
+} -run
+
+client c5 -connect ${h1_clearlst_sock} {
+ txreq
+ expect_close
+} -run
+
+client c6 -connect ${h1_clearlst_sock} {
+ txreq
+ expect_close
+} -run
+
+barrier b1 sync
+
+
+
+# Restore the root CA
+shell {
+ printf "set ssl ca-file ${testdir}/set_cafile_rootCA.crt <<\n$(cat ${testdir}/set_cafile_rootCA.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file ${testdir}/set_cafile_rootCA.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+# Change the intermediate CA in the frontends
+shell {
+ printf "set ssl ca-file ${testdir}/set_cafile_interCA1.crt <<\n$(cat ${testdir}/set_cafile_interCA2.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file ${testdir}/set_cafile_interCA1.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+client c7 -connect ${h1_clearlst_sock} {
+ txreq
+ expect_close
+} -run
+
+client c8 -connect ${h1_clearlst_sock} {
+ txreq
+ expect_close
+} -run
+
+client c9 -connect ${h1_clearlst_sock} {
+ txreq
+ expect_close
+} -run
+
+barrier b1 sync
+
+
+# Restore the intermediate CA in the frontends
+shell {
+ printf "set ssl ca-file ${testdir}/set_cafile_interCA1.crt <<\n$(cat ${testdir}/set_cafile_interCA1.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file ${testdir}/set_cafile_interCA1.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+# "No shared cipher" errors
+client c10 -connect ${h1_wrongcipherslst_sock} {
+ txreq
+ expect_close
+} -run
+client c11 -connect ${h1_wrongcipherslst_sock} {
+ txreq
+ expect_close
+} -run
+client c12 -connect ${h1_wrongcipherslst_sock} {
+ txreq
+ expect_close
+} -run
+
+
+shell {
+ printf "set ssl ca-file ${testdir}/set_cafile_interCA2.crt <<\n$(cat ${testdir}/set_cafile_interCA2.crt)\n$(cat ${testdir}/set_cafile_rootCA.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+ echo "commit ssl ca-file ${testdir}/set_cafile_interCA2.crt" | socat "${tmpdir}/h1/stats" -
+}
+
+client c13 -connect ${h1_backenderrorslst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+barrier b2 sync
+client c14 -connect ${h1_backenderrorslst_sock} {
+ txreq
+ expect_close
+} -run
+barrier b2 sync
+client c15 -connect ${h1_backenderrorslst_sock} {
+ txreq
+ expect_close
+} -run
+barrier b2 sync
+client c16 -connect ${h1_backenderrorslst_sock} {
+ txreq
+ expect_close
+} -run
+barrier b2 sync
+client c17 -connect ${h1_backenderrorslst_sock} {
+ txreq
+ expect_close
+} -run
+barrier b2 sync
+client c18 -connect ${h1_backenderrorslst_sock} {
+ txreq
+ expect_close
+} -run
+
+syslog Slg_cust_fmt -wait
+syslog Slg_https_fmt -wait
+syslog Slg_https_fmt_err -wait
+syslog Slg_logconnerror -wait
+syslog Slg_bcknd -wait
+syslog Slg_bcknd_fe -wait
diff --git a/reg-tests/ssl/ssl_frontend_samples.vtc b/reg-tests/ssl/ssl_frontend_samples.vtc
new file mode 100644
index 0000000..401e193
--- /dev/null
+++ b/reg-tests/ssl/ssl_frontend_samples.vtc
@@ -0,0 +1,69 @@
+#REGTEST_TYPE=devel
+
+varnishtest "Test the ssl_f_* sample fetches"
+#REQUIRE_OPTIONS=OPENSSL
+feature ignore_unknown_macro
+
+server s1 -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ crt-base ${testdir}
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ server s1 "${tmpdir}/ssl.sock" ssl verify none
+
+ listen ssl-lst
+ mode http
+
+ http-response add-header x-ssl-der %[ssl_f_der,hex]
+ http-response add-header x-ssl-sha1 %[ssl_f_sha1,hex]
+ http-response add-header x-ssl-notafter %[ssl_f_notafter]
+ http-response add-header x-ssl-notbefore %[ssl_f_notbefore]
+ http-response add-header x-ssl-sig_alg %[ssl_f_sig_alg]
+ http-response add-header x-ssl-i_dn %[ssl_f_i_dn]
+ http-response add-header x-ssl-s_dn %[ssl_f_s_dn]
+ http-response add-header x-ssl-s_serial %[ssl_f_serial,hex]
+ http-response add-header x-ssl-key_alg %[ssl_f_key_alg]
+ http-response add-header x-ssl-version %[ssl_f_version]
+
+ bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/common.pem
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-der ~ 308203C7308202AFA003020102021445B6C777.*65AD7F4469DB9C8581EE260ABCB727AEF8A7C3ADA
+ expect resp.http.x-ssl-sha1 == "DF3B6E847A7BF83DFAAFCFEC65EE9BC36230D3EA"
+ expect resp.http.x-ssl-notafter == "330917162600Z"
+ expect resp.http.x-ssl-notbefore == "230920162600Z"
+ expect resp.http.x-ssl-sig_alg == "RSA-SHA256"
+ expect resp.http.x-ssl-i_dn == "/C=FR/L=Paris/O=HAProxy Technologies/CN=HAProxy Test Intermediate CA"
+ expect resp.http.x-ssl-s_dn == "/C=FR/L=Paris/O=test1/CN=www.test1.com"
+ expect resp.http.x-ssl-s_serial == "45B6C777A017159A19126340C1053521B91E123B"
+ expect resp.http.x-ssl-key_alg == "rsaEncryption"
+ expect resp.http.x-ssl-version == "3"
+} -run
+
+
diff --git a/reg-tests/ssl/ssl_generate_certificate.vtc b/reg-tests/ssl/ssl_generate_certificate.vtc
new file mode 100644
index 0000000..0f8fe2c
--- /dev/null
+++ b/reg-tests/ssl/ssl_generate_certificate.vtc
@@ -0,0 +1,168 @@
+#REGTEST_TYPE=devel
+
+# This reg-test checks that the 'generate-certificates' SSL option works
+# properly. This option allows to generate server-side certificates on the fly
+# for clients that use an SNI for which no certificate was specified in the
+# configuration file.
+# This test also aims at checking that the 'generate-certificates' and the
+# 'ecdhe' bind options work correctly together.
+# Any bind line having a 'generate-certificates' needs to have a ca-sign-file
+# option as well that specifies the path to a CA pem file (containing a
+# certificate as well as its private key). For this reason, a new
+# ssl_gen_ca.pem CA certificate was created, along with the ssl_gen_server.pem
+# server certificate signed by the CA. This server certificate will be used as
+# a default certificate and will serve as a base for any newly created
+# certificate.
+
+varnishtest "Test the 'generate-certificates' SSL option"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && !ssllib_name_startswith(wolfSSL)'"
+feature cmd "command -v openssl && command -v grep"
+feature ignore_unknown_macro
+
+server s1 -repeat 6 {
+ rxreq
+ txresp
+} -start
+
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 2048
+
+ defaults
+ mode http
+ option httpslog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ option httpslog
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ http-request set-var(sess.sni) hdr(x-sni)
+
+ use_backend P-384_backend if { path /P-384 }
+ default_backend default_backend
+
+ backend default_backend
+ server s1 "${tmpdir}/ssl.sock" ssl verify none ssl-max-ver TLSv1.2 sni var(sess.sni)
+
+ backend P-384_backend
+ server s1 "${tmpdir}/ssl_P-384.sock" ssl verify none ssl-max-ver TLSv1.2 sni var(sess.sni)
+
+ listen ssl-lst
+ bind "${tmpdir}/ssl.sock" ssl generate-certificates crt ${testdir}/generate_certificates/gen_cert_server.pem ca-sign-file ${testdir}/generate_certificates/gen_cert_ca.pem ca-file ${testdir}/generate_certificates/gen_cert_ca.pem verify optional
+ http-response add-header x-ssl-s_dn %[ssl_f_s_dn(CN)]
+ http-response add-header x-ssl-i_dn %[ssl_f_i_dn(CN)]
+ http-response add-header x-ssl-sig_alg %[ssl_f_sig_alg]
+ http-response add-header x-ssl-key_alg %[ssl_f_key_alg]
+ http-response add-header x-ssl-sha1 %[ssl_f_sha1,hex]
+
+ server s1 ${s1_addr}:${s1_port}
+
+ listen ssl-lst-P-384
+ bind "${tmpdir}/ssl_P-384.sock" ssl generate-certificates crt ${testdir}/generate_certificates/gen_cert_server.pem ca-sign-file ${testdir}/generate_certificates/gen_cert_ca.pem ca-file ${testdir}/generate_certificates/gen_cert_ca.pem verify optional ecdhe secp384r1
+ http-response add-header x-ssl-s_dn %[ssl_f_s_dn(CN)]
+ http-response add-header x-ssl-i_dn %[ssl_f_i_dn(CN)]
+ http-response add-header x-ssl-sig_alg %[ssl_f_sig_alg]
+ http-response add-header x-ssl-key_alg %[ssl_f_key_alg]
+ http-response add-header x-ssl-sha1 %[ssl_f_sha1,hex]
+
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+# Use default certificate
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sig_alg == "ecdsa-with-SHA256"
+ expect resp.http.x-ssl-i_dn == "ECDSA CA"
+ expect resp.http.x-ssl-s_dn == "server.ecdsa.com"
+ expect resp.http.x-ssl-key_alg == "id-ecPublicKey"
+ expect resp.http.x-ssl-sha1 == "66AC64728CEA0C1F614A89C278FA2F94EDE9AB11"
+} -run
+
+
+# Use default certificate's sni
+client c2 -connect ${h1_clearlst_sock} {
+ txreq -hdr "x-sni: server.ecdsa.com"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sig_alg == "ecdsa-with-SHA256"
+ expect resp.http.x-ssl-i_dn == "ECDSA CA"
+ expect resp.http.x-ssl-s_dn == "server.ecdsa.com"
+ expect resp.http.x-ssl-key_alg == "id-ecPublicKey"
+ expect resp.http.x-ssl-sha1 == "66AC64728CEA0C1F614A89C278FA2F94EDE9AB11"
+} -run
+
+
+
+# Use another SNI - the server certificate should be generated and different
+# than the default one
+client c3 -connect ${h1_clearlst_sock} {
+ txreq -hdr "x-sni: unknown-sni.com"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sig_alg == "ecdsa-with-SHA256"
+ expect resp.http.x-ssl-i_dn == "ECDSA CA"
+ expect resp.http.x-ssl-s_dn == "ECDSA CA"
+ expect resp.http.x-ssl-key_alg == "id-ecPublicKey"
+ expect resp.http.x-ssl-sha1 != "66AC64728CEA0C1F614A89C278FA2F94EDE9AB11"
+} -run
+
+
+# Use default certificate
+client c4 -connect ${h1_clearlst_sock} {
+ txreq -url "/P-384"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sig_alg == "ecdsa-with-SHA256"
+ expect resp.http.x-ssl-i_dn == "ECDSA CA"
+ expect resp.http.x-ssl-s_dn == "server.ecdsa.com"
+ expect resp.http.x-ssl-key_alg == "id-ecPublicKey"
+ expect resp.http.x-ssl-sha1 == "66AC64728CEA0C1F614A89C278FA2F94EDE9AB11"
+} -run
+
+
+# Use default certificate's sni
+client c5 -connect ${h1_clearlst_sock} {
+ txreq -url "/P-384" -hdr "x-sni: server.ecdsa.com"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sig_alg == "ecdsa-with-SHA256"
+ expect resp.http.x-ssl-i_dn == "ECDSA CA"
+ expect resp.http.x-ssl-s_dn == "server.ecdsa.com"
+ expect resp.http.x-ssl-key_alg == "id-ecPublicKey"
+ expect resp.http.x-ssl-sha1 == "66AC64728CEA0C1F614A89C278FA2F94EDE9AB11"
+} -run
+
+
+# Use another SNI - the server certificate should be generated and different
+# than the default one
+client c6 -connect ${h1_clearlst_sock} {
+ txreq -url "/P-384" -hdr "x-sni: unknown-sni.com"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sig_alg == "ecdsa-with-SHA256"
+ expect resp.http.x-ssl-i_dn == "ECDSA CA"
+ expect resp.http.x-ssl-s_dn == "ECDSA CA"
+ expect resp.http.x-ssl-key_alg == "id-ecPublicKey"
+ expect resp.http.x-ssl-sha1 != "66AC64728CEA0C1F614A89C278FA2F94EDE9AB11"
+} -run
+
+# Check that the curves that the server accepts to use correspond to what we
+# expect it to be (according to ecdhe option).
+# The curve with the highest priority is X25519 for OpenSSL 1.1.1 and later,
+# and P-256 for OpenSSL 1.0.2.
+shell {
+ echo "Q" | openssl s_client -unix "${tmpdir}/ssl.sock" -servername server.ecdsa.com -tls1_2 2>/dev/null | grep -E "Server Temp Key: (ECDH, P-256, 256 bits|ECDH, prime256v1, 256 bits|X25519, 253 bits)"
+}
+
+shell {
+ echo "Q" | openssl s_client -unix "${tmpdir}/ssl_P-384.sock" -servername server.ecdsa.com 2>/dev/null| grep -E "Temp Key: ECDH,.+, 384 bits"
+}
diff --git a/reg-tests/ssl/ssl_reuse.vtc b/reg-tests/ssl/ssl_reuse.vtc
new file mode 100644
index 0000000..d7244ee
--- /dev/null
+++ b/reg-tests/ssl/ssl_reuse.vtc
@@ -0,0 +1,141 @@
+#REGTEST_TYPE=devel
+
+# This reg-test tests 4 scenarios with and without resumption tickets, with TLSv1.3 and TLSv1.2
+# Each client will try to established a connection, then try to reconnect 20 times resuming.
+
+
+varnishtest "Test if the SSL session/ticket reuse work correctly"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL_WOLFSSL) || feature(OPENSSL) && ssllib_name_startswith(OpenSSL) && openssl_version_atleast(1.1.1)'"
+feature ignore_unknown_macro
+
+server s1 -repeat 84 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ # forced to 1 here, because there is a cached session per thread
+ nbthread 1
+
+
+ defaults
+ mode http
+ option httplog
+ option logasap
+ log stderr local0 debug err
+ option httpclose
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen clst1
+ bind "fd@${clst1}"
+ server s1 "${h1_fe1_addr}:${h1_fe1_port}" ssl verify none sni str(www.test1.com)
+ http-response add-header x-ssl-bc-resumed %[ssl_bc_is_resumed]
+
+ listen clst2
+ bind "fd@${clst2}"
+ server s1 "${h1_fe2_addr}:${h1_fe2_port}" ssl verify none sni str(www.test1.com)
+ http-response add-header x-ssl-bc-resumed %[ssl_bc_is_resumed]
+
+ listen clst3
+ bind "fd@${clst3}"
+ server s1 "${h1_fe3_addr}:${h1_fe3_port}" ssl verify none sni str(www.test1.com)
+ http-response add-header x-ssl-bc-resumed %[ssl_bc_is_resumed]
+
+ listen clst4
+ bind "fd@${clst4}"
+ server s1 "${h1_fe4_addr}:${h1_fe4_port}" ssl verify none sni str(www.test1.com)
+ http-response add-header x-ssl-bc-resumed %[ssl_bc_is_resumed]
+
+ listen ssl
+ bind "fd@${fe1}" ssl crt ${testdir}/common.pem ssl-max-ver TLSv1.2
+ bind "fd@${fe2}" ssl crt ${testdir}/common.pem ssl-max-ver TLSv1.2 no-tls-tickets
+ bind "fd@${fe3}" ssl crt ${testdir}/common.pem ssl-min-ver TLSv1.3
+ bind "fd@${fe4}" ssl crt ${testdir}/common.pem ssl-min-ver TLSv1.3 no-tls-tickets
+
+ http-response add-header x-ssl-resumed %[ssl_fc_is_resumed]
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+# first bind
+# the first connection is not resumed
+client c1 -connect ${h1_clst1_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-resumed == 0
+} -run
+# the next 20 connections are resumed
+client c1 -connect ${h1_clst1_sock} -repeat 20 {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-resumed == 1
+} -run
+
+# second bind
+client c2 -connect ${h1_clst2_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-resumed == 0
+} -run
+
+client c2 -connect ${h1_clst2_sock} -repeat 20 {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-resumed == 1
+} -run
+
+# third bind
+client c3 -connect ${h1_clst3_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-resumed == 0
+} -run
+
+client c3 -connect ${h1_clst3_sock} -repeat 20 {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-resumed == 1
+} -run
+
+# fourth bind
+client c4 -connect ${h1_clst4_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-resumed == 0
+} -run
+
+client c4 -connect ${h1_clst4_sock} -repeat 20 {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-resumed == 1
+} -run
+
+
+# Could be useful to debug the result, the ssl_fc_is_resumed field in the log must be 1 after the 2nd command
+#shell {
+#
+# HOST=${h1_fe4_addr}
+# if [ "${h1_fe4_addr}" = "::1" ] ; then
+# HOST="\[::1\]"
+# fi
+#
+# rm sess.pem; (echo -e -n "GET / HTTP/1.1\r\n\r\n"; sleep 1) | openssl s_client -connect $HOST:${h1_fe4_port} -tls1_3 -sess_out sess.pem -keylogfile keys1.txt -servername www.test1.com > /tmp/ssl_debug1; echo | openssl s_client -connect ${HOST}:${h1_fe4_port} -tls1_3 -sess_in sess.pem -keylogfile keys2.txt -servername www.test1.com >> /tmp/ssl_debug1
+# echo "GET / HTTP/1.1" | openssl s_client -connect $HOST:${h1_fe4_port} -tls1_3 -servername www.test1.com
+#}
+
+haproxy h1 -cli {
+ send "show info"
+ expect ~ ".*SslFrontendSessionReuse_pct: 95.*"
+}
+
diff --git a/reg-tests/ssl/ssl_server_samples.vtc b/reg-tests/ssl/ssl_server_samples.vtc
new file mode 100644
index 0000000..cd97634
--- /dev/null
+++ b/reg-tests/ssl/ssl_server_samples.vtc
@@ -0,0 +1,73 @@
+#REGTEST_TYPE=devel
+
+varnishtest "Test the ssl_s_* sample fetches"
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTIONS=OPENSSL
+feature ignore_unknown_macro
+
+server s1 -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+ crt-base ${testdir}
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ http-response add-header x-ssl-sha1 %[ssl_s_sha1,hex]
+ http-response add-header x-ssl-notafter %[ssl_s_notafter]
+ http-response add-header x-ssl-notbefore %[ssl_s_notbefore]
+ http-response add-header x-ssl-sig_alg %[ssl_s_sig_alg]
+ http-response add-header x-ssl-i_dn %[ssl_s_i_dn]
+ http-response add-header x-ssl-s_dn %[ssl_s_s_dn]
+ http-response add-header x-ssl-s_serial %[ssl_s_serial,hex]
+ http-response add-header x-ssl-key_alg %[ssl_s_key_alg]
+ http-response add-header x-ssl-der %[ssl_s_der,hex]
+ http-response add-header x-ssl-chain-der %[ssl_s_chain_der,hex]
+ http-response add-header x-ssl-version %[ssl_s_version]
+
+ server s1 "${tmpdir}/ssl.sock" ssl verify none sni str(www.test1.com)
+
+ listen ssl-lst
+ mode http
+
+ bind "${tmpdir}/ssl.sock" ssl strict-sni crt-list ${testdir}/localhost.crt-list
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sha1 == "DF3B6E847A7BF83DFAAFCFEC65EE9BC36230D3EA"
+ expect resp.http.x-ssl-notafter == "330917162600Z"
+ expect resp.http.x-ssl-notbefore == "230920162600Z"
+ expect resp.http.x-ssl-sig_alg == "RSA-SHA256"
+ expect resp.http.x-ssl-i_dn == "/C=FR/L=Paris/O=HAProxy Technologies/CN=HAProxy Test Intermediate CA"
+ expect resp.http.x-ssl-s_dn == "/C=FR/L=Paris/O=test1/CN=www.test1.com"
+ expect resp.http.x-ssl-s_serial == "45B6C777A017159A19126340C1053521B91E123B"
+ expect resp.http.x-ssl-key_alg == "rsaEncryption"
+ expect resp.http.x-ssl-version == "3"
+ expect resp.http.x-ssl-der ~ 308203C7308202AFA003020102021445B6C777.*65AD7F4469DB9C8581EE260ABCB727AEF8A7C3ADA
+ expect resp.http.x-ssl-chain-der ~ 308203C7308202AFA003020102021445B6C777.*D457A8C66AECA6408FF5C1A3EDBFF2888D7CED
+} -run
+
+
diff --git a/reg-tests/ssl/ssl_simple_crt-list.vtc b/reg-tests/ssl/ssl_simple_crt-list.vtc
new file mode 100644
index 0000000..7f15056
--- /dev/null
+++ b/reg-tests/ssl/ssl_simple_crt-list.vtc
@@ -0,0 +1,50 @@
+#REGTEST_TYPE=bug
+varnishtest "Test for the bug #940"
+# Test that the SNI are correctly inserted with the same file multiple times.
+
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTIONS=OPENSSL
+feature ignore_unknown_macro
+
+server s1 -repeat 4 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ crt-base ${testdir}
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ log stderr local0 debug err
+ option logasap
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ server s1 "${tmpdir}/ssl.sock" ssl verify none sni str(record1.bug940.domain.tld)
+ server s2 "${tmpdir}/ssl.sock" ssl verify none sni str(record2.bug940.domain.tld)
+ server s3 "${tmpdir}/ssl.sock" ssl verify none sni str(record3.bug940.domain.tld)
+ server s4 "${tmpdir}/ssl.sock" ssl verify none sni str(record4.bug940.domain.tld)
+
+ listen ssl-lst
+ mode http
+ bind "${tmpdir}/ssl.sock" ssl strict-sni crt-list ${testdir}/simple.crt-list
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+client c1 -repeat 4 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/ssl/wrong_ctx_storage.vtc b/reg-tests/ssl/wrong_ctx_storage.vtc
new file mode 100644
index 0000000..c6cb19a
--- /dev/null
+++ b/reg-tests/ssl/wrong_ctx_storage.vtc
@@ -0,0 +1,45 @@
+# commit 28962c9
+# BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
+#
+# We never saw unexplicated crash with SSL, so I suppose that we are
+# luck, or the slot 0 is always reserved. Anyway the usage of the macro
+# SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
+# the deprecated functions SSL_get_app_data() and SSL_set_app_data()
+# by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
+# it reserves the slot in the SSL memory space.
+#
+# For information, this is the two declaration which seems wrong or
+# incomplete in the OpenSSL ssl.h file. We can see the usage of the
+# slot 0 whoch is hardcoded, but never reserved.
+#
+# #define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
+# #define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
+
+#REGTEST_TYPE=bug
+
+varnishtest "OpenSSL bug: Random crashes"
+#REQUIRE_OPTIONS=OPENSSL
+feature ignore_unknown_macro
+
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-buffer-size 1
+
+ listen frt
+ mode http
+ bind "fd@${frt}" ssl crt ${testdir}/common.pem
+ http-request redirect location /
+} -start
+
+shell {
+ HOST=${h1_frt_addr}
+ if [ "${h1_frt_addr}" = "::1" ] ; then
+ HOST="\[::1\]"
+ fi
+ for i in 1 2 3 4 5; do
+ curl -i -k https://$HOST:${h1_frt_port} & pids="$pids $!"
+ done
+ wait $pids
+}
diff --git a/reg-tests/startup/automatic_maxconn.vtc b/reg-tests/startup/automatic_maxconn.vtc
new file mode 100644
index 0000000..0173916
--- /dev/null
+++ b/reg-tests/startup/automatic_maxconn.vtc
@@ -0,0 +1,104 @@
+varnishtest "Automatic maxconn computation"
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature cmd "$HAPROXY_PROGRAM -cc '!feature(OBSOLETE_LINKER)'"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+feature ignore_unknown_macro
+#REGTEST_TYPE=broken
+
+
+# Check the maxconn computation with the -m parameter
+# Broken because it can't work with ASAN.
+
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+
+haproxy h1 -arg "-m 1024" -conf {
+} -start
+
+haproxy h1 -cli {
+ send "show info"
+ expect ~ ".*Maxconn: (29000|28000)\n.*"
+}
+
+haproxy h2 -arg "-m 384" -conf {
+} -start
+
+haproxy h2 -cli {
+ send "show info"
+ expect ~ ".*Maxconn: (11000|10000)\n.*"
+}
+
+haproxy h3 -arg "-m 256" -conf {
+} -start
+
+haproxy h3 -cli {
+ send "show info"
+ expect ~ ".*Maxconn: (7300|7000)\n.*"
+}
+
+# 1 SSL front but no back
+
+haproxy h4 -arg "-m 256" -conf {
+ defaults
+ mode http
+ timeout connect 1s
+ timeout client 1s
+ timeout server 1s
+
+ frontend fe1
+ bind "fd@${fe1}" ssl crt ${testdir}/common.pem
+
+} -start
+
+haproxy h4 -cli {
+ send "show info"
+ expect ~ ".*Maxconn: 1900\n.*"
+}
+
+# 1 SSL back but not front
+
+haproxy h5 -arg "-m 256" -conf {
+ defaults
+ mode http
+ timeout connect 1s
+ timeout client 1s
+ timeout server 1s
+
+ listen li2
+ bind "fd@${li2}"
+ server ssl "${s1_addr}:${s1_port}" ssl verify none
+
+} -start
+
+haproxy h5 -cli {
+ send "show info"
+ expect ~ ".*Maxconn: 1900\n.*"
+}
+
+
+# 1 SSL front and 1 back
+
+haproxy h6 -arg "-m 256" -conf {
+ defaults
+ mode http
+ timeout connect 1s
+ timeout client 1s
+ timeout server 1s
+
+ listen li3
+ bind "fd@${li3}" ssl crt ${testdir}/common.pem
+ server ssl "${s1_addr}:${s1_port}" ssl verify none
+
+} -start
+
+haproxy h6 -cli {
+ send "show info"
+ expect ~ ".*Maxconn: 1700\n.*"
+}
+
diff --git a/reg-tests/startup/check_condition.vtc b/reg-tests/startup/check_condition.vtc
new file mode 100644
index 0000000..3ab6ae4
--- /dev/null
+++ b/reg-tests/startup/check_condition.vtc
@@ -0,0 +1,32 @@
+varnishtest "Tests the -cc argument"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+
+shell {
+ set -e
+ $HAPROXY_PROGRAM -cc "version_atleast(2.4)"
+ ! $HAPROXY_PROGRAM -cc "version_atleast(1024)"
+
+ $HAPROXY_PROGRAM -cc "streq(foo,'foo')"
+ $HAPROXY_PROGRAM -cc "streq(\"foo bar\",'foo bar')"
+ ! $HAPROXY_PROGRAM -cc "streq(foo,bar)"
+
+ if $HAPROXY_PROGRAM -cc "version_atleast(2.5-dev2)"; then
+ export TESTVAR=1
+ $HAPROXY_PROGRAM -cc 'defined(TESTVAR) && streq("$TESTVAR","1")'
+ $HAPROXY_PROGRAM -cc 'feature(OPENSSL) || !feature(OPENSSL)'
+ $HAPROXY_PROGRAM -cc '1&&!0&&!((streq(a,b)||!streq(a,a)&&1)||strneq(a,a))'
+ $HAPROXY_PROGRAM -cc '1 &&! 0&& !((streq(a,b)||!streq(a,a)&&1)||strneq(a,a))'
+ $HAPROXY_PROGRAM -cc '1 && !0 && !((streq(a,b) || !streq(a,a) && 1) || strneq(a,a))'
+ ! $HAPROXY_PROGRAM -cc '1 && !0 && !((streq(a,b) || !streq(a,a) && 1) || strneq(a,b))'
+ ! $HAPROXY_PROGRAM -cc '1 && !0 && !((streq(a,a) || !streq(a,a) && 1) || strneq(a,a))'
+ # empty string is always false
+ ! $HAPROXY_PROGRAM -cc ''
+ # non-zero is true
+ $HAPROXY_PROGRAM -cc '-1000 && 200'
+ # check for various parsing errors (extra/missing chars)
+ ! $HAPROXY_PROGRAM -cc '200rrr'
+ ! $HAPROXY_PROGRAM -cc '!(0))'
+ ! $HAPROXY_PROGRAM -cc 'streq(a,"a)'
+ fi
+} -run
diff --git a/reg-tests/startup/common.pem b/reg-tests/startup/common.pem
new file mode 100644
index 0000000..206e417
--- /dev/null
+++ b/reg-tests/startup/common.pem
@@ -0,0 +1,117 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAnb0BDF7FsqzslakNg7u/n/JQkq6nheuKwvyTqECfpc9y7uSB
+e/vrEFqBaDSLQagJxuZdL5geFeVtRbdAoB97N1/LZa6vecjjgGSP0Aag/gS/ocnM
+RIyvlVWWT9MrD46OG3qZY1ORU1ltrVL0NKttJP8xME7j3bTwIDElx/hNI0n7L+yS
+kAe2xb/7CbZRfoOhjTVAcGv4aSLVc/Hi8k6VkIzdOEtH6TcghXmuGcuqvLNH9Buo
+syngKTcQ8zg6J+e64aVvC+e7vi94uil9Qu+JHm0pkDzAZ2WluNsuXlrJToPirWyj
+6/YdN6xgSI1hbZkBmUPAebgYuxBt6huvfyQd3wIDAQABAoIBABojc8UE/2W4WgwC
+04Z82ig7Ezb7Ui9S9M+S4zUCYHItijIkE4DkIfO3y7Hk4x6iJdyb191HK9UdC5p9
+32upS9XFPgM/izx3GZvxDhO+xXbSep7ovbyuQ3pPkHTx3TTavpm3GyvmcTKKoy4R
+jP4dWhzDXPdQW1ol3ZS4EDau4rlyClY6oi1mq9aBEX3MqVjB/nO7s2AbdgclAgP2
+OZMhTzWYR1k5tYySHCXh3ggGMCikyvHU0+SsGyrstYzP1VYi/n3f0VgqW/5ZjG8x
+6SHpe04unErPF3HuSun2ZMCFdBxaTFZ8FENb8evrSXe3nQOc9W21RQdRRrNNUbjl
+JYI4veECgYEA0ATYKMS1VCUYRZoQ49b5GTg7avUYqfW4bEo4fSfBue8NrnKR3Wu8
+PPBiCTuIYq1vSF+60B7Vu+hW0A8OuQ2UuMxLpYcQ7lKfNad/+yAfoWWafIqCqNU9
+at0QMdbW6A69d6jZt7OrXtleBsphCnN58jTz4ch4PIa2Oyq46NUXCvUCgYEAwh8t
+G6BOHOs3yRNI2s9Y9EEfwoil2uIKrZhqiL3AwdIpu5uNIMuPnbaEpXvRX6jv/qtL
+321i8vZLc31aM7zfxQ6B4ReQFJfYC80FJsWvcLwT9hB9mTJpLS4sIu5tzQc87O6w
+RtjFMom+5ns5hfPB4Eccy0EtbQWVY4nCzUeO6QMCgYBSvqqRRPXwG7VU8lznlHqP
+upuABzChYrnScY+Y0TixUlL54l79Wb6N6vzEOWceAWkzu8iewrU4QspNhr/PgoR3
+IeSxWlG0yy7Dc/ZnmTabx8O06I/iwrfkizzG5nOj6UEamRLJjPGNEB/jyZriQl7u
+pnugg1K4mMliLbNSAnlhBQKBgQCmYepbv260Qrex1KGhSg9Ia3k5V74weYYFfJnz
+UhChD+1NK+ourcsOtp3C6PlwMHBjq5aAjlU9QfUxq8NgjQaO8/xGXdfUjsFSfAtq
+TA4vZkUFpuTAJgEYBHc4CXx7OzTxLzRPxQRgaMgC7KNFOMR34vu/CsJQq3R7uFwL
+bsYC2QKBgQCtEmg1uDZVdByX9zyUMuRxz5Tq/vDcp+A5lJj2mha1+bUMaKX2+lxQ
+vPxY55Vaw/ukWkJirRrpGv6IytBn0dLAFSlKZworZGBaxsm8OGTFJ5Oe9+kZTjI9
+hvjpClOA1otbmj2F2uZAbuIjxQGDNUkLoifN5yDYCC8JPujHuHmULw==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIGeTCCBGGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJGUjEW
+MBQGA1UECBMNSWxlLWRlLUZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxEDAOBgNVBAoT
+B296b24uaW8xFTATBgNVBAMTDE96b24gVGVzdCBDQTEeMBwGCSqGSIb3DQEJARYP
+c3VwcG9ydEBvem9uLmlvMB4XDTE2MDExNzIzMDIzOFoXDTE4MDExNjIzMDIzOFow
+gb4xCzAJBgNVBAYTAkZSMRYwFAYDVQQIEw1JbGUtZGUtRnJhbmNlMRowGAYDVQQH
+ExFOZXVpbGx5LXN1ci1TZWluZTEYMBYGA1UEChMPVE9BRCBDb25zdWx0aW5nMRcw
+FQYDVQQLEw5lUGFyYXBoZXIgVGVhbTEWMBQGA1UEAxMNd3d3LnRlc3QxLmNvbTEw
+MC4GCSqGSIb3DQEJARYhYXJuYXVsdC5taWNoZWxAdG9hZC1jb25zdWx0aW5nLmZy
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnb0BDF7FsqzslakNg7u/
+n/JQkq6nheuKwvyTqECfpc9y7uSBe/vrEFqBaDSLQagJxuZdL5geFeVtRbdAoB97
+N1/LZa6vecjjgGSP0Aag/gS/ocnMRIyvlVWWT9MrD46OG3qZY1ORU1ltrVL0NKtt
+JP8xME7j3bTwIDElx/hNI0n7L+ySkAe2xb/7CbZRfoOhjTVAcGv4aSLVc/Hi8k6V
+kIzdOEtH6TcghXmuGcuqvLNH9BuosyngKTcQ8zg6J+e64aVvC+e7vi94uil9Qu+J
+Hm0pkDzAZ2WluNsuXlrJToPirWyj6/YdN6xgSI1hbZkBmUPAebgYuxBt6huvfyQd
+3wIDAQABo4IBvzCCAbswCwYDVR0PBAQDAgOoMBMGA1UdJQQMMAoGCCsGAQUFBwMB
+MB0GA1UdDgQWBBTIihFNVNgOseQnsWEcAQxAbIKE4TCBsgYDVR0jBIGqMIGngBRv
+G9At9gzk2MW5Z7JVey1LtPIZ8KGBg6SBgDB+MQswCQYDVQQGEwJGUjEWMBQGA1UE
+CBMNSWxlLWRlLUZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxEDAOBgNVBAoTB296b24u
+aW8xFTATBgNVBAMTDE96b24gVGVzdCBDQTEeMBwGCSqGSIb3DQEJARYPc3VwcG9y
+dEBvem9uLmlvggkA15FtIaGcrk8wDAYDVR0TAQH/BAIwADAaBgNVHREEEzARgg9j
+b21tb25OYW1lOmNvcHkwCQYDVR0SBAIwADBIBgNVHR8EQTA/MD2gO6A5hjdodHRw
+Oi8vb3BlbnNzbGNhLnRvYWQtY29uc3VsdGluZy5jb20vb3BlbnZwbi9MYXRlc3Qu
+Y3JsMBEGCWCGSAGG+EIBAQQEAwIGQDAxBglghkgBhvhCAQ0EJBYiVE9BRC1Db25z
+dWx0aW5nIHNlcnZlciBjZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAgEAewDa
+9BukGNJMex8gsXmmdaczTr8yh9Uvw4NJcZS38I+26o//2g+d6i7wxcQg8hIm62Hj
+0TblGU3+RsJo4uzcWxxA5YUYlVszbHNBRpQengEE5pjwHvoXVMNES6Bt8xP04+Vj
+0qVnA8gUaDMk9lN5anK7tF/mbHOIJwHJZYCa2t3y95dIOVEXFwOIzzbSbaprjkLN
+w0BgR5paJz7NZWNqo4sZHUUz94uH2bPEd01SqHO0dJwEVxadgxuPnD05I9gqGpGX
+Zf3Rn7EQylvUtX9mpPaulQPXc3emefewLUSSAdnZrVikZK2J/B4lSi9FpUwl4iQH
+pZoE0QLQHtB1SBKacnOAddGSTLSdFvpzjErjjWSpMukF0vutmrP86GG3xtshWVhI
+u+yLfDJVm/pXfaeDtWMXpxIT/U1i0avpk5MZtFMRC0MTaxEWBTnnJm+/yiaAXQYg
+E1ZIP0mkZkiUojIawTR7JTjHGhIraP9UVPNceVy0DLfETHEou3vhwBn7PFOz7piJ
+wjp3A47DStJD4fapaX6B1fqM+n34CMD9ZAiJFgQEIQfObAWC9hyr4m+pqkp1Qfuw
+vsAP/ZoS1CBirJfm3i+Gshh+VeH+TAmO/NBBYCfzBdgkNz4tJCkOc7CUT/NQTR/L
+N2OskR/Fkge149RJi7hHvE3gk/mtGtNmHJPuQ+s=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIJazCCBVOgAwIBAgIUWHoc5e2FUECgyCvyVf8wCtt8gTYwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA4MDQxODU4MTZaFw0yMDA5
+MDMxODU4MTZaMEUxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggQiMA0GCSqGSIb3DQEB
+AQUAA4IEDwAwggQKAoIEAQDARiuHkhrnf38Md1nxGDSneJfwv/QksdNNMNTJBdjg
+OVmaRCIAyz43oefTWDQ/TebbSwB+Lg9pud1zadGWhlZRhCgBPP8JDMhIKH4eXIRk
+5IIa8WD08EwvSlqJL0r4gsMtVsxy7BZHAkka/2Ket9pyGt4kG5n75RFdc6BI80/8
+RwJt/MDxPrcVBAT7LnCluxQpyya9mZCabj7l+9a2yU2hgWS6QqfZJ133krkP/MMh
+AEQkSoA4mmBwWk9yPqXmUqiOi7v6iLkIUEh5SgYVPRk9BtU/kDaUdSwuqRrpCZo4
+SsWZWFLxBmLHkSh+G+BWjCVYMQr2ye7e+VMT/20+5xAfq4fj9n5BsPcx3QcVuTof
+RAc/Oygnt4MYnIcUb7zRFvCAvgpUHL7BnEn6nhyXjHJGqGDchsg8m9t3v/Y3ohq+
+qmrSzdeuylE1n3W5aWJlbFmyXegNP45MJ0xicesVrXEWF7YD/ir9mGJ8bQYr4blf
+77PrbF02komC6AzVPKOJa0jR+eW1wErzYlkYgez6ylBWCiHJd1dhEHlK3h2rXdYa
+Gnb45ILCLpEDjNEUrHifLLNXwqJpgZQsJU6BgMgk7ZgBfAKrCfTeg0rkCqCAPeVb
+8eSLf7FBF7YBRJ5P6u8qXc4RtgEu607GaWV0gIMfyVBY52oV+OaNsEdFetrJnp3c
+friG8vJ+7jdq6zjUCGgnfUIHoViJPh3JuFfhA3jT0gQDKW5PeI7dxhrNvlqdYfHI
+fxX7Y1/J6cTQkqJ1cai2f0bwJIJiTAThNbG+zrtjJ7fZ3wJ4udyU/IKrwShqtmTb
+1Ofj0tJDdwOH8i84vIySLUvR9aAb7ClFlnsx6rzwOxG90W7C0LA2M0EHm4FezJm/
+FfujnZwEWr1T9Wki6qE0MHCbdN/TTDws//EKkkE44FC+amL96w0IQl70vpE37j2A
+zlDWvFFID95SIxfmpkwWDvXDKv6gr1GMLeysCl2fgpY05Xidw5cEo9/tEkuWn/dG
+x/D9hnLBGeroA0251ES12jemqDjI2U0tfaeHakjwSsoWElf94Qmuh2iPZ+1zIxQs
+7o6nAWN8X9hfsmrDTTHlww0TEfrjlbzG5Yh+0ZRxmejgiUyOCXck+eh/ZXMXvfWh
+y3CorIIuWgkRjm80PYkdaRDJdZuyP6R7tXfTXNVzAiSQf0Qx9ru2KB2Fs/XZPamH
+KjItAU5Q6msIVvaRMS0muQgV+b6hqSEBzqXqJfAlpVLHXr5FqK+U7EB9y02B6piB
+tAmxqXP8OOCoQql6/vgIcrDFUOo6KtGBW36ef74XE3KCUVaIzVJZSIt6i/Vi0bZj
+bAjsJUQ3qDlHdorv9TRVOhnC1GUz7SuYnpEOyiXmyx3LAgMBAAGjUzBRMB0GA1Ud
+DgQWBBQ62csZcH/meQcENHhNbqz9LMzwjjAfBgNVHSMEGDAWgBQ62csZcH/meQcE
+NHhNbqz9LMzwjjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IEAQBA
+wLsGf3R1+/I2zQE+lsj7RasZtA/Cos92iEGDAPvFbx9e+roG8Gg8KBsEJu/HN0JH
+lMMiQ8dDRHSBMvRBENL5/57oOOhmqc+1u5sazLuANhzAYPZG17Klib7YpEwWoXar
+FDDiJYtCyLW0oNLpCswYopWK9GC0RJNucB0NFvOxehJ2sP2/fxGBQMB09L6mjKjd
+4KsOzyd3dNf0VYS6jB+/1pcKSHKQUo9HRHB5FK04PsYHoh4AtmEHvmYQKcWWidgU
+v26ftlH00ERzuW2juqBbz9mghlNRqXi0IyZ9b4tSj29dxW+WWFzo7j2zEPaD6z2W
+DEHq7zvON+g+q6qLgWeszqMgJzjvWjMj00E/t06PoHPiz/cAnDKEqp+ZzxCIFrxj
+/qneChpogDWyLbawhyyzbZvbirx5znOSbWjPZgydqaNEFViqbxwinBx4Xxabo6XN
+TU020FuMWmgfbIcvtgjKgyKqc97l7JMNNm7LQV9+9W0U5zdIqQKLZ9MMrd2w3xh4
+MAB8NKnwzHReK0TWwUU9HSgFAGdEX6HnyZ3bQ13ijg+sNBRMEi0gBHaqZKDdyoft
+B2u2uasSwioV48dbSIcHl+rTBKxiMh5XQ7ENnaGOJkjsIqTVzizqnPHU8eMBnSbb
+dsXlamROYII44+j3Ku6OGt51w86eGk4VxI3tmaECcJKqTkwUFD8AcNDrkjtmLuxK
+12yjnoM+u1cclfqQ5NOtRc6MJZ27jCobfBBhVdKVDp4X1WNyqGlbsU5adDAzknuI
+GT7MJO7lGjkZX2n54BNPSfrSknYMOVYcZqL0Dbcrhx5IyEmg+iOlOu1HO1tdnZop
+ej4vT+1V2w9Sa4Wo3UCo84jcm5v/4z7jCYh4BRQ60CFb7GLxZoqXIslcGSPool3n
+jl8JWoaLXrJUPfZGXo1iAlayJ5EiMyZl4eB/TBUf6TMm8vLvsPiUT+CEsjLppOdS
+eYppZAZ6H1JrJGs5kKBdOJHGn6Pkp5QsHIswOBd1HqHrBbYbZmDaDLRHduILWLrM
+e0/IfDdeXB/bKfmZoEpT8xRiauw15p0AHLumiK7KISAehfgBqUnxx+YmgGoZ7EWX
+KnMYAfCuC6oJ1DL0gp4Z9yMK1eu+GV1sLxPq9ZruEHW1R+H+4sGyiA5Gso2tgB6/
+XW//wxKclNp5LZR7hqfs/kGuh5asrJrnEbMwWn2+tr/LqfYtYh1D6nHfIXpT0o1d
+rNy/HrsKnRDMWxjm03r4hCViuNVD3Zb9anAF/NSPDVu8ATM5JbJNrCYX4eipz6ZE
+aQBkwIBkTPgtgP4r8v2G+uMYDw8nq7xh72FK107aeTTwc6MgU5jfeFNMr2XJisJd
+lSem1ngKYQSEzjVsTE4c
+-----END CERTIFICATE-----
diff --git a/reg-tests/startup/default_rules.vtc b/reg-tests/startup/default_rules.vtc
new file mode 100644
index 0000000..1cbbfa9
--- /dev/null
+++ b/reg-tests/startup/default_rules.vtc
@@ -0,0 +1,185 @@
+varnishtest "Misuses of defaults section defining TCP/HTTP rules"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature ignore_unknown_macro
+
+#
+# anonymous defaults section cannot define TCP/HTTP rules
+#
+haproxy h1 -conf-BAD {} {
+ defaults
+ http-request set-header X-Hdr 1
+}
+
+haproxy h2 -conf-BAD {} {
+ defaults
+ http-response set-header X-Hdr 1
+}
+
+haproxy h3 -conf-BAD {} {
+ defaults
+ http-after-request set-header X-Hdr 1
+}
+
+haproxy h4 -conf-BAD {} {
+ defaults
+ tcp-request connection accept
+}
+
+haproxy h5 -conf-BAD {} {
+ defaults
+ tcp-request session accept
+}
+
+haproxy h6 -conf-BAD {} {
+ defaults
+ tcp-request inspect-delay 5s
+ tcp-request content accept
+}
+
+haproxy h7 -conf-BAD {} {
+ defaults
+ tcp-response inspect-delay 5s
+ tcp-response content accept
+}
+
+#
+# defaults section defining TCP/HTTP rules cannot be used to init another
+# defaults section
+#
+haproxy h8 -conf-BAD {} {
+ defaults invalid
+ tcp-response inspect-delay 5s
+ tcp-response content accept
+
+ defaults from invalid
+ mode tcp
+}
+
+#
+# defaults section defining TCP/HTTP rules cannot be used to init a listen
+# section
+#
+haproxy h9 -conf-BAD {} {
+ defaults invalid
+ tcp-request inspect-delay 5s
+ tcp-request content accept
+
+ listen li from invalid
+ mode tcp
+ bind "fd@${lih9}"
+ server www 127.0.0.1:80
+}
+
+#
+# defaults section defining TCP/HTTP rules cannot be used to init frontend and
+# backend sections at the same time
+#
+#
+haproxy h10 -conf-BAD {} {
+ defaults invalid
+ tcp-request inspect-delay 5s
+ tcp-request content accept
+
+ frontend fe from invalid
+ mode tcp
+ bind "fd@${feh10}"
+ default_backend be1
+
+ backend be from invalid
+ mode tcp
+ server www 127.0.0.1:80
+}
+
+#
+# defaults section defining 'tcp-request connection' or 'tcp-request session'
+# rules cannot be used to init backend sections
+#
+haproxy h11 -conf-BAD {} {
+ defaults invalid
+ tcp-request connection accept
+
+ backend be from invalid
+ mode tcp
+ server www 127.0.0.1:80
+}
+
+haproxy h12 -conf-BAD {} {
+ defaults invalid
+ tcp-request session accept
+
+ backend be from invalid
+ mode tcp
+ server www 127.0.0.1:80
+}
+
+#
+# defaults section defining 'tcp-response content' rules cannot be used to init
+# a frontend section
+#
+haproxy h13 -conf-BAD {} {
+ defaults invalid
+ tcp-response inspect-delay 5s
+ tcp-response content accept
+
+ frontend fe from invalid
+ mode tcp
+ bind "fd@${feh10}"
+}
+
+haproxy h14 -arg -V -conf-OK {
+ defaults tcp
+ tcp-response inspect-delay 5s
+ tcp-response content accept
+
+ backend be from tcp
+ mode tcp
+ server www 127.0.0.1:80
+}
+
+#
+# Check arguments resolutions in rules. FE/BE arguments must be resolved, but
+# SRV/TAB arguments without an explicit proxy name are not allowed.
+#
+
+haproxy h15 -conf-BAD {} {
+ defaults invalid
+ mode http
+ http-request set-header x-test "%[srv_conn(www)]"
+
+ backend be from invalid
+ server www 127.0.0.1:80
+}
+
+haproxy h16 -conf-BAD {} {
+ defaults invalid
+ mode http
+ http-request track-sc0 src
+ http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
+
+ backend be
+ stick-table type ip size 100k expire 30s store http_req_rate(10s)
+ server www 127.0.0.1:80
+}
+
+haproxy h17 -arg -V -conf-OK {
+ defaults common
+ mode http
+
+ defaults def_front from common
+ http-request set-header x-test1 "%[fe_conn]"
+
+ defaults def_back from common
+ http-request track-sc0 src table be
+ http-request deny deny_status 429 if { sc_http_req_rate(0,be) gt 20 }
+ http-request set-header x-test2 "%[be_conn]"
+ http-request set-header x-test3 "%[srv_conn(be/www)]"
+
+ frontend fe from def_front
+ bind "fd@${feh15}"
+ default_backend be
+
+ backend be from def_back
+ stick-table type ip size 100k expire 30s store http_req_rate(10s)
+ server www 127.0.0.1:80
+}
diff --git a/reg-tests/stick-table/converteers_ref_cnt_never_dec.vtc b/reg-tests/stick-table/converteers_ref_cnt_never_dec.vtc
new file mode 100644
index 0000000..533765f
--- /dev/null
+++ b/reg-tests/stick-table/converteers_ref_cnt_never_dec.vtc
@@ -0,0 +1,75 @@
+# commit 3e60b11
+# BUG/MEDIUM: stick-tables: Decrement ref_cnt in table_* converters
+#
+# When using table_* converters ref_cnt was incremented
+# and never decremented causing entries to not expire.
+#
+# The root cause appears to be that stktable_lookup_key()
+# was called within all sample_conv_table_* functions which was
+# incrementing ref_cnt and not decrementing after completion.
+#
+# Added stktable_release() to the end of each sample_conv_table_*
+# function and reworked the end logic to ensure that ref_cnt is
+# always decremented after use.
+#
+# This should be backported to 1.8
+
+#REGTEST_TYPE=bug
+#REQUIRE_VERSION=2.4
+
+varnishtest "stick-tables: Test expirations when used with table_*"
+
+# As some macros for haproxy are used in this file, this line is mandatory.
+feature ignore_unknown_macro
+
+# Do nothing.
+server s1 {
+} -start
+
+haproxy h1 -conf {
+ # Configuration file of 'h1' haproxy instance.
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend http1
+ bind "fd@${my_frontend_fd}"
+ stick-table size 1k expire 1ms type ip store conn_rate(10s),http_req_cnt,http_err_cnt,http_fail_cnt,http_req_rate(10s),http_err_rate(10s),http_fail_rate(10s),gpc0,gpc0_rate(10s),gpt0
+ http-request track-sc0 req.hdr(X-Forwarded-For)
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_http_req_cnt(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_trackers(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),in_table(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_bytes_in_rate(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_bytes_out_rate(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_conn_cnt(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_conn_cur(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_conn_rate(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_gpt0(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_gpc0(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_gpc0_rate(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_http_err_cnt(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_http_err_rate(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_http_fail_cnt(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_http_fail_rate(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_http_req_cnt(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_http_req_rate(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_kbytes_in(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_kbytes_out(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_server_id(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_sess_cnt(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_sess_rate(http1) -m int lt 0 }
+ http-request redirect location https://${s1_addr}:${s1_port}/ if { req.hdr(X-Forwarded-For),table_trackers(http1) -m int lt 0 }
+} -start
+
+client c1 -connect ${h1_my_frontend_fd_sock} {
+ txreq -url "/" -hdr "X-Forwarded-For: 127.0.0.1"
+ rxresp
+ expect resp.status == 503
+} -run
+
+haproxy h1 -cli {
+ send "show table http1"
+ expect ~ "table: http1, type: ip, size:1024, used:(0|1\\n0x[0-9a-f]*: key=127\\.0\\.0\\.1 use=0 exp=[0-9]* shard=0 gpt0=0 gpc0=0 gpc0_rate\\(10000\\)=0 conn_rate\\(10000\\)=1 http_req_cnt=1 http_req_rate\\(10000\\)=1 http_err_cnt=0 http_err_rate\\(10000\\)=0 http_fail_cnt=0 http_fail_rate\\(10000\\)=0)\\n$"
+} -wait
diff --git a/reg-tests/stick-table/src_conn_rate.vtc b/reg-tests/stick-table/src_conn_rate.vtc
new file mode 100644
index 0000000..bdf8869
--- /dev/null
+++ b/reg-tests/stick-table/src_conn_rate.vtc
@@ -0,0 +1,43 @@
+varnishtest "stick table: src_conn_rate"
+feature ignore_unknown_macro
+
+haproxy h0 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen li
+ bind "fd@${fe1}"
+ http-request track-sc0 src table conn_rate_table
+ http-request deny if { src_conn_rate(conn_rate_table) gt 3 }
+ http-request return status 200
+
+ backend conn_rate_table
+ stick-table type ip size 1m expire 1m store conn_rate(1m)
+} -start
+
+client c0 -connect ${h0_fe1_addr}:${h0_fe1_port} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c1 -connect ${h0_fe1_addr}:${h0_fe1_port} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c2 -connect ${h0_fe1_addr}:${h0_fe1_port} {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c3 -connect ${h0_fe1_addr}:${h0_fe1_port} {
+ txreq
+ rxresp
+ expect resp.status == 403
+} -run
diff --git a/reg-tests/stick-table/unknown_key.vtc b/reg-tests/stick-table/unknown_key.vtc
new file mode 100644
index 0000000..f0307cb
--- /dev/null
+++ b/reg-tests/stick-table/unknown_key.vtc
@@ -0,0 +1,32 @@
+# Shipped with the commit fixing the bug.
+
+#REGTEST_TYPE=bug
+
+varnishtest "Stick Table: Crash when accessing unknown key."
+feature ignore_unknown_macro
+
+server s0 {
+ rxreq
+ txresp
+} -start
+
+haproxy h0 -conf {
+ defaults
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend test
+ mode http
+ bind "fd@${fe1}"
+ stick-table type ip size 1m expire 1h store gpc0
+ http-request deny if { src,table_trackers(test) eq 1 }
+ http-request deny if { src,in_table(test) }
+ http-request deny deny_status 200
+} -start
+
+client c0 -connect ${h0_fe1_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/reg-tests/stickiness/lb-services.vtc b/reg-tests/stickiness/lb-services.vtc
new file mode 100644
index 0000000..23c9a9a
--- /dev/null
+++ b/reg-tests/stickiness/lb-services.vtc
@@ -0,0 +1,292 @@
+vtest "A reg test for stickiness"
+feature ignore_unknown_macro
+#REGTEST_TYPE=slow
+
+# The aim of this test is to check that "stick on" rules
+# do the job they are supposed to do.
+# If we remove one of the "stick on" rule, this script fails.
+
+server s_not_used_1 {}
+server s_not_used_2 {}
+server s_not_used_3 {}
+server s_not_used_4 {}
+server s_not_used_5 {}
+server s_not_used_6 {}
+server s_not_used_7 {}
+server s_not_used_8 {}
+server s_not_used_9 {}
+server s_not_used_10 {}
+server s_not_used_11 {}
+server s_not_used_12 {}
+
+# h1/be1 servers
+server s1 {
+ rxreq
+ txresp -hdr "Server: be1/s1"
+} -repeat 2 -start
+
+server s2 {
+ rxreq
+ txresp -hdr "Server: be1/s2"
+} -repeat 2 -start
+
+# h1/be2 servers
+server s3 {
+ rxreq
+ txresp -hdr "Server: be2/s3"
+} -repeat 2 -start
+
+server s4 {
+ rxreq
+ txresp -hdr "Server: be2/s4"
+} -repeat 2 -start
+
+haproxy h1 -arg "-L A" -conf {
+ defaults
+ mode http
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ log stdout format raw local0 debug
+
+ peers mypeers
+ bind "fd@${A}"
+ server A
+ server B ${h2_B_addr}:${h2_B_port}
+ table mytable type string size 10m
+
+ backend be1
+ balance roundrobin
+ stick on urlp(client) table mypeers/mytable
+ server srv1 ${s1_addr}:${s1_port}
+ server srv2 ${s2_addr}:${s2_port}
+
+ backend be2
+ balance roundrobin
+ stick on urlp(client) table mypeers/mytable
+ server s_not_used_1 ${s_not_used_1_addr}:${s_not_used_1_port}
+ server s_not_used_2 ${s_not_used_2_addr}:${s_not_used_2_port}
+ server s_not_used_3 ${s_not_used_3_addr}:${s_not_used_3_port}
+ server srv2 ${s4_addr}:${s4_port}
+ server s_not_used_4 ${s_not_used_4_addr}:${s_not_used_4_port}
+ server s_not_used_5 ${s_not_used_5_addr}:${s_not_used_5_port}
+ server s_not_used_6 ${s_not_used_6_addr}:${s_not_used_6_port}
+ server srv1 ${s3_addr}:${s3_port}
+
+ frontend fe
+ acl acl_be1 path_beg /be1
+ acl acl_be2 path_beg /be2
+ use_backend be1 if acl_be1
+ use_backend be2 if acl_be2
+ bind "fd@${fe}"
+}
+
+# h2/be1 servers
+server s5 {
+ rxreq
+ txresp -hdr "Server: be1/s5"
+} -repeat 2 -start
+
+server s6 {
+ rxreq
+ txresp -hdr "Server: be1/s6"
+} -repeat 2 -start
+
+# h2/be2 servers
+server s7 {
+ rxreq
+ txresp -hdr "Server: be2/s7"
+} -repeat 2 -start
+
+server s8 {
+ rxreq
+ txresp -hdr "Server: be2/s8"
+} -repeat 2 -start
+
+
+haproxy h2 -arg "-L B" -conf {
+ defaults
+ mode http
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ peers mypeers
+ bind "fd@${B}"
+ server A ${h1_A_addr}:${h1_A_port}
+ server B
+ table mytable type string size 10m
+
+ backend be1
+ balance roundrobin
+ stick on urlp(client) table mypeers/mytable
+ server s_not_used_7 ${s_not_used_7_addr}:${s_not_used_7_port}
+ server s_not_used_8 ${s_not_used_8_addr}:${s_not_used_8_port}
+ server s_not_used_9 ${s_not_used_9_addr}:${s_not_used_9_port}
+ server srv1 ${s5_addr}:${s5_port}
+ server s_not_used_10 ${s_not_used_10_addr}:${s_not_used_10_port}
+ server s_not_used_11 ${s_not_used_11_addr}:${s_not_used_11_port}
+ server s_not_used_12 ${s_not_used_12_addr}:${s_not_used_12_port}
+ server srv2 ${s6_addr}:${s6_port}
+
+ backend be2
+ balance roundrobin
+ stick on urlp(client) table mypeers/mytable
+ server s_not_used_1 ${s_not_used_1_addr}:${s_not_used_1_port}
+ server s_not_used_2 ${s_not_used_2_addr}:${s_not_used_2_port}
+ server s_not_used_3 ${s_not_used_3_addr}:${s_not_used_3_port}
+ server s_not_used_4 ${s_not_used_4_addr}:${s_not_used_4_port}
+ server s_not_used_5 ${s_not_used_5_addr}:${s_not_used_5_port}
+ server s_not_used_6 ${s_not_used_6_addr}:${s_not_used_6_port}
+ server srv1 ${s7_addr}:${s7_port}
+ server srv2 ${s8_addr}:${s8_port}
+
+ frontend fe
+ acl acl_be1 path_beg /be1
+ acl acl_be2 path_beg /be2
+ use_backend be1 if acl_be1
+ use_backend be2 if acl_be2
+ bind "fd@${fe}"
+}
+
+haproxy h1 -start
+delay 0.2
+haproxy h2 -start
+delay 2
+
+client cx -connect ${h1_fe_sock} {
+ txreq -url "/be1?client=c1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ be1/s1
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cy -connect ${h1_fe_sock} {
+ txreq -url "/be2?client=c1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ be2/s3
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cx -connect ${h2_fe_sock} {
+ txreq -url "/be1?client=c1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ be1/s5
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cy -connect ${h2_fe_sock} {
+ txreq -url "/be2?client=c1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ be2/s7
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cX -connect ${h1_fe_sock} {
+ txreq -url "/be1?client=c2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ be1/s2
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cY -connect ${h1_fe_sock} {
+ txreq -url "/be2?client=c2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ be2/s4
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cX -connect ${h2_fe_sock} {
+ txreq -url "/be1?client=c2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ be1/s6
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cY -connect ${h2_fe_sock} {
+ txreq -url "/be2?client=c2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ be2/s8
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
diff --git a/reg-tests/stickiness/srvkey-addr.vtc b/reg-tests/stickiness/srvkey-addr.vtc
new file mode 100644
index 0000000..0dc1148
--- /dev/null
+++ b/reg-tests/stickiness/srvkey-addr.vtc
@@ -0,0 +1,263 @@
+vtest "A reg test for stickiness with srvkey addr"
+feature ignore_unknown_macro
+#REGTEST_TYPE=slow
+
+# The aim of this test is to check that "stick on" rules
+# do the job they are supposed to do.
+# If we remove one of the "stick on" rule, this script fails.
+
+#REQUIRE_VERSION=2.4
+
+server s_not_used_1 {}
+server s_not_used_2 {}
+server s_not_used_3 {}
+server s_not_used_4 {}
+server s_not_used_5 {}
+server s_not_used_6 {}
+server s_not_used_7 {}
+server s_not_used_8 {}
+server s_not_used_9 {}
+server s_not_used_10 {}
+server s_not_used_11 {}
+server s_not_used_12 {}
+
+# h1/be1 servers
+server s1 {
+ rxreq
+ txresp -hdr "Server: s1"
+} -repeat 8 -start
+
+server s2 {
+ rxreq
+ txresp -hdr "Server: s2"
+} -repeat 8 -start
+
+haproxy h1 -arg "-L A" -conf {
+ defaults
+ mode http
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ log stdout format raw local0 debug
+
+ peers mypeers
+ bind "fd@${A}"
+ server A
+ server B ${h2_B_addr}:${h2_B_port}
+ table mytable type string size 10m srvkey addr
+
+ backend be1
+ balance roundrobin
+ stick on urlp(client) table mypeers/mytable
+ server srv1 ${s1_addr}:${s1_port}
+ server srv2 ${s2_addr}:${s2_port}
+
+ backend be2
+ balance roundrobin
+ stick on urlp(client) table mypeers/mytable
+ server s_not_used_1 ${s_not_used_1_addr}:${s_not_used_1_port}
+ server s_not_used_2 ${s_not_used_2_addr}:${s_not_used_2_port}
+ server s_not_used_3 ${s_not_used_3_addr}:${s_not_used_3_port}
+ server srv2_2 ${s2_addr}:${s2_port}
+ server s_not_used_4 ${s_not_used_4_addr}:${s_not_used_4_port}
+ server s_not_used_5 ${s_not_used_5_addr}:${s_not_used_5_port}
+ server s_not_used_6 ${s_not_used_6_addr}:${s_not_used_6_port}
+ server srv1_2 ${s1_addr}:${s1_port}
+ server s_no_addr_1 unresolvable1.addr.local init-addr none
+
+ frontend fe
+ acl acl_be1 path_beg /be1
+ acl acl_be2 path_beg /be2
+ use_backend be1 if acl_be1
+ use_backend be2 if acl_be2
+ bind "fd@${fe}"
+}
+
+haproxy h2 -arg "-L B" -conf {
+ defaults
+ mode http
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ peers mypeers
+ bind "fd@${B}"
+ server A ${h1_A_addr}:${h1_A_port}
+ server B
+ table mytable type string size 10m srvkey addr
+
+ backend be1
+ balance roundrobin
+ stick on urlp(client) table mypeers/mytable
+ server s_not_used_7 ${s_not_used_7_addr}:${s_not_used_7_port}
+ server s_not_used_8 ${s_not_used_8_addr}:${s_not_used_8_port}
+ server s_not_used_9 ${s_not_used_9_addr}:${s_not_used_9_port}
+ server srv1_h2_1 ${s1_addr}:${s1_port}
+ server s_not_used_10 ${s_not_used_10_addr}:${s_not_used_10_port}
+ server s_not_used_11 ${s_not_used_11_addr}:${s_not_used_11_port}
+ server s_not_used_12 ${s_not_used_12_addr}:${s_not_used_12_port}
+ server srv2_h2_1 ${s2_addr}:${s2_port}
+ server s_no_addr_1 unresolvable1.addr.local init-addr none
+
+ backend be2
+ balance roundrobin
+ stick on urlp(client) table mypeers/mytable
+ server s_not_used_1 ${s_not_used_1_addr}:${s_not_used_1_port}
+ server s_not_used_2 ${s_not_used_2_addr}:${s_not_used_2_port}
+ server s_not_used_3 ${s_not_used_3_addr}:${s_not_used_3_port}
+ server s_not_used_4 ${s_not_used_4_addr}:${s_not_used_4_port}
+ server s_not_used_5 ${s_not_used_5_addr}:${s_not_used_5_port}
+ server s_not_used_6 ${s_not_used_6_addr}:${s_not_used_6_port}
+ server srv1_h2_2 ${s1_addr}:${s1_port}
+ server srv2_h2_2 ${s2_addr}:${s2_port}
+ server s_no_addr_2 unresolvable2.addr.local init-addr none
+
+ frontend fe
+ acl acl_be1 path_beg /be1
+ acl acl_be2 path_beg /be2
+ use_backend be1 if acl_be1
+ use_backend be2 if acl_be2
+ bind "fd@${fe}"
+}
+
+haproxy h1 -start
+delay 0.2
+haproxy h2 -start
+delay 2
+
+client cx -connect ${h1_fe_sock} {
+ txreq -url "/be1?client=c1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s1
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cy -connect ${h1_fe_sock} {
+ txreq -url "/be2?client=c1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s1
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cx -connect ${h2_fe_sock} {
+ txreq -url "/be1?client=c1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s1
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cy -connect ${h2_fe_sock} {
+ txreq -url "/be2?client=c1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s1
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cX -connect ${h1_fe_sock} {
+ txreq -url "/be1?client=c2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s2
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cY -connect ${h1_fe_sock} {
+ txreq -url "/be2?client=c2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s2
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cX -connect ${h2_fe_sock} {
+ txreq -url "/be1?client=c2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s2
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+client cY -connect ${h2_fe_sock} {
+ txreq -url "/be2?client=c2"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.Server ~ s2
+} -repeat 2 -run
+
+haproxy h1 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
+haproxy h2 -cli {
+ send "show table mypeers/mytable"
+ expect ~ .*
+}
+
diff --git a/reg-tests/stream/unique-id-from-proxy.vtc b/reg-tests/stream/unique-id-from-proxy.vtc
new file mode 100644
index 0000000..eaac065
--- /dev/null
+++ b/reg-tests/stream/unique-id-from-proxy.vtc
@@ -0,0 +1,38 @@
+varnishtest "Check that we are able to read a unique-id from PROXYv2"
+
+#REQUIRE_VERSION=2.2
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend echo
+ bind "fd@${fe1}" accept-proxy
+ http-after-response set-header echo %[fc_pp_unique_id,hex]
+ http-request return status 200
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ # PROXY v2 signature
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ # version + PROXY
+ sendhex "21"
+ # TCP4
+ sendhex "11"
+ # length of the address (12) + length of the TLV (8)
+ sendhex "00 14"
+ # 127.0.0.1 42 127.0.0.1 1337
+ sendhex "7F 00 00 01 7F 00 00 01 00 2A 05 39"
+ # PP2_TYPE_UNIQUE_ID + length of the value + "12345"
+ sendhex "05 00 05 31 32 33 34 35"
+
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.echo == "3132333435"
+} -run
diff --git a/reg-tests/stream/unique-id.vtc b/reg-tests/stream/unique-id.vtc
new file mode 100644
index 0000000..0607b2a
--- /dev/null
+++ b/reg-tests/stream/unique-id.vtc
@@ -0,0 +1,47 @@
+varnishtest "unique-id test"
+
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+} -repeat 2 -start
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ frontend stable
+ bind "fd@${fe1}"
+ unique-id-format TEST-%[uuid]
+ http-response set-header A %[unique-id]
+ http-response set-header B %[unique-id]
+ default_backend be
+
+ frontend request_data
+ bind "fd@${fe2}"
+ unique-id-format TEST-%[req.hdr(in)]
+ http-response set-header out %[unique-id]
+ default_backend be
+
+ backend be
+ server srv1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.a == resp.http.b
+} -run
+
+client c2 -connect ${h1_fe2_sock} {
+ txreq -url "/" \
+ -hdr "in: 12345678"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.out == "TEST-12345678"
+} -run
diff --git a/reg-tests/tcp-rules/default_rules.vtc b/reg-tests/tcp-rules/default_rules.vtc
new file mode 100644
index 0000000..8c05f43
--- /dev/null
+++ b/reg-tests/tcp-rules/default_rules.vtc
@@ -0,0 +1,61 @@
+varnishtest "Test declaration of TCP rules in default sections"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
+feature ignore_unknown_macro
+
+server s1 {
+ rxreq
+ txresp
+ expect req.http.x-test1-frt == "def_front"
+ expect req.http.x-test1-bck == "def_back"
+} -start
+
+haproxy h1 -conf {
+ defaults common
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ defaults def_front from common
+ tcp-request connection accept
+ tcp-request session accept
+ tcp-request inspect-delay 5s
+ tcp-request content set-var(txn.test1) "str(def_front)"
+ tcp-request content accept
+
+ defaults def_back from common
+ tcp-request inspect-delay 5s
+ tcp-request content set-var(txn.test1) "str(def_back)"
+ tcp-request content accept
+
+ tcp-response inspect-delay 5s
+ tcp-response content set-var(txn.test2) "str(def_back)"
+ tcp-response content accept
+
+ frontend fe from def_front
+ bind "fd@${feh1}"
+ tcp-request connection reject
+ tcp-request session reject
+ tcp-request content reject
+
+ http-request set-header x-test1-frt "%[var(txn.test1)]"
+
+ default_backend be
+
+ backend be from def_back
+ tcp-response content reject
+
+ http-request set-header x-test1-bck "%[var(txn.test1)]"
+ http-response set-header x-test2 "%[var(txn.test2)]"
+
+ server s1 ${s1_addr}:${s1_port}
+
+} -start
+
+client c1 -connect ${h1_feh1_sock} {
+ txreq -req GET -url /
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-test2 == "def_back"
+} -run
diff --git a/reg-tests/webstats/missing-stats-fields.vtc b/reg-tests/webstats/missing-stats-fields.vtc
new file mode 100644
index 0000000..c85855d
--- /dev/null
+++ b/reg-tests/webstats/missing-stats-fields.vtc
@@ -0,0 +1,14 @@
+varnishtest "Verifies the absence of (null) in 'show stats' header"
+
+# This can happen if a new ST_F_xxx enum is added without updating
+# stats_fields[].
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+} -start
+
+haproxy h1 -cli {
+ send "show stat"
+ expect !~ (null)
+}
diff --git a/reg-tests/webstats/webstats-scope-and-post-change.vtc b/reg-tests/webstats/webstats-scope-and-post-change.vtc
new file mode 100644
index 0000000..e896c05
--- /dev/null
+++ b/reg-tests/webstats/webstats-scope-and-post-change.vtc
@@ -0,0 +1,84 @@
+varnishtest "Webgui stats page check filtering with scope and changing server state"
+
+feature ignore_unknown_macro
+
+server s1 {
+} -start
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+
+ frontend fe1
+ bind "fd@${fe1}"
+ stats enable
+ stats refresh 5s
+ stats uri /
+ stats admin if TRUE
+
+ backend b1
+ server srv1 ${s1_addr}:${s1_port}
+ server srv2 ${s1_addr}:${s1_port}
+ server srv3 ${s1_addr}:${s1_port}
+
+ backend b2
+ server srv1 ${s1_addr}:${s1_port}
+ server srv2 ${s1_addr}:${s1_port}
+
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -url "/;csv;"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c2 -connect ${h1_fe1_sock} {
+ txreq -url "/?;csv;scope=b1"
+ rxresp
+ expect resp.status == 200
+} -run
+
+haproxy h1 -cli {
+ send "show stat"
+ expect ~ .*
+}
+
+client c3 -connect ${h1_fe1_sock} {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+
+ txreq -url "/?;csv;scope=b1"
+ rxresp
+ expect resp.status == 200
+ expect resp.body ~ ".*\nb1,BACKEND.*"
+ expect resp.body !~ ".*\nb2,BACKEND.*"
+
+ txreq -req "POST" -url "/?scope=b2" -body "s=srv1&s=srv2&s=srv3&action=maint&b=%233"
+ rxresp
+ expect resp.status == 303
+
+ txreq -req "POST" -url "/" -body "s=srv2&action=drain&b=%233"
+ rxresp
+ expect resp.status == 303
+
+ txreq -req "POST" -url "/" -body "s=srv1&action=maint&b=%234"
+ rxresp
+ expect resp.status == 303
+
+ txreq -url "/?;csv;scope=fe1"
+ rxresp
+ expect resp.status == 200
+} -run
+
+haproxy h1 -cli {
+ send "show stat"
+ expect ~ "\nb1,srv1.*MAINT.*\nb1,srv2.*DRAIN.*\nb1,srv3.*MAINT.*\nb1,BACKEND.*DOWN.*\nb2,srv1.*MAINT.*\nb2,srv2.*no check.*\nb2,BACKEND.*UP"
+} -wait