fix: error handling and vendor
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
26
vendor/github.com/go-openapi/runtime/.editorconfig
generated
vendored
Normal file
26
vendor/github.com/go-openapi/runtime/.editorconfig
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Set default charset
|
||||
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
|
||||
charset = utf-8
|
||||
|
||||
# Tab indentation (no size specified)
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Matches the exact files either package.json or .travis.yml
|
||||
[{package.json,.travis.yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
1
vendor/github.com/go-openapi/runtime/.gitattributes
generated
vendored
Normal file
1
vendor/github.com/go-openapi/runtime/.gitattributes
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.go text eol=lf
|
5
vendor/github.com/go-openapi/runtime/.gitignore
generated
vendored
Normal file
5
vendor/github.com/go-openapi/runtime/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
secrets.yml
|
||||
coverage.out
|
||||
*.cov
|
||||
*.out
|
||||
playground
|
62
vendor/github.com/go-openapi/runtime/.golangci.yml
generated
vendored
Normal file
62
vendor/github.com/go-openapi/runtime/.golangci.yml
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
linters-settings:
|
||||
govet:
|
||||
check-shadowing: true
|
||||
golint:
|
||||
min-confidence: 0
|
||||
gocyclo:
|
||||
min-complexity: 45
|
||||
maligned:
|
||||
suggest-new: true
|
||||
dupl:
|
||||
threshold: 200
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 3
|
||||
|
||||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
- nilerr # nilerr crashes on this repo
|
||||
- maligned
|
||||
- unparam
|
||||
- lll
|
||||
- gochecknoinits
|
||||
- gochecknoglobals
|
||||
- funlen
|
||||
- godox
|
||||
- gocognit
|
||||
- whitespace
|
||||
- wsl
|
||||
- wrapcheck
|
||||
- testpackage
|
||||
- nlreturn
|
||||
- gomnd
|
||||
- exhaustivestruct
|
||||
- goerr113
|
||||
- errorlint
|
||||
- nestif
|
||||
- godot
|
||||
- gofumpt
|
||||
- paralleltest
|
||||
- tparallel
|
||||
- thelper
|
||||
- ifshort
|
||||
- exhaustruct
|
||||
- varnamelen
|
||||
- gci
|
||||
- depguard
|
||||
- errchkjson
|
||||
- inamedparam
|
||||
- nonamedreturns
|
||||
- musttag
|
||||
- ireturn
|
||||
- forcetypeassert
|
||||
- cyclop
|
||||
# deprecated linters
|
||||
- deadcode
|
||||
- interfacer
|
||||
- scopelint
|
||||
- varcheck
|
||||
- structcheck
|
||||
- golint
|
||||
- nosnakecase
|
74
vendor/github.com/go-openapi/runtime/CODE_OF_CONDUCT.md
generated
vendored
Normal file
74
vendor/github.com/go-openapi/runtime/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
202
vendor/github.com/go-openapi/runtime/LICENSE
generated
vendored
Normal file
202
vendor/github.com/go-openapi/runtime/LICENSE
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
10
vendor/github.com/go-openapi/runtime/README.md
generated
vendored
Normal file
10
vendor/github.com/go-openapi/runtime/README.md
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# runtime [](https://github.com/go-openapi/runtime/actions?query=workflow%3A"go+test") [](https://codecov.io/gh/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)
|
||||
|
||||
# go OpenAPI toolkit runtime
|
||||
|
||||
The runtime component for use in code generation or as untyped usage.
|
222
vendor/github.com/go-openapi/runtime/bytestream.go
generated
vendored
Normal file
222
vendor/github.com/go-openapi/runtime/bytestream.go
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
func defaultCloser() error { return nil }
|
||||
|
||||
type byteStreamOpt func(opts *byteStreamOpts)
|
||||
|
||||
// ClosesStream when the bytestream consumer or producer is finished
|
||||
func ClosesStream(opts *byteStreamOpts) {
|
||||
opts.Close = true
|
||||
}
|
||||
|
||||
type byteStreamOpts struct {
|
||||
Close bool
|
||||
}
|
||||
|
||||
// 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 {
|
||||
opt(&vals)
|
||||
}
|
||||
|
||||
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
|
||||
if reader == nil {
|
||||
return errors.New("ByteStreamConsumer requires a reader") // early exit
|
||||
}
|
||||
if data == nil {
|
||||
return errors.New("nil destination for ByteStreamConsumer")
|
||||
}
|
||||
|
||||
closer := defaultCloser
|
||||
if vals.Close {
|
||||
if cl, isReaderCloser := reader.(io.Closer); isReaderCloser {
|
||||
closer = cl.Close
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
_ = closer()
|
||||
}()
|
||||
|
||||
if readerFrom, isReaderFrom := data.(io.ReaderFrom); isReaderFrom {
|
||||
_, err := readerFrom.ReadFrom(reader)
|
||||
return err
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
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
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("%v (%T) is not supported by the ByteStreamConsumer, %s",
|
||||
data, data, "can be resolved by supporting Writer/BinaryUnmarshaler interface")
|
||||
})
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
if data == nil {
|
||||
return errors.New("nil data for ByteStreamProducer")
|
||||
}
|
||||
|
||||
closer := defaultCloser
|
||||
if vals.Close {
|
||||
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 io.WriterTo:
|
||||
_, err := origin.WriteTo(writer)
|
||||
return err
|
||||
|
||||
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
|
||||
|
||||
case error:
|
||||
_, err := writer.Write([]byte(origin.Error()))
|
||||
return err
|
||||
|
||||
default:
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
t := v.Type()
|
||||
|
||||
switch {
|
||||
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
|
||||
_, err := writer.Write(v.Bytes())
|
||||
return err
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("%v (%T) is not supported by the ByteStreamProducer, %s",
|
||||
data, data, "can be resolved by supporting Reader/BinaryMarshaler interface")
|
||||
})
|
||||
}
|
77
vendor/github.com/go-openapi/runtime/client/auth_info.go
generated
vendored
Normal file
77
vendor/github.com/go-openapi/runtime/client/auth_info.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
// PassThroughAuth never manipulates the request
|
||||
var PassThroughAuth runtime.ClientAuthInfoWriter
|
||||
|
||||
func init() {
|
||||
PassThroughAuth = runtime.ClientAuthInfoWriterFunc(func(_ runtime.ClientRequest, _ strfmt.Registry) error { return nil })
|
||||
}
|
||||
|
||||
// BasicAuth provides a basic auth info writer
|
||||
func BasicAuth(username, password string) runtime.ClientAuthInfoWriter {
|
||||
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
encoded := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||
return r.SetHeaderParam(runtime.HeaderAuthorization, "Basic "+encoded)
|
||||
})
|
||||
}
|
||||
|
||||
// APIKeyAuth provides an API key auth info writer
|
||||
func APIKeyAuth(name, in, value string) runtime.ClientAuthInfoWriter {
|
||||
if in == "query" {
|
||||
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return r.SetQueryParam(name, value)
|
||||
})
|
||||
}
|
||||
|
||||
if in == "header" {
|
||||
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return r.SetHeaderParam(name, value)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BearerToken provides a header based oauth2 bearer access token auth info writer
|
||||
func BearerToken(token string) runtime.ClientAuthInfoWriter {
|
||||
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
return r.SetHeaderParam(runtime.HeaderAuthorization, "Bearer "+token)
|
||||
})
|
||||
}
|
||||
|
||||
// Compose combines multiple ClientAuthInfoWriters into a single one.
|
||||
// Useful when multiple auth headers are needed.
|
||||
func Compose(auths ...runtime.ClientAuthInfoWriter) runtime.ClientAuthInfoWriter {
|
||||
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
|
||||
for _, auth := range auths {
|
||||
if auth == nil {
|
||||
continue
|
||||
}
|
||||
if err := auth.AuthenticateRequest(r, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
54
vendor/github.com/go-openapi/runtime/client/keepalive.go
generated
vendored
Normal file
54
vendor/github.com/go-openapi/runtime/client/keepalive.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// KeepAliveTransport drains the remaining body from a response
|
||||
// so that go will reuse the TCP connections.
|
||||
// This is not enabled by default because there are servers where
|
||||
// the response never gets closed and that would make the code hang forever.
|
||||
// So instead it's provided as a http client middleware that can be used to override
|
||||
// any request.
|
||||
func KeepAliveTransport(rt http.RoundTripper) http.RoundTripper {
|
||||
return &keepAliveTransport{wrapped: rt}
|
||||
}
|
||||
|
||||
type keepAliveTransport struct {
|
||||
wrapped http.RoundTripper
|
||||
}
|
||||
|
||||
func (k *keepAliveTransport) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||
resp, err := k.wrapped.RoundTrip(r)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp.Body = &drainingReadCloser{rdr: resp.Body}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
type drainingReadCloser struct {
|
||||
rdr io.ReadCloser
|
||||
seenEOF uint32
|
||||
}
|
||||
|
||||
func (d *drainingReadCloser) Read(p []byte) (n int, err error) {
|
||||
n, err = d.rdr.Read(p)
|
||||
if err == io.EOF || n == 0 {
|
||||
atomic.StoreUint32(&d.seenEOF, 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *drainingReadCloser) Close() error {
|
||||
// drain buffer
|
||||
if atomic.LoadUint32(&d.seenEOF) != 1 {
|
||||
// If the reader side (a HTTP server) is misbehaving, it still may send
|
||||
// some bytes, but the closer ignores them to keep the underling
|
||||
// connection open.
|
||||
_, _ = io.Copy(io.Discard, d.rdr)
|
||||
}
|
||||
return d.rdr.Close()
|
||||
}
|
211
vendor/github.com/go-openapi/runtime/client/opentelemetry.go
generated
vendored
Normal file
211
vendor/github.com/go-openapi/runtime/client/opentelemetry.go
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
|
||||
"go.opentelemetry.io/otel/semconv/v1.17.0/httpconv"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
instrumentationVersion = "1.0.0"
|
||||
tracerName = "go-openapi"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
Tracer trace.Tracer
|
||||
Propagator propagation.TextMapPropagator
|
||||
SpanStartOptions []trace.SpanStartOption
|
||||
SpanNameFormatter func(*runtime.ClientOperation) string
|
||||
TracerProvider trace.TracerProvider
|
||||
}
|
||||
|
||||
type OpenTelemetryOpt interface {
|
||||
apply(*config)
|
||||
}
|
||||
|
||||
type optionFunc func(*config)
|
||||
|
||||
func (o optionFunc) apply(c *config) {
|
||||
o(c)
|
||||
}
|
||||
|
||||
// WithTracerProvider specifies a tracer provider to use for creating a tracer.
|
||||
// If none is specified, the global provider is used.
|
||||
func WithTracerProvider(provider trace.TracerProvider) OpenTelemetryOpt {
|
||||
return optionFunc(func(c *config) {
|
||||
if provider != nil {
|
||||
c.TracerProvider = provider
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// WithPropagators configures specific propagators. If this
|
||||
// option isn't specified, then the global TextMapPropagator is used.
|
||||
func WithPropagators(ps propagation.TextMapPropagator) OpenTelemetryOpt {
|
||||
return optionFunc(func(c *config) {
|
||||
if ps != nil {
|
||||
c.Propagator = ps
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// WithSpanOptions configures an additional set of
|
||||
// trace.SpanOptions, which are applied to each new span.
|
||||
func WithSpanOptions(opts ...trace.SpanStartOption) OpenTelemetryOpt {
|
||||
return optionFunc(func(c *config) {
|
||||
c.SpanStartOptions = append(c.SpanStartOptions, opts...)
|
||||
})
|
||||
}
|
||||
|
||||
// WithSpanNameFormatter takes a function that will be called on every
|
||||
// request and the returned string will become the Span Name.
|
||||
func WithSpanNameFormatter(f func(op *runtime.ClientOperation) string) OpenTelemetryOpt {
|
||||
return optionFunc(func(c *config) {
|
||||
c.SpanNameFormatter = f
|
||||
})
|
||||
}
|
||||
|
||||
func defaultTransportFormatter(op *runtime.ClientOperation) string {
|
||||
if op.ID != "" {
|
||||
return op.ID
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s_%s", strings.ToLower(op.Method), op.PathPattern)
|
||||
}
|
||||
|
||||
type openTelemetryTransport struct {
|
||||
transport runtime.ClientTransport
|
||||
host string
|
||||
tracer trace.Tracer
|
||||
config *config
|
||||
}
|
||||
|
||||
func newOpenTelemetryTransport(transport runtime.ClientTransport, host string, opts []OpenTelemetryOpt) *openTelemetryTransport {
|
||||
tr := &openTelemetryTransport{
|
||||
transport: transport,
|
||||
host: host,
|
||||
}
|
||||
|
||||
defaultOpts := []OpenTelemetryOpt{
|
||||
WithSpanOptions(trace.WithSpanKind(trace.SpanKindClient)),
|
||||
WithSpanNameFormatter(defaultTransportFormatter),
|
||||
WithPropagators(otel.GetTextMapPropagator()),
|
||||
WithTracerProvider(otel.GetTracerProvider()),
|
||||
}
|
||||
|
||||
c := newConfig(append(defaultOpts, opts...)...)
|
||||
tr.config = c
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
func (t *openTelemetryTransport) Submit(op *runtime.ClientOperation) (interface{}, error) {
|
||||
if op.Context == nil {
|
||||
return t.transport.Submit(op)
|
||||
}
|
||||
|
||||
params := op.Params
|
||||
reader := op.Reader
|
||||
|
||||
var span trace.Span
|
||||
defer func() {
|
||||
if span != nil {
|
||||
span.End()
|
||||
}
|
||||
}()
|
||||
|
||||
op.Params = runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
span = t.newOpenTelemetrySpan(op, req.GetHeaderParams())
|
||||
return params.WriteToRequest(req, reg)
|
||||
})
|
||||
|
||||
op.Reader = runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if span != nil {
|
||||
statusCode := response.Code()
|
||||
// NOTE: this is replaced by semconv.HTTPResponseStatusCode in semconv v1.21
|
||||
span.SetAttributes(semconv.HTTPStatusCode(statusCode))
|
||||
// NOTE: the conversion from HTTP status code to trace code is no longer available with
|
||||
// semconv v1.21
|
||||
span.SetStatus(httpconv.ServerStatus(statusCode))
|
||||
}
|
||||
|
||||
return reader.ReadResponse(response, consumer)
|
||||
})
|
||||
|
||||
submit, err := t.transport.Submit(op)
|
||||
if err != nil && span != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, err.Error())
|
||||
}
|
||||
|
||||
return submit, err
|
||||
}
|
||||
|
||||
func (t *openTelemetryTransport) newOpenTelemetrySpan(op *runtime.ClientOperation, header http.Header) trace.Span {
|
||||
ctx := op.Context
|
||||
|
||||
tracer := t.tracer
|
||||
if tracer == nil {
|
||||
if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
|
||||
tracer = newTracer(span.TracerProvider())
|
||||
} else {
|
||||
tracer = newTracer(otel.GetTracerProvider())
|
||||
}
|
||||
}
|
||||
|
||||
ctx, span := tracer.Start(ctx, t.config.SpanNameFormatter(op), t.config.SpanStartOptions...)
|
||||
|
||||
var scheme string
|
||||
if len(op.Schemes) > 0 {
|
||||
scheme = op.Schemes[0]
|
||||
}
|
||||
|
||||
span.SetAttributes(
|
||||
attribute.String("net.peer.name", t.host),
|
||||
attribute.String(string(semconv.HTTPRouteKey), op.PathPattern),
|
||||
attribute.String(string(semconv.HTTPMethodKey), op.Method),
|
||||
attribute.String("span.kind", trace.SpanKindClient.String()),
|
||||
attribute.String("http.scheme", scheme),
|
||||
)
|
||||
|
||||
carrier := propagation.HeaderCarrier(header)
|
||||
t.config.Propagator.Inject(ctx, carrier)
|
||||
|
||||
return span
|
||||
}
|
||||
|
||||
func newTracer(tp trace.TracerProvider) trace.Tracer {
|
||||
return tp.Tracer(tracerName, trace.WithInstrumentationVersion(version()))
|
||||
}
|
||||
|
||||
func newConfig(opts ...OpenTelemetryOpt) *config {
|
||||
c := &config{
|
||||
Propagator: otel.GetTextMapPropagator(),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt.apply(c)
|
||||
}
|
||||
|
||||
// Tracer is only initialized if manually specified. Otherwise, can be passed with the tracing context.
|
||||
if c.TracerProvider != nil {
|
||||
c.Tracer = newTracer(c.TracerProvider)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Version is the current release version of the go-runtime instrumentation.
|
||||
func version() string {
|
||||
return instrumentationVersion
|
||||
}
|
99
vendor/github.com/go-openapi/runtime/client/opentracing.go
generated
vendored
Normal file
99
vendor/github.com/go-openapi/runtime/client/opentracing.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"github.com/opentracing/opentracing-go/log"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
type tracingTransport struct {
|
||||
transport runtime.ClientTransport
|
||||
host string
|
||||
opts []opentracing.StartSpanOption
|
||||
}
|
||||
|
||||
func newOpenTracingTransport(transport runtime.ClientTransport, host string, opts []opentracing.StartSpanOption,
|
||||
) runtime.ClientTransport {
|
||||
return &tracingTransport{
|
||||
transport: transport,
|
||||
host: host,
|
||||
opts: opts,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *tracingTransport) Submit(op *runtime.ClientOperation) (interface{}, error) {
|
||||
if op.Context == nil {
|
||||
return t.transport.Submit(op)
|
||||
}
|
||||
|
||||
params := op.Params
|
||||
reader := op.Reader
|
||||
|
||||
var span opentracing.Span
|
||||
defer func() {
|
||||
if span != nil {
|
||||
span.Finish()
|
||||
}
|
||||
}()
|
||||
|
||||
op.Params = runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
span = createClientSpan(op, req.GetHeaderParams(), t.host, t.opts)
|
||||
return params.WriteToRequest(req, reg)
|
||||
})
|
||||
|
||||
op.Reader = runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
if span != nil {
|
||||
code := response.Code()
|
||||
ext.HTTPStatusCode.Set(span, uint16(code))
|
||||
if code >= 400 {
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
}
|
||||
return reader.ReadResponse(response, consumer)
|
||||
})
|
||||
|
||||
submit, err := t.transport.Submit(op)
|
||||
if err != nil && span != nil {
|
||||
ext.Error.Set(span, true)
|
||||
span.LogFields(log.Error(err))
|
||||
}
|
||||
return submit, err
|
||||
}
|
||||
|
||||
func createClientSpan(op *runtime.ClientOperation, header http.Header, host string,
|
||||
opts []opentracing.StartSpanOption) opentracing.Span {
|
||||
ctx := op.Context
|
||||
span := opentracing.SpanFromContext(ctx)
|
||||
|
||||
if span != nil {
|
||||
opts = append(opts, ext.SpanKindRPCClient)
|
||||
span, _ = opentracing.StartSpanFromContextWithTracer(
|
||||
ctx, span.Tracer(), operationName(op), opts...)
|
||||
|
||||
ext.Component.Set(span, "go-openapi")
|
||||
ext.PeerHostname.Set(span, host)
|
||||
span.SetTag("http.path", op.PathPattern)
|
||||
ext.HTTPMethod.Set(span, op.Method)
|
||||
|
||||
_ = span.Tracer().Inject(
|
||||
span.Context(),
|
||||
opentracing.HTTPHeaders,
|
||||
opentracing.HTTPHeadersCarrier(header))
|
||||
|
||||
return span
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func operationName(op *runtime.ClientOperation) string {
|
||||
if op.ID != "" {
|
||||
return op.ID
|
||||
}
|
||||
return fmt.Sprintf("%s_%s", op.Method, op.PathPattern)
|
||||
}
|
482
vendor/github.com/go-openapi/runtime/client/request.go
generated
vendored
Normal file
482
vendor/github.com/go-openapi/runtime/client/request.go
generated
vendored
Normal file
@ -0,0 +1,482 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
// NewRequest creates a new swagger http client request
|
||||
func newRequest(method, pathPattern string, writer runtime.ClientRequestWriter) *request {
|
||||
return &request{
|
||||
pathPattern: pathPattern,
|
||||
method: method,
|
||||
writer: writer,
|
||||
header: make(http.Header),
|
||||
query: make(url.Values),
|
||||
timeout: DefaultTimeout,
|
||||
getBody: getRequestBuffer,
|
||||
}
|
||||
}
|
||||
|
||||
// Request represents a swagger client request.
|
||||
//
|
||||
// This Request struct converts to a HTTP request.
|
||||
// There might be others that convert to other transports.
|
||||
// There is no error checking here, it is assumed to be used after a spec has been validated.
|
||||
// so impossible combinations should not arise (hopefully).
|
||||
//
|
||||
// The main purpose of this struct is to hide the machinery of adding params to a transport request.
|
||||
// The generated code only implements what is necessary to turn a param into a valid value for these methods.
|
||||
type request struct {
|
||||
pathPattern string
|
||||
method string
|
||||
writer runtime.ClientRequestWriter
|
||||
|
||||
pathParams map[string]string
|
||||
header http.Header
|
||||
query url.Values
|
||||
formFields url.Values
|
||||
fileFields map[string][]runtime.NamedReadCloser
|
||||
payload interface{}
|
||||
timeout time.Duration
|
||||
buf *bytes.Buffer
|
||||
|
||||
getBody func(r *request) []byte
|
||||
}
|
||||
|
||||
var (
|
||||
// ensure interface compliance
|
||||
_ runtime.ClientRequest = new(request)
|
||||
)
|
||||
|
||||
func (r *request) isMultipart(mediaType string) bool {
|
||||
if len(r.fileFields) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return runtime.MultipartFormMime == mediaType
|
||||
}
|
||||
|
||||
// BuildHTTP creates a new http request based on the data from the params
|
||||
func (r *request) BuildHTTP(mediaType, basePath string, producers map[string]runtime.Producer, registry strfmt.Registry) (*http.Request, error) {
|
||||
return r.buildHTTP(mediaType, basePath, producers, registry, nil)
|
||||
}
|
||||
func escapeQuotes(s string) string {
|
||||
return strings.NewReplacer("\\", "\\\\", `"`, "\\\"").Replace(s)
|
||||
}
|
||||
|
||||
func logClose(err error, pw *io.PipeWriter) {
|
||||
log.Println(err)
|
||||
closeErr := pw.CloseWithError(err)
|
||||
if closeErr != nil {
|
||||
log.Println(closeErr)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *request) buildHTTP(mediaType, basePath string, producers map[string]runtime.Producer, registry strfmt.Registry, auth runtime.ClientAuthInfoWriter) (*http.Request, error) { //nolint:gocyclo,maintidx
|
||||
// build the data
|
||||
if err := r.writer.WriteToRequest(r, registry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Our body must be an io.Reader.
|
||||
// When we create the http.Request, if we pass it a
|
||||
// bytes.Buffer then it will wrap it in an io.ReadCloser
|
||||
// and set the content length automatically.
|
||||
var body io.Reader
|
||||
var pr *io.PipeReader
|
||||
var pw *io.PipeWriter
|
||||
|
||||
r.buf = bytes.NewBuffer(nil)
|
||||
if r.payload != nil || len(r.formFields) > 0 || len(r.fileFields) > 0 {
|
||||
body = r.buf
|
||||
if r.isMultipart(mediaType) {
|
||||
pr, pw = io.Pipe()
|
||||
body = pr
|
||||
}
|
||||
}
|
||||
|
||||
// check if this is a form type request
|
||||
if len(r.formFields) > 0 || len(r.fileFields) > 0 {
|
||||
if !r.isMultipart(mediaType) {
|
||||
r.header.Set(runtime.HeaderContentType, mediaType)
|
||||
formString := r.formFields.Encode()
|
||||
r.buf.WriteString(formString)
|
||||
goto DoneChoosingBodySource
|
||||
}
|
||||
|
||||
mp := multipart.NewWriter(pw)
|
||||
r.header.Set(runtime.HeaderContentType, mangleContentType(mediaType, mp.Boundary()))
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
mp.Close()
|
||||
pw.Close()
|
||||
}()
|
||||
|
||||
for fn, v := range r.formFields {
|
||||
for _, vi := range v {
|
||||
if err := mp.WriteField(fn, vi); err != nil {
|
||||
logClose(err, pw)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
for _, ff := range r.fileFields {
|
||||
for _, ffi := range ff {
|
||||
ffi.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
for fn, f := range r.fileFields {
|
||||
for _, fi := range f {
|
||||
var fileContentType string
|
||||
if p, ok := fi.(interface {
|
||||
ContentType() string
|
||||
}); ok {
|
||||
fileContentType = p.ContentType()
|
||||
} else {
|
||||
// Need to read the data so that we can detect the content type
|
||||
buf := make([]byte, 512)
|
||||
size, err := fi.Read(buf)
|
||||
if err != nil && err != io.EOF {
|
||||
logClose(err, pw)
|
||||
return
|
||||
}
|
||||
fileContentType = http.DetectContentType(buf)
|
||||
fi = runtime.NamedReader(fi.Name(), io.MultiReader(bytes.NewReader(buf[:size]), fi))
|
||||
}
|
||||
|
||||
// Create the MIME headers for the new part
|
||||
h := make(textproto.MIMEHeader)
|
||||
h.Set("Content-Disposition",
|
||||
fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
|
||||
escapeQuotes(fn), escapeQuotes(filepath.Base(fi.Name()))))
|
||||
h.Set("Content-Type", fileContentType)
|
||||
|
||||
wrtr, err := mp.CreatePart(h)
|
||||
if err != nil {
|
||||
logClose(err, pw)
|
||||
return
|
||||
}
|
||||
if _, err := io.Copy(wrtr, fi); err != nil {
|
||||
logClose(err, pw)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
goto DoneChoosingBodySource
|
||||
}
|
||||
|
||||
// if there is payload, use the producer to write the payload, and then
|
||||
// set the header to the content-type appropriate for the payload produced
|
||||
if r.payload != nil {
|
||||
// TODO: infer most appropriate content type based on the producer used,
|
||||
// and the `consumers` section of the spec/operation
|
||||
r.header.Set(runtime.HeaderContentType, mediaType)
|
||||
if rdr, ok := r.payload.(io.ReadCloser); ok {
|
||||
body = rdr
|
||||
goto DoneChoosingBodySource
|
||||
}
|
||||
|
||||
if rdr, ok := r.payload.(io.Reader); ok {
|
||||
body = rdr
|
||||
goto DoneChoosingBodySource
|
||||
}
|
||||
|
||||
producer := producers[mediaType]
|
||||
if err := producer.Produce(r.buf, r.payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
DoneChoosingBodySource:
|
||||
|
||||
if runtime.CanHaveBody(r.method) && body != nil && r.header.Get(runtime.HeaderContentType) == "" {
|
||||
r.header.Set(runtime.HeaderContentType, mediaType)
|
||||
}
|
||||
|
||||
if auth != nil {
|
||||
// If we're not using r.buf as our http.Request's body,
|
||||
// either the payload is an io.Reader or io.ReadCloser,
|
||||
// or we're doing a multipart form/file.
|
||||
//
|
||||
// In those cases, if the AuthenticateRequest call asks for the body,
|
||||
// we must read it into a buffer and provide that, then use that buffer
|
||||
// as the body of our http.Request.
|
||||
//
|
||||
// This is done in-line with the GetBody() request rather than ahead
|
||||
// of time, because there's no way to know if the AuthenticateRequest
|
||||
// will even ask for the body of the request.
|
||||
//
|
||||
// If for some reason the copy fails, there's no way to return that
|
||||
// error to the GetBody() call, so return it afterwards.
|
||||
//
|
||||
// An error from the copy action is prioritized over any error
|
||||
// from the AuthenticateRequest call, because the mis-read
|
||||
// body may have interfered with the auth.
|
||||
//
|
||||
var copyErr error
|
||||
if buf, ok := body.(*bytes.Buffer); body != nil && (!ok || buf != r.buf) {
|
||||
var copied bool
|
||||
r.getBody = func(r *request) []byte {
|
||||
if copied {
|
||||
return getRequestBuffer(r)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
copied = true
|
||||
}()
|
||||
|
||||
if _, copyErr = io.Copy(r.buf, body); copyErr != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if closer, ok := body.(io.ReadCloser); ok {
|
||||
if copyErr = closer.Close(); copyErr != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
body = r.buf
|
||||
return getRequestBuffer(r)
|
||||
}
|
||||
}
|
||||
|
||||
authErr := auth.AuthenticateRequest(r, registry)
|
||||
|
||||
if copyErr != nil {
|
||||
return nil, fmt.Errorf("error retrieving the response body: %v", copyErr)
|
||||
}
|
||||
|
||||
if authErr != nil {
|
||||
return nil, authErr
|
||||
}
|
||||
}
|
||||
|
||||
// In case the basePath or the request pathPattern include static query parameters,
|
||||
// parse those out before constructing the final path. The parameters themselves
|
||||
// will be merged with the ones set by the client, with the priority given first to
|
||||
// the ones set by the client, then the path pattern, and lastly the base path.
|
||||
basePathURL, err := url.Parse(basePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
staticQueryParams := basePathURL.Query()
|
||||
|
||||
pathPatternURL, err := url.Parse(r.pathPattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for name, values := range pathPatternURL.Query() {
|
||||
if _, present := staticQueryParams[name]; present {
|
||||
staticQueryParams.Del(name)
|
||||
}
|
||||
for _, value := range values {
|
||||
staticQueryParams.Add(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
// create http request
|
||||
var reinstateSlash bool
|
||||
if pathPatternURL.Path != "" && pathPatternURL.Path != "/" && pathPatternURL.Path[len(pathPatternURL.Path)-1] == '/' {
|
||||
reinstateSlash = true
|
||||
}
|
||||
|
||||
urlPath := path.Join(basePathURL.Path, pathPatternURL.Path)
|
||||
for k, v := range r.pathParams {
|
||||
urlPath = strings.ReplaceAll(urlPath, "{"+k+"}", url.PathEscape(v))
|
||||
}
|
||||
if reinstateSlash {
|
||||
urlPath += "/"
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(context.Background(), r.method, urlPath, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
originalParams := r.GetQueryParams()
|
||||
|
||||
// Merge the query parameters extracted from the basePath with the ones set by
|
||||
// the client in this struct. In case of conflict, the client wins.
|
||||
for k, v := range staticQueryParams {
|
||||
_, present := originalParams[k]
|
||||
if !present {
|
||||
if err = r.SetQueryParam(k, v...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
req.URL.RawQuery = r.query.Encode()
|
||||
req.Header = r.header
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func mangleContentType(mediaType, boundary string) string {
|
||||
if strings.ToLower(mediaType) == runtime.URLencodedFormMime {
|
||||
return fmt.Sprintf("%s; boundary=%s", mediaType, boundary)
|
||||
}
|
||||
return "multipart/form-data; boundary=" + boundary
|
||||
}
|
||||
|
||||
func (r *request) GetMethod() string {
|
||||
return r.method
|
||||
}
|
||||
|
||||
func (r *request) GetPath() string {
|
||||
path := r.pathPattern
|
||||
for k, v := range r.pathParams {
|
||||
path = strings.ReplaceAll(path, "{"+k+"}", v)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (r *request) GetBody() []byte {
|
||||
return r.getBody(r)
|
||||
}
|
||||
|
||||
func getRequestBuffer(r *request) []byte {
|
||||
if r.buf == nil {
|
||||
return nil
|
||||
}
|
||||
return r.buf.Bytes()
|
||||
}
|
||||
|
||||
// SetHeaderParam adds a header param to the request
|
||||
// when there is only 1 value provided for the varargs, it will set it.
|
||||
// when there are several values provided for the varargs it will add it (no overriding)
|
||||
func (r *request) SetHeaderParam(name string, values ...string) error {
|
||||
if r.header == nil {
|
||||
r.header = make(http.Header)
|
||||
}
|
||||
r.header[http.CanonicalHeaderKey(name)] = values
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetHeaderParams returns the all headers currently set for the request
|
||||
func (r *request) GetHeaderParams() http.Header {
|
||||
return r.header
|
||||
}
|
||||
|
||||
// SetQueryParam adds a query param to the request
|
||||
// when there is only 1 value provided for the varargs, it will set it.
|
||||
// when there are several values provided for the varargs it will add it (no overriding)
|
||||
func (r *request) SetQueryParam(name string, values ...string) error {
|
||||
if r.query == nil {
|
||||
r.query = make(url.Values)
|
||||
}
|
||||
r.query[name] = values
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetQueryParams returns a copy of all query params currently set for the request
|
||||
func (r *request) GetQueryParams() url.Values {
|
||||
var result = make(url.Values)
|
||||
for key, value := range r.query {
|
||||
result[key] = append([]string{}, value...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SetFormParam adds a forn param to the request
|
||||
// when there is only 1 value provided for the varargs, it will set it.
|
||||
// when there are several values provided for the varargs it will add it (no overriding)
|
||||
func (r *request) SetFormParam(name string, values ...string) error {
|
||||
if r.formFields == nil {
|
||||
r.formFields = make(url.Values)
|
||||
}
|
||||
r.formFields[name] = values
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPathParam adds a path param to the request
|
||||
func (r *request) SetPathParam(name string, value string) error {
|
||||
if r.pathParams == nil {
|
||||
r.pathParams = make(map[string]string)
|
||||
}
|
||||
|
||||
r.pathParams[name] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetFileParam adds a file param to the request
|
||||
func (r *request) SetFileParam(name string, files ...runtime.NamedReadCloser) error {
|
||||
for _, file := range files {
|
||||
if actualFile, ok := file.(*os.File); ok {
|
||||
fi, err := os.Stat(actualFile.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fi.IsDir() {
|
||||
return fmt.Errorf("%q is a directory, only files are supported", file.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r.fileFields == nil {
|
||||
r.fileFields = make(map[string][]runtime.NamedReadCloser)
|
||||
}
|
||||
if r.formFields == nil {
|
||||
r.formFields = make(url.Values)
|
||||
}
|
||||
|
||||
r.fileFields[name] = files
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *request) GetFileParam() map[string][]runtime.NamedReadCloser {
|
||||
return r.fileFields
|
||||
}
|
||||
|
||||
// SetBodyParam sets a body parameter on the request.
|
||||
// This does not yet serialze the object, this happens as late as possible.
|
||||
func (r *request) SetBodyParam(payload interface{}) error {
|
||||
r.payload = payload
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *request) GetBodyParam() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
// SetTimeout sets the timeout for a request
|
||||
func (r *request) SetTimeout(timeout time.Duration) error {
|
||||
r.timeout = timeout
|
||||
return nil
|
||||
}
|
50
vendor/github.com/go-openapi/runtime/client/response.go
generated
vendored
Normal file
50
vendor/github.com/go-openapi/runtime/client/response.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
var _ runtime.ClientResponse = response{}
|
||||
|
||||
func newResponse(resp *http.Response) runtime.ClientResponse { return response{resp: resp} }
|
||||
|
||||
type response struct {
|
||||
resp *http.Response
|
||||
}
|
||||
|
||||
func (r response) Code() int {
|
||||
return r.resp.StatusCode
|
||||
}
|
||||
|
||||
func (r response) Message() string {
|
||||
return r.resp.Status
|
||||
}
|
||||
|
||||
func (r response) GetHeader(name string) string {
|
||||
return r.resp.Header.Get(name)
|
||||
}
|
||||
|
||||
func (r response) GetHeaders(name string) []string {
|
||||
return r.resp.Header.Values(name)
|
||||
}
|
||||
|
||||
func (r response) Body() io.ReadCloser {
|
||||
return r.resp.Body
|
||||
}
|
552
vendor/github.com/go-openapi/runtime/client/runtime.go
generated
vendored
Normal file
552
vendor/github.com/go-openapi/runtime/client/runtime.go
generated
vendored
Normal file
@ -0,0 +1,552 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/logger"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/runtime/yamlpc"
|
||||
)
|
||||
|
||||
const (
|
||||
schemeHTTP = "http"
|
||||
schemeHTTPS = "https"
|
||||
)
|
||||
|
||||
// TLSClientOptions to configure client authentication with mutual TLS
|
||||
type TLSClientOptions struct {
|
||||
// Certificate is the path to a PEM-encoded certificate to be used for
|
||||
// client authentication. If set then Key must also be set.
|
||||
Certificate string
|
||||
|
||||
// LoadedCertificate is the certificate to be used for client authentication.
|
||||
// This field is ignored if Certificate is set. If this field is set, LoadedKey
|
||||
// is also required.
|
||||
LoadedCertificate *x509.Certificate
|
||||
|
||||
// Key is the path to an unencrypted PEM-encoded private key for client
|
||||
// authentication. This field is required if Certificate is set.
|
||||
Key string
|
||||
|
||||
// LoadedKey is the key for client authentication. This field is required if
|
||||
// LoadedCertificate is set.
|
||||
LoadedKey crypto.PrivateKey
|
||||
|
||||
// CA is a path to a PEM-encoded certificate that specifies the root certificate
|
||||
// to use when validating the TLS certificate presented by the server. If this field
|
||||
// (and LoadedCA) is not set, the system certificate pool is used. This field is ignored if LoadedCA
|
||||
// is set.
|
||||
CA string
|
||||
|
||||
// LoadedCA specifies the root certificate to use when validating the server's TLS certificate.
|
||||
// If this field (and CA) is not set, the system certificate pool is used.
|
||||
LoadedCA *x509.Certificate
|
||||
|
||||
// LoadedCAPool specifies a pool of RootCAs to use when validating the server's TLS certificate.
|
||||
// If set, it will be combined with the other loaded certificates (see LoadedCA and CA).
|
||||
// If neither LoadedCA or CA is set, the provided pool with override the system
|
||||
// certificate pool.
|
||||
// The caller must not use the supplied pool after calling TLSClientAuth.
|
||||
LoadedCAPool *x509.CertPool
|
||||
|
||||
// ServerName specifies the hostname to use when verifying the server certificate.
|
||||
// If this field is set then InsecureSkipVerify will be ignored and treated as
|
||||
// false.
|
||||
ServerName string
|
||||
|
||||
// InsecureSkipVerify controls whether the certificate chain and hostname presented
|
||||
// by the server are validated. If true, any certificate is accepted.
|
||||
InsecureSkipVerify bool
|
||||
|
||||
// VerifyPeerCertificate, if not nil, is called after normal
|
||||
// certificate verification. It receives the raw ASN.1 certificates
|
||||
// provided by the peer and also any verified chains that normal processing found.
|
||||
// If it returns a non-nil error, the handshake is aborted and that error results.
|
||||
//
|
||||
// If normal verification fails then the handshake will abort before
|
||||
// considering this callback. If normal verification is disabled by
|
||||
// setting InsecureSkipVerify then this callback will be considered but
|
||||
// the verifiedChains argument will always be nil.
|
||||
VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
|
||||
|
||||
// SessionTicketsDisabled may be set to true to disable session ticket and
|
||||
// PSK (resumption) support. Note that on clients, session ticket support is
|
||||
// also disabled if ClientSessionCache is nil.
|
||||
SessionTicketsDisabled bool
|
||||
|
||||
// ClientSessionCache is a cache of ClientSessionState entries for TLS
|
||||
// session resumption. It is only used by clients.
|
||||
ClientSessionCache tls.ClientSessionCache
|
||||
|
||||
// Prevents callers using unkeyed fields.
|
||||
_ struct{}
|
||||
}
|
||||
|
||||
// TLSClientAuth creates a tls.Config for mutual auth
|
||||
func TLSClientAuth(opts TLSClientOptions) (*tls.Config, error) {
|
||||
// create client tls config
|
||||
cfg := &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
|
||||
// load client cert if specified
|
||||
if opts.Certificate != "" {
|
||||
cert, err := tls.LoadX509KeyPair(opts.Certificate, opts.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tls client cert: %v", err)
|
||||
}
|
||||
cfg.Certificates = []tls.Certificate{cert}
|
||||
} else if opts.LoadedCertificate != nil {
|
||||
block := pem.Block{Type: "CERTIFICATE", Bytes: opts.LoadedCertificate.Raw}
|
||||
certPem := pem.EncodeToMemory(&block)
|
||||
|
||||
var keyBytes []byte
|
||||
switch k := opts.LoadedKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
keyBytes = x509.MarshalPKCS1PrivateKey(k)
|
||||
case *ecdsa.PrivateKey:
|
||||
var err error
|
||||
keyBytes, err = x509.MarshalECPrivateKey(k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tls client priv key: %v", err)
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("tls client priv key: unsupported key type")
|
||||
}
|
||||
|
||||
block = pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes}
|
||||
keyPem := pem.EncodeToMemory(&block)
|
||||
|
||||
cert, err := tls.X509KeyPair(certPem, keyPem)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tls client cert: %v", err)
|
||||
}
|
||||
cfg.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
|
||||
cfg.InsecureSkipVerify = opts.InsecureSkipVerify
|
||||
|
||||
cfg.VerifyPeerCertificate = opts.VerifyPeerCertificate
|
||||
cfg.SessionTicketsDisabled = opts.SessionTicketsDisabled
|
||||
cfg.ClientSessionCache = opts.ClientSessionCache
|
||||
|
||||
// When no CA certificate is provided, default to the system cert pool
|
||||
// that way when a request is made to a server known by the system trust store,
|
||||
// the name is still verified
|
||||
switch {
|
||||
case opts.LoadedCA != nil:
|
||||
caCertPool := basePool(opts.LoadedCAPool)
|
||||
caCertPool.AddCert(opts.LoadedCA)
|
||||
cfg.RootCAs = caCertPool
|
||||
case opts.CA != "":
|
||||
// load ca cert
|
||||
caCert, err := os.ReadFile(opts.CA)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tls client ca: %v", err)
|
||||
}
|
||||
caCertPool := basePool(opts.LoadedCAPool)
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
cfg.RootCAs = caCertPool
|
||||
case opts.LoadedCAPool != nil:
|
||||
cfg.RootCAs = opts.LoadedCAPool
|
||||
}
|
||||
|
||||
// apply servername overrride
|
||||
if opts.ServerName != "" {
|
||||
cfg.InsecureSkipVerify = false
|
||||
cfg.ServerName = opts.ServerName
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func basePool(pool *x509.CertPool) *x509.CertPool {
|
||||
if pool == nil {
|
||||
return x509.NewCertPool()
|
||||
}
|
||||
return pool
|
||||
}
|
||||
|
||||
// TLSTransport creates a http client transport suitable for mutual tls auth
|
||||
func TLSTransport(opts TLSClientOptions) (http.RoundTripper, error) {
|
||||
cfg, err := TLSClientAuth(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &http.Transport{TLSClientConfig: cfg}, nil
|
||||
}
|
||||
|
||||
// TLSClient creates a http.Client for mutual auth
|
||||
func TLSClient(opts TLSClientOptions) (*http.Client, error) {
|
||||
transport, err := TLSTransport(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &http.Client{Transport: transport}, nil
|
||||
}
|
||||
|
||||
// DefaultTimeout the default request timeout
|
||||
var DefaultTimeout = 30 * time.Second
|
||||
|
||||
// Runtime represents an API client that uses the transport
|
||||
// to make http requests based on a swagger specification.
|
||||
type Runtime struct {
|
||||
DefaultMediaType string
|
||||
DefaultAuthentication runtime.ClientAuthInfoWriter
|
||||
Consumers map[string]runtime.Consumer
|
||||
Producers map[string]runtime.Producer
|
||||
|
||||
Transport http.RoundTripper
|
||||
Jar http.CookieJar
|
||||
// Spec *spec.Document
|
||||
Host string
|
||||
BasePath string
|
||||
Formats strfmt.Registry
|
||||
Context context.Context //nolint:containedctx // we precisely want this type to contain the request context
|
||||
|
||||
Debug bool
|
||||
logger logger.Logger
|
||||
|
||||
clientOnce *sync.Once
|
||||
client *http.Client
|
||||
schemes []string
|
||||
response ClientResponseFunc
|
||||
}
|
||||
|
||||
// New creates a new default runtime for a swagger api runtime.Client
|
||||
func New(host, basePath string, schemes []string) *Runtime {
|
||||
var rt Runtime
|
||||
rt.DefaultMediaType = runtime.JSONMime
|
||||
|
||||
// TODO: actually infer this stuff from the spec
|
||||
rt.Consumers = map[string]runtime.Consumer{
|
||||
runtime.YAMLMime: yamlpc.YAMLConsumer(),
|
||||
runtime.JSONMime: runtime.JSONConsumer(),
|
||||
runtime.XMLMime: runtime.XMLConsumer(),
|
||||
runtime.TextMime: runtime.TextConsumer(),
|
||||
runtime.HTMLMime: runtime.TextConsumer(),
|
||||
runtime.CSVMime: runtime.CSVConsumer(),
|
||||
runtime.DefaultMime: runtime.ByteStreamConsumer(),
|
||||
}
|
||||
rt.Producers = map[string]runtime.Producer{
|
||||
runtime.YAMLMime: yamlpc.YAMLProducer(),
|
||||
runtime.JSONMime: runtime.JSONProducer(),
|
||||
runtime.XMLMime: runtime.XMLProducer(),
|
||||
runtime.TextMime: runtime.TextProducer(),
|
||||
runtime.HTMLMime: runtime.TextProducer(),
|
||||
runtime.CSVMime: runtime.CSVProducer(),
|
||||
runtime.DefaultMime: runtime.ByteStreamProducer(),
|
||||
}
|
||||
rt.Transport = http.DefaultTransport
|
||||
rt.Jar = nil
|
||||
rt.Host = host
|
||||
rt.BasePath = basePath
|
||||
rt.Context = context.Background()
|
||||
rt.clientOnce = new(sync.Once)
|
||||
if !strings.HasPrefix(rt.BasePath, "/") {
|
||||
rt.BasePath = "/" + rt.BasePath
|
||||
}
|
||||
|
||||
rt.Debug = logger.DebugEnabled()
|
||||
rt.logger = logger.StandardLogger{}
|
||||
rt.response = newResponse
|
||||
|
||||
if len(schemes) > 0 {
|
||||
rt.schemes = schemes
|
||||
}
|
||||
return &rt
|
||||
}
|
||||
|
||||
// NewWithClient allows you to create a new transport with a configured http.Client
|
||||
func NewWithClient(host, basePath string, schemes []string, client *http.Client) *Runtime {
|
||||
rt := New(host, basePath, schemes)
|
||||
if client != nil {
|
||||
rt.clientOnce.Do(func() {
|
||||
rt.client = client
|
||||
})
|
||||
}
|
||||
return rt
|
||||
}
|
||||
|
||||
// WithOpenTracing adds opentracing support to the provided runtime.
|
||||
// A new client span is created for each request.
|
||||
// If the context of the client operation does not contain an active span, no span is created.
|
||||
// The provided opts are applied to each spans - for example to add global tags.
|
||||
func (r *Runtime) WithOpenTracing(opts ...opentracing.StartSpanOption) runtime.ClientTransport {
|
||||
return newOpenTracingTransport(r, r.Host, opts)
|
||||
}
|
||||
|
||||
// WithOpenTelemetry adds opentelemetry support to the provided runtime.
|
||||
// A new client span is created for each request.
|
||||
// If the context of the client operation does not contain an active span, no span is created.
|
||||
// The provided opts are applied to each spans - for example to add global tags.
|
||||
func (r *Runtime) WithOpenTelemetry(opts ...OpenTelemetryOpt) runtime.ClientTransport {
|
||||
return newOpenTelemetryTransport(r, r.Host, opts)
|
||||
}
|
||||
|
||||
func (r *Runtime) pickScheme(schemes []string) string {
|
||||
if v := r.selectScheme(r.schemes); v != "" {
|
||||
return v
|
||||
}
|
||||
if v := r.selectScheme(schemes); v != "" {
|
||||
return v
|
||||
}
|
||||
return schemeHTTP
|
||||
}
|
||||
|
||||
func (r *Runtime) selectScheme(schemes []string) string {
|
||||
schLen := len(schemes)
|
||||
if schLen == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
scheme := schemes[0]
|
||||
// prefer https, but skip when not possible
|
||||
if scheme != schemeHTTPS && schLen > 1 {
|
||||
for _, sch := range schemes {
|
||||
if sch == schemeHTTPS {
|
||||
scheme = sch
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return scheme
|
||||
}
|
||||
|
||||
func transportOrDefault(left, right http.RoundTripper) http.RoundTripper {
|
||||
if left == nil {
|
||||
return right
|
||||
}
|
||||
return left
|
||||
}
|
||||
|
||||
// EnableConnectionReuse drains the remaining body from a response
|
||||
// so that go will reuse the TCP connections.
|
||||
//
|
||||
// This is not enabled by default because there are servers where
|
||||
// the response never gets closed and that would make the code hang forever.
|
||||
// So instead it's provided as a http client middleware that can be used to override
|
||||
// any request.
|
||||
func (r *Runtime) EnableConnectionReuse() {
|
||||
if r.client == nil {
|
||||
r.Transport = KeepAliveTransport(
|
||||
transportOrDefault(r.Transport, http.DefaultTransport),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
r.client.Transport = KeepAliveTransport(
|
||||
transportOrDefault(r.client.Transport,
|
||||
transportOrDefault(r.Transport, http.DefaultTransport),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// takes a client operation and creates equivalent http.Request
|
||||
func (r *Runtime) createHttpRequest(operation *runtime.ClientOperation) (*request, *http.Request, error) { //nolint:revive,stylecheck
|
||||
params, _, auth := operation.Params, operation.Reader, operation.AuthInfo
|
||||
|
||||
request := newRequest(operation.Method, operation.PathPattern, params)
|
||||
|
||||
var accept []string
|
||||
accept = append(accept, operation.ProducesMediaTypes...)
|
||||
if err := request.SetHeaderParam(runtime.HeaderAccept, accept...); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if auth == nil && r.DefaultAuthentication != nil {
|
||||
auth = runtime.ClientAuthInfoWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
if req.GetHeaderParams().Get(runtime.HeaderAuthorization) != "" {
|
||||
return nil
|
||||
}
|
||||
return r.DefaultAuthentication.AuthenticateRequest(req, reg)
|
||||
})
|
||||
}
|
||||
// if auth != nil {
|
||||
// if err := auth.AuthenticateRequest(request, r.Formats); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//}
|
||||
|
||||
// TODO: pick appropriate media type
|
||||
cmt := r.DefaultMediaType
|
||||
for _, mediaType := range operation.ConsumesMediaTypes {
|
||||
// Pick first non-empty media type
|
||||
if mediaType != "" {
|
||||
cmt = mediaType
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := r.Producers[cmt]; !ok && cmt != runtime.MultipartFormMime && cmt != runtime.URLencodedFormMime {
|
||||
return nil, nil, fmt.Errorf("none of producers: %v registered. try %s", r.Producers, cmt)
|
||||
}
|
||||
|
||||
req, err := request.buildHTTP(cmt, r.BasePath, r.Producers, r.Formats, auth)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req.URL.Scheme = r.pickScheme(operation.Schemes)
|
||||
req.URL.Host = r.Host
|
||||
req.Host = r.Host
|
||||
return request, req, nil
|
||||
}
|
||||
|
||||
func (r *Runtime) CreateHttpRequest(operation *runtime.ClientOperation) (req *http.Request, err error) { //nolint:revive,stylecheck
|
||||
_, req, err = r.createHttpRequest(operation)
|
||||
return
|
||||
}
|
||||
|
||||
// Submit a request and when there is a body on success it will turn that into the result
|
||||
// all other things are turned into an api error for swagger which retains the status code
|
||||
func (r *Runtime) Submit(operation *runtime.ClientOperation) (interface{}, error) {
|
||||
_, readResponse, _ := operation.Params, operation.Reader, operation.AuthInfo
|
||||
|
||||
request, req, err := r.createHttpRequest(operation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.clientOnce.Do(func() {
|
||||
r.client = &http.Client{
|
||||
Transport: r.Transport,
|
||||
Jar: r.Jar,
|
||||
}
|
||||
})
|
||||
|
||||
if r.Debug {
|
||||
b, err2 := httputil.DumpRequestOut(req, true)
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
r.logger.Debugf("%s\n", string(b))
|
||||
}
|
||||
|
||||
var parentCtx context.Context
|
||||
switch {
|
||||
case operation.Context != nil:
|
||||
parentCtx = operation.Context
|
||||
case r.Context != nil:
|
||||
parentCtx = r.Context
|
||||
default:
|
||||
parentCtx = context.Background()
|
||||
}
|
||||
|
||||
var (
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
)
|
||||
if request.timeout == 0 {
|
||||
// There may be a deadline in the context passed to the operation.
|
||||
// Otherwise, there is no timeout set.
|
||||
ctx, cancel = context.WithCancel(parentCtx)
|
||||
} else {
|
||||
// Sets the timeout passed from request params (by default runtime.DefaultTimeout).
|
||||
// If there is already a deadline in the parent context, the shortest will
|
||||
// apply.
|
||||
ctx, cancel = context.WithTimeout(parentCtx, request.timeout)
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
var client *http.Client
|
||||
if operation.Client != nil {
|
||||
client = operation.Client
|
||||
} else {
|
||||
client = r.client
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
res, err := client.Do(req) // make requests, by default follows 10 redirects before failing
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
ct := res.Header.Get(runtime.HeaderContentType)
|
||||
if ct == "" { // this should really never occur
|
||||
ct = r.DefaultMediaType
|
||||
}
|
||||
|
||||
if r.Debug {
|
||||
printBody := true
|
||||
if ct == runtime.DefaultMime {
|
||||
printBody = false // Spare the terminal from a binary blob.
|
||||
}
|
||||
b, err2 := httputil.DumpResponse(res, printBody)
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
r.logger.Debugf("%s\n", string(b))
|
||||
}
|
||||
|
||||
mt, _, err := mime.ParseMediaType(ct)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse content type: %s", err)
|
||||
}
|
||||
|
||||
cons, ok := r.Consumers[mt]
|
||||
if !ok {
|
||||
if cons, ok = r.Consumers["*/*"]; !ok {
|
||||
// scream about not knowing what to do
|
||||
return nil, fmt.Errorf("no consumer: %q", ct)
|
||||
}
|
||||
}
|
||||
return readResponse.ReadResponse(r.response(res), cons)
|
||||
}
|
||||
|
||||
// SetDebug changes the debug flag.
|
||||
// It ensures that client and middlewares have the set debug level.
|
||||
func (r *Runtime) SetDebug(debug bool) {
|
||||
r.Debug = debug
|
||||
middleware.Debug = debug
|
||||
}
|
||||
|
||||
// SetLogger changes the logger stream.
|
||||
// It ensures that client and middlewares use the same logger.
|
||||
func (r *Runtime) SetLogger(logger logger.Logger) {
|
||||
r.logger = logger
|
||||
middleware.Logger = logger
|
||||
}
|
||||
|
||||
type ClientResponseFunc = func(*http.Response) runtime.ClientResponse //nolint:revive
|
||||
|
||||
// SetResponseReader changes the response reader implementation.
|
||||
func (r *Runtime) SetResponseReader(f ClientResponseFunc) {
|
||||
if f == nil {
|
||||
return
|
||||
}
|
||||
r.response = f
|
||||
}
|
30
vendor/github.com/go-openapi/runtime/client_auth_info.go
generated
vendored
Normal file
30
vendor/github.com/go-openapi/runtime/client_auth_info.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import "github.com/go-openapi/strfmt"
|
||||
|
||||
// A ClientAuthInfoWriterFunc converts a function to a request writer interface
|
||||
type ClientAuthInfoWriterFunc func(ClientRequest, strfmt.Registry) error
|
||||
|
||||
// AuthenticateRequest adds authentication data to the request
|
||||
func (fn ClientAuthInfoWriterFunc) AuthenticateRequest(req ClientRequest, reg strfmt.Registry) error {
|
||||
return fn(req, reg)
|
||||
}
|
||||
|
||||
// A ClientAuthInfoWriter implementor knows how to write authentication info to a request
|
||||
type ClientAuthInfoWriter interface {
|
||||
AuthenticateRequest(ClientRequest, strfmt.Registry) error
|
||||
}
|
41
vendor/github.com/go-openapi/runtime/client_operation.go
generated
vendored
Normal file
41
vendor/github.com/go-openapi/runtime/client_operation.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ClientOperation represents the context for a swagger operation to be submitted to the transport
|
||||
type ClientOperation struct {
|
||||
ID string
|
||||
Method string
|
||||
PathPattern string
|
||||
ProducesMediaTypes []string
|
||||
ConsumesMediaTypes []string
|
||||
Schemes []string
|
||||
AuthInfo ClientAuthInfoWriter
|
||||
Params ClientRequestWriter
|
||||
Reader ClientResponseReader
|
||||
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(*ClientOperation) (interface{}, error)
|
||||
}
|
152
vendor/github.com/go-openapi/runtime/client_request.go
generated
vendored
Normal file
152
vendor/github.com/go-openapi/runtime/client_request.go
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// ClientRequestWriterFunc converts a function to a request writer interface
|
||||
type ClientRequestWriterFunc func(ClientRequest, strfmt.Registry) error
|
||||
|
||||
// WriteToRequest adds data to the request
|
||||
func (fn ClientRequestWriterFunc) WriteToRequest(req ClientRequest, reg strfmt.Registry) error {
|
||||
return fn(req, reg)
|
||||
}
|
||||
|
||||
// ClientRequestWriter is an interface for things that know how to write to a request
|
||||
type ClientRequestWriter interface {
|
||||
WriteToRequest(ClientRequest, strfmt.Registry) error
|
||||
}
|
||||
|
||||
// ClientRequest is an interface for things that know how to
|
||||
// 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
|
||||
|
||||
SetQueryParam(string, ...string) error
|
||||
|
||||
SetFormParam(string, ...string) error
|
||||
|
||||
SetPathParam(string, string) error
|
||||
|
||||
GetQueryParams() url.Values
|
||||
|
||||
SetFileParam(string, ...NamedReadCloser) error
|
||||
|
||||
SetBodyParam(interface{}) error
|
||||
|
||||
SetTimeout(time.Duration) error
|
||||
|
||||
GetMethod() string
|
||||
|
||||
GetPath() string
|
||||
|
||||
GetBody() []byte
|
||||
|
||||
GetBodyParam() interface{}
|
||||
|
||||
GetFileParam() map[string][]NamedReadCloser
|
||||
}
|
||||
|
||||
// NamedReadCloser represents a named ReadCloser interface
|
||||
type NamedReadCloser interface {
|
||||
io.ReadCloser
|
||||
Name() string
|
||||
}
|
||||
|
||||
// NamedReader creates a NamedReadCloser for use as file upload
|
||||
func NamedReader(name string, rdr io.Reader) NamedReadCloser {
|
||||
rc, ok := rdr.(io.ReadCloser)
|
||||
if !ok {
|
||||
rc = io.NopCloser(rdr)
|
||||
}
|
||||
return &namedReadCloser{
|
||||
name: name,
|
||||
cr: rc,
|
||||
}
|
||||
}
|
||||
|
||||
type namedReadCloser struct {
|
||||
name string
|
||||
cr io.ReadCloser
|
||||
}
|
||||
|
||||
func (n *namedReadCloser) Close() error {
|
||||
return n.cr.Close()
|
||||
}
|
||||
func (n *namedReadCloser) Read(p []byte) (int, error) {
|
||||
return n.cr.Read(p)
|
||||
}
|
||||
func (n *namedReadCloser) Name() string {
|
||||
return n.name
|
||||
}
|
||||
|
||||
type TestClientRequest struct {
|
||||
Headers http.Header
|
||||
Body interface{}
|
||||
}
|
||||
|
||||
func (t *TestClientRequest) SetHeaderParam(name string, values ...string) error {
|
||||
if t.Headers == nil {
|
||||
t.Headers = make(http.Header)
|
||||
}
|
||||
t.Headers.Set(name, values[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestClientRequest) SetQueryParam(_ string, _ ...string) error { return nil }
|
||||
|
||||
func (t *TestClientRequest) SetFormParam(_ string, _ ...string) error { return nil }
|
||||
|
||||
func (t *TestClientRequest) SetPathParam(_ string, _ string) error { return nil }
|
||||
|
||||
func (t *TestClientRequest) SetFileParam(_ string, _ ...NamedReadCloser) error { return nil }
|
||||
|
||||
func (t *TestClientRequest) SetBodyParam(body interface{}) error {
|
||||
t.Body = body
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestClientRequest) SetTimeout(time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestClientRequest) GetQueryParams() url.Values { return nil }
|
||||
|
||||
func (t *TestClientRequest) GetMethod() string { return "" }
|
||||
|
||||
func (t *TestClientRequest) GetPath() string { return "" }
|
||||
|
||||
func (t *TestClientRequest) GetBody() []byte { return nil }
|
||||
|
||||
func (t *TestClientRequest) GetBodyParam() interface{} {
|
||||
return t.Body
|
||||
}
|
||||
|
||||
func (t *TestClientRequest) GetFileParam() map[string][]NamedReadCloser {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestClientRequest) GetHeaderParams() http.Header {
|
||||
return t.Headers
|
||||
}
|
110
vendor/github.com/go-openapi/runtime/client_response.go
generated
vendored
Normal file
110
vendor/github.com/go-openapi/runtime/client_response.go
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// A ClientResponse represents a client response
|
||||
// This bridges between responses obtained from different transports
|
||||
type ClientResponse interface {
|
||||
Code() int
|
||||
Message() string
|
||||
GetHeader(string) string
|
||||
GetHeaders(string) []string
|
||||
Body() io.ReadCloser
|
||||
}
|
||||
|
||||
// A ClientResponseReaderFunc turns a function into a ClientResponseReader interface implementation
|
||||
type ClientResponseReaderFunc func(ClientResponse, Consumer) (interface{}, error)
|
||||
|
||||
// ReadResponse reads the response
|
||||
func (read ClientResponseReaderFunc) ReadResponse(resp ClientResponse, consumer Consumer) (interface{}, error) {
|
||||
return read(resp, consumer)
|
||||
}
|
||||
|
||||
// A ClientResponseReader is an interface for things want to read a response.
|
||||
// An application of this is to create structs from response values
|
||||
type ClientResponseReader interface {
|
||||
ReadResponse(ClientResponse, Consumer) (interface{}, error)
|
||||
}
|
||||
|
||||
// NewAPIError creates a new API error
|
||||
func NewAPIError(opName string, payload interface{}, code int) *APIError {
|
||||
return &APIError{
|
||||
OperationName: opName,
|
||||
Response: payload,
|
||||
Code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// APIError wraps an error model and captures the status code
|
||||
type APIError struct {
|
||||
OperationName string
|
||||
Response interface{}
|
||||
Code int
|
||||
}
|
||||
|
||||
func (o *APIError) Error() string {
|
||||
var resp []byte
|
||||
if err, ok := o.Response.(error); ok {
|
||||
resp = []byte("'" + err.Error() + "'")
|
||||
} else {
|
||||
resp, _ = json.Marshal(o.Response)
|
||||
}
|
||||
return fmt.Sprintf("%s (status %d): %s", o.OperationName, o.Code, resp)
|
||||
}
|
||||
|
||||
func (o *APIError) String() string {
|
||||
return o.Error()
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this elapse o k response returns a 2xx status code
|
||||
func (o *APIError) IsSuccess() bool {
|
||||
return o.Code/100 == 2
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this elapse o k response returns a 3xx status code
|
||||
func (o *APIError) IsRedirect() bool {
|
||||
return o.Code/100 == 3
|
||||
}
|
||||
|
||||
// IsClientError returns true when this elapse o k response returns a 4xx status code
|
||||
func (o *APIError) IsClientError() bool {
|
||||
return o.Code/100 == 4
|
||||
}
|
||||
|
||||
// IsServerError returns true when this elapse o k response returns a 5xx status code
|
||||
func (o *APIError) IsServerError() bool {
|
||||
return o.Code/100 == 5
|
||||
}
|
||||
|
||||
// IsCode returns true when this elapse o k response returns a 4xx status code
|
||||
func (o *APIError) IsCode(code int) bool {
|
||||
return o.Code == code
|
||||
}
|
||||
|
||||
// A ClientResponseStatus is a common interface implemented by all responses on the generated code
|
||||
// You can use this to treat any client response based on status code
|
||||
type ClientResponseStatus interface {
|
||||
IsSuccess() bool
|
||||
IsRedirect() bool
|
||||
IsClientError() bool
|
||||
IsServerError() bool
|
||||
IsCode(int) bool
|
||||
}
|
49
vendor/github.com/go-openapi/runtime/constants.go
generated
vendored
Normal file
49
vendor/github.com/go-openapi/runtime/constants.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
const (
|
||||
// HeaderContentType represents a http content-type header, it's value is supposed to be a mime type
|
||||
HeaderContentType = "Content-Type"
|
||||
|
||||
// HeaderTransferEncoding represents a http transfer-encoding header.
|
||||
HeaderTransferEncoding = "Transfer-Encoding"
|
||||
|
||||
// HeaderAccept the Accept header
|
||||
HeaderAccept = "Accept"
|
||||
// HeaderAuthorization the Authorization header
|
||||
HeaderAuthorization = "Authorization"
|
||||
|
||||
charsetKey = "charset"
|
||||
|
||||
// DefaultMime the default fallback mime type
|
||||
DefaultMime = "application/octet-stream"
|
||||
// JSONMime the json mime type
|
||||
JSONMime = "application/json"
|
||||
// YAMLMime the yaml mime type
|
||||
YAMLMime = "application/x-yaml"
|
||||
// XMLMime the xml mime type
|
||||
XMLMime = "application/xml"
|
||||
// TextMime the text mime type
|
||||
TextMime = "text/plain"
|
||||
// HTMLMime the html mime type
|
||||
HTMLMime = "text/html"
|
||||
// CSVMime the csv mime type
|
||||
CSVMime = "text/csv"
|
||||
// MultipartFormMime the multipart form mime type
|
||||
MultipartFormMime = "multipart/form-data"
|
||||
// URLencodedFormMime the url encoded form mime type
|
||||
URLencodedFormMime = "application/x-www-form-urlencoded"
|
||||
)
|
350
vendor/github.com/go-openapi/runtime/csv.go
generated
vendored
Normal file
350
vendor/github.com/go-openapi/runtime/csv.go
generated
vendored
Normal file
@ -0,0 +1,350 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding"
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// 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)
|
||||
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",
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
if data == nil {
|
||||
return errors.New("nil data for CSVProducer")
|
||||
}
|
||||
|
||||
csvWriter := csv.NewWriter(writer)
|
||||
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",
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
9
vendor/github.com/go-openapi/runtime/discard.go
generated
vendored
Normal file
9
vendor/github.com/go-openapi/runtime/discard.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package runtime
|
||||
|
||||
import "io"
|
||||
|
||||
// DiscardConsumer does absolutely nothing, it's a black hole.
|
||||
var DiscardConsumer = ConsumerFunc(func(_ io.Reader, _ interface{}) error { return nil })
|
||||
|
||||
// DiscardProducer does absolutely nothing, it's a black hole.
|
||||
var DiscardProducer = ProducerFunc(func(_ io.Writer, _ interface{}) error { return nil })
|
19
vendor/github.com/go-openapi/runtime/file.go
generated
vendored
Normal file
19
vendor/github.com/go-openapi/runtime/file.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import "github.com/go-openapi/swag"
|
||||
|
||||
type File = swag.File
|
45
vendor/github.com/go-openapi/runtime/headers.go
generated
vendored
Normal file
45
vendor/github.com/go-openapi/runtime/headers.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
)
|
||||
|
||||
// ContentType parses a content type header
|
||||
func ContentType(headers http.Header) (string, string, error) {
|
||||
ct := headers.Get(HeaderContentType)
|
||||
orig := ct
|
||||
if ct == "" {
|
||||
ct = DefaultMime
|
||||
}
|
||||
if ct == "" {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
mt, opts, err := mime.ParseMediaType(ct)
|
||||
if err != nil {
|
||||
return "", "", errors.NewParseError(HeaderContentType, "header", orig, err)
|
||||
}
|
||||
|
||||
if cs, ok := opts[charsetKey]; ok {
|
||||
return mt, cs, nil
|
||||
}
|
||||
|
||||
return mt, "", nil
|
||||
}
|
112
vendor/github.com/go-openapi/runtime/interfaces.go
generated
vendored
Normal file
112
vendor/github.com/go-openapi/runtime/interfaces.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// OperationHandlerFunc an adapter for a function to the OperationHandler interface
|
||||
type OperationHandlerFunc func(interface{}) (interface{}, error)
|
||||
|
||||
// Handle implements the operation handler interface
|
||||
func (s OperationHandlerFunc) Handle(data interface{}) (interface{}, error) {
|
||||
return s(data)
|
||||
}
|
||||
|
||||
// OperationHandler a handler for a swagger operation
|
||||
type OperationHandler interface {
|
||||
Handle(interface{}) (interface{}, error)
|
||||
}
|
||||
|
||||
// ConsumerFunc represents a function that can be used as a consumer
|
||||
type ConsumerFunc func(io.Reader, interface{}) error
|
||||
|
||||
// Consume consumes the reader into the data parameter
|
||||
func (fn ConsumerFunc) Consume(reader io.Reader, data interface{}) error {
|
||||
return fn(reader, data)
|
||||
}
|
||||
|
||||
// Consumer implementations know how to bind the values on the provided interface to
|
||||
// data provided by the request body
|
||||
type Consumer interface {
|
||||
// Consume performs the binding of request values
|
||||
Consume(io.Reader, interface{}) error
|
||||
}
|
||||
|
||||
// ProducerFunc represents a function that can be used as a producer
|
||||
type ProducerFunc func(io.Writer, interface{}) error
|
||||
|
||||
// Produce produces the response for the provided data
|
||||
func (f ProducerFunc) Produce(writer io.Writer, data interface{}) error {
|
||||
return f(writer, data)
|
||||
}
|
||||
|
||||
// Producer implementations know how to turn the provided interface into a valid
|
||||
// HTTP response
|
||||
type Producer interface {
|
||||
// Produce writes to the http response
|
||||
Produce(io.Writer, interface{}) error
|
||||
}
|
||||
|
||||
// AuthenticatorFunc turns a function into an authenticator
|
||||
type AuthenticatorFunc func(interface{}) (bool, interface{}, error)
|
||||
|
||||
// Authenticate authenticates the request with the provided data
|
||||
func (f AuthenticatorFunc) Authenticate(params interface{}) (bool, interface{}, error) {
|
||||
return f(params)
|
||||
}
|
||||
|
||||
// Authenticator represents an authentication strategy
|
||||
// implementations of Authenticator know how to authenticate the
|
||||
// request data and translate that into a valid principal object or an error
|
||||
type Authenticator interface {
|
||||
Authenticate(interface{}) (bool, interface{}, error)
|
||||
}
|
||||
|
||||
// AuthorizerFunc turns a function into an authorizer
|
||||
type AuthorizerFunc func(*http.Request, interface{}) error
|
||||
|
||||
// Authorize authorizes the processing of the request for the principal
|
||||
func (f AuthorizerFunc) Authorize(r *http.Request, principal interface{}) error {
|
||||
return f(r, principal)
|
||||
}
|
||||
|
||||
// Authorizer represents an authorization strategy
|
||||
// implementations of Authorizer know how to authorize the principal object
|
||||
// using the request data and returns error if unauthorized
|
||||
type Authorizer interface {
|
||||
Authorize(*http.Request, interface{}) error
|
||||
}
|
||||
|
||||
// Validatable types implementing this interface allow customizing their validation
|
||||
// this will be used instead of the reflective validation based on the spec document.
|
||||
// the implementations are assumed to have been generated by the swagger tool so they should
|
||||
// contain all the validations obtained from the spec
|
||||
type Validatable interface {
|
||||
Validate(strfmt.Registry) error
|
||||
}
|
||||
|
||||
// ContextValidatable types implementing this interface allow customizing their validation
|
||||
// this will be used instead of the reflective validation based on the spec document.
|
||||
// the implementations are assumed to have been generated by the swagger tool so they should
|
||||
// contain all the context validations obtained from the spec
|
||||
type ContextValidatable interface {
|
||||
ContextValidate(context.Context, strfmt.Registry) error
|
||||
}
|
38
vendor/github.com/go-openapi/runtime/json.go
generated
vendored
Normal file
38
vendor/github.com/go-openapi/runtime/json.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
// JSONConsumer creates a new JSON consumer
|
||||
func JSONConsumer() Consumer {
|
||||
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
|
||||
dec := json.NewDecoder(reader)
|
||||
dec.UseNumber() // preserve number formats
|
||||
return dec.Decode(data)
|
||||
})
|
||||
}
|
||||
|
||||
// JSONProducer creates a new JSON producer
|
||||
func JSONProducer() Producer {
|
||||
return ProducerFunc(func(writer io.Writer, data interface{}) error {
|
||||
enc := json.NewEncoder(writer)
|
||||
enc.SetEscapeHTML(false)
|
||||
return enc.Encode(data)
|
||||
})
|
||||
}
|
20
vendor/github.com/go-openapi/runtime/logger/logger.go
generated
vendored
Normal file
20
vendor/github.com/go-openapi/runtime/logger/logger.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
package logger
|
||||
|
||||
import "os"
|
||||
|
||||
type Logger interface {
|
||||
Printf(format string, args ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
func DebugEnabled() bool {
|
||||
d := os.Getenv("SWAGGER_DEBUG")
|
||||
if d != "" && d != "false" && d != "0" {
|
||||
return true
|
||||
}
|
||||
d = os.Getenv("DEBUG")
|
||||
if d != "" && d != "false" && d != "0" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
24
vendor/github.com/go-openapi/runtime/logger/standard.go
generated
vendored
Normal file
24
vendor/github.com/go-openapi/runtime/logger/standard.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
var _ Logger = StandardLogger{}
|
||||
|
||||
type StandardLogger struct{}
|
||||
|
||||
func (StandardLogger) Printf(format string, args ...interface{}) {
|
||||
if len(format) == 0 || format[len(format)-1] != '\n' {
|
||||
format += "\n"
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, format, args...)
|
||||
}
|
||||
|
||||
func (StandardLogger) Debugf(format string, args ...interface{}) {
|
||||
if len(format) == 0 || format[len(format)-1] != '\n' {
|
||||
format += "\n"
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, format, args...)
|
||||
}
|
722
vendor/github.com/go-openapi/runtime/middleware/context.go
generated
vendored
Normal file
722
vendor/github.com/go-openapi/runtime/middleware/context.go
generated
vendored
Normal file
@ -0,0 +1,722 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
stdContext "context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-openapi/analysis"
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/logger"
|
||||
"github.com/go-openapi/runtime/middleware/untyped"
|
||||
"github.com/go-openapi/runtime/security"
|
||||
)
|
||||
|
||||
// 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 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
|
||||
type Builder func(http.Handler) http.Handler
|
||||
|
||||
// PassthroughBuilder returns the handler, aka the builder identity function
|
||||
func PassthroughBuilder(handler http.Handler) http.Handler { return handler }
|
||||
|
||||
// RequestBinder is an interface for types to implement
|
||||
// when they want to be able to bind from a request
|
||||
type RequestBinder interface {
|
||||
BindRequest(*http.Request, *MatchedRoute) error
|
||||
}
|
||||
|
||||
// Responder is an interface for types to implement
|
||||
// when they want to be considered for writing HTTP responses
|
||||
type Responder interface {
|
||||
WriteResponse(http.ResponseWriter, runtime.Producer)
|
||||
}
|
||||
|
||||
// ResponderFunc wraps a func as a Responder interface
|
||||
type ResponderFunc func(http.ResponseWriter, runtime.Producer)
|
||||
|
||||
// WriteResponse writes to the response
|
||||
func (fn ResponderFunc) WriteResponse(rw http.ResponseWriter, pr runtime.Producer) {
|
||||
fn(rw, pr)
|
||||
}
|
||||
|
||||
// Context is a type safe wrapper around an untyped request context
|
||||
// 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
|
||||
debugLogf func(string, ...any) // a logging function to debug context and all components using it
|
||||
}
|
||||
|
||||
type routableUntypedAPI struct {
|
||||
api *untyped.API
|
||||
hlock *sync.Mutex
|
||||
handlers map[string]map[string]http.Handler
|
||||
defaultConsumes string
|
||||
defaultProduces string
|
||||
}
|
||||
|
||||
func newRoutableUntypedAPI(spec *loads.Document, api *untyped.API, context *Context) *routableUntypedAPI {
|
||||
var handlers map[string]map[string]http.Handler
|
||||
if spec == nil || api == nil {
|
||||
return nil
|
||||
}
|
||||
analyzer := analysis.New(spec.Spec())
|
||||
for method, hls := range analyzer.Operations() {
|
||||
um := strings.ToUpper(method)
|
||||
for path, op := range hls {
|
||||
schemes := analyzer.SecurityRequirementsFor(op)
|
||||
|
||||
if oh, ok := api.OperationHandlerFor(method, path); ok {
|
||||
if handlers == nil {
|
||||
handlers = make(map[string]map[string]http.Handler)
|
||||
}
|
||||
if b, ok := handlers[um]; !ok || b == nil {
|
||||
handlers[um] = make(map[string]http.Handler)
|
||||
}
|
||||
|
||||
var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// lookup route info in the context
|
||||
route, rCtx, _ := context.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
r = rCtx
|
||||
}
|
||||
|
||||
// bind and validate the request using reflection
|
||||
var bound interface{}
|
||||
var validation error
|
||||
bound, r, validation = context.BindAndValidate(r, route)
|
||||
if validation != nil {
|
||||
context.Respond(w, r, route.Produces, route, validation)
|
||||
return
|
||||
}
|
||||
|
||||
// actually handle the request
|
||||
result, err := oh.Handle(bound)
|
||||
if err != nil {
|
||||
// respond with failure
|
||||
context.Respond(w, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
|
||||
// respond with success
|
||||
context.Respond(w, r, route.Produces, route, result)
|
||||
})
|
||||
|
||||
if len(schemes) > 0 {
|
||||
handler = newSecureAPI(context, handler)
|
||||
}
|
||||
handlers[um][path] = handler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &routableUntypedAPI{
|
||||
api: api,
|
||||
hlock: new(sync.Mutex),
|
||||
handlers: handlers,
|
||||
defaultProduces: api.DefaultProduces,
|
||||
defaultConsumes: api.DefaultConsumes,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *routableUntypedAPI) HandlerFor(method, path string) (http.Handler, bool) {
|
||||
r.hlock.Lock()
|
||||
paths, ok := r.handlers[strings.ToUpper(method)]
|
||||
if !ok {
|
||||
r.hlock.Unlock()
|
||||
return nil, false
|
||||
}
|
||||
handler, ok := paths[path]
|
||||
r.hlock.Unlock()
|
||||
return handler, ok
|
||||
}
|
||||
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 {
|
||||
return r.api.ConsumersFor(mediaTypes)
|
||||
}
|
||||
func (r *routableUntypedAPI) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
|
||||
return r.api.ProducersFor(mediaTypes)
|
||||
}
|
||||
func (r *routableUntypedAPI) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
|
||||
return r.api.AuthenticatorsFor(schemes)
|
||||
}
|
||||
func (r *routableUntypedAPI) Authorizer() runtime.Authorizer {
|
||||
return r.api.Authorizer()
|
||||
}
|
||||
func (r *routableUntypedAPI) Formats() strfmt.Registry {
|
||||
return r.api.Formats()
|
||||
}
|
||||
|
||||
func (r *routableUntypedAPI) DefaultProduces() string {
|
||||
return r.defaultProduces
|
||||
}
|
||||
|
||||
func (r *routableUntypedAPI) DefaultConsumes() string {
|
||||
return r.defaultConsumes
|
||||
}
|
||||
|
||||
// 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 {
|
||||
an = analysis.New(spec.Spec())
|
||||
}
|
||||
|
||||
return NewRoutableContextWithAnalyzedSpec(spec, an, routableAPI, routes)
|
||||
}
|
||||
|
||||
// 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"))
|
||||
}
|
||||
|
||||
return &Context{
|
||||
spec: spec,
|
||||
api: routableAPI,
|
||||
analyzer: an,
|
||||
router: routes,
|
||||
debugLogf: debugLogfFunc(nil),
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
router: routes,
|
||||
debugLogf: debugLogfFunc(nil),
|
||||
}
|
||||
ctx.api = newRoutableUntypedAPI(spec, api, ctx)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
// Serve serves the specified spec with the specified api registrations as a http.Handler
|
||||
func Serve(spec *loads.Document, api *untyped.API) http.Handler {
|
||||
return ServeWithBuilder(spec, api, PassthroughBuilder)
|
||||
}
|
||||
|
||||
// ServeWithBuilder serves the specified spec with the specified api registrations as a http.Handler that is decorated
|
||||
// by the Builder
|
||||
func ServeWithBuilder(spec *loads.Document, api *untyped.API, builder Builder) http.Handler {
|
||||
context := NewContext(spec, api, nil)
|
||||
return context.APIHandler(builder)
|
||||
}
|
||||
|
||||
type contextKey int8
|
||||
|
||||
const (
|
||||
_ contextKey = iota
|
||||
ctxContentType
|
||||
ctxResponseFormat
|
||||
ctxMatchedRoute
|
||||
ctxBoundParams
|
||||
ctxSecurityPrincipal
|
||||
ctxSecurityScopes
|
||||
)
|
||||
|
||||
// MatchedRouteFrom request context value.
|
||||
func MatchedRouteFrom(req *http.Request) *MatchedRoute {
|
||||
mr := req.Context().Value(ctxMatchedRoute)
|
||||
if mr == nil {
|
||||
return nil
|
||||
}
|
||||
if res, ok := mr.(*MatchedRoute); ok {
|
||||
return res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SecurityPrincipalFrom request context value.
|
||||
func SecurityPrincipalFrom(req *http.Request) interface{} {
|
||||
return req.Context().Value(ctxSecurityPrincipal)
|
||||
}
|
||||
|
||||
// SecurityScopesFrom request context value.
|
||||
func SecurityScopesFrom(req *http.Request) []string {
|
||||
rs := req.Context().Value(ctxSecurityScopes)
|
||||
if res, ok := rs.([]string); ok {
|
||||
return res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type contentTypeValue struct {
|
||||
MediaType string
|
||||
Charset string
|
||||
}
|
||||
|
||||
// BasePath returns the base path for this API
|
||||
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()
|
||||
}
|
||||
|
||||
// BindValidRequest binds a params object to a request but only when the request is valid
|
||||
// if the request is not valid an error will be returned
|
||||
func (c *Context) BindValidRequest(request *http.Request, route *MatchedRoute, binder RequestBinder) error {
|
||||
var res []error
|
||||
var requestContentType string
|
||||
|
||||
// check and validate content type, select consumer
|
||||
if runtime.HasBody(request) {
|
||||
ct, _, err := runtime.ContentType(request.Header)
|
||||
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)
|
||||
}
|
||||
if len(res) == 0 {
|
||||
cons, ok := route.Consumers[ct]
|
||||
if !ok {
|
||||
res = append(res, errors.New(500, "no consumer registered for %s", ct))
|
||||
} else {
|
||||
route.Consumer = cons
|
||||
requestContentType = ct
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check and validate the response format
|
||||
if len(res) == 0 {
|
||||
// if the route does not provide Produces and a default contentType could not be identified
|
||||
// based on a body, typical for GET and DELETE requests, then default contentType to.
|
||||
if len(route.Produces) == 0 && requestContentType == "" {
|
||||
requestContentType = "*/*"
|
||||
}
|
||||
|
||||
if str := NegotiateContentType(request, route.Produces, requestContentType); str == "" {
|
||||
res = append(res, errors.InvalidResponseFormat(request.Header.Get(runtime.HeaderAccept), route.Produces))
|
||||
}
|
||||
}
|
||||
|
||||
// now bind the request with the provided binder
|
||||
// it's assumed the binder will also validate the request and return an error if the
|
||||
// request is invalid
|
||||
if binder != nil && len(res) == 0 {
|
||||
if err := binder.BindRequest(request, route); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContentType gets the parsed value of a content type
|
||||
// Returns the media type, its charset and a shallow copy of the request
|
||||
// when its context doesn't contain the content type value, otherwise it returns
|
||||
// the same request
|
||||
// Returns the error that runtime.ContentType may retunrs.
|
||||
func (c *Context) ContentType(request *http.Request) (string, string, *http.Request, error) {
|
||||
var rCtx = request.Context()
|
||||
|
||||
if v, ok := rCtx.Value(ctxContentType).(*contentTypeValue); ok {
|
||||
return v.MediaType, v.Charset, request, nil
|
||||
}
|
||||
|
||||
mt, cs, err := runtime.ContentType(request.Header)
|
||||
if err != nil {
|
||||
return "", "", nil, err
|
||||
}
|
||||
rCtx = stdContext.WithValue(rCtx, ctxContentType, &contentTypeValue{mt, cs})
|
||||
return mt, cs, request.WithContext(rCtx), nil
|
||||
}
|
||||
|
||||
// LookupRoute looks a route up and returns true when it is found
|
||||
func (c *Context) LookupRoute(request *http.Request) (*MatchedRoute, bool) {
|
||||
if route, ok := c.router.Lookup(request.Method, request.URL.EscapedPath()); ok {
|
||||
return route, ok
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// RouteInfo tries to match a route for this request
|
||||
// Returns the matched route, a shallow copy of the request if its context
|
||||
// contains the matched router, otherwise the same request, and a bool to
|
||||
// indicate if it the request matches one of the routes, if it doesn't
|
||||
// then it returns false and nil for the other two return values
|
||||
func (c *Context) RouteInfo(request *http.Request) (*MatchedRoute, *http.Request, bool) {
|
||||
var rCtx = request.Context()
|
||||
|
||||
if v, ok := rCtx.Value(ctxMatchedRoute).(*MatchedRoute); ok {
|
||||
return v, request, ok
|
||||
}
|
||||
|
||||
if route, ok := c.LookupRoute(request); ok {
|
||||
rCtx = stdContext.WithValue(rCtx, ctxMatchedRoute, route)
|
||||
return route, request.WithContext(rCtx), ok
|
||||
}
|
||||
|
||||
return nil, nil, false
|
||||
}
|
||||
|
||||
// ResponseFormat negotiates the response content type
|
||||
// Returns the response format and a shallow copy of the request if its context
|
||||
// doesn't contain the response format, otherwise the same request
|
||||
func (c *Context) ResponseFormat(r *http.Request, offers []string) (string, *http.Request) {
|
||||
var rCtx = r.Context()
|
||||
|
||||
if v, ok := rCtx.Value(ctxResponseFormat).(string); ok {
|
||||
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 != "" {
|
||||
c.debugLogf("[%s %s] set response format %q in context", r.Method, r.URL.Path, format)
|
||||
r = r.WithContext(stdContext.WithValue(rCtx, ctxResponseFormat, format))
|
||||
}
|
||||
c.debugLogf("[%s %s] negotiated response format %q", r.Method, r.URL.Path, format)
|
||||
return format, r
|
||||
}
|
||||
|
||||
// AllowedMethods gets the allowed methods for the path of this request
|
||||
func (c *Context) AllowedMethods(request *http.Request) []string {
|
||||
return c.router.OtherMethods(request.Method, request.URL.EscapedPath())
|
||||
}
|
||||
|
||||
// ResetAuth removes the current principal from the request context
|
||||
func (c *Context) ResetAuth(request *http.Request) *http.Request {
|
||||
rctx := request.Context()
|
||||
rctx = stdContext.WithValue(rctx, ctxSecurityPrincipal, nil)
|
||||
rctx = stdContext.WithValue(rctx, ctxSecurityScopes, nil)
|
||||
return request.WithContext(rctx)
|
||||
}
|
||||
|
||||
// Authorize authorizes the request
|
||||
// Returns the principal object and a shallow copy of the request when its
|
||||
// context doesn't contain the principal, otherwise the same request or an error
|
||||
// (the last) if one of the authenticators returns one or an Unauthenticated error
|
||||
func (c *Context) Authorize(request *http.Request, route *MatchedRoute) (interface{}, *http.Request, error) {
|
||||
if route == nil || !route.HasAuth() {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
var rCtx = request.Context()
|
||||
if v := rCtx.Value(ctxSecurityPrincipal); v != nil {
|
||||
return v, request, nil
|
||||
}
|
||||
|
||||
applies, usr, err := route.Authenticators.Authenticate(request, route)
|
||||
if !applies || err != nil || !route.Authenticators.AllowsAnonymous() && usr == nil {
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return nil, nil, errors.Unauthenticated("invalid credentials")
|
||||
}
|
||||
if route.Authorizer != nil {
|
||||
if err := route.Authorizer.Authorize(request, usr); err != nil {
|
||||
if _, ok := err.(errors.Error); ok {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return nil, nil, errors.New(http.StatusForbidden, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
rCtx = request.Context()
|
||||
|
||||
rCtx = stdContext.WithValue(rCtx, ctxSecurityPrincipal, usr)
|
||||
rCtx = stdContext.WithValue(rCtx, ctxSecurityScopes, route.Authenticator.AllScopes())
|
||||
return usr, request.WithContext(rCtx), nil
|
||||
}
|
||||
|
||||
// BindAndValidate binds and validates the request
|
||||
// Returns the validation map and a shallow copy of the request when its context
|
||||
// doesn't contain the validation, otherwise it returns the same request or an
|
||||
// CompositeValidationError error
|
||||
func (c *Context) BindAndValidate(request *http.Request, matched *MatchedRoute) (interface{}, *http.Request, error) {
|
||||
var rCtx = request.Context()
|
||||
|
||||
if v, ok := rCtx.Value(ctxBoundParams).(*validation); ok {
|
||||
c.debugLogf("got cached validation (valid: %t)", len(v.result) == 0)
|
||||
if len(v.result) > 0 {
|
||||
return v.bound, request, errors.CompositeValidationError(v.result...)
|
||||
}
|
||||
return v.bound, request, nil
|
||||
}
|
||||
result := validateRequest(c, request, matched)
|
||||
rCtx = stdContext.WithValue(rCtx, ctxBoundParams, result)
|
||||
request = request.WithContext(rCtx)
|
||||
if len(result.result) > 0 {
|
||||
return result.bound, request, errors.CompositeValidationError(result.result...)
|
||||
}
|
||||
c.debugLogf("no validation errors found")
|
||||
return result.bound, request, nil
|
||||
}
|
||||
|
||||
// NotFound the default not found responder for when no route has been matched yet
|
||||
func (c *Context) NotFound(rw http.ResponseWriter, r *http.Request) {
|
||||
c.Respond(rw, r, []string{c.api.DefaultProduces()}, nil, errors.NotFound("not found"))
|
||||
}
|
||||
|
||||
// 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{}) {
|
||||
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() {
|
||||
offers = append(offers, mt)
|
||||
}
|
||||
}
|
||||
// the default producer is last so more specific producers take precedence
|
||||
offers = append(offers, c.api.DefaultProduces())
|
||||
c.debugLogf("offers: %v", offers)
|
||||
|
||||
var format string
|
||||
format, r = c.ResponseFormat(r, offers)
|
||||
rw.Header().Set(runtime.HeaderContentType, format)
|
||||
|
||||
if resp, ok := data.(Responder); ok {
|
||||
producers := route.Producers
|
||||
// producers contains keys with normalized format, if a format has MIME type parameter such as `text/plain; charset=utf-8`
|
||||
// then you must provide `text/plain` to get the correct producer. HOWEVER, format here is not normalized.
|
||||
prod, ok := producers[normalizeOffer(format)]
|
||||
if !ok {
|
||||
prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
|
||||
pr, ok := prods[c.api.DefaultProduces()]
|
||||
if !ok {
|
||||
panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
|
||||
}
|
||||
prod = pr
|
||||
}
|
||||
resp.WriteResponse(rw, prod)
|
||||
return
|
||||
}
|
||||
|
||||
if err, ok := data.(error); ok {
|
||||
if format == "" {
|
||||
rw.Header().Set(runtime.HeaderContentType, runtime.JSONMime)
|
||||
}
|
||||
|
||||
if realm := security.FailedBasicAuth(r); realm != "" {
|
||||
rw.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", realm))
|
||||
}
|
||||
|
||||
if route == nil || route.Operation == nil {
|
||||
c.api.ServeErrorFor("")(rw, r, err)
|
||||
return
|
||||
}
|
||||
c.api.ServeErrorFor(route.Operation.ID)(rw, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
if route == nil || route.Operation == nil {
|
||||
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, cantFindProducer(format)))
|
||||
}
|
||||
if err := prod.Produce(rw, data); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if _, code, ok := route.Operation.SuccessResponse(); ok {
|
||||
rw.WriteHeader(code)
|
||||
if code == http.StatusNoContent || r.Method == http.MethodHead {
|
||||
return
|
||||
}
|
||||
|
||||
producers := route.Producers
|
||||
prod, ok := producers[format]
|
||||
if !ok {
|
||||
if !ok {
|
||||
prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
|
||||
pr, ok := prods[c.api.DefaultProduces()]
|
||||
if !ok {
|
||||
panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
|
||||
}
|
||||
prod = pr
|
||||
}
|
||||
}
|
||||
if err := prod.Produce(rw, data); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c.api.ServeErrorFor(route.Operation.ID)(rw, r, errors.New(http.StatusInternalServerError, "can't produce response"))
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
specPath, uiOpts, specOpts := c.uiOptionsForHandler(opts)
|
||||
var swaggerUIOpts SwaggerUIOpts
|
||||
fromCommonToAnyOptions(uiOpts, &swaggerUIOpts)
|
||||
|
||||
return Spec(specPath, c.spec.Raw(), SwaggerUI(swaggerUIOpts, c.RoutesHandler(b)), specOpts...)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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
|
||||
func (c *Context) RoutesHandler(builder Builder) http.Handler {
|
||||
b := builder
|
||||
if b == nil {
|
||||
b = PassthroughBuilder
|
||||
}
|
||||
return NewRouter(c, b(NewOperationExecutor(c)))
|
||||
}
|
||||
|
||||
func cantFindProducer(format string) string {
|
||||
return "can't find a producer for " + format
|
||||
}
|
19
vendor/github.com/go-openapi/runtime/middleware/denco/LICENSE
generated
vendored
Normal file
19
vendor/github.com/go-openapi/runtime/middleware/denco/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2014 Naoya Inada <naoina@kuune.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
180
vendor/github.com/go-openapi/runtime/middleware/denco/README.md
generated
vendored
Normal file
180
vendor/github.com/go-openapi/runtime/middleware/denco/README.md
generated
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
# Denco [](https://travis-ci.org/naoina/denco)
|
||||
|
||||
The fast and flexible HTTP request router for [Go](http://golang.org).
|
||||
|
||||
Denco is based on Double-Array implementation of [Kocha-urlrouter](https://github.com/naoina/kocha-urlrouter).
|
||||
However, Denco is optimized and some features added.
|
||||
|
||||
## Features
|
||||
|
||||
* Fast (See [go-http-routing-benchmark](https://github.com/naoina/go-http-routing-benchmark))
|
||||
* [URL patterns](#url-patterns) (`/foo/:bar` and `/foo/*wildcard`)
|
||||
* Small (but enough) URL router API
|
||||
* HTTP request multiplexer like `http.ServeMux`
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/go-openapi/runtime/middleware/denco
|
||||
|
||||
## Using as HTTP request multiplexer
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
func Index(w http.ResponseWriter, r *http.Request, params denco.Params) {
|
||||
fmt.Fprintf(w, "Welcome to Denco!\n")
|
||||
}
|
||||
|
||||
func User(w http.ResponseWriter, r *http.Request, params denco.Params) {
|
||||
fmt.Fprintf(w, "Hello %s!\n", params.Get("name"))
|
||||
}
|
||||
|
||||
func main() {
|
||||
mux := denco.NewMux()
|
||||
handler, err := mux.Build([]denco.Handler{
|
||||
mux.GET("/", Index),
|
||||
mux.GET("/user/:name", User),
|
||||
mux.POST("/user/:name", User),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Fatal(http.ListenAndServe(":8080", handler))
|
||||
}
|
||||
```
|
||||
|
||||
## Using as URL router
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
type route struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
router := denco.New()
|
||||
router.Build([]denco.Record{
|
||||
{"/", &route{"root"}},
|
||||
{"/user/:id", &route{"user"}},
|
||||
{"/user/:name/:id", &route{"username"}},
|
||||
{"/static/*filepath", &route{"static"}},
|
||||
})
|
||||
|
||||
data, params, found := router.Lookup("/")
|
||||
// print `&main.route{name:"root"}, denco.Params(nil), true`.
|
||||
fmt.Printf("%#v, %#v, %#v\n", data, params, found)
|
||||
|
||||
data, params, found = router.Lookup("/user/hoge")
|
||||
// print `&main.route{name:"user"}, denco.Params{denco.Param{Name:"id", Value:"hoge"}}, true`.
|
||||
fmt.Printf("%#v, %#v, %#v\n", data, params, found)
|
||||
|
||||
data, params, found = router.Lookup("/user/hoge/7")
|
||||
// print `&main.route{name:"username"}, denco.Params{denco.Param{Name:"name", Value:"hoge"}, denco.Param{Name:"id", Value:"7"}}, true`.
|
||||
fmt.Printf("%#v, %#v, %#v\n", data, params, found)
|
||||
|
||||
data, params, found = router.Lookup("/static/path/to/file")
|
||||
// print `&main.route{name:"static"}, denco.Params{denco.Param{Name:"filepath", Value:"path/to/file"}}, true`.
|
||||
fmt.Printf("%#v, %#v, %#v\n", data, params, found)
|
||||
}
|
||||
```
|
||||
|
||||
See [Godoc](http://godoc.org/github.com/go-openapi/runtime/middleware/denco) for more details.
|
||||
|
||||
## Getting the value of path parameter
|
||||
|
||||
You can get the value of path parameter by 2 ways.
|
||||
|
||||
1. Using [`denco.Params.Get`](http://godoc.org/github.com/go-openapi/runtime/middleware/denco#Params.Get) method
|
||||
2. Find by loop
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := denco.New()
|
||||
if err := router.Build([]denco.Record{
|
||||
{"/user/:name/:id", "route1"},
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 1. Using denco.Params.Get method.
|
||||
_, params, _ := router.Lookup("/user/alice/1")
|
||||
name := params.Get("name")
|
||||
if name != "" {
|
||||
fmt.Printf("Hello %s.\n", name) // prints "Hello alice.".
|
||||
}
|
||||
|
||||
// 2. Find by loop.
|
||||
for _, param := range params {
|
||||
if param.Name == "name" {
|
||||
fmt.Printf("Hello %s.\n", name) // prints "Hello alice.".
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## URL patterns
|
||||
|
||||
Denco's route matching strategy is "most nearly matching".
|
||||
|
||||
When routes `/:name` and `/alice` have been built, URI `/alice` matches the route `/alice`, not `/:name`.
|
||||
Because URI `/alice` is more match with the route `/alice` than `/:name`.
|
||||
|
||||
For more example, when routes below have been built:
|
||||
|
||||
```
|
||||
/user/alice
|
||||
/user/:name
|
||||
/user/:name/:id
|
||||
/user/alice/:id
|
||||
/user/:id/bob
|
||||
```
|
||||
|
||||
Routes matching are:
|
||||
|
||||
```
|
||||
/user/alice => "/user/alice" (no match with "/user/:name")
|
||||
/user/bob => "/user/:name"
|
||||
/user/naoina/1 => "/user/:name/1"
|
||||
/user/alice/1 => "/user/alice/:id" (no match with "/user/:name/:id")
|
||||
/user/1/bob => "/user/:id/bob" (no match with "/user/:name/:id")
|
||||
/user/alice/bob => "/user/alice/:id" (no match with "/user/:name/:id" and "/user/:id/bob")
|
||||
```
|
||||
|
||||
## Limitation
|
||||
|
||||
Denco has some limitations below.
|
||||
|
||||
* Number of param records (such as `/:name`) must be less than 2^22
|
||||
* Number of elements of internal slice must be less than 2^22
|
||||
|
||||
## Benchmarks
|
||||
|
||||
cd $GOPATH/github.com/go-openapi/runtime/middleware/denco
|
||||
go test -bench . -benchmem
|
||||
|
||||
## License
|
||||
|
||||
Denco is licensed under the MIT License.
|
467
vendor/github.com/go-openapi/runtime/middleware/denco/router.go
generated
vendored
Normal file
467
vendor/github.com/go-openapi/runtime/middleware/denco/router.go
generated
vendored
Normal file
@ -0,0 +1,467 @@
|
||||
// Package denco provides fast URL router.
|
||||
package denco
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// ParamCharacter is a special character for path parameter.
|
||||
ParamCharacter = ':'
|
||||
|
||||
// WildcardCharacter is a special character for wildcard path parameter.
|
||||
WildcardCharacter = '*'
|
||||
|
||||
// TerminationCharacter is a special character for end of path.
|
||||
TerminationCharacter = '#'
|
||||
|
||||
// SeparatorCharacter separates path segments.
|
||||
SeparatorCharacter = '/'
|
||||
|
||||
// PathParamCharacter indicates a RESTCONF path param
|
||||
PathParamCharacter = '='
|
||||
|
||||
// MaxSize is max size of records and internal slice.
|
||||
MaxSize = (1 << 22) - 1
|
||||
)
|
||||
|
||||
// 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{}
|
||||
}
|
||||
|
||||
// New returns a new Router.
|
||||
func New() *Router {
|
||||
return &Router{
|
||||
SizeHint: -1,
|
||||
static: make(map[string]interface{}),
|
||||
param: newDoubleArray(),
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup returns data and path parameters that associated with path.
|
||||
// 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 {
|
||||
return data, nil, true
|
||||
}
|
||||
if len(rt.param.node) == 1 {
|
||||
return nil, nil, false
|
||||
}
|
||||
nd, params, found := rt.param.lookup(path, make([]Param, 0, rt.SizeHint), 1)
|
||||
if !found {
|
||||
return nil, nil, false
|
||||
}
|
||||
for i := 0; i < len(params); i++ {
|
||||
params[i].Name = nd.paramNames[i]
|
||||
}
|
||||
return nd.data, params, true
|
||||
}
|
||||
|
||||
// Build builds URL router from records.
|
||||
func (rt *Router) Build(records []Record) error {
|
||||
statics, params := makeRecords(records)
|
||||
if len(params) > MaxSize {
|
||||
return errors.New("denco: too many records")
|
||||
}
|
||||
if rt.SizeHint < 0 {
|
||||
rt.SizeHint = 0
|
||||
for _, p := range params {
|
||||
size := 0
|
||||
for _, k := range p.Key {
|
||||
if k == ParamCharacter || k == WildcardCharacter {
|
||||
size++
|
||||
}
|
||||
}
|
||||
if size > rt.SizeHint {
|
||||
rt.SizeHint = size
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, r := range statics {
|
||||
rt.static[r.Key] = r.Value
|
||||
}
|
||||
if err := rt.param.build(params, 1, 0, make(map[int]struct{})); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Param represents name and value of path parameter.
|
||||
type Param struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
// Params represents the name and value of path parameters.
|
||||
type Params []Param
|
||||
|
||||
// Get gets the first value associated with the given name.
|
||||
// If there are no values associated with the key, Get returns "".
|
||||
func (ps Params) Get(name string) string {
|
||||
for _, p := range ps {
|
||||
if p.Name == name {
|
||||
return p.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type doubleArray struct {
|
||||
bc []baseCheck
|
||||
node []*node
|
||||
}
|
||||
|
||||
func newDoubleArray() *doubleArray {
|
||||
return &doubleArray{
|
||||
bc: []baseCheck{0},
|
||||
node: []*node{nil}, // A start index is adjusting to 1 because 0 will be used as a mark of non-existent node.
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
//
|
||||
// |----------------------|--|--------|
|
||||
// 32 10 8 0
|
||||
type baseCheck uint32
|
||||
|
||||
func (bc baseCheck) Base() int {
|
||||
return int(bc >> 10)
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetBase(base int) {
|
||||
*bc |= baseCheck(base) << 10
|
||||
}
|
||||
|
||||
func (bc baseCheck) Check() byte {
|
||||
return byte(bc)
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetCheck(check byte) {
|
||||
*bc |= baseCheck(check)
|
||||
}
|
||||
|
||||
func (bc baseCheck) IsEmpty() bool {
|
||||
return bc&0xfffffcff == 0
|
||||
}
|
||||
|
||||
func (bc baseCheck) IsSingleParam() bool {
|
||||
return bc¶mTypeSingle == paramTypeSingle
|
||||
}
|
||||
|
||||
func (bc baseCheck) IsWildcardParam() bool {
|
||||
return bc¶mTypeWildcard == paramTypeWildcard
|
||||
}
|
||||
|
||||
func (bc baseCheck) IsAnyParam() bool {
|
||||
return bc¶mTypeAny != 0
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetSingleParam() {
|
||||
*bc |= (1 << 8)
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetWildcardParam() {
|
||||
*bc |= (1 << 9)
|
||||
}
|
||||
|
||||
const (
|
||||
paramTypeSingle = 0x0100
|
||||
paramTypeWildcard = 0x0200
|
||||
paramTypeAny = 0x0300
|
||||
)
|
||||
|
||||
func (da *doubleArray) lookup(path string, params []Param, idx int) (*node, []Param, bool) {
|
||||
indices := make([]uint64, 0, 1)
|
||||
for i := 0; i < len(path); i++ {
|
||||
if da.bc[idx].IsAnyParam() {
|
||||
indices = append(indices, (uint64(i)<<32)|(uint64(idx)&0xffffffff))
|
||||
}
|
||||
c := path[i]
|
||||
if idx = nextIndex(da.bc[idx].Base(), c); idx >= len(da.bc) || da.bc[idx].Check() != c {
|
||||
goto BACKTRACKING
|
||||
}
|
||||
}
|
||||
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() {
|
||||
nextIdx := nextIndex(da.bc[idx].Base(), ParamCharacter)
|
||||
if nextIdx >= len(da.bc) {
|
||||
break
|
||||
}
|
||||
|
||||
next := NextSeparator(path, i)
|
||||
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() {
|
||||
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
|
||||
}
|
||||
|
||||
// build builds double-array from records.
|
||||
func (da *doubleArray) build(srcs []*record, idx, depth int, usedBase map[int]struct{}) error {
|
||||
sort.Stable(recordSlice(srcs))
|
||||
base, siblings, leaf, err := da.arrange(srcs, idx, depth, usedBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if leaf != nil {
|
||||
nd, err := makeNode(leaf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
da.bc[idx].SetBase(len(da.node))
|
||||
da.node = append(da.node, nd)
|
||||
}
|
||||
for _, sib := range siblings {
|
||||
da.setCheck(nextIndex(base, sib.c), sib.c)
|
||||
}
|
||||
for _, sib := range siblings {
|
||||
records := srcs[sib.start:sib.end]
|
||||
switch sib.c {
|
||||
case ParamCharacter:
|
||||
for _, r := range records {
|
||||
next := NextSeparator(r.Key, depth+1)
|
||||
name := r.Key[depth+1 : next]
|
||||
r.paramNames = append(r.paramNames, name)
|
||||
r.Key = r.Key[next:]
|
||||
}
|
||||
da.bc[idx].SetSingleParam()
|
||||
if err := da.build(records, nextIndex(base, sib.c), 0, usedBase); err != nil {
|
||||
return err
|
||||
}
|
||||
case WildcardCharacter:
|
||||
r := records[0]
|
||||
name := r.Key[depth+1 : len(r.Key)-1]
|
||||
r.paramNames = append(r.paramNames, name)
|
||||
r.Key = ""
|
||||
da.bc[idx].SetWildcardParam()
|
||||
if err := da.build(records, nextIndex(base, sib.c), 0, usedBase); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := da.build(records, nextIndex(base, sib.c), depth+1, usedBase); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setBase sets BASE.
|
||||
func (da *doubleArray) setBase(i, base int) {
|
||||
da.bc[i].SetBase(base)
|
||||
}
|
||||
|
||||
// setCheck sets CHECK.
|
||||
func (da *doubleArray) setCheck(i int, check byte) {
|
||||
da.bc[i].SetCheck(check)
|
||||
}
|
||||
|
||||
// findEmptyIndex returns an index of unused BASE/CHECK node.
|
||||
func (da *doubleArray) findEmptyIndex(start int) int {
|
||||
i := start
|
||||
for ; i < len(da.bc); i++ {
|
||||
if da.bc[i].IsEmpty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// findBase returns good BASE.
|
||||
func (da *doubleArray) findBase(siblings []sibling, start int, usedBase map[int]struct{}) (base int) {
|
||||
for idx, firstChar := start+1, siblings[0].c; ; idx = da.findEmptyIndex(idx + 1) {
|
||||
base = nextIndex(idx, firstChar)
|
||||
if _, used := usedBase[base]; used {
|
||||
continue
|
||||
}
|
||||
i := 0
|
||||
for ; i < len(siblings); i++ {
|
||||
next := nextIndex(base, siblings[i].c)
|
||||
if len(da.bc) <= next {
|
||||
da.bc = append(da.bc, make([]baseCheck, next-len(da.bc)+1)...)
|
||||
}
|
||||
if !da.bc[next].IsEmpty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(siblings) {
|
||||
break
|
||||
}
|
||||
}
|
||||
usedBase[base] = struct{}{}
|
||||
return base
|
||||
}
|
||||
|
||||
func (da *doubleArray) arrange(records []*record, idx, depth int, usedBase map[int]struct{}) (base int, siblings []sibling, leaf *record, err error) {
|
||||
siblings, leaf, err = makeSiblings(records, depth)
|
||||
if err != nil {
|
||||
return -1, nil, nil, err
|
||||
}
|
||||
if len(siblings) < 1 {
|
||||
return -1, nil, leaf, nil
|
||||
}
|
||||
base = da.findBase(siblings, idx, usedBase)
|
||||
if base > MaxSize {
|
||||
return -1, nil, nil, errors.New("denco: too many elements of internal slice")
|
||||
}
|
||||
da.setBase(idx, base)
|
||||
return base, siblings, leaf, err
|
||||
}
|
||||
|
||||
// node represents a node of Double-Array.
|
||||
type node struct {
|
||||
data interface{}
|
||||
|
||||
// Names of path parameters.
|
||||
paramNames []string
|
||||
}
|
||||
|
||||
// makeNode returns a new node from record.
|
||||
func makeNode(r *record) (*node, error) {
|
||||
dups := make(map[string]bool)
|
||||
for _, name := range r.paramNames {
|
||||
if dups[name] {
|
||||
return nil, fmt.Errorf("denco: path parameter `%v' is duplicated in the key `%v'", name, r.Key)
|
||||
}
|
||||
dups[name] = true
|
||||
}
|
||||
return &node{data: r.Value, paramNames: r.paramNames}, nil
|
||||
}
|
||||
|
||||
// sibling represents an intermediate data of build for Double-Array.
|
||||
type sibling struct {
|
||||
// An index of start of duplicated characters.
|
||||
start int
|
||||
|
||||
// An index of end of duplicated characters.
|
||||
end int
|
||||
|
||||
// A character of sibling.
|
||||
c byte
|
||||
}
|
||||
|
||||
// nextIndex returns a next index of array of BASE/CHECK.
|
||||
func nextIndex(base int, c byte) int {
|
||||
return base ^ int(c)
|
||||
}
|
||||
|
||||
// makeSiblings returns slice of sibling.
|
||||
func makeSiblings(records []*record, depth int) (sib []sibling, leaf *record, err error) {
|
||||
var (
|
||||
pc byte
|
||||
n int
|
||||
)
|
||||
for i, r := range records {
|
||||
if len(r.Key) <= depth {
|
||||
leaf = r
|
||||
continue
|
||||
}
|
||||
c := r.Key[depth]
|
||||
switch {
|
||||
case pc < c:
|
||||
sib = append(sib, sibling{start: i, c: c})
|
||||
case pc == c:
|
||||
continue
|
||||
default:
|
||||
return nil, nil, errors.New("denco: BUG: routing table hasn't been sorted")
|
||||
}
|
||||
if n > 0 {
|
||||
sib[n-1].end = i
|
||||
}
|
||||
pc = c
|
||||
n++
|
||||
}
|
||||
if n == 0 {
|
||||
return nil, leaf, nil
|
||||
}
|
||||
sib[n-1].end = len(records)
|
||||
return sib, leaf, nil
|
||||
}
|
||||
|
||||
// Record represents a record data for router construction.
|
||||
type Record struct {
|
||||
// Key for router construction.
|
||||
Key string
|
||||
|
||||
// Result value for Key.
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// NewRecord returns a new Record.
|
||||
func NewRecord(key string, value interface{}) Record {
|
||||
return Record{
|
||||
Key: key,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// record represents a record that use to build the Double-Array.
|
||||
type record struct {
|
||||
Record
|
||||
paramNames []string
|
||||
}
|
||||
|
||||
// makeRecords returns the records that use to build Double-Arrays.
|
||||
func makeRecords(srcs []Record) (statics, params []*record) {
|
||||
termChar := string(TerminationCharacter)
|
||||
paramPrefix := string(SeparatorCharacter) + string(ParamCharacter)
|
||||
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) {
|
||||
r.Key += termChar
|
||||
params = append(params, &record{Record: r})
|
||||
} else {
|
||||
statics = append(statics, &record{Record: r})
|
||||
}
|
||||
}
|
||||
return statics, params
|
||||
}
|
||||
|
||||
// recordSlice represents a slice of Record for sort and implements the sort.Interface.
|
||||
type recordSlice []*record
|
||||
|
||||
// Len implements the sort.Interface.Len.
|
||||
func (rs recordSlice) Len() int {
|
||||
return len(rs)
|
||||
}
|
||||
|
||||
// Less implements the sort.Interface.Less.
|
||||
func (rs recordSlice) Less(i, j int) bool {
|
||||
return rs[i].Key < rs[j].Key
|
||||
}
|
||||
|
||||
// Swap implements the sort.Interface.Swap.
|
||||
func (rs recordSlice) Swap(i, j int) {
|
||||
rs[i], rs[j] = rs[j], rs[i]
|
||||
}
|
106
vendor/github.com/go-openapi/runtime/middleware/denco/server.go
generated
vendored
Normal file
106
vendor/github.com/go-openapi/runtime/middleware/denco/server.go
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
package denco
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Mux represents a multiplexer for HTTP request.
|
||||
type Mux struct{}
|
||||
|
||||
// NewMux returns a new Mux.
|
||||
func NewMux() *Mux {
|
||||
return &Mux{}
|
||||
}
|
||||
|
||||
// GET is shorthand of Mux.Handler("GET", path, handler).
|
||||
func (m *Mux) GET(path string, handler HandlerFunc) Handler {
|
||||
return m.Handler("GET", path, handler)
|
||||
}
|
||||
|
||||
// POST is shorthand of Mux.Handler("POST", path, handler).
|
||||
func (m *Mux) POST(path string, handler HandlerFunc) Handler {
|
||||
return m.Handler("POST", path, handler)
|
||||
}
|
||||
|
||||
// PUT is shorthand of Mux.Handler("PUT", path, handler).
|
||||
func (m *Mux) PUT(path string, handler HandlerFunc) Handler {
|
||||
return m.Handler("PUT", path, handler)
|
||||
}
|
||||
|
||||
// HEAD is shorthand of Mux.Handler("HEAD", path, handler).
|
||||
func (m *Mux) HEAD(path string, handler HandlerFunc) Handler {
|
||||
return m.Handler("HEAD", path, handler)
|
||||
}
|
||||
|
||||
// Handler returns a handler for HTTP method.
|
||||
func (m *Mux) Handler(method, path string, handler HandlerFunc) Handler {
|
||||
return Handler{
|
||||
Method: method,
|
||||
Path: path,
|
||||
Func: handler,
|
||||
}
|
||||
}
|
||||
|
||||
// Build builds a http.Handler.
|
||||
func (m *Mux) Build(handlers []Handler) (http.Handler, error) {
|
||||
recordMap := make(map[string][]Record)
|
||||
for _, h := range handlers {
|
||||
recordMap[h.Method] = append(recordMap[h.Method], NewRecord(h.Path, h.Func))
|
||||
}
|
||||
mux := newServeMux()
|
||||
for m, records := range recordMap {
|
||||
router := New()
|
||||
if err := router.Build(records); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mux.routers[m] = router
|
||||
}
|
||||
return mux, nil
|
||||
}
|
||||
|
||||
// Handler represents a handler of HTTP request.
|
||||
type Handler struct {
|
||||
// Method is an HTTP method.
|
||||
Method string
|
||||
|
||||
// Path is a routing path for handler.
|
||||
Path string
|
||||
|
||||
// Func is a function of handler of HTTP request.
|
||||
Func HandlerFunc
|
||||
}
|
||||
|
||||
// The HandlerFunc type is aliased to type of handler function.
|
||||
type HandlerFunc func(w http.ResponseWriter, r *http.Request, params Params)
|
||||
|
||||
type serveMux struct {
|
||||
routers map[string]*Router
|
||||
}
|
||||
|
||||
func newServeMux() *serveMux {
|
||||
return &serveMux{
|
||||
routers: make(map[string]*Router),
|
||||
}
|
||||
}
|
||||
|
||||
// ServeHTTP implements http.Handler interface.
|
||||
func (mux *serveMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
handler, params := mux.handler(r.Method, r.URL.Path)
|
||||
handler(w, r, params)
|
||||
}
|
||||
|
||||
func (mux *serveMux) handler(method, path string) (HandlerFunc, []Param) {
|
||||
if router, found := mux.routers[method]; found {
|
||||
if handler, params, found := router.Lookup(path); found {
|
||||
return handler.(HandlerFunc), params
|
||||
}
|
||||
}
|
||||
return NotFound, nil
|
||||
}
|
||||
|
||||
// NotFound replies to the request with an HTTP 404 not found error.
|
||||
// NotFound is called when unknown HTTP method or a handler not found.
|
||||
// If you want to use the your own NotFound handler, please overwrite this variable.
|
||||
var NotFound = func(w http.ResponseWriter, r *http.Request, _ Params) {
|
||||
http.NotFound(w, r)
|
||||
}
|
12
vendor/github.com/go-openapi/runtime/middleware/denco/util.go
generated
vendored
Normal file
12
vendor/github.com/go-openapi/runtime/middleware/denco/util.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
package denco
|
||||
|
||||
// NextSeparator returns an index of next separator in path.
|
||||
func NextSeparator(path string, start int) int {
|
||||
for start < len(path) {
|
||||
if c := path[start]; c == '/' || c == TerminationCharacter {
|
||||
break
|
||||
}
|
||||
start++
|
||||
}
|
||||
return start
|
||||
}
|
63
vendor/github.com/go-openapi/runtime/middleware/doc.go
generated
vendored
Normal file
63
vendor/github.com/go-openapi/runtime/middleware/doc.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// 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.
|
||||
|
||||
Pseudo middleware handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"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 {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
332
vendor/github.com/go-openapi/runtime/middleware/header/header.go
generated
vendored
Normal file
332
vendor/github.com/go-openapi/runtime/middleware/header/header.go
generated
vendored
Normal file
@ -0,0 +1,332 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
// this file was taken from the github.com/golang/gddo repository
|
||||
|
||||
// Package header provides functions for parsing HTTP headers.
|
||||
package header
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Octet types from RFC 2616.
|
||||
var octetTypes [256]octetType
|
||||
|
||||
type octetType byte
|
||||
|
||||
const (
|
||||
isToken octetType = 1 << iota
|
||||
isSpace
|
||||
)
|
||||
|
||||
func init() {
|
||||
// OCTET = <any 8-bit sequence of data>
|
||||
// CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
// CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
|
||||
// CR = <US-ASCII CR, carriage return (13)>
|
||||
// LF = <US-ASCII LF, linefeed (10)>
|
||||
// SP = <US-ASCII SP, space (32)>
|
||||
// HT = <US-ASCII HT, horizontal-tab (9)>
|
||||
// <"> = <US-ASCII double-quote mark (34)>
|
||||
// CRLF = CR LF
|
||||
// LWS = [CRLF] 1*( SP | HT )
|
||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
||||
// separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
|
||||
// | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
|
||||
// token = 1*<any CHAR except CTLs or separators>
|
||||
// qdtext = <any TEXT except <">>
|
||||
|
||||
for c := 0; c < 256; c++ {
|
||||
var t octetType
|
||||
isCtl := c <= 31 || c == 127
|
||||
isChar := 0 <= c && c <= 127
|
||||
isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
|
||||
if strings.ContainsRune(" \t\r\n", rune(c)) {
|
||||
t |= isSpace
|
||||
}
|
||||
if isChar && !isCtl && !isSeparator {
|
||||
t |= isToken
|
||||
}
|
||||
octetTypes[c] = t
|
||||
}
|
||||
}
|
||||
|
||||
// Copy returns a shallow copy of the header.
|
||||
func Copy(header http.Header) http.Header {
|
||||
h := make(http.Header)
|
||||
for k, vs := range header {
|
||||
h[k] = vs
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
var timeLayouts = []string{"Mon, 02 Jan 2006 15:04:05 GMT", time.RFC850, time.ANSIC}
|
||||
|
||||
// ParseTime parses the header as time. The zero value is returned if the
|
||||
// header is not present or there is an error parsing the
|
||||
// header.
|
||||
func ParseTime(header http.Header, key string) time.Time {
|
||||
if s := header.Get(key); s != "" {
|
||||
for _, layout := range timeLayouts {
|
||||
if t, err := time.Parse(layout, s); err == nil {
|
||||
return t.UTC()
|
||||
}
|
||||
}
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// ParseList parses a comma separated list of values. Commas are ignored in
|
||||
// quoted strings. Quoted values are not unescaped or unquoted. Whitespace is
|
||||
// trimmed.
|
||||
func ParseList(header http.Header, key string) []string {
|
||||
var result []string
|
||||
for _, s := range header[http.CanonicalHeaderKey(key)] {
|
||||
begin := 0
|
||||
end := 0
|
||||
escape := false
|
||||
quote := false
|
||||
for i := 0; i < len(s); i++ {
|
||||
b := s[i]
|
||||
switch {
|
||||
case escape:
|
||||
escape = false
|
||||
end = i + 1
|
||||
case quote:
|
||||
switch b {
|
||||
case '\\':
|
||||
escape = true
|
||||
case '"':
|
||||
quote = false
|
||||
}
|
||||
end = i + 1
|
||||
case b == '"':
|
||||
quote = true
|
||||
end = i + 1
|
||||
case octetTypes[b]&isSpace != 0:
|
||||
if begin == end {
|
||||
begin = i + 1
|
||||
end = begin
|
||||
}
|
||||
case b == ',':
|
||||
if begin < end {
|
||||
result = append(result, s[begin:end])
|
||||
}
|
||||
begin = i + 1
|
||||
end = begin
|
||||
default:
|
||||
end = i + 1
|
||||
}
|
||||
}
|
||||
if begin < end {
|
||||
result = append(result, s[begin:end])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ParseValueAndParams parses a comma separated list of values with optional
|
||||
// semicolon separated name-value pairs. Content-Type and Content-Disposition
|
||||
// headers are in this format.
|
||||
func ParseValueAndParams(header http.Header, key string) (string, map[string]string) {
|
||||
return parseValueAndParams(header.Get(key))
|
||||
}
|
||||
|
||||
func parseValueAndParams(s string) (value string, params map[string]string) {
|
||||
params = make(map[string]string)
|
||||
value, s = expectTokenSlash(s)
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
value = strings.ToLower(value)
|
||||
s = skipSpace(s)
|
||||
for strings.HasPrefix(s, ";") {
|
||||
var pkey string
|
||||
pkey, s = expectToken(skipSpace(s[1:]))
|
||||
if pkey == "" {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(s, "=") {
|
||||
return
|
||||
}
|
||||
var pvalue string
|
||||
pvalue, s = expectTokenOrQuoted(s[1:])
|
||||
if pvalue == "" {
|
||||
return
|
||||
}
|
||||
pkey = strings.ToLower(pkey)
|
||||
params[pkey] = pvalue
|
||||
s = skipSpace(s)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AcceptSpec ...
|
||||
type AcceptSpec struct {
|
||||
Value string
|
||||
Q float64
|
||||
}
|
||||
|
||||
// ParseAccept2 ...
|
||||
func ParseAccept2(header http.Header, key string) (specs []AcceptSpec) {
|
||||
for _, en := range ParseList(header, key) {
|
||||
v, p := parseValueAndParams(en)
|
||||
var spec AcceptSpec
|
||||
spec.Value = v
|
||||
spec.Q = 1.0
|
||||
if p != nil {
|
||||
if q, ok := p["q"]; ok {
|
||||
spec.Q, _ = expectQuality(q)
|
||||
}
|
||||
}
|
||||
if spec.Q < 0.0 {
|
||||
continue
|
||||
}
|
||||
specs = append(specs, spec)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ParseAccept parses Accept* headers.
|
||||
func ParseAccept(header http.Header, key string) []AcceptSpec {
|
||||
var specs []AcceptSpec
|
||||
loop:
|
||||
for _, s := range header[key] {
|
||||
for {
|
||||
var spec AcceptSpec
|
||||
spec.Value, s = expectTokenSlash(s)
|
||||
if spec.Value == "" {
|
||||
continue loop
|
||||
}
|
||||
spec.Q = 1.0
|
||||
s = skipSpace(s)
|
||||
if strings.HasPrefix(s, ";") {
|
||||
s = skipSpace(s[1:])
|
||||
for !strings.HasPrefix(s, "q=") && s != "" && !strings.HasPrefix(s, ",") {
|
||||
s = skipSpace(s[1:])
|
||||
}
|
||||
if strings.HasPrefix(s, "q=") {
|
||||
spec.Q, s = expectQuality(s[2:])
|
||||
if spec.Q < 0.0 {
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
specs = append(specs, spec)
|
||||
s = skipSpace(s)
|
||||
if !strings.HasPrefix(s, ",") {
|
||||
continue loop
|
||||
}
|
||||
s = skipSpace(s[1:])
|
||||
}
|
||||
}
|
||||
|
||||
return specs
|
||||
}
|
||||
|
||||
func skipSpace(s string) (rest string) {
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
if octetTypes[s[i]]&isSpace == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return s[i:]
|
||||
}
|
||||
|
||||
func expectToken(s string) (token, rest string) {
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
if octetTypes[s[i]]&isToken == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return s[:i], s[i:]
|
||||
}
|
||||
|
||||
func expectTokenSlash(s string) (token, rest string) {
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
b := s[i]
|
||||
if (octetTypes[b]&isToken == 0) && b != '/' {
|
||||
break
|
||||
}
|
||||
}
|
||||
return s[:i], s[i:]
|
||||
}
|
||||
|
||||
func expectQuality(s string) (q float64, rest string) {
|
||||
switch {
|
||||
case len(s) == 0:
|
||||
return -1, ""
|
||||
case s[0] == '0':
|
||||
// q is already 0
|
||||
s = s[1:]
|
||||
case s[0] == '1':
|
||||
s = s[1:]
|
||||
q = 1
|
||||
case s[0] == '.':
|
||||
// q is already 0
|
||||
default:
|
||||
return -1, ""
|
||||
}
|
||||
if !strings.HasPrefix(s, ".") {
|
||||
return q, s
|
||||
}
|
||||
s = s[1:]
|
||||
i := 0
|
||||
n := 0
|
||||
d := 1
|
||||
for ; i < len(s); i++ {
|
||||
b := s[i]
|
||||
if b < '0' || b > '9' {
|
||||
break
|
||||
}
|
||||
n = n*10 + int(b) - '0'
|
||||
d *= 10
|
||||
}
|
||||
return q + float64(n)/float64(d), s[i:]
|
||||
}
|
||||
|
||||
func expectTokenOrQuoted(s string) (value string, rest string) {
|
||||
if !strings.HasPrefix(s, "\"") {
|
||||
return expectToken(s)
|
||||
}
|
||||
s = s[1:]
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case '"':
|
||||
return s[:i], s[i+1:]
|
||||
case '\\':
|
||||
p := make([]byte, len(s)-1)
|
||||
j := copy(p, s[:i])
|
||||
escape := true
|
||||
for i++; i < len(s); i++ {
|
||||
b := s[i]
|
||||
switch {
|
||||
case escape:
|
||||
escape = false
|
||||
p[j] = b
|
||||
j++
|
||||
case b == '\\':
|
||||
escape = true
|
||||
case b == '"':
|
||||
return string(p[:j]), s[i+1:]
|
||||
default:
|
||||
p[j] = b
|
||||
j++
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
98
vendor/github.com/go-openapi/runtime/middleware/negotiate.go
generated
vendored
Normal file
98
vendor/github.com/go-openapi/runtime/middleware/negotiate.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
// this file was taken from the github.com/golang/gddo repository
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware/header"
|
||||
)
|
||||
|
||||
// NegotiateContentEncoding returns the best offered content encoding for the
|
||||
// request's Accept-Encoding header. If two offers match with equal weight and
|
||||
// then the offer earlier in the list is preferred. If no offers are
|
||||
// acceptable, then "" is returned.
|
||||
func NegotiateContentEncoding(r *http.Request, offers []string) string {
|
||||
bestOffer := "identity"
|
||||
bestQ := -1.0
|
||||
specs := header.ParseAccept(r.Header, "Accept-Encoding")
|
||||
for _, offer := range offers {
|
||||
for _, spec := range specs {
|
||||
if spec.Q > bestQ &&
|
||||
(spec.Value == "*" || spec.Value == offer) {
|
||||
bestQ = spec.Q
|
||||
bestOffer = offer
|
||||
}
|
||||
}
|
||||
}
|
||||
if bestQ == 0 {
|
||||
bestOffer = ""
|
||||
}
|
||||
return bestOffer
|
||||
}
|
||||
|
||||
// NegotiateContentType returns the best offered content type for the request's
|
||||
// Accept header. If two offers match with equal weight, then the more specific
|
||||
// offer is preferred. For example, text/* trumps */*. If two offers match
|
||||
// with equal weight and specificity, then the offer earlier in the list is
|
||||
// preferred. If no offers match, then defaultOffer is returned.
|
||||
func NegotiateContentType(r *http.Request, offers []string, defaultOffer string) string {
|
||||
bestOffer := defaultOffer
|
||||
bestQ := -1.0
|
||||
bestWild := 3
|
||||
specs := header.ParseAccept(r.Header, "Accept")
|
||||
for _, rawOffer := range offers {
|
||||
offer := normalizeOffer(rawOffer)
|
||||
// No Accept header: just return the first offer.
|
||||
if len(specs) == 0 {
|
||||
return rawOffer
|
||||
}
|
||||
for _, spec := range specs {
|
||||
switch {
|
||||
case spec.Q == 0.0:
|
||||
// ignore
|
||||
case spec.Q < bestQ:
|
||||
// better match found
|
||||
case spec.Value == "*/*":
|
||||
if spec.Q > bestQ || bestWild > 2 {
|
||||
bestQ = spec.Q
|
||||
bestWild = 2
|
||||
bestOffer = rawOffer
|
||||
}
|
||||
case strings.HasSuffix(spec.Value, "/*"):
|
||||
if strings.HasPrefix(offer, spec.Value[:len(spec.Value)-1]) &&
|
||||
(spec.Q > bestQ || bestWild > 1) {
|
||||
bestQ = spec.Q
|
||||
bestWild = 1
|
||||
bestOffer = rawOffer
|
||||
}
|
||||
default:
|
||||
if spec.Value == offer &&
|
||||
(spec.Q > bestQ || bestWild > 0) {
|
||||
bestQ = spec.Q
|
||||
bestWild = 0
|
||||
bestOffer = rawOffer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestOffer
|
||||
}
|
||||
|
||||
func normalizeOffers(orig []string) (norm []string) {
|
||||
for _, o := range orig {
|
||||
norm = append(norm, normalizeOffer(o))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func normalizeOffer(orig string) string {
|
||||
return strings.SplitN(orig, ";", 2)[0]
|
||||
}
|
67
vendor/github.com/go-openapi/runtime/middleware/not_implemented.go
generated
vendored
Normal file
67
vendor/github.com/go-openapi/runtime/middleware/not_implemented.go
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
type errorResp struct {
|
||||
code int
|
||||
response interface{}
|
||||
headers http.Header
|
||||
}
|
||||
|
||||
func (e *errorResp) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
for k, v := range e.headers {
|
||||
for _, val := range v {
|
||||
rw.Header().Add(k, val)
|
||||
}
|
||||
}
|
||||
if e.code > 0 {
|
||||
rw.WriteHeader(e.code)
|
||||
} else {
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
if err := producer.Produce(rw, e.response); err != nil {
|
||||
Logger.Printf("failed to write error response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// NotImplemented the error response when the response is not implemented
|
||||
func NotImplemented(message string) Responder {
|
||||
return Error(http.StatusNotImplemented, message)
|
||||
}
|
||||
|
||||
// Error creates a generic responder for returning errors, the data will be serialized
|
||||
// with the matching producer for the request
|
||||
func Error(code int, data interface{}, headers ...http.Header) Responder {
|
||||
var hdr http.Header
|
||||
for _, h := range headers {
|
||||
for k, v := range h {
|
||||
if hdr == nil {
|
||||
hdr = make(http.Header)
|
||||
}
|
||||
hdr[k] = v
|
||||
}
|
||||
}
|
||||
return &errorResp{
|
||||
code: code,
|
||||
response: data,
|
||||
headers: hdr,
|
||||
}
|
||||
}
|
30
vendor/github.com/go-openapi/runtime/middleware/operation.go
generated
vendored
Normal file
30
vendor/github.com/go-openapi/runtime/middleware/operation.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package middleware
|
||||
|
||||
import "net/http"
|
||||
|
||||
// NewOperationExecutor creates a context aware middleware that handles the operations after routing
|
||||
func NewOperationExecutor(ctx *Context) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
// use context to lookup routes
|
||||
route, rCtx, _ := ctx.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
r = rCtx
|
||||
}
|
||||
|
||||
route.Handler.ServeHTTP(rw, r)
|
||||
})
|
||||
}
|
491
vendor/github.com/go-openapi/runtime/middleware/parameter.go
generated
vendored
Normal file
491
vendor/github.com/go-openapi/runtime/middleware/parameter.go
generated
vendored
Normal file
@ -0,0 +1,491 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
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 {
|
||||
binder := new(untypedParamBinder)
|
||||
binder.Name = param.Name
|
||||
binder.parameter = ¶m
|
||||
binder.formats = formats
|
||||
if param.In != "body" {
|
||||
binder.validator = validate.NewParamValidator(¶m, formats)
|
||||
} else {
|
||||
binder.validator = validate.NewSchemaValidator(param.Schema, spec, param.Name, formats)
|
||||
}
|
||||
|
||||
return binder
|
||||
}
|
||||
|
||||
type untypedParamBinder struct {
|
||||
parameter *spec.Parameter
|
||||
formats strfmt.Registry
|
||||
Name string
|
||||
validator validate.EntityValidator
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) Type() reflect.Type {
|
||||
return p.typeForSchema(p.parameter.Type, p.parameter.Format, p.parameter.Items)
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) typeForSchema(tpe, format string, items *spec.Items) reflect.Type {
|
||||
switch tpe {
|
||||
case "boolean":
|
||||
return reflect.TypeOf(true)
|
||||
|
||||
case typeString:
|
||||
if tt, ok := p.formats.GetType(format); ok {
|
||||
return tt
|
||||
}
|
||||
return reflect.TypeOf("")
|
||||
|
||||
case "integer":
|
||||
switch format {
|
||||
case "int8":
|
||||
return reflect.TypeOf(int8(0))
|
||||
case "int16":
|
||||
return reflect.TypeOf(int16(0))
|
||||
case "int32":
|
||||
return reflect.TypeOf(int32(0))
|
||||
case "int64":
|
||||
return reflect.TypeOf(int64(0))
|
||||
default:
|
||||
return reflect.TypeOf(int64(0))
|
||||
}
|
||||
|
||||
case "number":
|
||||
switch format {
|
||||
case "float":
|
||||
return reflect.TypeOf(float32(0))
|
||||
case "double":
|
||||
return reflect.TypeOf(float64(0))
|
||||
}
|
||||
|
||||
case typeArray:
|
||||
if items == nil {
|
||||
return nil
|
||||
}
|
||||
itemsType := p.typeForSchema(items.Type, items.Format, items.Items)
|
||||
if itemsType == nil {
|
||||
return nil
|
||||
}
|
||||
return reflect.MakeSlice(reflect.SliceOf(itemsType), 0, 0).Type()
|
||||
|
||||
case "file":
|
||||
return reflect.TypeOf(&runtime.File{}).Elem()
|
||||
|
||||
case "object":
|
||||
return reflect.TypeOf(map[string]interface{}{})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) allowsMulti() bool {
|
||||
return p.parameter.In == "query" || p.parameter.In == "formData"
|
||||
}
|
||||
|
||||
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 == typeArray {
|
||||
if cf == "multi" {
|
||||
if !p.allowsMulti() {
|
||||
return nil, false, false, errors.InvalidCollectionFormat(name, in, cf)
|
||||
}
|
||||
vv, hasKey, _ := values.GetOK(name)
|
||||
return vv, false, hasKey, nil
|
||||
}
|
||||
|
||||
v, hk, hv := values.GetOK(name)
|
||||
if !hv {
|
||||
return nil, false, hk, nil
|
||||
}
|
||||
d, c, e := p.readFormattedSliceFieldValue(v[len(v)-1], target)
|
||||
return d, c, hk, e
|
||||
}
|
||||
|
||||
vv, hk, _ := values.GetOK(name)
|
||||
return vv, false, hk, nil
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, target reflect.Value) error {
|
||||
// fmt.Println("binding", p.name, "as", p.Type())
|
||||
switch p.parameter.In {
|
||||
case "query":
|
||||
data, custom, hasKey, err := p.readValue(runtime.Values(request.URL.Query()), target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if custom {
|
||||
return nil
|
||||
}
|
||||
|
||||
return p.bindValue(data, hasKey, target)
|
||||
|
||||
case "header":
|
||||
data, custom, hasKey, err := p.readValue(runtime.Values(request.Header), target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if custom {
|
||||
return nil
|
||||
}
|
||||
return p.bindValue(data, hasKey, target)
|
||||
|
||||
case "path":
|
||||
data, custom, hasKey, err := p.readValue(routeParams, target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if custom {
|
||||
return nil
|
||||
}
|
||||
return p.bindValue(data, hasKey, target)
|
||||
|
||||
case "formData":
|
||||
var err error
|
||||
var mt string
|
||||
|
||||
mt, _, e := runtime.ContentType(request.Header)
|
||||
if e != nil {
|
||||
// because of the interface conversion go thinks the error is not nil
|
||||
// so we first check for nil and then set the err var if it's not nil
|
||||
err = e
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return errors.InvalidContentType("", []string{"multipart/form-data", "application/x-www-form-urlencoded"})
|
||||
}
|
||||
|
||||
if mt != "multipart/form-data" && mt != "application/x-www-form-urlencoded" {
|
||||
return errors.InvalidContentType(mt, []string{"multipart/form-data", "application/x-www-form-urlencoded"})
|
||||
}
|
||||
|
||||
if mt == "multipart/form-data" {
|
||||
if err = request.ParseMultipartForm(defaultMaxMemory); err != nil {
|
||||
return errors.NewParseError(p.Name, p.parameter.In, "", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = request.ParseForm(); err != nil {
|
||||
return errors.NewParseError(p.Name, p.parameter.In, "", err)
|
||||
}
|
||||
|
||||
if p.parameter.Type == "file" {
|
||||
file, header, ffErr := request.FormFile(p.parameter.Name)
|
||||
if ffErr != nil {
|
||||
if p.parameter.Required {
|
||||
return errors.NewParseError(p.Name, p.parameter.In, "", ffErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
target.Set(reflect.ValueOf(runtime.File{Data: file, Header: header}))
|
||||
return nil
|
||||
}
|
||||
|
||||
if request.MultipartForm != nil {
|
||||
data, custom, hasKey, rvErr := p.readValue(runtime.Values(request.MultipartForm.Value), target)
|
||||
if rvErr != nil {
|
||||
return rvErr
|
||||
}
|
||||
if custom {
|
||||
return nil
|
||||
}
|
||||
return p.bindValue(data, hasKey, target)
|
||||
}
|
||||
data, custom, hasKey, err := p.readValue(runtime.Values(request.PostForm), target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if custom {
|
||||
return nil
|
||||
}
|
||||
return p.bindValue(data, hasKey, target)
|
||||
|
||||
case "body":
|
||||
newValue := reflect.New(target.Type())
|
||||
if !runtime.HasBody(request) {
|
||||
if p.parameter.Default != nil {
|
||||
target.Set(reflect.ValueOf(p.parameter.Default))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
if err := consumer.Consume(request.Body, newValue.Interface()); err != nil {
|
||||
if err == io.EOF && p.parameter.Default != nil {
|
||||
target.Set(reflect.ValueOf(p.parameter.Default))
|
||||
return nil
|
||||
}
|
||||
tpe := p.parameter.Type
|
||||
if p.parameter.Format != "" {
|
||||
tpe = p.parameter.Format
|
||||
}
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, nil)
|
||||
}
|
||||
target.Set(reflect.Indirect(newValue))
|
||||
return nil
|
||||
default:
|
||||
return errors.New(500, fmt.Sprintf("invalid parameter location %q", p.parameter.In))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) bindValue(data []string, hasKey bool, target reflect.Value) error {
|
||||
if p.parameter.Type == typeArray {
|
||||
return p.setSliceFieldValue(target, p.parameter.Default, data, hasKey)
|
||||
}
|
||||
var d string
|
||||
if len(data) > 0 {
|
||||
d = data[len(data)-1]
|
||||
}
|
||||
return p.setFieldValue(target, p.parameter.Default, d, hasKey)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if (!hasKey || (!p.parameter.AllowEmptyValue && data == "")) && p.parameter.Required && p.parameter.Default == nil {
|
||||
return errors.Required(p.Name, p.parameter.In, data)
|
||||
}
|
||||
|
||||
ok, err := p.tryUnmarshaler(target, defaultValue, data)
|
||||
if err != nil {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
defVal := reflect.Zero(target.Type())
|
||||
if defaultValue != nil {
|
||||
defVal = reflect.ValueOf(defaultValue)
|
||||
}
|
||||
|
||||
if tpe == "byte" {
|
||||
if data == "" {
|
||||
if target.CanSet() {
|
||||
target.SetBytes(defVal.Bytes())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
b, err := base64.StdEncoding.DecodeString(data)
|
||||
if err != nil {
|
||||
b, err = base64.URLEncoding.DecodeString(data)
|
||||
if err != nil {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.SetBytes(b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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() {
|
||||
target.SetBool(defVal.Bool())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
b, err := swag.ConvertBool(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.SetBool(b)
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if data == "" {
|
||||
if target.CanSet() {
|
||||
rd := defVal.Convert(reflect.TypeOf(int64(0)))
|
||||
target.SetInt(rd.Int())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
i, err := strconv.ParseInt(data, 10, 64)
|
||||
if err != nil {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.OverflowInt(i) {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.SetInt(i)
|
||||
}
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
if data == "" {
|
||||
if target.CanSet() {
|
||||
rd := defVal.Convert(reflect.TypeOf(uint64(0)))
|
||||
target.SetUint(rd.Uint())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
u, err := strconv.ParseUint(data, 10, 64)
|
||||
if err != nil {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.OverflowUint(u) {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.SetUint(u)
|
||||
}
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if data == "" {
|
||||
if target.CanSet() {
|
||||
rd := defVal.Convert(reflect.TypeOf(float64(0)))
|
||||
target.SetFloat(rd.Float())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
f, err := strconv.ParseFloat(data, 64)
|
||||
if err != nil {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.OverflowFloat(f) {
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.SetFloat(f)
|
||||
}
|
||||
|
||||
case reflect.String:
|
||||
value := data
|
||||
if value == "" {
|
||||
value = defVal.String()
|
||||
}
|
||||
// validate string
|
||||
if target.CanSet() {
|
||||
target.SetString(value)
|
||||
}
|
||||
|
||||
case reflect.Ptr:
|
||||
if data == "" && defVal.Kind() == reflect.Ptr {
|
||||
if target.CanSet() {
|
||||
target.Set(defVal)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
newVal := reflect.New(target.Type().Elem())
|
||||
if err := p.setFieldValue(reflect.Indirect(newVal), defVal, data, hasKey); err != nil {
|
||||
return err
|
||||
}
|
||||
if target.CanSet() {
|
||||
target.Set(newVal)
|
||||
}
|
||||
|
||||
default:
|
||||
return errors.InvalidType(p.Name, p.parameter.In, tpe, data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) tryUnmarshaler(target reflect.Value, defaultValue interface{}, data string) (bool, error) {
|
||||
if !target.CanSet() {
|
||||
return false, nil
|
||||
}
|
||||
// When a type implements encoding.TextUnmarshaler we'll use that instead of reflecting some more
|
||||
if reflect.PtrTo(target.Type()).Implements(textUnmarshalType) {
|
||||
if defaultValue != nil && len(data) == 0 {
|
||||
target.Set(reflect.ValueOf(defaultValue))
|
||||
return true, nil
|
||||
}
|
||||
value := reflect.New(target.Type())
|
||||
if err := value.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(data)); err != nil {
|
||||
return true, err
|
||||
}
|
||||
target.Set(reflect.Indirect(value))
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) readFormattedSliceFieldValue(data string, target reflect.Value) ([]string, bool, error) {
|
||||
ok, err := p.tryUnmarshaler(target, p.parameter.Default, data)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
if ok {
|
||||
return nil, true, nil
|
||||
}
|
||||
|
||||
return swag.SplitByFormat(data, p.parameter.CollectionFormat), false, nil
|
||||
}
|
||||
|
||||
func (p *untypedParamBinder) setSliceFieldValue(target reflect.Value, defaultValue interface{}, data []string, hasKey bool) error {
|
||||
sz := len(data)
|
||||
if (!hasKey || (!p.parameter.AllowEmptyValue && (sz == 0 || (sz == 1 && data[0] == "")))) && p.parameter.Required && defaultValue == nil {
|
||||
return errors.Required(p.Name, p.parameter.In, data)
|
||||
}
|
||||
|
||||
defVal := reflect.Zero(target.Type())
|
||||
if defaultValue != nil {
|
||||
defVal = reflect.ValueOf(defaultValue)
|
||||
}
|
||||
|
||||
if !target.CanSet() {
|
||||
return nil
|
||||
}
|
||||
if sz == 0 {
|
||||
target.Set(defVal)
|
||||
return nil
|
||||
}
|
||||
|
||||
value := reflect.MakeSlice(reflect.SliceOf(target.Type().Elem()), sz, sz)
|
||||
|
||||
for i := 0; i < sz; i++ {
|
||||
if err := p.setFieldValue(value.Index(i), nil, data[i], hasKey); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
target.Set(value)
|
||||
|
||||
return nil
|
||||
}
|
80
vendor/github.com/go-openapi/runtime/middleware/rapidoc.go
generated
vendored
Normal file
80
vendor/github.com/go-openapi/runtime/middleware/rapidoc.go
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path"
|
||||
)
|
||||
|
||||
// RapiDocOpts configures the RapiDoc middlewares
|
||||
type RapiDocOpts 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
|
||||
|
||||
// RapiDocURL points to the js asset that generates the rapidoc site.
|
||||
//
|
||||
// Defaults to https://unpkg.com/rapidoc/dist/rapidoc-min.js
|
||||
RapiDocURL string
|
||||
}
|
||||
|
||||
func (r *RapiDocOpts) EnsureDefaults() {
|
||||
common := toCommonUIOptions(r)
|
||||
common.EnsureDefaults()
|
||||
fromCommonToAnyOptions(common, r)
|
||||
|
||||
// rapidoc-specifics
|
||||
if r.RapiDocURL == "" {
|
||||
r.RapiDocURL = rapidocLatest
|
||||
}
|
||||
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.
|
||||
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(opts.Template))
|
||||
assets := bytes.NewBuffer(nil)
|
||||
if err := tmpl.Execute(assets, opts); err != nil {
|
||||
panic(fmt.Errorf("cannot execute template: %w", err))
|
||||
}
|
||||
|
||||
return serveUI(pth, assets.Bytes(), next)
|
||||
}
|
||||
|
||||
const (
|
||||
rapidocLatest = "https://unpkg.com/rapidoc/dist/rapidoc-min.js"
|
||||
rapidocTemplate = `<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ .Title }}</title>
|
||||
<meta charset="utf-8"> <!-- Important: rapi-doc uses utf8 characters -->
|
||||
<script type="module" src="{{ .RapiDocURL }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
<rapi-doc spec-url="{{ .SpecURL }}"></rapi-doc>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
)
|
94
vendor/github.com/go-openapi/runtime/middleware/redoc.go
generated
vendored
Normal file
94
vendor/github.com/go-openapi/runtime/middleware/redoc.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path"
|
||||
)
|
||||
|
||||
// RedocOpts configures the Redoc middlewares
|
||||
type RedocOpts 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
|
||||
|
||||
// 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() {
|
||||
common := toCommonUIOptions(r)
|
||||
common.EnsureDefaults()
|
||||
fromCommonToAnyOptions(common, r)
|
||||
|
||||
// redoc-specifics
|
||||
if r.RedocURL == "" {
|
||||
r.RedocURL = redocLatest
|
||||
}
|
||||
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.
|
||||
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(opts.Template))
|
||||
assets := bytes.NewBuffer(nil)
|
||||
if err := tmpl.Execute(assets, opts); err != nil {
|
||||
panic(fmt.Errorf("cannot execute template: %w", err))
|
||||
}
|
||||
|
||||
return serveUI(pth, assets.Bytes(), next)
|
||||
}
|
||||
|
||||
const (
|
||||
redocLatest = "https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js"
|
||||
redocTemplate = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ .Title }}</title>
|
||||
<!-- needed for adaptive design -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
||||
|
||||
<!--
|
||||
ReDoc doesn't change outer page styles
|
||||
-->
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<redoc spec-url='{{ .SpecURL }}'></redoc>
|
||||
<script src="{{ .RedocURL }}"> </script>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
)
|
117
vendor/github.com/go-openapi/runtime/middleware/request.go
generated
vendored
Normal file
117
vendor/github.com/go-openapi/runtime/middleware/request.go
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"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"
|
||||
)
|
||||
|
||||
// UntypedRequestBinder binds and validates the data from a http request
|
||||
type UntypedRequestBinder struct {
|
||||
Spec *spec.Swagger
|
||||
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.
|
||||
func NewUntypedRequestBinder(parameters map[string]spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *UntypedRequestBinder {
|
||||
binders := make(map[string]*untypedParamBinder)
|
||||
for fieldName, param := range parameters {
|
||||
binders[fieldName] = newUntypedParamBinder(param, spec, formats)
|
||||
}
|
||||
return &UntypedRequestBinder{
|
||||
Parameters: parameters,
|
||||
paramBinders: binders,
|
||||
Spec: spec,
|
||||
Formats: formats,
|
||||
debugLogf: debugLogfFunc(nil),
|
||||
}
|
||||
}
|
||||
|
||||
// Bind perform the databinding and validation
|
||||
func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, data interface{}) error {
|
||||
val := reflect.Indirect(reflect.ValueOf(data))
|
||||
isMap := val.Kind() == reflect.Map
|
||||
var result []error
|
||||
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]
|
||||
o.debugLogf("binding parameter %s for %s %s", fieldName, request.Method, request.URL.EscapedPath())
|
||||
var target reflect.Value
|
||||
if !isMap {
|
||||
binder.Name = fieldName
|
||||
target = val.FieldByName(fieldName)
|
||||
}
|
||||
|
||||
if isMap {
|
||||
tpe := binder.Type()
|
||||
if tpe == nil {
|
||||
if param.Schema.Type.Contains(typeArray) {
|
||||
tpe = reflect.TypeOf([]interface{}{})
|
||||
} else {
|
||||
tpe = reflect.TypeOf(map[string]interface{}{})
|
||||
}
|
||||
}
|
||||
target = reflect.Indirect(reflect.New(tpe))
|
||||
}
|
||||
|
||||
if !target.IsValid() {
|
||||
result = append(result, errors.New(500, "parameter name %q is an unknown field", binder.Name))
|
||||
continue
|
||||
}
|
||||
|
||||
if err := binder.Bind(request, routeParams, consumer, target); err != nil {
|
||||
result = append(result, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if binder.validator != nil {
|
||||
rr := binder.validator.Validate(target.Interface())
|
||||
if rr != nil && rr.HasErrors() {
|
||||
result = append(result, rr.AsError())
|
||||
}
|
||||
}
|
||||
|
||||
if isMap {
|
||||
val.SetMapIndex(reflect.ValueOf(param.Name), target)
|
||||
}
|
||||
}
|
||||
|
||||
if len(result) > 0 {
|
||||
return errors.CompositeValidationError(result...)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
531
vendor/github.com/go-openapi/runtime/middleware/router.go
generated
vendored
Normal file
531
vendor/github.com/go-openapi/runtime/middleware/router.go
generated
vendored
Normal file
@ -0,0 +1,531 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
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"
|
||||
|
||||
"github.com/go-openapi/analysis"
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware/denco"
|
||||
)
|
||||
|
||||
// RouteParam is a object to capture route params in a framework agnostic way.
|
||||
// implementations of the muxer should use these route params to communicate with the
|
||||
// swagger framework
|
||||
type RouteParam struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
// RouteParams the collection of route params
|
||||
type RouteParams []RouteParam
|
||||
|
||||
// Get gets the value for the route param for the specified key
|
||||
func (r RouteParams) Get(name string) string {
|
||||
vv, _, _ := r.GetOK(name)
|
||||
if len(vv) > 0 {
|
||||
return vv[len(vv)-1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetOK gets the value but also returns booleans to indicate if a key or value
|
||||
// is present. This aids in validation and satisfies an interface in use there
|
||||
//
|
||||
// The returned values are: data, has key, has value
|
||||
func (r RouteParams) GetOK(name string) ([]string, bool, bool) {
|
||||
for _, p := range r {
|
||||
if p.Name == name {
|
||||
return []string{p.Value}, true, p.Value != ""
|
||||
}
|
||||
}
|
||||
return nil, false, false
|
||||
}
|
||||
|
||||
// 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, WithDefaultRouterLoggerFunc(ctx.debugLogf))
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if _, rCtx, ok := ctx.RouteInfo(r); ok {
|
||||
next.ServeHTTP(rw, rCtx)
|
||||
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.analyzer.RequiredProduces(), nil, errors.MethodNotAllowed(r.Method, others))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Respond(rw, r, ctx.analyzer.RequiredProduces(), nil, errors.NotFound("path %s was not found", r.URL.EscapedPath()))
|
||||
})
|
||||
}
|
||||
|
||||
// RoutableAPI represents an interface for things that can serve
|
||||
// as a provider of implementations for the swagger router
|
||||
type RoutableAPI interface {
|
||||
HandlerFor(string, string) (http.Handler, bool)
|
||||
ServeErrorFor(string) func(http.ResponseWriter, *http.Request, error)
|
||||
ConsumersFor([]string) map[string]runtime.Consumer
|
||||
ProducersFor([]string) map[string]runtime.Producer
|
||||
AuthenticatorsFor(map[string]spec.SecurityScheme) map[string]runtime.Authenticator
|
||||
Authorizer() runtime.Authorizer
|
||||
Formats() strfmt.Registry
|
||||
DefaultProduces() string
|
||||
DefaultConsumes() string
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
debugLogf func(string, ...any) // a logging function to debug context and all components using it
|
||||
}
|
||||
|
||||
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),
|
||||
debugLogf: o.debugLogf,
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
builder.debugLogf("adding route %s %s %q", method, fp, operation.ID)
|
||||
builder.AddRoute(method, fp, operation)
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.Build()
|
||||
}
|
||||
|
||||
// RouteAuthenticator is an authenticator that can compose several authenticators together.
|
||||
// It also knows when it contains an authenticator that allows for anonymous pass through.
|
||||
// Contains a group of 1 or more authenticators that have a logical AND relationship
|
||||
type RouteAuthenticator struct {
|
||||
Authenticator map[string]runtime.Authenticator
|
||||
Schemes []string
|
||||
Scopes map[string][]string
|
||||
allScopes []string
|
||||
commonScopes []string
|
||||
allowAnonymous bool
|
||||
}
|
||||
|
||||
func (ra *RouteAuthenticator) AllowsAnonymous() bool {
|
||||
return ra.allowAnonymous
|
||||
}
|
||||
|
||||
// AllScopes returns a list of unique scopes that is the combination
|
||||
// of all the scopes in the requirements
|
||||
func (ra *RouteAuthenticator) AllScopes() []string {
|
||||
return ra.allScopes
|
||||
}
|
||||
|
||||
// CommonScopes returns a list of unique scopes that are common in all the
|
||||
// scopes in the requirements
|
||||
func (ra *RouteAuthenticator) CommonScopes() []string {
|
||||
return ra.commonScopes
|
||||
}
|
||||
|
||||
// Authenticate Authenticator interface implementation
|
||||
func (ra *RouteAuthenticator) Authenticate(req *http.Request, route *MatchedRoute) (bool, interface{}, error) {
|
||||
if ra.allowAnonymous {
|
||||
route.Authenticator = ra
|
||||
return true, nil, nil
|
||||
}
|
||||
// iterate in proper order
|
||||
var lastResult interface{}
|
||||
for _, scheme := range ra.Schemes {
|
||||
if authenticator, ok := ra.Authenticator[scheme]; ok {
|
||||
applies, princ, err := authenticator.Authenticate(&security.ScopedAuthRequest{
|
||||
Request: req,
|
||||
RequiredScopes: ra.Scopes[scheme],
|
||||
})
|
||||
if !applies {
|
||||
return false, nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
route.Authenticator = ra
|
||||
return true, nil, err
|
||||
}
|
||||
lastResult = princ
|
||||
}
|
||||
}
|
||||
route.Authenticator = ra
|
||||
return true, lastResult, nil
|
||||
}
|
||||
|
||||
func stringSliceUnion(slices ...[]string) []string {
|
||||
unique := make(map[string]struct{})
|
||||
var result []string
|
||||
for _, slice := range slices {
|
||||
for _, entry := range slice {
|
||||
if _, ok := unique[entry]; ok {
|
||||
continue
|
||||
}
|
||||
unique[entry] = struct{}{}
|
||||
result = append(result, entry)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func stringSliceIntersection(slices ...[]string) []string {
|
||||
unique := make(map[string]int)
|
||||
var intersection []string
|
||||
|
||||
total := len(slices)
|
||||
var emptyCnt int
|
||||
for _, slice := range slices {
|
||||
if len(slice) == 0 {
|
||||
emptyCnt++
|
||||
continue
|
||||
}
|
||||
|
||||
for _, entry := range slice {
|
||||
unique[entry]++
|
||||
if unique[entry] == total-emptyCnt { // this entry appeared in all the non-empty slices
|
||||
intersection = append(intersection, entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return intersection
|
||||
}
|
||||
|
||||
// RouteAuthenticators represents a group of authenticators that represent a logical OR
|
||||
type RouteAuthenticators []RouteAuthenticator
|
||||
|
||||
// AllowsAnonymous returns true when there is an authenticator that means optional auth
|
||||
func (ras RouteAuthenticators) AllowsAnonymous() bool {
|
||||
for _, ra := range ras {
|
||||
if ra.AllowsAnonymous() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Authenticate method implemention so this collection can be used as authenticator
|
||||
func (ras RouteAuthenticators) Authenticate(req *http.Request, route *MatchedRoute) (bool, interface{}, error) {
|
||||
var lastError error
|
||||
var allowsAnon bool
|
||||
var anonAuth RouteAuthenticator
|
||||
|
||||
for _, ra := range ras {
|
||||
if ra.AllowsAnonymous() {
|
||||
anonAuth = ra
|
||||
allowsAnon = true
|
||||
continue
|
||||
}
|
||||
applies, usr, err := ra.Authenticate(req, route)
|
||||
if !applies || err != nil || usr == nil {
|
||||
if err != nil {
|
||||
lastError = err
|
||||
}
|
||||
continue
|
||||
}
|
||||
return applies, usr, nil
|
||||
}
|
||||
|
||||
if allowsAnon && lastError == nil {
|
||||
route.Authenticator = &anonAuth
|
||||
return true, nil, lastError
|
||||
}
|
||||
return lastError != nil, nil, lastError
|
||||
}
|
||||
|
||||
type routeEntry struct {
|
||||
PathPattern string
|
||||
BasePath string
|
||||
Operation *spec.Operation
|
||||
Consumes []string
|
||||
Consumers map[string]runtime.Consumer
|
||||
Produces []string
|
||||
Producers map[string]runtime.Producer
|
||||
Parameters map[string]spec.Parameter
|
||||
Handler http.Handler
|
||||
Formats strfmt.Registry
|
||||
Binder *UntypedRequestBinder
|
||||
Authenticators RouteAuthenticators
|
||||
Authorizer runtime.Authorizer
|
||||
}
|
||||
|
||||
// MatchedRoute represents the route that was matched in this request
|
||||
type MatchedRoute struct {
|
||||
routeEntry
|
||||
Params RouteParams
|
||||
Consumer runtime.Consumer
|
||||
Producer runtime.Producer
|
||||
Authenticator *RouteAuthenticator
|
||||
}
|
||||
|
||||
// HasAuth returns true when the route has a security requirement defined
|
||||
func (m *MatchedRoute) HasAuth() bool {
|
||||
return len(m.Authenticators) > 0
|
||||
}
|
||||
|
||||
// NeedsAuth returns true when the request still
|
||||
// needs to perform authentication
|
||||
func (m *MatchedRoute) NeedsAuth() bool {
|
||||
return m.HasAuth() && m.Authenticator == nil
|
||||
}
|
||||
|
||||
func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) {
|
||||
mth := strings.ToUpper(method)
|
||||
d.debugLogf("looking up route for %s %s", method, path)
|
||||
if Debug {
|
||||
if len(d.routers) == 0 {
|
||||
d.debugLogf("there are no known routers")
|
||||
}
|
||||
for meth := range d.routers {
|
||||
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 {
|
||||
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 := url.PathUnescape(p.Value)
|
||||
if err != nil {
|
||||
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
|
||||
// check if this parameter is a fragment within a path segment
|
||||
if xpos := strings.Index(entry.PathPattern, fmt.Sprintf("{%s}", p.Name)) + len(p.Name) + 2; xpos < len(entry.PathPattern) && entry.PathPattern[xpos] != '/' {
|
||||
// extract fragment parameters
|
||||
ep := strings.Split(entry.PathPattern[xpos:], "/")[0]
|
||||
pnames, pvalues := decodeCompositParams(p.Name, v, ep, nil, nil)
|
||||
for i, pname := range pnames {
|
||||
params = append(params, RouteParam{Name: pname, Value: pvalues[i]})
|
||||
}
|
||||
} else {
|
||||
// use the parameter directly
|
||||
params = append(params, RouteParam{Name: p.Name, Value: v})
|
||||
}
|
||||
}
|
||||
return &MatchedRoute{routeEntry: *entry, Params: params}, true
|
||||
}
|
||||
} else {
|
||||
d.debugLogf("couldn't find a route by path for %s %s", method, path)
|
||||
}
|
||||
} else {
|
||||
d.debugLogf("couldn't find a route by method for %s %s", method, path)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (d *defaultRouter) OtherMethods(method, path string) []string {
|
||||
mn := strings.ToUpper(method)
|
||||
var methods []string
|
||||
for k, v := range d.routers {
|
||||
if k != mn {
|
||||
if _, _, ok := v.Lookup(fpath.Clean(path)); ok {
|
||||
methods = append(methods, k)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
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(`{(.+?)}([^/]*)`)
|
||||
|
||||
func decodeCompositParams(name string, value string, pattern string, names []string, values []string) ([]string, []string) {
|
||||
pleft := strings.Index(pattern, "{")
|
||||
names = append(names, name)
|
||||
if pleft < 0 {
|
||||
if strings.HasSuffix(value, pattern) {
|
||||
values = append(values, value[:len(value)-len(pattern)])
|
||||
} else {
|
||||
values = append(values, "")
|
||||
}
|
||||
} else {
|
||||
toskip := pattern[:pleft]
|
||||
pright := strings.Index(pattern, "}")
|
||||
vright := strings.Index(value, toskip)
|
||||
if vright >= 0 {
|
||||
values = append(values, value[:vright])
|
||||
} else {
|
||||
values = append(values, "")
|
||||
value = ""
|
||||
}
|
||||
return decodeCompositParams(pattern[pleft+1:pright], value[vright+len(toskip):], pattern[pright+1:], names, values)
|
||||
}
|
||||
return names, values
|
||||
}
|
||||
|
||||
func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Operation) {
|
||||
mn := strings.ToUpper(method)
|
||||
|
||||
bp := fpath.Clean(d.spec.BasePath())
|
||||
if len(bp) > 0 && bp[len(bp)-1] == '/' {
|
||||
bp = bp[:len(bp)-1]
|
||||
}
|
||||
|
||||
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)
|
||||
parameters := d.analyzer.ParamsFor(method, strings.TrimPrefix(path, bp))
|
||||
|
||||
// add API defaults if not part of the spec
|
||||
if defConsumes := d.api.DefaultConsumes(); defConsumes != "" && !swag.ContainsStringsCI(consumes, defConsumes) {
|
||||
consumes = append(consumes, defConsumes)
|
||||
}
|
||||
|
||||
if defProduces := d.api.DefaultProduces(); defProduces != "" && !swag.ContainsStringsCI(produces, defProduces) {
|
||||
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,
|
||||
Operation: operation,
|
||||
Handler: handler,
|
||||
Consumes: consumes,
|
||||
Produces: produces,
|
||||
Consumers: d.api.ConsumersFor(normalizeOffers(consumes)),
|
||||
Producers: d.api.ProducersFor(normalizeOffers(produces)),
|
||||
Parameters: parameters,
|
||||
Formats: d.api.Formats(),
|
||||
Binder: requestBinder,
|
||||
Authenticators: d.buildAuthenticators(operation),
|
||||
Authorizer: d.api.Authorizer(),
|
||||
})
|
||||
d.records[mn] = append(d.records[mn], record)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *defaultRouteBuilder) buildAuthenticators(operation *spec.Operation) RouteAuthenticators {
|
||||
requirements := d.analyzer.SecurityRequirementsFor(operation)
|
||||
auths := make([]RouteAuthenticator, 0, len(requirements))
|
||||
for _, reqs := range requirements {
|
||||
schemes := make([]string, 0, len(reqs))
|
||||
scopes := make(map[string][]string, len(reqs))
|
||||
scopeSlices := make([][]string, 0, len(reqs))
|
||||
for _, req := range reqs {
|
||||
schemes = append(schemes, req.Name)
|
||||
scopes[req.Name] = req.Scopes
|
||||
scopeSlices = append(scopeSlices, req.Scopes)
|
||||
}
|
||||
|
||||
definitions := d.analyzer.SecurityDefinitionsForRequirements(reqs)
|
||||
authenticators := d.api.AuthenticatorsFor(definitions)
|
||||
auths = append(auths, RouteAuthenticator{
|
||||
Authenticator: authenticators,
|
||||
Schemes: schemes,
|
||||
Scopes: scopes,
|
||||
allScopes: stringSliceUnion(scopeSlices...),
|
||||
commonScopes: stringSliceIntersection(scopeSlices...),
|
||||
allowAnonymous: len(reqs) == 1 && reqs[0].Name == "",
|
||||
})
|
||||
}
|
||||
return auths
|
||||
}
|
||||
|
||||
func (d *defaultRouteBuilder) Build() *defaultRouter {
|
||||
routers := make(map[string]*denco.Router)
|
||||
for method, records := range d.records {
|
||||
router := denco.New()
|
||||
_ = router.Build(records)
|
||||
routers[method] = router
|
||||
}
|
||||
return &defaultRouter{
|
||||
spec: d.spec,
|
||||
routers: routers,
|
||||
debugLogf: d.debugLogf,
|
||||
}
|
||||
}
|
39
vendor/github.com/go-openapi/runtime/middleware/security.go
generated
vendored
Normal file
39
vendor/github.com/go-openapi/runtime/middleware/security.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package middleware
|
||||
|
||||
import "net/http"
|
||||
|
||||
func newSecureAPI(ctx *Context, next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
route, rCtx, _ := ctx.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
r = rCtx
|
||||
}
|
||||
if route != nil && !route.NeedsAuth() {
|
||||
next.ServeHTTP(rw, r)
|
||||
return
|
||||
}
|
||||
|
||||
_, rCtx, err := ctx.Authorize(r, route)
|
||||
if err != nil {
|
||||
ctx.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
r = rCtx
|
||||
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
}
|
102
vendor/github.com/go-openapi/runtime/middleware/spec.go
generated
vendored
Normal file
102
vendor/github.com/go-openapi/runtime/middleware/spec.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
)
|
||||
|
||||
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.
|
||||
//
|
||||
// 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 = "/"
|
||||
}
|
||||
o := specOptionsWithDefaults(opts)
|
||||
pth := path.Join(basePath, o.Path, o.Document)
|
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if path.Clean(r.URL.Path) == pth {
|
||||
rw.Header().Set(contentTypeHeader, applicationJSON)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
_, _ = rw.Write(b)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if next != nil {
|
||||
next.ServeHTTP(rw, r)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
175
vendor/github.com/go-openapi/runtime/middleware/swaggerui.go
generated
vendored
Normal file
175
vendor/github.com/go-openapi/runtime/middleware/swaggerui.go
generated
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path"
|
||||
)
|
||||
|
||||
// SwaggerUIOpts configures the SwaggerUI middleware
|
||||
type SwaggerUIOpts struct {
|
||||
// BasePath for the API, 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
|
||||
|
||||
// OAuthCallbackURL the url called after OAuth2 login
|
||||
OAuthCallbackURL string
|
||||
|
||||
// The three components needed to embed swagger-ui
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// EnsureDefaults in case some options are missing
|
||||
func (r *SwaggerUIOpts) EnsureDefaults() {
|
||||
r.ensureDefaults()
|
||||
|
||||
if r.Template == "" {
|
||||
r.Template = swaggeruiTemplate
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
if r.SwaggerURL == "" {
|
||||
r.SwaggerURL = swaggerLatest
|
||||
}
|
||||
if r.SwaggerPresetURL == "" {
|
||||
r.SwaggerPresetURL = swaggerPresetLatest
|
||||
}
|
||||
if r.SwaggerStylesURL == "" {
|
||||
r.SwaggerStylesURL = swaggerStylesLatest
|
||||
}
|
||||
if r.Favicon16 == "" {
|
||||
r.Favicon16 = swaggerFavicon16Latest
|
||||
}
|
||||
if r.Favicon32 == "" {
|
||||
r.Favicon32 = swaggerFavicon32Latest
|
||||
}
|
||||
}
|
||||
|
||||
// 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(opts.Template))
|
||||
assets := bytes.NewBuffer(nil)
|
||||
if err := tmpl.Execute(assets, opts); err != nil {
|
||||
panic(fmt.Errorf("cannot execute template: %w", err))
|
||||
}
|
||||
|
||||
return serveUI(pth, assets.Bytes(), next)
|
||||
}
|
||||
|
||||
const (
|
||||
swaggerLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"
|
||||
swaggerPresetLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"
|
||||
swaggerStylesLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui.css"
|
||||
swaggerFavicon32Latest = "https://unpkg.com/swagger-ui-dist/favicon-32x32.png"
|
||||
swaggerFavicon16Latest = "https://unpkg.com/swagger-ui-dist/favicon-16x16.png"
|
||||
swaggeruiTemplate = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{ .Title }}</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{{ .SwaggerStylesURL }}" >
|
||||
<link rel="icon" type="image/png" href="{{ .Favicon32 }}" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="{{ .Favicon16 }}" sizes="16x16" />
|
||||
<style>
|
||||
html
|
||||
{
|
||||
box-sizing: border-box;
|
||||
overflow: -moz-scrollbars-vertical;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after
|
||||
{
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
margin:0;
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
|
||||
<script src="{{ .SwaggerURL }}"> </script>
|
||||
<script src="{{ .SwaggerPresetURL }}"> </script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Begin Swagger UI call region
|
||||
const ui = SwaggerUIBundle({
|
||||
url: '{{ .SpecURL }}',
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
oauth2RedirectUrl: '{{ .OAuthCallbackURL }}'
|
||||
})
|
||||
// End Swagger UI call region
|
||||
|
||||
window.ui = ui
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
)
|
105
vendor/github.com/go-openapi/runtime/middleware/swaggerui_oauth2.go
generated
vendored
Normal file
105
vendor/github.com/go-openapi/runtime/middleware/swaggerui_oauth2.go
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func SwaggerUIOAuth2Callback(opts SwaggerUIOpts, next http.Handler) http.Handler {
|
||||
opts.EnsureDefaultsOauth2()
|
||||
|
||||
pth := opts.OAuthCallbackURL
|
||||
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))
|
||||
}
|
||||
|
||||
return serveUI(pth, assets.Bytes(), next)
|
||||
}
|
||||
|
||||
const (
|
||||
swaggerOAuthTemplate = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ .Title }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
'use strict';
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var redirectUrl = oauth2.redirectUrl;
|
||||
var isValid, qp, arr;
|
||||
|
||||
if (/code|token|error/.test(window.location.hash)) {
|
||||
qp = window.location.hash.substring(1).replace('?', '&');
|
||||
} else {
|
||||
qp = location.search.substring(1);
|
||||
}
|
||||
|
||||
arr = qp.split("&");
|
||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
|
||||
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||
function (key, value) {
|
||||
return key === "" ? value : decodeURIComponent(value);
|
||||
}
|
||||
) : {};
|
||||
|
||||
isValid = qp.state === sentState;
|
||||
|
||||
if ((
|
||||
oauth2.auth.schema.get("flow") === "accessCode" ||
|
||||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
|
||||
oauth2.auth.schema.get("flow") === "authorization_code"
|
||||
) && !oauth2.auth.code) {
|
||||
if (!isValid) {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "warning",
|
||||
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
|
||||
});
|
||||
}
|
||||
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||
} else {
|
||||
let oauthErrorMsg;
|
||||
if (qp.error) {
|
||||
oauthErrorMsg = "["+qp.error+"]: " +
|
||||
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||
}
|
||||
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "error",
|
||||
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
|
||||
});
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
|
||||
if (document.readyState !== 'loading') {
|
||||
run();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
run();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
)
|
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)))
|
||||
})
|
||||
}
|
287
vendor/github.com/go-openapi/runtime/middleware/untyped/api.go
generated
vendored
Normal file
287
vendor/github.com/go-openapi/runtime/middleware/untyped/api.go
generated
vendored
Normal file
@ -0,0 +1,287 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package untyped
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/analysis"
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
// NewAPI creates the default untyped API
|
||||
func NewAPI(spec *loads.Document) *API {
|
||||
var an *analysis.Spec
|
||||
if spec != nil && spec.Spec() != nil {
|
||||
an = analysis.New(spec.Spec())
|
||||
}
|
||||
api := &API{
|
||||
spec: spec,
|
||||
analyzer: an,
|
||||
consumers: make(map[string]runtime.Consumer, 10),
|
||||
producers: make(map[string]runtime.Producer, 10),
|
||||
authenticators: make(map[string]runtime.Authenticator),
|
||||
operations: make(map[string]map[string]runtime.OperationHandler),
|
||||
ServeError: errors.ServeError,
|
||||
Models: make(map[string]func() interface{}),
|
||||
formats: strfmt.NewFormats(),
|
||||
}
|
||||
return api.WithJSONDefaults()
|
||||
}
|
||||
|
||||
// API represents an untyped mux for a swagger spec
|
||||
type API struct {
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
DefaultProduces string
|
||||
DefaultConsumes string
|
||||
consumers map[string]runtime.Consumer
|
||||
producers map[string]runtime.Producer
|
||||
authenticators map[string]runtime.Authenticator
|
||||
authorizer runtime.Authorizer
|
||||
operations map[string]map[string]runtime.OperationHandler
|
||||
ServeError func(http.ResponseWriter, *http.Request, error)
|
||||
Models map[string]func() interface{}
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// WithJSONDefaults loads the json defaults for this api
|
||||
func (d *API) WithJSONDefaults() *API {
|
||||
d.DefaultConsumes = runtime.JSONMime
|
||||
d.DefaultProduces = runtime.JSONMime
|
||||
d.consumers[runtime.JSONMime] = runtime.JSONConsumer()
|
||||
d.producers[runtime.JSONMime] = runtime.JSONProducer()
|
||||
return d
|
||||
}
|
||||
|
||||
// WithoutJSONDefaults clears the json defaults for this api
|
||||
func (d *API) WithoutJSONDefaults() *API {
|
||||
d.DefaultConsumes = ""
|
||||
d.DefaultProduces = ""
|
||||
delete(d.consumers, runtime.JSONMime)
|
||||
delete(d.producers, runtime.JSONMime)
|
||||
return d
|
||||
}
|
||||
|
||||
// Formats returns the registered string formats
|
||||
func (d *API) Formats() strfmt.Registry {
|
||||
if d.formats == nil {
|
||||
d.formats = strfmt.NewFormats()
|
||||
}
|
||||
return d.formats
|
||||
}
|
||||
|
||||
// RegisterFormat registers a custom format validator
|
||||
func (d *API) RegisterFormat(name string, format strfmt.Format, validator strfmt.Validator) {
|
||||
if d.formats == nil {
|
||||
d.formats = strfmt.NewFormats()
|
||||
}
|
||||
d.formats.Add(name, format, validator)
|
||||
}
|
||||
|
||||
// RegisterAuth registers an auth handler in this api
|
||||
func (d *API) RegisterAuth(scheme string, handler runtime.Authenticator) {
|
||||
if d.authenticators == nil {
|
||||
d.authenticators = make(map[string]runtime.Authenticator)
|
||||
}
|
||||
d.authenticators[scheme] = handler
|
||||
}
|
||||
|
||||
// RegisterAuthorizer registers an authorizer handler in this api
|
||||
func (d *API) RegisterAuthorizer(handler runtime.Authorizer) {
|
||||
d.authorizer = handler
|
||||
}
|
||||
|
||||
// RegisterConsumer registers a consumer for a media type.
|
||||
func (d *API) RegisterConsumer(mediaType string, handler runtime.Consumer) {
|
||||
if d.consumers == nil {
|
||||
d.consumers = make(map[string]runtime.Consumer, 10)
|
||||
}
|
||||
d.consumers[strings.ToLower(mediaType)] = handler
|
||||
}
|
||||
|
||||
// RegisterProducer registers a producer for a media type
|
||||
func (d *API) RegisterProducer(mediaType string, handler runtime.Producer) {
|
||||
if d.producers == nil {
|
||||
d.producers = make(map[string]runtime.Producer, 10)
|
||||
}
|
||||
d.producers[strings.ToLower(mediaType)] = handler
|
||||
}
|
||||
|
||||
// RegisterOperation registers an operation handler for an operation name
|
||||
func (d *API) RegisterOperation(method, path string, handler runtime.OperationHandler) {
|
||||
if d.operations == nil {
|
||||
d.operations = make(map[string]map[string]runtime.OperationHandler, 30)
|
||||
}
|
||||
um := strings.ToUpper(method)
|
||||
if b, ok := d.operations[um]; !ok || b == nil {
|
||||
d.operations[um] = make(map[string]runtime.OperationHandler)
|
||||
}
|
||||
d.operations[um][path] = handler
|
||||
}
|
||||
|
||||
// OperationHandlerFor returns the operation handler for the specified id if it can be found
|
||||
func (d *API) OperationHandlerFor(method, path string) (runtime.OperationHandler, bool) {
|
||||
if d.operations == nil {
|
||||
return nil, false
|
||||
}
|
||||
if pi, ok := d.operations[strings.ToUpper(method)]; ok {
|
||||
h, ok := pi[path]
|
||||
return h, ok
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// ConsumersFor gets the consumers for the specified media types
|
||||
func (d *API) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
|
||||
result := make(map[string]runtime.Consumer)
|
||||
for _, mt := range mediaTypes {
|
||||
if consumer, ok := d.consumers[mt]; ok {
|
||||
result[mt] = consumer
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ProducersFor gets the producers for the specified media types
|
||||
func (d *API) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
|
||||
result := make(map[string]runtime.Producer)
|
||||
for _, mt := range mediaTypes {
|
||||
if producer, ok := d.producers[mt]; ok {
|
||||
result[mt] = producer
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// AuthenticatorsFor gets the authenticators for the specified security schemes
|
||||
func (d *API) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
|
||||
result := make(map[string]runtime.Authenticator)
|
||||
for k := range schemes {
|
||||
if a, ok := d.authenticators[k]; ok {
|
||||
result[k] = a
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Authorizer returns the registered authorizer
|
||||
func (d *API) Authorizer() runtime.Authorizer {
|
||||
return d.authorizer
|
||||
}
|
||||
|
||||
// Validate validates this API for any missing items
|
||||
func (d *API) Validate() error {
|
||||
return d.validate()
|
||||
}
|
||||
|
||||
// validateWith validates the registrations in this API against the provided spec analyzer
|
||||
func (d *API) validate() error {
|
||||
consumes := make([]string, 0, len(d.consumers))
|
||||
for k := range d.consumers {
|
||||
consumes = append(consumes, k)
|
||||
}
|
||||
|
||||
produces := make([]string, 0, len(d.producers))
|
||||
for k := range d.producers {
|
||||
produces = append(produces, k)
|
||||
}
|
||||
|
||||
authenticators := make([]string, 0, len(d.authenticators))
|
||||
for k := range d.authenticators {
|
||||
authenticators = append(authenticators, k)
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
secDefinitions := d.spec.Spec().SecurityDefinitions
|
||||
definedAuths := make([]string, 0, len(secDefinitions))
|
||||
for k := range secDefinitions {
|
||||
definedAuths = append(definedAuths, k)
|
||||
}
|
||||
|
||||
if err := d.verify("consumes", consumes, d.analyzer.RequiredConsumes()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.verify("produces", produces, d.analyzer.RequiredProduces()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.verify("operation", operations, d.analyzer.OperationMethodPaths()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
requiredAuths := d.analyzer.RequiredSecuritySchemes()
|
||||
if err := d.verify("auth scheme", authenticators, requiredAuths); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.verify("security definitions", definedAuths, requiredAuths); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *API) verify(name string, registrations []string, expectations []string) error {
|
||||
sort.Strings(registrations)
|
||||
sort.Strings(expectations)
|
||||
|
||||
expected := map[string]struct{}{}
|
||||
seen := map[string]struct{}{}
|
||||
|
||||
for _, v := range expectations {
|
||||
expected[v] = struct{}{}
|
||||
}
|
||||
|
||||
var unspecified []string
|
||||
for _, v := range registrations {
|
||||
seen[v] = struct{}{}
|
||||
if _, ok := expected[v]; !ok {
|
||||
unspecified = append(unspecified, v)
|
||||
}
|
||||
}
|
||||
|
||||
for k := range seen {
|
||||
delete(expected, k)
|
||||
}
|
||||
|
||||
unregistered := make([]string, 0, len(expected))
|
||||
for k := range expected {
|
||||
unregistered = append(unregistered, k)
|
||||
}
|
||||
sort.Strings(unspecified)
|
||||
sort.Strings(unregistered)
|
||||
|
||||
if len(unregistered) > 0 || len(unspecified) > 0 {
|
||||
return &errors.APIVerificationFailed{
|
||||
Section: name,
|
||||
MissingSpecification: unspecified,
|
||||
MissingRegistration: unregistered,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
130
vendor/github.com/go-openapi/runtime/middleware/validation.go
generated
vendored
Normal file
130
vendor/github.com/go-openapi/runtime/middleware/validation.go
generated
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/swag"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
type validation struct {
|
||||
context *Context
|
||||
result []error
|
||||
request *http.Request
|
||||
route *MatchedRoute
|
||||
bound map[string]interface{}
|
||||
}
|
||||
|
||||
// ContentType validates the content type of a request
|
||||
func validateContentType(allowed []string, actual string) error {
|
||||
if len(allowed) == 0 {
|
||||
return nil
|
||||
}
|
||||
mt, _, err := mime.ParseMediaType(actual)
|
||||
if err != nil {
|
||||
return errors.InvalidContentType(actual, allowed)
|
||||
}
|
||||
if swag.ContainsStringsCI(allowed, mt) {
|
||||
return nil
|
||||
}
|
||||
if swag.ContainsStringsCI(allowed, "*/*") {
|
||||
return nil
|
||||
}
|
||||
parts := strings.Split(actual, "/")
|
||||
if len(parts) == 2 && swag.ContainsStringsCI(allowed, parts[0]+"/*") {
|
||||
return nil
|
||||
}
|
||||
return errors.InvalidContentType(actual, allowed)
|
||||
}
|
||||
|
||||
func validateRequest(ctx *Context, request *http.Request, route *MatchedRoute) *validation {
|
||||
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 {
|
||||
validate.responseFormat()
|
||||
}
|
||||
if len(validate.result) == 0 {
|
||||
validate.parameters()
|
||||
}
|
||||
|
||||
return validate
|
||||
}
|
||||
|
||||
func (v *validation) debugLogf(format string, args ...any) {
|
||||
v.context.debugLogf(format, args...)
|
||||
}
|
||||
|
||||
func (v *validation) parameters() {
|
||||
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{}) {
|
||||
v.result = append(v.result, e.(error))
|
||||
}
|
||||
return
|
||||
}
|
||||
v.result = append(v.result, result)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *validation) contentType() {
|
||||
if len(v.result) == 0 && runtime.HasBody(v.request) {
|
||||
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)
|
||||
} else {
|
||||
v.request = req
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
if ct != "" && v.route.Consumer == nil {
|
||||
cons, ok := v.route.Consumers[ct]
|
||||
if !ok {
|
||||
v.result = append(v.result, errors.New(500, "no consumer registered for %s", ct))
|
||||
} else {
|
||||
v.route.Consumer = cons
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *validation) responseFormat() {
|
||||
// if the route provides values for Produces and no format could be identify then return an error.
|
||||
// if the route does not specify values for Produces then treat request as valid since the API designer
|
||||
// choose not to specify the format for responses.
|
||||
if str, rCtx := v.context.ResponseFormat(v.request, v.route.Produces); str == "" && len(v.route.Produces) > 0 {
|
||||
v.request = rCtx
|
||||
v.result = append(v.result, errors.InvalidResponseFormat(v.request.Header.Get(runtime.HeaderAccept), v.route.Produces))
|
||||
}
|
||||
}
|
149
vendor/github.com/go-openapi/runtime/request.go
generated
vendored
Normal file
149
vendor/github.com/go-openapi/runtime/request.go
generated
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// CanHaveBody returns true if this method can have a body
|
||||
func CanHaveBody(method string) bool {
|
||||
mn := strings.ToUpper(method)
|
||||
return mn == "POST" || mn == "PUT" || mn == "PATCH" || mn == "DELETE"
|
||||
}
|
||||
|
||||
// IsSafe returns true if this is a request with a safe method
|
||||
func IsSafe(r *http.Request) bool {
|
||||
mn := strings.ToUpper(r.Method)
|
||||
return mn == "GET" || mn == "HEAD"
|
||||
}
|
||||
|
||||
// AllowsBody returns true if the request allows for a body
|
||||
func AllowsBody(r *http.Request) bool {
|
||||
mn := strings.ToUpper(r.Method)
|
||||
return mn != "HEAD"
|
||||
}
|
||||
|
||||
// HasBody returns true if this method needs a content-type
|
||||
func HasBody(r *http.Request) bool {
|
||||
// happy case: we have a content length set
|
||||
if r.ContentLength > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if r.Header.Get("content-length") != "" {
|
||||
// in this case, no Transfer-Encoding should be present
|
||||
// we have a header set but it was explicitly set to 0, so we assume no body
|
||||
return false
|
||||
}
|
||||
|
||||
rdr := newPeekingReader(r.Body)
|
||||
r.Body = rdr
|
||||
return rdr.HasContent()
|
||||
}
|
||||
|
||||
func newPeekingReader(r io.ReadCloser) *peekingReader {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return &peekingReader{
|
||||
underlying: bufio.NewReader(r),
|
||||
orig: r,
|
||||
}
|
||||
}
|
||||
|
||||
type peekingReader struct {
|
||||
underlying interface {
|
||||
Buffered() int
|
||||
Peek(int) ([]byte, error)
|
||||
Read([]byte) (int, error)
|
||||
}
|
||||
orig io.ReadCloser
|
||||
}
|
||||
|
||||
func (p *peekingReader) HasContent() bool {
|
||||
if p == nil {
|
||||
return false
|
||||
}
|
||||
if p.underlying.Buffered() > 0 {
|
||||
return true
|
||||
}
|
||||
b, err := p.underlying.Peek(1)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return len(b) > 0
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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.NewRequestWithContext(context.Background(), method, urlStr, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Add(HeaderContentType, JSONMime)
|
||||
req.Header.Add(HeaderAccept, JSONMime)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// Gettable for things with a method GetOK(string) (data string, hasKey bool, hasValue bool)
|
||||
type Gettable interface {
|
||||
GetOK(string) ([]string, bool, bool)
|
||||
}
|
||||
|
||||
// ReadSingleValue reads a single value from the source
|
||||
func ReadSingleValue(values Gettable, name string) string {
|
||||
vv, _, hv := values.GetOK(name)
|
||||
if hv {
|
||||
return vv[len(vv)-1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ReadCollectionValue reads a collection value from a string data source
|
||||
func ReadCollectionValue(values Gettable, name, collectionFormat string) []string {
|
||||
v := ReadSingleValue(values, name)
|
||||
return swag.SplitByFormat(v, collectionFormat)
|
||||
}
|
277
vendor/github.com/go-openapi/runtime/security/authenticator.go
generated
vendored
Normal file
277
vendor/github.com/go-openapi/runtime/security/authenticator.go
generated
vendored
Normal file
@ -0,0 +1,277 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
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 { //nolint:revive,stylecheck
|
||||
return runtime.AuthenticatorFunc(func(params interface{}) (bool, interface{}, error) {
|
||||
if request, ok := params.(*http.Request); ok {
|
||||
return handler(request)
|
||||
}
|
||||
if scoped, ok := params.(*ScopedAuthRequest); ok {
|
||||
return handler(scoped.Request)
|
||||
}
|
||||
return false, nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
// ScopedAuthenticator is a function that authenticates a HTTP request against a list of valid scopes
|
||||
func ScopedAuthenticator(handler func(*ScopedAuthRequest) (bool, interface{}, error)) runtime.Authenticator {
|
||||
return runtime.AuthenticatorFunc(func(params interface{}) (bool, interface{}, error) {
|
||||
if request, ok := params.(*ScopedAuthRequest); ok {
|
||||
return handler(request)
|
||||
}
|
||||
return false, nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
// UserPassAuthentication authentication function
|
||||
type UserPassAuthentication func(string, string) (interface{}, error)
|
||||
|
||||
// UserPassAuthenticationCtx authentication function with context.Context
|
||||
type UserPassAuthenticationCtx func(context.Context, string, string) (context.Context, interface{}, error)
|
||||
|
||||
// TokenAuthentication authentication function
|
||||
type TokenAuthentication func(string) (interface{}, error)
|
||||
|
||||
// TokenAuthenticationCtx authentication function with context.Context
|
||||
type TokenAuthenticationCtx func(context.Context, string) (context.Context, interface{}, error)
|
||||
|
||||
// ScopedTokenAuthentication authentication function
|
||||
type ScopedTokenAuthentication func(string, []string) (interface{}, error)
|
||||
|
||||
// ScopedTokenAuthenticationCtx authentication function with context.Context
|
||||
type ScopedTokenAuthenticationCtx func(context.Context, string, []string) (context.Context, interface{}, error)
|
||||
|
||||
var DefaultRealmName = "API"
|
||||
|
||||
type secCtxKey uint8
|
||||
|
||||
const (
|
||||
failedBasicAuth secCtxKey = iota
|
||||
oauth2SchemeName
|
||||
)
|
||||
|
||||
func FailedBasicAuth(r *http.Request) string {
|
||||
return FailedBasicAuthCtx(r.Context())
|
||||
}
|
||||
|
||||
func FailedBasicAuthCtx(ctx context.Context) string {
|
||||
v, ok := ctx.Value(failedBasicAuth).(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func OAuth2SchemeName(r *http.Request) string {
|
||||
return OAuth2SchemeNameCtx(r.Context())
|
||||
}
|
||||
|
||||
func OAuth2SchemeNameCtx(ctx context.Context) string {
|
||||
v, ok := ctx.Value(oauth2SchemeName).(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// BasicAuth creates a basic auth authenticator with the provided authentication function
|
||||
func BasicAuth(authenticate UserPassAuthentication) runtime.Authenticator {
|
||||
return BasicAuthRealm(DefaultRealmName, authenticate)
|
||||
}
|
||||
|
||||
// BasicAuthRealm creates a basic auth authenticator with the provided authentication function and realm name
|
||||
func BasicAuthRealm(realm string, authenticate UserPassAuthentication) runtime.Authenticator {
|
||||
if realm == "" {
|
||||
realm = DefaultRealmName
|
||||
}
|
||||
|
||||
return HttpAuthenticator(func(r *http.Request) (bool, interface{}, error) {
|
||||
if usr, pass, ok := r.BasicAuth(); ok {
|
||||
p, err := authenticate(usr, pass)
|
||||
if err != nil {
|
||||
*r = *r.WithContext(context.WithValue(r.Context(), failedBasicAuth, realm))
|
||||
}
|
||||
return true, p, err
|
||||
}
|
||||
*r = *r.WithContext(context.WithValue(r.Context(), failedBasicAuth, realm))
|
||||
return false, nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
// BasicAuthCtx creates a basic auth authenticator with the provided authentication function with support for context.Context
|
||||
func BasicAuthCtx(authenticate UserPassAuthenticationCtx) runtime.Authenticator {
|
||||
return BasicAuthRealmCtx(DefaultRealmName, authenticate)
|
||||
}
|
||||
|
||||
// BasicAuthRealmCtx creates a basic auth authenticator with the provided authentication function and realm name with support for context.Context
|
||||
func BasicAuthRealmCtx(realm string, authenticate UserPassAuthenticationCtx) runtime.Authenticator {
|
||||
if realm == "" {
|
||||
realm = DefaultRealmName
|
||||
}
|
||||
|
||||
return HttpAuthenticator(func(r *http.Request) (bool, interface{}, error) {
|
||||
if usr, pass, ok := r.BasicAuth(); ok {
|
||||
ctx, p, err := authenticate(r.Context(), usr, pass)
|
||||
if err != nil {
|
||||
ctx = context.WithValue(ctx, failedBasicAuth, realm)
|
||||
}
|
||||
*r = *r.WithContext(ctx)
|
||||
return true, p, err
|
||||
}
|
||||
*r = *r.WithContext(context.WithValue(r.Context(), failedBasicAuth, realm))
|
||||
return false, nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
// APIKeyAuth creates an authenticator that uses a token for authorization.
|
||||
// This token can be obtained from either a header or a query string
|
||||
func APIKeyAuth(name, in string, authenticate TokenAuthentication) runtime.Authenticator {
|
||||
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\""))
|
||||
}
|
||||
|
||||
var getToken func(*http.Request) string
|
||||
switch inl {
|
||||
case header:
|
||||
getToken = func(r *http.Request) string { return r.Header.Get(name) }
|
||||
case query:
|
||||
getToken = func(r *http.Request) string { return r.URL.Query().Get(name) }
|
||||
}
|
||||
|
||||
return HttpAuthenticator(func(r *http.Request) (bool, interface{}, error) {
|
||||
token := getToken(r)
|
||||
if token == "" {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
p, err := authenticate(token)
|
||||
return true, p, err
|
||||
})
|
||||
}
|
||||
|
||||
// APIKeyAuthCtx creates an authenticator that uses a token for authorization with support for context.Context.
|
||||
// This token can be obtained from either a header or a query string
|
||||
func APIKeyAuthCtx(name, in string, authenticate TokenAuthenticationCtx) runtime.Authenticator {
|
||||
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\""))
|
||||
}
|
||||
|
||||
var getToken func(*http.Request) string
|
||||
switch inl {
|
||||
case header:
|
||||
getToken = func(r *http.Request) string { return r.Header.Get(name) }
|
||||
case query:
|
||||
getToken = func(r *http.Request) string { return r.URL.Query().Get(name) }
|
||||
}
|
||||
|
||||
return HttpAuthenticator(func(r *http.Request) (bool, interface{}, error) {
|
||||
token := getToken(r)
|
||||
if token == "" {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
ctx, p, err := authenticate(r.Context(), token)
|
||||
*r = *r.WithContext(ctx)
|
||||
return true, p, err
|
||||
})
|
||||
}
|
||||
|
||||
// ScopedAuthRequest contains both a http request and the required scopes for a particular operation
|
||||
type ScopedAuthRequest struct {
|
||||
Request *http.Request
|
||||
RequiredScopes []string
|
||||
}
|
||||
|
||||
// BearerAuth for use with oauth2 flows
|
||||
func BearerAuth(name string, authenticate ScopedTokenAuthentication) runtime.Authenticator {
|
||||
const prefix = "Bearer "
|
||||
return ScopedAuthenticator(func(r *ScopedAuthRequest) (bool, interface{}, error) {
|
||||
var token string
|
||||
hdr := r.Request.Header.Get(runtime.HeaderAuthorization)
|
||||
if strings.HasPrefix(hdr, prefix) {
|
||||
token = strings.TrimPrefix(hdr, prefix)
|
||||
}
|
||||
if token == "" {
|
||||
qs := r.Request.URL.Query()
|
||||
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(accessTokenParam)
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
rctx := context.WithValue(r.Request.Context(), oauth2SchemeName, name)
|
||||
*r.Request = *r.Request.WithContext(rctx)
|
||||
p, err := authenticate(token, r.RequiredScopes)
|
||||
return true, p, err
|
||||
})
|
||||
}
|
||||
|
||||
// BearerAuthCtx for use with oauth2 flows with support for context.Context.
|
||||
func BearerAuthCtx(name string, authenticate ScopedTokenAuthenticationCtx) runtime.Authenticator {
|
||||
const prefix = "Bearer "
|
||||
return ScopedAuthenticator(func(r *ScopedAuthRequest) (bool, interface{}, error) {
|
||||
var token string
|
||||
hdr := r.Request.Header.Get(runtime.HeaderAuthorization)
|
||||
if strings.HasPrefix(hdr, prefix) {
|
||||
token = strings.TrimPrefix(hdr, prefix)
|
||||
}
|
||||
if token == "" {
|
||||
qs := r.Request.URL.Query()
|
||||
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(accessTokenParam)
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
rctx := context.WithValue(r.Request.Context(), oauth2SchemeName, name)
|
||||
ctx, p, err := authenticate(rctx, token, r.RequiredScopes)
|
||||
*r.Request = *r.Request.WithContext(ctx)
|
||||
return true, p, err
|
||||
})
|
||||
}
|
27
vendor/github.com/go-openapi/runtime/security/authorizer.go
generated
vendored
Normal file
27
vendor/github.com/go-openapi/runtime/security/authorizer.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
)
|
||||
|
||||
// Authorized provides a default implementation of the Authorizer interface where all
|
||||
// requests are authorized (successful)
|
||||
func Authorized() runtime.Authorizer {
|
||||
return runtime.AuthorizerFunc(func(_ *http.Request, _ interface{}) error { return nil })
|
||||
}
|
90
vendor/github.com/go-openapi/runtime/statuses.go
generated
vendored
Normal file
90
vendor/github.com/go-openapi/runtime/statuses.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
// Statuses lists the most common HTTP status codes to default message
|
||||
// taken from https://httpstatuses.com/
|
||||
var Statuses = map[int]string{
|
||||
100: "Continue",
|
||||
101: "Switching Protocols",
|
||||
102: "Processing",
|
||||
103: "Checkpoint",
|
||||
122: "URI too long",
|
||||
200: "OK",
|
||||
201: "Created",
|
||||
202: "Accepted",
|
||||
203: "Request Processed",
|
||||
204: "No Content",
|
||||
205: "Reset Content",
|
||||
206: "Partial Content",
|
||||
207: "Multi-Status",
|
||||
208: "Already Reported",
|
||||
226: "IM Used",
|
||||
300: "Multiple Choices",
|
||||
301: "Moved Permanently",
|
||||
302: "Found",
|
||||
303: "See Other",
|
||||
304: "Not Modified",
|
||||
305: "Use Proxy",
|
||||
306: "Switch Proxy",
|
||||
307: "Temporary Redirect",
|
||||
308: "Permanent Redirect",
|
||||
400: "Bad Request",
|
||||
401: "Unauthorized",
|
||||
402: "Payment Required",
|
||||
403: "Forbidden",
|
||||
404: "Not Found",
|
||||
405: "Method Not Allowed",
|
||||
406: "Not Acceptable",
|
||||
407: "Proxy Authentication Required",
|
||||
408: "Request Timeout",
|
||||
409: "Conflict",
|
||||
410: "Gone",
|
||||
411: "Length Required",
|
||||
412: "Precondition Failed",
|
||||
413: "Request Entity Too Large",
|
||||
414: "Request-URI Too Long",
|
||||
415: "Unsupported Media Type",
|
||||
416: "Request Range Not Satisfiable",
|
||||
417: "Expectation Failed",
|
||||
418: "I'm a teapot",
|
||||
420: "Enhance Your Calm",
|
||||
422: "Unprocessable Entity",
|
||||
423: "Locked",
|
||||
424: "Failed Dependency",
|
||||
426: "Upgrade Required",
|
||||
428: "Precondition Required",
|
||||
429: "Too Many Requests",
|
||||
431: "Request Header Fields Too Large",
|
||||
444: "No Response",
|
||||
449: "Retry With",
|
||||
450: "Blocked by Windows Parental Controls",
|
||||
451: "Wrong Exchange Server",
|
||||
499: "Client Closed Request",
|
||||
500: "Internal Server Error",
|
||||
501: "Not Implemented",
|
||||
502: "Bad Gateway",
|
||||
503: "Service Unavailable",
|
||||
504: "Gateway Timeout",
|
||||
505: "HTTP Version Not Supported",
|
||||
506: "Variant Also Negotiates",
|
||||
507: "Insufficient Storage",
|
||||
508: "Loop Detected",
|
||||
509: "Bandwidth Limit Exceeded",
|
||||
510: "Not Extended",
|
||||
511: "Network Authentication Required",
|
||||
598: "Network read timeout error",
|
||||
599: "Network connect timeout error",
|
||||
}
|
116
vendor/github.com/go-openapi/runtime/text.go
generated
vendored
Normal file
116
vendor/github.com/go-openapi/runtime/text.go
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// TextConsumer creates a new text consumer
|
||||
func TextConsumer() Consumer {
|
||||
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
|
||||
if reader == nil {
|
||||
return errors.New("TextConsumer requires a reader") // early exit
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err := buf.ReadFrom(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b := buf.Bytes()
|
||||
|
||||
// If the buffer is empty, no need to unmarshal it, which causes a panic.
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if tu, ok := data.(encoding.TextUnmarshaler); ok {
|
||||
err := tu.UnmarshalText(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("text consumer: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(data)
|
||||
if data != nil && t.Kind() == reflect.Ptr {
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
if t.Elem().Kind() == reflect.String {
|
||||
v.SetString(string(b))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("%v (%T) is not supported by the TextConsumer, %s",
|
||||
data, data, "can be resolved by supporting TextUnmarshaler interface")
|
||||
})
|
||||
}
|
||||
|
||||
// TextProducer creates a new text producer
|
||||
func TextProducer() Producer {
|
||||
return ProducerFunc(func(writer io.Writer, data interface{}) error {
|
||||
if writer == nil {
|
||||
return errors.New("TextProducer requires a writer") // early exit
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
return errors.New("no data given to produce text from")
|
||||
}
|
||||
|
||||
if tm, ok := data.(encoding.TextMarshaler); ok {
|
||||
txt, err := tm.MarshalText()
|
||||
if err != nil {
|
||||
return fmt.Errorf("text producer: %v", err)
|
||||
}
|
||||
_, err = writer.Write(txt)
|
||||
return err
|
||||
}
|
||||
|
||||
if str, ok := data.(error); ok {
|
||||
_, err := writer.Write([]byte(str.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
if str, ok := data.(fmt.Stringer); ok {
|
||||
_, err := writer.Write([]byte(str.String()))
|
||||
return err
|
||||
}
|
||||
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
if t := v.Type(); t.Kind() == reflect.Struct || t.Kind() == reflect.Slice {
|
||||
b, err := swag.WriteJSON(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = writer.Write(b)
|
||||
return err
|
||||
}
|
||||
if v.Kind() != reflect.String {
|
||||
return fmt.Errorf("%T is not a supported type by the TextProducer", data)
|
||||
}
|
||||
|
||||
_, err := writer.Write([]byte(v.String()))
|
||||
return err
|
||||
})
|
||||
}
|
19
vendor/github.com/go-openapi/runtime/values.go
generated
vendored
Normal file
19
vendor/github.com/go-openapi/runtime/values.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
package runtime
|
||||
|
||||
// Values typically represent parameters on a http request.
|
||||
type Values map[string][]string
|
||||
|
||||
// GetOK returns the values collection for the given key.
|
||||
// When the key is present in the map it will return true for hasKey.
|
||||
// When the value is not empty it will return true for hasValue.
|
||||
func (v Values) GetOK(key string) (value []string, hasKey bool, hasValue bool) {
|
||||
value, hasKey = v[key]
|
||||
if !hasKey {
|
||||
return
|
||||
}
|
||||
if len(value) == 0 {
|
||||
return
|
||||
}
|
||||
hasValue = true
|
||||
return
|
||||
}
|
36
vendor/github.com/go-openapi/runtime/xml.go
generated
vendored
Normal file
36
vendor/github.com/go-openapi/runtime/xml.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io"
|
||||
)
|
||||
|
||||
// XMLConsumer creates a new XML consumer
|
||||
func XMLConsumer() Consumer {
|
||||
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
|
||||
dec := xml.NewDecoder(reader)
|
||||
return dec.Decode(data)
|
||||
})
|
||||
}
|
||||
|
||||
// XMLProducer creates a new XML producer
|
||||
func XMLProducer() Producer {
|
||||
return ProducerFunc(func(writer io.Writer, data interface{}) error {
|
||||
enc := xml.NewEncoder(writer)
|
||||
return enc.Encode(data)
|
||||
})
|
||||
}
|
39
vendor/github.com/go-openapi/runtime/yamlpc/yaml.go
generated
vendored
Normal file
39
vendor/github.com/go-openapi/runtime/yamlpc/yaml.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package yamlpc
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// YAMLConsumer creates a consumer for yaml data
|
||||
func YAMLConsumer() runtime.Consumer {
|
||||
return runtime.ConsumerFunc(func(r io.Reader, v interface{}) error {
|
||||
dec := yaml.NewDecoder(r)
|
||||
return dec.Decode(v)
|
||||
})
|
||||
}
|
||||
|
||||
// YAMLProducer creates a producer for yaml data
|
||||
func YAMLProducer() runtime.Producer {
|
||||
return runtime.ProducerFunc(func(w io.Writer, v interface{}) error {
|
||||
enc := yaml.NewEncoder(w)
|
||||
defer enc.Close()
|
||||
return enc.Encode(v)
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user