Skip to content

Commit

Permalink
work around localhost host mismatch with relative server url (#467)
Browse files Browse the repository at this point in the history
Co-authored-by: Chris Rodwell <crodwell@mediamath.com>
  • Loading branch information
fenollp and crodwell committed Dec 20, 2021
1 parent 4ce78d8 commit e4ff797
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/workflows/go.yml
Expand Up @@ -64,6 +64,7 @@ jobs:
- if: runner.os == 'Linux'
run: git --no-pager diff && [[ $(git --no-pager diff --name-only | wc -l) = 0 ]]

- run: go test -count=10 -v -run TestIssue356 ./routers
- run: go test ./...
- run: go test -v -run TestRaceyPatternSchema -race ./...
env:
Expand Down
6 changes: 4 additions & 2 deletions routers/gorillamux/router.go
Expand Up @@ -17,6 +17,8 @@ import (
"github.com/gorilla/mux"
)

var _ routers.Router = &Router{}

// Router helps link http.Request.s and an OpenAPIv3 spec
type Router struct {
muxes []*mux.Route
Expand Down Expand Up @@ -107,10 +109,10 @@ func (r *Router) FindRoute(req *http.Request) (*routers.Route, map[string]string
if err := match.MatchErr; err != nil {
// What then?
}
route := r.routes[i]
route := *r.routes[i]
route.Method = req.Method
route.Operation = route.Spec.Paths[route.Path].GetOperation(route.Method)
return route, match.Vars, nil
return &route, match.Vars, nil
}
switch match.MatchErr {
case nil:
Expand Down
141 changes: 141 additions & 0 deletions routers/issue356_test.go
@@ -0,0 +1,141 @@
package routers_test

import (
"context"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"

"github.com/getkin/kin-openapi/openapi3"
"github.com/getkin/kin-openapi/openapi3filter"
"github.com/getkin/kin-openapi/routers"
"github.com/getkin/kin-openapi/routers/gorillamux"
"github.com/getkin/kin-openapi/routers/legacy"
"github.com/stretchr/testify/require"
)

func TestIssue356(t *testing.T) {
spec := func(servers string) []byte {
return []byte(`
openapi: 3.0.0
info:
title: Example
version: '1.0'
description: test
servers:
` + servers + `
paths:
/test:
post:
responses:
'201':
description: Created
content:
application/json:
schema: {type: object}
requestBody:
content:
application/json:
schema: {type: object}
description: ''
description: Create a test object
`)
}

for servers, expectError := range map[string]bool{
`
- url: http://localhost:3000/base
- url: /base
`: false,

`
- url: /base
- url: http://localhost:3000/base
`: false,

`- url: /base`: false,

`- url: http://localhost:3000/base`: true,

``: true,
} {
loader := &openapi3.Loader{Context: context.Background()}
t.Logf("using servers: %q (%v)", servers, expectError)
doc, err := loader.LoadFromData(spec(servers))
require.NoError(t, err)
err = doc.Validate(context.Background())
require.NoError(t, err)

for i, newRouter := range []func(*openapi3.T) (routers.Router, error){gorillamux.NewRouter, legacy.NewRouter} {
t.Logf("using NewRouter from %s", map[int]string{0: "gorillamux", 1: "legacy"}[i])
router, err := newRouter(doc)
require.NoError(t, err)

if true {
t.Logf("using naked newRouter")
httpReq, err := http.NewRequest(http.MethodPost, "/base/test", strings.NewReader(`{}`))
require.NoError(t, err)
httpReq.Header.Set("Content-Type", "application/json")

route, pathParams, err := router.FindRoute(httpReq)
if expectError {
require.Error(t, err, routers.ErrPathNotFound)
return
}
require.NoError(t, err)

requestValidationInput := &openapi3filter.RequestValidationInput{
Request: httpReq,
PathParams: pathParams,
Route: route,
}
err = openapi3filter.ValidateRequest(context.Background(), requestValidationInput)
require.NoError(t, err)
}

if true {
t.Logf("using httptest.NewServer")
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
route, pathParams, err := router.FindRoute(r)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}

requestValidationInput := &openapi3filter.RequestValidationInput{
Request: r,
PathParams: pathParams,
Route: route,
}
err = openapi3filter.ValidateRequest(r.Context(), requestValidationInput)
require.NoError(t, err)

w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{}"))
}))
defer ts.Close()

req, err := http.NewRequest(http.MethodPost, ts.URL+"/base/test", strings.NewReader(`{}`))
require.NoError(t, err)
req.Header.Set("Content-Type", "application/json")

rep, err := http.DefaultClient.Do(req)
require.NoError(t, err)
defer rep.Body.Close()
body, err := ioutil.ReadAll(rep.Body)
require.NoError(t, err)

if expectError {
require.Equal(t, 500, rep.StatusCode)
require.Equal(t, routers.ErrPathNotFound.Error(), string(body))
return
}
require.Equal(t, 200, rep.StatusCode)
require.Equal(t, "{}", string(body))
}
}
}
}
7 changes: 7 additions & 0 deletions routers/types.go
Expand Up @@ -8,6 +8,13 @@ import (

// Router helps link http.Request.s and an OpenAPIv3 spec
type Router interface {
// FindRoute matches an HTTP request with the operation it resolves to.
// Hosts are matched from the OpenAPIv3 servers key.
//
// If you experience ErrPathNotFound and have localhost hosts specified as your servers,
// turning these server URLs as relative (leaving only the path) should resolve this.
//
// See openapi3filter for example uses with request and response validation.
FindRoute(req *http.Request) (route *Route, pathParams map[string]string, err error)
}

Expand Down

0 comments on commit e4ff797

Please sign in to comment.