mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[chore] Bump go swagger (#2871)
* bump go swagger version * bump swagger version
This commit is contained in:
56
vendor/github.com/go-openapi/runtime/.golangci.yml
generated
vendored
56
vendor/github.com/go-openapi/runtime/.golangci.yml
generated
vendored
@ -1,44 +1,62 @@
|
||||
linters-settings:
|
||||
govet:
|
||||
# Using err repeatedly considered as shadowing.
|
||||
check-shadowing: false
|
||||
check-shadowing: true
|
||||
golint:
|
||||
min-confidence: 0
|
||||
gocyclo:
|
||||
min-complexity: 30
|
||||
min-complexity: 45
|
||||
maligned:
|
||||
suggest-new: true
|
||||
dupl:
|
||||
threshold: 100
|
||||
threshold: 200
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 4
|
||||
min-occurrences: 3
|
||||
|
||||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
- nilerr # nilerr crashes on this repo
|
||||
- maligned
|
||||
- unparam
|
||||
- lll
|
||||
- gochecknoinits
|
||||
- gochecknoglobals
|
||||
- funlen
|
||||
- godox
|
||||
- gocognit
|
||||
- whitespace
|
||||
- wsl
|
||||
- funlen
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- scopelint
|
||||
- wrapcheck
|
||||
- exhaustivestruct
|
||||
- exhaustive
|
||||
- nlreturn
|
||||
- testpackage
|
||||
- gci
|
||||
- gofumpt
|
||||
- goerr113
|
||||
- nlreturn
|
||||
- gomnd
|
||||
- tparallel
|
||||
- exhaustivestruct
|
||||
- goerr113
|
||||
- errorlint
|
||||
- nestif
|
||||
- godot
|
||||
- errorlint
|
||||
- noctx
|
||||
- gofumpt
|
||||
- paralleltest
|
||||
- tparallel
|
||||
- thelper
|
||||
- ifshort
|
||||
- exhaustruct
|
||||
- varnamelen
|
||||
- gci
|
||||
- depguard
|
||||
- errchkjson
|
||||
- inamedparam
|
||||
- nonamedreturns
|
||||
- musttag
|
||||
- ireturn
|
||||
- forcetypeassert
|
||||
- cyclop
|
||||
# deprecated linters
|
||||
- deadcode
|
||||
- interfacer
|
||||
- nilerr
|
||||
- scopelint
|
||||
- varcheck
|
||||
- structcheck
|
||||
- golint
|
||||
- nosnakecase
|
||||
|
11
vendor/github.com/go-openapi/runtime/README.md
generated
vendored
11
vendor/github.com/go-openapi/runtime/README.md
generated
vendored
@ -1,7 +1,10 @@
|
||||
# runtime [](https://travis-ci.org/go-openapi/runtime) [](https://codecov.io/gh/go-openapi/runtime) [](https://slackin.goswagger.io)
|
||||
# runtime [](https://github.com/go-openapi/runtime/actions?query=workflow%3A"go+test") [](https://codecov.io/gh/go-openapi/runtime)
|
||||
|
||||
[](https://raw.githubusercontent.com/go-openapi/runtime/master/LICENSE) [](http://godoc.org/github.com/go-openapi/runtime)
|
||||
[](https://slackin.goswagger.io)
|
||||
[](https://raw.githubusercontent.com/go-openapi/runtime/master/LICENSE)
|
||||
[](https://pkg.go.dev/github.com/go-openapi/runtime)
|
||||
[](https://goreportcard.com/report/github.com/go-openapi/runtime)
|
||||
|
||||
# golang Open-API toolkit - runtime
|
||||
# go OpenAPI toolkit runtime
|
||||
|
||||
The runtime component for use in codegeneration or as untyped usage.
|
||||
The runtime component for use in code generation or as untyped usage.
|
||||
|
149
vendor/github.com/go-openapi/runtime/bytestream.go
generated
vendored
149
vendor/github.com/go-openapi/runtime/bytestream.go
generated
vendored
@ -38,9 +38,16 @@ type byteStreamOpts struct {
|
||||
Close bool
|
||||
}
|
||||
|
||||
// ByteStreamConsumer creates a consumer for byte streams,
|
||||
// takes a Writer/BinaryUnmarshaler interface or binary slice by reference,
|
||||
// and reads from the provided reader
|
||||
// ByteStreamConsumer creates a consumer for byte streams.
|
||||
//
|
||||
// The consumer consumes from a provided reader into the data passed by reference.
|
||||
//
|
||||
// Supported output underlying types and interfaces, prioritized in this order:
|
||||
// - io.ReaderFrom (for maximum control)
|
||||
// - io.Writer (performs io.Copy)
|
||||
// - encoding.BinaryUnmarshaler
|
||||
// - *string
|
||||
// - *[]byte
|
||||
func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
|
||||
var vals byteStreamOpts
|
||||
for _, opt := range opts {
|
||||
@ -51,44 +58,70 @@ func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
|
||||
if reader == nil {
|
||||
return errors.New("ByteStreamConsumer requires a reader") // early exit
|
||||
}
|
||||
if data == nil {
|
||||
return errors.New("nil destination for ByteStreamConsumer")
|
||||
}
|
||||
|
||||
close := defaultCloser
|
||||
closer := defaultCloser
|
||||
if vals.Close {
|
||||
if cl, ok := reader.(io.Closer); ok {
|
||||
close = cl.Close
|
||||
if cl, isReaderCloser := reader.(io.Closer); isReaderCloser {
|
||||
closer = cl.Close
|
||||
}
|
||||
}
|
||||
//nolint:errcheck // closing a reader wouldn't fail.
|
||||
defer close()
|
||||
defer func() {
|
||||
_ = closer()
|
||||
}()
|
||||
|
||||
if wrtr, ok := data.(io.Writer); ok {
|
||||
_, err := io.Copy(wrtr, reader)
|
||||
if readerFrom, isReaderFrom := data.(io.ReaderFrom); isReaderFrom {
|
||||
_, err := readerFrom.ReadFrom(reader)
|
||||
return err
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if writer, isDataWriter := data.(io.Writer); isDataWriter {
|
||||
_, err := io.Copy(writer, reader)
|
||||
return err
|
||||
}
|
||||
|
||||
// buffers input before writing to data
|
||||
var buf bytes.Buffer
|
||||
_, err := buf.ReadFrom(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b := buf.Bytes()
|
||||
|
||||
if bu, ok := data.(encoding.BinaryUnmarshaler); ok {
|
||||
return bu.UnmarshalBinary(b)
|
||||
}
|
||||
switch destinationPointer := data.(type) {
|
||||
case encoding.BinaryUnmarshaler:
|
||||
return destinationPointer.UnmarshalBinary(b)
|
||||
case *any:
|
||||
switch (*destinationPointer).(type) {
|
||||
case string:
|
||||
*destinationPointer = string(b)
|
||||
|
||||
return nil
|
||||
|
||||
case []byte:
|
||||
*destinationPointer = b
|
||||
|
||||
if data != nil {
|
||||
if str, ok := data.(*string); ok {
|
||||
*str = string(b)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
default:
|
||||
// check for the underlying type to be pointer to []byte or string,
|
||||
if ptr := reflect.TypeOf(data); ptr.Kind() != reflect.Ptr {
|
||||
return errors.New("destination must be a pointer")
|
||||
}
|
||||
|
||||
if t := reflect.TypeOf(data); data != nil && t.Kind() == reflect.Ptr {
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
if t = v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
|
||||
t := v.Type()
|
||||
|
||||
switch {
|
||||
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
|
||||
v.SetBytes(b)
|
||||
return nil
|
||||
|
||||
case t.Kind() == reflect.String:
|
||||
v.SetString(string(b))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,67 +130,87 @@ func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
|
||||
})
|
||||
}
|
||||
|
||||
// ByteStreamProducer creates a producer for byte streams,
|
||||
// takes a Reader/BinaryMarshaler interface or binary slice,
|
||||
// and writes to a writer (essentially a pipe)
|
||||
// ByteStreamProducer creates a producer for byte streams.
|
||||
//
|
||||
// The producer takes input data then writes to an output writer (essentially as a pipe).
|
||||
//
|
||||
// Supported input underlying types and interfaces, prioritized in this order:
|
||||
// - io.WriterTo (for maximum control)
|
||||
// - io.Reader (performs io.Copy). A ReadCloser is closed before exiting.
|
||||
// - encoding.BinaryMarshaler
|
||||
// - error (writes as a string)
|
||||
// - []byte
|
||||
// - string
|
||||
// - struct, other slices: writes as JSON
|
||||
func ByteStreamProducer(opts ...byteStreamOpt) Producer {
|
||||
var vals byteStreamOpts
|
||||
for _, opt := range opts {
|
||||
opt(&vals)
|
||||
}
|
||||
|
||||
return ProducerFunc(func(writer io.Writer, data interface{}) error {
|
||||
if writer == nil {
|
||||
return errors.New("ByteStreamProducer requires a writer") // early exit
|
||||
}
|
||||
close := defaultCloser
|
||||
if data == nil {
|
||||
return errors.New("nil data for ByteStreamProducer")
|
||||
}
|
||||
|
||||
closer := defaultCloser
|
||||
if vals.Close {
|
||||
if cl, ok := writer.(io.Closer); ok {
|
||||
close = cl.Close
|
||||
if cl, isWriterCloser := writer.(io.Closer); isWriterCloser {
|
||||
closer = cl.Close
|
||||
}
|
||||
}
|
||||
//nolint:errcheck // TODO: closing a writer would fail.
|
||||
defer close()
|
||||
defer func() {
|
||||
_ = closer()
|
||||
}()
|
||||
|
||||
if rc, ok := data.(io.ReadCloser); ok {
|
||||
if rc, isDataCloser := data.(io.ReadCloser); isDataCloser {
|
||||
defer rc.Close()
|
||||
}
|
||||
|
||||
if rdr, ok := data.(io.Reader); ok {
|
||||
_, err := io.Copy(writer, rdr)
|
||||
switch origin := data.(type) {
|
||||
case io.WriterTo:
|
||||
_, err := origin.WriteTo(writer)
|
||||
return err
|
||||
}
|
||||
|
||||
if bm, ok := data.(encoding.BinaryMarshaler); ok {
|
||||
bytes, err := bm.MarshalBinary()
|
||||
case io.Reader:
|
||||
_, err := io.Copy(writer, origin)
|
||||
return err
|
||||
|
||||
case encoding.BinaryMarshaler:
|
||||
bytes, err := origin.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = writer.Write(bytes)
|
||||
return err
|
||||
}
|
||||
|
||||
if data != nil {
|
||||
if str, ok := data.(string); ok {
|
||||
_, err := writer.Write([]byte(str))
|
||||
return err
|
||||
}
|
||||
|
||||
if e, ok := data.(error); ok {
|
||||
_, err := writer.Write([]byte(e.Error()))
|
||||
return err
|
||||
}
|
||||
case error:
|
||||
_, err := writer.Write([]byte(origin.Error()))
|
||||
return err
|
||||
|
||||
default:
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
if t := v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
|
||||
t := v.Type()
|
||||
|
||||
switch {
|
||||
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
|
||||
_, err := writer.Write(v.Bytes())
|
||||
return err
|
||||
}
|
||||
if t := v.Type(); t.Kind() == reflect.Struct || t.Kind() == reflect.Slice {
|
||||
|
||||
case t.Kind() == reflect.String:
|
||||
_, err := writer.Write([]byte(v.String()))
|
||||
return err
|
||||
|
||||
case t.Kind() == reflect.Struct || t.Kind() == reflect.Slice:
|
||||
b, err := swag.WriteJSON(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = writer.Write(b)
|
||||
return err
|
||||
}
|
||||
|
4
vendor/github.com/go-openapi/runtime/client_operation.go
generated
vendored
4
vendor/github.com/go-openapi/runtime/client_operation.go
generated
vendored
@ -30,12 +30,12 @@ type ClientOperation struct {
|
||||
AuthInfo ClientAuthInfoWriter
|
||||
Params ClientRequestWriter
|
||||
Reader ClientResponseReader
|
||||
Context context.Context
|
||||
Context context.Context //nolint:containedctx // we precisely want this type to contain the request context
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
// A ClientTransport implementor knows how to submit Request objects to some destination
|
||||
type ClientTransport interface {
|
||||
//Submit(string, RequestWriter, ResponseReader, AuthInfoWriter) (interface{}, error)
|
||||
// Submit(string, RequestWriter, ResponseReader, AuthInfoWriter) (interface{}, error)
|
||||
Submit(*ClientOperation) (interface{}, error)
|
||||
}
|
||||
|
4
vendor/github.com/go-openapi/runtime/client_request.go
generated
vendored
4
vendor/github.com/go-openapi/runtime/client_request.go
generated
vendored
@ -37,8 +37,8 @@ type ClientRequestWriter interface {
|
||||
}
|
||||
|
||||
// ClientRequest is an interface for things that know how to
|
||||
// add information to a swagger client request
|
||||
type ClientRequest interface {
|
||||
// add information to a swagger client request.
|
||||
type ClientRequest interface { //nolint:interfacebloat // a swagger-capable request is quite rich, hence the many getter/setters
|
||||
SetHeaderParam(string, ...string) error
|
||||
|
||||
GetHeaderParams() http.Header
|
||||
|
337
vendor/github.com/go-openapi/runtime/csv.go
generated
vendored
337
vendor/github.com/go-openapi/runtime/csv.go
generated
vendored
@ -16,62 +16,335 @@ package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding"
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// CSVConsumer creates a new CSV consumer
|
||||
func CSVConsumer() Consumer {
|
||||
// CSVConsumer creates a new CSV consumer.
|
||||
//
|
||||
// The consumer consumes CSV records from a provided reader into the data passed by reference.
|
||||
//
|
||||
// CSVOpts options may be specified to alter the default CSV behavior on the reader and the writer side (e.g. separator, skip header, ...).
|
||||
// The defaults are those of the standard library's csv.Reader and csv.Writer.
|
||||
//
|
||||
// Supported output underlying types and interfaces, prioritized in this order:
|
||||
// - *csv.Writer
|
||||
// - CSVWriter (writer options are ignored)
|
||||
// - io.Writer (as raw bytes)
|
||||
// - io.ReaderFrom (as raw bytes)
|
||||
// - encoding.BinaryUnmarshaler (as raw bytes)
|
||||
// - *[][]string (as a collection of records)
|
||||
// - *[]byte (as raw bytes)
|
||||
// - *string (a raw bytes)
|
||||
//
|
||||
// The consumer prioritizes situations where buffering the input is not required.
|
||||
func CSVConsumer(opts ...CSVOpt) Consumer {
|
||||
o := csvOptsWithDefaults(opts)
|
||||
|
||||
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
|
||||
if reader == nil {
|
||||
return errors.New("CSVConsumer requires a reader")
|
||||
}
|
||||
if data == nil {
|
||||
return errors.New("nil destination for CSVConsumer")
|
||||
}
|
||||
|
||||
csvReader := csv.NewReader(reader)
|
||||
writer, ok := data.(io.Writer)
|
||||
if !ok {
|
||||
return errors.New("data type must be io.Writer")
|
||||
}
|
||||
csvWriter := csv.NewWriter(writer)
|
||||
records, err := csvReader.ReadAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range records {
|
||||
if err := csvWriter.Write(r); err != nil {
|
||||
return err
|
||||
o.applyToReader(csvReader)
|
||||
closer := defaultCloser
|
||||
if o.closeStream {
|
||||
if cl, isReaderCloser := reader.(io.Closer); isReaderCloser {
|
||||
closer = cl.Close
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
_ = closer()
|
||||
}()
|
||||
|
||||
switch destination := data.(type) {
|
||||
case *csv.Writer:
|
||||
csvWriter := destination
|
||||
o.applyToWriter(csvWriter)
|
||||
|
||||
return pipeCSV(csvWriter, csvReader, o)
|
||||
|
||||
case CSVWriter:
|
||||
csvWriter := destination
|
||||
// no writer options available
|
||||
|
||||
return pipeCSV(csvWriter, csvReader, o)
|
||||
|
||||
case io.Writer:
|
||||
csvWriter := csv.NewWriter(destination)
|
||||
o.applyToWriter(csvWriter)
|
||||
|
||||
return pipeCSV(csvWriter, csvReader, o)
|
||||
|
||||
case io.ReaderFrom:
|
||||
var buf bytes.Buffer
|
||||
csvWriter := csv.NewWriter(&buf)
|
||||
o.applyToWriter(csvWriter)
|
||||
if err := bufferedCSV(csvWriter, csvReader, o); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := destination.ReadFrom(&buf)
|
||||
|
||||
return err
|
||||
|
||||
case encoding.BinaryUnmarshaler:
|
||||
var buf bytes.Buffer
|
||||
csvWriter := csv.NewWriter(&buf)
|
||||
o.applyToWriter(csvWriter)
|
||||
if err := bufferedCSV(csvWriter, csvReader, o); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return destination.UnmarshalBinary(buf.Bytes())
|
||||
|
||||
default:
|
||||
// support *[][]string, *[]byte, *string
|
||||
if ptr := reflect.TypeOf(data); ptr.Kind() != reflect.Ptr {
|
||||
return errors.New("destination must be a pointer")
|
||||
}
|
||||
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
t := v.Type()
|
||||
|
||||
switch {
|
||||
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Slice && t.Elem().Elem().Kind() == reflect.String:
|
||||
csvWriter := &csvRecordsWriter{}
|
||||
// writer options are ignored
|
||||
if err := pipeCSV(csvWriter, csvReader, o); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.Grow(len(csvWriter.records))
|
||||
v.SetCap(len(csvWriter.records)) // in case Grow was unnessary, trim down the capacity
|
||||
v.SetLen(len(csvWriter.records))
|
||||
reflect.Copy(v, reflect.ValueOf(csvWriter.records))
|
||||
|
||||
return nil
|
||||
|
||||
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
|
||||
var buf bytes.Buffer
|
||||
csvWriter := csv.NewWriter(&buf)
|
||||
o.applyToWriter(csvWriter)
|
||||
if err := bufferedCSV(csvWriter, csvReader, o); err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetBytes(buf.Bytes())
|
||||
|
||||
return nil
|
||||
|
||||
case t.Kind() == reflect.String:
|
||||
var buf bytes.Buffer
|
||||
csvWriter := csv.NewWriter(&buf)
|
||||
o.applyToWriter(csvWriter)
|
||||
if err := bufferedCSV(csvWriter, csvReader, o); err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetString(buf.String())
|
||||
|
||||
return nil
|
||||
|
||||
default:
|
||||
return fmt.Errorf("%v (%T) is not supported by the CSVConsumer, %s",
|
||||
data, data, "can be resolved by supporting CSVWriter/Writer/BinaryUnmarshaler interface",
|
||||
)
|
||||
}
|
||||
}
|
||||
csvWriter.Flush()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// CSVProducer creates a new CSV producer
|
||||
func CSVProducer() Producer {
|
||||
// CSVProducer creates a new CSV producer.
|
||||
//
|
||||
// The producer takes input data then writes as CSV to an output writer (essentially as a pipe).
|
||||
//
|
||||
// Supported input underlying types and interfaces, prioritized in this order:
|
||||
// - *csv.Reader
|
||||
// - CSVReader (reader options are ignored)
|
||||
// - io.Reader
|
||||
// - io.WriterTo
|
||||
// - encoding.BinaryMarshaler
|
||||
// - [][]string
|
||||
// - []byte
|
||||
// - string
|
||||
//
|
||||
// The producer prioritizes situations where buffering the input is not required.
|
||||
func CSVProducer(opts ...CSVOpt) Producer {
|
||||
o := csvOptsWithDefaults(opts)
|
||||
|
||||
return ProducerFunc(func(writer io.Writer, data interface{}) error {
|
||||
if writer == nil {
|
||||
return errors.New("CSVProducer requires a writer")
|
||||
}
|
||||
|
||||
dataBytes, ok := data.([]byte)
|
||||
if !ok {
|
||||
return errors.New("data type must be byte array")
|
||||
if data == nil {
|
||||
return errors.New("nil data for CSVProducer")
|
||||
}
|
||||
|
||||
csvReader := csv.NewReader(bytes.NewBuffer(dataBytes))
|
||||
records, err := csvReader.ReadAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
csvWriter := csv.NewWriter(writer)
|
||||
for _, r := range records {
|
||||
if err := csvWriter.Write(r); err != nil {
|
||||
return err
|
||||
o.applyToWriter(csvWriter)
|
||||
closer := defaultCloser
|
||||
if o.closeStream {
|
||||
if cl, isWriterCloser := writer.(io.Closer); isWriterCloser {
|
||||
closer = cl.Close
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
_ = closer()
|
||||
}()
|
||||
|
||||
if rc, isDataCloser := data.(io.ReadCloser); isDataCloser {
|
||||
defer rc.Close()
|
||||
}
|
||||
|
||||
switch origin := data.(type) {
|
||||
case *csv.Reader:
|
||||
csvReader := origin
|
||||
o.applyToReader(csvReader)
|
||||
|
||||
return pipeCSV(csvWriter, csvReader, o)
|
||||
|
||||
case CSVReader:
|
||||
csvReader := origin
|
||||
// no reader options available
|
||||
|
||||
return pipeCSV(csvWriter, csvReader, o)
|
||||
|
||||
case io.Reader:
|
||||
csvReader := csv.NewReader(origin)
|
||||
o.applyToReader(csvReader)
|
||||
|
||||
return pipeCSV(csvWriter, csvReader, o)
|
||||
|
||||
case io.WriterTo:
|
||||
// async piping of the writes performed by WriteTo
|
||||
r, w := io.Pipe()
|
||||
csvReader := csv.NewReader(r)
|
||||
o.applyToReader(csvReader)
|
||||
|
||||
pipe, _ := errgroup.WithContext(context.Background())
|
||||
pipe.Go(func() error {
|
||||
_, err := origin.WriteTo(w)
|
||||
_ = w.Close()
|
||||
return err
|
||||
})
|
||||
|
||||
pipe.Go(func() error {
|
||||
defer func() {
|
||||
_ = r.Close()
|
||||
}()
|
||||
|
||||
return pipeCSV(csvWriter, csvReader, o)
|
||||
})
|
||||
|
||||
return pipe.Wait()
|
||||
|
||||
case encoding.BinaryMarshaler:
|
||||
buf, err := origin.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rdr := bytes.NewBuffer(buf)
|
||||
csvReader := csv.NewReader(rdr)
|
||||
|
||||
return bufferedCSV(csvWriter, csvReader, o)
|
||||
|
||||
default:
|
||||
// support [][]string, []byte, string (or pointers to those)
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
t := v.Type()
|
||||
|
||||
switch {
|
||||
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Slice && t.Elem().Elem().Kind() == reflect.String:
|
||||
csvReader := &csvRecordsWriter{
|
||||
records: make([][]string, v.Len()),
|
||||
}
|
||||
reflect.Copy(reflect.ValueOf(csvReader.records), v)
|
||||
|
||||
return pipeCSV(csvWriter, csvReader, o)
|
||||
|
||||
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
|
||||
buf := bytes.NewBuffer(v.Bytes())
|
||||
csvReader := csv.NewReader(buf)
|
||||
o.applyToReader(csvReader)
|
||||
|
||||
return bufferedCSV(csvWriter, csvReader, o)
|
||||
|
||||
case t.Kind() == reflect.String:
|
||||
buf := bytes.NewBufferString(v.String())
|
||||
csvReader := csv.NewReader(buf)
|
||||
o.applyToReader(csvReader)
|
||||
|
||||
return bufferedCSV(csvWriter, csvReader, o)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("%v (%T) is not supported by the CSVProducer, %s",
|
||||
data, data, "can be resolved by supporting CSVReader/Reader/BinaryMarshaler interface",
|
||||
)
|
||||
}
|
||||
}
|
||||
csvWriter.Flush()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// pipeCSV copies CSV records from a CSV reader to a CSV writer
|
||||
func pipeCSV(csvWriter CSVWriter, csvReader CSVReader, opts csvOpts) error {
|
||||
for ; opts.skippedLines > 0; opts.skippedLines-- {
|
||||
_, err := csvReader.Read()
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
record, err := csvReader.Read()
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if err := csvWriter.Write(record); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
csvWriter.Flush()
|
||||
|
||||
return csvWriter.Error()
|
||||
}
|
||||
|
||||
// bufferedCSV copies CSV records from a CSV reader to a CSV writer,
|
||||
// by first reading all records then writing them at once.
|
||||
func bufferedCSV(csvWriter *csv.Writer, csvReader *csv.Reader, opts csvOpts) error {
|
||||
for ; opts.skippedLines > 0; opts.skippedLines-- {
|
||||
_, err := csvReader.Read()
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
records, err := csvReader.ReadAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return csvWriter.WriteAll(records)
|
||||
}
|
||||
|
121
vendor/github.com/go-openapi/runtime/csv_options.go
generated
vendored
Normal file
121
vendor/github.com/go-openapi/runtime/csv_options.go
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"io"
|
||||
)
|
||||
|
||||
// CSVOpts alter the behavior of the CSV consumer or producer.
|
||||
type CSVOpt func(*csvOpts)
|
||||
|
||||
type csvOpts struct {
|
||||
csvReader csv.Reader
|
||||
csvWriter csv.Writer
|
||||
skippedLines int
|
||||
closeStream bool
|
||||
}
|
||||
|
||||
// WithCSVReaderOpts specifies the options to csv.Reader
|
||||
// when reading CSV.
|
||||
func WithCSVReaderOpts(reader csv.Reader) CSVOpt {
|
||||
return func(o *csvOpts) {
|
||||
o.csvReader = reader
|
||||
}
|
||||
}
|
||||
|
||||
// WithCSVWriterOpts specifies the options to csv.Writer
|
||||
// when writing CSV.
|
||||
func WithCSVWriterOpts(writer csv.Writer) CSVOpt {
|
||||
return func(o *csvOpts) {
|
||||
o.csvWriter = writer
|
||||
}
|
||||
}
|
||||
|
||||
// WithCSVSkipLines will skip header lines.
|
||||
func WithCSVSkipLines(skipped int) CSVOpt {
|
||||
return func(o *csvOpts) {
|
||||
o.skippedLines = skipped
|
||||
}
|
||||
}
|
||||
|
||||
func WithCSVClosesStream() CSVOpt {
|
||||
return func(o *csvOpts) {
|
||||
o.closeStream = true
|
||||
}
|
||||
}
|
||||
|
||||
func (o csvOpts) applyToReader(in *csv.Reader) {
|
||||
if o.csvReader.Comma != 0 {
|
||||
in.Comma = o.csvReader.Comma
|
||||
}
|
||||
if o.csvReader.Comment != 0 {
|
||||
in.Comment = o.csvReader.Comment
|
||||
}
|
||||
if o.csvReader.FieldsPerRecord != 0 {
|
||||
in.FieldsPerRecord = o.csvReader.FieldsPerRecord
|
||||
}
|
||||
|
||||
in.LazyQuotes = o.csvReader.LazyQuotes
|
||||
in.TrimLeadingSpace = o.csvReader.TrimLeadingSpace
|
||||
in.ReuseRecord = o.csvReader.ReuseRecord
|
||||
}
|
||||
|
||||
func (o csvOpts) applyToWriter(in *csv.Writer) {
|
||||
if o.csvWriter.Comma != 0 {
|
||||
in.Comma = o.csvWriter.Comma
|
||||
}
|
||||
in.UseCRLF = o.csvWriter.UseCRLF
|
||||
}
|
||||
|
||||
func csvOptsWithDefaults(opts []CSVOpt) csvOpts {
|
||||
var o csvOpts
|
||||
for _, apply := range opts {
|
||||
apply(&o)
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
type CSVWriter interface {
|
||||
Write([]string) error
|
||||
Flush()
|
||||
Error() error
|
||||
}
|
||||
|
||||
type CSVReader interface {
|
||||
Read() ([]string, error)
|
||||
}
|
||||
|
||||
var (
|
||||
_ CSVWriter = &csvRecordsWriter{}
|
||||
_ CSVReader = &csvRecordsWriter{}
|
||||
)
|
||||
|
||||
// csvRecordsWriter is an internal container to move CSV records back and forth
|
||||
type csvRecordsWriter struct {
|
||||
i int
|
||||
records [][]string
|
||||
}
|
||||
|
||||
func (w *csvRecordsWriter) Write(record []string) error {
|
||||
w.records = append(w.records, record)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *csvRecordsWriter) Read() ([]string, error) {
|
||||
if w.i >= len(w.records) {
|
||||
return nil, io.EOF
|
||||
}
|
||||
defer func() {
|
||||
w.i++
|
||||
}()
|
||||
|
||||
return w.records[w.i], nil
|
||||
}
|
||||
|
||||
func (w *csvRecordsWriter) Flush() {}
|
||||
|
||||
func (w *csvRecordsWriter) Error() error {
|
||||
return nil
|
||||
}
|
2
vendor/github.com/go-openapi/runtime/logger/standard.go
generated
vendored
2
vendor/github.com/go-openapi/runtime/logger/standard.go
generated
vendored
@ -5,6 +5,8 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var _ Logger = StandardLogger{}
|
||||
|
||||
type StandardLogger struct{}
|
||||
|
||||
func (StandardLogger) Printf(format string, args ...interface{}) {
|
||||
|
179
vendor/github.com/go-openapi/runtime/middleware/context.go
generated
vendored
179
vendor/github.com/go-openapi/runtime/middleware/context.go
generated
vendored
@ -18,6 +18,8 @@ import (
|
||||
stdContext "context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -35,12 +37,21 @@ import (
|
||||
|
||||
// Debug when true turns on verbose logging
|
||||
var Debug = logger.DebugEnabled()
|
||||
|
||||
// Logger is the standard libray logger used for printing debug messages
|
||||
var Logger logger.Logger = logger.StandardLogger{}
|
||||
|
||||
func debugLog(format string, args ...interface{}) {
|
||||
if Debug {
|
||||
Logger.Printf(format, args...)
|
||||
func debugLogfFunc(lg logger.Logger) func(string, ...any) {
|
||||
if logger.DebugEnabled() {
|
||||
if lg == nil {
|
||||
return Logger.Debugf
|
||||
}
|
||||
|
||||
return lg.Debugf
|
||||
}
|
||||
|
||||
// muted logger
|
||||
return func(_ string, _ ...any) {}
|
||||
}
|
||||
|
||||
// A Builder can create middlewares
|
||||
@ -73,10 +84,11 @@ func (fn ResponderFunc) WriteResponse(rw http.ResponseWriter, pr runtime.Produce
|
||||
// used throughout to store request context with the standard context attached
|
||||
// to the http.Request
|
||||
type Context struct {
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
api RoutableAPI
|
||||
router Router
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
api RoutableAPI
|
||||
router Router
|
||||
debugLogf func(string, ...any) // a logging function to debug context and all components using it
|
||||
}
|
||||
|
||||
type routableUntypedAPI struct {
|
||||
@ -162,7 +174,7 @@ func (r *routableUntypedAPI) HandlerFor(method, path string) (http.Handler, bool
|
||||
r.hlock.Unlock()
|
||||
return handler, ok
|
||||
}
|
||||
func (r *routableUntypedAPI) ServeErrorFor(operationID string) func(http.ResponseWriter, *http.Request, error) {
|
||||
func (r *routableUntypedAPI) ServeErrorFor(_ string) func(http.ResponseWriter, *http.Request, error) {
|
||||
return r.api.ServeError
|
||||
}
|
||||
func (r *routableUntypedAPI) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
|
||||
@ -189,7 +201,9 @@ func (r *routableUntypedAPI) DefaultConsumes() string {
|
||||
return r.defaultConsumes
|
||||
}
|
||||
|
||||
// NewRoutableContext creates a new context for a routable API
|
||||
// NewRoutableContext creates a new context for a routable API.
|
||||
//
|
||||
// If a nil Router is provided, the DefaultRouter (denco-based) will be used.
|
||||
func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Router) *Context {
|
||||
var an *analysis.Spec
|
||||
if spec != nil {
|
||||
@ -199,26 +213,40 @@ func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Ro
|
||||
return NewRoutableContextWithAnalyzedSpec(spec, an, routableAPI, routes)
|
||||
}
|
||||
|
||||
// NewRoutableContextWithAnalyzedSpec is like NewRoutableContext but takes in input the analysed spec too
|
||||
// NewRoutableContextWithAnalyzedSpec is like NewRoutableContext but takes as input an already analysed spec.
|
||||
//
|
||||
// If a nil Router is provided, the DefaultRouter (denco-based) will be used.
|
||||
func NewRoutableContextWithAnalyzedSpec(spec *loads.Document, an *analysis.Spec, routableAPI RoutableAPI, routes Router) *Context {
|
||||
// Either there are no spec doc and analysis, or both of them.
|
||||
if !((spec == nil && an == nil) || (spec != nil && an != nil)) {
|
||||
panic(errors.New(http.StatusInternalServerError, "routable context requires either both spec doc and analysis, or none of them"))
|
||||
}
|
||||
|
||||
ctx := &Context{spec: spec, api: routableAPI, analyzer: an, router: routes}
|
||||
return ctx
|
||||
return &Context{
|
||||
spec: spec,
|
||||
api: routableAPI,
|
||||
analyzer: an,
|
||||
router: routes,
|
||||
debugLogf: debugLogfFunc(nil),
|
||||
}
|
||||
}
|
||||
|
||||
// NewContext creates a new context wrapper
|
||||
// NewContext creates a new context wrapper.
|
||||
//
|
||||
// If a nil Router is provided, the DefaultRouter (denco-based) will be used.
|
||||
func NewContext(spec *loads.Document, api *untyped.API, routes Router) *Context {
|
||||
var an *analysis.Spec
|
||||
if spec != nil {
|
||||
an = analysis.New(spec.Spec())
|
||||
}
|
||||
ctx := &Context{spec: spec, analyzer: an}
|
||||
ctx := &Context{
|
||||
spec: spec,
|
||||
analyzer: an,
|
||||
router: routes,
|
||||
debugLogf: debugLogfFunc(nil),
|
||||
}
|
||||
ctx.api = newRoutableUntypedAPI(spec, api, ctx)
|
||||
ctx.router = routes
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
@ -282,6 +310,13 @@ func (c *Context) BasePath() string {
|
||||
return c.spec.BasePath()
|
||||
}
|
||||
|
||||
// SetLogger allows for injecting a logger to catch debug entries.
|
||||
//
|
||||
// The logger is enabled in DEBUG mode only.
|
||||
func (c *Context) SetLogger(lg logger.Logger) {
|
||||
c.debugLogf = debugLogfFunc(lg)
|
||||
}
|
||||
|
||||
// RequiredProduces returns the accepted content types for responses
|
||||
func (c *Context) RequiredProduces() []string {
|
||||
return c.analyzer.RequiredProduces()
|
||||
@ -299,6 +334,7 @@ func (c *Context) BindValidRequest(request *http.Request, route *MatchedRoute, b
|
||||
if err != nil {
|
||||
res = append(res, err)
|
||||
} else {
|
||||
c.debugLogf("validating content type for %q against [%s]", ct, strings.Join(route.Consumes, ", "))
|
||||
if err := validateContentType(route.Consumes, ct); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
@ -397,16 +433,16 @@ func (c *Context) ResponseFormat(r *http.Request, offers []string) (string, *htt
|
||||
var rCtx = r.Context()
|
||||
|
||||
if v, ok := rCtx.Value(ctxResponseFormat).(string); ok {
|
||||
debugLog("[%s %s] found response format %q in context", r.Method, r.URL.Path, v)
|
||||
c.debugLogf("[%s %s] found response format %q in context", r.Method, r.URL.Path, v)
|
||||
return v, r
|
||||
}
|
||||
|
||||
format := NegotiateContentType(r, offers, "")
|
||||
if format != "" {
|
||||
debugLog("[%s %s] set response format %q in context", r.Method, r.URL.Path, format)
|
||||
c.debugLogf("[%s %s] set response format %q in context", r.Method, r.URL.Path, format)
|
||||
r = r.WithContext(stdContext.WithValue(rCtx, ctxResponseFormat, format))
|
||||
}
|
||||
debugLog("[%s %s] negotiated response format %q", r.Method, r.URL.Path, format)
|
||||
c.debugLogf("[%s %s] negotiated response format %q", r.Method, r.URL.Path, format)
|
||||
return format, r
|
||||
}
|
||||
|
||||
@ -469,7 +505,7 @@ func (c *Context) BindAndValidate(request *http.Request, matched *MatchedRoute)
|
||||
var rCtx = request.Context()
|
||||
|
||||
if v, ok := rCtx.Value(ctxBoundParams).(*validation); ok {
|
||||
debugLog("got cached validation (valid: %t)", len(v.result) == 0)
|
||||
c.debugLogf("got cached validation (valid: %t)", len(v.result) == 0)
|
||||
if len(v.result) > 0 {
|
||||
return v.bound, request, errors.CompositeValidationError(v.result...)
|
||||
}
|
||||
@ -481,7 +517,7 @@ func (c *Context) BindAndValidate(request *http.Request, matched *MatchedRoute)
|
||||
if len(result.result) > 0 {
|
||||
return result.bound, request, errors.CompositeValidationError(result.result...)
|
||||
}
|
||||
debugLog("no validation errors found")
|
||||
c.debugLogf("no validation errors found")
|
||||
return result.bound, request, nil
|
||||
}
|
||||
|
||||
@ -492,7 +528,7 @@ func (c *Context) NotFound(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Respond renders the response after doing some content negotiation
|
||||
func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []string, route *MatchedRoute, data interface{}) {
|
||||
debugLog("responding to %s %s with produces: %v", r.Method, r.URL.Path, produces)
|
||||
c.debugLogf("responding to %s %s with produces: %v", r.Method, r.URL.Path, produces)
|
||||
offers := []string{}
|
||||
for _, mt := range produces {
|
||||
if mt != c.api.DefaultProduces() {
|
||||
@ -501,7 +537,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
|
||||
}
|
||||
// the default producer is last so more specific producers take precedence
|
||||
offers = append(offers, c.api.DefaultProduces())
|
||||
debugLog("offers: %v", offers)
|
||||
c.debugLogf("offers: %v", offers)
|
||||
|
||||
var format string
|
||||
format, r = c.ResponseFormat(r, offers)
|
||||
@ -516,7 +552,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
|
||||
prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
|
||||
pr, ok := prods[c.api.DefaultProduces()]
|
||||
if !ok {
|
||||
panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format))
|
||||
panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
|
||||
}
|
||||
prod = pr
|
||||
}
|
||||
@ -542,14 +578,14 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
|
||||
}
|
||||
|
||||
if route == nil || route.Operation == nil {
|
||||
rw.WriteHeader(200)
|
||||
if r.Method == "HEAD" {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
if r.Method == http.MethodHead {
|
||||
return
|
||||
}
|
||||
producers := c.api.ProducersFor(normalizeOffers(offers))
|
||||
prod, ok := producers[format]
|
||||
if !ok {
|
||||
panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format))
|
||||
panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
|
||||
}
|
||||
if err := prod.Produce(rw, data); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
@ -559,7 +595,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
|
||||
|
||||
if _, code, ok := route.Operation.SuccessResponse(); ok {
|
||||
rw.WriteHeader(code)
|
||||
if code == 204 || r.Method == "HEAD" {
|
||||
if code == http.StatusNoContent || r.Method == http.MethodHead {
|
||||
return
|
||||
}
|
||||
|
||||
@ -570,7 +606,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
|
||||
prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
|
||||
pr, ok := prods[c.api.DefaultProduces()]
|
||||
if !ok {
|
||||
panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format))
|
||||
panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
|
||||
}
|
||||
prod = pr
|
||||
}
|
||||
@ -584,45 +620,92 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
|
||||
c.api.ServeErrorFor(route.Operation.ID)(rw, r, errors.New(http.StatusInternalServerError, "can't produce response"))
|
||||
}
|
||||
|
||||
func (c *Context) APIHandlerSwaggerUI(builder Builder) http.Handler {
|
||||
// APIHandlerSwaggerUI returns a handler to serve the API.
|
||||
//
|
||||
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
|
||||
//
|
||||
// A spec UI (SwaggerUI) is served at {API base path}/docs and the spec document at /swagger.json
|
||||
// (these can be modified with uiOptions).
|
||||
func (c *Context) APIHandlerSwaggerUI(builder Builder, opts ...UIOption) http.Handler {
|
||||
b := builder
|
||||
if b == nil {
|
||||
b = PassthroughBuilder
|
||||
}
|
||||
|
||||
var title string
|
||||
sp := c.spec.Spec()
|
||||
if sp != nil && sp.Info != nil && sp.Info.Title != "" {
|
||||
title = sp.Info.Title
|
||||
}
|
||||
specPath, uiOpts, specOpts := c.uiOptionsForHandler(opts)
|
||||
var swaggerUIOpts SwaggerUIOpts
|
||||
fromCommonToAnyOptions(uiOpts, &swaggerUIOpts)
|
||||
|
||||
swaggerUIOpts := SwaggerUIOpts{
|
||||
BasePath: c.BasePath(),
|
||||
Title: title,
|
||||
}
|
||||
|
||||
return Spec("", c.spec.Raw(), SwaggerUI(swaggerUIOpts, c.RoutesHandler(b)))
|
||||
return Spec(specPath, c.spec.Raw(), SwaggerUI(swaggerUIOpts, c.RoutesHandler(b)), specOpts...)
|
||||
}
|
||||
|
||||
// APIHandler returns a handler to serve the API, this includes a swagger spec, router and the contract defined in the swagger spec
|
||||
func (c *Context) APIHandler(builder Builder) http.Handler {
|
||||
// APIHandlerRapiDoc returns a handler to serve the API.
|
||||
//
|
||||
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
|
||||
//
|
||||
// A spec UI (RapiDoc) is served at {API base path}/docs and the spec document at /swagger.json
|
||||
// (these can be modified with uiOptions).
|
||||
func (c *Context) APIHandlerRapiDoc(builder Builder, opts ...UIOption) http.Handler {
|
||||
b := builder
|
||||
if b == nil {
|
||||
b = PassthroughBuilder
|
||||
}
|
||||
|
||||
specPath, uiOpts, specOpts := c.uiOptionsForHandler(opts)
|
||||
var rapidocUIOpts RapiDocOpts
|
||||
fromCommonToAnyOptions(uiOpts, &rapidocUIOpts)
|
||||
|
||||
return Spec(specPath, c.spec.Raw(), RapiDoc(rapidocUIOpts, c.RoutesHandler(b)), specOpts...)
|
||||
}
|
||||
|
||||
// APIHandler returns a handler to serve the API.
|
||||
//
|
||||
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
|
||||
//
|
||||
// A spec UI (Redoc) is served at {API base path}/docs and the spec document at /swagger.json
|
||||
// (these can be modified with uiOptions).
|
||||
func (c *Context) APIHandler(builder Builder, opts ...UIOption) http.Handler {
|
||||
b := builder
|
||||
if b == nil {
|
||||
b = PassthroughBuilder
|
||||
}
|
||||
|
||||
specPath, uiOpts, specOpts := c.uiOptionsForHandler(opts)
|
||||
var redocOpts RedocOpts
|
||||
fromCommonToAnyOptions(uiOpts, &redocOpts)
|
||||
|
||||
return Spec(specPath, c.spec.Raw(), Redoc(redocOpts, c.RoutesHandler(b)), specOpts...)
|
||||
}
|
||||
|
||||
func (c Context) uiOptionsForHandler(opts []UIOption) (string, uiOptions, []SpecOption) {
|
||||
var title string
|
||||
sp := c.spec.Spec()
|
||||
if sp != nil && sp.Info != nil && sp.Info.Title != "" {
|
||||
title = sp.Info.Title
|
||||
}
|
||||
|
||||
redocOpts := RedocOpts{
|
||||
BasePath: c.BasePath(),
|
||||
Title: title,
|
||||
// default options (may be overridden)
|
||||
optsForContext := []UIOption{
|
||||
WithUIBasePath(c.BasePath()),
|
||||
WithUITitle(title),
|
||||
}
|
||||
optsForContext = append(optsForContext, opts...)
|
||||
uiOpts := uiOptionsWithDefaults(optsForContext)
|
||||
|
||||
// If spec URL is provided, there is a non-default path to serve the spec.
|
||||
// This makes sure that the UI middleware is aligned with the Spec middleware.
|
||||
u, _ := url.Parse(uiOpts.SpecURL)
|
||||
var specPath string
|
||||
if u != nil {
|
||||
specPath = u.Path
|
||||
}
|
||||
|
||||
return Spec("", c.spec.Raw(), Redoc(redocOpts, c.RoutesHandler(b)))
|
||||
pth, doc := path.Split(specPath)
|
||||
if pth == "." {
|
||||
pth = ""
|
||||
}
|
||||
|
||||
return pth, uiOpts, []SpecOption{WithSpecDocument(doc)}
|
||||
}
|
||||
|
||||
// RoutesHandler returns a handler to serve the API, just the routes and the contract defined in the swagger spec
|
||||
@ -633,3 +716,7 @@ func (c *Context) RoutesHandler(builder Builder) http.Handler {
|
||||
}
|
||||
return NewRouter(c, b(NewOperationExecutor(c)))
|
||||
}
|
||||
|
||||
func cantFindProducer(format string) string {
|
||||
return "can't find a producer for " + format
|
||||
}
|
||||
|
37
vendor/github.com/go-openapi/runtime/middleware/denco/router.go
generated
vendored
37
vendor/github.com/go-openapi/runtime/middleware/denco/router.go
generated
vendored
@ -2,6 +2,7 @@
|
||||
package denco
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
@ -29,13 +30,13 @@ const (
|
||||
|
||||
// Router represents a URL router.
|
||||
type Router struct {
|
||||
param *doubleArray
|
||||
// SizeHint expects the maximum number of path parameters in records to Build.
|
||||
// SizeHint will be used to determine the capacity of the memory to allocate.
|
||||
// By default, SizeHint will be determined from given records to Build.
|
||||
SizeHint int
|
||||
|
||||
static map[string]interface{}
|
||||
param *doubleArray
|
||||
}
|
||||
|
||||
// New returns a new Router.
|
||||
@ -51,7 +52,7 @@ func New() *Router {
|
||||
// params is a slice of the Param that arranged in the order in which parameters appeared.
|
||||
// e.g. when built routing path is "/path/to/:id/:name" and given path is "/path/to/1/alice". params order is [{"id": "1"}, {"name": "alice"}], not [{"name": "alice"}, {"id": "1"}].
|
||||
func (rt *Router) Lookup(path string) (data interface{}, params Params, found bool) {
|
||||
if data, found := rt.static[path]; found {
|
||||
if data, found = rt.static[path]; found {
|
||||
return data, nil, true
|
||||
}
|
||||
if len(rt.param.node) == 1 {
|
||||
@ -71,7 +72,7 @@ func (rt *Router) Lookup(path string) (data interface{}, params Params, found bo
|
||||
func (rt *Router) Build(records []Record) error {
|
||||
statics, params := makeRecords(records)
|
||||
if len(params) > MaxSize {
|
||||
return fmt.Errorf("denco: too many records")
|
||||
return errors.New("denco: too many records")
|
||||
}
|
||||
if rt.SizeHint < 0 {
|
||||
rt.SizeHint = 0
|
||||
@ -131,7 +132,8 @@ func newDoubleArray() *doubleArray {
|
||||
// baseCheck contains BASE, CHECK and Extra flags.
|
||||
// From the top, 22bits of BASE, 2bits of Extra flags and 8bits of CHECK.
|
||||
//
|
||||
// BASE (22bit) | Extra flags (2bit) | CHECK (8bit)
|
||||
// BASE (22bit) | Extra flags (2bit) | CHECK (8bit)
|
||||
//
|
||||
// |----------------------|--|--------|
|
||||
// 32 10 8 0
|
||||
type baseCheck uint32
|
||||
@ -196,24 +198,29 @@ func (da *doubleArray) lookup(path string, params []Param, idx int) (*node, []Pa
|
||||
if next := nextIndex(da.bc[idx].Base(), TerminationCharacter); next < len(da.bc) && da.bc[next].Check() == TerminationCharacter {
|
||||
return da.node[da.bc[next].Base()], params, true
|
||||
}
|
||||
|
||||
BACKTRACKING:
|
||||
for j := len(indices) - 1; j >= 0; j-- {
|
||||
i, idx := int(indices[j]>>32), int(indices[j]&0xffffffff)
|
||||
if da.bc[idx].IsSingleParam() {
|
||||
idx := nextIndex(da.bc[idx].Base(), ParamCharacter)
|
||||
if idx >= len(da.bc) {
|
||||
nextIdx := nextIndex(da.bc[idx].Base(), ParamCharacter)
|
||||
if nextIdx >= len(da.bc) {
|
||||
break
|
||||
}
|
||||
|
||||
next := NextSeparator(path, i)
|
||||
params := append(params, Param{Value: path[i:next]})
|
||||
if nd, params, found := da.lookup(path[next:], params, idx); found {
|
||||
return nd, params, true
|
||||
nextParams := params
|
||||
nextParams = append(nextParams, Param{Value: path[i:next]})
|
||||
if nd, nextNextParams, found := da.lookup(path[next:], nextParams, nextIdx); found {
|
||||
return nd, nextNextParams, true
|
||||
}
|
||||
}
|
||||
|
||||
if da.bc[idx].IsWildcardParam() {
|
||||
idx := nextIndex(da.bc[idx].Base(), WildcardCharacter)
|
||||
params := append(params, Param{Value: path[i:]})
|
||||
return da.node[da.bc[idx].Base()], params, true
|
||||
nextIdx := nextIndex(da.bc[idx].Base(), WildcardCharacter)
|
||||
nextParams := params
|
||||
nextParams = append(nextParams, Param{Value: path[i:]})
|
||||
return da.node[da.bc[nextIdx].Base()], nextParams, true
|
||||
}
|
||||
}
|
||||
return nil, nil, false
|
||||
@ -325,7 +332,7 @@ func (da *doubleArray) arrange(records []*record, idx, depth int, usedBase map[i
|
||||
}
|
||||
base = da.findBase(siblings, idx, usedBase)
|
||||
if base > MaxSize {
|
||||
return -1, nil, nil, fmt.Errorf("denco: too many elements of internal slice")
|
||||
return -1, nil, nil, errors.New("denco: too many elements of internal slice")
|
||||
}
|
||||
da.setBase(idx, base)
|
||||
return base, siblings, leaf, err
|
||||
@ -386,7 +393,7 @@ func makeSiblings(records []*record, depth int) (sib []sibling, leaf *record, er
|
||||
case pc == c:
|
||||
continue
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("denco: BUG: routing table hasn't been sorted")
|
||||
return nil, nil, errors.New("denco: BUG: routing table hasn't been sorted")
|
||||
}
|
||||
if n > 0 {
|
||||
sib[n-1].end = i
|
||||
@ -431,7 +438,7 @@ func makeRecords(srcs []Record) (statics, params []*record) {
|
||||
wildcardPrefix := string(SeparatorCharacter) + string(WildcardCharacter)
|
||||
restconfPrefix := string(PathParamCharacter) + string(ParamCharacter)
|
||||
for _, r := range srcs {
|
||||
if strings.Contains(r.Key, paramPrefix) || strings.Contains(r.Key, wildcardPrefix) ||strings.Contains(r.Key, restconfPrefix){
|
||||
if strings.Contains(r.Key, paramPrefix) || strings.Contains(r.Key, wildcardPrefix) || strings.Contains(r.Key, restconfPrefix) {
|
||||
r.Key += termChar
|
||||
params = append(params, &record{Record: r})
|
||||
} else {
|
||||
|
73
vendor/github.com/go-openapi/runtime/middleware/doc.go
generated
vendored
73
vendor/github.com/go-openapi/runtime/middleware/doc.go
generated
vendored
@ -12,51 +12,52 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*Package middleware provides the library with helper functions for serving swagger APIs.
|
||||
/*
|
||||
Package middleware provides the library with helper functions for serving swagger APIs.
|
||||
|
||||
Pseudo middleware handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
)
|
||||
"github.com/go-openapi/errors"
|
||||
)
|
||||
|
||||
func newCompleteMiddleware(ctx *Context) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
// use context to lookup routes
|
||||
if matched, ok := ctx.RouteInfo(r); ok {
|
||||
func newCompleteMiddleware(ctx *Context) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
// use context to lookup routes
|
||||
if matched, ok := ctx.RouteInfo(r); ok {
|
||||
|
||||
if matched.NeedsAuth() {
|
||||
if _, err := ctx.Authorize(r, matched); err != nil {
|
||||
ctx.Respond(rw, r, matched.Produces, matched, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if matched.NeedsAuth() {
|
||||
if _, err := ctx.Authorize(r, matched); err != nil {
|
||||
ctx.Respond(rw, r, matched.Produces, matched, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
bound, validation := ctx.BindAndValidate(r, matched)
|
||||
if validation != nil {
|
||||
ctx.Respond(rw, r, matched.Produces, matched, validation)
|
||||
return
|
||||
}
|
||||
bound, validation := ctx.BindAndValidate(r, matched)
|
||||
if validation != nil {
|
||||
ctx.Respond(rw, r, matched.Produces, matched, validation)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := matched.Handler.Handle(bound)
|
||||
if err != nil {
|
||||
ctx.Respond(rw, r, matched.Produces, matched, err)
|
||||
return
|
||||
}
|
||||
result, err := matched.Handler.Handle(bound)
|
||||
if err != nil {
|
||||
ctx.Respond(rw, r, matched.Produces, matched, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Respond(rw, r, matched.Produces, matched, result)
|
||||
return
|
||||
}
|
||||
ctx.Respond(rw, r, matched.Produces, matched, result)
|
||||
return
|
||||
}
|
||||
|
||||
// Not found, check if it exists in the other methods first
|
||||
if others := ctx.AllowedMethods(r); len(others) > 0 {
|
||||
ctx.Respond(rw, r, ctx.spec.RequiredProduces(), nil, errors.MethodNotAllowed(r.Method, others))
|
||||
return
|
||||
}
|
||||
ctx.Respond(rw, r, ctx.spec.RequiredProduces(), nil, errors.NotFound("path %s was not found", r.URL.Path))
|
||||
})
|
||||
}
|
||||
// Not found, check if it exists in the other methods first
|
||||
if others := ctx.AllowedMethods(r); len(others) > 0 {
|
||||
ctx.Respond(rw, r, ctx.spec.RequiredProduces(), nil, errors.MethodNotAllowed(r.Method, others))
|
||||
return
|
||||
}
|
||||
ctx.Respond(rw, r, ctx.spec.RequiredProduces(), nil, errors.NotFound("path %s was not found", r.URL.Path))
|
||||
})
|
||||
}
|
||||
*/
|
||||
package middleware
|
||||
|
9
vendor/github.com/go-openapi/runtime/middleware/go18.go
generated
vendored
9
vendor/github.com/go-openapi/runtime/middleware/go18.go
generated
vendored
@ -1,9 +0,0 @@
|
||||
// +build go1.8
|
||||
|
||||
package middleware
|
||||
|
||||
import "net/url"
|
||||
|
||||
func pathUnescape(path string) (string, error) {
|
||||
return url.PathUnescape(path)
|
||||
}
|
9
vendor/github.com/go-openapi/runtime/middleware/header/header.go
generated
vendored
9
vendor/github.com/go-openapi/runtime/middleware/header/header.go
generated
vendored
@ -195,7 +195,8 @@ func ParseAccept2(header http.Header, key string) (specs []AcceptSpec) {
|
||||
}
|
||||
|
||||
// ParseAccept parses Accept* headers.
|
||||
func ParseAccept(header http.Header, key string) (specs []AcceptSpec) {
|
||||
func ParseAccept(header http.Header, key string) []AcceptSpec {
|
||||
var specs []AcceptSpec
|
||||
loop:
|
||||
for _, s := range header[key] {
|
||||
for {
|
||||
@ -218,6 +219,7 @@ loop:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
specs = append(specs, spec)
|
||||
s = skipSpace(s)
|
||||
if !strings.HasPrefix(s, ",") {
|
||||
@ -226,7 +228,8 @@ loop:
|
||||
s = skipSpace(s[1:])
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
return specs
|
||||
}
|
||||
|
||||
func skipSpace(s string) (rest string) {
|
||||
@ -306,7 +309,7 @@ func expectTokenOrQuoted(s string) (value string, rest string) {
|
||||
p := make([]byte, len(s)-1)
|
||||
j := copy(p, s[:i])
|
||||
escape := true
|
||||
for i = i + 1; i < len(s); i++ {
|
||||
for i++; i < len(s); i++ {
|
||||
b := s[i]
|
||||
switch {
|
||||
case escape:
|
||||
|
22
vendor/github.com/go-openapi/runtime/middleware/parameter.go
generated
vendored
22
vendor/github.com/go-openapi/runtime/middleware/parameter.go
generated
vendored
@ -34,6 +34,11 @@ import (
|
||||
|
||||
const defaultMaxMemory = 32 << 20
|
||||
|
||||
const (
|
||||
typeString = "string"
|
||||
typeArray = "array"
|
||||
)
|
||||
|
||||
var textUnmarshalType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
|
||||
|
||||
func newUntypedParamBinder(param spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *untypedParamBinder {
|
||||
@ -66,7 +71,7 @@ func (p *untypedParamBinder) typeForSchema(tpe, format string, items *spec.Items
|
||||
case "boolean":
|
||||
return reflect.TypeOf(true)
|
||||
|
||||
case "string":
|
||||
case typeString:
|
||||
if tt, ok := p.formats.GetType(format); ok {
|
||||
return tt
|
||||
}
|
||||
@ -94,7 +99,7 @@ func (p *untypedParamBinder) typeForSchema(tpe, format string, items *spec.Items
|
||||
return reflect.TypeOf(float64(0))
|
||||
}
|
||||
|
||||
case "array":
|
||||
case typeArray:
|
||||
if items == nil {
|
||||
return nil
|
||||
}
|
||||
@ -119,7 +124,7 @@ func (p *untypedParamBinder) allowsMulti() bool {
|
||||
|
||||
func (p *untypedParamBinder) readValue(values runtime.Gettable, target reflect.Value) ([]string, bool, bool, error) {
|
||||
name, in, cf, tpe := p.parameter.Name, p.parameter.In, p.parameter.CollectionFormat, p.parameter.Type
|
||||
if tpe == "array" {
|
||||
if tpe == typeArray {
|
||||
if cf == "multi" {
|
||||
if !p.allowsMulti() {
|
||||
return nil, false, false, errors.InvalidCollectionFormat(name, in, cf)
|
||||
@ -208,10 +213,11 @@ func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams
|
||||
if ffErr != nil {
|
||||
if p.parameter.Required {
|
||||
return errors.NewParseError(p.Name, p.parameter.In, "", ffErr)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
target.Set(reflect.ValueOf(runtime.File{Data: file, Header: header}))
|
||||
return nil
|
||||
}
|
||||
@ -263,7 +269,7 @@ func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) bindValue(data []string, hasKey bool, target reflect.Value) error {
|
||||
if p.parameter.Type == "array" {
|
||||
if p.parameter.Type == typeArray {
|
||||
return p.setSliceFieldValue(target, p.parameter.Default, data, hasKey)
|
||||
}
|
||||
var d string
|
||||
@ -273,7 +279,7 @@ func (p *untypedParamBinder) bindValue(data []string, hasKey bool, target reflec
|
||||
return p.setFieldValue(target, p.parameter.Default, d, hasKey)
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue interface{}, data string, hasKey bool) error {
|
||||
func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue interface{}, data string, hasKey bool) error { //nolint:gocyclo
|
||||
tpe := p.parameter.Type
|
||||
if p.parameter.Format != "" {
|
||||
tpe = p.parameter.Format
|
||||
@ -317,7 +323,7 @@ func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue in
|
||||
return nil
|
||||
}
|
||||
|
||||
switch target.Kind() {
|
||||
switch target.Kind() { //nolint:exhaustive // we want to check only types that map from a swagger parameter
|
||||
case reflect.Bool:
|
||||
if data == "" {
|
||||
if target.CanSet() {
|
||||
|
9
vendor/github.com/go-openapi/runtime/middleware/pre_go18.go
generated
vendored
9
vendor/github.com/go-openapi/runtime/middleware/pre_go18.go
generated
vendored
@ -1,9 +0,0 @@
|
||||
// +build !go1.8
|
||||
|
||||
package middleware
|
||||
|
||||
import "net/url"
|
||||
|
||||
func pathUnescape(path string) (string, error) {
|
||||
return url.QueryUnescape(path)
|
||||
}
|
72
vendor/github.com/go-openapi/runtime/middleware/rapidoc.go
generated
vendored
72
vendor/github.com/go-openapi/runtime/middleware/rapidoc.go
generated
vendored
@ -10,67 +10,57 @@ import (
|
||||
|
||||
// RapiDocOpts configures the RapiDoc middlewares
|
||||
type RapiDocOpts struct {
|
||||
// BasePath for the UI path, defaults to: /
|
||||
// BasePath for the UI, defaults to: /
|
||||
BasePath string
|
||||
// Path combines with BasePath for the full UI path, defaults to: docs
|
||||
|
||||
// Path combines with BasePath to construct the path to the UI, defaults to: "docs".
|
||||
Path string
|
||||
// SpecURL the url to find the spec for
|
||||
|
||||
// SpecURL is the URL of the spec document.
|
||||
//
|
||||
// Defaults to: /swagger.json
|
||||
SpecURL string
|
||||
// RapiDocURL for the js that generates the rapidoc site, defaults to: https://cdn.jsdelivr.net/npm/rapidoc/bundles/rapidoc.standalone.js
|
||||
RapiDocURL string
|
||||
|
||||
// Title for the documentation site, default to: API documentation
|
||||
Title string
|
||||
|
||||
// Template specifies a custom template to serve the UI
|
||||
Template string
|
||||
|
||||
// RapiDocURL points to the js asset that generates the rapidoc site.
|
||||
//
|
||||
// Defaults to https://unpkg.com/rapidoc/dist/rapidoc-min.js
|
||||
RapiDocURL string
|
||||
}
|
||||
|
||||
// EnsureDefaults in case some options are missing
|
||||
func (r *RapiDocOpts) EnsureDefaults() {
|
||||
if r.BasePath == "" {
|
||||
r.BasePath = "/"
|
||||
}
|
||||
if r.Path == "" {
|
||||
r.Path = "docs"
|
||||
}
|
||||
if r.SpecURL == "" {
|
||||
r.SpecURL = "/swagger.json"
|
||||
}
|
||||
common := toCommonUIOptions(r)
|
||||
common.EnsureDefaults()
|
||||
fromCommonToAnyOptions(common, r)
|
||||
|
||||
// rapidoc-specifics
|
||||
if r.RapiDocURL == "" {
|
||||
r.RapiDocURL = rapidocLatest
|
||||
}
|
||||
if r.Title == "" {
|
||||
r.Title = "API documentation"
|
||||
if r.Template == "" {
|
||||
r.Template = rapidocTemplate
|
||||
}
|
||||
}
|
||||
|
||||
// RapiDoc creates a middleware to serve a documentation site for a swagger spec.
|
||||
// This allows for altering the spec before starting the http listener.
|
||||
//
|
||||
// This allows for altering the spec before starting the http listener.
|
||||
func RapiDoc(opts RapiDocOpts, next http.Handler) http.Handler {
|
||||
opts.EnsureDefaults()
|
||||
|
||||
pth := path.Join(opts.BasePath, opts.Path)
|
||||
tmpl := template.Must(template.New("rapidoc").Parse(rapidocTemplate))
|
||||
tmpl := template.Must(template.New("rapidoc").Parse(opts.Template))
|
||||
assets := bytes.NewBuffer(nil)
|
||||
if err := tmpl.Execute(assets, opts); err != nil {
|
||||
panic(fmt.Errorf("cannot execute template: %w", err))
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
_ = tmpl.Execute(buf, opts)
|
||||
b := buf.Bytes()
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == pth {
|
||||
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
||||
_, _ = rw.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
if next == nil {
|
||||
rw.Header().Set("Content-Type", "text/plain")
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
return serveUI(pth, assets.Bytes(), next)
|
||||
}
|
||||
|
||||
const (
|
||||
@ -79,7 +69,7 @@ const (
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ .Title }}</title>
|
||||
<meta charset="utf-8"> <!-- Important: rapi-doc uses utf8 charecters -->
|
||||
<meta charset="utf-8"> <!-- Important: rapi-doc uses utf8 characters -->
|
||||
<script type="module" src="{{ .RapiDocURL }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
69
vendor/github.com/go-openapi/runtime/middleware/redoc.go
generated
vendored
69
vendor/github.com/go-openapi/runtime/middleware/redoc.go
generated
vendored
@ -10,67 +10,58 @@ import (
|
||||
|
||||
// RedocOpts configures the Redoc middlewares
|
||||
type RedocOpts struct {
|
||||
// BasePath for the UI path, defaults to: /
|
||||
// BasePath for the UI, defaults to: /
|
||||
BasePath string
|
||||
// Path combines with BasePath for the full UI path, defaults to: docs
|
||||
|
||||
// Path combines with BasePath to construct the path to the UI, defaults to: "docs".
|
||||
Path string
|
||||
// SpecURL the url to find the spec for
|
||||
|
||||
// SpecURL is the URL of the spec document.
|
||||
//
|
||||
// Defaults to: /swagger.json
|
||||
SpecURL string
|
||||
// RedocURL for the js that generates the redoc site, defaults to: https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js
|
||||
RedocURL string
|
||||
|
||||
// Title for the documentation site, default to: API documentation
|
||||
Title string
|
||||
|
||||
// Template specifies a custom template to serve the UI
|
||||
Template string
|
||||
|
||||
// RedocURL points to the js that generates the redoc site.
|
||||
//
|
||||
// Defaults to: https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js
|
||||
RedocURL string
|
||||
}
|
||||
|
||||
// EnsureDefaults in case some options are missing
|
||||
func (r *RedocOpts) EnsureDefaults() {
|
||||
if r.BasePath == "" {
|
||||
r.BasePath = "/"
|
||||
}
|
||||
if r.Path == "" {
|
||||
r.Path = "docs"
|
||||
}
|
||||
if r.SpecURL == "" {
|
||||
r.SpecURL = "/swagger.json"
|
||||
}
|
||||
common := toCommonUIOptions(r)
|
||||
common.EnsureDefaults()
|
||||
fromCommonToAnyOptions(common, r)
|
||||
|
||||
// redoc-specifics
|
||||
if r.RedocURL == "" {
|
||||
r.RedocURL = redocLatest
|
||||
}
|
||||
if r.Title == "" {
|
||||
r.Title = "API documentation"
|
||||
if r.Template == "" {
|
||||
r.Template = redocTemplate
|
||||
}
|
||||
}
|
||||
|
||||
// Redoc creates a middleware to serve a documentation site for a swagger spec.
|
||||
// This allows for altering the spec before starting the http listener.
|
||||
//
|
||||
// This allows for altering the spec before starting the http listener.
|
||||
func Redoc(opts RedocOpts, next http.Handler) http.Handler {
|
||||
opts.EnsureDefaults()
|
||||
|
||||
pth := path.Join(opts.BasePath, opts.Path)
|
||||
tmpl := template.Must(template.New("redoc").Parse(redocTemplate))
|
||||
tmpl := template.Must(template.New("redoc").Parse(opts.Template))
|
||||
assets := bytes.NewBuffer(nil)
|
||||
if err := tmpl.Execute(assets, opts); err != nil {
|
||||
panic(fmt.Errorf("cannot execute template: %w", err))
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
_ = tmpl.Execute(buf, opts)
|
||||
b := buf.Bytes()
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == pth {
|
||||
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
||||
_, _ = rw.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
if next == nil {
|
||||
rw.Header().Set("Content-Type", "text/plain")
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
return serveUI(pth, assets.Bytes(), next)
|
||||
}
|
||||
|
||||
const (
|
||||
|
23
vendor/github.com/go-openapi/runtime/middleware/request.go
generated
vendored
23
vendor/github.com/go-openapi/runtime/middleware/request.go
generated
vendored
@ -19,10 +19,10 @@ import (
|
||||
"reflect"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/logger"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
// UntypedRequestBinder binds and validates the data from a http request
|
||||
@ -31,6 +31,7 @@ type UntypedRequestBinder struct {
|
||||
Parameters map[string]spec.Parameter
|
||||
Formats strfmt.Registry
|
||||
paramBinders map[string]*untypedParamBinder
|
||||
debugLogf func(string, ...any) // a logging function to debug context and all components using it
|
||||
}
|
||||
|
||||
// NewUntypedRequestBinder creates a new binder for reading a request.
|
||||
@ -44,6 +45,7 @@ func NewUntypedRequestBinder(parameters map[string]spec.Parameter, spec *spec.Sw
|
||||
paramBinders: binders,
|
||||
Spec: spec,
|
||||
Formats: formats,
|
||||
debugLogf: debugLogfFunc(nil),
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,10 +54,10 @@ func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RoutePara
|
||||
val := reflect.Indirect(reflect.ValueOf(data))
|
||||
isMap := val.Kind() == reflect.Map
|
||||
var result []error
|
||||
debugLog("binding %d parameters for %s %s", len(o.Parameters), request.Method, request.URL.EscapedPath())
|
||||
o.debugLogf("binding %d parameters for %s %s", len(o.Parameters), request.Method, request.URL.EscapedPath())
|
||||
for fieldName, param := range o.Parameters {
|
||||
binder := o.paramBinders[fieldName]
|
||||
debugLog("binding parameter %s for %s %s", fieldName, request.Method, request.URL.EscapedPath())
|
||||
o.debugLogf("binding parameter %s for %s %s", fieldName, request.Method, request.URL.EscapedPath())
|
||||
var target reflect.Value
|
||||
if !isMap {
|
||||
binder.Name = fieldName
|
||||
@ -65,7 +67,7 @@ func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RoutePara
|
||||
if isMap {
|
||||
tpe := binder.Type()
|
||||
if tpe == nil {
|
||||
if param.Schema.Type.Contains("array") {
|
||||
if param.Schema.Type.Contains(typeArray) {
|
||||
tpe = reflect.TypeOf([]interface{}{})
|
||||
} else {
|
||||
tpe = reflect.TypeOf(map[string]interface{}{})
|
||||
@ -102,3 +104,14 @@ func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RoutePara
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetLogger allows for injecting a logger to catch debug entries.
|
||||
//
|
||||
// The logger is enabled in DEBUG mode only.
|
||||
func (o *UntypedRequestBinder) SetLogger(lg logger.Logger) {
|
||||
o.debugLogf = debugLogfFunc(lg)
|
||||
}
|
||||
|
||||
func (o *UntypedRequestBinder) setDebugLogf(fn func(string, ...any)) {
|
||||
o.debugLogf = fn
|
||||
}
|
||||
|
109
vendor/github.com/go-openapi/runtime/middleware/router.go
generated
vendored
109
vendor/github.com/go-openapi/runtime/middleware/router.go
generated
vendored
@ -17,10 +17,12 @@ package middleware
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
fpath "path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/runtime/logger"
|
||||
"github.com/go-openapi/runtime/security"
|
||||
"github.com/go-openapi/swag"
|
||||
|
||||
@ -67,10 +69,10 @@ func (r RouteParams) GetOK(name string) ([]string, bool, bool) {
|
||||
return nil, false, false
|
||||
}
|
||||
|
||||
// NewRouter creates a new context aware router middleware
|
||||
// NewRouter creates a new context-aware router middleware
|
||||
func NewRouter(ctx *Context, next http.Handler) http.Handler {
|
||||
if ctx.router == nil {
|
||||
ctx.router = DefaultRouter(ctx.spec, ctx.api)
|
||||
ctx.router = DefaultRouter(ctx.spec, ctx.api, WithDefaultRouterLoggerFunc(ctx.debugLogf))
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
@ -103,41 +105,75 @@ type RoutableAPI interface {
|
||||
DefaultConsumes() string
|
||||
}
|
||||
|
||||
// Router represents a swagger aware router
|
||||
// Router represents a swagger-aware router
|
||||
type Router interface {
|
||||
Lookup(method, path string) (*MatchedRoute, bool)
|
||||
OtherMethods(method, path string) []string
|
||||
}
|
||||
|
||||
type defaultRouteBuilder struct {
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
api RoutableAPI
|
||||
records map[string][]denco.Record
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
api RoutableAPI
|
||||
records map[string][]denco.Record
|
||||
debugLogf func(string, ...any) // a logging function to debug context and all components using it
|
||||
}
|
||||
|
||||
type defaultRouter struct {
|
||||
spec *loads.Document
|
||||
routers map[string]*denco.Router
|
||||
spec *loads.Document
|
||||
routers map[string]*denco.Router
|
||||
debugLogf func(string, ...any) // a logging function to debug context and all components using it
|
||||
}
|
||||
|
||||
func newDefaultRouteBuilder(spec *loads.Document, api RoutableAPI) *defaultRouteBuilder {
|
||||
func newDefaultRouteBuilder(spec *loads.Document, api RoutableAPI, opts ...DefaultRouterOpt) *defaultRouteBuilder {
|
||||
var o defaultRouterOpts
|
||||
for _, apply := range opts {
|
||||
apply(&o)
|
||||
}
|
||||
if o.debugLogf == nil {
|
||||
o.debugLogf = debugLogfFunc(nil) // defaults to standard logger
|
||||
}
|
||||
|
||||
return &defaultRouteBuilder{
|
||||
spec: spec,
|
||||
analyzer: analysis.New(spec.Spec()),
|
||||
api: api,
|
||||
records: make(map[string][]denco.Record),
|
||||
spec: spec,
|
||||
analyzer: analysis.New(spec.Spec()),
|
||||
api: api,
|
||||
records: make(map[string][]denco.Record),
|
||||
debugLogf: o.debugLogf,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultRouter creates a default implemenation of the router
|
||||
func DefaultRouter(spec *loads.Document, api RoutableAPI) Router {
|
||||
builder := newDefaultRouteBuilder(spec, api)
|
||||
// DefaultRouterOpt allows to inject optional behavior to the default router.
|
||||
type DefaultRouterOpt func(*defaultRouterOpts)
|
||||
|
||||
type defaultRouterOpts struct {
|
||||
debugLogf func(string, ...any)
|
||||
}
|
||||
|
||||
// WithDefaultRouterLogger sets the debug logger for the default router.
|
||||
//
|
||||
// This is enabled only in DEBUG mode.
|
||||
func WithDefaultRouterLogger(lg logger.Logger) DefaultRouterOpt {
|
||||
return func(o *defaultRouterOpts) {
|
||||
o.debugLogf = debugLogfFunc(lg)
|
||||
}
|
||||
}
|
||||
|
||||
// WithDefaultRouterLoggerFunc sets a logging debug method for the default router.
|
||||
func WithDefaultRouterLoggerFunc(fn func(string, ...any)) DefaultRouterOpt {
|
||||
return func(o *defaultRouterOpts) {
|
||||
o.debugLogf = fn
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultRouter creates a default implementation of the router
|
||||
func DefaultRouter(spec *loads.Document, api RoutableAPI, opts ...DefaultRouterOpt) Router {
|
||||
builder := newDefaultRouteBuilder(spec, api, opts...)
|
||||
if spec != nil {
|
||||
for method, paths := range builder.analyzer.Operations() {
|
||||
for path, operation := range paths {
|
||||
fp := fpath.Join(spec.BasePath(), path)
|
||||
debugLog("adding route %s %s %q", method, fp, operation.ID)
|
||||
builder.debugLogf("adding route %s %s %q", method, fp, operation.ID)
|
||||
builder.AddRoute(method, fp, operation)
|
||||
}
|
||||
}
|
||||
@ -319,24 +355,24 @@ func (m *MatchedRoute) NeedsAuth() bool {
|
||||
|
||||
func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) {
|
||||
mth := strings.ToUpper(method)
|
||||
debugLog("looking up route for %s %s", method, path)
|
||||
d.debugLogf("looking up route for %s %s", method, path)
|
||||
if Debug {
|
||||
if len(d.routers) == 0 {
|
||||
debugLog("there are no known routers")
|
||||
d.debugLogf("there are no known routers")
|
||||
}
|
||||
for meth := range d.routers {
|
||||
debugLog("got a router for %s", meth)
|
||||
d.debugLogf("got a router for %s", meth)
|
||||
}
|
||||
}
|
||||
if router, ok := d.routers[mth]; ok {
|
||||
if m, rp, ok := router.Lookup(fpath.Clean(path)); ok && m != nil {
|
||||
if entry, ok := m.(*routeEntry); ok {
|
||||
debugLog("found a route for %s %s with %d parameters", method, path, len(entry.Parameters))
|
||||
d.debugLogf("found a route for %s %s with %d parameters", method, path, len(entry.Parameters))
|
||||
var params RouteParams
|
||||
for _, p := range rp {
|
||||
v, err := pathUnescape(p.Value)
|
||||
v, err := url.PathUnescape(p.Value)
|
||||
if err != nil {
|
||||
debugLog("failed to escape %q: %v", p.Value, err)
|
||||
d.debugLogf("failed to escape %q: %v", p.Value, err)
|
||||
v = p.Value
|
||||
}
|
||||
// a workaround to handle fragment/composing parameters until they are supported in denco router
|
||||
@ -356,10 +392,10 @@ func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) {
|
||||
return &MatchedRoute{routeEntry: *entry, Params: params}, true
|
||||
}
|
||||
} else {
|
||||
debugLog("couldn't find a route by path for %s %s", method, path)
|
||||
d.debugLogf("couldn't find a route by path for %s %s", method, path)
|
||||
}
|
||||
} else {
|
||||
debugLog("couldn't find a route by method for %s %s", method, path)
|
||||
d.debugLogf("couldn't find a route by method for %s %s", method, path)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@ -378,6 +414,10 @@ func (d *defaultRouter) OtherMethods(method, path string) []string {
|
||||
return methods
|
||||
}
|
||||
|
||||
func (d *defaultRouter) SetLogger(lg logger.Logger) {
|
||||
d.debugLogf = debugLogfFunc(lg)
|
||||
}
|
||||
|
||||
// convert swagger parameters per path segment into a denco parameter as multiple parameters per segment are not supported in denco
|
||||
var pathConverter = regexp.MustCompile(`{(.+?)}([^/]*)`)
|
||||
|
||||
@ -413,7 +453,7 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
|
||||
bp = bp[:len(bp)-1]
|
||||
}
|
||||
|
||||
debugLog("operation: %#v", *operation)
|
||||
d.debugLogf("operation: %#v", *operation)
|
||||
if handler, ok := d.api.HandlerFor(method, strings.TrimPrefix(path, bp)); ok {
|
||||
consumes := d.analyzer.ConsumesFor(operation)
|
||||
produces := d.analyzer.ProducesFor(operation)
|
||||
@ -428,6 +468,8 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
|
||||
produces = append(produces, defProduces)
|
||||
}
|
||||
|
||||
requestBinder := NewUntypedRequestBinder(parameters, d.spec.Spec(), d.api.Formats())
|
||||
requestBinder.setDebugLogf(d.debugLogf)
|
||||
record := denco.NewRecord(pathConverter.ReplaceAllString(path, ":$1"), &routeEntry{
|
||||
BasePath: bp,
|
||||
PathPattern: path,
|
||||
@ -439,7 +481,7 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
|
||||
Producers: d.api.ProducersFor(normalizeOffers(produces)),
|
||||
Parameters: parameters,
|
||||
Formats: d.api.Formats(),
|
||||
Binder: NewUntypedRequestBinder(parameters, d.spec.Spec(), d.api.Formats()),
|
||||
Binder: requestBinder,
|
||||
Authenticators: d.buildAuthenticators(operation),
|
||||
Authorizer: d.api.Authorizer(),
|
||||
})
|
||||
@ -449,11 +491,11 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
|
||||
|
||||
func (d *defaultRouteBuilder) buildAuthenticators(operation *spec.Operation) RouteAuthenticators {
|
||||
requirements := d.analyzer.SecurityRequirementsFor(operation)
|
||||
var auths []RouteAuthenticator
|
||||
auths := make([]RouteAuthenticator, 0, len(requirements))
|
||||
for _, reqs := range requirements {
|
||||
var schemes []string
|
||||
schemes := make([]string, 0, len(reqs))
|
||||
scopes := make(map[string][]string, len(reqs))
|
||||
var scopeSlices [][]string
|
||||
scopeSlices := make([][]string, 0, len(reqs))
|
||||
for _, req := range reqs {
|
||||
schemes = append(schemes, req.Name)
|
||||
scopes[req.Name] = req.Scopes
|
||||
@ -482,7 +524,8 @@ func (d *defaultRouteBuilder) Build() *defaultRouter {
|
||||
routers[method] = router
|
||||
}
|
||||
return &defaultRouter{
|
||||
spec: d.spec,
|
||||
routers: routers,
|
||||
spec: d.spec,
|
||||
routers: routers,
|
||||
debugLogf: d.debugLogf,
|
||||
}
|
||||
}
|
||||
|
78
vendor/github.com/go-openapi/runtime/middleware/spec.go
generated
vendored
78
vendor/github.com/go-openapi/runtime/middleware/spec.go
generated
vendored
@ -19,30 +19,84 @@ import (
|
||||
"path"
|
||||
)
|
||||
|
||||
// Spec creates a middleware to serve a swagger spec.
|
||||
// This allows for altering the spec before starting the http listener.
|
||||
// This can be useful if you want to serve the swagger spec from another path than /swagger.json
|
||||
const (
|
||||
contentTypeHeader = "Content-Type"
|
||||
applicationJSON = "application/json"
|
||||
)
|
||||
|
||||
// SpecOption can be applied to the Spec serving middleware
|
||||
type SpecOption func(*specOptions)
|
||||
|
||||
var defaultSpecOptions = specOptions{
|
||||
Path: "",
|
||||
Document: "swagger.json",
|
||||
}
|
||||
|
||||
type specOptions struct {
|
||||
Path string
|
||||
Document string
|
||||
}
|
||||
|
||||
func specOptionsWithDefaults(opts []SpecOption) specOptions {
|
||||
o := defaultSpecOptions
|
||||
for _, apply := range opts {
|
||||
apply(&o)
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
// Spec creates a middleware to serve a swagger spec as a JSON document.
|
||||
//
|
||||
func Spec(basePath string, b []byte, next http.Handler) http.Handler {
|
||||
// This allows for altering the spec before starting the http listener.
|
||||
//
|
||||
// The basePath argument indicates the path of the spec document (defaults to "/").
|
||||
// Additional SpecOption can be used to change the name of the document (defaults to "swagger.json").
|
||||
func Spec(basePath string, b []byte, next http.Handler, opts ...SpecOption) http.Handler {
|
||||
if basePath == "" {
|
||||
basePath = "/"
|
||||
}
|
||||
pth := path.Join(basePath, "swagger.json")
|
||||
o := specOptionsWithDefaults(opts)
|
||||
pth := path.Join(basePath, o.Path, o.Document)
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == pth {
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
if path.Clean(r.URL.Path) == pth {
|
||||
rw.Header().Set(contentTypeHeader, applicationJSON)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
//#nosec
|
||||
_, _ = rw.Write(b)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if next == nil {
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
if next != nil {
|
||||
next.ServeHTTP(rw, r)
|
||||
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(rw, r)
|
||||
|
||||
rw.Header().Set(contentTypeHeader, applicationJSON)
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
})
|
||||
}
|
||||
|
||||
// WithSpecPath sets the path to be joined to the base path of the Spec middleware.
|
||||
//
|
||||
// This is empty by default.
|
||||
func WithSpecPath(pth string) SpecOption {
|
||||
return func(o *specOptions) {
|
||||
o.Path = pth
|
||||
}
|
||||
}
|
||||
|
||||
// WithSpecDocument sets the name of the JSON document served as a spec.
|
||||
//
|
||||
// By default, this is "swagger.json"
|
||||
func WithSpecDocument(doc string) SpecOption {
|
||||
return func(o *specOptions) {
|
||||
if doc == "" {
|
||||
return
|
||||
}
|
||||
|
||||
o.Document = doc
|
||||
}
|
||||
}
|
||||
|
87
vendor/github.com/go-openapi/runtime/middleware/swaggerui.go
generated
vendored
87
vendor/github.com/go-openapi/runtime/middleware/swaggerui.go
generated
vendored
@ -8,40 +8,65 @@ import (
|
||||
"path"
|
||||
)
|
||||
|
||||
// SwaggerUIOpts configures the Swaggerui middlewares
|
||||
// SwaggerUIOpts configures the SwaggerUI middleware
|
||||
type SwaggerUIOpts struct {
|
||||
// BasePath for the UI path, defaults to: /
|
||||
// BasePath for the API, defaults to: /
|
||||
BasePath string
|
||||
// Path combines with BasePath for the full UI path, defaults to: docs
|
||||
|
||||
// Path combines with BasePath to construct the path to the UI, defaults to: "docs".
|
||||
Path string
|
||||
// SpecURL the url to find the spec for
|
||||
|
||||
// SpecURL is the URL of the spec document.
|
||||
//
|
||||
// Defaults to: /swagger.json
|
||||
SpecURL string
|
||||
|
||||
// Title for the documentation site, default to: API documentation
|
||||
Title string
|
||||
|
||||
// Template specifies a custom template to serve the UI
|
||||
Template string
|
||||
|
||||
// OAuthCallbackURL the url called after OAuth2 login
|
||||
OAuthCallbackURL string
|
||||
|
||||
// The three components needed to embed swagger-ui
|
||||
SwaggerURL string
|
||||
|
||||
// SwaggerURL points to the js that generates the SwaggerUI site.
|
||||
//
|
||||
// Defaults to: https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js
|
||||
SwaggerURL string
|
||||
|
||||
SwaggerPresetURL string
|
||||
SwaggerStylesURL string
|
||||
|
||||
Favicon32 string
|
||||
Favicon16 string
|
||||
|
||||
// Title for the documentation site, default to: API documentation
|
||||
Title string
|
||||
}
|
||||
|
||||
// EnsureDefaults in case some options are missing
|
||||
func (r *SwaggerUIOpts) EnsureDefaults() {
|
||||
if r.BasePath == "" {
|
||||
r.BasePath = "/"
|
||||
r.ensureDefaults()
|
||||
|
||||
if r.Template == "" {
|
||||
r.Template = swaggeruiTemplate
|
||||
}
|
||||
if r.Path == "" {
|
||||
r.Path = "docs"
|
||||
}
|
||||
if r.SpecURL == "" {
|
||||
r.SpecURL = "/swagger.json"
|
||||
}
|
||||
|
||||
func (r *SwaggerUIOpts) EnsureDefaultsOauth2() {
|
||||
r.ensureDefaults()
|
||||
|
||||
if r.Template == "" {
|
||||
r.Template = swaggerOAuthTemplate
|
||||
}
|
||||
}
|
||||
|
||||
func (r *SwaggerUIOpts) ensureDefaults() {
|
||||
common := toCommonUIOptions(r)
|
||||
common.EnsureDefaults()
|
||||
fromCommonToAnyOptions(common, r)
|
||||
|
||||
// swaggerui-specifics
|
||||
if r.OAuthCallbackURL == "" {
|
||||
r.OAuthCallbackURL = path.Join(r.BasePath, r.Path, "oauth2-callback")
|
||||
}
|
||||
@ -60,40 +85,22 @@ func (r *SwaggerUIOpts) EnsureDefaults() {
|
||||
if r.Favicon32 == "" {
|
||||
r.Favicon32 = swaggerFavicon32Latest
|
||||
}
|
||||
if r.Title == "" {
|
||||
r.Title = "API documentation"
|
||||
}
|
||||
}
|
||||
|
||||
// SwaggerUI creates a middleware to serve a documentation site for a swagger spec.
|
||||
//
|
||||
// This allows for altering the spec before starting the http listener.
|
||||
func SwaggerUI(opts SwaggerUIOpts, next http.Handler) http.Handler {
|
||||
opts.EnsureDefaults()
|
||||
|
||||
pth := path.Join(opts.BasePath, opts.Path)
|
||||
tmpl := template.Must(template.New("swaggerui").Parse(swaggeruiTemplate))
|
||||
tmpl := template.Must(template.New("swaggerui").Parse(opts.Template))
|
||||
assets := bytes.NewBuffer(nil)
|
||||
if err := tmpl.Execute(assets, opts); err != nil {
|
||||
panic(fmt.Errorf("cannot execute template: %w", err))
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
_ = tmpl.Execute(buf, &opts)
|
||||
b := buf.Bytes()
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if path.Join(r.URL.Path) == pth {
|
||||
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
||||
_, _ = rw.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
if next == nil {
|
||||
rw.Header().Set("Content-Type", "text/plain")
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
return serveUI(pth, assets.Bytes(), next)
|
||||
}
|
||||
|
||||
const (
|
||||
|
31
vendor/github.com/go-openapi/runtime/middleware/swaggerui_oauth2.go
generated
vendored
31
vendor/github.com/go-openapi/runtime/middleware/swaggerui_oauth2.go
generated
vendored
@ -4,37 +4,20 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func SwaggerUIOAuth2Callback(opts SwaggerUIOpts, next http.Handler) http.Handler {
|
||||
opts.EnsureDefaults()
|
||||
opts.EnsureDefaultsOauth2()
|
||||
|
||||
pth := opts.OAuthCallbackURL
|
||||
tmpl := template.Must(template.New("swaggeroauth").Parse(swaggerOAuthTemplate))
|
||||
tmpl := template.Must(template.New("swaggeroauth").Parse(opts.Template))
|
||||
assets := bytes.NewBuffer(nil)
|
||||
if err := tmpl.Execute(assets, opts); err != nil {
|
||||
panic(fmt.Errorf("cannot execute template: %w", err))
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
_ = tmpl.Execute(buf, &opts)
|
||||
b := buf.Bytes()
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if path.Join(r.URL.Path) == pth {
|
||||
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
||||
_, _ = rw.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
if next == nil {
|
||||
rw.Header().Set("Content-Type", "text/plain")
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
return serveUI(pth, assets.Bytes(), next)
|
||||
}
|
||||
|
||||
const (
|
||||
|
173
vendor/github.com/go-openapi/runtime/middleware/ui_options.go
generated
vendored
Normal file
173
vendor/github.com/go-openapi/runtime/middleware/ui_options.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// constants that are common to all UI-serving middlewares
|
||||
defaultDocsPath = "docs"
|
||||
defaultDocsURL = "/swagger.json"
|
||||
defaultDocsTitle = "API Documentation"
|
||||
)
|
||||
|
||||
// uiOptions defines common options for UI serving middlewares.
|
||||
type uiOptions struct {
|
||||
// BasePath for the UI, defaults to: /
|
||||
BasePath string
|
||||
|
||||
// Path combines with BasePath to construct the path to the UI, defaults to: "docs".
|
||||
Path string
|
||||
|
||||
// SpecURL is the URL of the spec document.
|
||||
//
|
||||
// Defaults to: /swagger.json
|
||||
SpecURL string
|
||||
|
||||
// Title for the documentation site, default to: API documentation
|
||||
Title string
|
||||
|
||||
// Template specifies a custom template to serve the UI
|
||||
Template string
|
||||
}
|
||||
|
||||
// toCommonUIOptions converts any UI option type to retain the common options.
|
||||
//
|
||||
// This uses gob encoding/decoding to convert common fields from one struct to another.
|
||||
func toCommonUIOptions(opts interface{}) uiOptions {
|
||||
var buf bytes.Buffer
|
||||
enc := gob.NewEncoder(&buf)
|
||||
dec := gob.NewDecoder(&buf)
|
||||
var o uiOptions
|
||||
err := enc.Encode(opts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = dec.Decode(&o)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
func fromCommonToAnyOptions[T any](source uiOptions, target *T) {
|
||||
var buf bytes.Buffer
|
||||
enc := gob.NewEncoder(&buf)
|
||||
dec := gob.NewDecoder(&buf)
|
||||
err := enc.Encode(source)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = dec.Decode(target)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// UIOption can be applied to UI serving middleware, such as Context.APIHandler or
|
||||
// Context.APIHandlerSwaggerUI to alter the defaut behavior.
|
||||
type UIOption func(*uiOptions)
|
||||
|
||||
func uiOptionsWithDefaults(opts []UIOption) uiOptions {
|
||||
var o uiOptions
|
||||
for _, apply := range opts {
|
||||
apply(&o)
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
// WithUIBasePath sets the base path from where to serve the UI assets.
|
||||
//
|
||||
// By default, Context middleware sets this value to the API base path.
|
||||
func WithUIBasePath(base string) UIOption {
|
||||
return func(o *uiOptions) {
|
||||
if !strings.HasPrefix(base, "/") {
|
||||
base = "/" + base
|
||||
}
|
||||
o.BasePath = base
|
||||
}
|
||||
}
|
||||
|
||||
// WithUIPath sets the path from where to serve the UI assets (i.e. /{basepath}/{path}.
|
||||
func WithUIPath(pth string) UIOption {
|
||||
return func(o *uiOptions) {
|
||||
o.Path = pth
|
||||
}
|
||||
}
|
||||
|
||||
// WithUISpecURL sets the path from where to serve swagger spec document.
|
||||
//
|
||||
// This may be specified as a full URL or a path.
|
||||
//
|
||||
// By default, this is "/swagger.json"
|
||||
func WithUISpecURL(specURL string) UIOption {
|
||||
return func(o *uiOptions) {
|
||||
o.SpecURL = specURL
|
||||
}
|
||||
}
|
||||
|
||||
// WithUITitle sets the title of the UI.
|
||||
//
|
||||
// By default, Context middleware sets this value to the title found in the API spec.
|
||||
func WithUITitle(title string) UIOption {
|
||||
return func(o *uiOptions) {
|
||||
o.Title = title
|
||||
}
|
||||
}
|
||||
|
||||
// WithTemplate allows to set a custom template for the UI.
|
||||
//
|
||||
// UI middleware will panic if the template does not parse or execute properly.
|
||||
func WithTemplate(tpl string) UIOption {
|
||||
return func(o *uiOptions) {
|
||||
o.Template = tpl
|
||||
}
|
||||
}
|
||||
|
||||
// EnsureDefaults in case some options are missing
|
||||
func (r *uiOptions) EnsureDefaults() {
|
||||
if r.BasePath == "" {
|
||||
r.BasePath = "/"
|
||||
}
|
||||
if r.Path == "" {
|
||||
r.Path = defaultDocsPath
|
||||
}
|
||||
if r.SpecURL == "" {
|
||||
r.SpecURL = defaultDocsURL
|
||||
}
|
||||
if r.Title == "" {
|
||||
r.Title = defaultDocsTitle
|
||||
}
|
||||
}
|
||||
|
||||
// serveUI creates a middleware that serves a templated asset as text/html.
|
||||
func serveUI(pth string, assets []byte, next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if path.Clean(r.URL.Path) == pth {
|
||||
rw.Header().Set(contentTypeHeader, "text/html; charset=utf-8")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
_, _ = rw.Write(assets)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if next != nil {
|
||||
next.ServeHTTP(rw, r)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Set(contentTypeHeader, "text/plain")
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
|
||||
})
|
||||
}
|
15
vendor/github.com/go-openapi/runtime/middleware/untyped/api.go
generated
vendored
15
vendor/github.com/go-openapi/runtime/middleware/untyped/api.go
generated
vendored
@ -197,30 +197,31 @@ func (d *API) Validate() error {
|
||||
|
||||
// validateWith validates the registrations in this API against the provided spec analyzer
|
||||
func (d *API) validate() error {
|
||||
var consumes []string
|
||||
consumes := make([]string, 0, len(d.consumers))
|
||||
for k := range d.consumers {
|
||||
consumes = append(consumes, k)
|
||||
}
|
||||
|
||||
var produces []string
|
||||
produces := make([]string, 0, len(d.producers))
|
||||
for k := range d.producers {
|
||||
produces = append(produces, k)
|
||||
}
|
||||
|
||||
var authenticators []string
|
||||
authenticators := make([]string, 0, len(d.authenticators))
|
||||
for k := range d.authenticators {
|
||||
authenticators = append(authenticators, k)
|
||||
}
|
||||
|
||||
var operations []string
|
||||
operations := make([]string, 0, len(d.operations))
|
||||
for m, v := range d.operations {
|
||||
for p := range v {
|
||||
operations = append(operations, fmt.Sprintf("%s %s", strings.ToUpper(m), p))
|
||||
}
|
||||
}
|
||||
|
||||
var definedAuths []string
|
||||
for k := range d.spec.Spec().SecurityDefinitions {
|
||||
secDefinitions := d.spec.Spec().SecurityDefinitions
|
||||
definedAuths := make([]string, 0, len(secDefinitions))
|
||||
for k := range secDefinitions {
|
||||
definedAuths = append(definedAuths, k)
|
||||
}
|
||||
|
||||
@ -267,7 +268,7 @@ func (d *API) verify(name string, registrations []string, expectations []string)
|
||||
delete(expected, k)
|
||||
}
|
||||
|
||||
var unregistered []string
|
||||
unregistered := make([]string, 0, len(expected))
|
||||
for k := range expected {
|
||||
unregistered = append(unregistered, k)
|
||||
}
|
||||
|
12
vendor/github.com/go-openapi/runtime/middleware/validation.go
generated
vendored
12
vendor/github.com/go-openapi/runtime/middleware/validation.go
generated
vendored
@ -35,7 +35,6 @@ type validation struct {
|
||||
|
||||
// ContentType validates the content type of a request
|
||||
func validateContentType(allowed []string, actual string) error {
|
||||
debugLog("validating content type for %q against [%s]", actual, strings.Join(allowed, ", "))
|
||||
if len(allowed) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -57,13 +56,13 @@ func validateContentType(allowed []string, actual string) error {
|
||||
}
|
||||
|
||||
func validateRequest(ctx *Context, request *http.Request, route *MatchedRoute) *validation {
|
||||
debugLog("validating request %s %s", request.Method, request.URL.EscapedPath())
|
||||
validate := &validation{
|
||||
context: ctx,
|
||||
request: request,
|
||||
route: route,
|
||||
bound: make(map[string]interface{}),
|
||||
}
|
||||
validate.debugLogf("validating request %s %s", request.Method, request.URL.EscapedPath())
|
||||
|
||||
validate.contentType()
|
||||
if len(validate.result) == 0 {
|
||||
@ -76,8 +75,12 @@ func validateRequest(ctx *Context, request *http.Request, route *MatchedRoute) *
|
||||
return validate
|
||||
}
|
||||
|
||||
func (v *validation) debugLogf(format string, args ...any) {
|
||||
v.context.debugLogf(format, args...)
|
||||
}
|
||||
|
||||
func (v *validation) parameters() {
|
||||
debugLog("validating request parameters for %s %s", v.request.Method, v.request.URL.EscapedPath())
|
||||
v.debugLogf("validating request parameters for %s %s", v.request.Method, v.request.URL.EscapedPath())
|
||||
if result := v.route.Binder.Bind(v.request, v.route.Params, v.route.Consumer, v.bound); result != nil {
|
||||
if result.Error() == "validation failure list" {
|
||||
for _, e := range result.(*errors.Validation).Value.([]interface{}) {
|
||||
@ -91,7 +94,7 @@ func (v *validation) parameters() {
|
||||
|
||||
func (v *validation) contentType() {
|
||||
if len(v.result) == 0 && runtime.HasBody(v.request) {
|
||||
debugLog("validating body content type for %s %s", v.request.Method, v.request.URL.EscapedPath())
|
||||
v.debugLogf("validating body content type for %s %s", v.request.Method, v.request.URL.EscapedPath())
|
||||
ct, _, req, err := v.context.ContentType(v.request)
|
||||
if err != nil {
|
||||
v.result = append(v.result, err)
|
||||
@ -100,6 +103,7 @@ func (v *validation) contentType() {
|
||||
}
|
||||
|
||||
if len(v.result) == 0 {
|
||||
v.debugLogf("validating content type for %q against [%s]", ct, strings.Join(v.route.Consumes, ", "))
|
||||
if err := validateContentType(v.route.Consumes, ct); err != nil {
|
||||
v.result = append(v.result, err)
|
||||
}
|
||||
|
14
vendor/github.com/go-openapi/runtime/request.go
generated
vendored
14
vendor/github.com/go-openapi/runtime/request.go
generated
vendored
@ -16,6 +16,8 @@ package runtime
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -96,10 +98,16 @@ func (p *peekingReader) Read(d []byte) (int, error) {
|
||||
if p == nil {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if p.underlying == nil {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
return p.underlying.Read(d)
|
||||
}
|
||||
|
||||
func (p *peekingReader) Close() error {
|
||||
if p.underlying == nil {
|
||||
return errors.New("reader already closed")
|
||||
}
|
||||
p.underlying = nil
|
||||
if p.orig != nil {
|
||||
return p.orig.Close()
|
||||
@ -107,9 +115,11 @@ func (p *peekingReader) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// JSONRequest creates a new http request with json headers set
|
||||
// JSONRequest creates a new http request with json headers set.
|
||||
//
|
||||
// It uses context.Background.
|
||||
func JSONRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
|
||||
req, err := http.NewRequest(method, urlStr, body)
|
||||
req, err := http.NewRequestWithContext(context.Background(), method, urlStr, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
19
vendor/github.com/go-openapi/runtime/security/authenticator.go
generated
vendored
19
vendor/github.com/go-openapi/runtime/security/authenticator.go
generated
vendored
@ -25,12 +25,13 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
query = "query"
|
||||
header = "header"
|
||||
query = "query"
|
||||
header = "header"
|
||||
accessTokenParam = "access_token"
|
||||
)
|
||||
|
||||
// HttpAuthenticator is a function that authenticates a HTTP request
|
||||
func HttpAuthenticator(handler func(*http.Request) (bool, interface{}, error)) runtime.Authenticator {
|
||||
func HttpAuthenticator(handler func(*http.Request) (bool, interface{}, error)) runtime.Authenticator { //nolint:revive,stylecheck
|
||||
return runtime.AuthenticatorFunc(func(params interface{}) (bool, interface{}, error) {
|
||||
if request, ok := params.(*http.Request); ok {
|
||||
return handler(request)
|
||||
@ -158,7 +159,7 @@ func APIKeyAuth(name, in string, authenticate TokenAuthentication) runtime.Authe
|
||||
inl := strings.ToLower(in)
|
||||
if inl != query && inl != header {
|
||||
// panic because this is most likely a typo
|
||||
panic(errors.New(500, "api key auth: in value needs to be either \"query\" or \"header\"."))
|
||||
panic(errors.New(500, "api key auth: in value needs to be either \"query\" or \"header\""))
|
||||
}
|
||||
|
||||
var getToken func(*http.Request) string
|
||||
@ -186,7 +187,7 @@ func APIKeyAuthCtx(name, in string, authenticate TokenAuthenticationCtx) runtime
|
||||
inl := strings.ToLower(in)
|
||||
if inl != query && inl != header {
|
||||
// panic because this is most likely a typo
|
||||
panic(errors.New(500, "api key auth: in value needs to be either \"query\" or \"header\"."))
|
||||
panic(errors.New(500, "api key auth: in value needs to be either \"query\" or \"header\""))
|
||||
}
|
||||
|
||||
var getToken func(*http.Request) string
|
||||
@ -226,12 +227,12 @@ func BearerAuth(name string, authenticate ScopedTokenAuthentication) runtime.Aut
|
||||
}
|
||||
if token == "" {
|
||||
qs := r.Request.URL.Query()
|
||||
token = qs.Get("access_token")
|
||||
token = qs.Get(accessTokenParam)
|
||||
}
|
||||
//#nosec
|
||||
ct, _, _ := runtime.ContentType(r.Request.Header)
|
||||
if token == "" && (ct == "application/x-www-form-urlencoded" || ct == "multipart/form-data") {
|
||||
token = r.Request.FormValue("access_token")
|
||||
token = r.Request.FormValue(accessTokenParam)
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
@ -256,12 +257,12 @@ func BearerAuthCtx(name string, authenticate ScopedTokenAuthenticationCtx) runti
|
||||
}
|
||||
if token == "" {
|
||||
qs := r.Request.URL.Query()
|
||||
token = qs.Get("access_token")
|
||||
token = qs.Get(accessTokenParam)
|
||||
}
|
||||
//#nosec
|
||||
ct, _, _ := runtime.ContentType(r.Request.Header)
|
||||
if token == "" && (ct == "application/x-www-form-urlencoded" || ct == "multipart/form-data") {
|
||||
token = r.Request.FormValue("access_token")
|
||||
token = r.Request.FormValue(accessTokenParam)
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
|
Reference in New Issue
Block a user