Skip to content

Commit

Permalink
restore path match behavior of 3.9 with option to trim slash (#535)
Browse files Browse the repository at this point in the history
* restore path match behavior of 3.9 with option to trim slash

* remove obsolete tests, improved user-resource

* update change log
  • Loading branch information
emicklei committed Aug 19, 2023
1 parent bdefcac commit 0c5c401
Show file tree
Hide file tree
Showing 13 changed files with 53 additions and 325 deletions.
8 changes: 6 additions & 2 deletions CHANGES.md
@@ -1,11 +1,15 @@
# Change history of go-restful

## [v3.10.2] - 2023-03-09
## [v3.11.0] - 2023-08-19

- restored behavior as <= v3.9.0 with option to change path strategy using TrimRightSlashEnabled.

## [v3.10.2] - 2023-03-09 - DO NOT USE

- introduced MergePathStrategy to be able to revert behaviour of path concatenation to 3.9.0
see comment in Readme how to customize this behaviour.

## [v3.10.1] - 2022-11-19
## [v3.10.1] - 2022-11-19 - DO NOT USE

- fix broken 3.10.0 by using path package for joining paths

Expand Down
5 changes: 1 addition & 4 deletions README.md
Expand Up @@ -96,10 +96,7 @@ There are several hooks to customize the behavior of the go-restful package.
- Compression
- Encoders for other serializers
- Use [jsoniter](https://github.com/json-iterator/go) by building this package using a build tag, e.g. `go build -tags=jsoniter .`
- Use the variable `MergePathStrategy` to change the behaviour of composing the Route path given a root path and a local route path
- versions >= 3.10.1 has set the value to `PathJoinStrategy` that fixes a reported [security issue](https://github.com/advisories/GHSA-r48q-9g5r-8q2h) but may cause your services not to work correctly anymore.
- versions <= 3.9 had the behaviour that can be restored in newer versions by setting the value to `TrimSlashStrategy`.
- you can set value to a custom implementation (must implement MergePathStrategyFunc)
- Use the package variable `TrimRightSlashEnabled` (default true) to controls the behavior of matching routes that end with a slash `/`

## Resources

Expand Down
2 changes: 1 addition & 1 deletion curly_test.go
Expand Up @@ -106,7 +106,7 @@ var routeMatchers = []struct {
{"/a", "/a", true, 0, 1, false},
{"/a", "/b", false, 0, 0, false},
{"/a", "/b", false, 0, 0, false},
{"/a/{b}/c/", "/a/2/c", false, 0, 0, false},
{"/a/{b}/c/", "/a/2/c", true, 1, 2, false},
{"/{a}/{b}/{c}/", "/a/b", false, 0, 0, false},
{"/{x:*}", "/", false, 0, 0, false},
{"/{x:*}", "/a", true, 1, 0, false},
Expand Down
149 changes: 0 additions & 149 deletions examples/tests/restful-curly-router_test.go

This file was deleted.

39 changes: 0 additions & 39 deletions examples/tests/restful-route_test.go

This file was deleted.

29 changes: 0 additions & 29 deletions examples/tests/restful-routefunction_test.go

This file was deleted.

2 changes: 2 additions & 0 deletions examples/user-resource/go.mod
Expand Up @@ -2,6 +2,8 @@ module github.com/emicklei/go-restful/examples/user-resource

go 1.14

replace github.com/emicklei/go-restful/v3 => ../../.

require (
github.com/emicklei/go-restful-openapi/v2 v2.8.0
github.com/emicklei/go-restful/v3 v3.8.0
Expand Down
32 changes: 17 additions & 15 deletions examples/user-resource/restful-user-resource.go
@@ -1,8 +1,10 @@
package main

import (
"fmt"
"log"
"net/http"
"time"

restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
Expand Down Expand Up @@ -41,14 +43,14 @@ func (u UserResource) WebService() *restful.WebService {
Returns(200, "OK", User{}).
Returns(404, "Not Found", nil))

ws.Route(ws.PUT("/{user-id}").To(u.updateUser).
ws.Route(ws.PUT("/{user-id}").To(u.upsertUser).
// docs
Doc("update a user").
Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(User{})) // from the request

ws.Route(ws.PUT("").To(u.createUser).
ws.Route(ws.POST("").To(u.createUser).
// docs
Doc("create a user").
Metadata(restfulspec.KeyOpenAPITags, tags).
Expand All @@ -64,8 +66,8 @@ func (u UserResource) WebService() *restful.WebService {
}

// GET http://localhost:8080/users
//
func (u UserResource) findAllUsers(request *restful.Request, response *restful.Response) {
log.Println("findAllUsers")
list := []User{}
for _, each := range u.users {
list = append(list, each)
Expand All @@ -74,8 +76,8 @@ func (u UserResource) findAllUsers(request *restful.Request, response *restful.R
}

// GET http://localhost:8080/users/1
//
func (u UserResource) findUser(request *restful.Request, response *restful.Response) {
log.Println("findUser")
id := request.PathParameter("user-id")
usr := u.users[id]
if len(usr.ID) == 0 {
Expand All @@ -87,23 +89,23 @@ func (u UserResource) findUser(request *restful.Request, response *restful.Respo

// PUT http://localhost:8080/users/1
// <User><Id>1</Id><Name>Melissa Raspberry</Name></User>
//
func (u *UserResource) updateUser(request *restful.Request, response *restful.Response) {
usr := new(User)
func (u *UserResource) upsertUser(request *restful.Request, response *restful.Response) {
log.Println("upsertUser")
usr := User{ID: request.PathParameter("user-id")}
err := request.ReadEntity(&usr)
if err == nil {
u.users[usr.ID] = *usr
u.users[usr.ID] = usr
response.WriteEntity(usr)
} else {
response.WriteError(http.StatusInternalServerError, err)
}
}

// PUT http://localhost:8080/users/1
// POST http://localhost:8080/users
// <User><Id>1</Id><Name>Melissa</Name></User>
//
func (u *UserResource) createUser(request *restful.Request, response *restful.Response) {
usr := User{ID: request.PathParameter("user-id")}
log.Println("createUser")
usr := User{ID: fmt.Sprintf("%d", time.Now().Unix())}
err := request.ReadEntity(&usr)
if err == nil {
u.users[usr.ID] = usr
Expand All @@ -114,8 +116,8 @@ func (u *UserResource) createUser(request *restful.Request, response *restful.Re
}

// DELETE http://localhost:8080/users/1
//
func (u *UserResource) removeUser(request *restful.Request, response *restful.Response) {
log.Println("removeUser")
id := request.PathParameter("user-id")
delete(u.users, id)
}
Expand Down Expand Up @@ -167,7 +169,7 @@ func enrichSwaggerObject(swo *spec.Swagger) {

// User is just a sample type
type User struct {
ID string `json:"id" description:"identifier of the user"`
Name string `json:"name" description:"name of the user" default:"john"`
Age int `json:"age" description:"age of the user" default:"21"`
ID string `xml:"id" json:"id" description:"identifier of the user"`
Name string `xml:"name" json:"name" description:"name of the user" default:"john"`
Age int `xml:"age" json:"age" description:"age of the user" default:"21"`
}
1 change: 0 additions & 1 deletion filter_test.go
Expand Up @@ -18,7 +18,6 @@ func tearDown() {
DefaultContainer.webServices = []*WebService{}
DefaultContainer.isRegisteredOnRoot = true // this allows for setupServices multiple times
DefaultContainer.containerFilters = []FilterFunction{}
MergePathStrategy = PathJoinStrategy
}

func newTestService(addServiceFilter bool, addRouteFilter bool) *WebService {
Expand Down
10 changes: 9 additions & 1 deletion path_processor_test.go
Expand Up @@ -33,7 +33,15 @@ func TestMatchesPath_TwoVars(t *testing.T) {
}

func TestMatchesPath_VarOnFront(t *testing.T) {
params := doExtractParams("{what}/from/{source}/", 4, "who/from/SOS/", t) // slash is not removed
params := doExtractParams("{what}/from/{source}/", 3, "who/from/SOS/", t)
if params["source"] != "SOS" {
t.Errorf("parameter mismatch SOS")
}
}

func TestMatchesPath_VarOnFront_KeepSlash(t *testing.T) {
TrimRightSlashEnabled = false
params := doExtractParams("{what}/from/{source}/", 4, "who/from/SOS/", t)
if params["source"] != "SOS" {
t.Errorf("parameter mismatch SOS")
}
Expand Down

0 comments on commit 0c5c401

Please sign in to comment.