go-restful icon indicating copy to clipboard operation
go-restful copied to clipboard

detectWebService biased against webServices without path or rootpath

Open haitch opened this issue 7 months ago • 1 comments

When there are mix use of default webService and regexPath webService, the default webService may get biased and its route won't get selected.

with 2 webService setup like this:

  • one with default routes (empty Path, or rootPath '/')
  • one with regex Path during detectWebService, computeWebserviceScore, with a request trying to hit the default route.
  • defaultRoute would always get score 0
  • and regexPath would always get score 1 (regex not match) this would select wrong webService 100%, and won't find the correct route.

since I have fix on this part with issue #547 and PR #549 , I would image the fix is remove the default score for any regex routeToken, but that would definitely be a breaking change.

reproduce, also here is go playground link: https://go.dev/play/p/xbpUnvAETio

package main

import (
	"fmt"
	"io"
	"net/http/httptest"

	restful "github.com/emicklei/go-restful/v3"
)

func main() {
	defaultWS := new(restful.WebService) // or .Path("/")
	helloWS := new(restful.WebService).Path("/{:hello}")

	defaultWS.Route(defaultWS.GET("/{:robot.txt}").To(robotFile))
	restful.DefaultContainer.Add(defaultWS)

	helloWS.Route(helloWS.GET("/{name:*}").To(hello))
	restful.DefaultContainer.Add(helloWS) // comment out this line, and robot.txt will be served

	helloRequest := httptest.NewRequest("GET", "/hello/Juan", nil)
	helloRespWriter := httptest.NewRecorder()
	restful.DefaultContainer.ServeHTTP(helloRespWriter, helloRequest)

	robotRequest := httptest.NewRequest("GET", "/robot.txt", nil)
	robotRespWriter := httptest.NewRecorder()
	restful.DefaultContainer.ServeHTTP(robotRespWriter, robotRequest)

	fmt.Println(helloRequest.Method, helloRequest.URL.Path, "-", helloRespWriter.Result().Status, helloRespWriter.Body.String())
	fmt.Println(robotRequest.Method, robotRequest.URL.Path, "-", robotRespWriter.Result().Status, robotRespWriter.Body.String())
}

func hello(req *restful.Request, resp *restful.Response) {
	io.WriteString(resp, "hello "+req.PathParameter("name"))
}

func robotFile(req *restful.Request, resp *restful.Response) {
	io.WriteString(resp, "User-agent: *\nDisallow: /\n")
}

haitch avatar Jul 08 '24 20:07 haitch