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

BindStyledParameterWithOptions double-decodes path parameters #35

Open
reinkrul opened this issue Feb 13, 2024 · 0 comments
Open

BindStyledParameterWithOptions double-decodes path parameters #35

reinkrul opened this issue Feb 13, 2024 · 0 comments

Comments

@reinkrul
Copy link

reinkrul commented Feb 13, 2024

When a path parameter contains percent-encoded characters (in the original value), BindStyledParameterWithOptions causes the original percent characters to be decoded as if they were URL path encoded. This either causes the original value to be lost or a HTTP error 400 in case the characer can't be decoded. E.g., if a path parameter were a (fictional) discount ("/checkout/" + url.PathEscape("15%off")), a HTTP error 400 occurs. Or url.PathEscape("discount%20") would be received in the server interface as "discount " (decoded to a space).

This is caused by BindStyledParameterWithOptions which uses the path parameters from Echo (didn't test other HTTP servers) to unescape the parameters, which Echo already did. It does not occur with query parameters.

Example

OpenAPI spec:

openapi: "3.0.1"
paths:
  /test/{param1}:
    parameters:
      - name: param1
        in: path
        required: true
        schema:
          type: string
    get:
      operationId: test
      responses:
        204:
          description: good

Unit test:

package issueXX_test

import (
	"context"
	issueXX "github.com/deepmap/oapi-codegen/v2/internal/test/issues/issue-XX"
	"github.com/labstack/echo/v4"
	"github.com/stretchr/testify/require"
	"net/http"
	"net/http/httptest"
	"net/url"
	"sync/atomic"
	"testing"

	"github.com/stretchr/testify/assert"
)

type serverImplementation struct {
	param1 atomic.Value
}

var _ issueXX.StrictServerInterface = &serverImplementation{}

func (s *serverImplementation) Test(_ context.Context, request issueXX.TestRequestObject) (issueXX.TestResponseObject, error) {
	s.param1.Store(request.Param1)
	return issueXX.Test204Response{}, nil
}

func TestIssueXX(t *testing.T) {
	impl := &serverImplementation{}
	e := echo.New()
	issueXX.RegisterHandlers(e, issueXX.NewStrictHandler(impl, nil))
	svr := httptest.NewServer(e)
	defer svr.Close()

	const expected = "discount%20"
	httpResponse, err := http.Get(svr.URL + "/test/" + url.PathEscape(expected))
	require.NoError(t, err)
	require.Equal(t, http.StatusNoContent, httpResponse.StatusCode)
	assert.Equal(t, expected, impl.param1.Load(), "path unescape incorrect")
}

Test output:

        	Error:      	Not equal: 
        	            	expected: "discount%20"
        	            	actual  : "discount "

Solution

BindStyledParameterWithOptions should not unescape the value (at least for Echo).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant