fix: URL encode resource's id before calling API endpoints
This commit is contained in:
parent
03d2e35488
commit
49f04f2772
23 changed files with 408 additions and 29 deletions
|
@ -76,7 +76,7 @@ func New(staticConfig static.Configuration, runtimeConfig *runtime.Configuration
|
||||||
|
|
||||||
// createRouter creates API routes and router.
|
// createRouter creates API routes and router.
|
||||||
func (h Handler) createRouter() *mux.Router {
|
func (h Handler) createRouter() *mux.Router {
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter().UseEncodedPath()
|
||||||
|
|
||||||
if h.staticConfig.API.Debug {
|
if h.staticConfig.API.Debug {
|
||||||
DebugHandler{}.Append(router)
|
DebugHandler{}.Append(router)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
@ -49,7 +50,13 @@ func (h Handler) getEntryPoints(rw http.ResponseWriter, request *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getEntryPoint(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getEntryPoint(rw http.ResponseWriter, request *http.Request) {
|
||||||
entryPointID := mux.Vars(request)["entryPointID"]
|
scapedEntryPointID := mux.Vars(request)["entryPointID"]
|
||||||
|
|
||||||
|
entryPointID, err := url.PathUnescape(scapedEntryPointID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(rw, fmt.Sprintf("unable to decode entryPointID %q: %s", scapedEntryPointID, err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
@ -64,7 +71,7 @@ func (h Handler) getEntryPoint(rw http.ResponseWriter, request *http.Request) {
|
||||||
Name: entryPointID,
|
Name: entryPointID,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err = json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -169,6 +170,21 @@ func TestHandler_EntryPoints(t *testing.T) {
|
||||||
jsonFile: "testdata/entrypoint-bar.json",
|
jsonFile: "testdata/entrypoint-bar.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "one entry point by id containing slash",
|
||||||
|
path: "/api/entrypoints/" + url.PathEscape("foo / bar"),
|
||||||
|
conf: static.Configuration{
|
||||||
|
Global: &static.Global{},
|
||||||
|
API: &static.API{},
|
||||||
|
EntryPoints: map[string]*static.EntryPoint{
|
||||||
|
"foo / bar": {Address: ":81"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
jsonFile: "testdata/entrypoint-foo-slash-bar.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one entry point by id, that does not exist",
|
desc: "one entry point by id, that does not exist",
|
||||||
path: "/api/entrypoints/foo",
|
path: "/api/entrypoints/foo",
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -99,7 +100,13 @@ func (h Handler) getRouters(rw http.ResponseWriter, request *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getRouter(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getRouter(rw http.ResponseWriter, request *http.Request) {
|
||||||
routerID := mux.Vars(request)["routerID"]
|
scapedRouterID := mux.Vars(request)["routerID"]
|
||||||
|
|
||||||
|
routerID, err := url.PathUnescape(scapedRouterID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(rw, fmt.Sprintf("unable to decode routerID %q: %s", scapedRouterID, err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
@ -111,7 +118,7 @@ func (h Handler) getRouter(rw http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
result := newRouterRepresentation(routerID, router)
|
result := newRouterRepresentation(routerID, router)
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err = json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -151,7 +158,13 @@ func (h Handler) getServices(rw http.ResponseWriter, request *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getService(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getService(rw http.ResponseWriter, request *http.Request) {
|
||||||
serviceID := mux.Vars(request)["serviceID"]
|
scapedServiceID := mux.Vars(request)["serviceID"]
|
||||||
|
|
||||||
|
serviceID, err := url.PathUnescape(scapedServiceID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(rw, fmt.Sprintf("unable to decode serviceID %q: %s", scapedServiceID, err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rw.Header().Add("Content-Type", "application/json")
|
rw.Header().Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
@ -163,7 +176,7 @@ func (h Handler) getService(rw http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
result := newServiceRepresentation(serviceID, service)
|
result := newServiceRepresentation(serviceID, service)
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err = json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -203,7 +216,13 @@ func (h Handler) getMiddlewares(rw http.ResponseWriter, request *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getMiddleware(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getMiddleware(rw http.ResponseWriter, request *http.Request) {
|
||||||
middlewareID := mux.Vars(request)["middlewareID"]
|
scapedMiddlewareID := mux.Vars(request)["middlewareID"]
|
||||||
|
|
||||||
|
middlewareID, err := url.PathUnescape(scapedMiddlewareID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(rw, fmt.Sprintf("unable to decode middlewareID %q: %s", scapedMiddlewareID, err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
@ -215,7 +234,7 @@ func (h Handler) getMiddleware(rw http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
result := newMiddlewareRepresentation(middlewareID, middleware)
|
result := newMiddlewareRepresentation(middlewareID, middleware)
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err = json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -223,6 +224,27 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
jsonFile: "testdata/router-bar.json",
|
jsonFile: "testdata/router-bar.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "one router by id containing slash",
|
||||||
|
path: "/api/http/routers/" + url.PathEscape("foo / bar@myprovider"),
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
Routers: map[string]*runtime.RouterInfo{
|
||||||
|
"foo / bar@myprovider": {
|
||||||
|
Router: &dynamic.Router{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
Middlewares: []string{"auth", "addPrefixTest@anotherprovider"},
|
||||||
|
},
|
||||||
|
Status: "enabled",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
jsonFile: "testdata/router-foo-slash-bar.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one router by id, implicitly using default TLS options",
|
desc: "one router by id, implicitly using default TLS options",
|
||||||
path: "/api/http/routers/baz@myprovider",
|
path: "/api/http/routers/baz@myprovider",
|
||||||
|
@ -583,6 +605,35 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
jsonFile: "testdata/service-bar.json",
|
jsonFile: "testdata/service-bar.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "one service by id containing slash",
|
||||||
|
path: "/api/http/services/" + url.PathEscape("foo / bar@myprovider"),
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
|
"foo / bar@myprovider": func() *runtime.ServiceInfo {
|
||||||
|
si := &runtime.ServiceInfo{
|
||||||
|
Service: &dynamic.Service{
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
PassHostHeader: Bool(true),
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://127.0.0.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||||
|
}
|
||||||
|
si.UpdateServerStatus("http://127.0.0.1", "UP")
|
||||||
|
return si
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
jsonFile: "testdata/service-foo-slash-bar.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one service by id, that does not exist",
|
desc: "one service by id, that does not exist",
|
||||||
path: "/api/http/services/nono@myprovider",
|
path: "/api/http/services/nono@myprovider",
|
||||||
|
@ -819,6 +870,26 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
jsonFile: "testdata/middleware-auth.json",
|
jsonFile: "testdata/middleware-auth.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "one middleware by id containing slash",
|
||||||
|
path: "/api/http/middlewares/" + url.PathEscape("foo / bar@myprovider"),
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
Middlewares: map[string]*runtime.MiddlewareInfo{
|
||||||
|
"foo / bar@myprovider": {
|
||||||
|
Middleware: &dynamic.Middleware{
|
||||||
|
AddPrefix: &dynamic.AddPrefix{
|
||||||
|
Prefix: "/titi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"test@myprovider"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
jsonFile: "testdata/middleware-foo-slash-bar.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one middleware by id, that does not exist",
|
desc: "one middleware by id, that does not exist",
|
||||||
path: "/api/http/middlewares/foo@myprovider",
|
path: "/api/http/middlewares/foo@myprovider",
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -92,7 +93,13 @@ func (h Handler) getTCPRouters(rw http.ResponseWriter, request *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getTCPRouter(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getTCPRouter(rw http.ResponseWriter, request *http.Request) {
|
||||||
routerID := mux.Vars(request)["routerID"]
|
scapedRouterID := mux.Vars(request)["routerID"]
|
||||||
|
|
||||||
|
routerID, err := url.PathUnescape(scapedRouterID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(rw, fmt.Sprintf("unable to decode routerID %q: %s", scapedRouterID, err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
@ -104,7 +111,7 @@ func (h Handler) getTCPRouter(rw http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
result := newTCPRouterRepresentation(routerID, router)
|
result := newTCPRouterRepresentation(routerID, router)
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err = json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -144,7 +151,13 @@ func (h Handler) getTCPServices(rw http.ResponseWriter, request *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getTCPService(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getTCPService(rw http.ResponseWriter, request *http.Request) {
|
||||||
serviceID := mux.Vars(request)["serviceID"]
|
scapedServiceID := mux.Vars(request)["serviceID"]
|
||||||
|
|
||||||
|
serviceID, err := url.PathUnescape(scapedServiceID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(rw, fmt.Sprintf("unable to decode serviceID %q: %s", scapedServiceID, err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
@ -156,7 +169,7 @@ func (h Handler) getTCPService(rw http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
result := newTCPServiceRepresentation(serviceID, service)
|
result := newTCPServiceRepresentation(serviceID, service)
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err = json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -196,7 +209,13 @@ func (h Handler) getTCPMiddlewares(rw http.ResponseWriter, request *http.Request
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getTCPMiddleware(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getTCPMiddleware(rw http.ResponseWriter, request *http.Request) {
|
||||||
middlewareID := mux.Vars(request)["middlewareID"]
|
scapedMiddlewareID := mux.Vars(request)["middlewareID"]
|
||||||
|
|
||||||
|
middlewareID, err := url.PathUnescape(scapedMiddlewareID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(rw, fmt.Sprintf("unable to decode middlewareID %q: %s", scapedMiddlewareID, err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
@ -208,7 +227,7 @@ func (h Handler) getTCPMiddleware(rw http.ResponseWriter, request *http.Request)
|
||||||
|
|
||||||
result := newTCPMiddlewareRepresentation(middlewareID, middleware)
|
result := newTCPMiddlewareRepresentation(middlewareID, middleware)
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err = json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -212,6 +213,25 @@ func TestHandler_TCP(t *testing.T) {
|
||||||
jsonFile: "testdata/tcprouter-bar.json",
|
jsonFile: "testdata/tcprouter-bar.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "one TCP router by id containing slash",
|
||||||
|
path: "/api/tcp/routers/" + url.PathEscape("foo / bar@myprovider"),
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
TCPRouters: map[string]*runtime.TCPRouterInfo{
|
||||||
|
"foo / bar@myprovider": {
|
||||||
|
TCPRouter: &dynamic.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
jsonFile: "testdata/tcprouter-foo-slash-bar.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one TCP router by id, that does not exist",
|
desc: "one TCP router by id, that does not exist",
|
||||||
path: "/api/tcp/routers/foo@myprovider",
|
path: "/api/tcp/routers/foo@myprovider",
|
||||||
|
@ -476,6 +496,30 @@ func TestHandler_TCP(t *testing.T) {
|
||||||
jsonFile: "testdata/tcpservice-bar.json",
|
jsonFile: "testdata/tcpservice-bar.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "one tcp service by id containing slash",
|
||||||
|
path: "/api/tcp/services/" + url.PathEscape("foo / bar@myprovider"),
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
TCPServices: map[string]*runtime.TCPServiceInfo{
|
||||||
|
"foo / bar@myprovider": {
|
||||||
|
TCPService: &dynamic.TCPService{
|
||||||
|
LoadBalancer: &dynamic.TCPServersLoadBalancer{
|
||||||
|
Servers: []dynamic.TCPServer{
|
||||||
|
{
|
||||||
|
Address: "127.0.0.1:2345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
jsonFile: "testdata/tcpservice-foo-slash-bar.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one tcp service by id, that does not exist",
|
desc: "one tcp service by id, that does not exist",
|
||||||
path: "/api/tcp/services/nono@myprovider",
|
path: "/api/tcp/services/nono@myprovider",
|
||||||
|
@ -697,6 +741,26 @@ func TestHandler_TCP(t *testing.T) {
|
||||||
jsonFile: "testdata/tcpmiddleware-ipwhitelist.json",
|
jsonFile: "testdata/tcpmiddleware-ipwhitelist.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "one middleware by id containing slash",
|
||||||
|
path: "/api/tcp/middlewares/" + url.PathEscape("foo / bar@myprovider"),
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
TCPMiddlewares: map[string]*runtime.TCPMiddlewareInfo{
|
||||||
|
"foo / bar@myprovider": {
|
||||||
|
TCPMiddleware: &dynamic.TCPMiddleware{
|
||||||
|
IPWhiteList: &dynamic.TCPIPWhiteList{
|
||||||
|
SourceRange: []string{"127.0.0.1/32"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"bar@myprovider", "test@myprovider"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
jsonFile: "testdata/tcpmiddleware-foo-slash-bar.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one middleware by id, that does not exist",
|
desc: "one middleware by id, that does not exist",
|
||||||
path: "/api/tcp/middlewares/foo@myprovider",
|
path: "/api/tcp/middlewares/foo@myprovider",
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -76,7 +77,13 @@ func (h Handler) getUDPRouters(rw http.ResponseWriter, request *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getUDPRouter(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getUDPRouter(rw http.ResponseWriter, request *http.Request) {
|
||||||
routerID := mux.Vars(request)["routerID"]
|
scapedRouterID := mux.Vars(request)["routerID"]
|
||||||
|
|
||||||
|
routerID, err := url.PathUnescape(scapedRouterID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(rw, fmt.Sprintf("unable to decode routerID %q: %s", scapedRouterID, err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
@ -88,7 +95,7 @@ func (h Handler) getUDPRouter(rw http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
result := newUDPRouterRepresentation(routerID, router)
|
result := newUDPRouterRepresentation(routerID, router)
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err = json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -128,7 +135,13 @@ func (h Handler) getUDPServices(rw http.ResponseWriter, request *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Handler) getUDPService(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getUDPService(rw http.ResponseWriter, request *http.Request) {
|
||||||
serviceID := mux.Vars(request)["serviceID"]
|
scapedServiceID := mux.Vars(request)["serviceID"]
|
||||||
|
|
||||||
|
serviceID, err := url.PathUnescape(scapedServiceID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(rw, fmt.Sprintf("unable to decode serviceID %q: %s", scapedServiceID, err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
@ -140,7 +153,7 @@ func (h Handler) getUDPService(rw http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
result := newUDPServiceRepresentation(serviceID, service)
|
result := newUDPServiceRepresentation(serviceID, service)
|
||||||
|
|
||||||
err := json.NewEncoder(rw).Encode(result)
|
err = json.NewEncoder(rw).Encode(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(request.Context()).Error(err)
|
log.FromContext(request.Context()).Error(err)
|
||||||
writeError(rw, err.Error(), http.StatusInternalServerError)
|
writeError(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -190,6 +191,24 @@ func TestHandler_UDP(t *testing.T) {
|
||||||
jsonFile: "testdata/udprouter-bar.json",
|
jsonFile: "testdata/udprouter-bar.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "one UDP router by id containing slash",
|
||||||
|
path: "/api/udp/routers/" + url.PathEscape("foo / bar@myprovider"),
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
UDPRouters: map[string]*runtime.UDPRouterInfo{
|
||||||
|
"foo / bar@myprovider": {
|
||||||
|
UDPRouter: &dynamic.UDPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "foo-service@myprovider",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
jsonFile: "testdata/udprouter-foo-slash-bar.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one UDP router by id, that does not exist",
|
desc: "one UDP router by id, that does not exist",
|
||||||
path: "/api/udp/routers/foo@myprovider",
|
path: "/api/udp/routers/foo@myprovider",
|
||||||
|
@ -453,6 +472,30 @@ func TestHandler_UDP(t *testing.T) {
|
||||||
jsonFile: "testdata/udpservice-bar.json",
|
jsonFile: "testdata/udpservice-bar.json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "one udp service by id containing slash",
|
||||||
|
path: "/api/udp/services/" + url.PathEscape("foo / bar@myprovider"),
|
||||||
|
conf: runtime.Configuration{
|
||||||
|
UDPServices: map[string]*runtime.UDPServiceInfo{
|
||||||
|
"foo / bar@myprovider": {
|
||||||
|
UDPService: &dynamic.UDPService{
|
||||||
|
LoadBalancer: &dynamic.UDPServersLoadBalancer{
|
||||||
|
Servers: []dynamic.UDPServer{
|
||||||
|
{
|
||||||
|
Address: "127.0.0.1:2345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UsedBy: []string{"foo@myprovider", "test@myprovider"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expected{
|
||||||
|
statusCode: http.StatusOK,
|
||||||
|
jsonFile: "testdata/udpservice-foo-slash-bar.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "one udp service by id, that does not exist",
|
desc: "one udp service by id, that does not exist",
|
||||||
path: "/api/udp/services/nono@myprovider",
|
path: "/api/udp/services/nono@myprovider",
|
||||||
|
|
5
pkg/api/testdata/entrypoint-foo-slash-bar.json
vendored
Normal file
5
pkg/api/testdata/entrypoint-foo-slash-bar.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"address": ":81",
|
||||||
|
"http": {},
|
||||||
|
"name": "foo / bar"
|
||||||
|
}
|
12
pkg/api/testdata/middleware-foo-slash-bar.json
vendored
Normal file
12
pkg/api/testdata/middleware-foo-slash-bar.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"addPrefix": {
|
||||||
|
"prefix": "/titi"
|
||||||
|
},
|
||||||
|
"name": "foo / bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "addprefix",
|
||||||
|
"usedBy": [
|
||||||
|
"test@myprovider"
|
||||||
|
]
|
||||||
|
}
|
17
pkg/api/testdata/router-foo-slash-bar.json
vendored
Normal file
17
pkg/api/testdata/router-foo-slash-bar.json
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"entryPoints": [
|
||||||
|
"web"
|
||||||
|
],
|
||||||
|
"middlewares": [
|
||||||
|
"auth",
|
||||||
|
"addPrefixTest@anotherprovider"
|
||||||
|
],
|
||||||
|
"name": "foo / bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"rule": "Host(`foo.bar`)",
|
||||||
|
"service": "foo-service@myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
|
}
|
21
pkg/api/testdata/service-foo-slash-bar.json
vendored
Normal file
21
pkg/api/testdata/service-foo-slash-bar.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"loadBalancer": {
|
||||||
|
"passHostHeader": true,
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "http://127.0.0.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "foo / bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"serverStatus": {
|
||||||
|
"http://127.0.0.1": "UP"
|
||||||
|
},
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
|
"usedBy": [
|
||||||
|
"foo@myprovider",
|
||||||
|
"test@myprovider"
|
||||||
|
]
|
||||||
|
}
|
13
pkg/api/testdata/tcpmiddleware-foo-slash-bar.json
vendored
Normal file
13
pkg/api/testdata/tcpmiddleware-foo-slash-bar.json
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"ipWhiteList": {
|
||||||
|
"sourceRange": ["127.0.0.1/32"]
|
||||||
|
},
|
||||||
|
"name": "foo / bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "ipwhitelist",
|
||||||
|
"usedBy": [
|
||||||
|
"bar@myprovider",
|
||||||
|
"test@myprovider"
|
||||||
|
]
|
||||||
|
}
|
13
pkg/api/testdata/tcprouter-foo-slash-bar.json
vendored
Normal file
13
pkg/api/testdata/tcprouter-foo-slash-bar.json
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"entryPoints": [
|
||||||
|
"web"
|
||||||
|
],
|
||||||
|
"name": "foo / bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"rule": "Host(`foo.bar`)",
|
||||||
|
"service": "foo-service@myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
|
}
|
17
pkg/api/testdata/tcpservice-foo-slash-bar.json
vendored
Normal file
17
pkg/api/testdata/tcpservice-foo-slash-bar.json
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"loadBalancer": {
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"address": "127.0.0.1:2345"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "foo / bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
|
"usedBy": [
|
||||||
|
"foo@myprovider",
|
||||||
|
"test@myprovider"
|
||||||
|
]
|
||||||
|
}
|
12
pkg/api/testdata/udprouter-foo-slash-bar.json
vendored
Normal file
12
pkg/api/testdata/udprouter-foo-slash-bar.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"entryPoints": [
|
||||||
|
"web"
|
||||||
|
],
|
||||||
|
"name": "foo / bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"service": "foo-service@myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"using": [
|
||||||
|
"web"
|
||||||
|
]
|
||||||
|
}
|
17
pkg/api/testdata/udpservice-foo-slash-bar.json
vendored
Normal file
17
pkg/api/testdata/udpservice-foo-slash-bar.json
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"loadBalancer": {
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"address": "127.0.0.1:2345"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "foo / bar@myprovider",
|
||||||
|
"provider": "myprovider",
|
||||||
|
"status": "enabled",
|
||||||
|
"type": "loadbalancer",
|
||||||
|
"usedBy": [
|
||||||
|
"foo@myprovider",
|
||||||
|
"test@myprovider"
|
||||||
|
]
|
||||||
|
}
|
|
@ -138,7 +138,7 @@ const GetTablePropsMixin = {
|
||||||
return {
|
return {
|
||||||
onRowClick: row =>
|
onRowClick: row =>
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: `/${type.replace('-', '/', 'gi')}/${row.name}`
|
path: `/${type.replace('-', '/', 'gi')}/${encodeURIComponent(row.name)}`
|
||||||
}),
|
}),
|
||||||
columns: allColumns.filter(c =>
|
columns: allColumns.filter(c =>
|
||||||
get(propsByType, `${type}.columns`, []).includes(c.name)
|
get(propsByType, `${type}.columns`, []).includes(c.name)
|
||||||
|
|
|
@ -14,7 +14,7 @@ function getAllRouters (params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRouterByName (name) {
|
function getRouterByName (name) {
|
||||||
return APP.api.get(`${apiBase}/routers/${name}`)
|
return APP.api.get(`${apiBase}/routers/${encodeURIComponent(name)}`)
|
||||||
.then(body => {
|
.then(body => {
|
||||||
console.log('Success -> HttpService -> getRouterByName', body.data)
|
console.log('Success -> HttpService -> getRouterByName', body.data)
|
||||||
return body.data
|
return body.data
|
||||||
|
@ -32,7 +32,7 @@ function getAllServices (params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServiceByName (name) {
|
function getServiceByName (name) {
|
||||||
return APP.api.get(`${apiBase}/services/${name}`)
|
return APP.api.get(`${apiBase}/services/${encodeURIComponent(name)}`)
|
||||||
.then(body => {
|
.then(body => {
|
||||||
console.log('Success -> HttpService -> getServiceByName', body.data)
|
console.log('Success -> HttpService -> getServiceByName', body.data)
|
||||||
return body.data
|
return body.data
|
||||||
|
@ -50,7 +50,7 @@ function getAllMiddlewares (params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMiddlewareByName (name) {
|
function getMiddlewareByName (name) {
|
||||||
return APP.api.get(`${apiBase}/middlewares/${name}`)
|
return APP.api.get(`${apiBase}/middlewares/${encodeURIComponent(name)}`)
|
||||||
.then(body => {
|
.then(body => {
|
||||||
console.log('Success -> HttpService -> getMiddlewareByName', body.data)
|
console.log('Success -> HttpService -> getMiddlewareByName', body.data)
|
||||||
return body.data
|
return body.data
|
||||||
|
|
|
@ -14,7 +14,7 @@ function getAllRouters (params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRouterByName (name) {
|
function getRouterByName (name) {
|
||||||
return APP.api.get(`${apiBase}/routers/${name}`)
|
return APP.api.get(`${apiBase}/routers/${encodeURIComponent(name)}`)
|
||||||
.then(body => {
|
.then(body => {
|
||||||
console.log('Success -> TcpService -> getRouterByName', body.data)
|
console.log('Success -> TcpService -> getRouterByName', body.data)
|
||||||
return body.data
|
return body.data
|
||||||
|
@ -32,7 +32,7 @@ function getAllServices (params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServiceByName (name) {
|
function getServiceByName (name) {
|
||||||
return APP.api.get(`${apiBase}/services/${name}`)
|
return APP.api.get(`${apiBase}/services/${encodeURIComponent(name)}`)
|
||||||
.then(body => {
|
.then(body => {
|
||||||
console.log('Success -> TcpService -> getServiceByName', body.data)
|
console.log('Success -> TcpService -> getServiceByName', body.data)
|
||||||
return body.data
|
return body.data
|
||||||
|
@ -50,7 +50,7 @@ function getAllMiddlewares (params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMiddlewareByName (name) {
|
function getMiddlewareByName (name) {
|
||||||
return APP.api.get(`${apiBase}/middlewares/${name}`)
|
return APP.api.get(`${apiBase}/middlewares/${encodeURIComponent(name)}`)
|
||||||
.then(body => {
|
.then(body => {
|
||||||
console.log('Success -> TcpService -> getMiddlewareByName', body.data)
|
console.log('Success -> TcpService -> getMiddlewareByName', body.data)
|
||||||
return body.data
|
return body.data
|
||||||
|
|
|
@ -14,7 +14,7 @@ function getAllRouters (params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRouterByName (name) {
|
function getRouterByName (name) {
|
||||||
return APP.api.get(`${apiBase}/routers/${name}`)
|
return APP.api.get(`${apiBase}/routers/${encodeURIComponent(name)}`)
|
||||||
.then(body => {
|
.then(body => {
|
||||||
console.log('Success -> UdpService -> getRouterByName', body.data)
|
console.log('Success -> UdpService -> getRouterByName', body.data)
|
||||||
return body.data
|
return body.data
|
||||||
|
@ -32,7 +32,7 @@ function getAllServices (params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServiceByName (name) {
|
function getServiceByName (name) {
|
||||||
return APP.api.get(`${apiBase}/services/${name}`)
|
return APP.api.get(`${apiBase}/services/${encodeURIComponent(name)}`)
|
||||||
.then(body => {
|
.then(body => {
|
||||||
console.log('Success -> UdpService -> getServiceByName', body.data)
|
console.log('Success -> UdpService -> getServiceByName', body.data)
|
||||||
return body.data
|
return body.data
|
||||||
|
|
|
@ -279,7 +279,7 @@ export default {
|
||||||
return data.service
|
return data.service
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${data.service}@${data.provider}`
|
return `${encodeURIComponent(data.service)}@${data.provider}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
|
|
Loading…
Reference in a new issue