Commit b0694ca8 authored by Geoff Simmons's avatar Geoff Simmons

Generated VCL symbol names never longer than 50 chars.

Workaround for Varnish issue #2880:
https://github.com/varnishcache/varnish-cache/issues/2880

Refactor the test sources a bit while we're here.
parent f55338b7
......@@ -3,11 +3,11 @@ import re2;
sub vcl_init {
{{- range $auth := .Auths}}
new {{vclMangle .Realm}}_auth = re2.set(anchor=both);
new {{credsMatcher .Realm}} = re2.set(anchor=both);
{{- range $cred := .Credentials}}
{{vclMangle $auth.Realm}}_auth.add("\s*Basic\s+\Q{{$cred}}\E\s*");
{{credsMatcher $auth.Realm}}.add("\s*Basic\s+\Q{{$cred}}\E\s*");
{{- end}}
{{vclMangle .Realm}}_auth.compile();
{{credsMatcher .Realm}}.compile();
{{end -}}
}
......@@ -21,9 +21,9 @@ sub vcl_recv {
req.url ~ "{{.Condition.URLRegex}}" &&
{{- end}}
{{- if eq .Status 401}}
!{{vclMangle .Realm}}_auth.match(req.http.Authorization)
!{{credsMatcher .Realm}}.match(req.http.Authorization)
{{- else}}
!{{vclMangle .Realm}}_auth.match(req.http.Proxy-Authorization)
!{{credsMatcher .Realm}}.match(req.http.Proxy-Authorization)
{{- end}}
) {
{{- if .UTF8 }}
......
/*
* Copyright (c) 2018 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package vcl
import (
"reflect"
"testing"
)
var cafeSpec2 = Spec{
DefaultService: Service{},
Rules: []Rule{{
Host: "cafe.example.com",
PathMap: map[string]Service{
"/tea": teaSvc,
"/coffee": coffeeSvc3,
},
}},
AllServices: map[string]Service{
"tea-svc": teaSvc,
"coffee-svc": coffeeSvc3,
},
}
func TestDeepHash(t *testing.T) {
if cafeSpec.DeepHash() == cafeSpec2.DeepHash() {
t.Errorf("DeepHash(): Distinct specs have equal hashes")
if testing.Verbose() {
t.Logf("spec1: %+v", cafeSpec)
t.Logf("spec2: %+v", cafeSpec2)
t.Logf("hash: %0x", cafeSpec.DeepHash())
}
}
}
var teaSvcShuf = Service{
Name: "tea-svc",
Addresses: []Address{
{
IP: "192.0.2.3",
Port: 80,
},
{
IP: "192.0.2.1",
Port: 80,
},
{
IP: "192.0.2.2",
Port: 80,
},
},
}
var coffeeSvcShuf = Service{
Name: "coffee-svc",
Addresses: []Address{
{
IP: "192.0.2.5",
Port: 80,
},
{
IP: "192.0.2.4",
Port: 80,
},
},
}
var cafeSpecShuf = Spec{
DefaultService: Service{},
Rules: []Rule{{
Host: "cafe.example.com",
PathMap: map[string]Service{
"/coffee": coffeeSvcShuf,
"/tea": teaSvcShuf,
},
}},
AllServices: map[string]Service{
"coffee-svc": coffeeSvcShuf,
"tea-svc": teaSvcShuf,
},
}
func TestCanoncial(t *testing.T) {
canonCafe := cafeSpec.Canonical()
canonShuf := cafeSpecShuf.Canonical()
if !reflect.DeepEqual(canonCafe, canonShuf) {
t.Error("Canonical(): Equivalent VCL specs not deeply equal")
if testing.Verbose() {
t.Log("Canonical cafe:", canonCafe)
t.Log("Canonical shuffled cafe:", canonShuf)
}
}
if canonCafe.DeepHash() != canonShuf.DeepHash() {
t.Error("Canonical(): Unequal hashes for equivalent specs")
if testing.Verbose() {
t.Logf("spec1 canonical: %+v", canonCafe)
t.Logf("spec1 hash: %0x", canonCafe.DeepHash())
t.Logf("spec2 canonical: %+v", canonShuf)
t.Logf("spec2 hash: %0x", canonShuf.DeepHash())
}
}
}
var names = []string{
"vk8s_cafe_example_com_url",
"vk8s_very_long_name_that_breaks_the_symbol_length_upper_bound",
}
func TestBound(t *testing.T) {
for _, n := range names {
if len(bound(n, maxSymLen)) > maxSymLen {
t.Errorf("bound(\"%s\", %d) not shortened as "+
"expected: len(\"%s\")=%d", n, maxSymLen,
bound(n, maxSymLen), len(bound(n, maxSymLen)))
}
if len(n) <= maxSymLen && n != bound(n, maxSymLen) {
t.Errorf("bound(\"%s\", %d) exp=\"%s\" got=\"%s\"",
n, maxSymLen, n, bound(n, maxSymLen))
}
}
}
......@@ -31,6 +31,8 @@ package vcl
import (
"bytes"
"fmt"
"hash/fnv"
"math/big"
"path"
"regexp"
"strings"
......@@ -55,7 +57,13 @@ var fMap = template.FuncMap{
return urlMatcher(rule)
},
"aclName": func(name string) string {
return mangle(name) + "_acl"
return mangle(name + "_acl")
},
"probeName": func(name string) string {
return mangle(name + "_probe")
},
"credsMatcher": func(realm string) string {
return mangle(realm + "_auth")
},
}
......@@ -64,6 +72,11 @@ const (
shardTmplSrc = "self-shard.tmpl"
authTmplSrc = "auth.tmpl"
aclTmplSrc = "acl.tmpl"
// maxSymLen is a workaround for Varnish issue #2880
// https://github.com/varnishcache/varnish-cache/issues/2880
// Will be unnecssary as of the March 2019 release
maxSymLen = 50
)
var (
......@@ -141,6 +154,19 @@ func (spec Spec) GetSrc() (string, error) {
return buf.String(), nil
}
func bound(s string, l int) string {
if len(s) <= l {
return s
}
b := []byte(s)
h := fnv.New32a()
h.Write(b)
i := big.NewInt(int64(h.Sum32()))
b[l-7] = byte('_')
copy(b[l-6:l], []byte(i.Text(62)))
return string(b[0:l])
}
func mangle(s string) string {
if s == "" {
return s
......@@ -148,7 +174,7 @@ func mangle(s string) string {
prefixed := "vk8s_" + s
bytes := []byte(prefixed)
mangled := vclIllegal.ReplaceAllFunc(bytes, replIllegal)
return string(mangled)
return bound(string(mangled), maxSymLen)
}
func backendName(svc Service, addr string) string {
......
......@@ -13,7 +13,7 @@ backend vk8s_notfound {
{{- range $name, $svc := .AllServices}}
{{- if $svc.Probe}}
{{with $svc.Probe}}
probe {{vclMangle $name}}_probe {
probe {{probeName $name}} {
{{- if ne .URL ""}}
.url = "{{.URL}}";
{{- else if .Request}}
......@@ -71,7 +71,7 @@ backend {{backendName $svc $addr.IP}} {
.max_connections = {{.MaxConnections}};
{{- end}}
{{- if .Probe}}
.probe = {{vclMangle $name}}_probe;
.probe = {{probeName $name}};
{{- end}}
{{- end}}
}
......
......@@ -34,7 +34,6 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
"text/template"
)
......@@ -146,100 +145,6 @@ var coffeeSvc3 = Service{
},
}
var cafeSpec2 = Spec{
DefaultService: Service{},
Rules: []Rule{{
Host: "cafe.example.com",
PathMap: map[string]Service{
"/tea": teaSvc,
"/coffee": coffeeSvc3,
},
}},
AllServices: map[string]Service{
"tea-svc": teaSvc,
"coffee-svc": coffeeSvc3,
},
}
func TestDeepHash(t *testing.T) {
if cafeSpec.DeepHash() == cafeSpec2.DeepHash() {
t.Errorf("DeepHash(): Distinct specs have equal hashes")
if testing.Verbose() {
t.Logf("spec1: %+v", cafeSpec)
t.Logf("spec2: %+v", cafeSpec2)
t.Logf("hash: %0x", cafeSpec.DeepHash())
}
}
}
var teaSvcShuf = Service{
Name: "tea-svc",
Addresses: []Address{
{
IP: "192.0.2.3",
Port: 80,
},
{
IP: "192.0.2.1",
Port: 80,
},
{
IP: "192.0.2.2",
Port: 80,
},
},
}
var coffeeSvcShuf = Service{
Name: "coffee-svc",
Addresses: []Address{
{
IP: "192.0.2.5",
Port: 80,
},
{
IP: "192.0.2.4",
Port: 80,
},
},
}
var cafeSpecShuf = Spec{
DefaultService: Service{},
Rules: []Rule{{
Host: "cafe.example.com",
PathMap: map[string]Service{
"/coffee": coffeeSvcShuf,
"/tea": teaSvcShuf,
},
}},
AllServices: map[string]Service{
"coffee-svc": coffeeSvcShuf,
"tea-svc": teaSvcShuf,
},
}
func TestCanoncial(t *testing.T) {
canonCafe := cafeSpec.Canonical()
canonShuf := cafeSpecShuf.Canonical()
if !reflect.DeepEqual(canonCafe, canonShuf) {
t.Error("Canonical(): Equivalent VCL specs not deeply equal")
if testing.Verbose() {
t.Log("Canonical cafe:", canonCafe)
t.Log("Canonical shuffled cafe:", canonShuf)
}
}
if canonCafe.DeepHash() != canonShuf.DeepHash() {
t.Error("Canonical(): Unequal hashes for equivalent specs")
if testing.Verbose() {
t.Logf("spec1 canonical: %+v", canonCafe)
t.Logf("spec1 hash: %0x", canonCafe.DeepHash())
t.Logf("spec2 canonical: %+v", canonShuf)
t.Logf("spec2 hash: %0x", canonShuf.DeepHash())
}
}
}
var varnishCluster = ShardCluster{
Nodes: []Service{
Service{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment