Merge tag 'v1.4.4' into master

This commit is contained in:
Fernandez Ludovic 2017-11-23 15:21:47 +01:00
commit 66591cf216
14 changed files with 113 additions and 30 deletions

View file

@ -36,6 +36,7 @@ deploy:
on: on:
repo: containous/traefik repo: containous/traefik
tags: true tags: true
condition: ${TRAVIS_TAG} =~ ^v[0-9]+\.[0-9]+\.[0-9]+$
- provider: releases - provider: releases
api_key: ${GITHUB_TOKEN} api_key: ${GITHUB_TOKEN}
file: dist/traefik* file: dist/traefik*

View file

@ -1,5 +1,20 @@
# Change Log # Change Log
## [v1.4.4](https://github.com/containous/traefik/tree/v1.4.4) (2017-11-21)
[All Commits](https://github.com/containous/traefik/compare/v1.4.3...v1.4.4)
**Enhancements:**
- **[middleware]** Remove GzipHandler Fork ([#2436](https://github.com/containous/traefik/pull/2436) by [ldez](https://github.com/ldez))
**Bug fixes:**
- **[docker]** Fix problems about duplicated and missing Docker backends/frontends. ([#2434](https://github.com/containous/traefik/pull/2434) by [nmengin](https://github.com/nmengin))
- **[middleware]** Fix raw path handling in strip prefix ([#2382](https://github.com/containous/traefik/pull/2382) by [marco-jantke](https://github.com/marco-jantke))
- **[rancher]** Fix issue with label traefik.backend.loadbalancer.stickiness.cookieName ([#2423](https://github.com/containous/traefik/pull/2423) by [rawmind0](https://github.com/rawmind0))
- http.Server log goes to Debug level. ([#2420](https://github.com/containous/traefik/pull/2420) by [ldez](https://github.com/ldez))
**Documentation:**
- Documentation archive ([#2405](https://github.com/containous/traefik/pull/2405) by [ldez](https://github.com/ldez))
## [v1.4.3](https://github.com/containous/traefik/tree/v1.4.3) (2017-11-14) ## [v1.4.3](https://github.com/containous/traefik/tree/v1.4.3) (2017-11-14)
[All Commits](https://github.com/containous/traefik/compare/v1.4.2...v1.4.3) [All Commits](https://github.com/containous/traefik/compare/v1.4.2...v1.4.3)

17
docs/archive.md Normal file
View file

@ -0,0 +1,17 @@
## Previous documentation
- [Latest stable](https://docs.traefik.io)
- [Experimental](https://master--traefik-docs.netlify.com/)
- [v1.4 aka Roquefort](http://v1-4.archive.docs.traefik.io/)
- [v1.3 aka Raclette](http://v1-3.archive.docs.traefik.io/)
- [v1.2 aka Morbier](http://v1-2.archive.docs.traefik.io/)
- [v1.1 aka Camembert](http://v1-1.archive.docs.traefik.io/)
## More
[Change log](https://github.com/containous/traefik/blob/master/CHANGELOG.md)

6
glide.lock generated
View file

@ -1,4 +1,4 @@
hash: fec4fec4363272870c49e10cea64cc51095ecd0987b9c020c9714d950cf38784 hash: 6deb9adeca5f1724f9ef2b31b122f85a00cf47cf4308527d6d3ff68a6ac0e705
updated: 2017-11-17T14:21:55.148450413+01:00 updated: 2017-11-17T14:21:55.148450413+01:00
imports: imports:
- name: cloud.google.com/go - name: cloud.google.com/go
@ -420,9 +420,7 @@ imports:
repo: https://github.com/ijc25/Gotty.git repo: https://github.com/ijc25/Gotty.git
vcs: git vcs: git
- name: github.com/NYTimes/gziphandler - name: github.com/NYTimes/gziphandler
version: 26a3f68265200656f31940bc15b191f7d10b5bbd version: d6f46609c7629af3a02d791a4666866eed3cbd3e
repo: https://github.com/containous/gziphandler.git
vcs: git
- name: github.com/ogier/pflag - name: github.com/ogier/pflag
version: 45c278ab3607870051a2ea9040bb85fcb8557481 version: 45c278ab3607870051a2ea9040bb85fcb8557481
- name: github.com/opencontainers/go-digest - name: github.com/opencontainers/go-digest

View file

@ -84,9 +84,6 @@ import:
vcs: git vcs: git
- package: github.com/abbot/go-http-auth - package: github.com/abbot/go-http-auth
- package: github.com/NYTimes/gziphandler - package: github.com/NYTimes/gziphandler
version: fork-containous
repo: https://github.com/containous/gziphandler.git
vcs: git
- package: github.com/docker/leadership - package: github.com/docker/leadership
repo: https://github.com/containous/leadership.git repo: https://github.com/containous/leadership.git
vcs: git vcs: git

View file

@ -16,8 +16,11 @@ type StripPrefix struct {
func (s *StripPrefix) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s *StripPrefix) ServeHTTP(w http.ResponseWriter, r *http.Request) {
for _, prefix := range s.Prefixes { for _, prefix := range s.Prefixes {
if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) { if strings.HasPrefix(r.URL.Path, prefix) {
r.URL.Path = "/" + strings.TrimPrefix(p, "/") r.URL.Path = stripPrefix(r.URL.Path, prefix)
if r.URL.RawPath != "" {
r.URL.RawPath = stripPrefix(r.URL.RawPath, prefix)
}
s.serveRequest(w, r, strings.TrimSpace(prefix)) s.serveRequest(w, r, strings.TrimSpace(prefix))
return return
} }
@ -35,3 +38,11 @@ func (s *StripPrefix) serveRequest(w http.ResponseWriter, r *http.Request, prefi
func (s *StripPrefix) SetHandler(Handler http.Handler) { func (s *StripPrefix) SetHandler(Handler http.Handler) {
s.Handler = Handler s.Handler = Handler
} }
func stripPrefix(s, prefix string) string {
return ensureLeadingSlash(strings.TrimPrefix(s, prefix))
}
func ensureLeadingSlash(str string) string {
return "/" + strings.TrimPrefix(str, "/")
}

View file

@ -40,6 +40,9 @@ func (s *StripPrefixRegex) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
r.URL.Path = r.URL.Path[len(prefix.Path):] r.URL.Path = r.URL.Path[len(prefix.Path):]
if r.URL.RawPath != "" {
r.URL.RawPath = r.URL.RawPath[len(prefix.Path):]
}
r.Header.Add(ForwardedPrefixHeader, prefix.Path) r.Header.Add(ForwardedPrefixHeader, prefix.Path)
r.RequestURI = r.URL.RequestURI() r.RequestURI = r.URL.RequestURI()
s.Handler.ServeHTTP(w, r) s.Handler.ServeHTTP(w, r)

View file

@ -10,13 +10,13 @@ import (
) )
func TestStripPrefixRegex(t *testing.T) { func TestStripPrefixRegex(t *testing.T) {
testPrefixRegex := []string{"/a/api/", "/b/{regex}/", "/c/{category}/{id:[0-9]+}/"} testPrefixRegex := []string{"/a/api/", "/b/{regex}/", "/c/{category}/{id:[0-9]+}/"}
tests := []struct { tests := []struct {
path string path string
expectedStatusCode int expectedStatusCode int
expectedPath string expectedPath string
expectedRawPath string
expectedHeader string expectedHeader string
}{ }{
{ {
@ -61,6 +61,13 @@ func TestStripPrefixRegex(t *testing.T) {
path: "/c/api/abc/test4", path: "/c/api/abc/test4",
expectedStatusCode: http.StatusNotFound, expectedStatusCode: http.StatusNotFound,
}, },
{
path: "/a/api/a%2Fb",
expectedStatusCode: http.StatusOK,
expectedPath: "a/b",
expectedRawPath: "a%2Fb",
expectedHeader: "/a/api/",
},
} }
for _, test := range tests { for _, test := range tests {
@ -68,9 +75,10 @@ func TestStripPrefixRegex(t *testing.T) {
t.Run(test.path, func(t *testing.T) { t.Run(test.path, func(t *testing.T) {
t.Parallel() t.Parallel()
var actualPath, actualHeader string var actualPath, actualRawPath, actualHeader string
handlerPath := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handlerPath := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
actualPath = r.URL.Path actualPath = r.URL.Path
actualRawPath = r.URL.RawPath
actualHeader = r.Header.Get(ForwardedPrefixHeader) actualHeader = r.Header.Get(ForwardedPrefixHeader)
}) })
handler := NewStripPrefixRegex(handlerPath, testPrefixRegex) handler := NewStripPrefixRegex(handlerPath, testPrefixRegex)
@ -82,6 +90,7 @@ func TestStripPrefixRegex(t *testing.T) {
assert.Equal(t, test.expectedStatusCode, resp.Code, "Unexpected status code.") assert.Equal(t, test.expectedStatusCode, resp.Code, "Unexpected status code.")
assert.Equal(t, test.expectedPath, actualPath, "Unexpected path.") assert.Equal(t, test.expectedPath, actualPath, "Unexpected path.")
assert.Equal(t, test.expectedRawPath, actualRawPath, "Unexpected raw path.")
assert.Equal(t, test.expectedHeader, actualHeader, "Unexpected '%s' header.", ForwardedPrefixHeader) assert.Equal(t, test.expectedHeader, actualHeader, "Unexpected '%s' header.", ForwardedPrefixHeader)
}) })
} }

View file

@ -16,6 +16,7 @@ func TestStripPrefix(t *testing.T) {
path string path string
expectedStatusCode int expectedStatusCode int
expectedPath string expectedPath string
expectedRawPath string
expectedHeader string expectedHeader string
}{ }{
{ {
@ -94,6 +95,15 @@ func TestStripPrefix(t *testing.T) {
expectedPath: "/us", expectedPath: "/us",
expectedHeader: "/stat", expectedHeader: "/stat",
}, },
{
desc: "raw path is also stripped",
prefixes: []string{"/stat"},
path: "/stat/a%2Fb",
expectedStatusCode: http.StatusOK,
expectedPath: "/a/b",
expectedRawPath: "/a%2Fb",
expectedHeader: "/stat",
},
} }
for _, test := range tests { for _, test := range tests {
@ -101,11 +111,12 @@ func TestStripPrefix(t *testing.T) {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()
var actualPath, actualHeader, requestURI string var actualPath, actualRawPath, actualHeader, requestURI string
handler := &StripPrefix{ handler := &StripPrefix{
Prefixes: test.prefixes, Prefixes: test.prefixes,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
actualPath = r.URL.Path actualPath = r.URL.Path
actualRawPath = r.URL.RawPath
actualHeader = r.Header.Get(ForwardedPrefixHeader) actualHeader = r.Header.Get(ForwardedPrefixHeader)
requestURI = r.RequestURI requestURI = r.RequestURI
}), }),
@ -118,8 +129,15 @@ func TestStripPrefix(t *testing.T) {
assert.Equal(t, test.expectedStatusCode, resp.Code, "Unexpected status code.") assert.Equal(t, test.expectedStatusCode, resp.Code, "Unexpected status code.")
assert.Equal(t, test.expectedPath, actualPath, "Unexpected path.") assert.Equal(t, test.expectedPath, actualPath, "Unexpected path.")
assert.Equal(t, test.expectedRawPath, actualRawPath, "Unexpected raw path.")
assert.Equal(t, test.expectedHeader, actualHeader, "Unexpected '%s' header.", ForwardedPrefixHeader) assert.Equal(t, test.expectedHeader, actualHeader, "Unexpected '%s' header.", ForwardedPrefixHeader)
assert.Equal(t, test.expectedPath, requestURI, "Unexpected request URI.")
expectedURI := test.expectedPath
if test.expectedRawPath != "" {
// go HTTP uses the raw path when existent in the RequestURI
expectedURI = test.expectedRawPath
}
assert.Equal(t, expectedURI, requestURI, "Unexpected request URI.")
}) })
} }
} }

View file

@ -100,3 +100,4 @@ pages:
- 'Clustering/HA': 'user-guide/cluster.md' - 'Clustering/HA': 'user-guide/cluster.md'
- 'gRPC Example': 'user-guide/grpc.md' - 'gRPC Example': 'user-guide/grpc.md'
- Benchmarks: benchmarks.md - Benchmarks: benchmarks.md
- 'Archive': 'archive.md'

View file

@ -345,9 +345,15 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con
frontends := map[string][]dockerData{} frontends := map[string][]dockerData{}
backends := map[string]dockerData{} backends := map[string]dockerData{}
servers := map[string][]dockerData{} servers := map[string][]dockerData{}
serviceNames := make(map[string]struct{})
for idx, container := range filteredContainers { for idx, container := range filteredContainers {
if _, exists := serviceNames[container.ServiceName]; !exists {
frontendName := p.getFrontendName(container, idx) frontendName := p.getFrontendName(container, idx)
frontends[frontendName] = append(frontends[frontendName], container) frontends[frontendName] = append(frontends[frontendName], container)
if len(container.ServiceName) > 0 {
serviceNames[container.ServiceName] = struct{}{}
}
}
backendName := p.getBackend(container) backendName := p.getBackend(container)
backends[backendName] = container backends[backendName] = container
servers[backendName] = append(servers[backendName], container) servers[backendName] = append(servers[backendName], container)
@ -471,9 +477,9 @@ func (p *Provider) getServicePriority(container dockerData, serviceName string)
// Extract backend from labels for a given service and a given docker container // Extract backend from labels for a given service and a given docker container
func (p *Provider) getServiceBackend(container dockerData, serviceName string) string { func (p *Provider) getServiceBackend(container dockerData, serviceName string) string {
if value, ok := getContainerServiceLabel(container, serviceName, "frontend.backend"); ok { if value, ok := getContainerServiceLabel(container, serviceName, "frontend.backend"); ok {
return value return container.ServiceName + "-" + value
} }
return p.getBackend(container) + "-" + provider.Normalize(serviceName) return strings.TrimPrefix(container.ServiceName, "/") + "-" + p.getBackend(container) + "-" + provider.Normalize(serviceName)
} }
// Extract rule from labels for a given service and a given docker container // Extract rule from labels for a given service and a given docker container

View file

@ -171,19 +171,19 @@ func TestDockerGetServiceBackend(t *testing.T) {
}{ }{
{ {
container: containerJSON(name("foo")), container: containerJSON(name("foo")),
expected: "foo-myservice", expected: "foo-foo-myservice",
}, },
{ {
container: containerJSON(labels(map[string]string{ container: containerJSON(labels(map[string]string{
types.LabelBackend: "another-backend", types.LabelBackend: "another-backend",
})), })),
expected: "another-backend-myservice", expected: "fake-another-backend-myservice",
}, },
{ {
container: containerJSON(labels(map[string]string{ container: containerJSON(labels(map[string]string{
"traefik.myservice.frontend.backend": "custom-backend", "traefik.myservice.frontend.backend": "custom-backend",
})), })),
expected: "custom-backend", expected: "fake-custom-backend",
}, },
} }
@ -342,8 +342,8 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
), ),
}, },
expectedFrontends: map[string]*types.Frontend{ expectedFrontends: map[string]*types.Frontend{
"frontend-foo-service": { "frontend-foo-foo-service": {
Backend: "backend-foo-service", Backend: "backend-foo-foo-service",
PassHostHeader: true, PassHostHeader: true,
EntryPoints: []string{"http", "https"}, EntryPoints: []string{"http", "https"},
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"}, BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
@ -356,7 +356,7 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
}, },
}, },
expectedBackends: map[string]*types.Backend{ expectedBackends: map[string]*types.Backend{
"backend-foo-service": { "backend-foo-foo-service": {
Servers: map[string]types.Server{ Servers: map[string]types.Server{
"service-0": { "service-0": {
URL: "http://127.0.0.1:2503", URL: "http://127.0.0.1:2503",
@ -402,8 +402,8 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
), ),
}, },
expectedFrontends: map[string]*types.Frontend{ expectedFrontends: map[string]*types.Frontend{
"frontend-foobar": { "frontend-test1-foobar": {
Backend: "backend-foobar", Backend: "backend-test1-foobar",
PassHostHeader: false, PassHostHeader: false,
Priority: 5000, Priority: 5000,
EntryPoints: []string{"http", "https", "ws"}, EntryPoints: []string{"http", "https", "ws"},
@ -415,8 +415,8 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
}, },
}, },
}, },
"frontend-test2-anotherservice": { "frontend-test2-test2-anotherservice": {
Backend: "backend-test2-anotherservice", Backend: "backend-test2-test2-anotherservice",
PassHostHeader: true, PassHostHeader: true,
EntryPoints: []string{}, EntryPoints: []string{},
BasicAuth: []string{}, BasicAuth: []string{},
@ -429,7 +429,7 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
}, },
}, },
expectedBackends: map[string]*types.Backend{ expectedBackends: map[string]*types.Backend{
"backend-foobar": { "backend-test1-foobar": {
Servers: map[string]types.Server{ Servers: map[string]types.Server{
"service-0": { "service-0": {
URL: "https://127.0.0.1:2503", URL: "https://127.0.0.1:2503",
@ -438,7 +438,7 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
}, },
CircuitBreaker: nil, CircuitBreaker: nil,
}, },
"backend-test2-anotherservice": { "backend-test2-test2-anotherservice": {
Servers: map[string]types.Server{ Servers: map[string]types.Server{
"service-0": { "service-0": {
URL: "http://127.0.0.1:8079", URL: "http://127.0.0.1:8079",

View file

@ -133,7 +133,7 @@ func (p *Provider) hasStickinessLabel(service rancherData) bool {
return errStickiness == nil && len(labelStickiness) > 0 && strings.EqualFold(strings.TrimSpace(labelStickiness), "true") return errStickiness == nil && len(labelStickiness) > 0 && strings.EqualFold(strings.TrimSpace(labelStickiness), "true")
} }
func (p *Provider) getStickinessCookieName(service rancherData, backendName string) string { func (p *Provider) getStickinessCookieName(service rancherData) string {
if label, err := getServiceLabel(service, types.LabelBackendLoadbalancerStickinessCookieName); err == nil { if label, err := getServiceLabel(service, types.LabelBackendLoadbalancerStickinessCookieName); err == nil {
return label return label
} }

View file

@ -8,6 +8,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
stdlog "log"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
@ -20,6 +21,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/Sirupsen/logrus"
"github.com/armon/go-proxyproto" "github.com/armon/go-proxyproto"
"github.com/containous/mux" "github.com/containous/mux"
"github.com/containous/traefik/cluster" "github.com/containous/traefik/cluster"
@ -47,6 +49,10 @@ import (
"golang.org/x/net/http2" "golang.org/x/net/http2"
) )
var (
httpServerLogger = stdlog.New(log.WriterLevel(logrus.DebugLevel), "", 0)
)
// Server is the reverse-proxy/load-balancer engine // Server is the reverse-proxy/load-balancer engine
type Server struct { type Server struct {
serverEntryPoints serverEntryPoints serverEntryPoints serverEntryPoints
@ -794,6 +800,7 @@ func (server *Server) prepareServer(entryPointName string, entryPoint *configura
ReadTimeout: readTimeout, ReadTimeout: readTimeout,
WriteTimeout: writeTimeout, WriteTimeout: writeTimeout,
IdleTimeout: idleTimeout, IdleTimeout: idleTimeout,
ErrorLog: httpServerLogger,
}, },
listener, listener,
nil nil