-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
If a path parameter needs to be escaped the runtime code generates an invalid path.
BasePath = "/foo"
Path = "/v1/{param}"
I suggest adding a transport to the HTTP client that dumps the request.
import openapiclient "github.com/go-openapi/runtime/client"
c := generatedClient.New(
openapiclient.NewWithClient("localhost", "/foo", []string{"http"}, http.DefaultClient),
nil,
)
// all of the following fail.
// passing in a raw string will invoke an invalid path: /foo/v1/param/value
c.ResourceMethod((&ResourceMethodParameters{}).WithParam("param/value"))
// passing in an escaped string will invoke an invalid path: /foo/v1/param/value
c.ResourceMethod((&ResourceMethodParameters{}).WithParam(url.PathEscape("param/value")))
These fail because of the runtime/client's interaction with URL.
The http client uses URL.EscapedPath() to determine what path to use.
func (u *URL) EscapedPath() string {
if u.RawPath != "" && validEncodedPath(u.RawPath) {
p, err := unescape(u.RawPath, encodePath)
if err == nil && p == u.Path {
return u.RawPath
}
}
if u.Path == "*" {
return "*" // don't escape (Issue 11202)
}
return escape(u.Path, encodePath)
}
client.Runtime.Submit has the following code:
func (r *Runtime) Submit(operation *runtime.ClientOperation) (interface{}, error) {
// ...
if req.URL.Path != "" && req.URL.Path != "/" && req.URL.Path[len(req.URL.Path)-1] == '/' {
reinstateSlash = true
}
req.URL.Path = path.Join(r.BasePath, req.URL.Path)
if reinstateSlash {
req.URL.Path = req.URL.Path + "/"
}
// ...
}
setting req.URL.Path = path.Join(r.BasePath, req.URL.Path)
causes url.EscapedPath() to return
req.URL.Path unescaped, since escape(u.Path, encodePath) only escapes the ?, it assumes the fragments have already been properly escaped.
the fix is to properly set both the RawPath and the Path in the submit function.
req.URL.Path = path.Join(r.BasePath, req.URL.Path)
req.URL.RawPath = path.Join(r.BasePath, req.URL.RawPath)
I also believe that func (r *request) BuildHTTP(...) (*http.Request, error) {
should properly escape the path parameters, but that breaks current behaviour.
// create http request
path := r.pathPattern
for k, v := range r.pathParams {
log.Println("replacing", "{"+k+"}", "with", v, "in", path)
path = strings.Replace(path, "{"+k+"}", url.PathEscape(v), -1)
}
Environment
swagger version: master, d507f49
go version: 1.8.1
OS: linux