Skip to content

Commit d549290

Browse files
authored
Remove maxparam dependence from Context (#2611)
1 parent 011acb4 commit d549290

File tree

2 files changed

+62
-38
lines changed

2 files changed

+62
-38
lines changed

context.go

+25-15
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,29 @@ type Context interface {
202202
type context struct {
203203
request *http.Request
204204
response *Response
205-
path string
206-
pnames []string
207-
pvalues []string
208205
query url.Values
209-
handler HandlerFunc
210-
store Map
211206
echo *Echo
212207
logger Logger
213-
lock sync.RWMutex
208+
209+
store Map
210+
lock sync.RWMutex
211+
212+
// following fields are set by Router
213+
214+
// path is route path that Router matched. It is empty string where there is no route match.
215+
// Route registered with RouteNotFound is considered as a match and path therefore is not empty.
216+
path string
217+
218+
// pnames length is tied to param count for the matched route
219+
pnames []string
220+
221+
// Usually echo.Echo is sizing pvalues but there could be user created middlewares that decide to
222+
// overwrite parameter by calling SetParamNames + SetParamValues.
223+
// When echo.Echo allocated that slice it length/capacity is tied to echo.Echo.maxParam value.
224+
//
225+
// It is important that pvalues size is always equal or bigger to pnames length.
226+
pvalues []string
227+
handler HandlerFunc
214228
}
215229

216230
const (
@@ -330,10 +344,6 @@ func (c *context) SetParamNames(names ...string) {
330344
c.pnames = names
331345

332346
l := len(names)
333-
if *c.echo.maxParam < l {
334-
*c.echo.maxParam = l
335-
}
336-
337347
if len(c.pvalues) < l {
338348
// Keeping the old pvalues just for backward compatibility, but it sounds that doesn't make sense to keep them,
339349
// probably those values will be overridden in a Context#SetParamValues
@@ -348,11 +358,11 @@ func (c *context) ParamValues() []string {
348358
}
349359

350360
func (c *context) SetParamValues(values ...string) {
351-
// NOTE: Don't just set c.pvalues = values, because it has to have length c.echo.maxParam at all times
361+
// NOTE: Don't just set c.pvalues = values, because it has to have length c.echo.maxParam (or bigger) at all times
352362
// It will brake the Router#Find code
353363
limit := len(values)
354-
if limit > *c.echo.maxParam {
355-
limit = *c.echo.maxParam
364+
if limit > len(c.pvalues) {
365+
c.pvalues = make([]string, limit)
356366
}
357367
for i := 0; i < limit; i++ {
358368
c.pvalues[i] = values[i]
@@ -643,8 +653,8 @@ func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
643653
c.path = ""
644654
c.pnames = nil
645655
c.logger = nil
646-
// NOTE: Don't reset because it has to have length c.echo.maxParam at all times
647-
for i := 0; i < *c.echo.maxParam; i++ {
656+
// NOTE: Don't reset because it has to have length c.echo.maxParam (or bigger) at all times
657+
for i := 0; i < len(c.pvalues); i++ {
648658
c.pvalues[i] = ""
649659
}
650660
}

context_test.go

+37-23
Original file line numberDiff line numberDiff line change
@@ -653,36 +653,50 @@ func TestContextGetAndSetParam(t *testing.T) {
653653
})
654654
}
655655

656-
// Issue #1655
657-
func TestContextSetParamNamesShouldUpdateEchoMaxParam(t *testing.T) {
656+
func TestContextSetParamNamesEchoMaxParam(t *testing.T) {
658657
e := New()
659658
assert.Equal(t, 0, *e.maxParam)
660659

661660
expectedOneParam := []string{"one"}
662661
expectedTwoParams := []string{"one", "two"}
663662
expectedThreeParams := []string{"one", "two", ""}
664-
expectedABCParams := []string{"A", "B", "C"}
665663

666-
c := e.NewContext(nil, nil)
667-
c.SetParamNames("1", "2")
668-
c.SetParamValues(expectedTwoParams...)
669-
assert.Equal(t, 2, *e.maxParam)
670-
assert.EqualValues(t, expectedTwoParams, c.ParamValues())
671-
672-
c.SetParamNames("1")
673-
assert.Equal(t, 2, *e.maxParam)
674-
// Here for backward compatibility the ParamValues remains as they are
675-
assert.EqualValues(t, expectedOneParam, c.ParamValues())
676-
677-
c.SetParamNames("1", "2", "3")
678-
assert.Equal(t, 3, *e.maxParam)
679-
// Here for backward compatibility the ParamValues remains as they are, but the len is extended to e.maxParam
680-
assert.EqualValues(t, expectedThreeParams, c.ParamValues())
681-
682-
c.SetParamValues("A", "B", "C", "D")
683-
assert.Equal(t, 3, *e.maxParam)
684-
// Here D shouldn't be returned
685-
assert.EqualValues(t, expectedABCParams, c.ParamValues())
664+
{
665+
c := e.AcquireContext()
666+
c.SetParamNames("1", "2")
667+
c.SetParamValues(expectedTwoParams...)
668+
assert.Equal(t, 0, *e.maxParam) // has not been changed
669+
assert.EqualValues(t, expectedTwoParams, c.ParamValues())
670+
e.ReleaseContext(c)
671+
}
672+
673+
{
674+
c := e.AcquireContext()
675+
c.SetParamNames("1", "2", "3")
676+
c.SetParamValues(expectedThreeParams...)
677+
assert.Equal(t, 0, *e.maxParam) // has not been changed
678+
assert.EqualValues(t, expectedThreeParams, c.ParamValues())
679+
e.ReleaseContext(c)
680+
}
681+
682+
{ // values is always same size as names length
683+
c := e.NewContext(nil, nil)
684+
c.SetParamValues([]string{"one", "two"}...) // more values than names should be ok
685+
c.SetParamNames("1")
686+
assert.Equal(t, 0, *e.maxParam) // has not been changed
687+
assert.EqualValues(t, expectedOneParam, c.ParamValues())
688+
}
689+
690+
e.GET("/:id", handlerFunc)
691+
assert.Equal(t, 1, *e.maxParam) // has not been changed
692+
693+
{
694+
c := e.NewContext(nil, nil)
695+
c.SetParamValues([]string{"one", "two"}...)
696+
c.SetParamNames("1")
697+
assert.Equal(t, 1, *e.maxParam) // has not been changed
698+
assert.EqualValues(t, expectedOneParam, c.ParamValues())
699+
}
686700
}
687701

688702
func TestContextFormValue(t *testing.T) {

0 commit comments

Comments
 (0)