Skip to content

Request validation fails on localhost #118

@bjmc

Description

@bjmc

Hello, I'm not sure if this is a bug strictly-speaking, but we found it to be unexpected behavior.

Say you have a basic spec like this:

openapi: "3.0.0"
info:
  title: Simple API Example
  version: 0.1.0
servers:
- url: "https://example.com/api/"
  description: Deployed absolute URL
- url: "http://localhost:8080/"
  description: Running locally
paths:
  /:
    get:
      summary: Application health-check.
      responses:
        200:
          description: Application name and version.
          content:
            application/json:
              schema:
                properties:
                  data:
                    type: object
                    properties:
                      name:
                        type: string
                        example: "Sample App"
                      version:
                        type: string
                        example: "0.1.0"

And then a simple web app that includes validation using kin-openapi/openapi3filter:

package main

import (
	"context"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"path/filepath"

	"github.com/getkin/kin-openapi/openapi3filter"
)

func main() {
	// OpenAPIv3 request validation:
	specPath, _ := filepath.Abs("./spec.yaml")
	oa3router := openapi3filter.NewRouter().WithSwaggerFromFile(specPath)

	validationHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := context.TODO()
		log.Printf("request.URL is %s", r.URL)
		route, pathParams, _ := oa3router.FindRoute(r.Method, r.URL)
		// Validate request
		requestValidationInput := &openapi3filter.RequestValidationInput{
			Request:    r,
			PathParams: pathParams,
			Route:      route,
		}
		if err := openapi3filter.ValidateRequest(ctx, requestValidationInput); err != nil {
			w.WriteHeader(400)
			io.WriteString(w, err.Error()+"\n")
		} else {
			fmt.Fprint(w, "{\"version\": \"0.1.0\", \"name\": \"Sample App\"}\n")
		}
	})

	httpAddr := flag.String("http.addr", ":8080", "HTTP listen address")
	log.Printf("HTTP server starting on %v\n", *httpAddr)
	log.Fatal(http.ListenAndServe(*httpAddr, validationHandler))
}

If you run $ go run main.go and make a request using $ curl localhost:8080 you'll find you get an invalid route response.

The logging output is:

2019/09/27 14:24:17 HTTP server starting on :8080
2019/09/27 14:24:21 request.URL is /

As far as I can tell the issue is the same one described in this StackOverflow thread

what you get from Go's http.Request.URL is the raw URL (as parsed by the library). In the case you're getting, you're accessing the URL from a relative path, hence the lack of a Host or Scheme in the URL object.

Since the request is made from the same machine, it's only passing a relative URL, and openapi-kin doesn't know how to validate that request successfully. Even explicitly passing a Host header doesn't help:

$ curl localhost:8080/api -H 'Host: example.com'
invalid route

Maybe the FindRoute() method should take into account Host headers? Or maybe there's someplace that URL.ResolveReference() should be called and it's not?

I'm willing to work on putting together a PR, if there's consensus for what a good fix would look like. Otherwise, I'd just ask for extra documentation that kin-openapi validation doesn't work properly on localhost.

Thanks for your work on a very useful tool.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions