vtest "Test vcl defined via backends"

server s1 {
	loop 5 {
		rxreq
		txresp -hdr "Server: s1"
	}
} -start

server s2 {
	rxreq
	txresp -hdr "Server: s2"
} -start

# the use case for via-proxy is to have a(n ha)proxy make a (TLS)
# connection on our behalf. For the purpose of testing, we use another
# vinyl in place - but we are behaving realistically in that we do
# not use any prior information for the actual backend connection -
# just the information from the proxy protocol

vinyl v2 -proto PROXY -vcl+backend {
	import std;
	import proxy;

	sub vcl_recv {
		if (server.ip == "${s1_addr}" &&
		    std.port(server.ip) == ${s1_port}) {
			set req.backend_hint = s1;
		} else
		if (server.ip == "${s2_addr}" &&
		    std.port(server.ip) == ${s2_port}) {
			set req.backend_hint = s2;
		}
		else {
		    return (synth(404, "unknown backend"));
		}
		std.log("PROXY " + req.url + " -> " + req.backend_hint);
		return (pass);
	}

	sub vcl_deliver {
		set resp.http.Authority = proxy.authority();
	}
} -start

vinyl v2 -cliok "param.set debug +syncvsl"

vinyl v1 -vcl {
	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }
	backend s1 { .via = v2; .authority = "1.2.3.4.example.com"; .host = "${s1_addr}"; .port = "${s1_port}"; }
	backend s2 { .via = v2; .authority = "s2"; .host = "${s2_addr}"; .port = "${s2_port}"; }

	sub vcl_recv {
		if (req.url ~ "^/s1/") {
			set req.backend_hint = s1;
		} else if (req.url ~ "^/s2/") {
			set req.backend_hint = s2;
		} else {
			return (synth(400));
		}
	}
} -start

client c1 {
	txreq -url /s1/1
	rxresp
	expect resp.status == 200
	expect resp.http.Authority == "1.2.3.4.example.com"
	expect resp.http.Server == "s1"

	txreq -url /s2/1
	rxresp
	expect resp.status == 200
	expect resp.http.Authority == "s2"
	expect resp.http.Server == "s2"

	txreq -url /s1/2
	rxresp
	expect resp.status == 200
	expect resp.http.Authority == "1.2.3.4.example.com"
	expect resp.http.Server == "s1"
} -run

vinyl v1 -vcl {
	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }

	backend s1 {
		.via = v2;
		.host = "${s1_addr}";
		.port = "${s1_port}";
		.authority = "authority.com";
	}

	sub vcl_recv {
		set req.backend_hint = s1;
	}
}

client c1 {
	txreq -url /s1/3
	rxresp
	expect resp.status == 200
	expect resp.http.Authority == "authority.com"
} -run

vinyl v1 -vcl {
	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }

	backend s1 {
		.via = v2;
		.host = "${s1_addr}";
		.port = "${s1_port}";
		.host_header = "host.com:1234";
	}

	sub vcl_recv {
		set req.backend_hint = s1;
	}
}

client c1 {
	txreq -url /s1/4
	rxresp
	expect resp.status == 200
	expect resp.http.Authority == "host.com"
} -run

# Setting .authority = "" disables sending the TLV.
vinyl v1 -vcl {
	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }

	backend s1 {
		.via = v2;
		.host = "${s1_addr}";
		.port = "${s1_port}";
		.authority = "";
	}

	sub vcl_recv {
		set req.backend_hint = s1;
	}
}

client c1 {
	txreq -url /s1/5
	rxresp
	expect resp.status == 200

	# vmod_proxy returns the empty string if the TLV is absent.
	expect resp.http.Authority == ""
} -run

vinyl v1 -errvcl ".host used as authority can not be an ip address with .via" {
	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }

	backend s1 {
		.via = v2;
		.host = "${s1_addr}";
		.port = "${s1_port}";
	}
}

vinyl v1 -errvcl ".host_header used as authority can not be an ip address with .via" {
	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }

	backend s1 {
		.via = v2;
		.host = "${s1_addr}";
		.host_header = "${s1_addr}";
		.port = "${s1_port}";
	}
}

vinyl v1 -errvcl "Cannot set both .via and .path" {
	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }

	backend s1 {
		.via = v2;
		.path = "/path/to/uds";
	}
}

vinyl v1 -errvcl "Cannot stack .via backends" {
	backend a { .host = "${v2_addr}"; .port = "${v2_port}"; }

	backend b {
		.via = a;
		.host_header = "b";
		.host = "127.0.0.1";
	}

	backend c {
		.via = b;
		.authority = "c";
		.host = "127.0.0.2";
	}

	sub vcl_backend_fetch {
		set bereq.backend = c;
	}
}

# issue #4177: backend named default with .via property
vinyl v1 -vcl {
	backend via { .host = "${localhost}"; }
	backend default { .via = via; .authority = "localhost"; .host = "${localhost}"; }
}
