Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The proxy middleware is not forwarding requests #1808

Closed
gustavosbarreto opened this issue Mar 11, 2021 · 2 comments · Fixed by #1812
Closed

The proxy middleware is not forwarding requests #1808

gustavosbarreto opened this issue Mar 11, 2021 · 2 comments · Fixed by #1812

Comments

@gustavosbarreto
Copy link

gustavosbarreto commented Mar 11, 2021

Issue Description

The proxy middleware is not forwarding requests

Expected behaviour

Middleware should be called to forward request to the another echo instance

> GET http://localhost:8081/resource/1
< HTTP 200

> PUT http://localhost:8081/resource/1
< HTTP 200

Actual behaviour

Middleware is not called and I'm getting back a 405 status code (method not allowed)

> GET http://localhost:8081/resource/1
< HTTP 405

> PUT http://localhost:8081/resource/1
< HTTP 200

Steps to reproduce

GET http://localhost:8081/resource/1

Working code to debug

package main

import (
	"net/http"
	"net/url"

	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

func main() {
        // echo instance 1
	e1 := echo.New()
	g1 := e1.Group("/api")
	g1.GET("/resource/:id", func(c echo.Context) error {
		return c.NoContent(http.StatusOK)
	})

	e1url, _ := url.Parse("http://localhost:8080")

	// echo instance 2
	e2 := echo.New()
	g2 := e2.Group("/api")
	g2.PUT("/resource/:id", func(c echo.Context) error {
		return c.NoContent(http.StatusOK)
	})
	g2.Use(middleware.Proxy(middleware.NewRoundRobinBalancer([]*middleware.ProxyTarget{
		{
			URL: e1url, // forward all requests with /api prefix to server running on port 8080 (except PUT /resource/:id)
		},
	})))

	go e1.Start(":8080")
	e2.Start(":8081")
}
@aldas
Copy link
Contributor

aldas commented Mar 12, 2021

This is current limitation of Echo router. It finds match for /resource/:id route and stops searching for matching path. Then tries to look up method but GET (only PUT is for that path) is not registered and sends 405

Unless you want to wait for fix you can work around this problem by using skipper method for proxy and registering additional Any route on echo that does proxying. This Any will not be called but it will fool router to match and execute proxy middleware.

func TestProxy(t *testing.T) {
	targetEcho := echo.New()
	g1 := targetEcho.Group("/api")

	g1.Any("/*", func(c echo.Context) error {
		fmt.Println("targetEcho: " + c.Path())
		return c.String(http.StatusOK, fmt.Sprintf("response from targetEcho: %v\n", c.Path()))
	})

	g1.GET("/resource/:id", func(c echo.Context) error {
		fmt.Println("targetEcho: " + c.Path())
		return c.String(http.StatusOK, fmt.Sprintf("response from targetEcho: %v\n", c.Path()))
	})

	e1url, _ := url.Parse("http://localhost:8084")

	proxyingEcho := echo.New()
	g2 := proxyingEcho.Group("/api")
	g2.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{
		Skipper: func(e echo.Context) bool {
			if e.Request().Method == http.MethodPut && strings.HasPrefix(e.Request().URL.Path, "/api/resource/") {
				return true
			}
			return false
		},
		Balancer: middleware.NewRoundRobinBalancer([]*middleware.ProxyTarget{
			{
				URL: e1url, // forward all requests with /api prefix to server running on port 8084 (except PUT /resource/:id)
			},
		}),
	}),
	)
	g2.Any("/resource/:id", func(c echo.Context) error {
		return errors.New("never reached")
	})
	g2.PUT("/resource/:id", func(c echo.Context) error {
		fmt.Println("proxyingEcho: " + c.Path())
		return c.String(http.StatusOK, fmt.Sprintf("response from proxyingEcho: %v\n", c.Path()))
	})

	go targetEcho.Start(":8084")
	if err := proxyingEcho.Start(":8088"); err != nil {
		log.Fatal(err)
	}
}
x@x:~/code$ curl -X GET http://localhost:8088/api/resource/1
response from targetEcho: /api/resource/:id

x@x:~/code$ curl -X PUT http://localhost:8088/api/resource/1
response from proxyingEcho: /api/resource/:id

x@x:~/code$ curl -X PUT http://localhost:8088/api/should_proxy
response from targetEcho: /api/*

x@x:~/code$ curl -X GET http://localhost:8088/api/should_proxy
response from targetEcho: /api/*

@gustavosbarreto
Copy link
Author

Unless you want to wait for fix you can work around this problem by using skipper method for proxy and registering additional Any route on echo that does proxying. This Any will not be called but it will fool router to match and execute proxy middleware.

Is there any future plan to fix this issue?

aldas added a commit to aldas/echo that referenced this issue Mar 16, 2021
lammel pushed a commit that referenced this issue Apr 27, 2021
… matching by path+method (#1812)

* when url ends with slash first param route is the match (fix #1804)
* router should check if method is suitable for matching route and if not then continue search in tree (fix #1808)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants