go.mod: bump github.com/getkin/kin-openapi to v0.131.0
As deepmap/oapi-codegen didn't work with this newer version, upgrade to oapi-codegen/oapi-codegen v2. Mitigating CVE-2025-30153
This commit is contained in:
parent
c5cb0d0618
commit
b2700903ae
403 changed files with 44758 additions and 16347 deletions
1
vendor/github.com/oapi-codegen/runtime/.gitignore
generated
vendored
Normal file
1
vendor/github.com/oapi-codegen/runtime/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
bin/
|
||||
201
vendor/github.com/oapi-codegen/runtime/LICENSE
generated
vendored
Normal file
201
vendor/github.com/oapi-codegen/runtime/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
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.
|
||||
32
vendor/github.com/oapi-codegen/runtime/Makefile
generated
vendored
Normal file
32
vendor/github.com/oapi-codegen/runtime/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
GOBASE=$(shell pwd)
|
||||
GOBIN=$(GOBASE)/bin
|
||||
|
||||
help:
|
||||
@echo "This is a helper makefile for oapi-codegen"
|
||||
@echo "Targets:"
|
||||
@echo " generate: regenerate all generated files"
|
||||
@echo " test: run all tests"
|
||||
@echo " gin_example generate gin example server code"
|
||||
@echo " tidy tidy go mod"
|
||||
|
||||
$(GOBIN)/golangci-lint:
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.55.2
|
||||
|
||||
.PHONY: tools
|
||||
tools: $(GOBIN)/golangci-lint
|
||||
|
||||
lint: tools
|
||||
$(GOBIN)/golangci-lint run ./...
|
||||
|
||||
lint-ci: tools
|
||||
$(GOBIN)/golangci-lint run ./... --out-format=github-actions --timeout=5m
|
||||
|
||||
generate:
|
||||
go generate ./...
|
||||
|
||||
test:
|
||||
go test -cover ./...
|
||||
|
||||
tidy:
|
||||
@echo "tidy..."
|
||||
go mod tidy
|
||||
6
vendor/github.com/oapi-codegen/runtime/README.md
generated
vendored
Normal file
6
vendor/github.com/oapi-codegen/runtime/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# oapi-codegen/runtime
|
||||
|
||||
⚠️ This README may be for the latest development version, which may
|
||||
contain unreleased changes. Please ensure you're looking at the README for the latest release version.
|
||||
|
||||
This provides any runtime-specific code that the generated code that oapi-codegen generates may need, and therefore is expected to be used with [deepmap/oapi-codegen](https://github.com/deepmap/oapi-codegen).
|
||||
24
vendor/github.com/oapi-codegen/runtime/bind.go
generated
vendored
Normal file
24
vendor/github.com/oapi-codegen/runtime/bind.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2021 DeepMap, Inc.
|
||||
//
|
||||
// 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
|
||||
|
||||
// Binder is the interface implemented by types that can be bound to a query string or a parameter string
|
||||
// The input can be assumed to be a valid string. If you define a Bind method you are responsible for all
|
||||
// data being completely bound to the type.
|
||||
//
|
||||
// By convention, to approximate the behavior of Bind functions themselves,
|
||||
// Binder implements Bind("") as a no-op.
|
||||
type Binder interface {
|
||||
Bind(src string) error
|
||||
}
|
||||
318
vendor/github.com/oapi-codegen/runtime/bindform.go
generated
vendored
Normal file
318
vendor/github.com/oapi-codegen/runtime/bindform.go
generated
vendored
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/oapi-codegen/runtime/types"
|
||||
)
|
||||
|
||||
const tagName = "json"
|
||||
const jsonContentType = "application/json"
|
||||
|
||||
type RequestBodyEncoding struct {
|
||||
ContentType string
|
||||
Style string
|
||||
Explode *bool
|
||||
Required *bool
|
||||
}
|
||||
|
||||
func BindMultipart(ptr interface{}, reader multipart.Reader) error {
|
||||
const defaultMemory = 32 << 20
|
||||
form, err := reader.ReadForm(defaultMemory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return BindForm(ptr, form.Value, form.File, nil)
|
||||
}
|
||||
|
||||
func BindForm(ptr interface{}, form map[string][]string, files map[string][]*multipart.FileHeader, encodings map[string]RequestBodyEncoding) error {
|
||||
ptrVal := reflect.Indirect(reflect.ValueOf(ptr))
|
||||
if ptrVal.Kind() != reflect.Struct {
|
||||
return errors.New("form data body should be a struct")
|
||||
}
|
||||
tValue := ptrVal.Type()
|
||||
|
||||
for i := 0; i < tValue.NumField(); i++ {
|
||||
field := ptrVal.Field(i)
|
||||
tag := tValue.Field(i).Tag.Get(tagName)
|
||||
if !field.CanInterface() || tag == "-" {
|
||||
continue
|
||||
}
|
||||
tag = strings.Split(tag, ",")[0] // extract the name of the tag
|
||||
if encoding, ok := encodings[tag]; ok {
|
||||
// custom encoding
|
||||
values := form[tag]
|
||||
if len(values) == 0 {
|
||||
continue
|
||||
}
|
||||
value := values[0]
|
||||
if encoding.ContentType != "" {
|
||||
if strings.HasPrefix(encoding.ContentType, jsonContentType) {
|
||||
if err := json.Unmarshal([]byte(value), ptr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return errors.New("unsupported encoding, only application/json is supported")
|
||||
} else {
|
||||
var explode bool
|
||||
if encoding.Explode != nil {
|
||||
explode = *encoding.Explode
|
||||
}
|
||||
var required bool
|
||||
if encoding.Required != nil {
|
||||
required = *encoding.Required
|
||||
}
|
||||
if err := BindStyledParameterWithOptions(encoding.Style, tag, value, field.Addr().Interface(), BindStyledParameterOptions{
|
||||
ParamLocation: ParamLocationUndefined,
|
||||
Explode: explode,
|
||||
Required: required,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// regular form data
|
||||
if _, err := bindFormImpl(field, form, files, tag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func MarshalForm(ptr interface{}, encodings map[string]RequestBodyEncoding) (url.Values, error) {
|
||||
ptrVal := reflect.Indirect(reflect.ValueOf(ptr))
|
||||
if ptrVal.Kind() != reflect.Struct {
|
||||
return nil, errors.New("form data body should be a struct")
|
||||
}
|
||||
tValue := ptrVal.Type()
|
||||
result := make(url.Values)
|
||||
for i := 0; i < tValue.NumField(); i++ {
|
||||
field := ptrVal.Field(i)
|
||||
tag := tValue.Field(i).Tag.Get(tagName)
|
||||
if !field.CanInterface() || tag == "-" {
|
||||
continue
|
||||
}
|
||||
omitEmpty := strings.HasSuffix(tag, ",omitempty")
|
||||
if omitEmpty && field.IsZero() {
|
||||
continue
|
||||
}
|
||||
tag = strings.Split(tag, ",")[0] // extract the name of the tag
|
||||
if encoding, ok := encodings[tag]; ok && encoding.ContentType != "" {
|
||||
if strings.HasPrefix(encoding.ContentType, jsonContentType) {
|
||||
if data, err := json.Marshal(field); err != nil { //nolint:staticcheck
|
||||
return nil, err
|
||||
} else {
|
||||
result[tag] = append(result[tag], string(data))
|
||||
}
|
||||
}
|
||||
return nil, errors.New("unsupported encoding, only application/json is supported")
|
||||
} else {
|
||||
marshalFormImpl(field, result, tag)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func bindFormImpl(v reflect.Value, form map[string][]string, files map[string][]*multipart.FileHeader, name string) (bool, error) {
|
||||
var hasData bool
|
||||
switch v.Kind() {
|
||||
case reflect.Interface:
|
||||
return bindFormImpl(v.Elem(), form, files, name)
|
||||
case reflect.Ptr:
|
||||
ptrData := v.Elem()
|
||||
if !ptrData.IsValid() {
|
||||
ptrData = reflect.New(v.Type().Elem())
|
||||
}
|
||||
ptrHasData, err := bindFormImpl(ptrData, form, files, name)
|
||||
if err == nil && ptrHasData && !v.Elem().IsValid() {
|
||||
v.Set(ptrData)
|
||||
}
|
||||
return ptrHasData, err
|
||||
case reflect.Slice:
|
||||
if files := append(files[name], files[name+"[]"]...); len(files) != 0 {
|
||||
if _, ok := v.Interface().([]types.File); ok {
|
||||
result := make([]types.File, len(files))
|
||||
for i, file := range files {
|
||||
result[i].InitFromMultipart(file)
|
||||
}
|
||||
v.Set(reflect.ValueOf(result))
|
||||
hasData = true
|
||||
}
|
||||
}
|
||||
indexedElementsCount := indexedElementsCount(form, files, name)
|
||||
items := append(form[name], form[name+"[]"]...)
|
||||
if indexedElementsCount+len(items) != 0 {
|
||||
result := reflect.MakeSlice(v.Type(), indexedElementsCount+len(items), indexedElementsCount+len(items))
|
||||
for i := 0; i < indexedElementsCount; i++ {
|
||||
if _, err := bindFormImpl(result.Index(i), form, files, fmt.Sprintf("%s[%v]", name, i)); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
for i, item := range items {
|
||||
if err := BindStringToObject(item, result.Index(indexedElementsCount+i).Addr().Interface()); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
v.Set(result)
|
||||
hasData = true
|
||||
}
|
||||
case reflect.Struct:
|
||||
if files := files[name]; len(files) != 0 {
|
||||
if file, ok := v.Interface().(types.File); ok {
|
||||
file.InitFromMultipart(files[0])
|
||||
v.Set(reflect.ValueOf(file))
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
field := v.Type().Field(i)
|
||||
tag := field.Tag.Get(tagName)
|
||||
if field.Name == "AdditionalProperties" && field.Type.Kind() == reflect.Map && tag == "-" {
|
||||
additionalPropertiesHasData, err := bindAdditionalProperties(v.Field(i), v, form, files, name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
hasData = hasData || additionalPropertiesHasData
|
||||
}
|
||||
if !v.Field(i).CanInterface() || tag == "-" {
|
||||
continue
|
||||
}
|
||||
tag = strings.Split(tag, ",")[0] // extract the name of the tag
|
||||
fieldHasData, err := bindFormImpl(v.Field(i), form, files, fmt.Sprintf("%s[%s]", name, tag))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
hasData = hasData || fieldHasData
|
||||
}
|
||||
return hasData, nil
|
||||
default:
|
||||
value := form[name]
|
||||
if len(value) != 0 {
|
||||
return true, BindStringToObject(value[0], v.Addr().Interface())
|
||||
}
|
||||
}
|
||||
return hasData, nil
|
||||
}
|
||||
|
||||
func indexedElementsCount(form map[string][]string, files map[string][]*multipart.FileHeader, name string) int {
|
||||
name += "["
|
||||
maxIndex := -1
|
||||
for k := range form {
|
||||
if strings.HasPrefix(k, name) {
|
||||
str := strings.TrimPrefix(k, name)
|
||||
str = str[:strings.Index(str, "]")]
|
||||
if idx, err := strconv.Atoi(str); err == nil {
|
||||
if idx > maxIndex {
|
||||
maxIndex = idx
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for k := range files {
|
||||
if strings.HasPrefix(k, name) {
|
||||
str := strings.TrimPrefix(k, name)
|
||||
str = str[:strings.Index(str, "]")]
|
||||
if idx, err := strconv.Atoi(str); err == nil {
|
||||
if idx > maxIndex {
|
||||
maxIndex = idx
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxIndex + 1
|
||||
}
|
||||
|
||||
func bindAdditionalProperties(additionalProperties reflect.Value, parentStruct reflect.Value, form map[string][]string, files map[string][]*multipart.FileHeader, name string) (bool, error) {
|
||||
hasData := false
|
||||
valueType := additionalProperties.Type().Elem()
|
||||
|
||||
// store all fixed properties in a set
|
||||
fieldsSet := make(map[string]struct{})
|
||||
for i := 0; i < parentStruct.NumField(); i++ {
|
||||
tag := parentStruct.Type().Field(i).Tag.Get(tagName)
|
||||
if !parentStruct.Field(i).CanInterface() || tag == "-" {
|
||||
continue
|
||||
}
|
||||
tag = strings.Split(tag, ",")[0]
|
||||
fieldsSet[tag] = struct{}{}
|
||||
}
|
||||
|
||||
result := reflect.MakeMap(additionalProperties.Type())
|
||||
for k := range form {
|
||||
if strings.HasPrefix(k, name+"[") {
|
||||
key := strings.TrimPrefix(k, name+"[")
|
||||
key = key[:strings.Index(key, "]")]
|
||||
if _, ok := fieldsSet[key]; ok {
|
||||
continue
|
||||
}
|
||||
value := reflect.New(valueType)
|
||||
ptrHasData, err := bindFormImpl(value, form, files, fmt.Sprintf("%s[%s]", name, key))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result.SetMapIndex(reflect.ValueOf(key), value.Elem())
|
||||
hasData = hasData || ptrHasData
|
||||
}
|
||||
}
|
||||
for k := range files {
|
||||
if strings.HasPrefix(k, name+"[") {
|
||||
key := strings.TrimPrefix(k, name+"[")
|
||||
key = key[:strings.Index(key, "]")]
|
||||
if _, ok := fieldsSet[key]; ok {
|
||||
continue
|
||||
}
|
||||
value := reflect.New(valueType)
|
||||
result.SetMapIndex(reflect.ValueOf(key), value)
|
||||
ptrHasData, err := bindFormImpl(value, form, files, fmt.Sprintf("%s[%s]", name, key))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result.SetMapIndex(reflect.ValueOf(key), value.Elem())
|
||||
hasData = hasData || ptrHasData
|
||||
}
|
||||
}
|
||||
if hasData {
|
||||
additionalProperties.Set(result)
|
||||
}
|
||||
return hasData, nil
|
||||
}
|
||||
|
||||
func marshalFormImpl(v reflect.Value, result url.Values, name string) {
|
||||
switch v.Kind() {
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
marshalFormImpl(v.Elem(), result, name)
|
||||
case reflect.Slice:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
elem := v.Index(i)
|
||||
marshalFormImpl(elem, result, fmt.Sprintf("%s[%v]", name, i))
|
||||
}
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
field := v.Type().Field(i)
|
||||
tag := field.Tag.Get(tagName)
|
||||
if field.Name == "AdditionalProperties" && tag == "-" {
|
||||
iter := v.MapRange()
|
||||
for iter.Next() {
|
||||
marshalFormImpl(iter.Value(), result, fmt.Sprintf("%s[%s]", name, iter.Key().String()))
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !v.Field(i).CanInterface() || tag == "-" {
|
||||
continue
|
||||
}
|
||||
tag = strings.Split(tag, ",")[0] // extract the name of the tag
|
||||
marshalFormImpl(v.Field(i), result, fmt.Sprintf("%s[%s]", name, tag))
|
||||
}
|
||||
default:
|
||||
result[name] = append(result[name], fmt.Sprint(v.Interface()))
|
||||
}
|
||||
}
|
||||
555
vendor/github.com/oapi-codegen/runtime/bindparam.go
generated
vendored
Normal file
555
vendor/github.com/oapi-codegen/runtime/bindparam.go
generated
vendored
Normal file
|
|
@ -0,0 +1,555 @@
|
|||
// Copyright 2019 DeepMap, Inc.
|
||||
//
|
||||
// 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"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/oapi-codegen/runtime/types"
|
||||
)
|
||||
|
||||
// BindStyledParameter binds a parameter as described in the Path Parameters
|
||||
// section here to a Go object:
|
||||
// https://swagger.io/docs/specification/serialization/
|
||||
// It is a backward compatible function to clients generated with codegen
|
||||
// up to version v1.5.5. v1.5.6+ calls the function below.
|
||||
// Deprecated: BindStyledParameter is deprecated.
|
||||
func BindStyledParameter(style string, explode bool, paramName string,
|
||||
value string, dest interface{}) error {
|
||||
return BindStyledParameterWithOptions(style, paramName, value, dest, BindStyledParameterOptions{
|
||||
ParamLocation: ParamLocationUndefined,
|
||||
Explode: explode,
|
||||
Required: true,
|
||||
})
|
||||
}
|
||||
|
||||
// BindStyledParameterWithLocation binds a parameter as described in the Path Parameters
|
||||
// section here to a Go object:
|
||||
// https://swagger.io/docs/specification/serialization/
|
||||
// This is a compatibility function which is used by oapi-codegen v2.0.0 and earlier.
|
||||
// Deprecated: BindStyledParameterWithLocation is deprecated.
|
||||
func BindStyledParameterWithLocation(style string, explode bool, paramName string,
|
||||
paramLocation ParamLocation, value string, dest interface{}) error {
|
||||
return BindStyledParameterWithOptions(style, paramName, value, dest, BindStyledParameterOptions{
|
||||
ParamLocation: paramLocation,
|
||||
Explode: explode,
|
||||
Required: true, // This emulates behavior before the required parameter was optional.
|
||||
})
|
||||
}
|
||||
|
||||
// BindStyledParameterOptions defines optional arguments for BindStyledParameterWithOptions
|
||||
type BindStyledParameterOptions struct {
|
||||
// ParamLocation tells us where the parameter is located in the request.
|
||||
ParamLocation ParamLocation
|
||||
// Whether the parameter should use exploded structure
|
||||
Explode bool
|
||||
// Whether the parameter is required in the query
|
||||
Required bool
|
||||
}
|
||||
|
||||
// BindStyledParameterWithOptions binds a parameter as described in the Path Parameters
|
||||
// section here to a Go object:
|
||||
// https://swagger.io/docs/specification/serialization/
|
||||
func BindStyledParameterWithOptions(style string, paramName string, value string, dest any, opts BindStyledParameterOptions) error {
|
||||
if opts.Required {
|
||||
if value == "" {
|
||||
return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName)
|
||||
}
|
||||
}
|
||||
|
||||
// Based on the location of the parameter, we need to unescape it properly.
|
||||
var err error
|
||||
switch opts.ParamLocation {
|
||||
case ParamLocationQuery, ParamLocationUndefined:
|
||||
// We unescape undefined parameter locations here for older generated code,
|
||||
// since prior to this refactoring, they always query unescaped.
|
||||
value, err = url.QueryUnescape(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error unescaping query parameter '%s': %v", paramName, err)
|
||||
}
|
||||
case ParamLocationPath:
|
||||
value, err = url.PathUnescape(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error unescaping path parameter '%s': %v", paramName, err)
|
||||
}
|
||||
default:
|
||||
// Headers and cookies aren't escaped.
|
||||
}
|
||||
|
||||
// If the destination implements encoding.TextUnmarshaler we use it for binding
|
||||
if tu, ok := dest.(encoding.TextUnmarshaler); ok {
|
||||
if err := tu.UnmarshalText([]byte(value)); err != nil {
|
||||
return fmt.Errorf("error unmarshaling '%s' text as %T: %s", value, dest, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Everything comes in by pointer, dereference it
|
||||
v := reflect.Indirect(reflect.ValueOf(dest))
|
||||
|
||||
// This is the basic type of the destination object.
|
||||
t := v.Type()
|
||||
|
||||
if t.Kind() == reflect.Struct {
|
||||
// We've got a destination object, we'll create a JSON representation
|
||||
// of the input value, and let the json library deal with the unmarshaling
|
||||
parts, err := splitStyledParameter(style, opts.Explode, true, paramName, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bindSplitPartsToDestinationStruct(paramName, parts, opts.Explode, dest)
|
||||
}
|
||||
|
||||
if t.Kind() == reflect.Slice {
|
||||
// Chop up the parameter into parts based on its style
|
||||
parts, err := splitStyledParameter(style, opts.Explode, false, paramName, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error splitting input '%s' into parts: %s", value, err)
|
||||
}
|
||||
|
||||
return bindSplitPartsToDestinationArray(parts, dest)
|
||||
}
|
||||
|
||||
// Try to bind the remaining types as a base type.
|
||||
return BindStringToObject(value, dest)
|
||||
}
|
||||
|
||||
// This is a complex set of operations, but each given parameter style can be
|
||||
// packed together in multiple ways, using different styles of separators, and
|
||||
// different packing strategies based on the explode flag. This function takes
|
||||
// as input any parameter format, and unpacks it to a simple list of strings
|
||||
// or key-values which we can then treat generically.
|
||||
// Why, oh why, great Swagger gods, did you have to make this so complicated?
|
||||
func splitStyledParameter(style string, explode bool, object bool, paramName string, value string) ([]string, error) {
|
||||
switch style {
|
||||
case "simple":
|
||||
// In the simple case, we always split on comma
|
||||
parts := strings.Split(value, ",")
|
||||
return parts, nil
|
||||
case "label":
|
||||
// In the label case, it's more tricky. In the no explode case, we have
|
||||
// /users/.3,4,5 for arrays
|
||||
// /users/.role,admin,firstName,Alex for objects
|
||||
// in the explode case, we have:
|
||||
// /users/.3.4.5
|
||||
// /users/.role=admin.firstName=Alex
|
||||
if explode {
|
||||
// In the exploded case, split everything on periods.
|
||||
parts := strings.Split(value, ".")
|
||||
// The first part should be an empty string because we have a
|
||||
// leading period.
|
||||
if parts[0] != "" {
|
||||
return nil, fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName)
|
||||
}
|
||||
return parts[1:], nil
|
||||
|
||||
} else {
|
||||
// In the unexploded case, we strip off the leading period.
|
||||
if value[0] != '.' {
|
||||
return nil, fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName)
|
||||
}
|
||||
// The rest is comma separated.
|
||||
return strings.Split(value[1:], ","), nil
|
||||
}
|
||||
|
||||
case "matrix":
|
||||
if explode {
|
||||
// In the exploded case, we break everything up on semicolon
|
||||
parts := strings.Split(value, ";")
|
||||
// The first part should always be empty string, since we started
|
||||
// with ;something
|
||||
if parts[0] != "" {
|
||||
return nil, fmt.Errorf("invalid format for matrix parameter '%s', should start with ';'", paramName)
|
||||
}
|
||||
parts = parts[1:]
|
||||
// Now, if we have an object, we just have a list of x=y statements.
|
||||
// for a non-object, like an array, we have id=x, id=y. id=z, etc,
|
||||
// so we need to strip the prefix from each of them.
|
||||
if !object {
|
||||
prefix := paramName + "="
|
||||
for i := range parts {
|
||||
parts[i] = strings.TrimPrefix(parts[i], prefix)
|
||||
}
|
||||
}
|
||||
return parts, nil
|
||||
} else {
|
||||
// In the unexploded case, parameters will start with ;paramName=
|
||||
prefix := ";" + paramName + "="
|
||||
if !strings.HasPrefix(value, prefix) {
|
||||
return nil, fmt.Errorf("expected parameter '%s' to start with %s", paramName, prefix)
|
||||
}
|
||||
str := strings.TrimPrefix(value, prefix)
|
||||
return strings.Split(str, ","), nil
|
||||
}
|
||||
case "form":
|
||||
var parts []string
|
||||
if explode {
|
||||
parts = strings.Split(value, "&")
|
||||
if !object {
|
||||
prefix := paramName + "="
|
||||
for i := range parts {
|
||||
parts[i] = strings.TrimPrefix(parts[i], prefix)
|
||||
}
|
||||
}
|
||||
return parts, nil
|
||||
} else {
|
||||
parts = strings.Split(value, ",")
|
||||
prefix := paramName + "="
|
||||
for i := range parts {
|
||||
parts[i] = strings.TrimPrefix(parts[i], prefix)
|
||||
}
|
||||
}
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unhandled parameter style: %s", style)
|
||||
}
|
||||
|
||||
// Given a set of values as a slice, create a slice to hold them all, and
|
||||
// assign to each one by one.
|
||||
func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error {
|
||||
// Everything comes in by pointer, dereference it
|
||||
v := reflect.Indirect(reflect.ValueOf(dest))
|
||||
|
||||
// This is the basic type of the destination object.
|
||||
t := v.Type()
|
||||
|
||||
// We've got a destination array, bind each object one by one.
|
||||
// This generates a slice of the correct element type and length to
|
||||
// hold all the parts.
|
||||
newArray := reflect.MakeSlice(t, len(parts), len(parts))
|
||||
for i, p := range parts {
|
||||
err := BindStringToObject(p, newArray.Index(i).Addr().Interface())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error setting array element: %w", err)
|
||||
}
|
||||
}
|
||||
v.Set(newArray)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Given a set of chopped up parameter parts, bind them to a destination
|
||||
// struct. The exploded parameter controls whether we send key value pairs
|
||||
// in the exploded case, or a sequence of values which are interpreted as
|
||||
// tuples.
|
||||
// Given the struct Id { firstName string, role string }, as in the canonical
|
||||
// swagger examples, in the exploded case, we would pass
|
||||
// ["firstName=Alex", "role=admin"], where in the non-exploded case, we would
|
||||
// pass "firstName", "Alex", "role", "admin"]
|
||||
//
|
||||
// We punt the hard work of binding these values to the object to the json
|
||||
// library. We'll turn those arrays into JSON strings, and unmarshal
|
||||
// into the struct.
|
||||
func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error {
|
||||
// We've got a destination object, we'll create a JSON representation
|
||||
// of the input value, and let the json library deal with the unmarshaling
|
||||
var fields []string
|
||||
if explode {
|
||||
fields = make([]string, len(parts))
|
||||
for i, property := range parts {
|
||||
propertyParts := strings.Split(property, "=")
|
||||
if len(propertyParts) != 2 {
|
||||
return fmt.Errorf("parameter '%s' has invalid exploded format", paramName)
|
||||
}
|
||||
fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\""
|
||||
}
|
||||
} else {
|
||||
if len(parts)%2 != 0 {
|
||||
return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName)
|
||||
}
|
||||
fields = make([]string, len(parts)/2)
|
||||
for i := 0; i < len(parts); i += 2 {
|
||||
key := parts[i]
|
||||
value := parts[i+1]
|
||||
fields[i/2] = "\"" + key + "\":\"" + value + "\""
|
||||
}
|
||||
}
|
||||
jsonParam := "{" + strings.Join(fields, ",") + "}"
|
||||
err := json.Unmarshal([]byte(jsonParam), dest)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error binding parameter %s fields: %s", paramName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BindQueryParameter works much like BindStyledParameter, however it takes a query argument
|
||||
// input array from the url package, since query arguments come through a
|
||||
// different path than the styled arguments. They're also exceptionally fussy.
|
||||
// For example, consider the exploded and unexploded form parameter examples:
|
||||
// (exploded) /users?role=admin&firstName=Alex
|
||||
// (unexploded) /users?id=role,admin,firstName,Alex
|
||||
//
|
||||
// In the first case, we can pull the "id" parameter off the context,
|
||||
// and unmarshal via json as an intermediate. Easy. In the second case, we
|
||||
// don't have the id QueryParam present, but must find "role", and "firstName".
|
||||
// what if there is another parameter similar to "ID" named "role"? We can't
|
||||
// tell them apart. This code tries to fail, but the moral of the story is that
|
||||
// you shouldn't pass objects via form styled query arguments, just use
|
||||
// the Content parameter form.
|
||||
func BindQueryParameter(style string, explode bool, required bool, paramName string,
|
||||
queryParams url.Values, dest interface{}) error {
|
||||
|
||||
// dv = destination value.
|
||||
dv := reflect.Indirect(reflect.ValueOf(dest))
|
||||
|
||||
// intermediate value form which is either dv or dv dereferenced.
|
||||
v := dv
|
||||
|
||||
// inner code will bind the string's value to this interface.
|
||||
var output interface{}
|
||||
|
||||
if required {
|
||||
// If the parameter is required, then the generated code will pass us
|
||||
// a pointer to it: &int, &object, and so forth. We can directly set
|
||||
// them.
|
||||
output = dest
|
||||
} else {
|
||||
// For optional parameters, we have an extra indirect. An optional
|
||||
// parameter of type "int" will be *int on the struct. We pass that
|
||||
// in by pointer, and have **int.
|
||||
|
||||
// If the destination, is a nil pointer, we need to allocate it.
|
||||
if v.IsNil() {
|
||||
t := v.Type()
|
||||
newValue := reflect.New(t.Elem())
|
||||
// for now, hang onto the output buffer separately from destination,
|
||||
// as we don't want to write anything to destination until we can
|
||||
// unmarshal successfully, and check whether a field is required.
|
||||
output = newValue.Interface()
|
||||
} else {
|
||||
// If the destination isn't nil, just use that.
|
||||
output = v.Interface()
|
||||
}
|
||||
|
||||
// Get rid of that extra indirect as compared to the required case,
|
||||
// so the code below doesn't have to care.
|
||||
v = reflect.Indirect(reflect.ValueOf(output))
|
||||
}
|
||||
|
||||
// This is the basic type of the destination object.
|
||||
t := v.Type()
|
||||
k := t.Kind()
|
||||
|
||||
switch style {
|
||||
case "form":
|
||||
var parts []string
|
||||
if explode {
|
||||
// ok, the explode case in query arguments is very, very annoying,
|
||||
// because an exploded object, such as /users?role=admin&firstName=Alex
|
||||
// isn't actually present in the parameter array. We have to do
|
||||
// different things based on destination type.
|
||||
values, found := queryParams[paramName]
|
||||
var err error
|
||||
|
||||
switch k {
|
||||
case reflect.Slice:
|
||||
// In the slice case, we simply use the arguments provided by
|
||||
// http library.
|
||||
|
||||
if !found {
|
||||
if required {
|
||||
return fmt.Errorf("query parameter '%s' is required", paramName)
|
||||
} else {
|
||||
// If an optional parameter is not found, we do nothing,
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = bindSplitPartsToDestinationArray(values, output)
|
||||
case reflect.Struct:
|
||||
// This case is really annoying, and error prone, but the
|
||||
// form style object binding doesn't tell us which arguments
|
||||
// in the query string correspond to the object's fields. We'll
|
||||
// try to bind field by field.
|
||||
var fieldsPresent bool
|
||||
fieldsPresent, err = bindParamsToExplodedObject(paramName, queryParams, output)
|
||||
// If no fields were set, and there is no error, we will not fall
|
||||
// through to assign the destination.
|
||||
if !fieldsPresent {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
// Primitive object case. We expect to have 1 value to
|
||||
// unmarshal.
|
||||
if len(values) == 0 {
|
||||
if required {
|
||||
return fmt.Errorf("query parameter '%s' is required", paramName)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(values) != 1 {
|
||||
return fmt.Errorf("multiple values for single value parameter '%s'", paramName)
|
||||
}
|
||||
|
||||
if !found {
|
||||
if required {
|
||||
return fmt.Errorf("query parameter '%s' is required", paramName)
|
||||
} else {
|
||||
// If an optional parameter is not found, we do nothing,
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = BindStringToObject(values[0], output)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If the parameter is required, and we've successfully unmarshaled
|
||||
// it, this assigns the new object to the pointer pointer.
|
||||
if !required {
|
||||
dv.Set(reflect.ValueOf(output))
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
values, found := queryParams[paramName]
|
||||
if !found {
|
||||
if required {
|
||||
return fmt.Errorf("query parameter '%s' is required", paramName)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(values) != 1 {
|
||||
return fmt.Errorf("parameter '%s' is not exploded, but is specified multiple times", paramName)
|
||||
}
|
||||
parts = strings.Split(values[0], ",")
|
||||
}
|
||||
var err error
|
||||
switch k {
|
||||
case reflect.Slice:
|
||||
err = bindSplitPartsToDestinationArray(parts, output)
|
||||
case reflect.Struct:
|
||||
err = bindSplitPartsToDestinationStruct(paramName, parts, explode, output)
|
||||
default:
|
||||
if len(parts) == 0 {
|
||||
if required {
|
||||
return fmt.Errorf("query parameter '%s' is required", paramName)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(parts) != 1 {
|
||||
return fmt.Errorf("multiple values for single value parameter '%s'", paramName)
|
||||
}
|
||||
err = BindStringToObject(parts[0], output)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !required {
|
||||
dv.Set(reflect.ValueOf(output))
|
||||
}
|
||||
return nil
|
||||
case "deepObject":
|
||||
if !explode {
|
||||
return errors.New("deepObjects must be exploded")
|
||||
}
|
||||
return UnmarshalDeepObject(dest, paramName, queryParams)
|
||||
case "spaceDelimited", "pipeDelimited":
|
||||
return fmt.Errorf("query arguments of style '%s' aren't yet supported", style)
|
||||
default:
|
||||
return fmt.Errorf("style '%s' on parameter '%s' is invalid", style, paramName)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// bindParamsToExplodedObject reflects the destination structure, and pulls the value for
|
||||
// each settable field from the given parameters map. This is to deal with the
|
||||
// exploded form styled object which may occupy any number of parameter names.
|
||||
// We don't try to be smart here, if the field exists as a query argument,
|
||||
// set its value. This function returns a boolean, telling us whether there was
|
||||
// anything to bind. There will be nothing to bind if a parameter isn't found by name,
|
||||
// or none of an exploded object's fields are present.
|
||||
func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) {
|
||||
// Dereference pointers to their destination values
|
||||
binder, v, t := indirect(dest)
|
||||
if binder != nil {
|
||||
_, found := values[paramName]
|
||||
if !found {
|
||||
return false, nil
|
||||
}
|
||||
return true, BindStringToObject(values.Get(paramName), dest)
|
||||
}
|
||||
if t.Kind() != reflect.Struct {
|
||||
return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName)
|
||||
}
|
||||
|
||||
fieldsPresent := false
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
fieldT := t.Field(i)
|
||||
|
||||
// Skip unsettable fields, such as internal ones.
|
||||
if !v.Field(i).CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Find the json annotation on the field, and use the json specified
|
||||
// name if available, otherwise, just the field name.
|
||||
tag := fieldT.Tag.Get("json")
|
||||
fieldName := fieldT.Name
|
||||
if tag != "" {
|
||||
tagParts := strings.Split(tag, ",")
|
||||
name := tagParts[0]
|
||||
if name != "" {
|
||||
fieldName = name
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we look up field name in the parameter list.
|
||||
fieldVal, found := values[fieldName]
|
||||
if found {
|
||||
if len(fieldVal) != 1 {
|
||||
return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName)
|
||||
}
|
||||
err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface())
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("could not bind query arg '%s' to request object: %s'", paramName, err)
|
||||
}
|
||||
fieldsPresent = true
|
||||
}
|
||||
}
|
||||
return fieldsPresent, nil
|
||||
}
|
||||
|
||||
// indirect
|
||||
func indirect(dest interface{}) (interface{}, reflect.Value, reflect.Type) {
|
||||
v := reflect.ValueOf(dest)
|
||||
if v.Type().NumMethod() > 0 && v.CanInterface() {
|
||||
if u, ok := v.Interface().(Binder); ok {
|
||||
return u, reflect.Value{}, nil
|
||||
}
|
||||
}
|
||||
v = reflect.Indirect(v)
|
||||
t := v.Type()
|
||||
// special handling for custom types which might look like an object. We
|
||||
// don't want to use object binding on them, but rather treat them as
|
||||
// primitive types. time.Time{} is a unique case since we can't add a Binder
|
||||
// to it without changing the underlying generated code.
|
||||
if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
|
||||
return dest, reflect.Value{}, nil
|
||||
}
|
||||
if t.ConvertibleTo(reflect.TypeOf(types.Date{})) {
|
||||
return dest, reflect.Value{}, nil
|
||||
}
|
||||
return nil, v, t
|
||||
}
|
||||
174
vendor/github.com/oapi-codegen/runtime/bindstring.go
generated
vendored
Normal file
174
vendor/github.com/oapi-codegen/runtime/bindstring.go
generated
vendored
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
// Copyright 2019 DeepMap, Inc.
|
||||
//
|
||||
// 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"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/oapi-codegen/runtime/types"
|
||||
)
|
||||
|
||||
// BindStringToObject takes a string, and attempts to assign it to the destination
|
||||
// interface via whatever type conversion is necessary. We have to do this
|
||||
// via reflection instead of a much simpler type switch so that we can handle
|
||||
// type aliases. This function was the easy way out, the better way, since we
|
||||
// know the destination type each place that we use this, is to generate code
|
||||
// to read each specific type.
|
||||
func BindStringToObject(src string, dst interface{}) error {
|
||||
var err error
|
||||
|
||||
v := reflect.ValueOf(dst)
|
||||
t := reflect.TypeOf(dst)
|
||||
|
||||
// We need to dereference pointers
|
||||
if t.Kind() == reflect.Ptr {
|
||||
v = reflect.Indirect(v)
|
||||
t = v.Type()
|
||||
}
|
||||
|
||||
// For some optional args
|
||||
if t.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.New(t.Elem()))
|
||||
}
|
||||
|
||||
v = reflect.Indirect(v)
|
||||
t = v.Type()
|
||||
}
|
||||
|
||||
// The resulting type must be settable. reflect will catch issues like
|
||||
// passing the destination by value.
|
||||
if !v.CanSet() {
|
||||
return errors.New("destination is not settable")
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
var val int64
|
||||
val, err = strconv.ParseInt(src, 10, 64)
|
||||
if err == nil {
|
||||
if v.OverflowInt(val) {
|
||||
err = fmt.Errorf("value '%s' overflows destination of type: %s", src, t.Kind())
|
||||
}
|
||||
if err == nil {
|
||||
v.SetInt(val)
|
||||
}
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
var val uint64
|
||||
val, err = strconv.ParseUint(src, 10, 64)
|
||||
if err == nil {
|
||||
if v.OverflowUint(val) {
|
||||
err = fmt.Errorf("value '%s' overflows destination of type: %s", src, t.Kind())
|
||||
}
|
||||
v.SetUint(val)
|
||||
}
|
||||
case reflect.String:
|
||||
v.SetString(src)
|
||||
err = nil
|
||||
case reflect.Float64, reflect.Float32:
|
||||
var val float64
|
||||
val, err = strconv.ParseFloat(src, 64)
|
||||
if err == nil {
|
||||
if v.OverflowFloat(val) {
|
||||
err = fmt.Errorf("value '%s' overflows destination of type: %s", src, t.Kind())
|
||||
}
|
||||
v.SetFloat(val)
|
||||
}
|
||||
case reflect.Bool:
|
||||
var val bool
|
||||
val, err = strconv.ParseBool(src)
|
||||
if err == nil {
|
||||
v.SetBool(val)
|
||||
}
|
||||
case reflect.Array:
|
||||
if tu, ok := dst.(encoding.TextUnmarshaler); ok {
|
||||
if err := tu.UnmarshalText([]byte(src)); err != nil {
|
||||
return fmt.Errorf("error unmarshaling '%s' text as %T: %s", src, dst, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
fallthrough
|
||||
case reflect.Struct:
|
||||
// if this is not of type Time or of type Date look to see if this is of type Binder.
|
||||
if dstType, ok := dst.(Binder); ok {
|
||||
return dstType.Bind(src)
|
||||
}
|
||||
|
||||
if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
|
||||
// Don't fail on empty string.
|
||||
if src == "" {
|
||||
return nil
|
||||
}
|
||||
// Time is a special case of a struct that we handle
|
||||
parsedTime, err := time.Parse(time.RFC3339Nano, src)
|
||||
if err != nil {
|
||||
parsedTime, err = time.Parse(types.DateFormat, src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing '%s' as RFC3339 or 2006-01-02 time: %s", src, err)
|
||||
}
|
||||
}
|
||||
// So, assigning this gets a little fun. We have a value to the
|
||||
// dereference destination. We can't do a conversion to
|
||||
// time.Time because the result isn't assignable, so we need to
|
||||
// convert pointers.
|
||||
if t != reflect.TypeOf(time.Time{}) {
|
||||
vPtr := v.Addr()
|
||||
vtPtr := vPtr.Convert(reflect.TypeOf(&time.Time{}))
|
||||
v = reflect.Indirect(vtPtr)
|
||||
}
|
||||
v.Set(reflect.ValueOf(parsedTime))
|
||||
return nil
|
||||
}
|
||||
|
||||
if t.ConvertibleTo(reflect.TypeOf(types.Date{})) {
|
||||
// Don't fail on empty string.
|
||||
if src == "" {
|
||||
return nil
|
||||
}
|
||||
parsedTime, err := time.Parse(types.DateFormat, src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing '%s' as date: %s", src, err)
|
||||
}
|
||||
parsedDate := types.Date{Time: parsedTime}
|
||||
|
||||
// We have to do the same dance here to assign, just like with times
|
||||
// above.
|
||||
if t != reflect.TypeOf(types.Date{}) {
|
||||
vPtr := v.Addr()
|
||||
vtPtr := vPtr.Convert(reflect.TypeOf(&types.Date{}))
|
||||
v = reflect.Indirect(vtPtr)
|
||||
}
|
||||
v.Set(reflect.ValueOf(parsedDate))
|
||||
return nil
|
||||
}
|
||||
|
||||
// We fall through to the error case below if we haven't handled the
|
||||
// destination type above.
|
||||
fallthrough
|
||||
default:
|
||||
// We've got a bunch of types unimplemented, don't fail silently.
|
||||
err = fmt.Errorf("can not bind to destination of type: %s", t.Kind())
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error binding string parameter: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
371
vendor/github.com/oapi-codegen/runtime/deepobject.go
generated
vendored
Normal file
371
vendor/github.com/oapi-codegen/runtime/deepobject.go
generated
vendored
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/oapi-codegen/runtime/types"
|
||||
)
|
||||
|
||||
func marshalDeepObject(in interface{}, path []string) ([]string, error) {
|
||||
var result []string
|
||||
|
||||
switch t := in.(type) {
|
||||
case []interface{}:
|
||||
// For the array, we will use numerical subscripts of the form [x],
|
||||
// in the same order as the array.
|
||||
for i, iface := range t {
|
||||
newPath := append(path, strconv.Itoa(i))
|
||||
fields, err := marshalDeepObject(iface, newPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error traversing array: %w", err)
|
||||
}
|
||||
result = append(result, fields...)
|
||||
}
|
||||
case map[string]interface{}:
|
||||
// For a map, each key (field name) becomes a member of the path, and
|
||||
// we recurse. First, sort the keys.
|
||||
keys := make([]string, len(t))
|
||||
i := 0
|
||||
for k := range t {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
// Now, for each key, we recursively marshal it.
|
||||
for _, k := range keys {
|
||||
newPath := append(path, k)
|
||||
fields, err := marshalDeepObject(t[k], newPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error traversing map: %w", err)
|
||||
}
|
||||
result = append(result, fields...)
|
||||
}
|
||||
default:
|
||||
// Now, for a concrete value, we will turn the path elements
|
||||
// into a deepObject style set of subscripts. [a, b, c] turns into
|
||||
// [a][b][c]
|
||||
prefix := "[" + strings.Join(path, "][") + "]"
|
||||
result = []string{
|
||||
prefix + fmt.Sprintf("=%v", t),
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func MarshalDeepObject(i interface{}, paramName string) (string, error) {
|
||||
// We're going to marshal to JSON and unmarshal into an interface{},
|
||||
// which will use the json pkg to deal with all the field annotations. We
|
||||
// can then walk the generic object structure to produce a deepObject. This
|
||||
// isn't efficient and it would be more efficient to reflect on our own,
|
||||
// but it's complicated, error-prone code.
|
||||
buf, err := json.Marshal(i)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal input to JSON: %w", err)
|
||||
}
|
||||
var i2 interface{}
|
||||
err = json.Unmarshal(buf, &i2)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal JSON: %w", err)
|
||||
}
|
||||
fields, err := marshalDeepObject(i2, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error traversing JSON structure: %w", err)
|
||||
}
|
||||
|
||||
// Prefix the param name to each subscripted field.
|
||||
for i := range fields {
|
||||
fields[i] = paramName + fields[i]
|
||||
}
|
||||
return strings.Join(fields, "&"), nil
|
||||
}
|
||||
|
||||
type fieldOrValue struct {
|
||||
fields map[string]fieldOrValue
|
||||
value string
|
||||
}
|
||||
|
||||
func (f *fieldOrValue) appendPathValue(path []string, value string) {
|
||||
fieldName := path[0]
|
||||
if len(path) == 1 {
|
||||
f.fields[fieldName] = fieldOrValue{value: value}
|
||||
return
|
||||
}
|
||||
|
||||
pv, found := f.fields[fieldName]
|
||||
if !found {
|
||||
pv = fieldOrValue{
|
||||
fields: make(map[string]fieldOrValue),
|
||||
}
|
||||
f.fields[fieldName] = pv
|
||||
}
|
||||
pv.appendPathValue(path[1:], value)
|
||||
}
|
||||
|
||||
func makeFieldOrValue(paths [][]string, values []string) fieldOrValue {
|
||||
|
||||
f := fieldOrValue{
|
||||
fields: make(map[string]fieldOrValue),
|
||||
}
|
||||
for i := range paths {
|
||||
path := paths[i]
|
||||
value := values[i]
|
||||
f.appendPathValue(path, value)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func UnmarshalDeepObject(dst interface{}, paramName string, params url.Values) error {
|
||||
// Params are all the query args, so we need those that look like
|
||||
// "paramName["...
|
||||
var fieldNames []string
|
||||
var fieldValues []string
|
||||
searchStr := paramName + "["
|
||||
for pName, pValues := range params {
|
||||
if strings.HasPrefix(pName, searchStr) {
|
||||
// trim the parameter name from the full name.
|
||||
pName = pName[len(paramName):]
|
||||
fieldNames = append(fieldNames, pName)
|
||||
if len(pValues) != 1 {
|
||||
return fmt.Errorf("%s has multiple values", pName)
|
||||
}
|
||||
fieldValues = append(fieldValues, pValues[0])
|
||||
}
|
||||
}
|
||||
|
||||
// Now, for each field, reconstruct its subscript path and value
|
||||
paths := make([][]string, len(fieldNames))
|
||||
for i, path := range fieldNames {
|
||||
path = strings.TrimLeft(path, "[")
|
||||
path = strings.TrimRight(path, "]")
|
||||
paths[i] = strings.Split(path, "][")
|
||||
}
|
||||
|
||||
fieldPaths := makeFieldOrValue(paths, fieldValues)
|
||||
err := assignPathValues(dst, fieldPaths)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error assigning value to destination: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// This returns a field name, either using the variable name, or the json
|
||||
// annotation if that exists.
|
||||
func getFieldName(f reflect.StructField) string {
|
||||
n := f.Name
|
||||
tag, found := f.Tag.Lookup("json")
|
||||
if found {
|
||||
// If we have a json field, and the first part of it before the
|
||||
// first comma is non-empty, that's our field name.
|
||||
parts := strings.Split(tag, ",")
|
||||
if parts[0] != "" {
|
||||
n = parts[0]
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Create a map of field names that we'll see in the deepObject to reflect
|
||||
// field indices on the given type.
|
||||
func fieldIndicesByJSONTag(i interface{}) (map[string]int, error) {
|
||||
t := reflect.TypeOf(i)
|
||||
if t.Kind() != reflect.Struct {
|
||||
return nil, errors.New("expected a struct as input")
|
||||
}
|
||||
|
||||
n := t.NumField()
|
||||
fieldMap := make(map[string]int)
|
||||
for i := 0; i < n; i++ {
|
||||
field := t.Field(i)
|
||||
fieldName := getFieldName(field)
|
||||
fieldMap[fieldName] = i
|
||||
}
|
||||
return fieldMap, nil
|
||||
}
|
||||
|
||||
func assignPathValues(dst interface{}, pathValues fieldOrValue) error {
|
||||
//t := reflect.TypeOf(dst)
|
||||
v := reflect.ValueOf(dst)
|
||||
|
||||
iv := reflect.Indirect(v)
|
||||
it := iv.Type()
|
||||
|
||||
switch it.Kind() {
|
||||
case reflect.Map:
|
||||
dstMap := reflect.MakeMap(iv.Type())
|
||||
for key, value := range pathValues.fields {
|
||||
dstKey := reflect.ValueOf(key)
|
||||
dstVal := reflect.New(iv.Type().Elem())
|
||||
err := assignPathValues(dstVal.Interface(), value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error binding map: %w", err)
|
||||
}
|
||||
dstMap.SetMapIndex(dstKey, dstVal.Elem())
|
||||
}
|
||||
iv.Set(dstMap)
|
||||
return nil
|
||||
case reflect.Slice:
|
||||
sliceLength := len(pathValues.fields)
|
||||
dstSlice := reflect.MakeSlice(it, sliceLength, sliceLength)
|
||||
err := assignSlice(dstSlice, pathValues)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error assigning slice: %w", err)
|
||||
}
|
||||
iv.Set(dstSlice)
|
||||
return nil
|
||||
case reflect.Struct:
|
||||
// Some special types we care about are structs. Handle them
|
||||
// here. They may be redefined, so we need to do some hoop
|
||||
// jumping. If the types are aliased, we need to type convert
|
||||
// the pointer, then set the value of the dereference pointer.
|
||||
|
||||
// We check to see if the object implements the Binder interface first.
|
||||
if dst, isBinder := v.Interface().(Binder); isBinder {
|
||||
return dst.Bind(pathValues.value)
|
||||
}
|
||||
// Then check the legacy types
|
||||
if it.ConvertibleTo(reflect.TypeOf(types.Date{})) {
|
||||
var date types.Date
|
||||
var err error
|
||||
date.Time, err = time.Parse(types.DateFormat, pathValues.value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid date format: %w", err)
|
||||
}
|
||||
dst := iv
|
||||
if it != reflect.TypeOf(types.Date{}) {
|
||||
// Types are aliased, convert the pointers.
|
||||
ivPtr := iv.Addr()
|
||||
aPtr := ivPtr.Convert(reflect.TypeOf(&types.Date{}))
|
||||
dst = reflect.Indirect(aPtr)
|
||||
}
|
||||
dst.Set(reflect.ValueOf(date))
|
||||
}
|
||||
if it.ConvertibleTo(reflect.TypeOf(time.Time{})) {
|
||||
var tm time.Time
|
||||
var err error
|
||||
tm, err = time.Parse(time.RFC3339Nano, pathValues.value)
|
||||
if err != nil {
|
||||
// Fall back to parsing it as a date.
|
||||
// TODO: why is this marked as an ineffassign?
|
||||
tm, err = time.Parse(types.DateFormat, pathValues.value) //nolint:ineffassign,staticcheck
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing '%s' as RFC3339 or 2006-01-02 time: %s", pathValues.value, err)
|
||||
}
|
||||
return fmt.Errorf("invalid date format: %w", err)
|
||||
}
|
||||
dst := iv
|
||||
if it != reflect.TypeOf(time.Time{}) {
|
||||
// Types are aliased, convert the pointers.
|
||||
ivPtr := iv.Addr()
|
||||
aPtr := ivPtr.Convert(reflect.TypeOf(&time.Time{}))
|
||||
dst = reflect.Indirect(aPtr)
|
||||
}
|
||||
dst.Set(reflect.ValueOf(tm))
|
||||
}
|
||||
fieldMap, err := fieldIndicesByJSONTag(iv.Interface())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed enumerating fields: %w", err)
|
||||
}
|
||||
for _, fieldName := range sortedFieldOrValueKeys(pathValues.fields) {
|
||||
fieldValue := pathValues.fields[fieldName]
|
||||
fieldIndex, found := fieldMap[fieldName]
|
||||
if !found {
|
||||
return fmt.Errorf("field [%s] is not present in destination object", fieldName)
|
||||
}
|
||||
field := iv.Field(fieldIndex)
|
||||
err = assignPathValues(field.Addr().Interface(), fieldValue)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error assigning field [%s]: %w", fieldName, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case reflect.Ptr:
|
||||
// If we have a pointer after redirecting, it means we're dealing with
|
||||
// an optional field, such as *string, which was passed in as &foo. We
|
||||
// will allocate it if necessary, and call ourselves with a different
|
||||
// interface.
|
||||
dstVal := reflect.New(it.Elem())
|
||||
dstPtr := dstVal.Interface()
|
||||
err := assignPathValues(dstPtr, pathValues)
|
||||
iv.Set(dstVal)
|
||||
return err
|
||||
case reflect.Bool:
|
||||
val, err := strconv.ParseBool(pathValues.value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("expected a valid bool, got %s", pathValues.value)
|
||||
}
|
||||
iv.SetBool(val)
|
||||
return nil
|
||||
case reflect.Float32:
|
||||
val, err := strconv.ParseFloat(pathValues.value, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("expected a valid float, got %s", pathValues.value)
|
||||
}
|
||||
iv.SetFloat(val)
|
||||
return nil
|
||||
case reflect.Float64:
|
||||
val, err := strconv.ParseFloat(pathValues.value, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("expected a valid float, got %s", pathValues.value)
|
||||
}
|
||||
iv.SetFloat(val)
|
||||
return nil
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
val, err := strconv.ParseInt(pathValues.value, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("expected a valid int, got %s", pathValues.value)
|
||||
}
|
||||
iv.SetInt(val)
|
||||
return nil
|
||||
case reflect.String:
|
||||
iv.SetString(pathValues.value)
|
||||
return nil
|
||||
default:
|
||||
return errors.New("unhandled type: " + it.String())
|
||||
}
|
||||
}
|
||||
|
||||
func assignSlice(dst reflect.Value, pathValues fieldOrValue) error {
|
||||
// Gather up the values
|
||||
nValues := len(pathValues.fields)
|
||||
values := make([]string, nValues)
|
||||
// We expect to have consecutive array indices in the map
|
||||
for i := 0; i < nValues; i++ {
|
||||
indexStr := strconv.Itoa(i)
|
||||
fv, found := pathValues.fields[indexStr]
|
||||
if !found {
|
||||
return errors.New("array deepObjects must have consecutive indices")
|
||||
}
|
||||
values[i] = fv.value
|
||||
}
|
||||
|
||||
// This could be cleaner, but we can call into assignPathValues to
|
||||
// avoid recreating this logic.
|
||||
for i := 0; i < nValues; i++ {
|
||||
dstElem := dst.Index(i).Addr()
|
||||
err := assignPathValues(dstElem.Interface(), fieldOrValue{value: values[i]})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error binding array: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sortedFieldOrValueKeys(m map[string]fieldOrValue) []string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
34
vendor/github.com/oapi-codegen/runtime/jsonmerge.go
generated
vendored
Normal file
34
vendor/github.com/oapi-codegen/runtime/jsonmerge.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/apapsch/go-jsonmerge/v2"
|
||||
)
|
||||
|
||||
// JsonMerge merges two JSON representation into a single object. `data` is the
|
||||
// existing representation and `patch` is the new data to be merged in
|
||||
//
|
||||
// Deprecated: Use JSONMerge instead.
|
||||
func JsonMerge(data, patch json.RawMessage) (json.RawMessage, error) {
|
||||
return JSONMerge(data, patch)
|
||||
}
|
||||
|
||||
// JSONMerge merges two JSON representation into a single object. `data` is the
|
||||
// existing representation and `patch` is the new data to be merged in
|
||||
func JSONMerge(data, patch json.RawMessage) (json.RawMessage, error) {
|
||||
merger := jsonmerge.Merger{
|
||||
CopyNonexistent: true,
|
||||
}
|
||||
if data == nil {
|
||||
data = []byte(`{}`)
|
||||
}
|
||||
if patch == nil {
|
||||
patch = []byte(`{}`)
|
||||
}
|
||||
merged, err := merger.MergeBytes(data, patch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return merged, nil
|
||||
}
|
||||
6
vendor/github.com/oapi-codegen/runtime/renovate.json
generated
vendored
Normal file
6
vendor/github.com/oapi-codegen/runtime/renovate.json
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"local>oapi-codegen/renovate-config"
|
||||
]
|
||||
}
|
||||
478
vendor/github.com/oapi-codegen/runtime/styleparam.go
generated
vendored
Normal file
478
vendor/github.com/oapi-codegen/runtime/styleparam.go
generated
vendored
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
// Copyright 2019 DeepMap, Inc.
|
||||
//
|
||||
// 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"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/oapi-codegen/runtime/types"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Parameter escaping works differently based on where a header is found
|
||||
|
||||
type ParamLocation int
|
||||
|
||||
const (
|
||||
ParamLocationUndefined ParamLocation = iota
|
||||
ParamLocationQuery
|
||||
ParamLocationPath
|
||||
ParamLocationHeader
|
||||
ParamLocationCookie
|
||||
)
|
||||
|
||||
// StyleParam is used by older generated code, and must remain compatible
|
||||
// with that code. It is not to be used in new templates. Please see the
|
||||
// function below, which can specialize its output based on the location of
|
||||
// the parameter.
|
||||
func StyleParam(style string, explode bool, paramName string, value interface{}) (string, error) {
|
||||
return StyleParamWithLocation(style, explode, paramName, ParamLocationUndefined, value)
|
||||
}
|
||||
|
||||
// Given an input value, such as a primitive type, array or object, turn it
|
||||
// into a parameter based on style/explode definition, performing whatever
|
||||
// escaping is necessary based on parameter location
|
||||
func StyleParamWithLocation(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
|
||||
t := reflect.TypeOf(value)
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
// Things may be passed in by pointer, we need to dereference, so return
|
||||
// error on nil.
|
||||
if t.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return "", fmt.Errorf("value is a nil pointer")
|
||||
}
|
||||
v = reflect.Indirect(v)
|
||||
t = v.Type()
|
||||
}
|
||||
|
||||
// If the value implements encoding.TextMarshaler we use it for marshaling
|
||||
// https://github.com/deepmap/oapi-codegen/issues/504
|
||||
if tu, ok := value.(encoding.TextMarshaler); ok {
|
||||
t := reflect.Indirect(reflect.ValueOf(value)).Type()
|
||||
convertableToTime := t.ConvertibleTo(reflect.TypeOf(time.Time{}))
|
||||
convertableToDate := t.ConvertibleTo(reflect.TypeOf(types.Date{}))
|
||||
|
||||
// Since both time.Time and types.Date implement encoding.TextMarshaler
|
||||
// we should avoid calling theirs MarshalText()
|
||||
if !convertableToTime && !convertableToDate {
|
||||
b, err := tu.MarshalText()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error marshaling '%s' as text: %s", value, err)
|
||||
}
|
||||
|
||||
return stylePrimitive(style, explode, paramName, paramLocation, string(b))
|
||||
}
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Slice:
|
||||
n := v.Len()
|
||||
sliceVal := make([]interface{}, n)
|
||||
for i := 0; i < n; i++ {
|
||||
sliceVal[i] = v.Index(i).Interface()
|
||||
}
|
||||
return styleSlice(style, explode, paramName, paramLocation, sliceVal)
|
||||
case reflect.Struct:
|
||||
return styleStruct(style, explode, paramName, paramLocation, value)
|
||||
case reflect.Map:
|
||||
return styleMap(style, explode, paramName, paramLocation, value)
|
||||
default:
|
||||
return stylePrimitive(style, explode, paramName, paramLocation, value)
|
||||
}
|
||||
}
|
||||
|
||||
func styleSlice(style string, explode bool, paramName string, paramLocation ParamLocation, values []interface{}) (string, error) {
|
||||
if style == "deepObject" {
|
||||
if !explode {
|
||||
return "", errors.New("deepObjects must be exploded")
|
||||
}
|
||||
return MarshalDeepObject(values, paramName)
|
||||
}
|
||||
|
||||
var prefix string
|
||||
var separator string
|
||||
|
||||
switch style {
|
||||
case "simple":
|
||||
separator = ","
|
||||
case "label":
|
||||
prefix = "."
|
||||
if explode {
|
||||
separator = "."
|
||||
} else {
|
||||
separator = ","
|
||||
}
|
||||
case "matrix":
|
||||
prefix = fmt.Sprintf(";%s=", paramName)
|
||||
if explode {
|
||||
separator = prefix
|
||||
} else {
|
||||
separator = ","
|
||||
}
|
||||
case "form":
|
||||
prefix = fmt.Sprintf("%s=", paramName)
|
||||
if explode {
|
||||
separator = "&" + prefix
|
||||
} else {
|
||||
separator = ","
|
||||
}
|
||||
case "spaceDelimited":
|
||||
prefix = fmt.Sprintf("%s=", paramName)
|
||||
if explode {
|
||||
separator = "&" + prefix
|
||||
} else {
|
||||
separator = " "
|
||||
}
|
||||
case "pipeDelimited":
|
||||
prefix = fmt.Sprintf("%s=", paramName)
|
||||
if explode {
|
||||
separator = "&" + prefix
|
||||
} else {
|
||||
separator = "|"
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported style '%s'", style)
|
||||
}
|
||||
|
||||
// We're going to assume here that the array is one of simple types.
|
||||
var err error
|
||||
var part string
|
||||
parts := make([]string, len(values))
|
||||
for i, v := range values {
|
||||
part, err = primitiveToString(v)
|
||||
part = escapeParameterString(part, paramLocation)
|
||||
parts[i] = part
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error formatting '%s': %s", paramName, err)
|
||||
}
|
||||
}
|
||||
return prefix + strings.Join(parts, separator), nil
|
||||
}
|
||||
|
||||
func sortedKeys(strMap map[string]string) []string {
|
||||
keys := make([]string, len(strMap))
|
||||
i := 0
|
||||
for k := range strMap {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
// These are special cases. The value may be a date, time, or uuid,
|
||||
// in which case, marshal it into the correct format.
|
||||
func marshalKnownTypes(value interface{}) (string, bool) {
|
||||
v := reflect.Indirect(reflect.ValueOf(value))
|
||||
t := v.Type()
|
||||
|
||||
if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
|
||||
tt := v.Convert(reflect.TypeOf(time.Time{}))
|
||||
timeVal := tt.Interface().(time.Time)
|
||||
return timeVal.Format(time.RFC3339Nano), true
|
||||
}
|
||||
|
||||
if t.ConvertibleTo(reflect.TypeOf(types.Date{})) {
|
||||
d := v.Convert(reflect.TypeOf(types.Date{}))
|
||||
dateVal := d.Interface().(types.Date)
|
||||
return dateVal.Format(types.DateFormat), true
|
||||
}
|
||||
|
||||
if t.ConvertibleTo(reflect.TypeOf(types.UUID{})) {
|
||||
u := v.Convert(reflect.TypeOf(types.UUID{}))
|
||||
uuidVal := u.Interface().(types.UUID)
|
||||
return uuidVal.String(), true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
func styleStruct(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
|
||||
if timeVal, ok := marshalKnownTypes(value); ok {
|
||||
styledVal, err := stylePrimitive(style, explode, paramName, paramLocation, timeVal)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to style time: %w", err)
|
||||
}
|
||||
return styledVal, nil
|
||||
}
|
||||
|
||||
if style == "deepObject" {
|
||||
if !explode {
|
||||
return "", errors.New("deepObjects must be exploded")
|
||||
}
|
||||
return MarshalDeepObject(value, paramName)
|
||||
}
|
||||
|
||||
// If input has Marshaler, such as object has Additional Property or AnyOf,
|
||||
// We use this Marshaler and convert into interface{} before styling.
|
||||
if m, ok := value.(json.Marshaler); ok {
|
||||
buf, err := m.MarshalJSON()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal input to JSON: %w", err)
|
||||
}
|
||||
e := json.NewDecoder(bytes.NewReader(buf))
|
||||
e.UseNumber()
|
||||
var i2 interface{}
|
||||
err = e.Decode(&i2)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal JSON: %w", err)
|
||||
}
|
||||
s, err := StyleParamWithLocation(style, explode, paramName, paramLocation, i2)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error style JSON structure: %w", err)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Otherwise, we need to build a dictionary of the struct's fields. Each
|
||||
// field may only be a primitive value.
|
||||
v := reflect.ValueOf(value)
|
||||
t := reflect.TypeOf(value)
|
||||
fieldDict := make(map[string]string)
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
fieldT := t.Field(i)
|
||||
// Find the json annotation on the field, and use the json specified
|
||||
// name if available, otherwise, just the field name.
|
||||
tag := fieldT.Tag.Get("json")
|
||||
fieldName := fieldT.Name
|
||||
if tag != "" {
|
||||
tagParts := strings.Split(tag, ",")
|
||||
name := tagParts[0]
|
||||
if name != "" {
|
||||
fieldName = name
|
||||
}
|
||||
}
|
||||
f := v.Field(i)
|
||||
|
||||
// Unset optional fields will be nil pointers, skip over those.
|
||||
if f.Type().Kind() == reflect.Ptr && f.IsNil() {
|
||||
continue
|
||||
}
|
||||
str, err := primitiveToString(f.Interface())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error formatting '%s': %s", paramName, err)
|
||||
}
|
||||
fieldDict[fieldName] = str
|
||||
}
|
||||
|
||||
return processFieldDict(style, explode, paramName, paramLocation, fieldDict)
|
||||
}
|
||||
|
||||
func styleMap(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
|
||||
if style == "deepObject" {
|
||||
if !explode {
|
||||
return "", errors.New("deepObjects must be exploded")
|
||||
}
|
||||
return MarshalDeepObject(value, paramName)
|
||||
}
|
||||
|
||||
dict, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
return "", errors.New("map not of type map[string]interface{}")
|
||||
}
|
||||
|
||||
fieldDict := make(map[string]string)
|
||||
for fieldName, value := range dict {
|
||||
str, err := primitiveToString(value)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error formatting '%s': %s", paramName, err)
|
||||
}
|
||||
fieldDict[fieldName] = str
|
||||
}
|
||||
return processFieldDict(style, explode, paramName, paramLocation, fieldDict)
|
||||
}
|
||||
|
||||
func processFieldDict(style string, explode bool, paramName string, paramLocation ParamLocation, fieldDict map[string]string) (string, error) {
|
||||
var parts []string
|
||||
|
||||
// This works for everything except deepObject. We'll handle that one
|
||||
// separately.
|
||||
if style != "deepObject" {
|
||||
if explode {
|
||||
for _, k := range sortedKeys(fieldDict) {
|
||||
v := escapeParameterString(fieldDict[k], paramLocation)
|
||||
parts = append(parts, k+"="+v)
|
||||
}
|
||||
} else {
|
||||
for _, k := range sortedKeys(fieldDict) {
|
||||
v := escapeParameterString(fieldDict[k], paramLocation)
|
||||
parts = append(parts, k)
|
||||
parts = append(parts, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var prefix string
|
||||
var separator string
|
||||
|
||||
switch style {
|
||||
case "simple":
|
||||
separator = ","
|
||||
case "label":
|
||||
prefix = "."
|
||||
if explode {
|
||||
separator = prefix
|
||||
} else {
|
||||
separator = ","
|
||||
}
|
||||
case "matrix":
|
||||
if explode {
|
||||
separator = ";"
|
||||
prefix = ";"
|
||||
} else {
|
||||
separator = ","
|
||||
prefix = fmt.Sprintf(";%s=", paramName)
|
||||
}
|
||||
case "form":
|
||||
if explode {
|
||||
separator = "&"
|
||||
} else {
|
||||
prefix = fmt.Sprintf("%s=", paramName)
|
||||
separator = ","
|
||||
}
|
||||
case "deepObject":
|
||||
{
|
||||
if !explode {
|
||||
return "", fmt.Errorf("deepObject parameters must be exploded")
|
||||
}
|
||||
for _, k := range sortedKeys(fieldDict) {
|
||||
v := fieldDict[k]
|
||||
part := fmt.Sprintf("%s[%s]=%s", paramName, k, v)
|
||||
parts = append(parts, part)
|
||||
}
|
||||
separator = "&"
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported style '%s'", style)
|
||||
}
|
||||
|
||||
return prefix + strings.Join(parts, separator), nil
|
||||
}
|
||||
|
||||
func stylePrimitive(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
|
||||
strVal, err := primitiveToString(value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var prefix string
|
||||
switch style {
|
||||
case "simple":
|
||||
case "label":
|
||||
prefix = "."
|
||||
case "matrix":
|
||||
prefix = fmt.Sprintf(";%s=", paramName)
|
||||
case "form":
|
||||
prefix = fmt.Sprintf("%s=", paramName)
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported style '%s'", style)
|
||||
}
|
||||
return prefix + escapeParameterString(strVal, paramLocation), nil
|
||||
}
|
||||
|
||||
// Converts a primitive value to a string. We need to do this based on the
|
||||
// Kind of an interface, not the Type to work with aliased types.
|
||||
func primitiveToString(value interface{}) (string, error) {
|
||||
var output string
|
||||
|
||||
// sometimes time and date used like primitive types
|
||||
// it can happen if paramether is object and has time or date as field
|
||||
if res, ok := marshalKnownTypes(value); ok {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Values may come in by pointer for optionals, so make sure to dereferene.
|
||||
v := reflect.Indirect(reflect.ValueOf(value))
|
||||
t := v.Type()
|
||||
kind := t.Kind()
|
||||
|
||||
switch kind {
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||
output = strconv.FormatInt(v.Int(), 10)
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
output = strconv.FormatUint(v.Uint(), 10)
|
||||
case reflect.Float64:
|
||||
output = strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
||||
case reflect.Float32:
|
||||
output = strconv.FormatFloat(v.Float(), 'f', -1, 32)
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
output = "true"
|
||||
} else {
|
||||
output = "false"
|
||||
}
|
||||
case reflect.String:
|
||||
output = v.String()
|
||||
case reflect.Struct:
|
||||
// If input has Marshaler, such as object has Additional Property or AnyOf,
|
||||
// We use this Marshaler and convert into interface{} before styling.
|
||||
if v, ok := value.(uuid.UUID); ok {
|
||||
output = v.String()
|
||||
break
|
||||
}
|
||||
if m, ok := value.(json.Marshaler); ok {
|
||||
buf, err := m.MarshalJSON()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal input to JSON: %w", err)
|
||||
}
|
||||
e := json.NewDecoder(bytes.NewReader(buf))
|
||||
e.UseNumber()
|
||||
var i2 interface{}
|
||||
err = e.Decode(&i2)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal JSON: %w", err)
|
||||
}
|
||||
output, err = primitiveToString(i2)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error convert JSON structure: %w", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
v, ok := value.(fmt.Stringer)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String())
|
||||
}
|
||||
|
||||
output = v.String()
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// escapeParameterString escapes a parameter value bas on the location of that parameter.
|
||||
// Query params and path params need different kinds of escaping, while header
|
||||
// and cookie params seem not to need escaping.
|
||||
func escapeParameterString(value string, paramLocation ParamLocation) string {
|
||||
switch paramLocation {
|
||||
case ParamLocationQuery:
|
||||
return url.QueryEscape(value)
|
||||
case ParamLocationPath:
|
||||
return url.PathEscape(value)
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
43
vendor/github.com/oapi-codegen/runtime/types/date.go
generated
vendored
Normal file
43
vendor/github.com/oapi-codegen/runtime/types/date.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
const DateFormat = "2006-01-02"
|
||||
|
||||
type Date struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
func (d Date) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(d.Time.Format(DateFormat))
|
||||
}
|
||||
|
||||
func (d *Date) UnmarshalJSON(data []byte) error {
|
||||
var dateStr string
|
||||
err := json.Unmarshal(data, &dateStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parsed, err := time.Parse(DateFormat, dateStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Time = parsed
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d Date) String() string {
|
||||
return d.Time.Format(DateFormat)
|
||||
}
|
||||
|
||||
func (d *Date) UnmarshalText(data []byte) error {
|
||||
parsed, err := time.Parse(DateFormat, string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Time = parsed
|
||||
return nil
|
||||
}
|
||||
40
vendor/github.com/oapi-codegen/runtime/types/email.go
generated
vendored
Normal file
40
vendor/github.com/oapi-codegen/runtime/types/email.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// ErrValidationEmail is the sentinel error returned when an email fails validation
|
||||
var ErrValidationEmail = errors.New("email: failed to pass regex validation")
|
||||
|
||||
// Email represents an email address.
|
||||
// It is a string type that must pass regex validation before being marshalled
|
||||
// to JSON or unmarshalled from JSON.
|
||||
type Email string
|
||||
|
||||
func (e Email) MarshalJSON() ([]byte, error) {
|
||||
if !emailRegex.MatchString(string(e)) {
|
||||
return nil, ErrValidationEmail
|
||||
}
|
||||
|
||||
return json.Marshal(string(e))
|
||||
}
|
||||
|
||||
func (e *Email) UnmarshalJSON(data []byte) error {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var s string
|
||||
if err := json.Unmarshal(data, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*e = Email(s)
|
||||
if !emailRegex.MatchString(s) {
|
||||
return ErrValidationEmail
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
71
vendor/github.com/oapi-codegen/runtime/types/file.go
generated
vendored
Normal file
71
vendor/github.com/oapi-codegen/runtime/types/file.go
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
multipart *multipart.FileHeader
|
||||
data []byte
|
||||
filename string
|
||||
}
|
||||
|
||||
func (file *File) InitFromMultipart(header *multipart.FileHeader) {
|
||||
file.multipart = header
|
||||
file.data = nil
|
||||
file.filename = ""
|
||||
}
|
||||
|
||||
func (file *File) InitFromBytes(data []byte, filename string) {
|
||||
file.data = data
|
||||
file.filename = filename
|
||||
file.multipart = nil
|
||||
}
|
||||
|
||||
func (file File) MarshalJSON() ([]byte, error) {
|
||||
b, err := file.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(b)
|
||||
}
|
||||
|
||||
func (file *File) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &file.data)
|
||||
}
|
||||
|
||||
func (file File) Bytes() ([]byte, error) {
|
||||
if file.multipart != nil {
|
||||
f, err := file.multipart.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
return io.ReadAll(f)
|
||||
}
|
||||
return file.data, nil
|
||||
}
|
||||
|
||||
func (file File) Reader() (io.ReadCloser, error) {
|
||||
if file.multipart != nil {
|
||||
return file.multipart.Open()
|
||||
}
|
||||
return io.NopCloser(bytes.NewReader(file.data)), nil
|
||||
}
|
||||
|
||||
func (file File) Filename() string {
|
||||
if file.multipart != nil {
|
||||
return file.multipart.Filename
|
||||
}
|
||||
return file.filename
|
||||
}
|
||||
|
||||
func (file File) FileSize() int64 {
|
||||
if file.multipart != nil {
|
||||
return file.multipart.Size
|
||||
}
|
||||
return int64(len(file.data))
|
||||
}
|
||||
11
vendor/github.com/oapi-codegen/runtime/types/regexes.go
generated
vendored
Normal file
11
vendor/github.com/oapi-codegen/runtime/types/regexes.go
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package types
|
||||
|
||||
import "regexp"
|
||||
|
||||
const (
|
||||
emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
|
||||
)
|
||||
|
||||
var (
|
||||
emailRegex = regexp.MustCompile(emailRegexString)
|
||||
)
|
||||
7
vendor/github.com/oapi-codegen/runtime/types/uuid.go
generated
vendored
Normal file
7
vendor/github.com/oapi-codegen/runtime/types/uuid.go
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type UUID = uuid.UUID
|
||||
Loading…
Add table
Add a link
Reference in a new issue