Skip to content

Commit

Permalink
canonicalize server URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
Johannes Koch committed May 17, 2021
1 parent 1da226a commit 4512e27
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
25 changes: 25 additions & 0 deletions handler/validation/openapi_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package validation
import (
"fmt"
"io/ioutil"
"net/url"
"path/filepath"

"github.com/getkin/kin-openapi/openapi3"
Expand Down Expand Up @@ -40,6 +41,26 @@ func NewOpenAPIOptions(openapi *config.OpenAPI) (*OpenAPIOptions, error) {
return NewOpenAPIOptionsFromBytes(openapi, b)
}

func canonicalizeServerURLs(swagger *openapi3.Swagger) error {
for _, server := range swagger.Servers {
su, err := url.Parse(server.URL)
if err != nil {
return err
}

if su.IsAbs() && su.Port() == "" && (su.Scheme == "https" || su.Scheme == "http") {
su.Host = su.Hostname() + ":"
if su.Scheme == "https" {
su.Host += "443"
} else {
su.Host += "80"
}
server.URL = su.String()
}
}
return nil
}

func NewOpenAPIOptionsFromBytes(openapi *config.OpenAPI, bytes []byte) (*OpenAPIOptions, error) {
if openapi == nil || bytes == nil {
return nil, nil
Expand All @@ -50,6 +71,10 @@ func NewOpenAPIOptionsFromBytes(openapi *config.OpenAPI, bytes []byte) (*OpenAPI
return nil, fmt.Errorf("error loading openapi file: %w", err)
}

if err = canonicalizeServerURLs(swagger); err != nil {
return nil, err
}

// Always buffer if openAPI is active. Request buffering is handled by openapifilter too.
// Anyway adding request buffer option to let Couper check the body limits.
bufferBodies := eval.BufferRequest | eval.BufferResponse
Expand Down
49 changes: 49 additions & 0 deletions handler/validation/openapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,52 @@ func TestOpenAPIValidator_RelativeServerURL(t *testing.T) {
}
})
}

func TestOpenAPIValidator_NonCanonicalServerURL(t *testing.T) {
helper := test.New(t)

log, hook := logrustest.NewNullLogger()
logger := log.WithContext(context.Background())
beConf := &config.Backend{
Remain: body.New(&hcl.BodyContent{Attributes: hcl.Attributes{
"origin": &hcl.Attribute{
Name: "origin",
Expr: hcltest.MockExprLiteral(cty.StringVal("https://httpbin.org")),
},
}}),
OpenAPI: &config.OpenAPI{
File: filepath.Join("testdata/backend_03_openapi.yaml"),
},
}
openAPI, err := validation.NewOpenAPIOptions(beConf.OpenAPI)
helper.Must(err)

backend := transport.NewBackend(beConf.Remain, &transport.Config{}, &transport.BackendOptions{
OpenAPI: openAPI,
}, logger)

tests := []struct {
name, url string
}{
{"http", "http://httpbin.org/anything"},
{"https", "https://httpbin.org/anything"},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, tt.url, nil)

hook.Reset()
_, err := backend.RoundTrip(req)
if err != nil {
helper.Must(err)
}

if t.Failed() {
for _, entry := range hook.Entries {
t.Log(entry.String())
}
}
})
}
}
13 changes: 13 additions & 0 deletions handler/validation/testdata/backend_03_openapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
openapi: '3'
info:
title: 'Couper backend validation test: non-canonical server URL'
version: 'v1.2.3'
servers:
- url: https://httpbin.org/
- url: http://httpbin.org/
paths:
/anything:
get:
responses:
200:
description: OK

0 comments on commit 4512e27

Please sign in to comment.